static void max17047_reset_soc(struct i2c_client *client) { struct max17047_fuelgauge_data *fg_data = i2c_get_clientdata(client); u8 data[2]; pr_info("%s: Before quick-start - " "VFOCV(%d), VFSOC(%d), SOC(%d)\n", __func__, max17047_get_vfocv(client), max17047_get_rawsoc(client), max17047_get_soc(client)); max17047_test_read(fg_data); if (max17047_i2c_read(client, MAX17047_REG_MISCCFG, data) < 0) return; /* Set bit10 makes quick start */ data[1] |= (0x1 << 2); max17047_i2c_write(client, MAX17047_REG_MISCCFG, data); msleep(500); pr_info("%s: After quick-start - " "VFOCV(%d), VFSOC(%d), SOC(%d)\n", __func__, max17047_get_vfocv(client), max17047_get_rawsoc(client), max17047_get_soc(client)); max17047_test_read(fg_data); return; }
static void max17047_polling_work(struct work_struct *work) { struct max17047_fuelgauge_data *fg_data = container_of(work, struct max17047_fuelgauge_data, polling_work.work); int reg; int i; u8 data[2]; u8 buf[512]; max17047_get_vcell(fg_data->client); max17047_get_vfocv(fg_data->client); max17047_get_avgvcell(fg_data->client); max17047_get_rawsoc(fg_data->client); max17047_get_soc(fg_data->client); pr_info("%s: VCELL(%d), VFOCV(%d), AVGVCELL(%d), RAWSOC(%d), SOC(%d)\n", __func__, fg_data->vcell, fg_data->vfocv, fg_data->avgvcell, fg_data->rawsoc, fg_data->soc); max17047_test_read(fg_data); schedule_delayed_work(&fg_data->polling_work, msecs_to_jiffies(MAX17047_POLLING_INTERVAL)); }
static int max17047_detect_trim_error(struct max17047_fuelgauge_data *fuelgauge_data) { int vcell, soc; vcell = max17047_get_vcell(fuelgauge_data->client); soc = max17047_get_soc(fuelgauge_data->client); if (((vcell < TRIM_ERROR_DETECT_VOLTAGE1) || ( vcell == TRIM_ERROR_DETECT_VOLTAGE2)) && (soc == 0)) { pr_debug("%s: (maybe)It's a trim error version. VCELL(%d), SOC(%d)\n", __func__, vcell, soc); return 1; } return 0; }
static bool max17047_detect_trim_error(struct max17047_fuelgauge_data *fg_data) { bool ret = false; int vcell, soc; vcell = max17047_get_vcell(fg_data->client); soc = max17047_get_soc(fg_data->client); if (((vcell < TRIM_ERROR_DETECT_VOLTAGE1) || (vcell == TRIM_ERROR_DETECT_VOLTAGE2)) && (soc == 0)) { pr_err("%s: (maybe)It's a trim error version. " "VCELL(%d), SOC(%d)\n", __func__, vcell, soc); ret = true; } return ret; }
static void max17047_update_work(struct work_struct *work) { struct max17047_fuelgauge_data *fg_data = container_of(work, struct max17047_fuelgauge_data, update_work.work); struct power_supply *battery_psy; struct i2c_client *client = fg_data->client; union power_supply_propval value; pr_debug("%s\n", __func__); #ifdef CONFIG_SLP battery_psy = &fg_data->fuelgauge; #else battery_psy = power_supply_get_by_name("battery"); #endif max17047_get_vcell(client); max17047_get_vfocv(client); max17047_get_avgvcell(client); max17047_get_rawsoc(client); max17047_get_soc(client); pr_info("%s: VCELL(%d), VFOCV(%d), AVGVCELL(%d), RAWSOC(%d), SOC(%d)\n", __func__, fg_data->vcell, fg_data->vfocv, fg_data->avgvcell, fg_data->rawsoc, fg_data->soc); max17047_test_read(fg_data); if (!battery_psy || !battery_psy->set_property) { pr_err("%s: fail to get battery power supply\n", __func__); mutex_unlock(&fg_data->irq_lock); return; } battery_psy->set_property(battery_psy, POWER_SUPPLY_PROP_STATUS, &value); wake_lock_timeout(&fg_data->update_wake_lock, HZ); }
static int __devinit max17047_fuelgauge_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct max17047_fuelgauge_data *fg_data; int ret; u8 i2c_data[2]; int rawsoc, firstsoc; pr_info("%s: max17047 Fuel gauge Driver Loading\n", __func__); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; fg_data = kzalloc(sizeof(struct max17047_fuelgauge_data), GFP_KERNEL); if (!fg_data) return -ENOMEM; fg_data->client = client; fg_data->pdata = client->dev.platform_data; i2c_set_clientdata(client, fg_data); mutex_init(&fg_data->irq_lock); wake_lock_init(&fg_data->update_wake_lock, WAKE_LOCK_SUSPEND, "fuel-update"); /* Initialize full_soc, set this before fisrt SOC reading */ fg_data->full_soc = FULL_SOC_DEFAULT; /* first full_soc update */ rawsoc = max17047_get_rawsoc(fg_data->client); if (rawsoc > FULL_SOC_DEFAULT) max17047_adjust_fullsoc(client); firstsoc = max17047_get_soc(client); pr_info("%s: rsoc=%d, fsoc=%d, soc=%d\n", __func__, rawsoc, fg_data->full_soc, firstsoc); if (fg_data->pdata->psy_name) fg_data->fuelgauge.name = fg_data->pdata->psy_name; else fg_data->fuelgauge.name = "max17047-fuelgauge"; fg_data->fuelgauge.type = POWER_SUPPLY_TYPE_BATTERY; fg_data->fuelgauge.properties = max17047_fuelgauge_props; fg_data->fuelgauge.num_properties = ARRAY_SIZE(max17047_fuelgauge_props); fg_data->fuelgauge.get_property = max17047_get_property; fg_data->fuelgauge.set_property = max17047_set_property; ret = power_supply_register(&client->dev, &fg_data->fuelgauge); if (ret) { pr_err("%s: failed power supply register\n", __func__); goto err_psy_reg_fg; } /* Initialize fuelgauge registers */ max17047_reg_init(fg_data); /* Initialize fuelgauge alert */ max17047_alert_init(fg_data); /* Request IRQ */ fg_data->irq = gpio_to_irq(fg_data->pdata->irq_gpio); ret = gpio_request(fg_data->pdata->irq_gpio, "fuelgauge-irq"); if (ret) { pr_err("%s: failed requesting gpio %d\n", __func__, fg_data->pdata->irq_gpio); goto err_irq; } gpio_direction_input(fg_data->pdata->irq_gpio); gpio_free(fg_data->pdata->irq_gpio); ret = request_threaded_irq(fg_data->irq, NULL, max17047_fuelgauge_isr, IRQF_TRIGGER_FALLING, "max17047-alert", fg_data); if (ret < 0) { pr_err("%s: fail to request max17047 irq: %d: %d\n", __func__, fg_data->irq, ret); goto err_irq; } ret = enable_irq_wake(fg_data->irq); if (ret < 0) { pr_err("%s: failed enable irq wake %d\n", __func__, fg_data->irq); goto err_enable_irq; } INIT_DELAYED_WORK_DEFERRABLE(&fg_data->update_work, max17047_update_work); #ifdef DEBUG_FUELGAUGE_POLLING INIT_DELAYED_WORK_DEFERRABLE(&fg_data->polling_work, max17047_polling_work); schedule_delayed_work(&fg_data->polling_work, 0); #else max17047_test_read(fg_data); #endif max17047_i2c_read(client, MAX17047_REG_VERSION, i2c_data); pr_info("max17047 fuelgauge(rev.%d%d) initialized.\n", i2c_data[0], i2c_data[1]); #if defined(CONFIG_TARGET_LOCALE_KOR) #ifdef CONFIG_DEBUG_FS fg_data->fg_debugfs_dir = debugfs_create_dir("fg_debug", NULL); if (fg_data->fg_debugfs_dir) { if (!debugfs_create_file("max17047_regs", 0644, fg_data->fg_debugfs_dir, fg_data, &max17047_debugfs_fops)) pr_err("%s : debugfs_create_file, error\n", __func__); if (!debugfs_create_file("default_data", 0644, fg_data->fg_debugfs_dir, fg_data, &max17047_debugfs_fops2)) pr_err("%s : debugfs_create_file2, error\n", __func__); } else pr_err("%s : debugfs_create_dir, error\n", __func__); #endif #endif return 0; err_enable_irq: free_irq(fg_data->irq, fg_data); err_irq: power_supply_unregister(&fg_data->fuelgauge); err_psy_reg_fg: wake_lock_destroy(&fg_data->update_wake_lock); mutex_destroy(&fg_data->irq_lock); kfree(fg_data); return ret; }
static int max17047_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct max17047_fuelgauge_data *fg_data = container_of(psy, struct max17047_fuelgauge_data, fuelgauge); #ifdef USE_TRIM_ERROR_DETECTION if (max17047_detect_trim_error(fg_data)) { switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_VOLTAGE_AVG: val->intval = 4200000; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = 99; break; case POWER_SUPPLY_PROP_TEMP: val->intval = 300; break; default: return -EINVAL; } return 0; } #endif switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_NOW: switch (val->intval) { case VOLTAGE_TYPE_VCELL: val->intval = max17047_get_vcell(fg_data->client); break; case VOLTAGE_TYPE_VFOCV: val->intval = max17047_get_vfocv(fg_data->client); break; default: val->intval = max17047_get_vcell(fg_data->client); break; } break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: val->intval = max17047_get_avgvcell(fg_data->client); break; case POWER_SUPPLY_PROP_CAPACITY: switch (val->intval) { case SOC_TYPE_ADJUSTED: val->intval = max17047_get_soc(fg_data->client); break; case SOC_TYPE_RAW: val->intval = max17047_get_rawsoc(fg_data->client); break; case SOC_TYPE_FULL: val->intval = fg_data->full_soc; break; default: val->intval = max17047_get_soc(fg_data->client); break; } break; case POWER_SUPPLY_PROP_TEMP: val->intval = max17047_get_temperature(fg_data->client); break; default: return -EINVAL; } return 0; }