diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/power/wmt_battery/gauge/vt1603/vt1603.c')
-rwxr-xr-x | ANDROID_3.4.5/drivers/power/wmt_battery/gauge/vt1603/vt1603.c | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/power/wmt_battery/gauge/vt1603/vt1603.c b/ANDROID_3.4.5/drivers/power/wmt_battery/gauge/vt1603/vt1603.c new file mode 100755 index 00000000..e75a99e8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/power/wmt_battery/gauge/vt1603/vt1603.c @@ -0,0 +1,513 @@ +/* + * vt1603.c - WonderMedia VT1603 Adc Battery Driver. + * + * Copyright (C) 2013 WonderMedia Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/power_supply.h> +#include <linux/platform_device.h> +#include <linux/power/wmt_battery.h> +#include <mach/wmt_env.h> + +#include "vt1603.h" +#include "batt_leds.h" + +enum { + COMPENSATION_VOLUME = 0, + COMPENSATION_BRIGHTNESS, + COMPENSATION_WIFI, + COMPENSATION_VIDEO, + COMPENSATION_USB, + COMPENSATION_HDMI, + COMPENSATION_COUNT +}; + +static const char *compensation_strings[] = { + "volume", + "brightness", + "wifi", + "video", + "usb", + "hdmi" +}; + +struct vt1603_device_info { + struct vt1603 *vt1603; + struct device *dev; + struct power_supply ps_bat; + struct mutex mutex; + int compensation[COMPENSATION_COUNT]; + + int capacity; + int sleeping; + int debug; +}; + +static struct vt1603_device_info *vt1603_dev_info = NULL; + +static int vt1603_set_reg8(struct vt1603 *vt1603, u8 reg, u8 val) +{ + int ret = vt1603->reg_write(vt1603, reg, val); + if (ret) + pr_err("vt1603 battery write error, errno%d\n", ret); + return ret; +} + +static u8 vt1603_get_reg8(struct vt1603 *vt1603, u8 reg) +{ + u8 val = 0; + int ret = 0; + + ret = vt1603->reg_read(vt1603, reg, &val); + if (ret < 0){ + pr_err("vt1603 battery read error, errno%d\n", ret); + return 0; + } + + return val; +} + +static int vt1603_read8(struct vt1603 *vt1603, u8 reg, u8 *data) +{ + int ret = vt1603->reg_read(vt1603, reg, data); + if (ret) + pr_err("vt1603 battery read error, errno%d\n", ret); + return ret; +} + +static void vt1603_setbits(struct vt1603 *vt1603, u8 reg, u8 mask) +{ + u8 tmp = vt1603_get_reg8(vt1603, reg) | mask; + vt1603_set_reg8(vt1603, reg, tmp); +} + +static void vt1603_clrbits(struct vt1603 *vt1603, u8 reg, u8 mask) +{ + u8 tmp = vt1603_get_reg8(vt1603, reg) & (~mask); + vt1603_set_reg8(vt1603, reg, tmp); +} + +#define ADC_DATA(low, high) ((((high) & 0x0F) << 8) + (low)) + +static int vt1603_get_bat_data(struct vt1603 *vt1603,int *data) +{ + int ret = 0; + u8 data_l, data_h; + + ret |= vt1603_read8(vt1603, VT1603_DATL_REG, &data_l); + ret |= vt1603_read8(vt1603, VT1603_DATH_REG, &data_h); + + *data = ADC_DATA(data_l, data_h); + return ret; +} + +static void vt1603_switch_to_bat_mode(struct vt1603 *vt1603) +{ + vt1603_set_reg8(vt1603, VT1603_CR_REG, 0x00); + vt1603_set_reg8(vt1603, 0xc6, 0x00); + vt1603_set_reg8(vt1603, VT1603_AMCR_REG, BIT0); +} + +static inline void vt1603_bat_pen_manual(struct vt1603 *vt1603) +{ + vt1603_setbits(vt1603, VT1603_INTCR_REG, BIT7); +} + +static void vt1603_bat_power_up(struct vt1603 *vt1603) +{ + if (vt1603_get_reg8(vt1603, VT1603_PWC_REG) != 0x08) + vt1603_set_reg8(vt1603, VT1603_PWC_REG, 0x08); +} + +static int vt1603_read_volt(struct vt1603 *vt1603) +{ + int timeout = 2000; + int ret = 0; + int value; + + // wait for interrupt that adc converted completed. + do { + if (vt1603_get_reg8(vt1603, VT1603_INTS_REG) & BIT0) + break; + } while (timeout--); + + if (!timeout) { + pr_err("wait adc end timeout ?!\n"); + return -ETIMEDOUT; + } + + ret = vt1603_get_bat_data(vt1603, &value); + if (ret < 0) { + pr_err("vt1603 get bat adc data Failed!\n"); + return ret; + } + + return value; +} + +static int vt1603_manual_read_adc(struct vt1603 *vt1603) +{ + int i; + int ret = 0; + uint32_t sum = 0; + + /* enable sar-adc power and clock */ + vt1603_bat_power_up(vt1603); + /* enable pen down/up to avoid miss irq */ + vt1603_bat_pen_manual(vt1603); + /* switch vt1603 to battery detect mode */ + vt1603_switch_to_bat_mode(vt1603); + /* do conversion use battery manual mode */ + vt1603_setbits(vt1603, VT1603_INTS_REG, BIT0); + vt1603_set_reg8(vt1603, VT1603_CR_REG, BIT4); + + for (i = 0; i < 4; i++) { + ret = vt1603_read_volt(vt1603); + if (ret < 0) + break; + sum += ret; + + vt1603_setbits(vt1603, VT1603_INTS_REG, BIT0); + vt1603_set_reg8(vt1603, VT1603_CR_REG, BIT4); //start manual ADC mode + } + vt1603_clrbits(vt1603, VT1603_INTCR_REG, BIT7); + vt1603_setbits(vt1603, VT1603_INTS_REG, BIT0 | BIT3); + vt1603_set_reg8(vt1603, VT1603_CR_REG, BIT1); + + return (ret < 0) ? ret : (sum >> 2); +} + +static inline int volt_reg_to_mV(int value) +{ + return ((value * 1047) / 1000); +} + +static int vt1603_bat_read_voltage(struct vt1603_device_info *di, int *intval) +{ + int ret = vt1603_manual_read_adc(di->vt1603); + if (ret < 0) + return ret; + + *intval = volt_reg_to_mV(ret); + return 0; +} + +static int vt1603_bat_read_status(struct vt1603_device_info *di, int *intval) +{ + int status; + + status = charger_get_status(); + if (status < 0) + return status; + + if (status == POWER_SUPPLY_STATUS_CHARGING && di->capacity == 100) + status = POWER_SUPPLY_STATUS_FULL; + + batt_leds_update(status); + *intval = status; + return 0; +} + +static int vt1603_proc_read(char *buf, char **start, off_t offset, int len, + int *eof, void *data) +{ + int l = 0, i; + int ret, status, dcin, voltage, full; + struct vt1603_device_info *di = vt1603_dev_info; + + mutex_lock(&di->mutex); + + ret = vt1603_bat_read_status(di, &status); + if (ret) { + pr_err("vt1603_bat_read_status failed\n"); + goto out; + } + voltage = vt1603_manual_read_adc(di->vt1603); + if (voltage < 0) { + pr_err("vt1603_manual_read_adc failed\n"); + goto out; + } + + dcin = power_supply_is_system_supplied(); + full = charger_is_full(); + + l += sprintf(buf + l, "status : %d\n", status); + l += sprintf(buf + l, "dcin : %d\n", dcin); + l += sprintf(buf + l, "voltage : %d\n", voltage); + l += sprintf(buf + l, "full : %d\n", full); + l += sprintf(buf + l, "sleeping : %d\n", di->sleeping); + l += sprintf(buf + l, "debug : %d\n", di->debug); + + for (i = 0; i < COMPENSATION_COUNT; i++) { + l += sprintf(buf +l, "compensation %10s : %d\n", + compensation_strings[i], di->compensation[i]); + } + + /* clear after read */ + di->sleeping = 0; +out: + mutex_unlock(&di->mutex); + return l; +} + +static int vt1603_proc_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int bm, usage; + struct vt1603_device_info *di = vt1603_dev_info; + int capacity; + + if (sscanf(buffer, "capacity=%d", &capacity)) { + di->capacity = capacity; + power_supply_changed(&di->ps_bat); + return count; + } + + if (sscanf(buffer, "debug=%d", &di->debug)) + return count; + + if (sscanf(buffer, "MODULE_CHANGE:%d-%d", &bm, &usage) < 2) + return 0; + + if (bm < 0 || bm >= COMPENSATION_COUNT) { + pr_err("bm %d error, [0, %d)\n", bm, COMPENSATION_COUNT); + return 0; + } + + if (usage > 100 || usage < 0) { + pr_err("usage %d error\n", usage); + return 0; + } + + mutex_lock(&di->mutex); + di->compensation[bm] = usage; + mutex_unlock(&di->mutex); + return count; +} + +#define VT1603_PROC_NAME "battery_calibration" + +static void vt1603_proc_init(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_entry(VT1603_PROC_NAME, 0666, NULL); + if (entry) { + entry->read_proc = vt1603_proc_read; + entry->write_proc = vt1603_proc_write; + } +} + +static void vt1603_proc_cleanup(void) +{ + remove_proc_entry(VT1603_PROC_NAME, NULL); +} + +#define to_vt1603_device_info(x) container_of((x), \ + struct vt1603_device_info, ps_bat); + +static int vt1603_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct vt1603_device_info *di = to_vt1603_device_info(psy); + + mutex_lock(&di->mutex); + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + ret = vt1603_bat_read_status(di, &val->intval); + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = di->capacity; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = vt1603_bat_read_voltage(di, &val->intval); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = 250; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = 1; + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&di->mutex); + return ret; +} + +static void vt1603_external_power_changed(struct power_supply *psy) +{ + power_supply_changed(psy); +} + +static enum power_supply_property vt1603_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, +}; + +static int __devinit vt1603_batt_probe(struct platform_device *pdev) +{ + struct vt1603_device_info *di; + int ret; + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) { + dev_err(&pdev->dev, "no memery\n"); + return -ENOMEM; + } + + di->dev = &pdev->dev; + di->vt1603 = dev_get_platdata(&pdev->dev); + di->capacity = 50; + + mutex_init(&di->mutex); + + di->ps_bat.name = "battery"; + di->ps_bat.type = POWER_SUPPLY_TYPE_BATTERY; + di->ps_bat.properties = vt1603_battery_props; + di->ps_bat.num_properties = ARRAY_SIZE(vt1603_battery_props); + di->ps_bat.get_property = vt1603_battery_get_property; + di->ps_bat.external_power_changed = vt1603_external_power_changed; + + ret = power_supply_register(di->dev, &di->ps_bat); + if (ret) { + dev_err(di->dev, "failed to register battery: %d\n", ret); + kfree(di); + return ret; + } + + platform_set_drvdata(pdev, di); + vt1603_dev_info = di; + + vt1603_proc_init(); + + pr_info("VT1603 Battery Driver Installed!\n"); + return 0; +} + +static int __devexit vt1603_batt_remove(struct platform_device *pdev) +{ + struct vt1603_device_info *di = platform_get_drvdata(pdev); + vt1603_proc_cleanup(); + power_supply_unregister(&di->ps_bat); + kfree(di); + vt1603_dev_info = NULL; + pr_info("VT1603 Battery Driver Removed!\n"); + return 0; +} + +static int vt1603_batt_suspend_prepare(struct device *dev) +{ + struct vt1603_device_info *di = dev_get_drvdata(dev); + int status, ret; + + ret = vt1603_bat_read_status(di, &status); + if (ret) { + pr_err("vt1603_bat_read_status failed\n"); + return 0; + } + + if (status == POWER_SUPPLY_STATUS_CHARGING) + batt_leds_suspend_prepare(); + + return 0; +} + +static int vt1603_batt_suspend(struct device *dev) +{ + return 0; +} + +static int vt1603_batt_resume(struct device *dev) +{ + struct vt1603_device_info *di = dev_get_drvdata(dev); + di->sleeping = 1; + return 0; +} + +static void vt1603_batt_resume_complete(struct device *dev) +{ + return batt_leds_resume_complete(); +} + +static const struct dev_pm_ops vt1603_batt_manager_pm = { + .prepare = vt1603_batt_suspend_prepare, + .suspend = vt1603_batt_suspend, + .resume = vt1603_batt_resume, + .complete = vt1603_batt_resume_complete, +}; + +static struct platform_driver vt1603_batt_driver = { + .driver = { + .name = "vt1603-batt", + .owner = THIS_MODULE, + .pm = &vt1603_batt_manager_pm, + }, + .probe = vt1603_batt_probe, + .remove = __devexit_p(vt1603_batt_remove), +}; + +static int parse_battery_param(void) +{ + char env[] = "wmt.battery.param"; + char buf[64]; + size_t l = sizeof(buf); + + if (wmt_getsyspara(env, buf, &l)) + return -EINVAL; + + return prefixcmp(buf, "vt1603") ? -ENODEV : 0; +} + +static int __init vt1603_batt_init(void) +{ + if (parse_battery_param()) + return -EINVAL; + + batt_leds_setup(); + return platform_driver_register(&vt1603_batt_driver); +} + +static void __exit vt1603_batt_exit(void) +{ + platform_driver_unregister(&vt1603_batt_driver); + batt_leds_cleanup(); +} + +module_init(vt1603_batt_init); +module_exit(vt1603_batt_exit); + +MODULE_AUTHOR("WonderMedia"); +MODULE_DESCRIPTION("WonderMedia VT1603 Adc Battery Driver"); +MODULE_LICENSE("GPL"); + |