static int rt5025_get_external_temp_index(struct rt5025_swjeita_info *swji) { u8 data[2]; s32 temp = 0; int sect_index; RTINFO("\n"); if (rt5025_reg_block_read(swji->i2c, RT5025_REG_AINH, 2, data) < 0) { pr_err("%s: failed to read ext_temp register\n", __func__); return swji->cur_section; } temp = (data[0]*256+data[1])*61/100; temp = (temp * (-91738) +81521000)/100000; swji->cur_temp = temp; RTINFO("cur_section = %d, cur_temp = %d\n", swji->cur_section, swji->cur_temp); switch (swji->cur_section) { case 0: if (temp < swji->temp[0]+TEMP_TOLERANCE) sect_index = rt5025_sel_external_temp_index(swji); else sect_index = swji->cur_section; break; case 1: if (temp <= swji->temp[0]-TEMP_TOLERANCE || temp >= swji->temp[1]+TEMP_TOLERANCE) sect_index = rt5025_sel_external_temp_index(swji); else sect_index = swji->cur_section; break; case 2: if (temp <= swji->temp[1]-TEMP_TOLERANCE || temp >= swji->temp[2]+TEMP_TOLERANCE) sect_index = rt5025_sel_external_temp_index(swji); else sect_index = swji->cur_section; break; case 3: if (temp <= swji->temp[2]-TEMP_TOLERANCE || temp >= swji->temp[3]+TEMP_TOLERANCE) sect_index = rt5025_sel_external_temp_index(swji); else sect_index = swji->cur_section; break; case 4: if (temp <= swji->temp[3]-TEMP_TOLERANCE) sect_index = rt5025_sel_external_temp_index(swji); else sect_index = swji->cur_section; break; default: sect_index = swji->cur_section; break; } RTINFO("sect_index = %d\n", sect_index); return sect_index; }
static int rt5025_set_exttemp_alert(struct rt5025_swjeita_info *swji, int index) { int ret = 0; RTINFO("index = %d\n", index); switch (index) { case 0: rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]); break; case 1: rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]); rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]); break; case 2: rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]); rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[5]); break; case 3: rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[4]); rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[7]); break; case 4: rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[6]); break; } return ret; }
static int rt5025_exttemp_alert_switch(struct rt5025_swjeita_info *swji, int onoff) { if (!onoff) { rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); } else { switch (swji->cur_section) { case 0: rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 1: rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 2: rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 3: rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 4: rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); break; } } RTINFO("index=%d, onoff=%d\n", swji->cur_section, onoff); return 0; }
static void rt5025_general_irq_handler(void *info, int eventno) { struct rt5025_misc_info *mi = info; RTINFO("eventno=%02d\n", eventno); switch (eventno) { case MISCEVENT_RESETB: dev_warn(mi->dev, "RESETB event trigger\n"); break; case MISCEVENT_KPSHDN: dev_warn(mi->dev, "PwrKey force shdn\n"); break; case MISCEVENT_SYSLV: dev_warn(mi->dev, "syslv event trigger\n"); break; case MISCEVENT_DCDC4LVHV: dev_warn(mi->dev, "DCDC4LVHV event trigger\n"); break; case MISCEVENT_DCDC3LV: dev_warn(mi->dev, "DCDC3LV event trigger\n"); break; case MISCEVENT_DCDC2LV: dev_warn(mi->dev, "DCDC2LV event trigger\n"); break; case MISCEVENT_DCDC1LV: dev_warn(mi->dev, "DCDC2LV event trigger\n"); break; case MISCEVENT_OT: dev_warn(mi->dev, "Over temperature event trigger\n"); break; default: break; } }
static void rt5025_charger_event_callback(uint32_t detected) { RTINFO("charger event detected = 0x%08x\n", detected); if (detected & CHG_EVENT_CHTERMI) { pr_info("charger termination OK\n"); } }
static int __devexit rt5025_swjeita_remove(struct platform_device *pdev) { struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); swji->chip->jeita_info = NULL; kfree(swji); RTINFO("\n"); return 0; }
int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *swji, unsigned char event) { int ret = 0; RTINFO("event = 0x%02x\n", event); if (event&(RT5025_TMXEN_MASK|RT5025_TMNEN_MASK)) rt5025_notify_charging_cable(swji, swji->cur_cable); return ret; }
static int rt5025_set_charging_cc_switch (struct i2c_client *i2c, int onoff) { int ret; RTINFO("onoff = %d\n", onoff); if (onoff) ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK); else ret = rt5025_clr_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK); return ret; }
static int rt5025_swjeita_resume(struct platform_device *pdev) { #if 1 struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); swji->suspend = 0; schedule_delayed_work(&swji->thermal_reg_work, 0); #endif /* #if 1 */ RTINFO("\n"); return 0; }
static int rt5746_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); int ret; RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); mutex_lock(&ri->io_lock); ret = i2c_smbus_write_byte_data(i2c, reg, data); mutex_unlock(&ri->io_lock); return ret; }
static int rt5746_reg_read(struct i2c_client *i2c, int reg) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); int ret; RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n", (unsigned int)i2c,(unsigned int)reg); mutex_lock(&ri->io_lock); ret = i2c_smbus_read_byte_data(i2c, reg); mutex_unlock(&ri->io_lock); return ret; }
static int rt5025_sel_external_temp_index(struct rt5025_swjeita_info *swji) { int temp = swji->cur_temp; int sect_index; RTINFO("\n"); if (temp < swji->temp[0]) sect_index = 0; else if (temp >= swji->temp[0] && temp < swji->temp[1]) sect_index = 1; else if (temp >= swji->temp[1] && temp < swji->temp[2]) sect_index = 2; else if (temp >= swji->temp[2] && temp < swji->temp[3]) sect_index = 3; else if (temp >= swji->temp[3]) sect_index = 4; RTINFO("sect_index = %d\n", sect_index); return sect_index; }
static inline int rt5025_set_intadc_onoff(struct rt5025_swjeita_info *swji, int enable) { int ret; RTINFO("enable = %d\n", enable); if (enable) ret = rt5025_set_bits(swji->i2c, RT5025_REG_CHANNELL, RT5025_INTEN_MASK); else ret = rt5025_clr_bits(swji->i2c, RT5025_REG_CHANNELL, RT5025_INTEN_MASK); return ret; }
static int rt5025_swjeita_suspend(struct platform_device *pdev, pm_message_t state) { #if 1 struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); swji->suspend = 1; cancel_delayed_work_sync(&swji->thermal_reg_work); swji->cur_therm_region = swji->dec_current = 0; rt5025_notify_charging_cable(swji, swji->cur_cable); #endif /* #if 1 */ RTINFO("\n"); return 0; }
static void rt5025_swjeita_earlyresume(struct early_suspend *h) { #if 0 struct rt5025_swjeita_info *swji; swji = container_of(h, struct rt5025_swjeita_info, early_suspend); if (swji->cur_cable == JEITA_AC_ADAPTER || swji->cur_cable == JEITA_USB_TA) rt5025_set_charging_cc(swji->i2c, swji->temp_cc[swji->cur_cable][swji->cur_section]); swji->suspend = 0; schedule_delayed_work(&swji->thermal_reg_work, 0); #endif /* #if 0 */ RTINFO("\n"); }
static void rt5025_swjeita_earlysuspend(struct early_suspend *h) { #if 0 struct rt5025_swjeita_info *swji; swji = container_of(h, struct rt5025_swjeita_info, early_suspend); swji->suspend = 1; cancel_delayed_work_sync(&swji->thermal_reg_work); swji->cur_therm_region = swji->dec_current = 0; rt5025_notify_charging_cable(swji, swji->cur_cable); if (swji->cur_cable == JEITA_AC_ADAPTER || swji->cur_cable == JEITA_USB_TA) rt5025_set_charging_cc(swji->i2c, swji->temp_cc[swji->cur_cable][swji->cur_section]\ +1400); #endif /* #if 0 */ RTINFO("\n"); }
static int rt5025_set_charging_cv(struct i2c_client *i2c, int voltage) { int ret; u8 data; RTINFO("voltage = %d\n", voltage); if (voltage < 3500) data = 0; else if (voltage > 4440) data = 0x2f<<RT5025_CHGCV_SHIFT; else data = ((voltage-3500)/20)<<RT5025_CHGCV_SHIFT; ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL3, RT5025_CHGCV_MASK, data); return ret; }
static void rt5025_get_internal_temp(struct rt5025_swjeita_info *swji) { u8 data[2]; s32 temp; if (rt5025_reg_block_read(swji->i2c, RT5025_REG_INTTEMP_MSB, 2, data) < 0){ pr_err("%s: Failed to read internal TEMPERATURE\n", __func__); } temp = ((data[0]&0x1F)<<8) + data[1]; temp *= 15625; temp /= 100000; temp = (data[0]&0x20)?-temp:temp; swji->cur_inttemp = temp; RTINFO("internal temperature: %d\n", temp); }
int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_type) { int sect_index; int ret = 0; RTINFO("cable_type = %d\n", cable_type); rt5025_exttemp_alert_switch(swji, 0); sect_index = rt5025_get_external_temp_index(swji); if (swji->cur_section != sect_index || swji->init_once == 0) { rt5025_set_exttemp_alert(swji, sect_index); swji->cur_section = sect_index; swji->init_once = 1; } switch (cable_type) { case JEITA_NORMAL_USB: rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - swji->dec_current); rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); break; case JEITA_USB_TA: rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - swji->dec_current); rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); break; case JEITA_AC_ADAPTER: rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - swji->dec_current); rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); break; case JEITA_NO_CHARGE: rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); break; } swji->cur_cable = cable_type; rt5025_exttemp_alert_switch(swji, 1); return ret; }
static int rt5746_assign_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { struct rt5746_regulator_info *ri = i2c_get_clientdata(i2c); unsigned char value; int ret; RTINFO("(client : 0x%x) reg = 0x%x, mask = 0x%x, data = 0x%x\n", (unsigned int)i2c,(unsigned int)reg,(unsigned int)mask, (unsigned int)data); mutex_lock(&ri->io_lock); ret = rt5746_read_device(i2c, reg, 1, &value); if (ret < 0) goto out; value &= ~mask; value |= (data&mask); ret = i2c_smbus_write_byte_data(i2c,reg,value); out: mutex_unlock(&ri->io_lock); return ret; }
static int rt5025_set_charging_cc(struct i2c_client *i2c, int cur_value) { int ret; u8 data; RTINFO("current value = %d\n", cur_value); if (cur_value < 500) data = 0; else if (cur_value > 2000) data = 0xf<<RT5025_CHGICC_SHIFT; else data = ((cur_value-500)/100)<<RT5025_CHGICC_SHIFT; ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGICC_MASK, data); if (cur_value < 500) rt5025_set_charging_cc_switch(i2c, 0); else rt5025_set_charging_cc_switch(i2c, 1); return ret; }
static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_platform_data *pdata = chip->dev->platform_data; struct rt5025_swjeita_info *swji; int ret = 0; swji = kzalloc(sizeof(*swji), GFP_KERNEL); if (!swji) return -ENOMEM; #if 0 // for debug pdata->jeita_data for (ret=0; ret<4; ret++) RTINFO("jeita temp value %d\n", pdata->jeita_data->temp[ret]); for (ret=0; ret<4; ret++) { RTINFO("jeita temp_cc value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cc[ret][0], \ pdata->jeita_data->temp_cc[ret][1], pdata->jeita_data->temp_cc[ret][2], \ pdata->jeita_data->temp_cc[ret][3], pdata->jeita_data->temp_cc[ret][4]); } for (ret=0; ret<4; ret++) { RTINFO("jeita temp_cv value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cv[ret][0], \ pdata->jeita_data->temp_cv[ret][1], pdata->jeita_data->temp_cv[ret][2], \ pdata->jeita_data->temp_cv[ret][3], pdata->jeita_data->temp_cv[ret][4]); } for (ret=0; ret<8; ret++) { RTINFO("temp_scalar[%d] = 0x%02x\n", ret, pdata->jeita_data->temp_scalar[ret]); } ret = 0; #endif /* #if 0 */ swji->i2c = chip->i2c; swji->chip = chip; swji->cur_section = 2; //initial as the normal temperature swji->cur_cable = JEITA_NO_CHARGE; swji->temp = pdata->jeita_data->temp; swji->temp_scalar = pdata->jeita_data->temp_scalar; swji->temp_cc = pdata->jeita_data->temp_cc; swji->temp_cv = pdata->jeita_data->temp_cv; INIT_DELAYED_WORK(&swji->thermal_reg_work, thermal_reg_work_func); platform_set_drvdata(pdev, swji); #ifdef CONFIG_HAS_EARLYSUSPEND swji->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; swji->early_suspend.suspend = rt5025_swjeita_earlysuspend; swji->early_suspend.resume = rt5025_swjeita_earlyresume; register_early_suspend(&swji->early_suspend); #endif /* CONFIG_HAS_EARLYSUSPEND */ rt5025_set_ainadc_onoff(swji, 1); rt5025_set_intadc_onoff(swji, 1); mdelay(100); rt5025_notify_charging_cable(swji, swji->cur_cable); schedule_delayed_work(&swji->thermal_reg_work, 1*HZ); chip->jeita_info = swji; RTINFO("rt5025-swjeita driver is successfully loaded\n"); return ret; }
static void rt5025_power_event_callback(uint32_t detected) { RTINFO("power event detected = 0x%08x\n", detected); }
static void thermal_reg_work_func(struct work_struct *work) { struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); struct rt5025_swjeita_info *swji = (struct rt5025_swjeita_info *)container_of(delayed_work, struct rt5025_swjeita_info, thermal_reg_work); int therm_region = 0; RTINFO("%s ++", __func__); rt5025_get_internal_temp(swji); #if 1 switch (swji->cur_therm_region) { case 0: if (swji->cur_inttemp >=820) therm_region = 1; else therm_region = 0; break; case 1: if (swji->cur_inttemp <= 780) therm_region = 0; else if (swji->cur_inttemp >= 1020) therm_region = 2; else therm_region = 1; break; case 2: if (swji->cur_inttemp <= 980) therm_region = 1; else therm_region = 2; break; } #else if (swji->cur_inttemp < 800) therm_region = 0; else if (swji->cur_inttemp >= 800 && swji->cur_inttemp < 1000) therm_region = 1; else therm_region = 2; #endif /* #if 1*/ if (therm_region != swji->cur_therm_region) { switch (therm_region) { case 0: swji->dec_current = 0; break; case 1: swji->dec_current = 300; break; case 2: swji->dec_current = 800; break; } swji->cur_therm_region = therm_region; rt5025_notify_charging_cable(swji, swji->cur_cable); } if (!swji->suspend) schedule_delayed_work(&swji->thermal_reg_work, 5*HZ); RTINFO("%s --", __func__); }