aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/sec-switch_max8997.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/sec-switch_max8997.c')
-rw-r--r--arch/arm/mach-exynos/sec-switch_max8997.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/sec-switch_max8997.c b/arch/arm/mach-exynos/sec-switch_max8997.c
new file mode 100644
index 0000000..51f9c31
--- /dev/null
+++ b/arch/arm/mach-exynos/sec-switch_max8997.c
@@ -0,0 +1,496 @@
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio_event.h>
+#include <plat/devs.h>
+#include <plat/gpio-cfg.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/input.h>
+#include <plat/udc-hs.h>
+/*#include <linux/mmc/host.h>*/
+#include <linux/regulator/machine.h>
+#include <linux/regulator/max8649.h>
+#include <linux/regulator/fixed.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/max8997.h>
+#include <linux/mfd/max8997-private.h>
+/* #include <linux/mfd/max77686.h> */
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#ifdef CONFIG_BATTERY_SAMSUNG
+#include <linux/power_supply.h>
+#include <linux/battery/samsung_battery.h>
+#endif
+#include <linux/switch.h>
+#include <linux/sii9234.h>
+
+#ifdef CONFIG_USB_HOST_NOTIFY
+#include <linux/host_notify.h>
+#endif
+#include <linux/pm_runtime.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#ifdef CONFIG_JACK_MON
+#include <linux/jack.h>
+#endif
+
+#define MUIC_DEBUG 1
+#ifdef MUIC_DEBUG
+#define MUIC_PRINT_LOG() \
+ pr_info("MUIC:[%s] func:%s\n", __FILE__, __func__);
+#else
+#define MUIC_PRINT_LOG() {}
+#endif
+
+static struct switch_dev switch_dock = {
+ .name = "dock",
+};
+
+extern struct class *sec_class;
+
+struct device *switch_dev;
+EXPORT_SYMBOL(switch_dev);
+
+static int uart_switch_init(void);
+
+static ssize_t u1_switch_show_vbus(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ struct regulator *regulator;
+
+ regulator = regulator_get(NULL, "safeout1");
+ if (IS_ERR(regulator)) {
+ pr_warn("%s: fail to get regulator\n", __func__);
+ return sprintf(buf, "UNKNOWN\n");
+ }
+ if (regulator_is_enabled(regulator))
+ i = sprintf(buf, "VBUS is enabled\n");
+ else
+ i = sprintf(buf, "VBUS is disabled\n");
+ MUIC_PRINT_LOG();
+ regulator_put(regulator);
+
+ return i;
+}
+
+static ssize_t u1_switch_store_vbus(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int disable, ret, usb_mode;
+ struct regulator *regulator;
+ /* struct s3c_udc *udc = platform_get_drvdata(&s3c_device_usbgadget); */
+
+ MUIC_PRINT_LOG();
+ if (!strncmp(buf, "0", 1))
+ disable = 0;
+ else if (!strncmp(buf, "1", 1))
+ disable = 1;
+ else {
+ pr_warn("%s: Wrong command\n", __func__);
+ return count;
+ }
+
+ pr_info("%s: disable=%d\n", __func__, disable);
+ usb_mode =
+ disable ? USB_CABLE_DETACHED_WITHOUT_NOTI : USB_CABLE_ATTACHED;
+ /* ret = udc->change_usb_mode(usb_mode); */
+ ret = -1;
+ if (ret < 0)
+ pr_err("%s: fail to change mode!!!\n", __func__);
+
+ regulator = regulator_get(NULL, "safeout1");
+ if (IS_ERR(regulator)) {
+ pr_warn("%s: fail to get regulator\n", __func__);
+ return count;
+ }
+
+ if (disable) {
+ if (regulator_is_enabled(regulator))
+ regulator_force_disable(regulator);
+ if (!regulator_is_enabled(regulator))
+ regulator_enable(regulator);
+ } else {
+ if (!regulator_is_enabled(regulator))
+ regulator_enable(regulator);
+ }
+ regulator_put(regulator);
+
+ return count;
+}
+
+DEVICE_ATTR(disable_vbus, 0664, u1_switch_show_vbus,
+ u1_switch_store_vbus);
+
+#ifdef CONFIG_TARGET_LOCALE_KOR
+#include "../../../drivers/usb/gadget/s3c_udc.h"
+/* usb access control for SEC DM */
+struct device *usb_lock;
+static int is_usb_locked;
+
+int u1_switch_get_usb_lock_state(void)
+{
+ return is_usb_locked;
+}
+EXPORT_SYMBOL(u1_switch_get_usb_lock_state);
+
+static ssize_t u1_switch_show_usb_lock(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (is_usb_locked)
+ return snprintf(buf, PAGE_SIZE, "USB_LOCK");
+ else
+ return snprintf(buf, PAGE_SIZE, "USB_UNLOCK");
+}
+
+static ssize_t u1_switch_store_usb_lock(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int lock;
+ struct s3c_udc *udc = platform_get_drvdata(&s3c_device_usbgadget);
+
+ if (!strncmp(buf, "0", 1))
+ lock = 0;
+ else if (!strncmp(buf, "1", 1))
+ lock = 1;
+ else {
+ pr_warn("%s: Wrong command\n", __func__);
+ return count;
+ }
+
+ if (IS_ERR_OR_NULL(udc))
+ return count;
+
+ pr_info("%s: lock=%d\n", __func__, lock);
+
+ if (lock != is_usb_locked) {
+ is_usb_locked = lock;
+
+ if (lock) {
+ if (udc->udc_enabled)
+ usb_gadget_vbus_disconnect(&udc->gadget);
+ }
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(enable, 0664,
+ u1_switch_show_usb_lock, u1_switch_store_usb_lock);
+#endif
+
+static int __init u1_sec_switch_init(void)
+{
+ int ret;
+ switch_dev = device_create(sec_class, NULL, 0, NULL, "switch");
+
+ if (IS_ERR(switch_dev))
+ pr_err("Failed to create device(switch)!\n");
+
+ ret = device_create_file(switch_dev, &dev_attr_disable_vbus);
+ if (ret)
+ pr_err("Failed to create device file(disable_vbus)!\n");
+
+#ifdef CONFIG_TARGET_LOCALE_KOR
+ usb_lock = device_create(sec_class, switch_dev,
+ MKDEV(0, 0), NULL, ".usb_lock");
+
+ if (IS_ERR(usb_lock))
+ pr_err("Failed to create device (usb_lock)!\n");
+
+ if (device_create_file(usb_lock, &dev_attr_enable) < 0)
+ pr_err("Failed to create device file(.usblock/enable)!\n");
+#endif
+
+#if !defined(CONFIG_MACH_U1CAMERA_BD)
+ ret = uart_switch_init();
+ if (ret)
+ pr_err("Failed to create uart_switch\n");
+#endif /* CONFIG_MACH_U1CAMERA_BD */
+
+ return 0;
+};
+
+static int uart_switch_init(void)
+{
+ int ret, val;
+ MUIC_PRINT_LOG();
+
+ ret = gpio_request(GPIO_UART_SEL, "UART_SEL");
+ if (ret < 0) {
+ pr_err("Failed to request GPIO_UART_SEL!\n");
+ return -ENODEV;
+ }
+ s3c_gpio_setpull(GPIO_UART_SEL, S3C_GPIO_PULL_NONE);
+ val = gpio_get_value(GPIO_UART_SEL);
+ pr_info("##MUIC [ %s ]- func : %s !! val:-%d-\n", __FILE__, __func__,
+ val);
+ gpio_direction_output(GPIO_UART_SEL, val);
+
+ gpio_export(GPIO_UART_SEL, 1);
+
+ gpio_export_link(switch_dev, "uart_sel", GPIO_UART_SEL);
+
+ return 0;
+}
+
+#if 0
+int max77693_muic_charger_cb(enum cable_type_muic cable_type)
+{
+ MUIC_PRINT_LOG();
+ return 0;
+}
+
+#define RETRY_CNT_LIMIT 100
+/* usb cable call back function */
+void max77693_muic_usb_cb(u8 usb_mode)
+{
+ struct usb_gadget *gadget = platform_get_drvdata(&s3c_device_usbgadget);
+#ifdef CONFIG_USB_EHCI_S5P
+ struct usb_hcd *ehci_hcd = platform_get_drvdata(&s5p_device_ehci);
+#endif
+#ifdef CONFIG_USB_OHCI_S5P
+ struct usb_hcd *ohci_hcd = platform_get_drvdata(&s5p_device_ohci);
+#endif
+#ifdef CONFIG_USB_HOST_NOTIFY
+ struct host_notifier_platform_data *host_noti_pdata =
+ host_notifier_device.dev.platform_data;
+#endif
+ int retry_cnt = 1;
+
+ pr_info("MUIC usb_cb:%d\n", usb_mode);
+ if (gadget) {
+ switch (usb_mode) {
+ case USB_CABLE_DETACHED:
+ pr_info("usb: muic: USB_CABLE_DETACHED(%d)\n",
+ usb_mode);
+ usb_gadget_vbus_disconnect(gadget);
+ break;
+ case USB_CABLE_ATTACHED:
+ pr_info("usb: muic: USB_CABLE_ATTACHED(%d)\n",
+ usb_mode);
+ usb_gadget_vbus_connect(gadget);
+ break;
+ default:
+ pr_info("usb: muic: invalid mode%d\n", usb_mode);
+ }
+ }
+
+ if (usb_mode == USB_OTGHOST_ATTACHED) {
+#ifdef CONFIG_USB_EHCI_S5P
+ pm_runtime_get_sync(&s5p_device_ehci.dev);
+#endif
+#ifdef CONFIG_USB_OHCI_S5P
+ pm_runtime_get_sync(&s5p_device_ohci.dev);
+#endif
+#ifdef CONFIG_USB_HOST_NOTIFY
+ host_noti_pdata->ndev.mode = NOTIFY_HOST_MODE;
+ if (host_noti_pdata->usbhostd_start)
+ host_noti_pdata->usbhostd_start();
+
+ host_noti_pdata->booster(1);
+#endif
+ } else if (usb_mode == USB_OTGHOST_DETACHED) {
+#ifdef CONFIG_USB_EHCI_S5P
+ pm_runtime_put_sync(&s5p_device_ehci.dev);
+ /* waiting for ehci root hub suspend is done */
+ while (ehci_hcd->state != HC_STATE_SUSPENDED) {
+ msleep(50);
+ if (retry_cnt++ > RETRY_CNT_LIMIT) {
+ printk(KERN_ERR "ehci suspend not completed\n");
+ break;
+ }
+ }
+#endif
+#ifdef CONFIG_USB_OHCI_S5P
+ pm_runtime_put_sync(&s5p_device_ohci.dev);
+ /* waiting for ohci root hub suspend is done */
+ while (ohci_hcd->state != HC_STATE_SUSPENDED) {
+ msleep(50);
+ if (retry_cnt++ > RETRY_CNT_LIMIT) {
+ printk(KERN_ERR
+ "ohci suspend is not completed\n");
+ break;
+ }
+ }
+#endif
+#ifdef CONFIG_USB_HOST_NOTIFY
+ host_noti_pdata->ndev.mode = NOTIFY_NONE_MODE;
+ if (host_noti_pdata->usbhostd_stop)
+ host_noti_pdata->usbhostd_stop();
+
+ host_noti_pdata->booster(0);
+#endif
+ }
+
+#ifdef CONFIG_JACK_MON
+ if (usb_mode == USB_OTGHOST_ATTACHED)
+ jack_event_handler("host", USB_CABLE_ATTACHED);
+ else if (usb_mode == USB_OTGHOST_DETACHED)
+ jack_event_handler("host", USB_CABLE_DETACHED);
+ else if ((usb_mode == USB_CABLE_ATTACHED)
+ || (usb_mode == USB_CABLE_DETACHED))
+ jack_event_handler("usb", usb_mode);
+#endif
+}
+
+/*extern void MHL_On(bool on);*/
+void max77693_muic_mhl_cb(int attached)
+{
+ MUIC_PRINT_LOG();
+ pr_info("MUIC attached:%d\n", attached);
+ if (attached == MAX77693_MUIC_ATTACHED) {
+ /*MHL_On(1);*/ /* GPIO_LEVEL_HIGH */
+ pr_info("MHL Attached !!\n");
+#ifdef CONFIG_SAMSUNG_MHL
+ sii9234_mhl_detection_sched();
+#endif
+ } else {
+ /*MHL_On(0);*/ /* GPIO_LEVEL_LOW */
+ pr_info("MHL Detached !!\n");
+ }
+}
+
+bool max77693_muic_is_mhl_attached(void)
+{
+ int val;
+ MUIC_PRINT_LOG();
+ gpio_request(GPIO_MHL_SEL, "MHL_SEL");
+ val = gpio_get_value(GPIO_MHL_SEL);
+ pr_info("MUIC val:%d\n", val);
+ gpio_free(GPIO_MHL_SEL);
+
+ return !!val;
+}
+
+void max77693_muic_deskdock_cb(bool attached)
+{
+ MUIC_PRINT_LOG();
+ pr_info("MUIC deskdock attached=%d\n", attached);
+ if (attached)
+ switch_set_state(&switch_dock, 1);
+ else
+ switch_set_state(&switch_dock, 0);
+}
+
+void max77693_muic_cardock_cb(bool attached)
+{
+ MUIC_PRINT_LOG();
+ pr_info("MUIC cardock attached=%d\n", attached);
+ pr_info("##MUIC [ %s ]- func : %s !!\n", __FILE__, __func__);
+ if (attached)
+ switch_set_state(&switch_dock, 2);
+ else
+ switch_set_state(&switch_dock, 0);
+}
+
+void max77693_muic_init_cb(void)
+{
+ int ret;
+
+ /* for CarDock, DeskDock */
+ ret = switch_dev_register(&switch_dock);
+
+ MUIC_PRINT_LOG();
+ pr_info("MUIC ret=%d\n", ret);
+
+ if (ret < 0)
+ pr_err("Failed to register dock switch. %d\n", ret);
+}
+
+int max77693_muic_cfg_uart_gpio(void)
+{
+ int val, path;
+ pr_info("## MUIC func : %s ! please path: (uart:%d - usb:%d)\n",
+ __func__, gpio_get_value(GPIO_UART_SEL),
+ gpio_get_value(GPIO_USB_SEL));
+ val = gpio_get_value(GPIO_UART_SEL);
+ path = val ? UART_PATH_AP : UART_PATH_CP;
+ pr_info("##MUIC [ %s ]- func : %s !! -- val:%d -- path:%d\n", __FILE__,
+ __func__, val, path);
+
+ return path;
+}
+
+void max77693_muic_jig_uart_cb(int path)
+{
+ int val;
+
+ val = path == UART_PATH_AP ? 1 : 0;
+ pr_info("##MUIC [ %s ]- func : %s !! -- val:%d\n", __FILE__, __func__,
+ val);
+ gpio_set_value(GPIO_UART_SEL, val);
+}
+
+int max77693_muic_host_notify_cb(int enable)
+{
+ MUIC_PRINT_LOG();
+ pr_info("MUIC host_noti enable=%d\n", enable);
+ return 0;
+}
+
+int max77693_muic_set_safeout(int path)
+{
+ struct regulator *regulator;
+
+ MUIC_PRINT_LOG();
+ pr_info("MUIC safeout path=%d\n", path);
+
+ if (path == CP_USB_MODE) {
+ regulator = regulator_get(NULL, "safeout1");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+ if (regulator_is_enabled(regulator))
+ regulator_force_disable(regulator);
+ regulator_put(regulator);
+
+ regulator = regulator_get(NULL, "safeout2");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+ if (!regulator_is_enabled(regulator))
+ regulator_enable(regulator);
+ regulator_put(regulator);
+ } else {
+ /* AP_USB_MODE || AUDIO_MODE */
+ regulator = regulator_get(NULL, "safeout1");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+ if (!regulator_is_enabled(regulator))
+ regulator_enable(regulator);
+ regulator_put(regulator);
+
+ regulator = regulator_get(NULL, "safeout2");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+ if (regulator_is_enabled(regulator))
+ regulator_force_disable(regulator);
+ regulator_put(regulator);
+ }
+
+ return 0;
+}
+
+struct max77693_muic_data max77693_muic = {
+ .usb_cb = max77693_muic_usb_cb,
+ .charger_cb = max77693_muic_charger_cb,
+ .mhl_cb = max77693_muic_mhl_cb,
+ .is_mhl_attached = max77693_muic_is_mhl_attached,
+ .set_safeout = max77693_muic_set_safeout,
+ .init_cb = max77693_muic_init_cb,
+ .deskdock_cb = max77693_muic_deskdock_cb,
+ .cardock_cb = max77693_muic_cardock_cb,
+ .cfg_uart_gpio = max77693_muic_cfg_uart_gpio,
+ .jig_uart_cb = max77693_muic_jig_uart_cb,
+ .host_notify_cb = max77693_muic_host_notify_cb,
+ .gpio_usb_sel = GPIO_USB_SEL,
+};
+#endif
+
+device_initcall(u1_sec_switch_init);