diff options
Diffstat (limited to 'drivers/accessory/30pin_con.c')
-rw-r--r-- | drivers/accessory/30pin_con.c | 148 |
1 files changed, 136 insertions, 12 deletions
diff --git a/drivers/accessory/30pin_con.c b/drivers/accessory/30pin_con.c index 3ecaa62..0014afb 100644 --- a/drivers/accessory/30pin_con.c +++ b/drivers/accessory/30pin_con.c @@ -67,10 +67,15 @@ struct acc_con_info { struct switch_dev ear_jack_switch; struct wake_lock wake_lock; struct s3c_adc_client *padc; + struct sec_30pin_callbacks callbacks; enum accessory_type current_accessory; + enum accessory_type univ_kdb_accessory; enum dock_type current_dock; int accessory_irq; int dock_irq; + int cable_type; + int cable_sub_type; + int cable_pwr_type; #if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290) int mhl_irq; bool mhl_pwr_state; @@ -81,7 +86,7 @@ struct acc_con_info { }; #if defined(CONFIG_STMPE811_ADC) -#ifdef CONFIG_MACH_P4NOTE +#if defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_KONA) #define ACCESSORY_ID_ADC_CH 7 #else #define ACCESSORY_ID_ADC_CH 0 @@ -138,6 +143,8 @@ static int acc_get_accessory_id(struct acc_con_info *acc) for (i = 0; i < 5; i++) { adc_val = acc_get_adc_accessroy_id(acc->padc); + ACC_CONDEV_DBG("ACCESSORY_ID adc_val[%d] value = %d", + i, adc_val); adc_buff[i] = adc_val; adc_sum += adc_buff[i]; if (i == 0) { @@ -151,7 +158,8 @@ static int acc_get_accessory_id(struct acc_con_info *acc) } msleep(20); } - adc = (adc_sum - adc_max - adc_min)/3; + /* adc = (adc_sum - adc_max - adc_min)/3; */ + adc = adc_buff[4]; ACC_CONDEV_DBG("ACCESSORY_ID ADC value = %d", adc); return (int)adc; } @@ -323,7 +331,7 @@ static void acc_dock_psy(struct acc_con_info *acc) union power_supply_propval value; /* only support p4note(high current charging) */ -#ifndef CONFIG_MACH_P4NOTE +#if !defined(CONFIG_MACH_P4NOTE) && !defined(CONFIG_MACH_KONA) return; #endif @@ -332,17 +340,65 @@ static void acc_dock_psy(struct acc_con_info *acc) return; } - value.intval = acc->current_dock; + value.intval = 0; + value.intval = (acc->cable_type << 16) + (acc->cable_sub_type << 8) + + (acc->cable_pwr_type << 0); + pr_info("[BATT]30 cx(%d), sub(%d), pwr(%d)\n", + acc->cable_type, acc->cable_sub_type, acc->cable_pwr_type); + psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &value); } +void acc_otg_enable_by_univkbd(struct acc_con_info *acc, bool val) +{ + char *env_ptr; + char *stat_ptr; + char *envp[3]; + + if (val == true) { + if (acc->univ_kdb_accessory == ACCESSORY_NONE) { + env_ptr = "ACCESSORY=OTG"; + stat_ptr = "STATE=online"; + acc->univ_kdb_accessory = ACCESSORY_OTG; + + if (acc->pdata->usb_ldo_en) + acc->pdata->usb_ldo_en(1); + if (acc->pdata->otg_en) + acc->pdata->otg_en(1); + + envp[0] = env_ptr; + envp[1] = stat_ptr; + envp[2] = NULL; + kobject_uevent_env(&acc->acc_dev->kobj, + KOBJ_CHANGE, envp); + ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr); + } + } else { + if (acc->univ_kdb_accessory == ACCESSORY_OTG) { + env_ptr = "ACCESSORY=OTG"; + stat_ptr = "STATE=offline"; + + envp[0] = env_ptr; + envp[1] = stat_ptr; + envp[2] = NULL; + kobject_uevent_env(&acc->acc_dev->kobj, + KOBJ_CHANGE, envp); + ACC_CONDEV_DBG("%s : %s", env_ptr, stat_ptr); + + if (acc->pdata->otg_en) + acc->pdata->otg_en(0); + + acc->univ_kdb_accessory = ACCESSORY_NONE; + } + } +} + static void acc_check_dock_detection(struct acc_con_info *acc) { if (NULL == acc->pdata->get_dock_state) { ACC_CONDEV_DBG("[30PIN] failed to get acc state!!!"); return; } - if (!acc->pdata->get_dock_state()) { #ifdef CONFIG_SEC_KEYBOARD_DOCK if (acc->pdata->check_keyboard && @@ -355,16 +411,20 @@ static void acc_check_dock_detection(struct acc_con_info *acc) acc->current_dock = DOCK_KEYBOARD; ACC_CONDEV_DBG - ("[30PIN] keyboard dock station attached!!!"); + ("The dock proves to be a keyboard dock..!"); switch_set_state(&acc->dock_switch, UEVENT_DOCK_KEYBOARD); + acc->cable_type = POWER_SUPPLY_TYPE_DOCK; + acc->cable_sub_type = ONLINE_SUB_TYPE_DESK; } else #endif { ACC_CONDEV_DBG - ("[30PIN] desktop dock station attached!!!"); + ("The dock proves to be a desktop dock..!"); switch_set_state(&acc->dock_switch, UEVENT_DOCK_DESK); acc->current_dock = DOCK_DESK; + acc->cable_type = POWER_SUPPLY_TYPE_DOCK; + acc->cable_sub_type = ONLINE_SUB_TYPE_DESK; #if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290) mutex_lock(&acc->lock); @@ -382,12 +442,21 @@ static void acc_check_dock_detection(struct acc_con_info *acc) acc_dock_uevent(acc, true); } else { - ACC_CONDEV_DBG("[30PIN] dock station detached!!!"); + ACC_CONDEV_DBG("dock station detached.. !"); switch_set_state(&acc->dock_switch, UEVENT_DOCK_NONE); + acc->current_dock = DOCK_NONE; + acc->cable_type = POWER_SUPPLY_TYPE_BATTERY; + acc->cable_sub_type = ONLINE_SUB_TYPE_UNKNOWN; #ifdef CONFIG_SEC_KEYBOARD_DOCK if (acc->pdata->check_keyboard) acc->pdata->check_keyboard(false); + if (acc->univ_kdb_accessory == ACCESSORY_OTG) { + acc_otg_enable_by_univkbd(acc, false); + acc->current_dock = DOCK_NONE; + acc->cable_type = POWER_SUPPLY_TYPE_BATTERY; + acc->cable_sub_type = ONLINE_SUB_TYPE_UNKNOWN; + } #endif #if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290) /*call MHL deinit */ @@ -400,11 +469,9 @@ static void acc_check_dock_detection(struct acc_con_info *acc) acc->mhl_pwr_state = false; } #endif - /*TVout_LDO_ctrl(false); */ acc_dock_uevent(acc, false); } - acc_dock_psy(acc); } @@ -412,6 +479,8 @@ static irqreturn_t acc_dock_isr(int irq, void *ptr) { struct acc_con_info *acc = ptr; wake_lock(&acc->wake_lock); + ACC_CONDEV_DBG + ("A dock station attached or detached.."); acc_check_dock_detection(acc); wake_unlock(&acc->wake_lock); return IRQ_HANDLED; @@ -506,6 +575,48 @@ err_irq_dock: return ; } +static int acc_noti_univkbd_dock(struct sec_30pin_callbacks *cb, + unsigned int code) +{ + struct acc_con_info *acc = + container_of(cb, struct acc_con_info, callbacks); + + char *env_ptr; + char *stat_ptr; + char *envp[3]; + + ACC_CONDEV_DBG("universal keyboard noti. callback 0x%x", code); + + switch (code) { + case 0x68: /*dock is con*/ + acc_otg_enable_by_univkbd(acc, true); + acc->cable_type = POWER_SUPPLY_TYPE_DOCK; + acc->cable_sub_type = ONLINE_SUB_TYPE_KBD; + acc_dock_psy(acc); + break; + case 0x69: /*usb charging*/ + acc->cable_pwr_type = ONLINE_POWER_TYPE_USB; + acc_dock_psy(acc); + break; + case 0x6a: /*USB cable attached */ + acc_otg_enable_by_univkbd(acc, false); + acc->cable_pwr_type = ONLINE_POWER_TYPE_USB; + acc_dock_psy(acc); + break; + case 0x6b: /*TA connection*/ + acc->cable_pwr_type = ONLINE_POWER_TYPE_TA; + acc_dock_psy(acc); + break; + case 0x6c: /* USB cable detached */ + acc_otg_enable_by_univkbd(acc, true); + acc->cable_pwr_type = ONLINE_POWER_TYPE_BATTERY; + acc_dock_psy(acc); + break; + } + + return 0; +} + static void acc_dwork_accessory_detect(struct work_struct *work) { struct acc_con_info *acc = container_of(work, @@ -513,6 +624,7 @@ static void acc_dwork_accessory_detect(struct work_struct *work) int adc_val = 0; int acc_state = 0; + int acc_state2 = 0; acc_state = acc->pdata->get_acc_state(); @@ -520,9 +632,16 @@ static void acc_dwork_accessory_detect(struct work_struct *work) ACC_CONDEV_DBG("Accessory detached"); acc_accessory_uevent(acc, false); } else { - ACC_CONDEV_DBG("Accessory attached"); adc_val = acc_get_accessory_id(acc); + + acc_state2 = acc->pdata->get_acc_state(); + if (acc_state2) { + ACC_CONDEV_DBG("Accessory detached2."); + acc_accessory_uevent(acc, false); + } else { + ACC_CONDEV_DBG("Accessory attached"); acc_accessory_uevent(acc, adc_val); + } } } @@ -544,7 +663,7 @@ static int acc_con_probe(struct platform_device *pdev) } #ifdef CONFIG_REGULATOR -#ifndef CONFIG_MACH_P4NOTE +#if !defined(CONFIG_MACH_P4NOTE) && !defined(CONFIG_MACH_KONA) /* LDO1 regulator ON */ vadc_regulator = regulator_get(&pdev->dev, "vadc_3.3v"); if (IS_ERR(vadc_regulator)) { @@ -563,6 +682,7 @@ static int acc_con_probe(struct platform_device *pdev) acc->pdata = pdata; acc->current_dock = DOCK_NONE; acc->current_accessory = ACCESSORY_NONE; + acc->univ_kdb_accessory = ACCESSORY_NONE; #if defined(CONFIG_MHL_SII9234) || defined(CONFIG_SAMSUNG_MHL_9290) acc->mhl_irq = gpio_to_irq(pdata->mhl_irq_gpio); acc->mhl_pwr_state = false; @@ -580,6 +700,10 @@ static int acc_con_probe(struct platform_device *pdev) acc->padc = s3c_adc_register(pdev, NULL, NULL, 0); #endif + acc->callbacks.noti_univ_kdb_dock = acc_noti_univkbd_dock; + if (pdata->register_cb) + pdata->register_cb(&acc->callbacks); + #ifdef CONFIG_MHL_SII9234 retval = i2c_add_driver(&SII9234A_i2c_driver); if (retval) { |