static int smb347_shutdown(struct i2c_client *client) { int ret; printk("smb347_shutdown+\n"); cancel_delayed_work(&charger->curr_limit_work); smb347_set_InputCurrentlimit(charger->client, 1800); /* Disable OTG */ ret = smb347_configure_otg(client, 0); if (ret < 0) dev_err(&client->dev, "%s() error in configuring" "otg..\n", __func__); /* configure charger */ ret = smb347_configure_charger(client, 1); if (ret < 0) dev_err(&client->dev, "%s() error in configuring" "otg..\n", __func__); printk("smb347_shutdown-\n"); return 0; }
static int __devinit smb347_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret, irq_num; uint8_t buf[15]; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; charger = kzalloc(sizeof(*charger), GFP_KERNEL); if (!charger) return -ENOMEM; charger->client = client; charger->dev = &client->dev; i2c_set_clientdata(client, charger); /* disable STAT pin IRQ */ smb347_intr_sts(charger->client); ret = sysfs_create_group(&client->dev.kobj, &smb347_group); if (ret) { dev_err(&client->dev, "smb347_probe: unable to create the sysfs\n"); } mutex_init(&charger->cable_lock); smb347_wq = create_singlethread_workqueue("smb347_wq"); INIT_DELAYED_WORK_DEFERRABLE(&charger->inok_isr_work, inok_isr_work_function); INIT_DELAYED_WORK_DEFERRABLE(&charger->cable_det_work, cable_type_detect); wake_lock_init(&charger_wakelock, WAKE_LOCK_SUSPEND, "charger_configuration"); wake_lock_init(&charger_ac_detec_wakelock, WAKE_LOCK_SUSPEND, "charger_ac_detec_wakelock"); INIT_DELAYED_WORK(&charger->curr_limit_work, smb347_set_curr_limit_work_func); INIT_DELAYED_WORK(&charger->test_fail_clear_work, smb347_test_fail_clear_work_function); charger->curr_limit = UINT_MAX; smb347_set_InputCurrentlimit(charger->client, 900); charger->cur_cable_type = non_cable; charger->old_cable_type = non_cable; charger->test_1800mA_fail = 0; ret = smb347_inok_irq(charger); if (ret) { dev_err(&client->dev, "%s(): Failed in requesting ACOK# pin isr\n", __func__); goto error; } queue_delayed_work(smb347_wq, &charger->cable_det_work, 0.5*HZ); ret = register_otg_callback(smb347_otg_status, charger); if (ret < 0) goto error; smb347_charger_status = 1; return 0; error: kfree(charger); return ret; }
static void smb347_set_curr_limit_work_func(struct work_struct *work) { smb347_set_InputCurrentlimit(charger->client, 1800); }
/* workqueue function */ static int cable_type_detect(void) { struct i2c_client *client = charger->client; u8 retval; int success = 0; int ac_ok = GPIO_AC_OK; /* printk("cable_type_detect %d %lu %d %x jiffies=%lu %lu+\n", charger->old_cable_type, charger->time_of_1800mA_limit, gpio_get_value(gpio), time_after(charger->time_of_1800mA_limit+(4*HZ), jiffies ), jiffies, charger->time_of_1800mA_limit+(ADAPTER_PROTECT_DELAY*HZ)); */ mutex_lock(&charger->cable_lock); if ((charger->old_cable_type == ac_cable) && charger->time_of_1800mA_limit && gpio_get_value(ac_ok) && time_after(charger->time_of_1800mA_limit+ ADAPTER_PROTECT_DELAY, jiffies)) { smb347_set_InputCurrentlimit(client, 900); charger->test_1800mA_fail = 1; queue_delayed_work(smb347_wq, &charger->test_fail_clear_work, 1*HZ); } if (gpio_get_value(ac_ok)) { printk(KERN_INFO "INOK=H\n"); charger->cur_cable_type = non_cable; smb347_set_InputCurrentlimit(client, 900); success = bq27541_battery_callback(non_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(non_cable); #endif wake_unlock(&charger_wakelock); } else { printk(KERN_INFO "INOK=L\n"); /* cable type dection */ retval = smb347_read(client, smb347_STS_REG_E); SMB_NOTICE("Reg3F : 0x%02x\n", retval); if (retval & USBIN) { retval = smb347_read(client, smb347_STS_REG_D); SMB_NOTICE("Reg3E : 0x%02x\n", retval); if (retval & APSD_OK) { retval &= APSD_RESULT; if (retval == APSD_CDP) { printk(KERN_INFO "Cable: CDP\n"); charger->cur_cable_type = ac_cable; success = bq27541_battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif } else if (retval == APSD_DCP) { printk(KERN_INFO "Cable: DCP\n"); charger->cur_cable_type = ac_cable; success = bq27541_battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif } else if (retval == APSD_OTHER) { charger->cur_cable_type = ac_cable; success = bq27541_battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif printk(KERN_INFO "Cable: OTHER\n"); } else if (retval == APSD_SDP) { printk(KERN_INFO "Cable: SDP\n"); charger->cur_cable_type = usb_cable; success = bq27541_battery_callback(usb_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(usb_cable); #endif } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "Unkown Plug In Cable type !\n"); if(ac_cable == cable_state_detect) { charger->cur_cable_type = ac_cable; success = bq27541_battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif printk(KERN_INFO "Change unknow type to ac\n"); } else if(usb_cable == cable_state_detect) { charger->cur_cable_type = usb_cable; success = bq27541_battery_callback(usb_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(usb_cable); #endif printk(KERN_INFO "Change unknow type to usb\n"); } } } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "APSD not completed\n"); } } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "USBIN=0\n"); } } if (charger->cur_cable_type == ac_cable && charger->old_cable_type != ac_cable && charger->test_1800mA_fail == 0) { wake_lock(&charger_wakelock); queue_delayed_work(smb347_wq, &charger->curr_limit_work, DELAY_FOR_CURR_LIMIT_RECONF*HZ); } charger->old_cable_type = charger->cur_cable_type; mutex_unlock(&charger->cable_lock); return success; }
/* workqueue function */ static int cable_type_detect(void) { struct i2c_client *client = charger->client; u8 retval; int success = 0; int ac_ok = GPIO_AC_OK; int dock_in = gpio_dock_in; /* printk("cable_type_detect %d %lu %d %x jiffies=%lu %lu+\n", charger->old_cable_type, charger->time_of_1800mA_limit, gpio_get_value(gpio), time_after(charger->time_of_1800mA_limit+(4*HZ), jiffies ), jiffies, charger->time_of_1800mA_limit+(ADAPTER_PROTECT_DELAY*HZ)); */ if((pcba_ver <= GROUPER_PCBA_ER2) && (project_id == GROUPER_PROJECT_NAKASI)) return 0; mutex_lock(&charger->cable_lock); if ((charger->old_cable_type == ac_cable) && charger->time_of_1800mA_limit && gpio_get_value(ac_ok) && time_after(charger->time_of_1800mA_limit+ ADAPTER_PROTECT_DELAY, jiffies)) { smb347_set_InputCurrentlimit(client, 900); charger->test_1800mA_fail = 1; queue_delayed_work(smb347_wq, &charger->test_fail_clear_work, 1*HZ); } if (gpio_get_value(ac_ok)) { printk(KERN_INFO "INOK=H\n"); charger->cur_cable_type = non_cable; smb347_set_InputCurrentlimit(client, 900); success = battery_callback(non_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(non_cable); #endif wake_unlock(&charger_wakelock); } else { printk(KERN_INFO "INOK=L\n"); retval = smb347_read(client, smb347_INTR_STS_E); SMB_NOTICE("Reg39 : 0x%02x\n", retval); if (!(retval & DCIN_OV_UV_STS) && !gpio_get_value(dock_in)) { SMB_NOTICE("DC_IN\n"); success = battery_callback(ac_cable); } else { /* cable type dection */ retval = smb347_read(client, smb347_STS_REG_E); SMB_NOTICE("Reg3F : 0x%02x\n", retval); if (retval & USBIN) { SMB_NOTICE("USB_IN\n"); retval = smb347_read(client, smb347_STS_REG_D); SMB_NOTICE("Reg3E : 0x%02x\n", retval); if (retval & APSD_OK) { retval &= APSD_RESULT; if (retval == APSD_CDP) { printk(KERN_INFO "Cable: CDP\n"); charger->cur_cable_type = ac_cable; success = battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif } else if (retval == APSD_DCP) { printk(KERN_INFO "Cable: DCP\n"); charger->cur_cable_type = ac_cable; success = battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif } else if (retval == APSD_OTHER) { charger->cur_cable_type = ac_cable; success = battery_callback(ac_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(ac_cable); #endif printk(KERN_INFO "Cable: OTHER\n"); } else if (retval == APSD_SDP) { printk(KERN_INFO "Cable: SDP\n"); charger->cur_cable_type = usb_cable; success = battery_callback(usb_cable); #ifdef TOUCH_CALLBACK_ENABLED touch_callback(usb_cable); #endif } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "Unkown Plug In Cable type !\n"); if(usb_det_cable_type) { printk(KERN_INFO "Use usb det %s cable to report\n", (usb_det_cable_type == ac_cable) ? "ac" : "usb"); charger->cur_cable_type = usb_det_cable_type; success = battery_callback(usb_det_cable_type); } } } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "APSD not completed\n"); } } else { charger->cur_cable_type = unknow_cable; printk(KERN_INFO "USBIN=0\n"); } } } if (charger->cur_cable_type == ac_cable && charger->old_cable_type != ac_cable && charger->test_1800mA_fail == 0) { wake_lock(&charger_wakelock); queue_delayed_work(smb347_wq, &charger->curr_limit_work, DELAY_FOR_CURR_LIMIT_RECONF*HZ); } charger->old_cable_type = charger->cur_cable_type; mutex_unlock(&charger->cable_lock); return success; }