zte's code,first commit
Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/power/zx234502_charger.c b/ap/os/linux/linux-3.4.x/drivers/power/zx234502_charger.c
new file mode 100644
index 0000000..9e72408
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/power/zx234502_charger.c
@@ -0,0 +1,2391 @@
+/*
+ * Driver for the TI zx234502 battery charger.
+ *
+ * Author: Mark A. Greer <mgreer@animalcreek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/power_supply.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/kthread.h>
+//#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+#include <linux/power/zx234502_charger.h>
+#include <linux/mfd/zx234290.h>
+
+#include <mach/gpio.h>
+#include <mach/pcu.h>
+#include <mach/zx29_usb.h>
+#include <linux/workqueue.h>
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+
+/*
+ * The FAULT register is latched by the zx234502 (except for NTC_FAULT)
+ * so the first read after a fault returns the latched value and subsequent
+ * reads return the current value. In order to return the fault status
+ * to the user, have the interrupt handler save the reg's value and retrieve
+ * it in the appropriate health/status routine. Each routine has its own
+ * flag indicating whether it should use the value stored by the last run
+ * of the interrupt handler or do an actual reg read. That way each routine
+ * can report back whatever fault may have occured.
+ */
+struct zx234502_dev_info {
+ struct i2c_client *client;
+ struct device *dev;
+ struct power_supply charger;
+ struct power_supply battery;
+ struct power_supply boost;
+ char model_name[I2C_NAME_SIZE];
+ kernel_ulong_t model;
+ unsigned int gpio_int;
+ unsigned int irq;
+ struct mutex bs_reg_lock;
+ bool first_time; /*let the first reset do not ask mmi*/
+ bool charger_health_valid;
+ bool battery_health_valid;
+ bool battery_status_valid;
+ u8 ciis_curr_reg;
+ u8 cbis_curr_reg;
+ u8 pis_curr_reg;
+ u8 cfis_curr_reg;
+
+ u8 ciis_pre_reg;
+ u8 cbis_pre_reg;
+ u8 pis_pre_reg;
+ u8 cfis_pre_reg;
+ u8 watchdog;
+ u8 boost_online_flag;
+ struct delayed_work boostWorkStruct ;
+ struct workqueue_struct *boostQueue;
+ struct semaphore chgirq_sem;
+ struct task_struct *chg_irq_thread;
+ u16 boostcount;
+
+ struct zx234502_platform_data *pdata;
+ //unsigned int chg_type;
+};
+
+//struct zx234502_platform_data *g_platform_data = NULL;
+struct zx234502_dev_info *g_bdi = NULL;
+
+/* REG01[2:0] (ISET_DCIN) in mAh */
+static const int zx234502_in_ilimit_values[] = {
+ 150, 450, 850, 1000, 1500, 2000, 2500, 3000
+};
+/* REG01[6:3] (VINDPM) in mVh */
+static const int zx234502_vindpm_values[] = {
+ 3880, 3960, 4040, 4120,
+ 4200,4280, 4360, 4440,
+ 4520,4600, 4680, 4760,
+ 4840,4920, 5000, 5080,
+};
+
+/*
+ * The tables below provide a 2-way mapping for the value that goes in
+ * the register field and the real-world value that it represents.
+ * The index of the array is the value that goes in the register; the
+ * number at that index in the array is the real-world value that it
+ * represents.
+ */
+/* REG02[7:2] (ISETA) in mAh */
+static const int zx234502_isc_ichg_values[] = {
+ 512, 576, 640, 704, 768, 832, 896, 960,
+ 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472,
+ 1536, 1600, 1664, 1728, 1792, 1856, 1920, 1984,
+ 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496,
+ 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008,
+ 3072, 3136, 3200, 3264, 3328, 3392, 3456, 3520,
+ 3584, 3648, 3712, 3776, 3840, 3904, 3968, 4032,
+ 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544
+};
+
+/* REG04[3:1] (VSETA) in mV */
+static const int zx234502_cvc_vseta_values[] = {
+ 4100, 4150, 4200, 4250, 4300, 4350, 4400, 4450,
+};
+
+/* REG02[7:5] (VSYS_MIN) in mV */
+static const int zx234502_vsc_sysmin_values[] = {
+ 3100, 3200, 3300, 3400, 3500, 3600, 3700,3800
+};
+static int stopchg_flag = 0;
+/*
+ * Return the index in 'tbl' of greatest value that is less than or equal to
+ * 'val'. The index range returned is 0 to 'tbl_size' - 1. Assumes that
+ * the values in 'tbl' are sorted from smallest to largest and 'tbl_size'
+ * is less than 2^8.
+ */
+static u8 zx234502_find_idx(const int tbl[], int tbl_size, int v)
+{
+ int i;
+
+ for (i = 1; i < tbl_size; i++)
+ if (v < tbl[i])
+ break;
+
+ return i - 1;
+}
+
+/* Basic driver I/O routines */
+
+static int zx234502_read(struct zx234502_dev_info *bdi, u8 reg, u8 *data)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(bdi->client, reg);
+ if (ret < 0)
+ return ret;
+
+ *data = ret;
+ return 0;
+}
+
+static int zx234502_write(struct zx234502_dev_info *bdi, u8 reg, u8 data)
+{
+ return i2c_smbus_write_byte_data(bdi->client, reg, data);
+}
+
+static int zx234502_read_mask(struct zx234502_dev_info *bdi, u8 reg,
+ u8 mask, u8 shift, u8 *data)
+{
+ u8 v;
+ int ret;
+
+ ret = zx234502_read(bdi, reg, &v);
+ if (ret < 0)
+ return ret;
+
+ v &= mask;
+ v >>= shift;
+ *data = v;
+
+ return 0;
+}
+
+static int zx234502_write_mask(struct zx234502_dev_info *bdi, u8 reg,
+ u8 mask, u8 shift, u8 data)
+{
+ u8 v;
+ int ret;
+
+ ret = zx234502_read(bdi, reg, &v);
+ if (ret < 0)
+ return ret;
+
+ v &= ~mask;
+ v |= ((data << shift) & mask);
+
+ return zx234502_write(bdi, reg, v);
+}
+
+static int zx234502_get_field_val(struct zx234502_dev_info *bdi,
+ u8 reg, u8 mask, u8 shift,
+ const int tbl[], int tbl_size,
+ int *val)
+{
+ u8 v;
+ int ret;
+
+ ret = zx234502_read_mask(bdi, reg, mask, shift, &v);
+ if (ret < 0)
+ return ret;
+
+ v = (v >= tbl_size) ? (tbl_size - 1) : v;
+ *val = tbl[v];
+
+ return 0;
+}
+
+static int zx234502_set_field_val(struct zx234502_dev_info *bdi,
+ u8 reg, u8 mask, u8 shift,
+ const int tbl[], int tbl_size,
+ int val)
+{
+ u8 idx;
+
+ idx = zx234502_find_idx(tbl, tbl_size, val);
+
+ return zx234502_write_mask(bdi, reg, mask, shift, idx);
+}
+
+//#ifdef CONFIG_SYSFS
+#if 0
+/*
+ * There are a numerous options that are configurable on the zx234502
+ * that go well beyond what the power_supply properties provide access to.
+ * Provide sysfs access to them so they can be examined and possibly modified
+ * on the fly. They will be provided for the charger power_supply object only
+ * and will be prefixed by 'f_' to make them easier to recognize.
+ */
+
+struct zx234502_sysfs_field_info {
+ struct device_attribute attr;
+ u8 reg;
+ u8 mask;
+ u8 shift;
+};
+
+
+#define ZX234502_SYSFS_FIELD(_name, r, f, m, store) \
+{ \
+ .attr = __ATTR(f_##_name, m, zx234502_sysfs_show, store), \
+ .reg = ZX234502_REG_##r, \
+ .mask = ZX234502_REG_##r##_##f##_MASK, \
+ .shift = ZX234502_REG_##r##_##f##_SHIFT, \
+}
+
+#define ZX234502_SYSFS_FIELD_RW(_name, r, f) \
+ ZX234502_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO, \
+ zx234502_sysfs_store)
+
+#define ZX234502_SYSFS_FIELD_RO(_name, r, f) \
+ ZX234502_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL)
+
+static ssize_t zx234502_sysfs_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t zx234502_sysfs_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+
+/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */
+//#undef SS
+
+static struct zx234502_sysfs_field_info zx234502_sysfs_field_tbl[] = {
+ /* sysfs name reg field in reg */
+ ZX234502_SYSFS_FIELD_RW(chg_reset, MS, CHGRST),
+ ZX234502_SYSFS_FIELD_RW(pmuon, MS, PMUON),
+ ZX234502_SYSFS_FIELD_RW(en_ship, MS, ENSHIP),
+ ZX234502_SYSFS_FIELD_RW(en_otg, MS, ENOTG),
+ ZX234502_SYSFS_FIELD_RW(chg_config, MS, ENCHG),
+ ZX234502_SYSFS_FIELD_RW(en_powerbank, MS, PWRBNK),
+ ZX234502_SYSFS_FIELD_RW(insus, MS, INSUS),
+ ZX234502_SYSFS_FIELD_RW(in_limit, ISC, ISET_DCIN),
+ ZX234502_SYSFS_FIELD_RW(vsys_min, VSC, VSYS_MIN),
+ ZX234502_SYSFS_FIELD_RW(ichg, CCC, ISETA),
+ ZX234502_SYSFS_FIELD_RW(force_ichg_50pct, CCC, ICHG_50PCT),
+ ZX234502_SYSFS_FIELD_RW(iprechg, CVC, IPRECHG),
+ ZX234502_SYSFS_FIELD_RW(vbat_full, CVC, VBAT),
+ ZX234502_SYSFS_FIELD_RW(vpre_to_fast, CVC, VBATFC),
+ ZX234502_SYSFS_FIELD_RW(en_timer, CTC, EN_TIMER),
+ ZX234502_SYSFS_FIELD_RW(en_2timer, CTC, EN_2XTIMER),
+ ZX234502_SYSFS_FIELD_RW(stopchg_flag, OTGC, OTGV),
+ ZX234502_SYSFS_FIELD_RW(iotg_limit, OTGC, OTGI_LIM),
+ ZX234502_SYSFS_FIELD_RW(ents_otg, OTGC, ENTS_OTG),
+ ZX234502_SYSFS_FIELD_RO(en_therm, THR, EN_THERM),
+ ZX234502_SYSFS_FIELD_RW(therm_threshold, THR, THERM_THLD),
+ ZX234502_SYSFS_FIELD_RW(en_2det, THR, EN_2DET),
+ ZX234502_SYSFS_FIELD_RW(en_1det, THR, EN_1DET),
+ ZX234502_SYSFS_FIELD_RW(en_jeita, THR, EN_JEITA),
+ ZX234502_SYSFS_FIELD_RW(en_ilimitdj, THR, EN_ILIMITDJ),
+ ZX234502_SYSFS_FIELD_RW(tscold, TS, COLD),
+ ZX234502_SYSFS_FIELD_RW(tscool, TS, COOL),
+ ZX234502_SYSFS_FIELD_RW(tswarm, TS, WARM),
+ ZX234502_SYSFS_FIELD_RW(tshot, TS, HOT),
+ ZX234502_SYSFS_FIELD_RW(ntcdet, PTS,NTCDET),
+ ZX234502_SYSFS_FIELD_RW(int_clear, CIIS, INT),
+ ZX234502_SYSFS_FIELD_RO(ciis_reg, CIIS, ALL),
+ ZX234502_SYSFS_FIELD_RW(mask_chgrun, CIIM, MASK_CHGRUN),
+ ZX234502_SYSFS_FIELD_RW(mask_inlimit, CIIM, MASK_INLIMIT),
+ ZX234502_SYSFS_FIELD_RW(mask_thr, CIIM, MASK_THR),
+ ZX234502_SYSFS_FIELD_RW(mask_ts, CIIM, MASK_TS),
+ ZX234502_SYSFS_FIELD_RW(mask_dcdet, CIIM, MASK_DCDET),
+ ZX234502_SYSFS_FIELD_RO(cbis_reg, CBIS, ALL),
+ ZX234502_SYSFS_FIELD_RW(mask_pg, CBIM, MASK_DCIN_PG),
+ ZX234502_SYSFS_FIELD_RW(mask_batlow, CBIM, MASK_BATLOW),
+ ZX234502_SYSFS_FIELD_RW(mask_nobat, CBIM, MASK_NOBAT),
+ ZX234502_SYSFS_FIELD_RW(mask_eoc, CBIM, MASK_EOC),
+ ZX234502_SYSFS_FIELD_RW(mask_timer, CBIM, MASK_SAFE_TIMER),
+ ZX234502_SYSFS_FIELD_RW(mask_otg_fault, CBIM, MASK_OTG_FAULT),
+ ZX234502_SYSFS_FIELD_RO(pis_reg, PIS, ALL),
+ ZX234502_SYSFS_FIELD_RW(mask_pwron_it, PIM, MASK_POWERON_IT),
+ ZX234502_SYSFS_FIELD_RW(mask_pwron_lp, PIM, MASK_POWERON_LP),
+ ZX234502_SYSFS_FIELD_RO(cfis_reg, CFIS, ALL),
+ ZX234502_SYSFS_FIELD_RO(version_info, VER, INFO),
+};
+
+static struct attribute *
+ zx234502_sysfs_attrs[ARRAY_SIZE(zx234502_sysfs_field_tbl) + 1];
+
+static const struct attribute_group zx234502_sysfs_attr_group = {
+ .attrs = zx234502_sysfs_attrs,
+};
+
+static void zx234502_sysfs_init_attrs(void)
+{
+ int i, limit = ARRAY_SIZE(zx234502_sysfs_field_tbl);
+
+ for (i = 0; i < limit; i++)
+ zx234502_sysfs_attrs[i] = &zx234502_sysfs_field_tbl[i].attr.attr;
+
+ zx234502_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
+}
+
+static struct zx234502_sysfs_field_info *zx234502_sysfs_field_lookup(
+ const char *name)
+{
+ int i, limit = ARRAY_SIZE(zx234502_sysfs_field_tbl);
+
+ for (i = 0; i < limit; i++)
+ if (!strcmp(name, zx234502_sysfs_field_tbl[i].attr.attr.name))
+ break;
+
+ if (i >= limit)
+ return NULL;
+
+ return &zx234502_sysfs_field_tbl[i];
+}
+
+static ssize_t zx234502_sysfs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, charger);
+ struct zx234502_sysfs_field_info *info;
+ int ret;
+ u8 v;
+
+ info = zx234502_sysfs_field_lookup(attr->attr.name);
+ if (!info)
+ return -EINVAL;
+
+ ret = zx234502_read_mask(bdi, info->reg, info->mask, info->shift, &v);
+ if (ret)
+ return ret;
+
+ return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
+}
+
+static ssize_t zx234502_sysfs_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, charger);
+ struct zx234502_sysfs_field_info *info;
+ int ret;
+ u8 v;
+
+ info = zx234502_sysfs_field_lookup(attr->attr.name);
+ if (!info)
+ return -EINVAL;
+
+ ret = kstrtou8(buf, 0, &v);
+ if (ret < 0)
+ return ret;
+
+ ret = zx234502_write_mask(bdi, info->reg, info->mask, info->shift, v);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static int zx234502_sysfs_create_group(struct zx234502_dev_info *bdi)
+{
+ zx234502_sysfs_init_attrs();
+
+ return sysfs_create_group(&bdi->charger.dev->kobj,
+ &zx234502_sysfs_attr_group);
+}
+
+static void zx234502_sysfs_remove_group(struct zx234502_dev_info *bdi)
+{
+ sysfs_remove_group(&bdi->charger.dev->kobj, &zx234502_sysfs_attr_group);
+}
+#else
+static int zx234502_sysfs_create_group(struct zx234502_dev_info *bdi)
+{
+ return 0;
+}
+
+static inline void zx234502_sysfs_remove_group(struct zx234502_dev_info *bdi) {}
+#endif
+
+#if 0
+/*set the Vsys min*/
+static int zx234502_set_vsys_min(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ return zx234502_set_field_val(bdi, ZX234502_REG_VSC,
+ ZX234502_REG_VSC_VSYS_MIN_MASK, ZX234502_REG_VSC_VSYS_MIN_SHIFT,
+ zx234502_cvc_vseta_values,
+ ARRAY_SIZE(zx234502_cvc_vseta_values), val->intval);
+ //return 0
+}
+#endif
+static int zx234502_register_reset(struct zx234502_dev_info *bdi)
+{
+ int ret, limit = 100;
+ u8 v;
+
+ /* Reset the registers */
+ ret = zx234502_write_mask(bdi, ZX234502_REG_MS,ZX234502_REG_MS_CHGRST_MASK,ZX234502_REG_MS_CHGRST_SHIFT,0x1);
+ if (ret < 0)
+ return ret;
+
+ /* Reset bit will be cleared by hardware so poll until it is */
+ do
+ {
+ ret = zx234502_read_mask(bdi, ZX234502_REG_MS,ZX234502_REG_MS_CHGRST_MASK,ZX234502_REG_MS_CHGRST_SHIFT,&v);
+ if (ret < 0)
+ return ret;
+
+ if (!v)
+ break;
+
+ udelay(10);
+ } while (--limit);
+
+ if (!limit)
+ return -EIO;
+
+ return 0;
+}
+
+
+/* Charger power supply property routines */
+
+static int zx234502_charger_get_charge_type(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ val->intval = bdi->charger.type;
+ return 0;
+}
+
+static int zx234502_charger_get_status(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 cbis_reg=0,ms_reg=0;
+ int status=POWER_SUPPLY_STATUS_UNKNOWN;
+ int ret=0;
+
+ mutex_lock(&bdi->bs_reg_lock);
+
+ if (bdi->battery_status_valid) {
+ cbis_reg = bdi->cbis_curr_reg;
+ bdi->battery_status_valid = false;
+ mutex_unlock(&bdi->bs_reg_lock);
+ } else {
+ mutex_unlock(&bdi->bs_reg_lock);
+
+ ret = zx234502_read(bdi, ZX234502_REG_CBIS, &cbis_reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = zx234502_read(bdi, ZX234502_REG_MS, &ms_reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * The battery must be discharging when any of these are true:
+ * - there is no good power source;
+ * - there is a charge fault.
+ * Could also be discharging when in "supplement mode" but
+ * there is no way to tell when its in that mode.
+ */
+ if (!(cbis_reg & ZX234502_REG_CBIS_DCIN_PG_MASK )||(cbis_reg & ZX234502_REG_CBIS_NOBAT_MASK )) {
+ status = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+ else if (ms_reg & ZX234502_REG_MS_ENCHG_MASK){
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ }
+ // disable or full
+ else if(ms_reg & ZX234502_REG_MS_INSUS_MASK)
+ {
+ if (((cbis_reg & ZX234502_REG_CBIS_CHGSTAT_MASK) >> ZX234502_REG_CBIS_CHGSTAT_SHIFT)== 3)
+ {
+ status = POWER_SUPPLY_STATUS_FULL;
+ }
+ else
+ status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ }
+ else {
+ cbis_reg &= ZX234502_REG_CBIS_CHGSTAT_MASK;
+ cbis_reg >>= ZX234502_REG_CBIS_CHGSTAT_SHIFT;
+
+ switch (cbis_reg) {
+ case 0x0: /* Charging */
+ case 0x2: /* ReCharging frome THERM */
+ status = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case 0x3: /* Charge Termination Done */
+ status = POWER_SUPPLY_STATUS_FULL;
+ break;
+ default:
+ ret = -EIO;
+ }
+ }
+
+ if (!ret)
+ val->intval = status;
+
+ return ret;
+}
+
+static int zx234502_charger_get_health(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 ciis_reg=0, cbis_reg=0, cfis_reg=0;
+ int health=0, ret=0;
+
+ mutex_lock(&bdi->bs_reg_lock);
+
+ if (bdi->charger_health_valid) {
+ bdi->charger_health_valid = false;
+ cbis_reg = bdi->cbis_curr_reg;
+ ciis_reg = bdi->ciis_curr_reg;
+ cfis_reg = bdi->cfis_curr_reg;
+ mutex_unlock(&bdi->bs_reg_lock);
+ } else {
+ mutex_unlock(&bdi->bs_reg_lock);
+
+ ret = zx234502_read(bdi, ZX234502_REG_CIIS, &ciis_reg);
+ if (ret < 0)
+ return ret;
+ ret = zx234502_read(bdi, ZX234502_REG_CBIS, &cbis_reg);
+ if (ret < 0)
+ return ret;
+ ret = zx234502_read(bdi, ZX234502_REG_CFIS, &cfis_reg);
+ if (ret < 0)
+ return ret;
+
+ printk(KERN_INFO "zx234502_charger_get_health REG_0xa=0x%x,REG_0xc=0x%x,REG_0x10=0x%x.\n",ciis_reg,cbis_reg,cfis_reg);
+
+ }
+
+ if (cbis_reg & ZX234502_REG_CBIS_OTG_FAULT_MASK) {
+ /*
+ * This could be over-current or over-voltage but there's
+ * no way to tell which. Return 'OVERVOLTAGE' since there
+ * isn't an 'OVERCURRENT' value defined that we can return
+ * even if it was over-current.
+ */
+ health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ }
+ else if(cbis_reg & ZX234502_REG_CBIS_SAFE_TIMER_MASK) {
+ health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ }
+ else if(cbis_reg & ZX234502_REG_CBIS_DCIN_PG_MASK) {
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ }
+ else if(ciis_reg & (ZX234502_REG_CIIS_INLIMIT_MASK|ZX234502_REG_CIIS_THERM_MASK)) {
+ health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ }
+ else if(cfis_reg & ZX234502_REG_CFIS_THSD_MASK){
+ health = POWER_SUPPLY_HEALTH_OVERHEAT; /*the chip hot error*/
+ }
+ else{
+ health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ }
+
+ val->intval = health;
+
+ return 0;
+}
+
+int zx234502_charger_get_online(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 v;
+ int ret;
+
+ ret = zx234502_read_mask(bdi, ZX234502_REG_CBIS,ZX234502_REG_CBIS_DCIN_PG_MASK,
+ ZX234502_REG_CBIS_DCIN_PG_SHIFT, &v);
+ if (ret < 0)
+ return ret;
+
+ val->intval = v;
+ return 0;
+}EXPORT_SYMBOL (zx234502_charger_get_online);
+#if 0
+static int zx234502_charger_get_current(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ int curr, ret;
+
+ ret = zx234502_get_field_val(bdi, ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK, ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ zx234502_in_ilimit_values,
+ ARRAY_SIZE(zx234502_in_ilimit_values), &curr);
+ if (ret < 0)
+ return ret;
+
+ val->intval = curr;
+ return 0;
+}
+
+static int zx234502_charger_get_current_max(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ int idx = ARRAY_SIZE(zx234502_in_ilimit_values) - 1;
+
+ val->intval = zx234502_in_ilimit_values[idx];
+ return 0;
+}
+
+static int zx234502_charger_get_voltage(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+#if 0
+ int voltage, ret;
+ ret = zx234502_get_field_val(bdi, ZX234502_REG_CVC,
+ ZX234502_REG_CVC_VBAT_MASK, ZX234502_REG_CVC_VBAT_SHIFT,
+ zx234502_cvc_vseta_values,
+ ARRAY_SIZE(zx234502_cvc_vseta_values), &voltage);
+ if (ret < 0)
+ return ret;
+
+ val->intval = voltage;
+#endif
+return 0;
+}
+#endif
+
+static int zx234502_charger_get_charger_enabled(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 charger_enabled;
+ int ret;
+
+ ret = zx234502_read_mask(bdi, ZX234502_REG_MS,
+ ZX234502_REG_MS_INSUS_MASK,
+ ZX234502_REG_MS_INSUS_SHIFT, &charger_enabled);
+ if (ret < 0)
+ return ret;
+
+ val->intval = !charger_enabled;
+ return 0;
+}
+static int zx234502_charger_get_voltage_max(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ int voltage, ret;
+
+ ret = zx234502_get_field_val(bdi, ZX234502_REG_CVC,
+ ZX234502_REG_CVC_VBAT_MASK, ZX234502_REG_CVC_VBAT_SHIFT,
+ zx234502_cvc_vseta_values,
+ ARRAY_SIZE(zx234502_cvc_vseta_values), &voltage);
+ if (ret < 0)
+ return ret;
+
+ val->intval = voltage;
+ return 0;
+
+}
+#if 0
+static int zx234502_charger_set_current(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ return zx234502_set_field_val(bdi, ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK, ZX234502_REG_ISC_ISET_DCIN_MASK,
+ zx234502_in_ilimit_values,
+ ARRAY_SIZE(zx234502_in_ilimit_values), val->intval);
+
+}
+#endif
+static int zx234502_charger_set_voltage(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ return zx234502_set_field_val(bdi, ZX234502_REG_CVC,
+ ZX234502_REG_CVC_VBAT_MASK, ZX234502_REG_CVC_VBAT_SHIFT,
+ zx234502_cvc_vseta_values,
+ ARRAY_SIZE(zx234502_cvc_vseta_values), val->intval);
+}
+
+static int zx234502_charger_set_charger_config(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ int ret;
+ union power_supply_propval enable_charge;
+
+ if (val->intval){
+ enable_charge.intval = 0 ;
+ stopchg_flag = 1;
+ ret = zx234502_write_mask(bdi, ZX234502_REG_OTGC,
+ ZX234502_REG_OTGC_OTGV_MASK,
+ ZX234502_REG_OTGC_OTGV_SHIFT,1);
+ printk("mmi start chg\n");
+ }
+ else{
+ stopchg_flag = 2;
+ enable_charge.intval = 1 ;
+ ret = zx234502_write_mask(bdi, ZX234502_REG_OTGC,
+ ZX234502_REG_OTGC_OTGV_MASK,
+ ZX234502_REG_OTGC_OTGV_SHIFT,2);
+ printk("mmi stop chg\n");
+ }
+
+ ret = zx234502_write_mask(bdi, ZX234502_REG_MS,
+ ZX234502_REG_MS_INSUS_MASK,
+ ZX234502_REG_MS_INSUS_SHIFT, enable_charge.intval ); /*0:disable 1:enable*/
+
+ return ret;
+}
+
+
+static int zx234502_charger_get_property(struct power_supply *psy,enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi = container_of(psy, struct zx234502_dev_info, charger);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_get_sync(bdi->dev);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PC1_AC2:
+ ret = zx234502_charger_get_charge_type(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = zx234502_charger_get_status(bdi, val);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = zx234502_charger_get_health(bdi, val);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = zx234502_charger_get_online(bdi, val);
+ break;
+
+ /*
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = zx234502_charger_get_current(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ ret = zx234502_charger_get_current_max(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = zx234502_charger_get_voltage(bdi, val);
+ break;
+*/
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ ret = zx234502_charger_get_voltage_max(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_ENABLED:
+ ret = zx234502_charger_get_charger_enabled(bdi, val);
+ break;
+ default:
+ ret = -ENODATA;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_charger_set_property(struct power_supply *psy,enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, charger);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_get_sync(bdi->dev);
+
+ switch (psp) {
+#if 0
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = zx234502_charger_set_current(bdi, val);
+ break;
+#endif
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ ret = zx234502_charger_set_voltage(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_ENABLED:
+ ret = zx234502_charger_set_charger_config(bdi, val);
+ power_supply_changed(&bdi->charger);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_charger_property_is_writeable(struct power_supply *psy,enum power_supply_property psp)
+{
+ int ret;
+
+ switch (psp)
+ {
+ //case POWER_SUPPLY_PROP_CURRENT_NOW:
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ case POWER_SUPPLY_PROP_CHARGE_ENABLED:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property zx234502_charger_properties[] = {
+ POWER_SUPPLY_PROP_PC1_AC2,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_ONLINE,
+ //POWER_SUPPLY_PROP_CURRENT_NOW,
+ //POWER_SUPPLY_PROP_CURRENT_MAX,
+ //POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CHARGE_ENABLED,
+};
+
+static char *zx234502_charger_supplied_to[] = {
+ "main-battery",
+};
+
+static void zx234502_charger_init(struct power_supply *charger)
+{
+ charger->name = "charger";
+ charger->type = POWER_SUPPLY_PCAC_UNKNOWN;
+ charger->properties = zx234502_charger_properties;
+ charger->num_properties = ARRAY_SIZE(zx234502_charger_properties);
+ charger->supplied_to = zx234502_charger_supplied_to;
+ //charger->num_supplies = ARRAY_SIZE(zx234502_charger_supplied_to);
+ charger->get_property = zx234502_charger_get_property;
+ charger->set_property = zx234502_charger_set_property;
+ charger->property_is_writeable = zx234502_charger_property_is_writeable;
+}
+
+/* Battery power supply property routines */
+
+static int zx234502_battery_get_health(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 v;
+ int health, ret;
+
+ mutex_lock(&bdi->bs_reg_lock);
+
+ if(true!=bdi->pdata->ts_flag){
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ mutex_unlock(&bdi->bs_reg_lock);
+ return 0;
+ }
+
+ if (bdi->battery_health_valid) {
+ v = bdi->ciis_curr_reg;
+ bdi->battery_health_valid = false;
+ } else {
+
+ ret = zx234502_read(bdi, ZX234502_REG_CIIS, &v);
+ if (ret < 0){
+
+ mutex_unlock(&bdi->bs_reg_lock);
+ return ret;
+ }
+ }
+
+ if (v & ZX234502_REG_CIIS_THERM_MASK) {
+ health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ } else {
+ v &= ZX234502_REG_CIIS_TS_METER_MASK;
+ v >>= ZX234502_REG_CIIS_TS_METER_SHIFT;
+
+ switch (v) {
+ case ZX234502_REG_CISS_TS_NORMAL: /* Normal */
+ health = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case ZX234502_REG_CISS_TS_WARM: /*warm*/
+ health = POWER_SUPPLY_HEALTH_WARM;
+ break;
+ case ZX234502_REG_CISS_TS_HOT: /* TS1 Hot */
+ health = POWER_SUPPLY_HEALTH_OVERHEAT;
+ break;
+ case ZX234502_REG_CISS_TS_COOL:/*Cool*/
+ health = POWER_SUPPLY_HEALTH_COOL;
+ break;
+ case ZX234502_REG_CISS_TS_COLD: /* TS1 Cold */
+ health = POWER_SUPPLY_HEALTH_COLD;
+ break;
+ default:
+ health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ }
+ }
+
+ val->intval = health;
+ mutex_unlock(&bdi->bs_reg_lock);
+ return 0;
+}
+
+static int zx234502_battery_get_online(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ u8 batfet_disable;
+ int ret;
+
+ ret = zx234502_read_mask(bdi, ZX234502_REG_CBIS,
+ ZX234502_REG_CBIS_NOBAT_MASK,
+ ZX234502_REG_CBIS_NOBAT_SHIFT, &batfet_disable);
+ if (ret < 0)
+ return ret;
+
+ val->intval = !batfet_disable;
+ return 0;
+}
+#if 0
+static int zx234502_battery_get_capacity(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ int ret;
+ uint volt;
+ int bat_levl = 0;
+ int i =0;
+ //union power_supply_propval * online;
+ struct zx234502_bat_calibration *calibration;
+
+ //zx234502_charger_get_online(bdi,online);
+
+ u8 v;
+ ret = zx234502_read_mask(bdi, ZX234502_REG_CBIS,ZX234502_REG_CBIS_DCIN_PG_MASK,
+ ZX234502_REG_CBIS_DCIN_PG_SHIFT, &v);
+ if(v)
+ calibration = bdi->pdata->charging;
+ else
+ calibration = bdi->pdata->discharging;
+//#ifdef CONFIG_ZX234290_ADC
+ volt = get_battery_voltage();
+//#endif
+ if (volt > calibration[0].voltage) {
+ bat_levl = calibration[0].level;
+ } else {
+ for (i = 0; calibration[i+1].voltage >= 0; i++) {
+ if (volt <= calibration[i].voltage &&
+ volt >= calibration[i+1].voltage) {
+ /* interval found - interpolate within range */
+ bat_levl = calibration[i].level -
+ ((calibration[i].voltage - volt) *
+ (calibration[i].level -
+ calibration[i+1].level)) /
+ (calibration[i].voltage -
+ calibration[i+1].voltage);
+ break;
+ }
+ }
+ }
+
+ val->intval = bat_levl;
+ //return 0;
+
+ return ret;
+}
+#endif
+
+static int zx234502_battery_set_online(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ return zx234502_write_mask(bdi, ZX234502_REG_MS,
+ ZX234502_REG_MS_ENSHIP_MASK,
+ ZX234502_REG_MS_ENSHIP_SHIFT, !val->intval); /*1:enable 0:disable*/
+}
+
+
+static int zx234502_battery_get_property(struct power_supply *psy,enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, battery);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_get_sync(bdi->dev);
+
+ switch (psp) {
+
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = zx234502_battery_get_health(bdi, val);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = zx234502_battery_get_online(bdi, val);
+ break;
+
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = get_adc2_voltage();
+ ret = 0;
+ break;
+
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ //#ifdef CONFIG_ZX234290_ADC
+ val->intval = get_adc1_voltage() - 15;
+ ret = 0;
+ break;
+#if 0
+ case POWER_SUPPLY_PROP_CAPACITY:
+ ret = zx234502_battery_get_capacity(bdi, val);
+ break;
+#endif
+ default:
+ ret = -ENODATA;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_battery_set_property(struct power_supply *psy,enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, battery);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_put_sync(bdi->dev);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = zx234502_battery_set_online(bdi, val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_battery_property_is_writeable(struct power_supply *psy,enum power_supply_property psp)
+{
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property zx234502_battery_properties[] = {
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ //POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static void zx234502_battery_init(struct power_supply *battery)
+{
+ battery->name = "battery";
+ battery->type = POWER_SUPPLY_PCAC_UNKNOWN;
+ battery->properties = zx234502_battery_properties;
+ battery->num_properties = ARRAY_SIZE(zx234502_battery_properties);
+ battery->get_property = zx234502_battery_get_property;
+ battery->set_property = zx234502_battery_set_property;
+ battery->property_is_writeable = zx234502_battery_property_is_writeable;
+}
+
+
+static int zx234502_boost_get_online(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+
+ val->intval = bdi->boost_online_flag;
+ return 0;
+}
+
+
+static int zx234502_boost_get_current_now(struct zx234502_dev_info *bdi,union power_supply_propval *val)
+{
+ //gpio_set1 is GPIO39
+ //gpio_set2 is GPIO40
+ //gpio_set3 is GPIO41
+ int gpio_set1,gpio_set2,gpio_set3;
+
+ gpio_set1 = gpio_get_value(bdi->pdata->boost_cur_gpio1);
+ gpio_set2 = gpio_get_value(bdi->pdata->boost_cur_gpio2);
+ gpio_set3 = gpio_get_value(bdi->pdata->boost_cur_gpio3);
+
+ if((GPIO_LOW==gpio_set1)&(GPIO_LOW==gpio_set2)&(GPIO_HIGH==gpio_set3)){
+ val->intval = 600;
+ }
+ else if((GPIO_LOW==gpio_set1)&(GPIO_HIGH==gpio_set2)&(GPIO_LOW==gpio_set3)){
+ val->intval = 1000;
+ }
+ else if((GPIO_LOW==gpio_set1)&(GPIO_HIGH==gpio_set2)&(GPIO_HIGH==gpio_set3)){
+ val->intval = 1750;
+ }
+ else if((GPIO_HIGH==gpio_set1)&(GPIO_LOW==gpio_set2)&(GPIO_LOW==gpio_set3)){
+ val->intval = 2000;
+ }
+ else if((GPIO_HIGH==gpio_set1)&(GPIO_LOW==gpio_set2)&(GPIO_HIGH==gpio_set3)){
+ val->intval = 2850;
+ }
+ else{
+
+ dev_dbg(bdi->dev, "The boost current set with err\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#if 0
+static int zx234502_boost_get_current_max(struct zx234502_dev_info *bdi, union power_supply_propval *val)
+{
+ val->intval = 2850;
+ return 0;
+}
+#endif
+static int zx234502_boost_set_charge_enable(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ zx234502_write_mask(bdi,ZX234502_REG_MS,
+ ZX234502_REG_MS_PWRBNK_MASK,ZX234502_REG_MS_PWRBNK_SHIFT,val->intval);
+
+ /*set the gpio34 open = HIGH*/
+ gpio_set_value(bdi->pdata->boost_loadswitch_gpio,val->intval);
+ //zx29_gpio_output_data(bdi->pdata->boost_loadswitch_gpio,GPIO_HIGH);
+
+ return 0;
+}
+
+static int zx234502_boost_set_current_now(struct zx234502_dev_info *bdi,const union power_supply_propval *val)
+{
+ //gpio from 35/36/37 changed to 39/40/41
+ //gpio_set1 is GPIO39
+ //gpio_set2 is GPIO40
+ //gpio_set3 is GPIO41
+ int gpio_set1,gpio_set2,gpio_set3;
+
+ if(val->intval < 601){
+ /*0.6A GPIO35:LOW GPIO36:LOW GPIO37:HIGH 40k */
+ gpio_set1 = GPIO_LOW;
+ gpio_set2 = GPIO_LOW;
+ gpio_set3 = GPIO_HIGH;
+ }
+ else if( (600 < val->intval)&&(val->intval< 1001)){
+ /*1A GPIO35:LOW GPIO36:HIGH GPIO37:LOW 20k */
+ gpio_set1 = GPIO_LOW;
+ gpio_set2 = GPIO_HIGH;
+ gpio_set3 = GPIO_LOW;
+ }
+ else if( (1000 < val->intval)&&(val->intval < 1751)){
+ /*1.75A GPIO35:LOW GPIO36:HIGH GPIO37:HIGH 13.3k*/
+ gpio_set1 = GPIO_LOW;
+ gpio_set2 = GPIO_HIGH;
+ gpio_set3 = GPIO_HIGH;
+ }
+ else if(( 1750 < val->intval) &&( val->intval < 2001)){
+ /*2A GPIO35:HIGH GPIO36:LOW GPIO37:LOW 10k */
+ gpio_set1 = GPIO_HIGH;
+ gpio_set2 = GPIO_LOW;
+ gpio_set3 = GPIO_LOW;
+ }
+ else{
+ /*2.85A GPIO35:HIGH GPIO36:LOW GPIO37:HIGH 8k*/
+ gpio_set1 = GPIO_HIGH;
+ gpio_set2 = GPIO_LOW;
+ gpio_set3 = GPIO_HIGH;
+ }
+
+ gpio_set_value(bdi->pdata->boost_cur_gpio1, gpio_set1);
+ gpio_set_value(bdi->pdata->boost_cur_gpio2, gpio_set2);
+ gpio_set_value(bdi->pdata->boost_cur_gpio3, gpio_set3);
+ return 0;
+}
+
+static int zx234502_boost_get_property(struct power_supply *psy,enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, boost);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_get_sync(bdi->dev);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = zx234502_boost_get_online(bdi, val);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = zx234502_boost_get_current_now(bdi, val);
+ break;
+ #if 0
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ ret = zx234502_boost_get_current_max(bdi, val);
+ break;
+ #endif
+ default:
+ ret = -ENODATA;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_boost_set_property(struct power_supply *psy,enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct zx234502_dev_info *bdi =
+ container_of(psy, struct zx234502_dev_info, boost);
+ int ret;
+
+ //dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+ //pm_runtime_put_sync(bdi->dev);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_BOOST_ENABLE:
+ ret = zx234502_boost_set_charge_enable(bdi, val);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = zx234502_boost_set_current_now(bdi, val);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ //pm_runtime_put_sync(bdi->dev);
+ return ret;
+}
+
+static int zx234502_boost_property_is_writeable(struct power_supply *psy,enum power_supply_property psp)
+{
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_BOOST_ENABLE:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property zx234502_boost_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ //WER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_BOOST_ENABLE,
+};
+
+static void zx234502_boost_init(struct power_supply *boost)
+{
+ #ifdef DBG_CHARGE
+ //printk(KERN_INFO "zx234502_boost_init =%x.\n",boost);
+ #endif
+ boost->name = "boost";
+ boost->type = POWER_SUPPLY_PCAC_UNKNOWN;
+ boost->properties = zx234502_boost_properties;
+ boost->num_properties = ARRAY_SIZE(zx234502_boost_properties);
+ boost->get_property = zx234502_boost_get_property;
+ boost->set_property = zx234502_boost_set_property;
+ boost->property_is_writeable = zx234502_boost_property_is_writeable;
+}
+
+
+static int zx234502_charger_gpio_config(struct device *dev,int pin,gpio_func_id func_sel,char *name)
+{
+ int ret = -1;
+
+ if (gpio_is_valid(pin)){
+ ret = gpio_request(pin, name);
+ if (ret){
+ dev_err(dev, "cannot get [%s] gpio\n",name);
+ return -1;
+ }
+ ret = zx29_gpio_config(pin,func_sel);
+ if(ret){
+ dev_err(dev, "cannot config [%s] gpio\n",name);
+ gpio_free(pin);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+//zx234500_charger_gpio_config_input
+static void zx234502_charger_gpio_config_input(struct device *dev,int gpio,gpio_func_id func_sel,char *str)
+{
+ if(zx234502_charger_gpio_config(dev,gpio,func_sel,str)!=0)
+ return;
+ zx29_gpio_set_direction(gpio,GPIO_IN);
+ zx29_gpio_input_data(gpio);
+}
+#endif
+
+//zx234500_charger_gpio_config_output
+static int zx234502_charger_gpio_config_output(struct device *dev,int gpio,gpio_func_id func_sel,char *str,int value2)
+{
+ if(zx234502_charger_gpio_config(dev,gpio,func_sel,str)!=0)
+ return -1;
+ zx29_gpio_set_direction(gpio,GPIO_OUT);
+ zx29_gpio_output_data(gpio,value2);
+
+ return 0;
+}
+
+static int zx234502_boost_gpio_init(struct device *dev, struct zx234502_platform_data *pdata)
+{
+ int ret = -1;
+
+ ret = zx234502_charger_gpio_config_output(dev,pdata->boost_loadswitch_gpio,pdata->boost_loadswitch_fun_sel,"LoadSwitch",GPIO_LOW);
+ /*set the out put current 1A*/
+ ret += zx234502_charger_gpio_config_output(dev,pdata->boost_cur_gpio1,pdata->boost_gpio1_fun_sel,"Iset1",GPIO_LOW);
+ ret += zx234502_charger_gpio_config_output(dev,pdata->boost_cur_gpio2,pdata->boost_gpio2_fun_sel,"Iset2",GPIO_HIGH);
+ ret += zx234502_charger_gpio_config_output(dev,pdata->boost_cur_gpio3,pdata->boost_gpio3_fun_sel,"Iset3",GPIO_LOW);
+
+ return ret;
+}
+
+static void zx234502_boost_gpio_uninit(struct zx234502_platform_data *pdata)
+{
+ gpio_free(pdata->boost_loadswitch_gpio);
+ gpio_free(pdata->boost_cur_gpio1);
+ gpio_free(pdata->boost_cur_gpio2);
+ gpio_free(pdata->boost_cur_gpio3);
+}
+
+/*
+ when BAT goes under BAEdet(3.4V) or CHGRST set 1
+ Group B(A1,A2,A3,A4,A5,A7) registers will reset
+ call this function in init or dcin
+*/
+static int zx234502_charger_config_groupB_Regs(struct zx234502_dev_info *bdi)
+{
+ int ret;
+
+ /*set VINDPM to 4.52V*/
+ ret = zx234502_write_mask(bdi,ZX234502_REG_ISC,
+ ZX234502_REG_ISC_VINDPM_MASK,
+ ZX234502_REG_ISC_VINDPM_SHIFT,
+ 0x8);
+ /*set VSETA to 4.2V*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CVC,
+ ZX234502_REG_CVC_VBAT_MASK,
+ ZX234502_REG_CVC_VBAT_SHIFT,
+ 0x2);
+
+ /*disable the timer*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CTC,
+ ZX234502_REG_CTC_EN_TIMER_MASK,
+ ZX234502_REG_CTC_EN_TIMER_SHIFT,
+ 0x0);
+ /*disable the 2*timer*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CTC,
+ ZX234502_REG_CTC_EN_2XTIMER_MASK,
+ ZX234502_REG_CTC_EN_2XTIMER_SHIFT,
+ 0x0);
+ /*set CVCOMP to 20mV*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CTC,
+ ZX234502_REG_CTC_CVCOMP_MASK,
+ ZX234502_REG_CTC_CVCOMP_SHIFT,
+ 0x4);
+
+
+ /*disable the JETTA*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_THR,
+ ZX234502_REG_THR_EN_JEITA_MASK,
+ ZX234502_REG_THR_EN_JEITA_SHIFT,
+ 0x0);
+
+ /*set the temprator cool */
+ /*00:0 01:5 10:10 11:15*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_TS,
+ ZX234502_REG_TS_COOL_MASK,
+ ZX234502_REG_TS_COOL_SHIFT,
+ 0x0);
+
+ if (ret < 0){
+ goto out;
+ }
+
+ return 0;
+
+ out:
+ //pm_runtime_put_sync(bdi->dev);
+ dev_err(bdi->dev, "zx234502_charger_groupB_config ERROR: %d\n", ret);
+ return ret;
+
+}
+
+static int zx234502_hw_init(struct zx234502_dev_info *bdi)
+{
+ u8 v;
+ int ret;
+
+ union power_supply_propval voltage_val = {0};
+
+#ifdef DBG_CHARGE
+ //set pshold1 1,just for test
+ //gpio_request(ZX29_GPIO_51, "pshold1");
+ //zx29_gpio_config(ZX29_GPIO_51, GPIO51_GPIO51);
+ //zx29_gpio_set_direction(ZX29_GPIO_51, GPIO_OUT);
+ //zx29_gpio_output_data(ZX29_GPIO_51, 1);
+#endif
+ //pm_runtime_get_sync(bdi->dev);
+
+ /* First check that the device really is what its supposed to be */
+ ret = zx234502_read_mask(bdi, ZX234502_REG_VER,
+ ZX234502_REG_VER_INFO_MASK,
+ ZX234502_REG_VER_INFO_SHIFT,
+ &v);
+
+ if (ret < 0){
+ goto out;
+ }
+ //printk(KERN_INFO "zx234502_hw_init:zx234502-charger version reg: 0x%x\n", v);
+ /*
+ if (v != bdi->model) {
+ ret = -ENODEV;
+ goto out;
+ }
+ */
+ voltage_val.intval = 4350;
+ ret = zx234502_charger_set_voltage(bdi,&voltage_val);
+ if (ret < 0){
+ goto out;
+ }
+
+ /*disable the timer*/
+ ret = zx234502_write_mask(bdi,ZX234502_REG_CTC,
+ ZX234502_REG_CTC_EN_TIMER_MASK,
+ ZX234502_REG_CTC_EN_TIMER_SHIFT,
+ 0x0);
+ if (ret < 0){
+ goto out;
+ }
+ /*disable the 2*timer*/
+ ret = zx234502_write_mask(bdi,ZX234502_REG_CTC,
+ ZX234502_REG_CTC_EN_2XTIMER_MASK,
+ ZX234502_REG_CTC_EN_2XTIMER_SHIFT,
+ 0x0);
+
+ if (ret < 0){
+ goto out;
+ }
+
+ //enable PMUON
+ //ret = zx234502_write_mask(bdi,ZX234502_REG_MS,
+ // ZX234502_REG_MS_PMUON_MASK,
+ // ZX234502_REG_MS_PMUON_SHIFT,
+ // 0x1);
+ //config NTCDET
+ // 0:enable auto ntc detection
+ // 1:disable auto ntc detection
+ ret += zx234502_write_mask(bdi,ZX234502_REG_PTS,
+ ZX234502_REG_PTS_NTCDET_MASK,
+ ZX234502_REG_PTS_NTCDET_SHIFT,
+ 0x1);
+ //when NTCDET is 1 ,TSSEL is to select R
+ // 0:10k
+ // 1:100k
+ //ret += zx234502_write_mask(bdi,ZX234502_REG_PTS,
+ // ZX234502_REG_PTS_TSSEL_MASK,
+ // ZX234502_REG_PTS_TSSEL_SHIFT,
+ // 0x0);
+
+ /*disable the charger detect*/
+ ret += zx234502_write_mask(bdi,ZX234502_REG_THR,
+ ZX234502_REG_THR_EN_2DET_MASK,
+ ZX234502_REG_THR_EN_2DET_SHIFT,
+ 0x0);
+ ret += zx234502_write_mask(bdi,ZX234502_REG_THR,
+ ZX234502_REG_THR_EN_1DET_MASK,
+ ZX234502_REG_THR_EN_1DET_SHIFT,
+ 0x0);
+ //enable charger
+ ret += zx234502_write_mask(bdi,ZX234502_REG_MS,
+ ZX234502_REG_MS_ENCHG_MASK,
+ ZX234502_REG_MS_ENCHG_SHIFT,
+ 0x0);
+ ret += zx234502_write_mask(bdi,ZX234502_REG_MS,
+ ZX234502_REG_MS_INSUS_MASK,
+ ZX234502_REG_MS_INSUS_SHIFT,
+ 0x0);
+ //mask /SAFE it
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CBIM,ZX234502_REG_CBIM_MASK_SAFE_TIMER_MASK,
+ ZX234502_REG_CBIM_MASK_SAFE_TIMER_SHIFT,0x1);
+ //mask CHGRUN it
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CIIM,ZX234502_REG_CIIM_MASK_CHGRUN_MASK,
+ ZX234502_REG_CIIM_MASK_CHGRUN_SHIFT,0x1);
+ //mask INLIMIT it
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CIIM,ZX234502_REG_CIIM_MASK_INLIMIT_MASK,
+ ZX234502_REG_CIIM_MASK_INLIMIT_SHIFT,0x1);
+ //mask DCDET it
+ ret += zx234502_write_mask(bdi,ZX234502_REG_CIIM,ZX234502_REG_CIIM_MASK_DCDET_MASK,
+ ZX234502_REG_CIIM_MASK_DCDET_SHIFT,0x1);
+ if (ret < 0){
+ goto out;
+ }
+
+ //set ts_meter interrupt mask
+ if(true !=bdi->pdata->ts_flag){
+ zx234502_write_mask(bdi,ZX234502_REG_CIIM,ZX234502_REG_CIIM_MASK_TS_MASK,
+ ZX234502_REG_CIIM_MASK_TS_SHIFT,0x1);
+ }
+
+ return 0;
+
+out:
+ //pm_runtime_put_sync(bdi->dev);
+ dev_err(bdi->dev, "zx234502_hw_init err: %d\n", ret);
+ return ret;
+}
+
+
+static irqreturn_t zx234502_charger_irq_primary_handler(int irq, struct zx234502_dev_info *bdi)
+{
+ disable_irq_nosync(irq);
+ //pcu_int_clear(irq);
+ pcu_clr_irq_pending(irq);
+
+ up(&bdi->chgirq_sem);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t zx234502_irq_handler_thread(void *data)
+{
+ struct zx234502_dev_info *bdi = data;
+ bool charger_changed_flag = false;
+ bool battery_changed_flag = false;
+ bool boost_changed_flag = false;
+ int ret;
+ u8 ms;
+ struct sched_param param = { .sched_priority = 2 };
+ param.sched_priority= 31;
+ sched_setscheduler(current, SCHED_FIFO, ¶m);
+
+ while(1)
+ {
+ down(&bdi->chgirq_sem);
+ //pm_runtime_get_sync(bdi->dev);
+ mutex_lock(&bdi->bs_reg_lock);
+ bdi->cbis_pre_reg=bdi->cbis_curr_reg;
+ bdi->pis_pre_reg=bdi->pis_curr_reg;
+ bdi->ciis_pre_reg=bdi->ciis_curr_reg;
+ bdi->cfis_pre_reg = bdi->cfis_curr_reg;
+
+ //printk(KERN_INFO"zx234502_irq_handler_thread\n");
+
+
+ ret = zx234502_read(bdi, ZX234502_REG_MS, &ms);
+ if (ret < 0) {
+ dev_err(bdi->dev, "Can't read MS reg: %d\n", ret);
+ mutex_unlock(&bdi->bs_reg_lock);
+ goto out;
+ }
+ //printk("zx234502 MS reg is %d",ms);
+
+ ret = zx234502_read(bdi, ZX234502_REG_CBIS, &bdi->cbis_curr_reg);
+ if (ret < 0) {
+ dev_err(bdi->dev, "Can't read CBIS reg: %d\n", ret);
+ mutex_unlock(&bdi->bs_reg_lock);
+ goto out;
+ }
+
+
+ ret = zx234502_read(bdi, ZX234502_REG_PIS, &bdi->pis_curr_reg);
+ if (ret < 0) {
+ dev_err(bdi->dev, "Can't read PIS reg: %d\n", ret);
+ mutex_unlock(&bdi->bs_reg_lock);
+ goto out;
+ }
+
+ ret = zx234502_read(bdi, ZX234502_REG_CIIS, &bdi->ciis_curr_reg);
+ if (ret < 0) {
+ dev_err(bdi->dev, "Can't read CIIS reg: %d\n", ret);
+ mutex_unlock(&bdi->bs_reg_lock);
+ goto out;
+ }
+ printk("cbis_reg: 0x%02x, pis_reg: 0x%02x, ciis_reg: 0x%02x\n",
+ bdi->cbis_curr_reg, bdi->pis_curr_reg, bdi->ciis_curr_reg);
+ /*clear the A10 int*/
+ ret = zx234502_write_mask(bdi, ZX234502_REG_CIIS,ZX234502_REG_CIIS_INT_MASK,ZX234502_REG_CIIS_INT_SHIFT,0);
+
+ if (ret < 0) {
+ printk(KERN_INFO"chg clear int failed 1\n");
+ ret = zx234502_write_mask(bdi, ZX234502_REG_CIIS,ZX234502_REG_CIIS_INT_MASK,ZX234502_REG_CIIS_INT_SHIFT,0);
+ if (ret < 0) {
+ printk(KERN_INFO"chg clear int failed 2\n");
+ ret = zx234502_write_mask(bdi, ZX234502_REG_CIIS,ZX234502_REG_CIIS_INT_MASK,ZX234502_REG_CIIS_INT_SHIFT,0);
+ if (ret < 0) {
+ printk(KERN_INFO"chg clear int failed 3\n");
+ }
+ else{
+ printk(KERN_INFO"chg clear int failed ok 3\n");
+ //panic(0);
+ }
+ }
+ else{
+ printk(KERN_INFO"chg clear int failed ok 2\n");
+ }
+ }
+
+ if(bdi->cbis_curr_reg != bdi->cbis_pre_reg){
+ if ((bdi->cbis_curr_reg & ZX234502_REG_CBIS_DCIN_PG_MASK) != (bdi->cbis_pre_reg & ZX234502_REG_CBIS_DCIN_PG_MASK)) {
+ if(bdi->cbis_curr_reg & ZX234502_REG_CBIS_DCIN_PG_MASK){
+ //zx234502_hw_init(bdi);
+ printk(KERN_INFO"chg usb in\n");
+ dwc_otg_chg_inform(0);/*usb in*/
+
+ ret = zx234502_charger_config_groupB_Regs(bdi);
+ if(ret)
+ {
+ printk(KERN_INFO"chg config groupB Regs failed\n");
+ }
+ // ret = zx234502_write_mask(bdi,ZX234502_REG_MS,ZX234502_REG_MS_PMUON_MASK,ZX234502_REG_MS_PMUON_SHIFT,0x1);
+ }
+ else{
+ printk(KERN_INFO"chg usb out\n");
+ dwc_otg_chg_inform(1);/*usb out*/
+ bdi->charger.type = POWER_SUPPLY_PCAC_UNKNOWN;
+ // ret = zx234502_write_mask(bdi,ZX234502_REG_MS,ZX234502_REG_MS_PMUON_MASK,ZX234502_REG_MS_PMUON_SHIFT,0x0);
+ }
+ }
+ charger_changed_flag = true;
+ }
+
+ if(true == bdi->pdata->boost_flag){
+ if (bdi->pis_curr_reg != bdi->pis_pre_reg) {
+ if(bdi->pis_curr_reg & ZX234502_REG_PIS_POWERON_IT_MASK){
+ queue_delayed_work(g_bdi->boostQueue,&bdi->boostWorkStruct,2000);
+ }
+ boost_changed_flag = true;
+ bdi->boost_online_flag = 1;
+ }
+ }
+
+ if (bdi->ciis_curr_reg != bdi->ciis_pre_reg) {
+ if(true == bdi->pdata->ts_flag){
+ if((bdi->ciis_curr_reg & ZX234502_REG_CIIS_TS_METER_MASK) != (bdi->ciis_pre_reg & ZX234502_REG_CIIS_TS_METER_MASK)){
+#ifdef DBG_CHARGE
+ switch((bdi->ciis_curr_reg&ZX234502_REG_CIIS_TS_METER_MASK )>>ZX234502_REG_CIIS_TS_METER_SHIFT){
+ case 0:
+#ifdef DBG_CHARGE
+ printk(KERN_INFO"chg bat temp nomrmal\n");
+#endif
+ break;
+ case ZX234502_REG_CISS_TS_WARM:/*warm*/
+ /*in warm state,stop boost*/
+#ifdef DBG_CHARGE
+ printk(KERN_INFO"chg bat temp warm \n");
+#endif
+ break;
+ case ZX234502_REG_CISS_TS_COOL:/*cool*/
+ /*in cool state,stop boost*/
+#ifdef DBG_CHARGE
+ printk(KERN_INFO"chg bat temp cool\n");
+#endif
+ //chg_disable.intval = 1;
+ //pwrbnk_enable.intval = 0;
+ //zx234502_charger_set_charger_config(bdi,&chg_disable);
+ //zx234502_boost_set_charge_enable(bdi, &pwrbnk_enable);
+ break;
+ case 3:/*hot*/
+ /*in hot state,charger chip auto off*/
+ printk(KERN_INFO"chg bat temp hot \n");
+ break;
+ case 6:/*cold*/
+ /*in cold state,charger chip auto off*/
+ printk(KERN_INFO"chg bat temp cold\n");
+ break;
+ default:
+ printk(KERN_INFO"chg bat temp unkonw\n");
+ break;
+ }
+#endif
+ }
+ }
+ battery_changed_flag = true;
+ }
+ bdi->charger_health_valid = true;/****?***/
+ bdi->battery_health_valid = true;/****?***/
+ bdi->battery_status_valid = true;/****?***/
+
+ mutex_unlock(&bdi->bs_reg_lock);
+
+ /*
+ * Sometimes zx234502 gives a steady trickle of interrupts even
+ * though the watchdog timer is turned off and neither the STATUS
+ * nor FAULT registers have changed. Weed out these sprurious
+ * interrupts so userspace isn't alerted for no reason.
+ * In addition, the chip always generates an interrupt after
+ * register reset so we should ignore that one (the very first
+ * interrupt received).
+ */
+ //if (charger_changed_flag && !bdi->first_time)
+ if (charger_changed_flag )
+ power_supply_changed(&bdi->charger);
+ //if (battery_changed_flag && !bdi->first_time)
+ if (battery_changed_flag)
+ power_supply_changed(&bdi->battery);
+ if (true == bdi->pdata->boost_flag){
+ //if (boost_changed_flag && !bdi->first_time)
+ if (boost_changed_flag )
+ power_supply_changed(&bdi->boost);
+ }
+
+ bdi->first_time = false;
+
+ out:
+ //pm_runtime_put_sync(bdi->dev);
+
+ dev_dbg(bdi->dev, "read reg:cbis_reg: 0x%02x, pis_reg: 0x%02x, ciis_reg: 0x%02x\n",
+ bdi->cbis_curr_reg, bdi->pis_curr_reg, bdi->ciis_curr_reg);
+
+ enable_irq(bdi->irq);
+ }
+ return 0;
+}
+
+
+static int zx234502_setup_pdata(struct zx234502_dev_info *bdi,
+ struct zx234502_platform_data *pdata)
+{
+ int ret;
+
+#if 0
+ if (!gpio_is_valid(pdata->gpio_int))
+ return -1;
+
+ ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
+ if (ret < 0)
+ return -1;
+
+ ret = gpio_direction_input(pdata->gpio_int);
+ if (ret < 0)
+ goto out;
+
+ bdi->irq = gpio_to_irq(pdata->gpio_int);
+ if (!bdi->irq)
+ goto out;
+#endif
+
+ bdi->irq = gpio_to_irq(pdata->gpio_int);
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO"zx234502_setup_pdata irq= %d\n",bdi->irq);
+ #endif
+ /*Ñ¡Ôñ´Ë¸´Óù¦ÄÜΪÖжϹ¦ÄÜ*/
+ ret = zx29_gpio_config(pdata->gpio_int,pdata->gpio_int_fun_sel);/********GPIO11:0 /EXT_INT:5*******/
+ if (ret < 0){
+ printk(KERN_INFO"zx234502 zx29_gpio_config error int= %d,fun= %d\n",pdata->gpio_int,pdata->gpio_int_fun_sel);
+ return -1;
+ }
+
+ zx29_gpio_set_inttype(pdata->gpio_int,IRQ_TYPE_EDGE_FALLING/*IRQ_TYPE_EDGE_RISING*/); //INT_POSEDGE
+ zx29_gpio_pd_pu_set(pdata->gpio_int, IO_CFG_PULL_DISABLE);
+
+ bdi->gpio_int = pdata->gpio_int;
+ //pcu_int_clear(bdi->irq);
+ pcu_clr_irq_pending(bdi->irq);
+ return 0;
+#if 0
+out:
+ gpio_free(pdata->gpio_int);
+ return -1;
+#endif
+
+}
+
+
+static int zx234502_init_state(struct zx234502_dev_info *bdi)
+{
+ u8 cfis_reg,pis_reg,cbis_reg,ciis_reg;
+ int ret;
+
+ printk(KERN_INFO "zx234502_init_state start.\n");
+
+ ret = zx234502_read(bdi, ZX234502_REG_CBIS, &cbis_reg);
+ if (ret < 0){
+ printk(KERN_INFO "charger:init state:Can't read CBIS reg: 0x%x\n", cbis_reg);
+ return ret;
+ }
+
+ ret = zx234502_read(bdi, ZX234502_REG_PIS, &pis_reg);
+ if (ret < 0) {
+ printk(KERN_INFO "charger:init Power On /PMID state:Can't read PIS reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = zx234502_read(bdi, ZX234502_REG_CFIS, &cfis_reg);
+ if (ret < 0) {
+ printk(KERN_INFO "charger:init Power On /PMID state:Can't read CFIS reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = zx234502_read(bdi, ZX234502_REG_CIIS, &ciis_reg);
+ if (ret < 0) {
+ printk(KERN_INFO "charger:init Power On /PMID state:Can't read CISS reg: %d\n", ret);
+ return ret;
+ }
+
+ mutex_lock(&bdi->bs_reg_lock);
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO "zx234502_init_state get lock ok.\n");
+ #endif
+ bdi->cbis_curr_reg= cbis_reg;
+ bdi->pis_curr_reg= pis_reg;
+ bdi->cfis_curr_reg= cfis_reg;
+ bdi->ciis_curr_reg = ciis_reg;
+ bdi->charger.type = POWER_SUPPLY_TYPE_UNKNOWN;
+
+ if(bdi->cbis_curr_reg & ZX234502_REG_CBIS_DCIN_PG_MASK){
+ printk(KERN_INFO"send ap usb in message\n");
+ dwc_otg_chg_inform(0);/*usb in*/
+ }
+ else{
+ printk(KERN_INFO"send ap usb out message\n");
+ dwc_otg_chg_inform(1);/*usb out*/
+ }
+ #ifdef DBG_CHARGE
+ if(bdi->cbis_curr_reg & BIT(5))
+ printk(KERN_INFO "no batterty.\n");
+ else
+ printk(KERN_INFO " baterry installed.\n");
+ #endif
+ mutex_unlock(&bdi->bs_reg_lock);
+#ifdef DBG_CHARGE
+ printk(KERN_INFO "zx234502_init_state:cfis_reg10=0x%x,pis_reg0E=0x%x,cbis_reg0C=0x%x,ciis_reg0A=0x%x.\n",cfis_reg,pis_reg,cbis_reg,ciis_reg);
+#endif
+
+ return 0;
+}
+
+
+static void zx234502_boost_workstruct_callback(struct work_struct *work )
+{
+ uint vol_curr = 0;
+ #ifdef DBG_CHARGE
+ u8 mainset;
+ #endif
+ struct zx234502_dev_info *bdi =
+ container_of(work, struct zx234502_dev_info, boostWorkStruct);
+ vol_curr = get_adc2_voltage();/*get boost current*/
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO"boost current is %d in\n",vol_curr);
+ zx234502_read(bdi, 0, &mainset);
+ printk(KERN_INFO"powerbank is %d in\n",mainset);
+ printk(KERN_INFO"workqueue test\n");
+ #endif
+ if (vol_curr < ZX234502_BOOST_V_LIMIT)/*50mV*/{
+ bdi->boostcount++;
+ }
+ if(bdi->boostcount > 3){
+ bdi->boostcount = 0;
+ bdi->boost_online_flag = 0;
+ power_supply_changed(&bdi->boost);
+ cancel_delayed_work_sync(&bdi->boostWorkStruct);
+ }
+ else{
+ bdi->boost_online_flag = 1;
+ queue_delayed_work(bdi->boostQueue,&bdi->boostWorkStruct,2000);
+ }
+
+}
+static void zx234502_charge_typedet(T_TYPE_USB_DETECT chg_type)
+{
+ int ret;
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO"charge type is %d in\n",chg_type);
+ #endif
+ if(TYPE_ADAPTER == chg_type){
+
+ printk(KERN_INFO"chg type is TYPE_ADAPTER\n");
+ /*set the DCIN Current = 1A*/
+ ret = zx234502_write_mask(g_bdi,ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK,
+ ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ 0x3);
+ if (ret < 0){
+ printk(KERN_INFO"write REG_01 fault\n");
+ }
+ g_bdi->charger.type = POWER_SUPPLY_PCAC__AC;
+ }
+
+ else{
+ printk(KERN_INFO"chgage type is TYPE_PC\n");
+
+ /*set the DCIN Current = 450mA*/
+ ret = zx234502_write_mask(g_bdi,ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK,
+ ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ 0x1);
+ if (ret < 0){
+ printk(KERN_INFO"write REG_01 fault\n");
+ }
+
+ g_bdi->charger.type = POWER_SUPPLY_PCAC__PC;
+ }
+
+
+ #ifdef CONFIG_CHARGER_ZX234502_EVB
+ /*set the DCIN Current = 2A*/
+ ret = zx234502_write_mask(g_bdi,ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK,
+ ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ 0x5);
+ if (ret < 0){
+ printk(KERN_INFO"write REG_01 fault\n");
+ }
+ #endif
+
+}
+
+
+#if defined(CONFIG_DEBUG_FS)
+static ssize_t debugfs_regs_write(struct file *file, const char __user *buf,size_t nbytes, loff_t *ppos)
+{
+ unsigned int val1, val2;
+ u8 reg, value;
+ int ret;
+ char *kern_buf;
+ struct seq_file *s = file->private_data;
+ struct zx234502_dev_info *zx234502 = s->private;
+
+ kern_buf = kzalloc(nbytes, GFP_KERNEL);
+
+ if (!kern_buf) {
+ printk(KERN_INFO "zx234502_charger: Failed to allocate buffer\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
+ kfree(kern_buf);
+ return -ENOMEM;
+ }
+ printk(KERN_INFO "%s input str=%s,nbytes=%d \n", __func__, kern_buf,nbytes);
+
+ ret = sscanf(kern_buf, "%x:%x", &val1, &val2);
+ if (ret < 2 || val1 > ZX234502_REG_MAX ) {
+ printk(KERN_INFO "zx234502_charger: failed to read user buf, ret=%d, input 0x%x:0x%x\n",
+ ret, val1, val2);
+ kfree(kern_buf);
+ return -EINVAL;
+ }
+ kfree(kern_buf);
+
+ reg = val1 & 0xff;
+ value = val2 & 0xff;
+ printk(KERN_INFO "%s input %x,%x; reg=%x,value=%x\n", __func__, val1, val2, reg, value);
+ ret = zx234502_write(zx234502,reg, value);
+
+ return ret ? ret : nbytes;
+}
+
+static int debugfs_regs_show(struct seq_file *s, void *v)
+{
+ int i;
+ u8 value[ZX234502_REG_MAX];
+ int ret=0;
+ int curr = 0;
+ struct zx234502_dev_info *zx234502 = s->private;
+
+ for (i = 0; i < ZX234502_REG_MAX; i++){
+ ret = zx234502_read(zx234502, i, &(value[i]));
+
+ if(ret){
+ printk(KERN_INFO "%s err=%d, break\n", __func__, ret);
+ seq_printf(s, "%s err=%d, break", __func__, ret);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ZX234502_REG_MAX; i++) {
+ if((i+1)%9 == 0)
+ seq_printf(s, "\n");
+
+ seq_printf(s, "[0x%x]%02x ", i, value[i]);
+ }
+ /*charger type*/
+ if(zx234502->charger.type ==POWER_SUPPLY_PCAC__PC){
+ seq_printf(s, "charger type is PC\n");
+ }
+ else if(zx234502->charger.type ==POWER_SUPPLY_PCAC__AC){
+ seq_printf(s, "charger type is AC\n");
+ }
+ else
+ seq_printf(s, "charger type is unknow = %d\n",zx234502->charger.type);
+
+ /*stopchg_flag*/
+ if(1==stopchg_flag){
+ seq_printf(s, "mmi set charger enable,the charger state = %d\n",!(value[ZX234502_REG_MS]&ZX234502_REG_MS_INSUS_MASK));
+ }
+ else if(2==stopchg_flag){
+ seq_printf(s, "mmi set charger disable,the charger state = %d\n",!(value[ZX234502_REG_MS]&ZX234502_REG_MS_INSUS_MASK));
+ }
+ else
+ seq_printf(s, "mmi never set the charger ,the charger state = %d\n",!(value[ZX234502_REG_MS]&ZX234502_REG_MS_INSUS_MASK));
+
+ /*charge current*/
+ ret = zx234502_get_field_val(zx234502, ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK, ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ zx234502_in_ilimit_values,
+ ARRAY_SIZE(zx234502_in_ilimit_values), &curr);
+
+ if (ret < 0)
+ return ret;
+ seq_printf(s, "the charger current now = %dmA\n",curr);
+
+
+ return ret;
+}
+
+#define DEBUGFS_FILE_ENTRY(name) \
+static int debugfs_##name##_open(struct inode *inode, struct file *file) \
+{\
+return single_open(file, debugfs_##name##_show, inode->i_private); \
+}\
+\
+static const struct file_operations debugfs_##name##_fops = { \
+.owner= THIS_MODULE, \
+.open= debugfs_##name##_open, \
+.write=debugfs_##name##_write, \
+.read= seq_read, \
+.llseek= seq_lseek, \
+.release= single_release, \
+}
+
+DEBUGFS_FILE_ENTRY(regs);
+
+static struct dentry *g_charger_root;
+
+static void debugfs_charger_init(struct zx234502_dev_info *zx234502)
+{
+ struct dentry *root;
+ struct dentry *node;
+ int i;
+
+ if(!zx234502)
+ return;
+
+ //create root
+ root = debugfs_create_dir("charger_zx29", NULL);
+ if (!root) {
+ dev_err(&zx234502->dev, "debugfs_create_dir err=%d\n", IS_ERR(root));
+ goto err;
+ }
+
+ //print regs;
+ node = debugfs_create_file("regs", S_IRUGO | S_IWUGO, root, zx234502, &debugfs_regs_fops);
+ if (!node){
+ dev_err(&zx234502->dev, "debugfs_create_dir err=%d\n", IS_ERR(node));
+ goto err;
+ }
+
+ g_charger_root = (void *)root;
+ return;
+err:
+ dev_err(&zx234502->dev, "debugfs_charger_init err\n");
+}
+
+#endif
+
+
+static int zx234502_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct device *dev = &client->dev;
+ struct zx234502_platform_data *pdata = client->dev.platform_data;
+ struct zx234502_dev_info *bdi;
+ int ret;
+ int i; /*when err try 3 times*/
+ //use for other
+ //g_platform_data= client->dev.platform_data;
+
+ printk(KERN_INFO "charger probe.\n");
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
+ return -ENODEV;
+ }
+
+ bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
+ if (!bdi) {
+ dev_err(dev, "Can't alloc bdi struct\n");
+ return -ENOMEM;
+ }
+ bdi->pdata = pdata;
+ bdi->client = client;
+ bdi->dev = dev;
+ bdi->model = id->driver_data;
+ strncpy(bdi->model_name, id->name, sizeof(bdi->model_name)-1);
+ mutex_init(&bdi->bs_reg_lock);
+ bdi->first_time = true;
+ bdi->charger_health_valid = false;
+ bdi->battery_health_valid = false;
+ bdi->battery_status_valid = false;
+
+ g_bdi = bdi;
+
+ i2c_set_clientdata(client, bdi);
+
+ if (dev->of_node)
+ ret = 0;//zx234502_setup_dt(bdi);
+ else
+ ret = zx234502_setup_pdata(bdi, pdata);
+
+ if (ret) {
+ dev_err(dev, "Can't get irq info\n");
+ return -EINVAL;
+ }
+#ifdef DBG_CHARGE
+ printk(KERN_INFO "hwinit.\n");
+#endif
+ //pm_runtime_enable(dev);
+ //pm_runtime_resume(dev);
+ i = 0;
+ do{
+ ret = zx234502_hw_init(bdi);
+ if (ret < 0) {
+ printk(KERN_INFO "zx234502_probe Hardware init failed times = %d\n",(i+1));
+ i++;
+ }
+ else
+ break;
+
+ }while(i<3);
+
+#ifdef DBG_CHARGE
+ printk(KERN_INFO "zx234502_probe zx234502_hw_init ok.\n");
+#endif
+#ifdef CONFIG_CHARGER_ZX234502_EVB
+ /*set the DCIN Current = 2A*/
+ ret = zx234502_write_mask(g_bdi,ZX234502_REG_ISC,
+ ZX234502_REG_ISC_ISET_DCIN_MASK,
+ ZX234502_REG_ISC_ISET_DCIN_SHIFT,
+ 0x5);
+ if (ret < 0){
+ printk(KERN_INFO"write REG_01 fault\n");
+ }
+#endif
+ ret = zx234502_charger_config_groupB_Regs(bdi);
+ if (ret < 0) {
+ printk(KERN_INFO "groupB config faild.\n");
+ }
+
+ zx234502_charger_init(&bdi->charger);
+
+ ret = power_supply_register(dev, &bdi->charger);
+ if (ret) {
+ dev_err(dev, "Can't register charger\n");
+ goto out2;
+ }
+ printk(KERN_INFO "zx234502_probe power_supply_register charger ok.\n");
+
+ zx234502_battery_init(&bdi->battery);
+
+ ret = power_supply_register(dev, &bdi->battery);
+ if (ret) {
+ dev_err(dev, "Can't register battery\n");
+ goto out3;
+ }
+ printk(KERN_INFO "zx234502_probe power_supply_register battery ok.\n");
+
+ if(true == pdata->boost_flag){
+ zx234502_boost_init(&bdi->boost);
+ ret = power_supply_register(dev, &bdi->boost);
+ if (ret) {
+ dev_err(dev, "Can't register boost\n");
+ goto out4;
+ }
+
+ ret = zx234502_boost_gpio_init(dev,pdata);
+ if (ret) {
+ dev_err(dev, "Can't register boost\n");
+ goto out4;
+ }
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO "zx234502_boost_gpio_init.\n");
+ #endif
+
+ bdi->boostQueue = create_workqueue("zx234502boost");
+ if (!bdi->boostQueue){
+ if(bdi->pdata->boost_cur_gpio1)
+ gpio_free(bdi->pdata->boost_cur_gpio1);
+ if(bdi->pdata->boost_cur_gpio2)
+ gpio_free(bdi->pdata->boost_cur_gpio2);
+ if(bdi->pdata->boost_cur_gpio3)
+ gpio_free(bdi->pdata->boost_cur_gpio3);
+ if(bdi->pdata->boost_loadswitch_gpio)
+ gpio_free(bdi->pdata->boost_loadswitch_gpio);
+
+ ret = -1;
+ goto out4;
+ }
+
+ INIT_DELAYED_WORK(&bdi->boostWorkStruct,zx234502_boost_workstruct_callback);
+
+ //queue_delayed_work(bdi->boostQueue,&bdi->boostWorkStruct,20000);
+ #ifdef DBG_CHARGE
+ printk(KERN_INFO "setup_workqueue.\n");
+ #endif
+ }
+#if 0
+//#ifdef CONFIG_SYSFS
+ ret = zx234502_sysfs_create_group(bdi);
+ if (ret) {
+ dev_err(dev, "Can't create sysfs entries\n");
+ goto out5;
+ }
+#endif
+ dwc_chg_Regcallback(zx234502_charge_typedet);/*register for usb*/
+
+ sema_init(&bdi->chgirq_sem, 0);
+
+ ret = zx234502_init_state(bdi);
+ if(ret)
+ {
+ dev_err(dev, "zx234502 init state error.\n");
+ goto out1;
+ }
+
+ bdi->chg_irq_thread = kthread_run(zx234502_irq_handler_thread, bdi, "zx234502-chgirq");
+ BUG_ON(IS_ERR(bdi->chg_irq_thread));
+
+ ret = request_irq(bdi->irq, zx234502_charger_irq_primary_handler,IRQF_NO_THREAD, "zx234502-charger", bdi);
+ if (ret < 0) {
+ dev_err(dev, "Can't set up irq handler\n");
+ goto out1;
+ }
+ irq_set_irq_wake(bdi->irq, 1);
+
+ /*clear all int*/
+ ret = zx234502_write_mask(bdi,ZX234502_REG_CIIS,ZX234502_REG_CIIS_INT_MASK,ZX234502_REG_CIIS_INT_SHIFT,0x0);
+ if (ret == 0) {
+ printk(KERN_INFO "clear int ok \n");
+ }
+
+
+#if defined(CONFIG_DEBUG_FS)
+ debugfs_charger_init(bdi);
+#endif
+
+#ifdef DBG_CHARGE
+ printk(KERN_INFO "zx234502_probe end.\n");
+#endif
+
+ return 0;
+#if 0
+out5:
+ zx234502_sysfs_remove_group(bdi);
+#endif
+out4:
+ power_supply_unregister(&bdi->boost);
+out3:
+ power_supply_unregister(&bdi->battery);
+out2:
+ //pm_runtime_disable(dev);
+ power_supply_unregister(&bdi->charger);
+out1:
+ if (bdi->gpio_int)
+ gpio_free(bdi->gpio_int);
+ dwc_chg_Regcallback(NULL);/*unregister for usb*/
+
+ return ret;
+}
+
+static int zx234502_remove(struct i2c_client *client)
+{
+ struct zx234502_dev_info *bdi = i2c_get_clientdata(client);
+ struct zx234502_platform_data *pdata = client->dev.platform_data;
+
+ if(!bdi)
+ return -EINVAL;
+
+ //pm_runtime_get_sync(bdi->dev);
+ zx234502_register_reset(bdi);
+ //pm_runtime_put_sync(bdi->dev);
+
+ zx234502_sysfs_remove_group(bdi);
+ power_supply_unregister(&bdi->battery);
+ power_supply_unregister(&bdi->charger);
+ if(true == pdata->boost_flag)
+ power_supply_unregister(&bdi->boost);
+ pm_runtime_disable(bdi->dev);
+
+ if (bdi->gpio_int)
+ gpio_free(bdi->gpio_int);
+ zx234502_boost_gpio_uninit(pdata);
+
+ if(bdi->boostQueue)
+ destroy_workqueue(bdi->boostQueue);
+
+#if defined(CONFIG_DEBUG_FS)
+ if(g_charger_root){
+ printk(KERN_INFO "zx234502_device_exit:debugfs_remove_recursive \n");
+ debugfs_remove_recursive(g_charger_root);
+ }
+#endif
+
+ return 0;
+}
+
+static int zx234502_suspend(struct i2c_client *not_use, pm_message_t mesg)
+{
+
+ disable_irq_nosync(g_bdi->irq);
+ return 0;
+
+}
+
+static int zx234502_resume(struct i2c_client *not_use)
+{
+
+ enable_irq(g_bdi->irq);
+ return 0;
+
+}
+/*
+ * Only support the zx234502 right now. The bq24192, bq24192i, and bq24193
+ * are similar but not identical so the driver needs to be extended to
+ * support them.
+ */
+static const struct i2c_device_id zx234502_i2c_ids[] = {
+ { "zx234502-charger", ZX234502_REG_VERS },
+ { },
+};
+
+static struct i2c_driver zx234502_driver = {
+ .probe = zx234502_probe,
+ .remove = zx234502_remove,
+ .id_table = zx234502_i2c_ids,
+ .driver = {
+ .name = "zx234502-charger",
+ .owner = THIS_MODULE,
+ },
+ .suspend = zx234502_suspend,
+ .resume = zx234502_resume,
+};
+static int __init zx234502_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&zx234502_driver);
+ if (ret != 0)
+ pr_err("Failed to register visionox_i2c_driver : %d\n", ret);
+
+ return ret;
+}
+/* init early so consumer devices can complete system boot */
+module_init(zx234502_i2c_init);
+
+static void __exit zx234502_i2c_exit(void)
+{
+ i2c_del_driver(&zx234502_driver);
+}
+module_exit(zx234502_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
+MODULE_ALIAS("i2c:zx234502-charger");
+MODULE_DESCRIPTION("TI ZX234502 Charger Driver");