static void dockin_isr_work_function(struct work_struct *dat) { struct i2c_client *client = charger->client; int dock_in = gpio_dock_in; int ac_ok = GPIO_AC_OK; wake_lock(&charger->wake_lock_dockin); mutex_lock(&charger->dockin_lock); if (gpio_get_value(dock_in)) { if (!gpio_get_value(ac_ok)) { SMB_NOTICE("dc_in=H & ac_ok=L\n"); cable_type_detect(); } } else { if (!gpio_get_value(ac_ok)) { SMB_NOTICE("dc_in=L & ac_ok=L\n"); msleep(40); cable_type_detect(); } } mutex_unlock(&charger->dockin_lock); wake_unlock(&charger->wake_lock_dockin); }
/* workqueue function */ static int cable_type_detect(void) { struct i2c_client *client = charger->client; u8 retval; int success = 0; int gpio = TEGRA_GPIO_PV1; if(grouper_query_pcba_revision() <= 0x02) return 0; mutex_lock(&charger->cable_lock); if (gpio_get_value(gpio)) { printk("INOK=H\n"); success = battery_callback(non_cable); } else { printk("INOK=L\n"); /* cable type dection */ retval = smb347_read(client, smb347_STS_REG_E); SMB_NOTICE("Reg3F : 0x%02x\n", retval); if(retval & USBIN) { //USBIN retval = smb347_read(client, smb347_STS_REG_D); SMB_NOTICE("Reg3E : 0x%02x\n", retval); if(retval & APSD_OK) { //APSD completed retval &= APSD_RESULT; if(retval == APSD_CDP) { //APSD resulted printk("Cable: CDP\n"); success = battery_callback(ac_cable); } else if(retval == APSD_DCP) { printk("Cable: DCP\n"); success = battery_callback(ac_cable); } else if(retval == APSD_OTHER) { printk("Cable: OTHER\n"); } else if(retval == APSD_SDP) { printk("Cable: SDP\n"); success = battery_callback(usb_cable); } else printk("Unkown Plug In Cable type !\n"); }else printk("APSD not completed\n"); } else { printk("USBIN=0\n"); } } mutex_unlock(&charger->cable_lock); return success; }
void smb345_otg_status(bool on) { struct i2c_client *client = charger->client; int ret; SMB_NOTICE("otg function: %s\n", on ? "on" : "off"); if (on) { otg_on = true; /* ENABLE OTG */ ret = smb345_configure_otg(client); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring" "otg..\n", __func__); return; } if (wireless_is_plugged()) wireless_reset(); return; } else otg_on = false; if (wireless_is_plugged()) wireless_set(); }
static int smb345_inok_irq(struct smb345_charger *smb) { int err = 0 ; unsigned gpio = GPIO_AC_OK; unsigned irq_num = gpio_to_irq(gpio); err = gpio_request(gpio, "smb345_inok"); if (err) { SMB_ERR("gpio %d request failed \n", gpio); } err = gpio_direction_input(gpio); if (err) { SMB_ERR("gpio %d unavaliable for input \n", gpio); } err = request_irq(irq_num, smb345_inok_isr, IRQF_TRIGGER_FALLING |IRQF_TRIGGER_RISING|IRQF_SHARED, "smb345_inok", smb); if (err < 0) { SMB_ERR("%s irq %d request failed \n","smb345_inok", irq_num); goto fault ; } enable_irq_wake(irq_num); SMB_NOTICE("GPIO pin irq %d requested ok, smb345_INOK = %s\n", irq_num, gpio_get_value(gpio)? "H":"L"); return 0; fault: gpio_free(gpio); return err; }
static void wireless_isr_work_function(struct work_struct *dat) { if (delayed_work_pending(&charger->wireless_isr_work)) cancel_delayed_work(&charger->wireless_isr_work); SMB_NOTICE("wireless state = %d\n", wireless_is_plugged()); if (otg_on) { SMB_NOTICE("bypass wireless isr due to otg_on\n"); return; } if (wireless_is_plugged()) wireless_set(); else wireless_reset(); }
void usb_det_cable_callback(unsigned cable_type) { usb_det_cable_type = cable_type; SMB_NOTICE("usb_det_cable_type=%d\n", usb_det_cable_type); if(unknow_cable == charger->cur_cable_type) { cable_type_detect(); } }
static void wireless_det_work_function(struct work_struct *dat) { if (otg_on) { SMB_NOTICE("bypass wireless isr due to otg_on\n"); return; } if (wireless_is_plugged()) wireless_set(); }
void reconfig_AICL(void) { struct i2c_client *client = charger->client; if (ac_on && !gpio_get_value(GPIO_AC_OK)) { int retval; retval = smb345_read(client, smb345_STS_REG_E); if (retval < 0) dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_STS_REG_E); else { SMB_NOTICE("Status Reg E=0x%02x\n", retval); if ((retval & 0xF) <= 0x1) { SMB_NOTICE("reconfig input current limit\n"); smb345_set_InputCurrentlimit(client, 1200); } } } }
static void wireless_isr_work_function(struct work_struct *dat) { if (delayed_work_pending(&charger->wireless_isr_work)) cancel_delayed_work(&charger->wireless_isr_work); SMB_NOTICE("wireless state = %d\n", wireless_is_plugged()); if (wireless_is_plugged()) wireless_set(); else wireless_reset(); }
int smb345_config_thermal_limit(void) { struct i2c_client *client = charger->client; int ret = 0, retval, setting = 0; ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } retval = smb345_read(client, smb345_HRD_SFT_TEMP); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_HRD_SFT_TEMP); goto error; } setting = retval & HOT_LIMIT_MASK; if (setting != 0x33) { setting = retval & (~HOT_LIMIT_MASK); setting |= 0x33; SMB_NOTICE("Set HRD SFT limit, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_HRD_SFT_TEMP, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_HRD_SFT_TEMP); goto error; } } else SMB_NOTICE("Bypass set HRD SFT limit=%x\n", retval); ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } error: return ret; }
int smb345_vflt_setting(void) { struct i2c_client *client = charger->client; u8 ret = 0, setting; ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in smb345 volatile writes \n", __func__); goto error; } ret = smb345_read(client, smb345_FLOAT_VLTG); if (ret < 0) { dev_err(&client->dev, "%s() error in smb345 read \n", __func__); goto error; } setting = ret & FLOAT_VOLT_MASK; if (setting != FLOAT_VOLT_43V) { setting = ret & (~FLOAT_VOLT_MASK); setting |= FLOAT_VOLT_43V; SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", ret, setting); ret = smb345_write(client, smb345_FLOAT_VLTG, setting); if (ret < 0) { dev_err(&client->dev, "%s() error in smb345 write \n", __func__); goto error; } } else SMB_NOTICE("Bypass set Float Volt=%x\n", ret); ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in smb345 volatile writes \n", __func__); goto error; } error: return ret; }
static void cable_det_work_function(struct work_struct *dat) { struct i2c_client *client = charger->client; if (delayed_work_pending(&charger->cable_det_work)) cancel_delayed_work(&charger->cable_det_work); if (ac_on && !gpio_get_value(GPIO_AC_OK)) { int retval; retval = smb345_read(client, smb345_STS_REG_E); if (retval < 0) dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_STS_REG_E); else { SMB_NOTICE("Status Reg E=0x02%x\n", retval); if ((retval & 0xF) <= 0x1) { SMB_NOTICE("reconfig input current limit\n"); smb345_set_InputCurrentlimit(client, 1200); } } } }
static irqreturn_t smb345_inok_isr(int irq, void *dev_id) { struct smb345_charger *smb = dev_id; int status = gpio_get_value(GPIO_AC_OK); SMB_NOTICE("VBUS_DET = %s\n", status ? "H" : "L"); if (ac_on && !status) queue_delayed_work(smb345_wq, &smb->cable_det_work, 0); else { if (delayed_work_pending(&charger->cable_det_work)) cancel_delayed_work(&charger->cable_det_work); } return IRQ_HANDLED; }
static int __init smb347_init(void) { project_id = grouper_get_project_id(); pcba_ver = grouper_query_pcba_revision(); u32 project_info = grouper_get_project_id(); if (project_info == GROUPER_PROJECT_NAKASI_3G) gpio_dock_in = TEGRA_GPIO_PO5; else gpio_dock_in = TEGRA_GPIO_PU4; SMB_NOTICE("project_id=%x, pcba_ver=%d, dock_in_gpio=%d\n", project_id, pcba_ver, gpio_dock_in); return i2c_add_driver(&smb347_i2c_driver); }
static int smb345_wireless_en_config(struct smb345_charger *smb) { int err = 0 ; err = gpio_request(charger->wpc_en1, "WPC_EN1"); if (err) return -ENODEV; err = gpio_request(charger->wpc_en2, "WPC_EN2"); if (err) goto fault; gpio_set_value(charger->wpc_en1, 0); gpio_set_value(charger->wpc_en2, 0); SMB_NOTICE("GPIO pin %d, %d requested ok, wpc_en1 = %s, wpc_en2 = %s\n", charger->wpc_en1, charger->wpc_en2, gpio_get_value(charger->wpc_en1) ? "H" : "L", gpio_get_value(charger->wpc_en2) ? "H" : "L"); return 0; fault: gpio_free(charger->wpc_en1); return err; }
/* 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; }
int usb_cable_type_detect(unsigned int chgr_type) { struct i2c_client *client = charger->client; int success = 0; mutex_lock(&charger->usb_lock); if (chgr_type == CHARGER_NONE) { SMB_NOTICE("INOK=H\n"); if (wpc_en) { if (disable_DCIN) { SMB_NOTICE("enable wpc_pok, enable DCIN\n"); disable_DCIN = false; enable_irq_wake(gpio_to_irq(charger->wpc_pok_gpio)); enable_irq(gpio_to_irq(charger->wpc_pok_gpio)); gpio_set_value(charger->wpc_en1, 0); gpio_set_value(charger->wpc_en2, 0); } } success = bq27541_battery_callback(non_cable); touch_callback(non_cable); } else { SMB_NOTICE("INOK=L\n"); if (chgr_type == CHARGER_SDP) { SMB_NOTICE("Cable: SDP\n"); smb345_vflt_setting(); success = bq27541_battery_callback(usb_cable); touch_callback(usb_cable); } else { if (chgr_type == CHARGER_CDP) { SMB_NOTICE("Cable: CDP\n"); } else if (chgr_type == CHARGER_DCP) { SMB_NOTICE("Cable: DCP\n"); } else if (chgr_type == CHARGER_OTHER) { SMB_NOTICE("Cable: OTHER\n"); } else if (chgr_type == CHARGER_ACA) { SMB_NOTICE("Cable: ACA\n"); } else { SMB_NOTICE("Cable: TBD\n"); smb345_vflt_setting(); success = bq27541_battery_callback(usb_cable); touch_callback(usb_cable); goto done; } smb345_set_InputCurrentlimit(client, 1200); smb345_vflt_setting(); success = bq27541_battery_callback(ac_cable); touch_callback(ac_cable); if (wpc_en) { if (delayed_work_pending(&charger->wireless_set_current_work)) cancel_delayed_work(&charger->wireless_set_current_work); if (!disable_DCIN) { SMB_NOTICE("AC cable detect, disable wpc_pok, disable DCIN"); disable_DCIN = true; disable_irq(gpio_to_irq(charger->wpc_pok_gpio)); disable_irq_wake(gpio_to_irq(charger->wpc_pok_gpio)); gpio_set_value(charger->wpc_en1, 1); gpio_set_value(charger->wpc_en2, 1); mdelay(200); if (wireless_on) wireless_reset(); } } } } done: mutex_unlock(&charger->usb_lock); return success; }
static irqreturn_t smb345_inok_isr(int irq, void *dev_id) { SMB_NOTICE("VBUS_DET = %s\n", gpio_get_value(GPIO_AC_OK) ? "H" : "L"); return IRQ_HANDLED; }
int smb345_set_WCInputCurrentlimit(struct i2c_client *client, u32 current_setting) { int ret = 0, retval; u8 setting; charger->wpc_curr_limit_count++; ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } if (current_setting != 0) { retval = smb345_read(client, smb345_CHRG_CRNTS); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_CHRG_CRNTS); goto error; } setting = retval & 0x0F; if (current_setting == 2000) setting |= 0x70; else if (current_setting == 1800) setting |= 0x60; else if (current_setting == 1200) setting |= 0x40; else if (current_setting == 900) setting |= 0x30; else if (current_setting == 700) setting |= 0x20; else if (current_setting == 500) setting |= 0x10; else if (current_setting == 300) setting |= 0x00; else setting |= 0x20; SMB_NOTICE("Set ICL=%u retval =%x setting=%x\n", current_setting, retval, setting); ret = smb345_write(client, smb345_CHRG_CRNTS, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_CHRG_CRNTS); goto error; } charger->wpc_curr_limit = current_setting; } if (current_setting == 300) { retval = smb345_read(client, smb345_VRS_FUNC); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_VRS_FUNC); goto error; } setting = retval & (~(BIT(4))); SMB_NOTICE("Disable AICL, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_VRS_FUNC, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_VRS_FUNC); goto error; } } ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } error: return ret; }
int smb345_config_thermal_charging(int temp, int volt, int rule) { struct i2c_client *client = charger->client; int ret = 0, retval, setting = 0; int BAT_Mid_Temp = BAT_Mid_Temp_Wired; if (rule == THERMAL_RULE1) BAT_Mid_Temp = BAT_Mid_Temp_Wired; else if (rule == THERMAL_RULE2) BAT_Mid_Temp = BAT_Mid_Temp_Wireless; smb345_config_thermal_limit(); SMB_NOTICE("temp=%d, volt=%d\n", temp, volt); ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } /*control float voltage*/ retval = smb345_read(client, smb345_FLOAT_VLTG); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_FLOAT_VLTG); goto error; } setting = retval & FLOAT_VOLT_MASK; if (temp <= BAT_Mid_Temp || (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL) || temp > BAT_Hot_Limit) { if (setting != FLOAT_VOLT_43V) { setting = retval & (~FLOAT_VOLT_MASK); setting |= FLOAT_VOLT_43V; SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_FLOAT_VLTG, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_FLOAT_VLTG); goto error; } } else SMB_NOTICE("Bypass set Float Volt=%x\n", retval); } else { if (setting != FLOAT_VOLT_LOW) { setting = retval & (~FLOAT_VOLT_MASK); setting |= FLOAT_VOLT_LOW; SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_FLOAT_VLTG, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_FLOAT_VLTG); goto error; } } else SMB_NOTICE("Bypass set Float Volt=%x\n", retval); } /*charger enable/disable*/ retval = smb345_read(client, smb345_PIN_CTRL); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_PIN_CTRL); goto error; } setting = retval & ENABLE_PIN_CTRL_MASK; if (temp < BAT_Cold_Limit || temp > BAT_Hot_Limit || (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)) { if (setting != 0x40) { SMB_NOTICE("Charger disable\n"); smb345_charger_enable(false); } else SMB_NOTICE("Bypass charger disable\n"); } else { if (setting != 0x60) { SMB_NOTICE("Charger enable\n"); smb345_charger_enable(true); } else { /*interrupt status*/ retval = smb345_read(client, smb345_INTR_STS_B); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_INTR_STS_B); goto error; } if ((retval & BAT_OVER_VOLT_MASK) == 0x40) { SMB_NOTICE("disable then enable charger to recover bat over-volt\n"); smb345_charger_enable(false); smb345_charger_enable(true); } else SMB_NOTICE("Bypass charger enable\n"); } } ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } error: return ret; }
int smb345_set_InputCurrentlimit(struct i2c_client *client, u32 current_setting) { int ret = 0, retval; u8 setting = 0; wake_lock(&charger_wakelock); ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } if (charge_en_flag) smb345_pin_control(0); retval = smb345_read(client, smb345_VRS_FUNC); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_VRS_FUNC); goto error; } setting = retval & (~(BIT(4))); SMB_NOTICE("Disable AICL, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_VRS_FUNC, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_VRS_FUNC); goto error; } retval = smb345_read(client, smb345_CHRG_CRNTS); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_CHRG_CRNTS); goto error; } setting = retval & 0xF0; if(current_setting == 2000) setting |= 0x07; else if(current_setting == 1800) setting |= 0x06; else if (current_setting == 1200) setting |= 0x04; else if(current_setting == 900) setting |= 0x03; else if(current_setting == 500) setting |= 0x01; else setting |= 0x07; SMB_NOTICE("Set ICL=%u retval =%x setting=%x\n", current_setting, retval, setting); ret = smb345_write(client, smb345_CHRG_CRNTS, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_CHRG_CRNTS); goto error; } if(current_setting == 2000) charger->curr_limit = 2000; else if(current_setting == 1800) charger->curr_limit = 1800; else if (current_setting == 1200) charger->curr_limit = 1200; else if(current_setting == 900) charger->curr_limit = 900; else if(current_setting == 500) charger->curr_limit = 500; else charger->curr_limit = 2000; if (current_setting > 900) { charger->time_of_1800mA_limit = jiffies; } else{ charger->time_of_1800mA_limit = 0; } retval = smb345_read(client, smb345_VRS_FUNC); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_VRS_FUNC); goto error; } setting = retval | BIT(4); SMB_NOTICE("Re-enable AICL, setting=%x\n", setting); msleep(20); ret = smb345_write(client, smb345_VRS_FUNC, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_VRS_FUNC); goto error; } if (charge_en_flag) smb345_pin_control(1); ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() error in configuring charger..\n", __func__); goto error; } error: wake_unlock(&charger_wakelock); return ret; }
/* 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; }
int smb345_config_thermal_charging(int temp, int volt, int rule) { struct i2c_client *client = charger->client; int ret = 0, retval, setting = 0; int BAT_Mid_Temp = BAT_Mid_Temp_Wired; /*Charger float voltage for normal temperature conditions. Default 4.3V.*/ int flt_volt_43 = FLOAT_VOLT_43V; /*Charger float voltage for high temperature conditions. Default 4.1V.*/ int flt_volt_low = FLOAT_VOLT_LOW; flt_volt_43 = (float_volt_setting - 3500) / 20; if(flt_volt_43 < 0 || flt_volt_43 > FLOAT_VOLT_43V) { SMB_NOTICE("BUG: Invalid float voltage setting calculated: %d\n", flt_volt_43); flt_volt_43 = FLOAT_VOLT_43V; } if(flt_volt_low > flt_volt_43) flt_volt_low = flt_volt_43; if (rule == THERMAL_RULE1) BAT_Mid_Temp = BAT_Mid_Temp_Wired; else if (rule == THERMAL_RULE2) BAT_Mid_Temp = BAT_Mid_Temp_Wireless; mdelay(100); smb345_config_thermal_limit(); SMB_NOTICE("temp=%d, volt=%d\n", temp, volt); ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } /*control float voltage*/ retval = smb345_read(client, smb345_FLOAT_VLTG); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_FLOAT_VLTG); goto error; } setting = retval & FLOAT_VOLT_MASK; if (temp <= BAT_Mid_Temp || (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL) || temp > BAT_Hot_Limit) { if (setting != flt_volt_43) { setting = retval & (~FLOAT_VOLT_MASK); setting |= flt_volt_43; SMB_NOTICE("Set Float Volt, retval=%x setting=%x V=%dmV\n", retval, setting, float_volt_setting); ret = smb345_write(client, smb345_FLOAT_VLTG, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_FLOAT_VLTG); goto error; } } else SMB_NOTICE("Bypass set Float Volt setting=%x V=%dmV\n", retval, float_volt_setting); } else { if (setting != flt_volt_low) { setting = retval & (~FLOAT_VOLT_MASK); setting |= flt_volt_low; SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting); ret = smb345_write(client, smb345_FLOAT_VLTG, setting); if (ret < 0) { dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register" "0x%02x\n", __func__, setting, smb345_FLOAT_VLTG); goto error; } } else SMB_NOTICE("Bypass set Float Volt=%x\n", retval); } /*charger enable/disable*/ retval = smb345_read(client, smb345_PIN_CTRL); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_PIN_CTRL); goto error; } setting = retval & ENABLE_PIN_CTRL_MASK; if (temp < BAT_Cold_Limit || temp > BAT_Hot_Limit || (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)) { if (setting != 0x40) { SMB_NOTICE("Charger disable\n"); smb345_charger_enable(false); } else SMB_NOTICE("Bypass charger disable\n"); } else { if (setting != 0x60) { SMB_NOTICE("Charger enable\n"); smb345_charger_enable(true); } else { /*interrupt status*/ retval = smb345_read(client, smb345_INTR_STS_B); if (retval < 0) { dev_err(&client->dev, "%s(): Failed in reading 0x%02x", __func__, smb345_INTR_STS_B); goto error; } if ((retval & BAT_OVER_VOLT_MASK) == 0x40) { SMB_NOTICE("disable then enable charger to recover bat over-volt\n"); smb345_charger_enable(false); smb345_charger_enable(true); } else SMB_NOTICE("Bypass charger enable\n"); } } ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE); if (ret < 0) { dev_err(&client->dev, "%s() charger enable write error..\n", __func__); goto error; } error: return ret; }