static int max17047_get_avgvcell(struct i2c_client *client) { struct max17047_fuelgauge_data *fg_data = i2c_get_clientdata(client); u8 data[2]; int ret; u32 avgvcell; pr_debug("%s\n", __func__); ret = max17047_i2c_read(client, MAX17047_REG_AVGVCELL, data); if (ret < 0) return ret; avgvcell = fg_data->avgvcell = ((data[0] >> 3) + (data[1] << 5)) * 625; pr_debug("%s: AVGVCELL(0x%02x%02x, %d)\n", __func__, data[1], data[0], avgvcell); return avgvcell; }
/* max17047_get_XXX(); Return current value and update data value */ static int max17047_get_vfocv(struct i2c_client *client) { struct max17047_fuelgauge_data *fg_data = i2c_get_clientdata(client); u8 data[2]; int ret; u32 vfocv; pr_debug("%s\n", __func__); ret = max17047_i2c_read(client, MAX17047_REG_VFOCV, data); if (ret < 0) return ret; vfocv = fg_data->vfocv = ((data[0] >> 3) + (data[1] << 5)) * 625 / 1000; pr_debug("%s: VFOCV(0x%02x%02x, %d)\n", __func__, data[1], data[0], vfocv); return vfocv * 1000; }
static int max17047_get_rawsoc(struct i2c_client *client) { struct max17047_fuelgauge_data *fg_data = i2c_get_clientdata(client); u8 data[2]; int ret; int rawsoc; pr_debug("%s\n", __func__); ret = max17047_i2c_read(client, MAX17047_REG_SOC_VF, data); if (ret < 0) return ret; rawsoc = fg_data->rawsoc = (data[1] * 100) + (data[0] * 100 / 256); pr_debug("%s: RAWSOC(0x%02x%02x, %d)\n", __func__, data[1], data[0], rawsoc); return rawsoc; }
static ssize_t max17047_debugfs_read_defaultdata(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { struct max17047_fuelgauge_data *fg_data = filp->private_data; struct i2c_client *client = NULL; u8 i2c_data[2]; int reg = 0; char *buf; size_t len = 0; ssize_t ret; if (!fg_data) { pr_err("%s : fg_data is null\n", __func__); return 0; } client = fg_data->client; if (*ppos != 0) return 0; if (count < sizeof(buf)) return -ENOSPC; buf = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; reg = MAX17047_REG_RCOMP; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "rcomp=%02x%02x ", i2c_data[1], i2c_data[0]); len += snprintf(buf + len, PAGE_SIZE - len, "fsoc=%d", fg_data->full_soc); len += snprintf(buf + len, PAGE_SIZE - len, "\n"); ret = simple_read_from_buffer(buffer, len, ppos, buf, PAGE_SIZE); kfree(buf); return ret; }
static irqreturn_t max17047_fuelgauge_isr(int irq, void *data) { struct max17047_fuelgauge_data *fg_data = data; struct i2c_client *client = fg_data->client; union power_supply_propval value; u8 i2c_data[2]; pr_info("%s: irq(%d)\n", __func__, irq); mutex_lock(&fg_data->irq_lock); max17047_i2c_read(client, MAX17047_REG_STATUS, i2c_data); pr_info("%s: MAX17047_REG_STATUS(0x%02x%02x)\n", __func__, i2c_data[1], i2c_data[0]); wake_lock(&fg_data->update_wake_lock); schedule_delayed_work(&fg_data->update_work, msecs_to_jiffies(1000)); mutex_unlock(&fg_data->irq_lock); return IRQ_HANDLED; }
static void max17047_alert_init(struct max17047_fuelgauge_data *fg_data) { struct i2c_client *client = fg_data->client; u8 i2c_data[2]; pr_debug("%s\n", __func__); /* SALRT Threshold setting */ /* min 1%, max disable */ max17047_set_salrt(fg_data, 0x01, 0xFF); /* TALRT Threshold setting */ /* min disable, max disable */ max17047_set_talrt(fg_data, 0x80, 0x7F); /* VALRT Threshold setting */ /* min disable, max disable */ max17047_set_valrt(fg_data, 0x00, 0xFF); /* Enable SOC alerts */ max17047_i2c_read(client, MAX17047_REG_CONFIG, i2c_data); i2c_data[0] |= (0x1 << 2); max17047_i2c_write(client, MAX17047_REG_CONFIG, i2c_data); }
static void max17047_reset_soc(struct i2c_client *client) { u8 data[2]; pr_info("%s: Before quick-start - " "VFOCV(%d), VFSOC(%d)\n", __func__, max17047_get_vfocv(client), max17047_get_soc(client)); 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)\n", __func__, max17047_get_vfocv(client), max17047_get_soc(client)); return; }
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 ssize_t max17047_debugfs_read_registers(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { struct max17047_fuelgauge_data *fg_data = filp->private_data; struct i2c_client *client = NULL; u8 i2c_data[2]; int reg = 0; char *buf; size_t len = 0; ssize_t ret; if (!fg_data) { pr_err("%s : fg_data is null\n", __func__); return 0; } client = fg_data->client; if (*ppos != 0) return 0; if (count < sizeof(buf)) return -ENOSPC; buf = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; reg = MAX17047_REG_STATUS; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "status(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = MAX17047_REG_CONFIG; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "config(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = MAX17047_REG_RCOMP; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "rcomp(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = MAX17047_REG_CGAIN; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "cgain(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = MAX17047_REG_SALRT_TH; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "salrt(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = MAX17047_REG_MISCCFG; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "misc(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = 0x39; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "tempc0(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = 0x0F; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "remCap(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); reg = 0x10; max17047_i2c_read(client, reg, i2c_data); len += snprintf(buf + len, PAGE_SIZE - len, "fullCap(0x%x)=%02x%02x ", reg, i2c_data[1], i2c_data[0]); len += snprintf(buf + len, PAGE_SIZE - len, "\n"); ret = simple_read_from_buffer(buffer, len, ppos, buf, PAGE_SIZE); kfree(buf); return ret; }
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 *fuelgauge_data; int ret; u8 i2c_data[2]; pr_info("%s: max17047 Fuel gauge Driver Loading\n", __func__); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) return -EIO; fuelgauge_data = kzalloc(sizeof(struct max17047_fuelgauge_data), GFP_KERNEL); if (!fuelgauge_data) return -ENOMEM; fuelgauge_data->client = client; fuelgauge_data->pdata = client->dev.platform_data; i2c_set_clientdata(client, fuelgauge_data); if (fuelgauge_data->pdata->psy_name) fuelgauge_data->fuelgauge.name = fuelgauge_data->pdata->psy_name; else fuelgauge_data->fuelgauge.name = "max17047-fuelgauge"; fuelgauge_data->fuelgauge.type = POWER_SUPPLY_TYPE_BATTERY; fuelgauge_data->fuelgauge.properties = max17047_fuelgauge_props; fuelgauge_data->fuelgauge.num_properties = ARRAY_SIZE(max17047_fuelgauge_props); fuelgauge_data->fuelgauge.get_property = max17047_get_property; fuelgauge_data->fuelgauge.set_property = max17047_set_property; ret = power_supply_register(&client->dev, &fuelgauge_data->fuelgauge); if (ret) { pr_err("%s: failed power supply register\n", __func__); kfree(fuelgauge_data); return ret; } /* Initialize fuelgauge registers */ max17047_reg_init(fuelgauge_data); /* Initialize fuelgauge alert */ max17047_alert_init(fuelgauge_data); /* Request IRQ */ fuelgauge_data->irq = gpio_to_irq(fuelgauge_data->pdata->irq_gpio); ret = gpio_request(fuelgauge_data->pdata->irq_gpio, "fuelgauge-irq"); if (ret) { pr_err("%s: failed requesting gpio %d\n", __func__, fuelgauge_data->pdata->irq_gpio); return ret; } gpio_direction_input(fuelgauge_data->pdata->irq_gpio); gpio_free(fuelgauge_data->pdata->irq_gpio); if (request_irq(fuelgauge_data->irq, max17047_fuelgauge_isr, IRQF_TRIGGER_FALLING, "max17047-alert", fuelgauge_data)) pr_err("Can NOT request irq 'FUEL_ALERT' %d", fuelgauge_data->irq); #ifdef DEBUG_FUELGAUGE_POLLING INIT_DELAYED_WORK_DEFERRABLE(&fuelgauge_data->polling_work, max17047_polling_work); schedule_delayed_work(&fuelgauge_data->polling_work, 0); #else max17047_test_read(fuelgauge_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]); return 0; }