static ssize_t store_orig_interval(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct device *dev = to_dev(kobj->parent); struct net_device *net_dev = to_net_dev(dev); struct bat_priv *bat_priv = netdev_priv(net_dev); unsigned long orig_interval_tmp; int ret; ret = strict_strtoul(buff, 10, &orig_interval_tmp); if (ret) { bat_info(net_dev, "Invalid parameter for 'orig_interval' " "setting received: %s\n", buff); return -EINVAL; } if (orig_interval_tmp < JITTER * 2) { bat_info(net_dev, "New originator interval too small: %li " "(min: %i)\n", orig_interval_tmp, JITTER * 2); return -EINVAL; } if (atomic_read(&bat_priv->orig_interval) == orig_interval_tmp) return count; bat_info(net_dev, "Changing originator interval from: %i to: %li\n", atomic_read(&bat_priv->orig_interval), orig_interval_tmp); atomic_set(&bat_priv->orig_interval, orig_interval_tmp); return count; }
static ssize_t store_log_level(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct device *dev = to_dev(kobj->parent); struct net_device *net_dev = to_net_dev(dev); struct bat_priv *bat_priv = netdev_priv(net_dev); unsigned long log_level_tmp; int ret; ret = strict_strtoul(buff, 10, &log_level_tmp); if (ret) { bat_info(net_dev, "Invalid parameter for 'log_level' " "setting received: %s\n", buff); return -EINVAL; } if (log_level_tmp > 3) { bat_info(net_dev, "New log level too big: %li " "(max: %i)\n", log_level_tmp, 3); return -EINVAL; } if (atomic_read(&bat_priv->log_level) == log_level_tmp) return count; bat_info(net_dev, "Changing log level from: %i to: %li\n", atomic_read(&bat_priv->log_level), log_level_tmp); atomic_set(&bat_priv->log_level, (unsigned)log_level_tmp); return count; }
static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct net_device *net_dev = kobj_to_netdev(kobj); struct bat_priv *bat_priv = netdev_priv(net_dev); char *curr_gw_mode_str; int gw_mode_tmp = -1; if (buff[count - 1] == '\n') buff[count - 1] = '\0'; if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) gw_mode_tmp = GW_MODE_OFF; if (strncmp(buff, GW_MODE_CLIENT_NAME, strlen(GW_MODE_CLIENT_NAME)) == 0) gw_mode_tmp = GW_MODE_CLIENT; if (strncmp(buff, GW_MODE_SERVER_NAME, strlen(GW_MODE_SERVER_NAME)) == 0) gw_mode_tmp = GW_MODE_SERVER; if (gw_mode_tmp < 0) { bat_info(net_dev, "Invalid parameter for 'gw mode' setting received: " "%s\n", buff); return -EINVAL; } if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) return count; switch (atomic_read(&bat_priv->gw_mode)) { case GW_MODE_CLIENT: curr_gw_mode_str = GW_MODE_CLIENT_NAME; break; case GW_MODE_SERVER: curr_gw_mode_str = GW_MODE_SERVER_NAME; break; default: curr_gw_mode_str = GW_MODE_OFF_NAME; break; } bat_info(net_dev, "Changing gw mode from: %s to: %s\n", curr_gw_mode_str, buff); gw_deselect(bat_priv); atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); return count; }
static void max8998_set_cable(struct max8998_charger_callbacks *ptr, enum cable_type_t status) { struct chg_data *chg = container_of(ptr, struct chg_data, callbacks); chg->cable_status = status; chg->lowbat_warning = false; if (chg->esafe == MAX8998_ESAFE_ALLOFF) chg->esafe = MAX8998_USB_VBUS_AP_ON; bat_info("%s : cable_status = %d\n", __func__, status); #ifdef __VZW_AUTH_CHECK__ /* debug info */ if ((status != CABLE_TYPE_NONE) && (chg->bat_info.batt_health == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE)) { int i; printk("/BATT_ID/ rom code ="); for (i = 0; i < 8; i++) printk(" %d", vzw_rcode[i]); printk("\n"); printk("/BATT_ID/ rom code crc = %d\n", vzw_crc1); printk("/BATT_ID/ crc = %d", vzw_crc2); } #endif if (lpm_charging_mode && (max8998_check_vdcin(chg) != 1) && pm_power_off) pm_power_off(); power_supply_changed(&chg->psy_ac); power_supply_changed(&chg->psy_usb); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); }
static void max8998_lowbat_warning(struct chg_data *chg) { bat_info("%s\n", __func__); if (chg->bat_info.decimal_point_level == 0) return ; // already requested... wake_lock_timeout(&chg->lowbat_wake_lock, 5 * HZ); chg->lowbat_warning = 1; }
static void max8998_lowbat_critical(struct chg_data *chg) { if (chg->bat_info.decimal_point_level == 0) return ; // already requested... bat_info("%s\n", __func__); wake_lock_timeout(&chg->lowbat_wake_lock, 30 * HZ); chg->bat_info.batt_soc = 0; chg->bat_info.decimal_point_level = 0; }
static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct device *dev = to_dev(kobj->parent); struct net_device *net_dev = to_net_dev(dev); struct bat_priv *bat_priv = netdev_priv(net_dev); unsigned long val; int ret, vis_mode_tmp = -1; ret = strict_strtoul(buff, 10, &val); if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || (strncmp(buff, "client", 6) == 0) || (strncmp(buff, "off", 3) == 0)) vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || (strncmp(buff, "server", 6) == 0)) vis_mode_tmp = VIS_TYPE_SERVER_SYNC; if (vis_mode_tmp < 0) { if (buff[count - 1] == '\n') buff[count - 1] = '\0'; bat_info(net_dev, "Invalid parameter for 'vis mode' setting received: " "%s\n", buff); return -EINVAL; } if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) return count; bat_info(net_dev, "Changing vis mode from: %s to: %s\n", atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? "client" : "server"); atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); return count; }
static void check_lpm_charging_mode(struct chg_data *chg) { if (readl(S5P_INFORM5)) { lpm_charging_mode = 1; if (max8998_check_vdcin(chg) != 1) if (pm_power_off) pm_power_off(); } else lpm_charging_mode = 0; bat_info("%s : lpm_charging_mode(%d)\n", __func__, lpm_charging_mode); }
static bool max8998_set_esafe(struct max8998_charger_callbacks *ptr, u8 esafe) { struct chg_data *chg = container_of(ptr, struct chg_data, callbacks); if (esafe > 3) { pr_err("%s : esafe value must not be bigger than 3\n", __func__); return 0; } chg->esafe = esafe; max8998_update_reg(chg->iodev->i2c, MAX8998_REG_CHGR2, (esafe << MAX8998_SHIFT_ESAFEOUT), MAX8998_MASK_ESAFEOUT); bat_info("%s : esafe = %d\n", __func__, esafe); return 1; }
static ssize_t store_aggr_ogms(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct device *dev = to_dev(kobj->parent); struct net_device *net_dev = to_net_dev(dev); struct bat_priv *bat_priv = netdev_priv(net_dev); int aggr_tmp = -1; if (((count == 2) && (buff[0] == '1')) || (strncmp(buff, "enable", 6) == 0)) aggr_tmp = 1; if (((count == 2) && (buff[0] == '0')) || (strncmp(buff, "disable", 7) == 0)) aggr_tmp = 0; if (aggr_tmp < 0) { if (buff[count - 1] == '\n') buff[count - 1] = '\0'; bat_info(net_dev, "Invalid parameter for 'aggregate OGM' setting" "received: %s\n", buff); return -EINVAL; } if (atomic_read(&bat_priv->aggregation_enabled) == aggr_tmp) return count; bat_info(net_dev, "Changing aggregation from: %s to: %s\n", atomic_read(&bat_priv->aggregation_enabled) == 1 ? "enabled" : "disabled", aggr_tmp == 1 ? "enabled" : "disabled"); atomic_set(&bat_priv->aggregation_enabled, (unsigned)aggr_tmp); return count; }
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; }
static int store_bool_attr(char *buff, size_t count, struct net_device *net_dev, char *attr_name, atomic_t *attr) { int enabled = -1; if (buff[count - 1] == '\n') buff[count - 1] = '\0'; if ((strncmp(buff, "1", 2) == 0) || (strncmp(buff, "enable", 7) == 0) || (strncmp(buff, "enabled", 8) == 0)) enabled = 1; if ((strncmp(buff, "0", 2) == 0) || (strncmp(buff, "disable", 8) == 0) || (strncmp(buff, "disabled", 9) == 0)) enabled = 0; if (enabled < 0) { bat_info(net_dev, "%s: Invalid parameter received: %s\n", attr_name, buff); return -EINVAL; } if (atomic_read(attr) == enabled) return count; bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, atomic_read(attr) == 1 ? "enabled" : "disabled", enabled == 1 ? "enabled" : "disabled"); atomic_set(attr, (unsigned)enabled); return count; }
static int store_uint_attr(char *buff, size_t count, struct net_device *net_dev, char *attr_name, unsigned int min, unsigned int max, atomic_t *attr) { unsigned long uint_val; int ret; ret = strict_strtoul(buff, 10, &uint_val); if (ret) { bat_info(net_dev, "%s: Invalid parameter received: %s\n", attr_name, buff); return -EINVAL; } if (uint_val < min) { bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", attr_name, uint_val, min); return -EINVAL; } if (uint_val > max) { bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", attr_name, uint_val, max); return -EINVAL; } if (atomic_read(attr) == uint_val) return count; bat_info(net_dev, "%s: Changing from: %i to: %lu\n", attr_name, atomic_read(attr), uint_val); atomic_set(attr, uint_val); return count; }
ssize_t gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) { struct bat_priv *bat_priv = netdev_priv(net_dev); long gw_bandwidth_tmp = 0, up = 0, down = 0; bool ret; ret = parse_gw_bandwidth(net_dev, buff, &up, &down); if (!ret) goto end; if ((!down) || (down < 256)) down = 2000; if (!up) up = down / 5; kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); /** * the gw bandwidth we guessed above might not match the given * speeds, hence we need to calculate it back to show the number * that is going to be propagated **/ gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, (int *)&down, (int *)&up); gw_deselect(bat_priv); bat_info(net_dev, "Changing gateway bandwidth from: '%i' to: '%ld' " "(propagating: %ld%s/%ld%s)\n", atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, (down > 2048 ? down / 1024 : down), (down > 2048 ? "MBit" : "KBit"), (up > 2048 ? up / 1024 : up), (up > 2048 ? "MBit" : "KBit")); atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); end: return count; }
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 max8998_set_cable(struct max8998_charger_callbacks *ptr, enum cable_type_t status) { struct chg_data *chg = container_of(ptr, struct chg_data, callbacks); chg->cable_status = status; chg->lowbat_warning = false; if (chg->esafe == MAX8998_ESAFE_ALLOFF) chg->esafe = MAX8998_USB_VBUS_AP_ON; bat_info("%s : cable_status(%d) esafe(%d)\n", __func__, status, chg->esafe); if (lpm_charging_mode && (max8998_check_vdcin(chg) != 1) && pm_power_off) pm_power_off(); power_supply_changed(&chg->psy_ac); power_supply_changed(&chg->psy_usb); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); }
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_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 void max8998_lowbat_critical(struct chg_data *chg) { bat_info("%s\n", __func__); wake_lock_timeout(&chg->lowbat_wake_lock, 30 * HZ); chg->bat_info.batt_soc = 0; }
static void max8998_lowbat_warning(struct chg_data *chg) { bat_info("%s\n", __func__); wake_lock_timeout(&chg->lowbat_wake_lock, 5 * HZ); chg->lowbat_warning = 1; }
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; }
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 void max8998_set_jig(struct max8998_charger_callbacks *ptr, bool attached) { struct chg_data *chg = container_of(ptr, struct chg_data, callbacks); chg->jig_status = attached; bat_info("%s %d\n", __func__, (int)attached); }