static int max8998_charging_control(struct chg_data *chg) { int ret; struct i2c_client *i2c = chg->iodev->i2c; if (!chg->charging) { /* disable charging */ ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, (1 << MAX8998_SHIFT_CHGEN), MAX8998_MASK_CHGEN); if (ret < 0) goto err; pr_debug("%s : charging disabled\n", __func__); } else { /* enable charging */ if (chg->cable_status == CABLE_TYPE_AC) { /* ac */ ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (2 << MAX8998_SHIFT_TOPOFF) | (3 << MAX8998_SHIFT_RSTR) | (5 << MAX8998_SHIFT_ICHG)); if (ret < 0) goto err; pr_debug("%s : TA charging enabled\n", __func__); } else { /* usb */ ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (6 << MAX8998_SHIFT_TOPOFF) | (3 << MAX8998_SHIFT_RSTR) | (2 << MAX8998_SHIFT_ICHG)); if (ret < 0) goto err; pr_debug("%s : USB charging enabled\n", __func__); } ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (2 << MAX8998_SHIFT_ESAFEOUT) | (2 << MAX8998_SHIFT_FT) | (0 << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } return 0; err: pr_err("max8998_read_reg error\n"); return ret; }
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg) { int ret; u8 data[MAX8998_NUM_IRQ_REGS]; struct chg_data *chg = max8998_chg; struct i2c_client *i2c = chg->iodev->i2c; ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data); if (ret < 0) goto err; wake_lock(&chg->work_wake_lock); #ifndef TOPOFF_CURRENT_CHECK if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) { bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full); if (chg->set_batt_full) chg->bat_info.batt_is_full = true; else { chg->set_batt_full = true; if (chg->cable_status == CABLE_TYPE_AC) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); else if (chg->cable_status == CABLE_TYPE_USB) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); } } #endif if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT1_MASK) max8998_lowbat_warning(chg); if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT2_MASK) max8998_lowbat_critical(chg); queue_work(chg->monitor_wqueue, &chg->bat_work); return IRQ_HANDLED; err: pr_err("%s : pmic read error\n", __func__); return IRQ_HANDLED; }
int max8998_set_dvsint_direct(u32 armSet, u32 voltage) { struct max8998_data *max8998 = client_data_p; int reg, i, value; DBG("func =%s called with set=%d, voltage=%d",__func__, armSet, voltage); if(armSet == DVSINT1) reg = MAX8998_REG_DVSINT1; else if(armSet == DVSINT2) reg = MAX8998_REG_DVSINT2; else { printk("Invalid parameter for dvs int\n"); return -EINVAL; } for( i =0; i < sizeof(dcdc12_voltage_map)/4; i++) { if(dcdc12_voltage_map[i] == voltage) break; } if(i == sizeof(dcdc12_voltage_map)/4) { printk("Invalid parameter of voltage value for dvs int\n"); return -EINVAL; } value = i; max8998_write_reg(max8998, value, reg); return 0; }
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info) { int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0); if (info->lp3974_bug_workaround) msleep(2000); return ret; }
/* Restore registers after hibernation */ static int max8998_restore(struct device *dev) { struct i2c_client *i2c = to_i2c_client(dev); int i; for (i = 0; i < ARRAY_SIZE(max8998_dump); i++) max8998_write_reg(i2c, max8998_dump[i].addr, max8998_dump[i].val); return 0; }
int max8998_ldo_disable_direct(int ldo) { struct max8998_data *max8998 = client_data_p; int value, shift; if((ldo < MAX8998_LDO1) || (ldo > MAX8998_DCDC4)) { printk("ERROR: Invalid argument passed\n"); return -EINVAL; } DBG("func =%s called for regulator = %d\n",__func__,ldo); spin_lock(&pmic_access_lock); if (ldo <= MAX8998_LDO5) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1); shift = 5 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1); } else if (ldo <= MAX8998_LDO13) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF2); shift = 13 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF2); } else if (ldo <= MAX8998_LDO17) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF3); shift = 21 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF3); } else { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1); shift = 7 - (ldo - MAX8998_DCDC1); value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1); } spin_unlock(&pmic_access_lock); return 0; }
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg) { int ret; u8 data[MAX8998_NUM_IRQ_REGS]; struct chg_data *chg = max8998_chg; struct i2c_client *i2c = chg->iodev->i2c; ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data); if (ret < 0) goto err; wake_lock(&chg->work_wake_lock); if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) { bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full); if (chg->set_batt_full) chg->bat_info.batt_is_full = true; else { chg->set_batt_full = true; if (chg->cable_status == CABLE_TYPE_AC) #if defined(CONFIG_ARIES_NTT) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_700 << MAX8998_SHIFT_ICHG)); #else max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); #endif else if (chg->cable_status == CABLE_TYPE_USB) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_25 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); }
static void s3c_bat_top_off(struct chg_data *chg) { struct i2c_client *i2c = chg->iodev->i2c; bat_info("%s : topoff(%d)\n", __func__, chg->set_batt_full); if (chg->set_batt_full) chg->bat_info.batt_is_full = true; else { chg->set_batt_full = true; if (chg->cable_status == CABLE_TYPE_AC) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); else if (chg->cable_status == CABLE_TYPE_USB) max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); } }
static int max8998_ldo_disable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); int ldo = max8998_get_ldo(rdev); int value, shift; DBG("func =%s called for regulator = %d\n",__func__,ldo); spin_lock(&pmic_access_lock); if (ldo <= MAX8998_LDO5) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1); //shift = 6 - ldo; shift = 5 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1); } else if (ldo <= MAX8998_LDO13) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF2); shift = 13 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF2); } else if (ldo <= MAX8998_LDO17) { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF3); shift = 21 - ldo; value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF3); } else { value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1); shift = 7 - (ldo - MAX8998_DCDC1); value &= ~(1 << shift); max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1); } spin_unlock(&pmic_access_lock); return 0; }
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info) { int ret; u8 alarm0_conf = 0x77; /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */ if (info->lp3974_bug_workaround) alarm0_conf = 0x57; ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf); if (info->lp3974_bug_workaround) msleep(2000); return ret; }
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info) { int ret; u8 alarm0_conf = 0x77; if (info->lp3974_bug_workaround) alarm0_conf = 0x57; ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf); if (info->lp3974_bug_workaround) msleep(2000); return ret; }
static int max8998_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8998_platform_data *pdata = i2c->dev.platform_data; struct max8998_dev *max8998; int ret = 0; u8 val; max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL); if (max8998 == NULL) return -ENOMEM; i2c_set_clientdata(i2c, max8998); max8998->dev = &i2c->dev; max8998->i2c_client = i2c; max8998->irq = i2c->irq; if (pdata) { max8998->ono = pdata->ono; max8998->irq_base = pdata->irq_base; } max8998->dev_read = max8998_i2c_device_read; max8998->dev_write = max8998_i2c_device_write; max8998->dev_update = max8998_i2c_device_update; mutex_init(&max8998->iolock); max8998_irq_init(max8998); max8998_read_reg(max8998, MAX8998_REG_ONOFF1, &val); val &= ~(MAX8998_MASK_EN1|MAX8998_MASK_EN2|MAX8998_MASK_EN4); max8998_write_reg(max8998, MAX8998_REG_ONOFF1, val); ret = mfd_add_devices(max8998->dev, -1, max8998_devs, ARRAY_SIZE(max8998_devs), NULL, 0); if (ret < 0) goto err; return ret; err: mfd_remove_devices(max8998->dev); kfree(max8998); return ret; }
int max8998_ldo_set_voltage_direct(int ldo, int min_uV, int max_uV) { struct max8998_data *max8998 = client_data_p; int value, shift = 0, mask = 0xff, reg; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; int i = 0; const int *vol_map = NULL; if((ldo < MAX8998_LDO1) || (ldo > MAX8998_DCDC4)) { printk("ERROR: Invalid argument passed\n"); return -EINVAL; } vol_map = ldo_voltage_map[ldo]; DBG("func =%s called for regulator = %d, min_v=%d, max_v=%d\n",__func__,ldo,min_uV,max_uV); if (min_vol < 750 || max_vol > 3600) return -EINVAL; while (vol_map[i]) { if (vol_map[i] >= min_vol) break; i++; } DBG("Found voltage=%d\n",vol_map[i]); if (!vol_map[i]) return -EINVAL; if (vol_map[i] > max_vol) return -EINVAL; if (ldo == MAX8998_LDO3) { reg = MAX8998_REG_LDO23; mask = 0x0F; } else if (ldo == MAX8998_LDO2) { reg = MAX8998_REG_LDO23; shift = 4; mask = 0x0F; } else if (ldo == MAX8998_LDO8) { reg = MAX8998_REG_LDO89; shift = 4; mask = 0x07; } else if (ldo == MAX8998_LDO9) { reg = MAX8998_REG_LDO89; shift = 2; mask = 0x03; } else if (ldo == MAX8998_LDO10) { reg = MAX8998_REG_LDO1011; shift = 5; mask = 0x07; } else if (ldo == MAX8998_LDO11) { reg = MAX8998_REG_LDO1011; mask = 0x1F; } else if (ldo == MAX8998_LDO12) { reg = MAX8998_REG_LDO12; mask = 0xFF; } else if (ldo == MAX8998_LDO13) { reg = MAX8998_REG_LDO13; mask = 0xFF; } else if (ldo == MAX8998_LDO14) { reg = MAX8998_REG_LDO14; mask = 0xFF; } else if (ldo == MAX8998_LDO15) { reg = MAX8998_REG_LDO15; mask = 0xFF; } else if (ldo == MAX8998_LDO16) { reg = MAX8998_REG_LDO16; mask = 0xFF; } else if (ldo == MAX8998_LDO17) { reg = MAX8998_REG_LDO17; mask = 0xFF; } else if (ldo == MAX8998_DCDC1) { //reg = 0x04; reg = MAX8998_REG_DVSARM1; mask = 0x1f; } else if (ldo == MAX8998_DCDC2) { //reg = 0x06; reg = MAX8998_REG_DVSINT1; mask = 0x1f; } else if (ldo == MAX8998_DCDC3) { reg = MAX8998_REG_BUCK3; mask = 0xff; } else if (ldo == MAX8998_DCDC4) { reg = MAX8998_REG_BUCK4; mask = 0xff; } else {// for ldo4,5,6,7 reg = MAX8998_REG_LDO23 + (ldo - MAX8998_LDO3); mask = 0xff; } spin_lock(&pmic_access_lock); value = max8998_read_reg(max8998, reg); value &= ~(mask << shift); value |= (i << shift); max8998_write_reg(max8998, value, reg); spin_unlock(&pmic_access_lock); return 0; }
static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; pr_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery", chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, chg->psy_bat.properties = max8998_battery_props, chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props), chg->psy_bat.get_property = s3c_bat_get_property, chg->psy_bat.property_is_writeable = s3c_bat_property_is_writeable, chg->psy_bat.set_property = s3c_bat_set_property, chg->psy_usb.name = "usb", chg->psy_usb.type = POWER_SUPPLY_TYPE_USB, chg->psy_usb.supplied_to = supply_list, chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_usb.properties = s3c_power_properties, chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_usb.get_property = s3c_usb_get_property, chg->psy_ac.name = "ac", chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, chg->psy_ac.supplied_to = supply_list, chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_ac.properties = s3c_power_properties, chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_ac.get_property = s3c_ac_get_property, chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->bat_info.batt_temp = 100; //fake chg->bat_info.batt_percentage = 50; //fake, modem will bootup soon and update it... hopefully chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_update_reg(i2c, MAX8998_REG_CHGR1, /* disable */ (0x3 << MAX8998_SHIFT_RSTR), MAX8998_MASK_RSTR); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 6 Hr */ (0x2 << MAX8998_SHIFT_FT), MAX8998_MASK_FT); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 4.2V */ (0x0 << MAX8998_SHIFT_BATTSL), MAX8998_MASK_BATTSL); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 105c */ (0x0 << MAX8998_SHIFT_TMP), MAX8998_MASK_TMP); if (ret < 0) goto err_kfree; pr_info("%s : pmic interrupt registered\n", __func__); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_MASK_DCINR | MAX8998_MASK_DCINF)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_CHGRSTF_MASK); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, 0xFF); if (ret < 0) goto err_kfree; wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); INIT_WORK(&chg->bat_work, s3c_bat_work); chg->monitor_wqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_wake_lock; } chg->last_poll = alarm_get_elapsed_realtime(); alarm_init(&chg->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, s3c_battery_alarm); check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("Failed to register power supply psy_bat\n"); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("Failed to register power supply psy_usb\n"); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("Failed to register power supply psy_ac\n"); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("Failed to enable pmic irq wake\n"); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); alarm_cancel(&chg->alarm); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }
static int max8998_charging_control(struct chg_data *chg) { struct i2c_client *i2c = chg->iodev->i2c; static int prev_charging = -1, prev_cable = -1; int ret; int topoff; if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status)) return 0; bat_info("%s : chg(%d) cable(%d) dis(%X) bat(%d,%d,%d), esafe(%d)\n", __func__, chg->charging, chg->cable_status, chg->bat_info.dis_reason, chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full, chg->esafe); if (!chg->charging) { /* disable charging */ s3c_clean_chg_current(chg); ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_DISABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } else { /* enable charging */ if (chg->cable_status == CABLE_TYPE_AC) { /* termination current adc NOT used to detect full-charging */ if (chg->pdata->termination_curr_adc > 0) topoff = MAX8998_TOPOFF_10; else topoff = MAX8998_TOPOFF_30; /* ac */ ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (topoff << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); if (ret < 0) goto err; ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_ENABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } else { if (chg->pdata->termination_curr_adc > 0) topoff = MAX8998_TOPOFF_10; else topoff = MAX8998_TOPOFF_35; /* usb */ ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (topoff << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); if (ret < 0) goto err; ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_ENABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } } prev_charging = chg->charging; prev_cable = chg->cable_status; return 0; err: pr_err("max8998_read_reg error\n"); return ret; }
static int max8998_charging_control(struct chg_data *chg) { struct i2c_client *i2c = chg->iodev->i2c; static int prev_charging = -1, prev_cable = -1; int ret; if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status)) return 0; bat_info("%s : chg(%d) cable(%d) dis(%X) esafe(%d) bat(%d,%d,%d)\n", __func__, chg->charging, chg->cable_status, chg->bat_info.dis_reason, chg->esafe, chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full); if (!chg->charging) { /* disable charging */ ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_DISABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } else { /* enable charging */ if (chg->cable_status == CABLE_TYPE_AC) { /* ac */ #if defined(CONFIG_ARIES_NTT) if (chg->set_batt_full) ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_700 << MAX8998_SHIFT_ICHG)); else ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_15 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_700 << MAX8998_SHIFT_ICHG)); #else if (chg->set_batt_full) ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_10 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); else ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_20 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_600 << MAX8998_SHIFT_ICHG)); #endif if (ret < 0) goto err; ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_ENABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } else { /* usb */ if (chg->set_batt_full) ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_25 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); else ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1, (MAX8998_TOPOFF_30 << MAX8998_SHIFT_TOPOFF) | (MAX8998_RSTR_DISABLE << MAX8998_SHIFT_RSTR) | (MAX8998_ICHG_475 << MAX8998_SHIFT_ICHG)); if (ret < 0) goto err; ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, (chg->esafe << MAX8998_SHIFT_ESAFEOUT) | (MAX8998_CHGTIME_7HR << MAX8998_SHIFT_FT) | (MAX8998_CHGEN_ENABLE << MAX8998_SHIFT_CHGEN)); if (ret < 0) goto err; } } prev_charging = chg->charging; prev_cable = chg->cable_status; return 0; err: pr_err("max8998_read_reg error\n"); return ret; }
static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; bat_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery"; chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY; chg->psy_bat.properties = max8998_battery_props; chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props); chg->psy_bat.get_property = s3c_bat_get_property; chg->psy_usb.name = "usb"; chg->psy_usb.type = POWER_SUPPLY_TYPE_USB; chg->psy_usb.supplied_to = supply_list; chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list); chg->psy_usb.properties = s3c_power_properties; chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties); chg->psy_usb.get_property = s3c_usb_get_property; chg->psy_ac.name = "ac"; chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS; chg->psy_ac.supplied_to = supply_list; chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list); chg->psy_ac.properties = s3c_power_properties; chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties); chg->psy_ac.get_property = s3c_ac_get_property; chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->set_batt_full = false; chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; chg->esafe = MAX8998_USB_VBUS_AP_ON; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_IRQ_DCINR_MASK | MAX8998_IRQ_DCINF_MASK)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; #ifdef TOPOFF_CURRENT_CHECK ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, 0xFF); #else ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_TOPOFFR_MASK); #endif if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, ~(MAX8998_IRQ_LOBAT2_MASK | MAX8998_IRQ_LOBAT1_MASK)); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_ONOFF3, (1 << MAX8998_SHIFT_ENBATTMON), MAX8998_MASK_ENBATTMON); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG1, 0x7, 0x37); //3.57V if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG2, 0x5, 0x37); //3.4V if (ret < 0) goto err_kfree; max8998_lowbat_config(chg, 0); wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); wake_lock_init(&chg->lowbat_wake_lock, WAKE_LOCK_SUSPEND, "max8998-lowbat"); INIT_WORK(&chg->bat_work, s3c_bat_work); setup_timer(&chg->bat_work_timer, s3c_bat_work_timer_func, (unsigned long)chg); chg->monitor_wqueue = create_freezeable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("%s : Failed to create freezeable workqueue\n", __func__); ret = -ENOMEM; goto err_wake_lock; } check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("%s : Failed to register power supply psy_bat\n", __func__); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("%s : Failed to register power supply psy_usb\n", __func__); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("%s : Failed to register power supply psy_ac\n", __func__); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("%s : Failed to enable pmic irq wake\n", __func__); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; chg->callbacks.set_esafe = max8998_set_esafe; chg->callbacks.get_vdcin = max8998_get_vdcin; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); wake_lock_destroy(&chg->lowbat_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }