From: hehopmajieh <
gami...@gmail.com>
HdG: Note as usual with code imported from the sunxi SDK there are severe
style issues :|
drivers/power/axp_power/axp15-board.c | 787 +++++++++++
drivers/power/axp_power/axp15-gpio.c | 348 +++++
drivers/power/axp_power/axp15-mfd.h | 363 +++++
drivers/power/axp_power/axp15-regu.c | 704 ++++++++++
drivers/power/axp_power/axp15-sply.c | 2318 +++++++++++++++++++++++++++++++
drivers/power/axp_power/virtual15.c | 427 ++++++
drivers/power/axp_power/virtual15_dev.c | 125 ++
7 files changed, 5072 insertions(+)
create mode 100755 drivers/power/axp_power/axp15-board.c
create mode 100755 drivers/power/axp_power/axp15-gpio.c
create mode 100755 drivers/power/axp_power/axp15-mfd.h
create mode 100755 drivers/power/axp_power/axp15-regu.c
create mode 100755 drivers/power/axp_power/axp15-sply.c
create mode 100755 drivers/power/axp_power/virtual15.c
create mode 100755 drivers/power/axp_power/virtual15_dev.c
diff --git a/drivers/power/axp_power/axp15-board.c b/drivers/power/axp_power/axp15-board.c
new file mode 100755
index 0000000..b97b2aa
--- /dev/null
+++ b/drivers/power/axp_power/axp15-board.c
@@ -0,0 +1,787 @@
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <mach/irqs.h>
+#include <linux/power_supply.h>
+#include <linux/apm_bios.h>
+#include <linux/apm-emulation.h>
+#include <linux/mfd/axp-mfd.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <mach/sys_config.h>
+#include "axp-cfg.h"
+//#include "axp-sply.h"
+
+
+
+//int axp_usbcurflag = 0;
+//int axp_usbvolflag= 0;
+
+int pmu_used;
+int pmu_twi_id;
+int pmu_irq_id;
+int pmu_twi_addr;
+int pmu_battery_rdc;
+int pmu_battery_cap;
+int pmu_init_chgcur;
+int pmu_suspend_chgcur;
+int pmu_resume_chgcur;
+int pmu_shutdown_chgcur;
+int pmu_init_chgvol;
+int pmu_init_chgend_rate;
+int pmu_init_chg_enabled;
+int pmu_init_adc_freq;
+int pmu_init_adc_freqc;
+int pmu_init_chg_pretime;
+int pmu_init_chg_csttime;
+
+int pmu_bat_para1;
+int pmu_bat_para2;
+int pmu_bat_para3;
+int pmu_bat_para4;
+int pmu_bat_para5;
+int pmu_bat_para6;
+int pmu_bat_para7;
+int pmu_bat_para8;
+int pmu_bat_para9;
+int pmu_bat_para10;
+int pmu_bat_para11;
+int pmu_bat_para12;
+int pmu_bat_para13;
+int pmu_bat_para14;
+int pmu_bat_para15;
+int pmu_bat_para16;
+
+int pmu_usbvol_limit;
+int pmu_usbvol;
+int pmu_usbcur_limit;
+int pmu_usbcur;
+
+int pmu_pwroff_vol;
+int pmu_pwron_vol;
+
+int dcdc2_vol;
+int dcdc3_vol;
+int ldo2_vol;
+int ldo3_vol;
+int ldo4_vol;
+
+int pmu_pekoff_time;
+int pmu_pekoff_en;
+int pmu_peklong_time;
+int pmu_pekon_time;
+int pmu_pwrok_time;
+int pmu_pwrnoe_time;
+int pmu_intotp_en;
+
+/*
+int axp_usbvol(void)
+{
+ axp_usbvolflag = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbvol);
+
+int axp_usbcur(void)
+{
+ axp_usbcurflag = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbcur);
+
+int axp_usbvol_restore(void)
+{
+ axp_usbvolflag = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbvol_restore);
+
+int axp_usbcur_restore(void)
+{
+ axp_usbcurflag = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbcur_restore);
+*/
+
+/* Reverse engineered partly from Platformx drivers */
+enum axp_regls{
+
+ vcc_ldo1,
+ vcc_ldo2,
+ vcc_ldo3,
+ vcc_ldo4,
+ vcc_ldo5,
+ vcc_ldo6,
+ vcc_ldo7,
+
+ vcc_dcdc1,
+ vcc_dcdc2,
+ vcc_dcdc3,
+ vcc_dcdc4,
+};
+
+/* The values of the various regulator constraints are obviously dependent
+ * on exactly what is wired to each ldo. Unfortunately this information is
+ * not generally available. More information has been requested from Xbow
+ * but as of yet they haven't been forthcoming.
+ *
+ * Some of these are clearly Stargate 2 related (no way of plugging
+ * in an lcd on the IM2 for example!).
+ */
+
+static struct regulator_consumer_supply ldo1_data[] = {
+ {
+ .supply = "axp15_rtc",
+ },
+ };
+
+
+
+static struct regulator_consumer_supply ldo2_data[] = {
+ {
+ .supply = "axp15_analog/fm",
+ },
+ };
+
+static struct regulator_consumer_supply ldo3_data[] = {
+ {
+ .supply = "axp15_analog/fm1",
+ },
+ };
+
+static struct regulator_consumer_supply ldo4_data[] = {
+ {
+ .supply = "axp15_analog/fm2",
+ },
+ };
+
+static struct regulator_consumer_supply ldo5_data[] = {
+ {
+ .supply = "axp15_pll/sdram",
+ },
+ };
+
+static struct regulator_consumer_supply ldo6_data[] = {
+ {
+ .supply = "axp15_pll/hdmi",
+ },
+ };
+
+static struct regulator_consumer_supply ldo7_data[] = {
+ {
+ .supply = "axp15_mic",
+ },
+ };
+
+static struct regulator_consumer_supply buck1_data[] = {
+ {
+ .supply = "axp15_io",
+ }
+ };
+
+static struct regulator_consumer_supply buck2_data[] = {
+ {
+ .supply = "axp15_core",
+ },
+ };
+
+static struct regulator_consumer_supply buck3_data[] = {
+ {
+ .supply = "axp15_ddr",
+ },
+ };
+
+static struct regulator_consumer_supply buck4_data[] = {
+ {
+ .supply = "axp15_ddr2",
+ },
+ };
+
+static struct regulator_init_data axp_regl_init_data[] = {
+ [vcc_ldo1] = {
+ .constraints = { /* board default 1.25V */
+ .name = "axp15_ldo1",
+ .min_uV = 2500000,
+ .max_uV = 5000000,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo1_data),
+ .consumer_supplies = ldo1_data,
+ },
+ [vcc_ldo2] = {
+ .constraints = { /* board default 3.0V */
+ .name = "axp15_ldo2",
+ .min_uV = 1300000,
+ .max_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo2_data),
+ .consumer_supplies = ldo2_data,
+
+ },
+ [vcc_ldo3] = {
+ .constraints = {/* default is 1.8V */
+ .name = "axp15_ldo3",
+ .min_uV = 1200000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo3_data),
+ .consumer_supplies = ldo3_data,
+
+ },
+ [vcc_ldo4] = {
+ .constraints = {
+ /* board default is 3.3V */
+ .name = "axp15_ldo4",
+ .min_uV = 1200000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo4_data),
+ .consumer_supplies = ldo4_data,
+ },
+ [vcc_ldo5] = {
+ .constraints = { /* default 3.3V */
+ .name = "axp15_ldo5",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo5_data),
+ .consumer_supplies = ldo5_data,
+ },
+ [vcc_ldo6] = {
+ .constraints = { /* default 3.3V */
+ .name = "axp15_ldo6",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo6_data),
+ .consumer_supplies = ldo6_data,
+ },
+ [vcc_ldo7] = {
+ .constraints = { /* default 3.3V */
+ .name = "axp15_ldoIO0",
+ .min_uV = 1800000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ldo7_data),
+ .consumer_supplies = ldo7_data,
+ },
+ [vcc_dcdc1] = {
+ .constraints = { /* default 3.3V */
+ .name = "axp15_dcdc1",
+ .min_uV = 1700000,
+ .max_uV = 3500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE ,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(buck1_data),
+ .consumer_supplies = buck1_data,
+ },
+ [vcc_dcdc2] = {
+ .constraints = { /* default 1.24V */
+ .name = "axp15_dcdc2",
+ //.min_uV = DCDC2MIN * 1000,
+ //.max_uV = DCDC2MAX * 1000,
+ .min_uV = 700000,
+ .max_uV = 2275000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(buck2_data),
+ .consumer_supplies = buck2_data,
+ },
+ [vcc_dcdc3] = {
+ .constraints = { /* default 2.5V */
+ .name = "axp15_dcdc3",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(buck3_data),
+ .consumer_supplies = buck3_data,
+ },
+ [vcc_dcdc4] = {
+ .constraints = { /* default 2.5V */
+ .name = "axp15_dcdc4",
+ .min_uV = 700000,
+ .max_uV = 3500000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(buck4_data),
+ .consumer_supplies = buck4_data,
+ },
+};
+
+static struct axp_funcdev_info axp_regldevs[] = {
+ {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO0,
+ .platform_data = &axp_regl_init_data[vcc_ldo1],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO1,
+ .platform_data = &axp_regl_init_data[vcc_ldo2],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO2,
+ .platform_data = &axp_regl_init_data[vcc_ldo3],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO3,
+ .platform_data = &axp_regl_init_data[vcc_ldo4],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO4,
+ .platform_data = &axp_regl_init_data[vcc_ldo5],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDO5,
+ .platform_data = &axp_regl_init_data[vcc_ldo6],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_LDOIO0,
+ .platform_data = &axp_regl_init_data[vcc_ldo7],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_DCDC1,
+ .platform_data = &axp_regl_init_data[vcc_dcdc1],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_DCDC2,
+ .platform_data = &axp_regl_init_data[vcc_dcdc2],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_DCDC3,
+ .platform_data = &axp_regl_init_data[vcc_dcdc3],
+ }, {
+ .name = "axp15-regulator",
+ .id = AXP15_ID_DCDC4,
+ .platform_data = &axp_regl_init_data[vcc_dcdc4],
+ },
+};
+static struct power_supply_info battery_data ={
+ .name ="PTI PL336078",
+ .technology = POWER_SUPPLY_TECHNOLOGY_LiFe,
+ //.voltage_max_design = pmu_init_chgvol,
+ //.voltage_min_design = pmu_pwroff_vol,
+ //.energy_full_design = pmu_battery_cap,
+ .use_for_apm = 1,
+};
+
+
+static struct axp_supply_init_data axp_sply_init_data = {
+ .battery_info = &battery_data,
+ //.chgcur = pmu_init_chgcur,
+ //.chgvol = pmu_init_chgvol,
+ //.chgend = pmu_init_chgend_rate,
+ //.chgen = pmu_init_chg_enabled,
+ //.sample_time = pmu_init_adc_freq,
+ //.chgpretime = pmu_init_chg_pretime,
+ //.chgcsttime = pmu_init_chg_csttime,
+};
+
+static struct axp_funcdev_info axp_splydev[]={
+ {
+ .name = "axp15-supplyer",
+ .id = AXP15_ID_SUPPLY,
+ .platform_data = &axp_sply_init_data,
+ },
+};
+
+static struct axp_funcdev_info axp_gpiodev[]={
+ { .name = "axp15-gpio",
+ .id = AXP15_ID_GPIO,
+ },
+};
+
+
+static struct axp_platform_data axp_pdata = {
+ .num_regl_devs = ARRAY_SIZE(axp_regldevs),
+ .num_sply_devs = ARRAY_SIZE(axp_splydev),
+ .num_gpio_devs = ARRAY_SIZE(axp_gpiodev),
+ .regl_devs = axp_regldevs,
+ .sply_devs = axp_splydev,
+ .gpio_devs = axp_gpiodev,
+ .gpio_base = 0,
+};
+
+static struct i2c_board_info __initdata axp_mfd_i2c_board_info[] = {
+ {
+ .type = "axp15_mfd",
+ .addr = AXP15_ADDR,
+ .platform_data = &axp_pdata,
+ .irq = SW_INT_IRQNO_ENMI,
+ },
+};
+
+static int __init axp_board_init(void)
+{
+ int ret;
+ ret = script_parser_fetch("pmu_para", "pmu_used", &pmu_used, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ return ;
+ }
+ if (pmu_used)
+ {
+ ret = script_parser_fetch("pmu_para", "pmu_twi_id", &pmu_twi_id, sizeof(int));
+ printk("line:%d,pmu_twi_id=%d\n",__LINE__,pmu_twi_id);
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_twi_id = AXP15_I2CBUS;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_irq_id", &pmu_irq_id, sizeof(int));
+ printk("line:%d,pmu_irq_id=%d\n",__LINE__,pmu_irq_id);
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_irq_id = AXP15_IRQNO;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_twi_addr", &pmu_twi_addr, sizeof(int));
+ printk("line:%d,pmu_twi_addr=%d\n",__LINE__,pmu_twi_addr);
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_twi_addr = AXP15_ADDR;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_battery_rdc", &pmu_battery_rdc, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ //int BATRDC = 0;
+ pmu_battery_rdc = BATRDC;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_battery_cap", &pmu_battery_cap, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_battery_cap = BATTERYCAP;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_chgcur", &pmu_init_chgcur, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chgcur = INTCHGCUR / 1000;
+ }
+ pmu_init_chgcur = pmu_init_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_suspend_chgcur", &pmu_suspend_chgcur, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_suspend_chgcur = SUSCHGCUR / 1000;
+ }
+ pmu_suspend_chgcur = pmu_suspend_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_resume_chgcur", &pmu_resume_chgcur, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_resume_chgcur = RESCHGCUR / 1000;
+ }
+ pmu_resume_chgcur = pmu_resume_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_shutdown_chgcur", &pmu_shutdown_chgcur, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_shutdown_chgcur = CLSCHGCUR / 1000;
+ }
+ pmu_shutdown_chgcur = pmu_shutdown_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_init_chgvol", &pmu_init_chgvol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chgvol = INTCHGVOL / 1000;
+ }
+ pmu_init_chgvol = pmu_init_chgvol * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_init_chgend_rate", &pmu_init_chgend_rate, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chgend_rate = INTCHGENDRATE;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_chg_enabled", &pmu_init_chg_enabled, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chg_enabled = INTCHGENABLED;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_adc_freq", &pmu_init_adc_freq, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_adc_freq = INTADCFREQ;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_adc_freqc", &pmu_init_adc_freqc, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_adc_freq = INTADCFREQC;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_chg_pretime", &pmu_init_chg_pretime, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chg_pretime = INTCHGPRETIME;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_init_chg_csttime", &pmu_init_chg_csttime, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chg_csttime = INTCHGCSTTIME;
+ }
+
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para1", &pmu_bat_para1, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para1 = OCVREG0;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para2", &pmu_bat_para2, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para2 = OCVREG1;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para3", &pmu_bat_para3, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para3 = OCVREG2;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para4", &pmu_bat_para4, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para4 = OCVREG3;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para5", &pmu_bat_para5, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para5 = OCVREG4;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para6", &pmu_bat_para6, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para6 = OCVREG5;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para7", &pmu_bat_para7, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para7 = OCVREG6;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para8", &pmu_bat_para8, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para8 = OCVREG7;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para9", &pmu_bat_para9, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para9 = OCVREG8;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para10", &pmu_bat_para10, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para10 = OCVREG9;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para11", &pmu_bat_para11, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para11 = OCVREGA;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para12", &pmu_bat_para12, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para12 = OCVREGB;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para13", &pmu_bat_para13, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para13 = OCVREGC;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para14", &pmu_bat_para14, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para14 = OCVREGD;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para15", &pmu_bat_para15, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para15 = OCVREGE;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_bat_para16", &pmu_bat_para16, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_bat_para16 = OCVREGF;
+ }
+
+ ret = script_parser_fetch("pmu_para", "pmu_usbvol_limit", &pmu_usbvol_limit, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_usbvol_limit = 1;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_usbvol", &pmu_usbvol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_usbvol = 4400;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_usbcur_limit", &pmu_usbcur_limit, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_usbcur_limit = 1;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_usbcur", &pmu_usbcur, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_usbcur = 0;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pwroff_vol", &pmu_pwroff_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pwroff_vol = 3300;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pwron_vol", &pmu_pwron_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pwron_vol = 2900;
+ }
+
+ ret = script_parser_fetch("target", "dcdc2_vol", &dcdc2_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ dcdc2_vol = 1400;
+ }
+ ret = script_parser_fetch("target", "dcdc3_vol", &dcdc3_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ dcdc3_vol = 1250;
+ }
+ ret = script_parser_fetch("target", "ldo2_vol", &ldo2_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ ldo2_vol = 3000;
+ }
+ ret = script_parser_fetch("target", "ldo3_vol", &ldo3_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ ldo3_vol = 2800;
+ }
+ ret = script_parser_fetch("target", "ldo4_vol", &ldo4_vol, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ ldo4_vol = 2800;
+ }
+
+ ret = script_parser_fetch("pmu_para", "pmu_pekoff_time", &pmu_pekoff_time, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pekoff_time = 6000;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pekoff_en", &pmu_pekoff_en, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pekoff_en = 1;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_peklong_time", &pmu_peklong_time, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_peklong_time = 1500;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pwrok_time", &pmu_pwrok_time, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pwrok_time = 64;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pwrnoe_time", &pmu_pwrnoe_time, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pwrnoe_time = 2000;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_intotp_en", &pmu_intotp_en, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_intotp_en = 1;
+ }
+ ret = script_parser_fetch("pmu_para", "pmu_pekon_time", &pmu_pekon_time, sizeof(int));
+ if (ret)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_pekon_time = 1000;
+ }
+
+ axp_regl_init_data[1].constraints.state_standby.uV = ldo2_vol * 1000;
+ axp_regl_init_data[2].constraints.state_standby.uV = ldo3_vol * 1000;
+ axp_regl_init_data[3].constraints.state_standby.uV = ldo4_vol * 1000;
+ axp_regl_init_data[5].constraints.state_standby.uV = dcdc2_vol * 1000;
+ axp_regl_init_data[6].constraints.state_standby.uV = dcdc3_vol * 1000;
+ axp_regl_init_data[1].constraints.state_standby.enabled = (ldo2_vol)?1:0;
+ axp_regl_init_data[1].constraints.state_standby.disabled = (ldo2_vol)?0:1;
+ axp_regl_init_data[2].constraints.state_standby.enabled = (ldo3_vol)?1:0;
+ axp_regl_init_data[2].constraints.state_standby.disabled = (ldo3_vol)?0:1;
+ axp_regl_init_data[3].constraints.state_standby.enabled = (ldo4_vol)?1:0;
+ axp_regl_init_data[3].constraints.state_standby.disabled = (ldo4_vol)?0:1;
+ axp_regl_init_data[5].constraints.state_standby.enabled = (dcdc2_vol)?1:0;
+ axp_regl_init_data[5].constraints.state_standby.disabled = (dcdc2_vol)?0:1;
+ axp_regl_init_data[6].constraints.state_standby.enabled = (dcdc3_vol)?1:0;
+ axp_regl_init_data[6].constraints.state_standby.disabled = (dcdc3_vol)?0:1;
+ battery_data.voltage_max_design = pmu_init_chgvol;
+ battery_data.voltage_min_design = pmu_pwroff_vol;
+ battery_data.energy_full_design = pmu_battery_cap;
+ axp_sply_init_data.chgcur = pmu_init_chgcur;
+ axp_sply_init_data.chgvol = pmu_init_chgvol;
+ axp_sply_init_data.chgend = pmu_init_chgend_rate;
+ axp_sply_init_data.chgen = pmu_init_chg_enabled;
+ axp_sply_init_data.sample_time = pmu_init_adc_freq;
+ axp_sply_init_data.chgpretime = pmu_init_chg_pretime;
+ axp_sply_init_data.chgcsttime = pmu_init_chg_csttime;
+ axp_mfd_i2c_board_info[0].addr = pmu_twi_addr;
+ axp_mfd_i2c_board_info[0].irq = pmu_irq_id;
+
+ return i2c_register_board_info(pmu_twi_id, axp_mfd_i2c_board_info,
+ ARRAY_SIZE(axp_mfd_i2c_board_info));
+ }
+ else
+ return -1;
+
+}
+fs_initcall(axp_board_init);
+
+MODULE_DESCRIPTION("Axp board");
+MODULE_AUTHOR("Kyle Cheung");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/power/axp_power/axp15-gpio.c b/drivers/power/axp_power/axp15-gpio.c
new file mode 100755
index 0000000..2faf11c
--- /dev/null
+++ b/drivers/power/axp_power/axp15-gpio.c
@@ -0,0 +1,348 @@
+/*
+ * axp15-gpio.c -- gpiolib support for X-Power &axp PMICs
+ *
+ * Copyright 2012 X-Powers Microelectronics PLC.
+ *
+ * Author: Kyle Cheung <>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/mfd/axp-mfd.h>
+
+#include "axp-gpio.h"
+
+struct virtual_gpio_data {
+ struct mutex lock;
+ int gpio; //gpio number : 0/1/2/...
+ int io; //0: input 1: output
+ int value; //0: low 1: high
+};
+
+int axp_gpio_set_io(int gpio, int io_state)
+{
+ if(io_state == 1){
+ switch(gpio)
+ {
+ case 0: return axp_clr_bits(&axp->dev,AXP15_GPIO0_CFG, 0x06);
+ case 1: return axp_clr_bits(&axp->dev,AXP15_GPIO1_CFG, 0x06);
+ case 2: return axp_clr_bits(&axp->dev,AXP15_GPIO2_CFG, 0x06);
+ case 3: return axp_clr_bits(&axp->dev,AXP15_GPIO3_CFG, 0x04);
+ default:return -ENXIO;
+ }
+ }
+ else if(io_state == 0){
+ switch(gpio)
+ {
+ case 0: axp_clr_bits(&axp->dev,AXP15_GPIO0_CFG,0x05);
+ return axp_set_bits(&axp->dev,AXP15_GPIO0_CFG,0x02);
+ case 1: axp_clr_bits(&axp->dev,AXP15_GPIO1_CFG,0x05);
+ return axp_set_bits(&axp->dev,AXP15_GPIO1_CFG,0x02);
+ case 2: axp_clr_bits(&axp->dev,AXP15_GPIO2_CFG,0x05);
+ return axp_set_bits(&axp->dev,AXP15_GPIO2_CFG,0x02);
+ case 3: return axp_set_bits(&axp->dev,AXP15_GPIO3_CFG,0x04);
+ default:return -ENXIO;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(axp_gpio_set_io);
+
+
+int axp_gpio_get_io(int gpio, int *io_state)
+{
+ uint8_t val;
+ switch(gpio)
+ {
+ case 0: axp_read(&axp->dev,AXP15_GPIO0_CFG,&val);val &= 0x07;
+ if(val < 0x02)
+ *io_state = 1;
+ else if (val == 0x02)
+ *io_state = 0;
+ else
+ return -EIO;
+ break;
+ case 1: axp_read(&axp->dev,AXP15_GPIO1_CFG,&val);val &= 0x07;
+ if(val < 0x02)
+ *io_state = 1;
+ else if (val == 0x02)
+ *io_state = 0;
+ else
+ return -EIO;
+ break;
+ case 2: axp_read(&axp->dev,AXP15_GPIO2_CFG,&val);val &= 0x07;
+ if(val < 0x02)
+ *io_state = 1;
+ else if (val == 0x02)
+ *io_state = 0;
+ else
+ return -EIO;
+ break;
+ case 3: axp_read(&axp->dev,AXP15_GPIO3_CFG,&val);val &= 0x04;
+ if(val == 0x0)
+ *io_state = 1;
+ else
+ *io_state = 0;
+ break;
+ default:return -ENXIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_gpio_get_io);
+
+
+int axp_gpio_set_value(int gpio, int value)
+{
+ int io_state,ret;
+ ret = axp_gpio_get_io(gpio,&io_state);
+ if(ret)
+ return ret;
+ if(io_state){
+ if(value){
+ switch(gpio)
+ {
+ case 0: axp_clr_bits(&axp->dev,AXP15_GPIO0_CFG,0x06);
+ return axp_set_bits(&axp->dev,AXP15_GPIO0_CFG,0x01);
+ case 1: axp_clr_bits(&axp->dev,AXP15_GPIO1_CFG,0x06);
+ return axp_set_bits(&axp->dev,AXP15_GPIO1_CFG,0x01);
+ case 2: return axp_set_bits(&axp->dev,AXP15_GPIO2_CFG,0x01);
+ case 3: return axp_set_bits(&axp->dev,AXP15_GPIO3_CFG,0x02);
+ default:break;
+ }
+ }
+ else{
+ switch(gpio)
+ {
+ case 0: return axp_clr_bits(&axp->dev,AXP15_GPIO0_CFG,0x03);
+ case 1: return axp_clr_bits(&axp->dev,AXP15_GPIO1_CFG,0x03);
+ case 2: return axp_clr_bits(&axp->dev,AXP15_GPIO2_CFG,0x03);
+ case 3: return axp_clr_bits(&axp->dev,AXP15_GPIO3_CFG,0x02);
+ default:break;
+ }
+ }
+ return -ENXIO;
+ }
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(axp_gpio_set_value);
+
+
+int axp_gpio_get_value(int gpio, int *value)
+{
+ int io_state;
+ int ret;
+ uint8_t val;
+ ret = axp_gpio_get_io(gpio,&io_state);
+ if(ret)
+ return ret;
+ if(io_state){
+ switch(gpio)
+ {
+ case 0:ret = axp_read(&axp->dev,AXP15_GPIO0_CFG,&val);*value = val & 0x01;break;
+ case 1:ret =axp_read(&axp->dev,AXP15_GPIO1_CFG,&val);*value = val & 0x01;break;
+ case 2:ret = axp_read(&axp->dev,AXP15_GPIO2_CFG,&val);*value = val & 0x01;break;
+ case 3:ret = axp_read(&axp->dev,AXP15_GPIO3_CFG,&val);val &= 0x02;*value = val>>1;break;
+ default:return -ENXIO;
+ }
+ }
+ else{
+ switch(gpio)
+ {
+ case 0:ret = axp_read(&axp->dev,AXP15_GPIO0123_STATE,&val);val &= 0x01;break;
+ case 1:ret = axp_read(&axp->dev,AXP15_GPIO0123_STATE,&val);val &= 0x02;*value = val>>1;break;
+ case 2:ret = axp_read(&axp->dev,AXP15_GPIO0123_STATE,&val);val &= 0x04;*value = val>>2;break;
+ case 3:ret = axp_read(&axp->dev,AXP15_GPIO0123_STATE,&val);val &= 0x08;*value = val>>3;break;
+ default:return -ENXIO;
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(axp_gpio_get_value);
+
+static ssize_t show_gpio(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", data->gpio);
+}
+
+static ssize_t set_gpio(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+
+ data->gpio = val;
+
+ return count;
+}
+
+static ssize_t show_io(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ int ret;
+ mutex_lock(&data->lock);
+
+ ret = axp_gpio_get_io(data->gpio,&data->io);
+
+ mutex_unlock(&data->lock);
+
+ if(ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", data->io);
+}
+
+static ssize_t set_io(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+
+ mutex_lock(&data->lock);
+
+ data->io = val;
+ ret = axp_gpio_set_io(data->gpio,data->io);
+
+ mutex_unlock(&data->lock);
+ if(ret)
+ return ret;
+ return count;
+}
+
+
+static ssize_t show_value(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = axp_gpio_get_value(data->gpio,&data->value);
+
+ mutex_unlock(&data->lock);
+
+ if(ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", data->value);
+}
+
+static ssize_t set_value(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_gpio_data *data = dev_get_drvdata(dev);
+ long val;
+ int ret;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+
+ mutex_lock(&data->lock);
+
+ data->value = val;
+ ret = axp_gpio_set_value(data->gpio,data->value);
+
+ mutex_unlock(&data->lock);
+
+ if(ret){
+ return ret;
+ }
+
+ return count;
+}
+
+
+static DEVICE_ATTR(gpio,0664, show_gpio, set_gpio);
+static DEVICE_ATTR(io, 0664, show_io, set_io);
+static DEVICE_ATTR(value, 0664, show_value, set_value);
+
+struct device_attribute *attributes[] = {
+ &dev_attr_gpio,
+ &dev_attr_io,
+ &dev_attr_value,
+};
+
+
+static int __devinit axp_gpio_probe(struct platform_device *pdev)
+{
+ //struct axp_mfd_chip *axp_chip = dev_get_drvdata(pdev->dev.parent);
+ struct virtual_gpio_data *drvdata;
+ int ret, i;
+
+ drvdata = kzalloc(sizeof(struct virtual_gpio_data), GFP_KERNEL);
+ if (drvdata == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ mutex_init(&drvdata->lock);
+
+ for (i = 0; i < ARRAY_SIZE(attributes); i++) {
+ ret = device_create_file(&pdev->dev, attributes[i]);
+ if (ret != 0)
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0;
+
+err:
+ for (i = 0; i < ARRAY_SIZE(attributes); i++)
+ device_remove_file(&pdev->dev, attributes[i]);
+ kfree(drvdata);
+ return ret;
+
+return 0;
+}
+
+static int __devexit axp_gpio_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver axp_gpio_driver = {
+ .
driver.name = "axp20-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = axp_gpio_probe,
+ .remove = __devexit_p(axp_gpio_remove),
+};
+
+static int __init axp_gpio_init(void)
+{
+ return platform_driver_register(&axp_gpio_driver);
+}
+subsys_initcall(axp_gpio_init);
+
+static void __exit axp_gpio_exit(void)
+{
+ platform_driver_unregister(&axp_gpio_driver);
+}
+module_exit(axp_gpio_exit);
+
+MODULE_AUTHOR("Kyle Cheung ");
+MODULE_DESCRIPTION("GPIO interface for AXP PMICs");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:axp-gpio");
diff --git a/drivers/power/axp_power/axp15-mfd.h b/drivers/power/axp_power/axp15-mfd.h
new file mode 100755
index 0000000..6d6463d
--- /dev/null
+++ b/drivers/power/axp_power/axp15-mfd.h
@@ -0,0 +1,363 @@
+#include "axp-rw.h"
+
+
+static int __devinit axp15_init_chip(struct axp_mfd_chip *chip)
+{
+ uint8_t chip_id;
+ uint8_t v[11] = {0x00,POWER15_INTEN2, 0x03,POWER15_INTEN3,0x00,
+ POWER15_INTSTS1,0xff,POWER15_INTSTS2, 0xff,
+ POWER15_INTSTS3,0xff,};
+ int err;
+ /*read chip id*/
+ err = __axp_read(chip->client, POWER15_IC_TYPE, &chip_id);
+ if (err) {
+ printk("[AXP15-MFD] try to read chip id failed!\n");
+ return err;
+ }
+
+ /*enable irqs and clear*/
+ err = __axp_writes(chip->client, POWER15_INTEN1, 11, v);
+ if (err) {
+ printk("[AXP15-MFD] try to clear irq failed!\n");
+ return err;
+ }
+
+ dev_info(chip->dev, "AXP (CHIP ID: 0x%02x) detected\n", chip_id);
+ chip->type = AXP15;
+
+ /* mask and clear all IRQs */
+ chip->irqs_enabled = 0xffffff;
+ chip->ops->disable_irqs(chip, chip->irqs_enabled);
+
+ return 0;
+}
+
+static int axp15_disable_irqs(struct axp_mfd_chip *chip, uint64_t irqs)
+{
+ uint8_t v[5];
+ int ret;
+
+ chip->irqs_enabled &= ~irqs;
+
+ v[0] = ((chip->irqs_enabled) & 0xff);
+ v[1] = POWER15_INTEN2;
+ v[2] = ((chip->irqs_enabled) >> 8) & 0xff;
+ v[3] = POWER15_INTEN3;
+ v[4] = ((chip->irqs_enabled) >> 16) & 0xff;
+ ret = __axp_writes(chip->client, POWER15_INTEN1, 5, v);
+
+ return ret;
+
+}
+
+static int axp15_enable_irqs(struct axp_mfd_chip *chip, uint64_t irqs)
+{
+ uint8_t v[5];
+ int ret;
+
+ chip->irqs_enabled |= irqs;
+
+ v[0] = ((chip->irqs_enabled) & 0xff);
+ v[1] = POWER15_INTEN2;
+ v[2] = ((chip->irqs_enabled) >> 8) & 0xff;
+ v[3] = POWER15_INTEN3;
+ v[4] = ((chip->irqs_enabled) >> 16) & 0xff;
+ ret = __axp_writes(chip->client, POWER15_INTEN1, 5, v);
+
+ return ret;
+}
+
+static int axp15_read_irqs(struct axp_mfd_chip *chip, uint64_t *irqs)
+{
+ uint8_t v[3] = {0, 0, 0};
+ int ret;
+ ret = __axp_reads(chip->client, POWER15_INTSTS1, 3, v);
+ if (ret < 0)
+ return ret;
+
+ *irqs =((((uint64_t) v[2])<< 16) | (((uint64_t)v[1]) << 8) | ((uint64_t) v[0]));
+ return 0;
+}
+
+
+static ssize_t axp15_offvol_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val = 0;
+ axp_read(dev,POWER15_VOFF_SET,&val);
+ return sprintf(buf,"%d\n",(val & 0x07) * 100 + 2600);
+}
+
+static ssize_t axp15_offvol_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if (tmp < 2600)
+ tmp = 2600;
+ if (tmp > 3300)
+ tmp = 3300;
+
+ axp_read(dev,POWER15_VOFF_SET,&val);
+ val &= 0xf8;
+ val |= ((tmp - 2600) / 100);
+ axp_write(dev,POWER15_VOFF_SET,val);
+ return count;
+}
+
+static ssize_t axp15_noedelay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,POWER15_OFF_CTL,&val);
+ if( (val & 0x03) == 0)
+ return sprintf(buf,"%d\n",128);
+ else
+ return sprintf(buf,"%d\n",(val & 0x03) * 1000);
+}
+
+static ssize_t axp15_noedelay_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if (tmp < 1000)
+ tmp = 128;
+ if (tmp > 3000)
+ tmp = 3000;
+ axp_read(dev,POWER15_OFF_CTL,&val);
+ val &= 0xfc;
+ val |= ((tmp) / 1000);
+ axp_write(dev,POWER15_OFF_CTL,val);
+ return count;
+}
+
+static ssize_t axp15_pekopen_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ int tmp = 0;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ switch(val >> 6){
+ case 0: tmp = 128;break;
+ case 1: tmp = 3000;break;
+ case 2: tmp = 1000;break;
+ case 3: tmp = 2000;break;
+ default:
+ tmp = 0;break;
+ }
+ return sprintf(buf,"%d\n",tmp);
+}
+
+static ssize_t axp15_pekopen_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ axp_read(dev,POWER15_PEK_SET,&val);
+ if (tmp < 1000)
+ val &= 0x3f;
+ else if(tmp < 2000){
+ val &= 0x3f;
+ val |= 0x80;
+ }
+ else if(tmp < 3000){
+ val &= 0x3f;
+ val |= 0xc0;
+ }
+ else {
+ val &= 0x3f;
+ val |= 0x40;
+ }
+ axp_write(dev,POWER15_PEK_SET,val);
+ return count;
+}
+
+static ssize_t axp15_peklong_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val = 0;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ return sprintf(buf,"%d\n",((val >> 4) & 0x03) * 500 + 1000);
+}
+
+static ssize_t axp15_peklong_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if(tmp < 1000)
+ tmp = 1000;
+ if(tmp > 2500)
+ tmp = 2500;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ val &= 0xcf;
+ val |= (((tmp - 1000) / 500) << 4);
+ axp_write(dev,POWER15_PEK_SET,val);
+ return count;
+}
+
+static ssize_t axp15_peken_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ return sprintf(buf,"%d\n",((val >> 3) & 0x01));
+}
+
+static ssize_t axp15_peken_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if(tmp)
+ tmp = 1;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ val &= 0xf7;
+ val |= (tmp << 3);
+ axp_write(dev,POWER15_PEK_SET,val);
+ return count;
+}
+
+static ssize_t axp15_pekdelay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,POWER15_PEK_SET,&val);
+
+ return sprintf(buf,"%d\n",((val >> 2) & 0x01)? 64:8);
+}
+
+static ssize_t axp15_pekdelay_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if(tmp <= 8)
+ tmp = 0;
+ else
+ tmp = 1;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ val &= 0xfb;
+ val |= tmp << 2;
+ axp_write(dev,POWER15_PEK_SET,val);
+ return count;
+}
+
+static ssize_t axp15_pekclose_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ return sprintf(buf,"%d\n",((val & 0x03) * 2000) + 4000);
+}
+
+static ssize_t axp15_pekclose_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if(tmp < 4000)
+ tmp = 4000;
+ if(tmp > 10000)
+ tmp =10000;
+ tmp = (tmp - 4000) / 2000 ;
+ axp_read(dev,POWER15_PEK_SET,&val);
+ val &= 0xfc;
+ val |= tmp ;
+ axp_write(dev,POWER15_PEK_SET,val);
+ return count;
+}
+
+static ssize_t axp15_ovtemclsen_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,POWER15_HOTOVER_CTL,&val);
+ return sprintf(buf,"%d\n",((val >> 2) & 0x01));
+}
+
+static ssize_t axp15_ovtemclsen_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 10);
+ if(tmp)
+ tmp = 1;
+ axp_read(dev,POWER15_HOTOVER_CTL,&val);
+ val &= 0xfb;
+ val |= tmp << 2 ;
+ axp_write(dev,POWER15_HOTOVER_CTL,val);
+ return count;
+}
+
+static ssize_t axp15_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val;
+ axp_read(dev,axp_reg_addr,&val);
+ return sprintf(buf,"REG[%x]=%x\n",axp_reg_addr,val);
+}
+
+static ssize_t axp15_reg_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val;
+ tmp = simple_strtoul(buf, NULL, 16);
+ if( tmp < 256 )
+ axp_reg_addr = tmp;
+ else {
+ val = tmp & 0x00FF;
+ axp_reg_addr= (tmp >> 8) & 0x00FF;
+ axp_write(dev,axp_reg_addr, val);
+ }
+ return count;
+}
+
+static ssize_t axp15_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ uint8_t val[2];
+ axp_reads(dev,axp_reg_addr,2,val);
+ return sprintf(buf,"REG[0x%x]=0x%x,REG[0x%x]=0x%x\n",axp_reg_addr,val[0],axp_reg_addr+1,val[1]);
+}
+
+static ssize_t axp15_regs_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int tmp;
+ uint8_t val[3];
+ tmp = simple_strtoul(buf, NULL, 16);
+ if( tmp < 256 )
+ axp_reg_addr = tmp;
+ else {
+ axp_reg_addr= (tmp >> 16) & 0xFF;
+ val[0] = (tmp >> 8) & 0xFF;
+ val[1] = axp_reg_addr + 1;
+ val[2] = tmp & 0xFF;
+ axp_writes(dev,axp_reg_addr,3,val);
+ }
+ return count;
+}
+
+static struct device_attribute axp15_mfd_attrs[] = {
+ AXP_MFD_ATTR(axp15_offvol),
+ AXP_MFD_ATTR(axp15_noedelay),
+ AXP_MFD_ATTR(axp15_pekopen),
+ AXP_MFD_ATTR(axp15_peklong),
+ AXP_MFD_ATTR(axp15_peken),
+ AXP_MFD_ATTR(axp15_pekdelay),
+ AXP_MFD_ATTR(axp15_pekclose),
+ AXP_MFD_ATTR(axp15_ovtemclsen),
+ AXP_MFD_ATTR(axp15_reg),
+ AXP_MFD_ATTR(axp15_regs),
+};
diff --git a/drivers/power/axp_power/axp15-regu.c b/drivers/power/axp_power/axp15-regu.c
new file mode 100755
index 0000000..d46e4f7
--- /dev/null
+++ b/drivers/power/axp_power/axp15-regu.c
@@ -0,0 +1,704 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * 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/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/module.h>
+
+#include "axp-regu.h"
+
+static int axp15_ldo0_data[] = { 5000, 3300, 2800, 2500};
+static int axp15_dcdc1_data[] = { 1700, 1800, 1900, 2000, 2100, 2400, 2500, 2600,\
+ 2700, 2800, 3000, 3100, 3200, 3300, 3400, 3500};
+static int axp15_aldo12_data[] = { 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900,\
+ 2000, 2500, 2700, 2800, 3000, 3100, 3200, 3300};
+
+static inline struct device *to_axp_dev(struct regulator_dev *rdev)
+{
+ return rdev_get_dev(rdev)->parent->parent;
+}
+
+static inline int check_range(struct axp_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (min_uV < info->min_uV || min_uV > info->max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* AXP common operations */
+static int axp_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ printk("reg=[%x],val=%d,mask=%d,line=%d\n",info->vol_reg,val,mask,__LINE__);
+ return axp_update(axp_dev, info->vol_reg, val, mask);
+}
+
+static int axp_get_voltage(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int ret;
+
+ ret = axp_read(axp_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ return info->min_uV + info->step_uV * val;
+
+}
+
+static int axp_enable(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+
+ return axp_set_bits(axp_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int axp_disable(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+
+ return axp_clr_bits(axp_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int axp_is_enabled(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t reg_val;
+ int ret;
+
+ ret = axp_read(axp_dev, info->enable_reg, ®_val);
+ if (ret)
+ return ret;
+
+ return !!(reg_val & (1 << info->enable_bit));
+}
+
+static int axp_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if(info->
desc.id == AXP15_ID_LDO0)
+ return axp15_ldo0_data[selector] * 1000;
+ if(info->
desc.id == AXP15_ID_DCDC1)
+ return axp15_dcdc1_data[selector] * 1000;
+ if(info->
desc.id == AXP15_ID_LDO2)
+ return axp15_aldo12_data[selector] * 1000;
+ if(info->
desc.id == AXP15_ID_LDO3)
+ return axp15_aldo12_data[selector] * 1000;
+
+ ret = info->min_uV + info->step_uV * selector;
+ if (ret > info->max_uV)
+ return -EINVAL;
+ return ret;
+}
+
+static int axp_set_ldo0_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int i;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ for(i = 0,val = 0; i < sizeof(axp15_ldo0_data);i++){
+ if(min_uV <= axp15_ldo0_data[i] * 1000){
+ val = i;
+ break;
+ }
+ }
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ return axp_update(axp_dev, info->vol_reg, val, mask);
+}
+
+static int axp_set_dcdc1_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int i;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ for(i = 0,val = 0; i < sizeof(axp15_dcdc1_data);i++){
+ if(min_uV <= axp15_dcdc1_data[i] * 1000){
+ val = i;
+ break;
+ }
+ }
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ return axp_update(axp_dev, info->vol_reg, val, mask);
+}
+
+static int axp_set_aldo12_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int i;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ for(i = 0,val = 0; i < sizeof(axp15_aldo12_data);i++){
+ if(min_uV <= axp15_aldo12_data[i] * 1000){
+ val = i;
+ break;
+ }
+ }
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ return axp_update(axp_dev, info->vol_reg, val, mask);
+}
+
+/*static int axp_set_ldoio0_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int i;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ for(i = 0,val = 0; i < sizeof(axp15_ldoio0_data);i++){
+ if(min_uV <= axp15_ldoio0_data[i] * 1000){
+ val = i;
+ break;
+ }
+ }
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ return axp_update(axp_dev, info->vol_reg, val, mask);
+}*/
+
+static int axp_get_ldo0_voltage(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int ret;
+
+ ret = axp_read(axp_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+ ret = axp15_ldo0_data[val]*1000;
+ return ret;
+}
+
+static int axp_get_dcdc1_voltage(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int ret;
+
+ ret = axp_read(axp_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+ ret = axp15_dcdc1_data[val]*1000;
+ return ret;
+}
+
+static int axp_get_aldo12_voltage(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val, mask;
+ int ret;
+
+ ret = axp_read(axp_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+ ret = axp15_aldo12_data[val]*1000;
+ return ret;
+}
+
+static int axp_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ int ldo = rdev_get_id(rdev);
+printk("%s,%d\n", __func__, __LINE__);
+ switch (ldo) {
+
+ case AXP15_ID_LDO0:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_ldo0_voltage(rdev, uV, uV);
+ case AXP15_ID_LDO2:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_aldo12_voltage(rdev, uV, uV);
+ case AXP15_ID_LDO3:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_aldo12_voltage(rdev, uV, uV);
+ case AXP15_ID_LDO4:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_LDO5:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_DCDC1:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_dcdc1_voltage(rdev, uV, uV);
+ case AXP15_ID_DCDC2:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_DCDC3:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_DCDC4:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_LDO1:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ case AXP15_ID_LDOIO0:
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return axp_set_voltage(rdev, uV, uV);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static struct regulator_ops axp15_ops = {
+ .set_voltage = axp_set_voltage,
+ .get_voltage = axp_get_voltage,
+ .list_voltage = axp_list_voltage,
+ .enable = axp_enable,
+ .disable = axp_disable,
+ .is_enabled = axp_is_enabled,
+ .set_suspend_enable = axp_enable,
+ .set_suspend_disable = axp_disable,
+ .set_suspend_voltage = axp_set_suspend_voltage,
+};
+
+static struct regulator_ops axp15_ldo0_ops = {
+ .set_voltage = axp_set_ldo0_voltage,
+ .get_voltage = axp_get_ldo0_voltage,
+ .list_voltage = axp_list_voltage,
+ .enable = axp_enable,
+ .disable = axp_disable,
+ .is_enabled = axp_is_enabled,
+ .set_suspend_enable = axp_enable,
+ .set_suspend_disable = axp_disable,
+ .set_suspend_voltage = axp_set_suspend_voltage,
+};
+
+static struct regulator_ops axp15_dcdc1_ops = {
+ .set_voltage = axp_set_dcdc1_voltage,
+ .get_voltage = axp_get_dcdc1_voltage,
+ .list_voltage = axp_list_voltage,
+ .enable = axp_enable,
+ .disable = axp_disable,
+ .is_enabled = axp_is_enabled,
+ .set_suspend_enable = axp_enable,
+ .set_suspend_disable = axp_disable,
+ .set_suspend_voltage = axp_set_suspend_voltage,
+};
+
+static struct regulator_ops axp15_aldo12_ops = {
+ .set_voltage = axp_set_aldo12_voltage,
+ .get_voltage = axp_get_aldo12_voltage,
+ .list_voltage = axp_list_voltage,
+ .enable = axp_enable,
+ .disable = axp_disable,
+ .is_enabled = axp_is_enabled,
+ .set_suspend_enable = axp_enable,
+ .set_suspend_disable = axp_disable,
+ .set_suspend_voltage = axp_set_suspend_voltage,
+};
+
+static int axp_ldoio0_enable(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+
+ axp_set_bits(axp_dev, info->enable_reg,0x03);
+ return axp_clr_bits(axp_dev, info->enable_reg,0x04);
+}
+
+static int axp_ldoio0_disable(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+
+ return axp_clr_bits(axp_dev, info->enable_reg,0x07);
+}
+
+static int axp_ldoio0_is_enabled(struct regulator_dev *rdev)
+{
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t reg_val;
+ int ret;
+
+ ret = axp_read(axp_dev, info->enable_reg, ®_val);
+ if (ret)
+ return ret;
+
+ return (((reg_val &= 0x07)== 0x03)?1:0);
+}
+
+static struct regulator_ops axp15_ldoio0_ops = {
+ .set_voltage = axp_set_voltage,
+ .get_voltage = axp_get_voltage,
+ .list_voltage = axp_list_voltage,
+ .enable = axp_ldoio0_enable,
+ .disable = axp_ldoio0_disable,
+ .is_enabled = axp_ldoio0_is_enabled,
+ .set_suspend_enable = axp_ldoio0_enable,
+ .set_suspend_disable = axp_ldoio0_disable,
+ .set_suspend_voltage = axp_set_suspend_voltage,
+};
+
+
+#define AXP15_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ AXP_LDO(AXP15, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define AXP15_BUCK(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ AXP_BUCK(AXP15, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define AXP15_DCDC(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ AXP_DCDC(AXP15, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+static struct axp_regulator_info axp_regulator_info[] = {
+ AXP15_LDO( 0, 2500, 5000, 833, LDO0, 4, 2, LDO0EN, 7),//ldo0
+ AXP15_LDO( 1, 1200, 3100, 100, RTC, 0, 0, RTCLDOEN, 0),//ldo1 for rtc
+ AXP15_LDO( 2, 1200, 3300, 120, ANALOG1, 4, 4, ANALOG1EN, 3),//ldo2 for analog1
+ AXP15_LDO( 3, 1200, 3300, 120, ANALOG2, 0, 4, ANALOG2EN, 2),//ldo3 for analog2
+ AXP15_LDO( 4, 700, 3500, 100, DIGITAL1, 0, 4, ANALOG1EN, 1),//ldo2 for DigtalLDO1
+ AXP15_LDO( 5, 700, 3500, 100, DIGITAL2, 0, 4, ANALOG2EN, 0),//ldo3 for DigtalLDO2
+ AXP15_DCDC( 1, 1700, 3500, 120, DCDC1, 0, 4, DCDC1EN, 7) , //buck1
+ AXP15_DCDC( 2, 700, 2275, 25, DCDC2, 0, 6, DCDC2EN, 6),//buck2
+ AXP15_DCDC( 3, 700, 3500, 50, DCDC3, 0, 6, DCDC3EN, 5),//buck3
+ AXP15_DCDC( 4, 700, 3500, 25, DCDC4, 0, 7, DCDC4EN, 4),//buck4
+ AXP15_LDO( IO0, 1800, 3300, 100, LDOIO0, 0, 4, LDOI0EN, 1),//ldoio0
+};
+
+static ssize_t workmode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ int ret;
+ uint8_t val;
+ ret = axp_read(axp_dev, AXP15_BUCKMODE, &val);
+ if (ret)
+ return sprintf(buf, "IO ERROR\n");
+
+ if(info->
desc.id == AXP15_ID_DCDC1){
+ switch (val & 0x08) {
+ case 0:return sprintf(buf, "AUTO\n");
+ case 8:return sprintf(buf, "PWM\n");
+ default:return sprintf(buf, "UNKNOWN\n");
+ }
+ }
+ if(info->
desc.id == AXP15_ID_DCDC2){
+ switch (val & 0x04) {
+ case 0:return sprintf(buf, "AUTO\n");
+ case 4:return sprintf(buf, "PWM\n");
+ default:return sprintf(buf, "UNKNOWN\n");
+ }
+ }
+ if(info->
desc.id == AXP15_ID_DCDC3){
+ switch (val & 0x02) {
+ case 0:return sprintf(buf, "AUTO\n");
+ case 2:return sprintf(buf, "PWM\n");
+ default:return sprintf(buf, "UNKNOWN\n");
+ }
+ }
+ else if(info->
desc.id == AXP15_ID_DCDC4){
+ switch (val & 0x01) {
+ case 0:return sprintf(buf, "AUTO\n");
+ case 1:return sprintf(buf, "PWM\n");
+ default:return sprintf(buf, "UNKNOWN\n");
+ }
+ }
+ else
+ return sprintf(buf, "IO ID ERROR\n");
+}
+
+static ssize_t workmode_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ struct axp_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ char mode;
+ uint8_t val;
+ if( buf[0] > '0' && buf[0] < '9' )// 1/AUTO: auto mode; 2/PWM: pwm mode;
+ mode = buf[0];
+ else
+ mode = buf[1];
+
+ switch(mode){
+ case 'U':
+ case 'u':
+ case '1':
+ val = 0;break;
+ case 'W':
+ case 'w':
+ case '2':
+ val = 1;break;
+ default:
+ val =0;
+ }
+
+ if(info->
desc.id == AXP15_ID_DCDC1){
+ if(val)
+ axp_set_bits(axp_dev, AXP15_BUCKMODE,0x08);
+ else
+ axp_clr_bits(axp_dev, AXP15_BUCKMODE,0x08);
+ }
+ if(info->
desc.id == AXP15_ID_DCDC2){
+ if(val)
+ axp_set_bits(axp_dev, AXP15_BUCKMODE,0x04);
+ else
+ axp_clr_bits(axp_dev, AXP15_BUCKMODE,0x04);
+ }
+ if(info->
desc.id == AXP15_ID_DCDC3){
+ if(val)
+ axp_set_bits(axp_dev, AXP15_BUCKMODE,0x02);
+ else
+ axp_clr_bits(axp_dev, AXP15_BUCKMODE,0x02);
+ }
+ else if(info->
desc.id == AXP15_ID_DCDC4){
+ if(val)
+ axp_set_bits(axp_dev, AXP15_BUCKMODE,0x01);
+ else
+ axp_clr_bits(axp_dev, AXP15_BUCKMODE,0x01);
+ }
+
+ return count;
+}
+
+static ssize_t frequency_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ int ret;
+ uint8_t val;
+ ret = axp_read(axp_dev, AXP15_BUCKFREQ, &val);
+ if (ret)
+ return ret;
+ ret = val & 0x0F;
+ return sprintf(buf, "%d\n",(ret*5 + 50));
+}
+
+static ssize_t frequency_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ struct device *axp_dev = to_axp_dev(rdev);
+ uint8_t val,tmp;
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var < 50)
+ var = 50;
+ if(var > 100)
+ var = 100;
+
+ val = (var -50)/5;
+ val &= 0x0F;
+
+ axp_read(axp_dev, AXP15_BUCKFREQ, &tmp);
+ tmp &= 0xF0;
+ val |= tmp;
+ axp_write(axp_dev, AXP15_BUCKFREQ, val);
+ return count;
+}
+
+
+static struct device_attribute axp_regu_attrs[] = {
+ AXP_REGU_ATTR(workmode),
+ AXP_REGU_ATTR(frequency),
+};
+
+int axp_regu_create_attrs(struct platform_device *pdev)
+{
+ int j,ret;
+ for (j = 0; j < ARRAY_SIZE(axp_regu_attrs); j++) {
+ ret = device_create_file(&pdev->dev,&axp_regu_attrs[j]);
+ if (ret)
+ goto sysfs_failed;
+ }
+ goto succeed;
+
+sysfs_failed:
+ while (j--)
+ device_remove_file(&pdev->dev,&axp_regu_attrs[j]);
+succeed:
+ return ret;
+}
+
+static inline struct axp_regulator_info *find_regulator_info(int id)
+{
+ struct axp_regulator_info *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(axp_regulator_info); i++) {
+ ri = &axp_regulator_info[i];
+ if (ri->
desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int __devinit axp_regulator_probe(struct platform_device *pdev)
+{
+ struct axp_regulator_info *ri = NULL;
+ struct regulator_dev *rdev;
+ int ret;
+
+ ri = find_regulator_info(pdev->id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+
+ if (ri->
desc.id == AXP15_ID_LDO4 || ri->
desc.id == AXP15_ID_LDO5 \
+ ||ri->
desc.id == AXP15_ID_DCDC1 ||ri->
desc.id == AXP15_ID_DCDC2 \
+ ||ri->
desc.id == AXP15_ID_DCDC3 ||ri->
desc.id == AXP15_ID_DCDC4 \
+ ||ri->
desc.id == AXP15_ID_LDO1 ||ri->
desc.id == AXP15_ID_LDOIO0)
+ {
+ ri->desc.ops = &axp15_ops;
+ printk("Register AXP15_OPS sucess!\n");
+ }
+
+
+ if(ri->
desc.id == AXP15_ID_LDO0)
+ {
+ ri->desc.ops = &axp15_ldo0_ops;
+ printk("Register AXP15_ldo0_OPS finish!\n");
+ }
+
+ if(ri->
desc.id == AXP15_ID_LDO3 || ri->
desc.id == AXP15_ID_LDO2)
+ {
+ ri->desc.ops = &axp15_aldo12_ops;
+ printk("Register AXP15_aldo12_OPS finish!\n");
+ }
+
+ if(ri->
desc.id == AXP15_ID_DCDC1)
+ {
+ ri->desc.ops = &axp15_dcdc1_ops;
+ printk("Register AXP15_dcdc1_OPS finish!\n");
+ }
+
+ rdev = regulator_register(&ri->desc, &pdev->dev,
+ pdev->dev.platform_data, ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->
desc.name);
+ return PTR_ERR(rdev);
+ }
+ platform_set_drvdata(pdev, rdev);
+
+ if(ri->
desc.id == AXP15_ID_DCDC1 ||ri->
desc.id == AXP15_ID_DCDC2 \
+ ||ri->
desc.id == AXP15_ID_DCDC3 ||ri->
desc.id == AXP15_ID_DCDC4){
+ ret = axp_regu_create_attrs(pdev);
+ if(ret){
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __devexit axp_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver axp_regulator_driver = {
+ .driver = {
+ .name = "axp15-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = axp_regulator_probe,
+ .remove = axp_regulator_remove,
+};
+
+static int __init axp_regulator_init(void)
+{
+ return platform_driver_register(&axp_regulator_driver);
+}
+module_init(axp_regulator_init);
+
+static void __exit axp_regulator_exit(void)
+{
+ platform_driver_unregister(&axp_regulator_driver);
+}
+module_exit(axp_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyle Cheung");
+MODULE_DESCRIPTION("Regulator Driver for AXP15 PMIC");
+MODULE_ALIAS("platform:axp-regulator");
diff --git a/drivers/power/axp_power/axp15-sply.c b/drivers/power/axp_power/axp15-sply.c
new file mode 100755
index 0000000..adb7198
--- /dev/null
+++ b/drivers/power/axp_power/axp15-sply.c
@@ -0,0 +1,2318 @@
+/*
+ * Battery charger driver for KrossPower AXP15X
+ *
+ * Copyright (C) 2012 X-Power, Ltd.
+ * Zhang Donglu <
zhang...@x-powers.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/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/input.h>
+#include <linux/mfd/axp-mfd.h>
+#include <asm/div64.h>
+
+#include <mach/sys_config.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include "axp-cfg.h"
+#include "axp-sply.h"
+
+#define DBG_AXP_PSY 1
+#if DBG_AXP_PSY
+#define DBG_PSY_MSG(format,args...) printk("[AXP]"format,##args)
+#else
+#define DBG_PSY_MSG(format,args...) do {} while (0)
+#endif
+static int axp_debug = 0;
+static int pmu_used2 = 0;
+static int gpio_adp_hdle = 0;
+static int pmu_suspendpwroff_vol = 0;
+static int pmu_earlysuspend_chgcur = 0;
+static int pmu_batdeten = 0;
+struct axp_adc_res adc;
+static int count_rdc = 0;
+static int count_dis = 0;
+struct delayed_work usbwork;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static struct early_suspend axp_early_suspend;
+int early_suspend_flag = 0;
+#endif
+
+int pmu_usbvolnew ;
+int pmu_usbcurnew ;
+int axp_usbcurflag ;
+int axp_usbvolflag ;
+
+int axp_usbvol(void)
+{
+ axp_usbvolflag = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbvol);
+
+int axp_usbcur(void)
+{
+ axp_usbcurflag = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbcur);
+
+int axp_usbvol_restore(void)
+{
+ axp_usbvolflag = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbvol_restore);
+
+int axp_usbcur_restore(void)
+{
+ axp_usbcurflag = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axp_usbcur_restore);
+
+static ssize_t axpdebug_store(struct class *class,
+ struct class_attribute *attr, const char *buf, size_t count)
+{
+ if(buf[0] == '1'){
+ axp_debug = 1;
+ }
+ else{
+ axp_debug = 0;
+ }
+ return count;
+}
+
+static ssize_t axpdebug_show(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "bat-debug value is %d\n", axp_debug);
+}
+
+static struct class_attribute axppower_class_attrs[] = {
+ __ATTR(axpdebug,S_IRUGO|S_IWUSR,axpdebug_show,axpdebug_store),
+ __ATTR_NULL
+};
+static struct class axppower_class = {
+ .name = "axppower",
+ .class_attrs = axppower_class_attrs,
+};
+
+int ADC_Freq_Get(struct axp_charger *charger)
+{
+ //uint8_t temp;
+ int rValue = 25;
+
+// axp_read(charger->master, AXP15_ADC_CONTROL3,&temp);
+// temp &= 0xc0;
+// switch(temp >> 6)
+// {
+// case 0:
+// rValue = 25;
+// break;
+// case 1:
+// rValue = 50;
+// break;
+// case 2:
+// rValue = 100;
+// break;
+// case 3:
+// rValue = 200;
+// break;
+// default:
+// break;
+// }
+ return rValue;
+}
+
+static inline int axp15_vbat_to_mV(uint16_t reg)
+{
+ return 4000;
+ //return ((int)((( reg >> 8) << 4 ) | (reg & 0x000F))) * 1100 / 1000;
+}
+
+static inline int axp15_vdc_to_mV(uint16_t reg)
+{
+ return 5000;
+ //return ((int)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 1700 / 1000;
+}
+
+
+static inline int axp15_ibat_to_mA(uint16_t reg)
+{
+ return 200;
+ //return ((int)(((reg >> 8) << 5 ) | (reg & 0x001F))) * 500 / 1000;
+}
+
+static inline int axp15_icharge_to_mA(uint16_t reg)
+{
+ return 200;
+ //return ((int)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 500 / 1000;
+}
+
+static inline int axp15_iac_to_mA(uint16_t reg)
+{
+ return 200;
+
+ //return ((int)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 625 / 1000;
+}
+
+static inline int axp15_iusb_to_mA(uint16_t reg)
+{
+ return 200;
+
+ //return ((int)(((reg >> 8) << 4 ) | (reg & 0x000F))) * 375 / 1000;
+}
+
+/*adc may not be used*/
+static inline void axp_read_adc(struct axp_charger *charger,
+ struct axp_adc_res *adc)
+{
+// uint8_t tmp[8];
+//
+// axp_reads(charger->master,AXP15_VACH_RES,8,tmp);
+// adc->vac_res = ((uint16_t) tmp[0] << 8 )| tmp[1];
+// adc->iac_res = ((uint16_t) tmp[2] << 8 )| tmp[3];
+// adc->vusb_res = ((uint16_t) tmp[4] << 8 )| tmp[5];
+// adc->iusb_res = ((uint16_t) tmp[6] << 8 )| tmp[7];
+// axp_reads(charger->master,AXP15_VBATH_RES,6,tmp);
+// adc->vbat_res = ((uint16_t) tmp[0] << 8 )| tmp[1];
+// adc->ichar_res = ((uint16_t) tmp[2] << 8 )| tmp[3];
+// adc->idischar_res = ((uint16_t) tmp[4] << 8 )| tmp[5];
+// return 0xEEA;
+}
+
+
+static void axp_charger_update_state(struct axp_charger *charger)
+{
+// uint8_t val[2];
+// uint16_t tmp;
+//
+// axp_reads(charger->master,AXP15_CHARGE_STATUS,2,val);
+// tmp = (val[1] << 8 )+ val[0];
+// charger->is_on = (val[1] & AXP15_IN_CHARGE) ? 1 : 0;
+// charger->fault = val[1];
+// charger->bat_det = (tmp & AXP15_STATUS_BATEN)?1:0;
+// charger->ac_det = (tmp & AXP15_STATUS_ACEN)?1:0;
+// charger->usb_det = (tmp & AXP15_STATUS_USBEN)?1:0;
+// charger->usb_valid = (tmp & AXP15_STATUS_USBVA)?1:0;
+// charger->ac_valid = (tmp & AXP15_STATUS_ACVA)?1:0;
+// charger->ext_valid = charger->ac_valid | charger->usb_valid;
+// charger->bat_current_direction = (tmp & AXP15_STATUS_BATCURDIR)?1:0;
+// charger->in_short = (tmp& AXP15_STATUS_ACUSBSH)?1:0;
+// charger->batery_active = (tmp & AXP15_STATUS_BATINACT)?1:0;
+// charger->low_charge_current = (tmp & AXP15_STATUS_CHACURLOEXP)?1:0;
+// charger->int_over_temp = (tmp & AXP15_STATUS_ICTEMOV)?1:0;
+// axp_read(charger->master,AXP15_CHARGE_CONTROL1,val);
+// charger->charge_on = ((val[0] >> 7) & 0x01);
+}
+/*
+static void axp_charger_update(struct axp_charger *charger)
+{
+ uint16_t tmp;
+ uint8_t val[2];
+ //struct axp_adc_res adc;
+ charger->adc = &adc;
+ axp_read_adc(charger, &adc);
+ tmp = charger->adc->vbat_res;
+ charger->vbat = axp15_vbat_to_mV(tmp);
+ //tmp = charger->adc->ichar_res + charger->adc->idischar_res;
+ charger->ibat = ABS(axp15_icharge_to_mA(charger->adc->ichar_res)-axp15_ibat_to_mA(charger->adc->idischar_res));
+ tmp = charger->adc->vac_res;
+ charger->vac = axp15_vdc_to_mV(tmp);
+ tmp = charger->adc->iac_res;
+ charger->iac = axp15_iac_to_mA(tmp);
+ tmp = charger->adc->vusb_res;
+ charger->vusb = axp15_vdc_to_mV(tmp);
+ tmp = charger->adc->iusb_res;
+ charger->iusb = axp15_iusb_to_mA(tmp);
+ axp_reads(charger->master,AXP15_INTTEMP,2,val);
+ //DBG_PSY_MSG("TEMPERATURE:val1=0x%x,val2=0x%x\n",val[1],val[0]);
+ tmp = (val[0] << 4 ) + (val[1] & 0x0F);
+ charger->ic_temp = (int) tmp - 1447;
+ if(!charger->ext_valid){
+ charger->disvbat = charger->vbat;
+ charger->disibat = charger->ibat;
+ }
+}
+*/
+static void axp_charger_update(struct axp_charger *charger)
+{
+ uint16_t tmp;
+ uint8_t val[2];
+ //struct axp_adc_res adc;
+
+
+ charger->vbat = 4000;
+ //tmp = charger->adc->ichar_res + charger->adc->idischar_res;
+ charger->ibat = 200;
+ charger->vac = 5000;
+ charger->iac = 500;
+ charger->vusb = 5000;
+ charger->iusb = 200;
+
+ charger->ic_temp = 30;
+
+ charger->disvbat = charger->vbat;
+ charger->disibat = charger->ibat;
+
+}
+
+
+#if defined (CONFIG_AXP_CHARGEINIT)
+static void axp_set_charge(struct axp_charger *charger)
+{
+/*
+ uint8_t val=0x00;
+ uint8_t tmp=0x00;
+ if(charger->chgvol < 4150000)
+ val &= ~(3 << 5);
+ else if (charger->chgvol<4150000){
+ val &= ~(3 << 5);
+ val |= 1 << 5;
+ }
+ else if (charger->chgvol<4360000){
+ val &= ~(3 << 5);
+ val |= 1 << 6;
+ }
+ else
+ val |= 3 << 5;
+
+ if(charger->chgcur == 0)
+ charger->chgen = 0;
+
+ if(charger->chgcur< 300000)
+ charger->chgcur = 300000;
+ else if(charger->chgcur > 1800000)
+ charger->chgcur = 1800000;
+
+ val |= (charger->chgcur - 150001) / 100000 ;
+ if(charger ->chgend == 10){
+ val &= ~(1 << 4);
+ }
+ else {
+ val |= 1 << 4;
+ }
+ val &= 0x7F;
+ val |= charger->chgen << 7;
+ if(charger->chgpretime < 30)
+ charger->chgpretime = 30;
+ if(charger->chgcsttime < 360)
+ charger->chgcsttime = 360;
+
+ tmp = ((((charger->chgpretime - 40) / 10) << 6) \
+ | ((charger->chgcsttime - 360) / 120));
+ axp_write(charger->master, AXP15_CHARGE_CONTROL1,val);
+ axp_update(charger->master, AXP15_CHARGE_CONTROL2,tmp,0xC2);
+*/
+}
+#else
+static void axp_set_charge(struct axp_charger *charger)
+{
+
+}
+#endif
+
+/*may not be used*/
+static enum power_supply_property axp_battery_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ //POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ //POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CAPACITY,
+ //POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ //POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static enum power_supply_property axp_ac_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+static enum power_supply_property axp_usb_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+/*may not be used*/
+static void axp_battery_check_status(struct axp_charger *charger,
+ union power_supply_propval *val)
+{
+/*
+ if (charger->bat_det) {
+ if (charger->ext_valid){
+ if( charger->rest_vol == 100)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else if(charger->charge_on)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ }
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+ else
+*/
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+}
+
+/*may not be used*/
+static void axp_battery_check_health(struct axp_charger *charger,
+ union power_supply_propval *val)
+{
+/*
+ if (charger->fault & AXP15_FAULT_LOG_BATINACT)
+ val->intval = POWER_SUPPLY_HEALTH_DEAD;
+ else if (charger->fault & AXP15_FAULT_LOG_OVER_TEMP)
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (charger->fault & AXP15_FAULT_LOG_COLD)
+ val->intval = POWER_SUPPLY_HEALTH_COLD;
+ else
+*/
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+}
+
+/*may not be used*/
+static int axp_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct axp_charger *charger;
+ int ret = 0;
+ charger = container_of(psy, struct axp_charger, batt);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ axp_battery_check_status(charger, val);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ axp_battery_check_health(charger, val);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = charger->battery_info->technology;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = charger->battery_info->voltage_max_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = charger->battery_info->voltage_min_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = charger->ocv * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = charger->ibat * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = charger->
batt.name;
+ break;
+/* case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = charger->battery_info->charge_full_design;
+ break;
+*/
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ val->intval = charger->battery_info->energy_full_design;
+ // DBG_PSY_MSG("POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:%d\n",val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ charger->rest_vol = 100;
+ val->intval = charger->rest_vol;
+ break;
+/* case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+ if(charger->bat_det && !(charger->is_on) && !(charger->ext_valid))
+ val->intval = charger->rest_time;
+ else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+ if(charger->bat_det && charger->is_on)
+ val->intval = charger->rest_time;
+ else
+ val->intval = 0;
+ break;
+*/
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = (!charger->is_on)&&(charger->bat_det) && (! charger->ext_valid);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = charger->bat_det;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ //val->intval = charger->ic_temp - 150;
+ val->intval = 300;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int axp_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct axp_charger *charger;
+ int ret = 0;
+ charger = container_of(psy, struct axp_charger, ac);
+
+ switch(psp){
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = charger->
ac.name;break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = charger->ac_det;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = charger->ac_valid;break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = charger->vac * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = charger->iac * 1000;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int axp_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct axp_charger *charger;
+ int ret = 0;
+ charger = container_of(psy, struct axp_charger, usb);
+
+ switch(psp){
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = charger->
usb.name;break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = charger->usb_det;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = charger->usb_valid;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = charger->vusb * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = charger->iusb * 1000;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static void axp_change(struct axp_charger *charger)
+{
+/*
+ uint8_t val,tmp;
+ int var;
+ DBG_PSY_MSG("battery state change\n");
+ axp_charger_update_state(charger);
+ axp_charger_update(charger);
+ printk("charger->usb_valid = %d\n",charger->usb_valid);
+ if(!charger->usb_valid){
+ printk("set usb vol-lim to %d mV, cur-lim to %d mA\n",pmu_usbvolnew,pmu_usbcurnew);
+ cancel_delayed_work_sync(&usbwork);
+ //reset usb-pc after usb removed
+ if(pmu_usbcurnew){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ var = pmu_usbcurnew * 1000;
+ if(var >= 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if ((var >= 500000)&& (var < 900000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if ((var >= 100000)&& (var < 500000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+ else
+ printk("set usb limit current error,%d mA\n",pmu_usbcur);
+ }
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+
+ if(pmu_usbvolnew){
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ var = pmu_usbvolnew * 1000;
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ else
+ printk("set usb limit voltage error,%d mV\n",pmu_usbvol);
+ }
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ }
+ else {
+ schedule_delayed_work(&usbwork, msecs_to_jiffies(4 * 1000));
+ }
+
+ flag_state_change = 1;
+ power_supply_changed(&charger->batt);
+*/
+}
+
+static void axp_presslong(struct axp_charger *charger)
+{
+ DBG_PSY_MSG("press long\n");
+ input_report_key(powerkeydev, KEY_POWER, 1);
+ input_sync(powerkeydev);
+ ssleep(2);
+ DBG_PSY_MSG("press long up\n");
+ input_report_key(powerkeydev, KEY_POWER, 0);
+ input_sync(powerkeydev);
+}
+
+static void axp_pressshort(struct axp_charger *charger)
+{
+ DBG_PSY_MSG("press short\n");
+ input_report_key(powerkeydev, KEY_POWER, 1);
+ input_sync(powerkeydev);
+ msleep(100);
+ input_report_key(powerkeydev, KEY_POWER, 0);
+ input_sync(powerkeydev);
+}
+
+static void axp_capchange(struct axp_charger *charger)
+{
+/*
+ uint8_t val;
+ int k;
+
+ DBG_PSY_MSG("battery change\n");
+ ssleep(2);
+ axp_charger_update_state(charger);
+ axp_charger_update(charger);
+ axp_read(charger->master, AXP15_CAP,&val);
+ charger->rest_vol = (int) (val & 0x7F);
+
+ if((charger->bat_det == 0) || (charger->rest_vol == 127)){
+ charger->rest_vol = 100;
+ }
+
+ DBG_PSY_MSG("rest_vol = %d\n",charger->rest_vol);
+ memset(Bat_Cap_Buffer, 0, sizeof(Bat_Cap_Buffer));
+ for(k = 0;k < AXP15_VOL_MAX; k++){
+ Bat_Cap_Buffer[k] = charger->rest_vol;
+ }
+ Total_Cap = charger->rest_vol * AXP15_VOL_MAX;
+ power_supply_changed(&charger->batt);
+*/
+}
+
+static void axp_close(struct axp_charger *charger)
+{
+/*
+ charger->rest_vol = 5;
+ axp_write(charger->master,AXP15_DATA_BUFFER1,0x85);
+ DBG_PSY_MSG("\n==================event in close==============\n");
+ power_supply_changed(&charger->batt);
+*/
+}
+
+
+static int axp_battery_event(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct axp_charger *charger =
+ container_of(nb, struct axp_charger, nb);
+
+ uint8_t w[5];
+
+ w[0] = (uint8_t) ((event) & 0xFF);
+ w[1] = POWER15_INTSTS2;
+ w[2] = (uint8_t) ((event >> 8) & 0xFF);
+ w[3] = POWER15_INTSTS3;
+ w[4] = (uint8_t) ((event >> 16) & 0xFF);
+
+
+// if(event & (AXP15_IRQ_BATIN|AXP15_IRQ_BATRE)) {
+// axp_capchange(charger);
+// }
+/*
+ if(event & (AXP15_IRQ_ACIN|AXP15_IRQ_USBIN|AXP15_IRQ_ACOV|AXP15_IRQ_USBOV|AXP15_IRQ_CHAOV
+ |AXP15_IRQ_CHAST|AXP15_IRQ_TEMOV|AXP15_IRQ_TEMLO)) {
+ axp_change(charger);
+ }
+
+ if(event & (AXP15_IRQ_ACRE|AXP15_IRQ_USBRE)) {
+ axp_change(charger);
+ axp_clr_bits(charger->master,0x32,0x38);
+ }
+*/
+ if(event & AXP15_IRQ_PEKLO) {
+ axp_presslong(charger);
+ }
+
+ if(event & AXP15_IRQ_PEKSH) {
+ axp_pressshort(charger);
+ }
+
+ DBG_PSY_MSG("event = 0x%x\n",(int) event);
+ axp_writes(charger->master,POWER15_INTSTS1,9,w);
+
+ return 0;
+}
+
+//may not used
+static char *supply_list[] = {
+ "battery",
+};
+
+
+
+static void axp_battery_setup_psy(struct axp_charger *charger)
+{
+ struct power_supply *batt = &charger->batt; /*may not used*/
+ struct power_supply *ac = &charger->ac;
+ struct power_supply *usb = &charger->usb;
+ struct power_supply_info *info = charger->battery_info; /*may not used*/
+
+/*may not used*/
+ batt->name = "battery";
+ batt->use_for_apm = info->use_for_apm;
+ batt->type = POWER_SUPPLY_TYPE_BATTERY;
+ batt->get_property = axp_battery_get_property;
+
+ batt->properties = axp_battery_props;
+ batt->num_properties = ARRAY_SIZE(axp_battery_props);
+
+ ac->name = "ac";
+ ac->type = POWER_SUPPLY_TYPE_MAINS;
+ ac->get_property = axp_ac_get_property;
+
+ ac->supplied_to = supply_list,
+ ac->num_supplicants = ARRAY_SIZE(supply_list),
+
+ ac->properties = axp_ac_props;
+ ac->num_properties = ARRAY_SIZE(axp_ac_props);
+
+ usb->name = "usb";
+ usb->type = POWER_SUPPLY_TYPE_USB;
+ usb->get_property = axp_usb_get_property;
+
+ usb->supplied_to = supply_list,
+ usb->num_supplicants = ARRAY_SIZE(supply_list),
+
+ usb->properties = axp_usb_props;
+ usb->num_properties = ARRAY_SIZE(axp_usb_props);
+};
+
+#if defined (CONFIG_AXP_CHARGEINIT)
+static int axp_battery_adc_set(struct axp_charger *charger)
+{
+/*
+ int ret ;
+ uint8_t val;
+
+ //enable adc and set adc
+ val= AXP15_ADC_BATVOL_ENABLE | AXP15_ADC_BATCUR_ENABLE
+ | AXP15_ADC_DCINCUR_ENABLE | AXP15_ADC_DCINVOL_ENABLE
+ | AXP15_ADC_USBVOL_ENABLE | AXP15_ADC_USBCUR_ENABLE;
+
+ ret = axp_update(charger->master, AXP15_ADC_CONTROL1, val , val);
+ if (ret)
+ return ret;
+ ret = axp_update(charger->master, AXP15_COULOMB_CONTROL, AXP15_COULOMB_ENABLE , AXP15_COULOMB_ENABLE);
+ if (ret)
+ return ret;
+ ret = axp_read(charger->master, AXP15_ADC_CONTROL3, &val);
+ switch (charger->sample_time/25){
+ case 1: val &= ~(3 << 6);break;
+ case 2: val &= ~(3 << 6);val |= 1 << 6;break;
+ case 4: val &= ~(3 << 6);val |= 2 << 6;break;
+ case 8: val |= 3 << 6;break;
+ default: break;
+ }
+ ret = axp_write(charger->master, AXP15_ADC_CONTROL3, val);
+ if (ret)
+ return ret;
+*/
+ return 0;
+}
+#else
+static int axp_battery_adc_set(struct axp_charger *charger)
+{
+ return 0;
+}
+#endif
+
+static int axp_battery_first_init(struct axp_charger *charger)
+{
+// int ret;
+// uint8_t val;
+// axp_set_charge(charger);
+// ret = axp_battery_adc_set(charger);
+// if(ret)
+// return ret;
+//
+// ret = axp_read(charger->master, AXP15_ADC_CONTROL3, &val);
+// switch ((val >> 6) & 0x03){
+// case 0: charger->sample_time = 25;break;
+// case 1: charger->sample_time = 50;break;
+// case 2: charger->sample_time = 100;break;
+// case 3: charger->sample_time = 200;break;
+// default:break;
+// }
+// return ret;
+ return 0;
+}
+
+/*may not used*/
+static int axp_get_rdc(struct axp_charger *charger)
+{
+/*
+ int temp;
+ int rdc;
+ uint8_t v[2];
+ axp_reads(charger->master,0xba,2,v);
+ rdc = (((v[0] & 0x1F) << 8) | v[1]) * 10742 / 10000;
+ DBG_PSY_MSG("===========================calculate rdc \n");
+
+ if(!charger->bat_det){
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ }
+ if( charger->ext_valid){
+ axp_charger_update(charger);
+ if( axp15_ibat_to_mA(charger->adc->idischar_res) == 0 && axp15_icharge_to_mA(charger->adc->ichar_res) > 150){
+ } else {
+ DBG_PSY_MSG("%s->%d\n",__FUNCTION__,__LINE__);
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ }
+ DBG_PSY_MSG("CHARGING: charger->vbat = %d, charger->ibat = %d\n",charger->vbat,charger->ibat);
+ DBG_PSY_MSG("DISCHARGING:charger->disvbat = %d,charger->disibat = %d\n",charger->disvbat,charger->disibat);
+ axp_charger_update_state(charger);
+ if(!charger->bat_current_direction){
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ }
+ if(charger->disvbat == 0){
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ }else{
+ temp = 1000 * ABS(charger->vbat - charger->disvbat) / ABS(charger->ibat + charger->disibat);
+ DBG_PSY_MSG("CALRDC:temp = %d\n",temp);
+ if((temp < 75) || (temp > pmu_battery_rdc * 2)){
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ } else {
+ axp_set_bits(charger->master,0x04,0x08);
+ return temp;
+ }
+ }
+ }else{
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ return rdc;
+ }
+ */
+ return 100;
+}
+
+static ssize_t chgen_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+/*
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ uint8_t val;
+ axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ charger->chgen = val >> 7;
+ return sprintf(buf, "%d\n",charger->chgen);
+ */
+ return 1;
+}
+
+static ssize_t chgen_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var){
+ charger->chgen = 1;
+ //axp_set_bits(charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ }
+ else{
+ charger->chgen = 0;
+ //axp_clr_bits(charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ }
+ return count;
+}
+
+static ssize_t chgmicrovol_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ struct axp_charger *charger = dev_get_drvdata(dev);
+/* uint8_t val;
+ axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ switch ((val >> 5) & 0x03){
+ case 0: charger->chgvol = 4100000;break;
+ case 1: charger->chgvol = 4150000;break;
+ case 2: charger->chgvol = 4200000;break;
+ case 3: charger->chgvol = 4360000;break;
+ */
+ charger->chgvol = 4200000;
+ //}
+ return sprintf(buf, "%d\n",charger->chgvol);
+}
+
+static ssize_t chgmicrovol_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t tmp, val;
+ var = simple_strtoul(buf, NULL, 10);
+ switch(var){
+ case 4100000:tmp = 0;break;
+ case 4150000:tmp = 1;break;
+ case 4200000:tmp = 2;break;
+ case 4360000:tmp = 3;break;
+ default: tmp = 4;break;
+ }
+ if(tmp < 4){
+ charger->chgvol = var;
+ //axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ val &= 0x9F;
+ val |= tmp << 5;
+ //axp_write(charger->master, AXP15_CHARGE_CONTROL1, val);
+ }
+ return count;
+}
+
+static ssize_t chgintmicrocur_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ /*uint8_t val;
+ axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ charger->chgcur = (val & 0x0F) * 100000 +300000;
+ */
+ charger->chgcur = 300000;
+ return sprintf(buf, "%d\n",charger->chgcur);
+}
+
+static ssize_t chgintmicrocur_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t val,tmp;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var >= 300000 && var <= 1800000){
+ tmp = (var -200001)/100000;
+ charger->chgcur = tmp *100000 + 300000;
+ //axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ val &= 0xF0;
+ val |= tmp;
+ //axp_write(charger->master, AXP15_CHARGE_CONTROL1, val);
+ }
+ return count;
+}
+
+static ssize_t chgendcur_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ /*uint8_t val;
+ axp_read(charger->master, AXP15_CHARGE_CONTROL1, &val);
+ charger->chgend = ((val >> 4)& 0x01)? 15 : 10;
+ */
+ charger->chgend = 10;
+ return sprintf(buf, "%d\n",charger->chgend);
+}
+
+static ssize_t chgendcur_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var == 10 ){
+ charger->chgend = var;
+ //axp_clr_bits(charger->master ,AXP15_CHARGE_CONTROL1,0x10);
+ }
+ else if (var == 15){
+ charger->chgend = var;
+ // axp_set_bits(charger->master ,AXP15_CHARGE_CONTROL1,0x10);
+
+ }
+ return count;
+}
+
+static ssize_t chgpretimemin_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ /* uint8_t val;
+ axp_read(charger->master,AXP15_CHARGE_CONTROL2, &val);
+ charger->chgpretime = (val >> 6) * 10 +40;
+ */
+ charger->chgpretime = 40;
+ return sprintf(buf, "%d\n",charger->chgpretime);
+}
+
+static ssize_t chgpretimemin_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t tmp,val;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var >= 40 && var <= 70){
+ tmp = (var - 40)/10;
+ charger->chgpretime = tmp * 10 + 40;
+ //axp_read(charger->master,AXP15_CHARGE_CONTROL2,&val);
+ val &= 0x3F;
+ val |= (tmp << 6);
+ //axp_write(charger->master,AXP15_CHARGE_CONTROL2,val);
+ }
+ return count;
+}
+
+static ssize_t chgcsttimemin_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ //uint8_t val;
+ //axp_read(charger->master,AXP15_CHARGE_CONTROL2, &val);
+ //charger->chgcsttime = (val & 0x03) *120 + 360;
+ charger->chgcsttime = 360;
+ return sprintf(buf, "%d\n",charger->chgcsttime);
+}
+
+static ssize_t chgcsttimemin_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t tmp,val;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var >= 360 && var <= 720){
+ tmp = (var - 360)/120;
+ charger->chgcsttime = tmp * 120 + 360;
+ //axp_read(charger->master,AXP15_CHARGE_CONTROL2,&val);
+ val &= 0xFC;
+ val |= tmp;
+ //axp_write(charger->master,AXP15_CHARGE_CONTROL2,val);
+ }
+ return count;
+}
+
+static ssize_t adcfreq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ /*uint8_t val;
+ axp_read(charger->master, AXP15_ADC_CONTROL3, &val);
+ switch ((val >> 6) & 0x03){
+ case 0: charger->sample_time = 25;break;
+ case 1: charger->sample_time = 50;break;
+ case 2: charger->sample_time = 100;break;
+ case 3: charger->sample_time = 200;break;
+ default:break;
+ }
+ */
+ charger->sample_time = 25;
+ return sprintf(buf, "%d\n",charger->sample_time);
+}
+
+static ssize_t adcfreq_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t val;
+ var = simple_strtoul(buf, NULL, 10);
+ //axp_read(charger->master, AXP15_ADC_CONTROL3, &val);
+ switch (var/25){
+ case 1: val &= ~(3 << 6);charger->sample_time = 25;break;
+ case 2: val &= ~(3 << 6);val |= 1 << 6;charger->sample_time = 50;break;
+ case 4: val &= ~(3 << 6);val |= 2 << 6;charger->sample_time = 100;break;
+ case 8: val |= 3 << 6;charger->sample_time = 200;break;
+ default: break;
+ }
+ //axp_write(charger->master, AXP15_ADC_CONTROL3, val);
+ return count;
+}
+
+
+static ssize_t vholden_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ uint8_t val;
+ //axp_read(charger->master,AXP15_CHARGE_VBUS, &val);
+ //val = (val>>6) & 0x01;
+ val = 0x01;
+ return sprintf(buf, "%d\n",val);
+}
+
+static ssize_t vholden_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+/*
+ if(var)
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ */
+
+ return count;
+}
+
+static ssize_t vhold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ uint8_t val;
+ int vhold;
+ //axp_read(charger->master,AXP15_CHARGE_VBUS, &val);
+ //vhold = ((val >> 3) & 0x07) * 100000 + 4000000;
+ vhold = 4000000;
+ return sprintf(buf, "%d\n",vhold);
+}
+
+static ssize_t vhold_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ uint8_t val,tmp;
+ var = simple_strtoul(buf, NULL, 10);
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ //printk("tmp = 0x%x\n",tmp);
+ //axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ //printk("val = 0x%x\n",val);
+ //axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ return count;
+}
+
+static ssize_t iholden_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ uint8_t val = 1;
+ //axp_read(charger->master,AXP15_CHARGE_VBUS, &val);
+ return sprintf(buf, "%d\n",((val & 0x03) == 0x03)?0:1);
+}
+
+static ssize_t iholden_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+ /*
+ if(var)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+*/
+ return count;
+}
+
+static ssize_t ihold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ uint8_t val,tmp;
+ int ihold;
+ /*
+ axp_read(charger->master,AXP15_CHARGE_VBUS, &val);
+ tmp = (val) & 0x03;
+ switch(tmp){
+ case 0: ihold = 900000;break;
+ case 1: ihold = 500000;break;
+ case 2: ihold = 100000;break;
+ default: ihold = 0;break;
+ }
+ */
+ ihold = 900000;
+ return sprintf(buf, "%d\n",ihold);
+}
+
+static ssize_t ihold_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct axp_charger *charger = dev_get_drvdata(dev);
+ int var;
+ var = simple_strtoul(buf, NULL, 10);
+ /*
+ if(var == 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if (var == 500000){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if (var == 100000){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+*/
+ return count;
+}
+
+static struct device_attribute axp_charger_attrs[] = {
+ AXP_CHG_ATTR(chgen),
+ AXP_CHG_ATTR(chgmicrovol),
+ AXP_CHG_ATTR(chgintmicrocur),
+ AXP_CHG_ATTR(chgendcur),
+ AXP_CHG_ATTR(chgpretimemin),
+ AXP_CHG_ATTR(chgcsttimemin),
+ AXP_CHG_ATTR(adcfreq),
+ AXP_CHG_ATTR(vholden),
+ AXP_CHG_ATTR(vhold),
+ AXP_CHG_ATTR(iholden),
+ AXP_CHG_ATTR(ihold),
+};
+
+#if defined CONFIG_HAS_EARLYSUSPEND
+static void axp_earlysuspend(struct early_suspend *h)
+{
+ uint8_t tmp;
+ DBG_PSY_MSG("======early suspend=======\n");
+
+#if defined (CONFIG_AXP_CHGCHANGE)
+ early_suspend_flag = 1;
+/* if(pmu_earlysuspend_chgcur == 0)
+ axp_clr_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ else
+ axp_set_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+
+ if(pmu_earlysuspend_chgcur >= 300000 && pmu_earlysuspend_chgcur <= 1800000){
+ tmp = (pmu_earlysuspend_chgcur -200001)/100000;
+ axp_update(axp_charger->master, AXP15_CHARGE_CONTROL1, tmp,0x0F);
+ }
+*/
+
+#endif
+
+}
+static void axp_lateresume(struct early_suspend *h)
+{
+ uint8_t tmp;
+ DBG_PSY_MSG("======late resume=======\n");
+
+#if defined (CONFIG_AXP_CHGCHANGE)
+ early_suspend_flag = 0;
+/*
+ if(pmu_resume_chgcur == 0)
+ axp_clr_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ else
+ axp_set_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+
+ if(pmu_resume_chgcur >= 300000 && pmu_resume_chgcur <= 1800000){
+ tmp = (pmu_resume_chgcur -200001)/100000;
+ axp_update(axp_charger->master, AXP15_CHARGE_CONTROL1, tmp,0x0F);
+ }
+*/
+#endif
+
+}
+#endif
+
+int axp_charger_create_attrs(struct power_supply *psy)
+{
+ int j,ret;
+ for (j = 0; j < ARRAY_SIZE(axp_charger_attrs); j++) {
+ ret = device_create_file(psy->dev,
+ &axp_charger_attrs[j]);
+ if (ret)
+ goto sysfs_failed;
+ }
+ goto succeed;
+
+sysfs_failed:
+ while (j--)
+ device_remove_file(psy->dev,
+ &axp_charger_attrs[j]);
+succeed:
+ return ret;
+}
+
+int Get_Bat_Coulomb_Count(struct axp_charger *charger)
+{
+/*
+ uint8_t temp[8];
+ int64_t rValue1,rValue2,rValue;
+ int Cur_CoulombCounter_tmp,m;
+
+ axp_reads(charger->master, AXP15_CCHAR3_RES,8,temp);
+ rValue1 = ((temp[0] << 24) + (temp[1] << 16) + (temp[2] << 8) + temp[3]);
+ rValue2 = ((temp[4] << 24) + (temp[5] << 16) + (temp[6] << 8) + temp[7]);
+ if(axp_debug){
+ DBG_PSY_MSG("%s->%d - CHARGINGOULB:[0]=0x%x,[1]=0x%x,[2]=0x%x,[3]=0x%x\n",__FUNCTION__,__LINE__,temp[0],temp[1],temp[2],temp[3]);
+ DBG_PSY_MSG("%s->%d - DISCHARGINGCLOUB:[4]=0x%x,[5]=0x%x,[6]=0x%x,[7]=0x%x\n",__FUNCTION__,__LINE__,temp[4],temp[5],temp[6],temp[7]);
+ }
+ rValue = (ABS(rValue1 - rValue2)) * 4369;
+ m = ADC_Freq_Get(charger) * 480;
+ do_div(rValue,m);
+ if(rValue1 >= rValue2)
+ Cur_CoulombCounter_tmp = (int)rValue;
+ else
+ Cur_CoulombCounter_tmp = (int)(0 - rValue);
+ if(axp_debug){
+ DBG_PSY_MSG("Cur_CoulombCounter_tmp = %d\n",Cur_CoulombCounter_tmp);
+ }
+ */
+ return 1000; //unit mAh
+}
+
+static void axp_usb(struct work_struct *work)
+{
+/*
+ int var;
+ uint8_t tmp,val;
+ struct axp_charger *charger;
+
+ charger = axp_charger;
+
+ if(axp_usbcurflag){
+ printk("set usbcur %d mA\n",pmu_usbcurnew);
+ if(pmu_usbcurnew){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ var = pmu_usbcurnew * 1000;
+ if(var >= 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if ((var >= 500000)&& (var < 900000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if ((var >= 100000)&& (var < 500000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+ else{
+ printk("set usb limit current error,%d mA\n",pmu_usbcurnew);
+ }
+ }
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ }else {
+ printk("set usbcur %d mA\n",pmu_usbcur);
+ if((pmu_usbcur) && (pmu_usbcur_limit)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ var = pmu_usbcur * 1000;
+ if(var >= 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if ((var >= 500000)&& (var < 900000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if ((var >= 100000)&& (var < 500000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+ else
+ printk("set usb limit current error,%d mA\n",pmu_usbcur);
+ }
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ }
+
+ if(axp_usbvolflag){
+ printk("set usbvol %d mV\n",pmu_usbvolnew);
+ if(pmu_usbvolnew){
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ var = pmu_usbvolnew * 1000;
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ else
+ printk("set usb limit voltage error,%d mV\n",pmu_usbvolnew);
+ }
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ }else {
+ printk("set usbvol %d mV\n",pmu_usbvol);
+ if((pmu_usbvol) && (pmu_usbvol_limit)){
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ var = pmu_usbvol * 1000;
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ else
+ printk("set usb limit voltage error,%d mV\n",pmu_usbvol);
+ }
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ }
+*/
+}
+
+static void axp_charging_monitor(struct work_struct *work)
+{
+ struct axp_charger *charger;
+
+ uint8_t val;
+ uint8_t v[5];
+ int pre_rest_vol;
+ int rdc,k,i;
+ int rt_rest_vol;
+ int rest_vol;
+ uint16_t tmp;
+ int Cur_CoulombCounter;
+ int cap_index_p = 0;
+ int gpio_adp_val,ret;
+ /*
+
+ charger = container_of(work, struct axp_charger,
work.work);
+
+ Cur_CoulombCounter = ABS(Get_Bat_Coulomb_Count(charger));
+ if(axp_debug){
+ DBG_PSY_MSG("Cur_CoulombCounter = %d\n",Cur_CoulombCounter);
+ }
+ axp_reads(charger->master,0xbc,2,v);
+ charger->ocv = ((v[0] << 4) + (v[1] & 0x0f)) * 11 /10 ;
+ axp_reads(charger->master,AXP15_IC_TYPE,2,v);
+ //DBG_PSY_MSG("v[0] = 0x%x,v[1] = 0x%x\n",v[0],v[1]);
+ pre_rest_vol = charger->rest_vol;
+ axp_charger_update_state(charger);
+ axp_charger_update(charger);
+
+ if(charger->is_on && axp15_icharge_to_mA(charger->adc->ichar_res) > 200 && charger->vbat > 3600 && charger->disvbat != 0){
+ if((((v[1] >> 7) == 0) || (((v[1] >> 3) & 0x1) == 0)) && count_rdc >= 3){
+ axp_set_bits(charger->master,AXP15_CAP,0x80);
+ axp_clr_bits(charger->master,0xBA,0x80);
+ rdc = (axp_get_rdc(charger) * 10000 + 5371) / 10742;
+ tmp = (uint16_t) rdc;
+ axp_write(charger->master,0xBB,tmp & 0x00FF);
+ axp_update(charger->master, 0xBA, (tmp >> 8), 0x1F);
+ axp_clr_bits(charger->master,AXP15_CAP,0x80);
+ axp_set_bits(charger->master,0x04,0x80);
+ if(axp_debug){
+ DBG_PSY_MSG("==============================rdc = %d\n",rdc * 10742 / 10000);
+ }
+ count_rdc = 0;
+ }
+ else if((((v[1] >> 7) == 0) || (((v[1] >> 3) & 0x1) == 0)) && count_rdc < 3){
+ count_rdc ++;
+ }
+ else{
+ count_rdc = 0;
+ }
+ }
+ else{
+ count_rdc = 0;
+ }
+
+ if(flag_state_change){
+ rt_rest_vol = charger->rest_vol;
+ rest_vol = charger->rest_vol;
+ flag_state_change = 0;
+ }
+ else{
+ axp_read(charger->master, AXP15_CAP,&val);
+ rt_rest_vol = (int) (val & 0x7F);
+ if((charger->bat_det == 0) || (rt_rest_vol == 127) ){
+ rt_rest_vol = 100;
+ }
+
+ Total_Cap -= Bat_Cap_Buffer[Cap_Index];
+ if(Cap_Index == 0){
+ cap_index_p = AXP15_VOL_MAX - 1;
+ }
+ else{
+ cap_index_p = Cap_Index - 1;
+ }
+ if(ABS(rt_rest_vol - Bat_Cap_Buffer[cap_index_p]) > 5){
+ if(axp_debug){
+ DBG_PSY_MSG("-----------correct rdc-----------\n");
+ }
+ axp_clr_bits(charger->master,0x04,0x08);
+ }
+
+ Bat_Cap_Buffer[Cap_Index] = rt_rest_vol;
+ Total_Cap += Bat_Cap_Buffer[Cap_Index];
+ Cap_Index++;
+ if(Cap_Index == AXP15_VOL_MAX){
+ Cap_Index = 0;
+ }
+
+ rest_vol = (Total_Cap + AXP15_VOL_MAX / 2 ) / AXP15_VOL_MAX;
+ if(axp_debug){
+ DBG_PSY_MSG("Before Modify:Cap_Index = %d,val = 0x%x,pre_rest_vol = %d,rest_vol = %d\n",Cap_Index,val,pre_rest_vol,rest_vol);
+ }
+
+ if(charger->is_on && (rest_vol < pre_rest_vol)){
+ rest_vol = pre_rest_vol;
+ }
+ else if(!charger->ext_valid && (rest_vol > pre_rest_vol)){
+ rest_vol = pre_rest_vol;
+ }
+ if(axp_debug){
+ DBG_PSY_MSG("After Modify:val = 0x%x,pre_rest_vol = %d,rest_vol = %d\n",val,pre_rest_vol,rest_vol);
+ }
+ // full
+ if(charger->ocv >= 4100 && !charger->is_on && charger->ext_valid && charger->charge_on){
+ rest_vol = 100;
+ for(k = 0;k < AXP15_VOL_MAX; k++){
+ Bat_Cap_Buffer[k] = rest_vol;
+ }
+ Total_Cap = rest_vol * AXP15_VOL_MAX;
+ charger->bat_current_direction = 1;
+// if(charger->rest_vol < 100)
+// axp_set_bits(charger->master,0x32,0x38);
+ }
+
+ // charging
+ if(charger->is_on && rest_vol == 100){
+ rest_vol = 99;
+ }
+
+
+ if(rest_vol > pre_rest_vol){
+ if(counter >= 3){
+ charger->rest_vol ++;
+ counter = 0;
+ } else
+ counter ++;
+ } else if(rest_vol < pre_rest_vol){
+ if(counter >= 3){
+ charger->rest_vol --;
+ counter = 0;
+ } else
+ counter ++;
+ } else
+ counter = 0;
+ }
+
+ if((count_dis >= 8) && (charger->disvbat != 0)){
+ charger->disvbat = 0;
+ charger->disibat = 0;
+ count_dis = 0;
+ }
+ if(charger->bat_current_direction == 1){
+ count_dis++;
+ } else
+ count_dis = 0;
+
+ if(axp_debug){
+#if DBG_AXP_PSY
+ for(i = 0; i < AXP15_VOL_MAX; i ++){
+ DBG_PSY_MSG("Bat_Cap_Buffer[%d] = %d,Cap_Index = %d,cap_index_p = %d\n",i,Bat_Cap_Buffer[i],Cap_Index-1,cap_index_p);
+ }
+ DBG_PSY_MSG("charger->ic_temp = %d\n",charger->ic_temp);
+ DBG_PSY_MSG("charger->vbat = %d\n",charger->vbat);
+ DBG_PSY_MSG("charger->ibat = %d\n",charger->ibat);
+ DBG_PSY_MSG("charger->vusb = %d\n",charger->vusb);
+ DBG_PSY_MSG("charger->iusb = %d\n",charger->iusb);
+ DBG_PSY_MSG("charger->vac = %d\n",charger->vac);
+ DBG_PSY_MSG("charger->iac = %d\n",charger->iac);
+ DBG_PSY_MSG("charger->ocv = %d\n",charger->ocv);
+ DBG_PSY_MSG("charger->disvbat = %d\n",charger->disvbat);
+ DBG_PSY_MSG("charger->disibat = %d\n",charger->disibat);
+ DBG_PSY_MSG("rt_rest_vol = %d\n",rt_rest_vol);
+ DBG_PSY_MSG("rest_vol = %d\n",rest_vol);
+ DBG_PSY_MSG("charger->rest_vol = %d\n",charger->rest_vol);
+ //axp_reads(charger->master,0xba,2,v);
+ //rdc = (((v[0] & 0x1F) << 8) | v[1]) * 10742 / 10000;
+ DBG_PSY_MSG("rdc = %d\n",rdc);
+ DBG_PSY_MSG("charger->is_on = %d\n",charger->is_on);
+ DBG_PSY_MSG("charger->charge_on = %d\n",charger->charge_on);
+ DBG_PSY_MSG("charger->ext_valid = %d\n",charger->ext_valid);
+ //DBG_PSY_MSG("count_dis = %d\n",count_dis);
+ //DBG_PSY_MSG("count_rdc = %d\n",count_rdc);
+#endif
+ }
+*//*
+#if defined (CONFIG_AXP_CHGCHANGE)
+ if(pmu_used2){
+ gpio_adp_val = gpio_read_one_pin_value(gpio_adp_hdle,"pmu_adpdet");
+ DBG_PSY_MSG("GPIO->H2 = %d\n",gpio_adp_val);
+ if(!gpio_adp_val){
+ ret = script_parser_fetch("pmu_para", "pmu_init_chgcur2", &pmu_init_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chgcur = INTCHGCUR / 1000;
+ }
+ pmu_init_chgcur = pmu_init_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_earlysuspend_chgcur2", &pmu_earlysuspend_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_earlysuspend_chgcur = SUSCHGCUR / 1000;
+ }
+ pmu_earlysuspend_chgcur = pmu_earlysuspend_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_suspend_chgcur2", &pmu_suspend_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_suspend_chgcur = SUSCHGCUR / 1000;
+ }
+ pmu_suspend_chgcur = pmu_suspend_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_resume_chgcur2", &pmu_resume_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_resume_chgcur = RESCHGCUR / 1000;
+ }
+ pmu_resume_chgcur = pmu_resume_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_shutdown_chgcur2", &pmu_shutdown_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_shutdown_chgcur = CLSCHGCUR / 1000;
+ }
+ pmu_shutdown_chgcur = pmu_shutdown_chgcur * 1000;
+ }
+ else{
+ ret = script_parser_fetch("pmu_para", "pmu_init_chgcur", &pmu_init_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_init_chgcur = INTCHGCUR / 1000;
+ }
+ pmu_init_chgcur = pmu_init_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_earlysuspend_chgcur", &pmu_earlysuspend_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_earlysuspend_chgcur = SUSCHGCUR / 1000;
+ }
+ pmu_earlysuspend_chgcur = pmu_earlysuspend_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_suspend_chgcur", &pmu_suspend_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_suspend_chgcur = SUSCHGCUR / 1000;
+ }
+ pmu_suspend_chgcur = pmu_suspend_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_resume_chgcur", &pmu_resume_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_resume_chgcur = RESCHGCUR / 1000;
+ }
+ pmu_resume_chgcur = pmu_resume_chgcur * 1000;
+ ret = script_parser_fetch("pmu_para", "pmu_shutdown_chgcur", &pmu_shutdown_chgcur, sizeof(int));
+ if (ret){
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_shutdown_chgcur = CLSCHGCUR / 1000;
+ }
+ pmu_shutdown_chgcur = pmu_shutdown_chgcur * 1000;
+ }
+
+
+#if defined CONFIG_HAS_EARLYSUSPEND
+ if(early_suspend_flag){
+ if(pmu_earlysuspend_chgcur == 0){
+ axp_clr_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ }
+ else if(pmu_earlysuspend_chgcur >= 300000 && pmu_init_chgcur <= 1800000){
+ axp_set_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ tmp = (pmu_earlysuspend_chgcur -150001)/100000;
+ charger->chgcur = tmp *100000 + 300000;
+ axp_update(charger->master, AXP15_CHARGE_CONTROL1, tmp, 0x0F);
+ }
+ }else
+#endif
+ {
+ if(pmu_init_chgcur == 0){
+ axp_clr_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ }
+ else if (pmu_init_chgcur >= 300000 && pmu_init_chgcur <= 1800000){
+ axp_set_bits(axp_charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ tmp = (pmu_init_chgcur -150001)/100000;
+ charger->chgcur = tmp *100000 + 300000;
+ axp_update(charger->master, AXP15_CHARGE_CONTROL1, tmp, 0x0F);
+ }
+ }
+
+ }
+#endif
+ if(axp_debug){
+ DBG_PSY_MSG("pmu_init_chgcur = %d\n",pmu_init_chgcur);
+ DBG_PSY_MSG("pmu_earlysuspend_chgcur = %d\n",pmu_earlysuspend_chgcur);
+ DBG_PSY_MSG("pmu_suspend_chgcur = %d\n",pmu_suspend_chgcur);
+ DBG_PSY_MSG("pmu_resume_chgcur = %d\n",pmu_resume_chgcur);
+ DBG_PSY_MSG("pmu_shutdown_chgcur = %d\n",pmu_shutdown_chgcur);
+ }*/
+ /* if battery volume changed, inform uevent
+ if(charger->rest_vol - pre_rest_vol){
+ printk("battery vol change: %d->%d \n", pre_rest_vol, charger->rest_vol);
+ pre_rest_vol = charger->rest_vol;
+ axp_write(charger->master,AXP15_DATA_BUFFER1,charger->rest_vol | 0x80);
+ if(charger->rest_vol == 100){
+ axp_clr_bits(charger->master,0x32,0x38);
+ }*/
+ charger->rest_vol = 100;
+ power_supply_changed(&charger->batt);
+ //}
+
+ /* reschedule for the next time */
+ schedule_delayed_work(&charger->work, charger->interval);
+}
+
+static int axp_battery_probe(struct platform_device *pdev)
+{
+ struct axp_charger *charger;
+ struct axp_supply_init_data *pdata = pdev->dev.platform_data;
+ int ret,k,var;
+ uint8_t val1,val2,tmp,val;
+ uint8_t ocv_cap[31],v[2];
+ int Cur_CoulombCounter,rdc;
+
+
+
+ powerkeydev = input_allocate_device();
+ if (!powerkeydev) {
+ kfree(powerkeydev);
+ return -ENODEV;
+ }
+
+ powerkeydev->name = pdev->name;
+ powerkeydev->phys = "m1kbd/input2";
+ powerkeydev->id.bustype = BUS_HOST;
+ powerkeydev->id.vendor = 0x0001;
+ powerkeydev->id.product = 0x0001;
+ powerkeydev->id.version = 0x0100;
+ powerkeydev->open = NULL;
+ powerkeydev->close = NULL;
+ powerkeydev->dev.parent = &pdev->dev;
+
+ set_bit(EV_KEY, powerkeydev->evbit);
+ set_bit(EV_REL, powerkeydev->evbit);
+ //set_bit(EV_REP, powerkeydev->evbit);
+ set_bit(KEY_POWER, powerkeydev->keybit);
+
+ ret = input_register_device(powerkeydev);
+ if(ret) {
+ printk("Unable to Register the power key\n");
+ }
+
+ if (pdata == NULL)
+ return -EINVAL;
+
+ if (pdata->chgcur > 1800000 ||
+ pdata->chgvol < 4100000 ||
+ pdata->chgvol > 4360000){
+ printk("charger milliamp is too high or target voltage is over range\n");
+ return -EINVAL;
+ }
+
+ if (pdata->chgpretime < 40 || pdata->chgpretime >70 ||
+ pdata->chgcsttime < 360 || pdata->chgcsttime > 720){
+ printk("prechaging time or constant current charging time is over range\n");
+ return -EINVAL;
+ }
+
+ charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+ if (charger == NULL)
+ return -ENOMEM;
+
+ charger->master = pdev->dev.parent;
+
+ charger->chgcur = pdata->chgcur;
+ charger->chgvol = pdata->chgvol;
+ charger->chgend = pdata->chgend;
+ charger->sample_time = pdata->sample_time;
+ charger->chgen = pdata->chgen;
+ charger->chgpretime = pdata->chgpretime;
+ charger->chgcsttime = pdata->chgcsttime;
+ charger->battery_info = pdata->battery_info;
+ charger->disvbat = 0;
+ charger->disibat = 0;
+
+ ret = axp_battery_first_init(charger);
+ if (ret)
+ goto err_charger_init;
+
+ charger->nb.notifier_call = axp_battery_event;
+ ret = axp_register_notifier(charger->master, &charger->nb, AXP15_NOTIFIER_ON);
+ if (ret)
+ goto err_notifier;
+
+ axp_battery_setup_psy(charger);
+ ret = power_supply_register(&pdev->dev, &charger->batt);
+ if (ret)
+ goto err_ps_register;
+
+ //axp_read(charger->master,AXP15_CHARGE_STATUS,&val);
+ //if(!((val >> 1) & 0x01)){
+ ret = power_supply_register(&pdev->dev, &charger->ac);
+ if (ret){
+ power_supply_unregister(&charger->batt);
+ goto err_ps_register;
+ }
+ //}
+ ret = power_supply_register(&pdev->dev, &charger->usb);
+ if (ret){
+ power_supply_unregister(&charger->ac);
+ power_supply_unregister(&charger->batt);
+ goto err_ps_register;
+ }
+
+ ret = axp_charger_create_attrs(&charger->batt);
+ if(ret){
+ return ret;
+ }
+
+
+ platform_set_drvdata(pdev, charger);
+
+#if defined (CONFIG_AXP_CHGCHANGE)
+ if(pmu_used2){
+ gpio_adp_hdle = gpio_request_ex("pmu_para", "pmu_adpdet");
+ if (!gpio_adp_hdle)
+ {
+ DBG_PSY_MSG("get adapter parameter failed\n");
+ }
+ }
+#endif
+
+ axp_charger = charger;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ axp_early_suspend.suspend = axp_earlysuspend;
+ axp_early_suspend.resume = axp_lateresume;
+ axp_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 2;
+ register_early_suspend(&axp_early_suspend);
+#endif
+
+ /* ���Խӿ�ע�� */
+ class_register(&axppower_class);
+
+ return ret;
+
+ err_ps_register:
+ axp_unregister_notifier(charger->master, &charger->nb, AXP15_NOTIFIER_ON);
+
+ err_notifier:
+ cancel_delayed_work_sync(&charger->work);
+
+ err_charger_init:
+ kfree(charger);
+ input_unregister_device(powerkeydev);
+ kfree(powerkeydev);
+
+ return ret;
+}
+
+ /* initial restvol*/
+
+/* usb current and voltage limit
+ if((pmu_usbvol) && (pmu_usbvol_limit)){
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ var = pmu_usbvol * 1000;
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ }
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+
+ if((pmu_usbcur) && (pmu_usbcur_limit)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ var = pmu_usbcur * 1000;
+ if(var >= 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if ((var >= 500000)&& (var < 900000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if ((var >= 100000)&& (var < 500000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+ }
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+*/
+
+
+ /* set lowe power warning/shutdown voltage
+ var = script_parser_fetch("pmu_para", "pmu_suspendpwroff_vol", &pmu_suspendpwroff_vol, sizeof(int));
+ if (var)
+ {
+ printk("[AXP]axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_suspendpwroff_vol = 3500;
+ printk("[AXP]pmu_suspendpwroff_vol = %d\n",pmu_suspendpwroff_vol);
+ }
+ pmu_suspendpwroff_vol = pmu_suspendpwroff_vol * 1000;
+
+ if(pmu_suspendpwroff_vol >= 2867200 && pmu_suspendpwroff_vol <= 4200000){
+ val = (pmu_suspendpwroff_vol - 2867200) / 5600;
+ }*/
+
+ /* 3.5552V--%5 close
+ axp_write(charger->master, AXP15_APS_WARNING1,val);
+ axp_write(charger->master, AXP15_APS_WARNING2,(val - 0x0a));
+
+ ocv_cap[0] = pmu_bat_para1;
+ ocv_cap[1] = 0xC1;
+ ocv_cap[2] = pmu_bat_para2;
+ ocv_cap[3] = 0xC2;
+ ocv_cap[4] = pmu_bat_para3;
+ ocv_cap[5] = 0xC3;
+ ocv_cap[6] = pmu_bat_para4;
+ ocv_cap[7] = 0xC4;
+ ocv_cap[8] = pmu_bat_para5;
+ ocv_cap[9] = 0xC5;
+ ocv_cap[10] = pmu_bat_para6;
+ ocv_cap[11] = 0xC6;
+ ocv_cap[12] = pmu_bat_para7;
+ ocv_cap[13] = 0xC7;
+ ocv_cap[14] = pmu_bat_para8;
+ ocv_cap[15] = 0xC8;
+ ocv_cap[16] = pmu_bat_para9;
+ ocv_cap[17] = 0xC9;
+ ocv_cap[18] = pmu_bat_para10;
+ ocv_cap[19] = 0xCA;
+ ocv_cap[20] = pmu_bat_para11;
+ ocv_cap[21] = 0xCB;
+ ocv_cap[22] = pmu_bat_para12;
+ ocv_cap[23] = 0xCC;
+ ocv_cap[24] = pmu_bat_para13;
+ ocv_cap[25] = 0xCD;
+ ocv_cap[26] = pmu_bat_para14;
+ ocv_cap[27] = 0xCE;
+ ocv_cap[28] = pmu_bat_para15;
+ ocv_cap[29] = 0xCF;
+ ocv_cap[30] = pmu_bat_para16;
+ axp_writes(charger->master, 0xC0,31,ocv_cap);*/
+
+ /* open/close set
+ printk("pmu_pekoff_time = %d\n",pmu_pekoff_time);
+ printk("pmu_pekoff_en = %d\n",pmu_pekoff_en);
+ printk("pmu_peklong_time = %d\n",pmu_peklong_time);
+ printk("pmu_pekon_time = %d\n",pmu_pekon_time);
+ printk("pmu_pwrok_time = %d\n",pmu_pwrok_time);
+ printk("pmu_pwrnoe_time = %d\n",pmu_pwrnoe_time);
+ printk("pmu_intotp_en = %d\n",pmu_intotp_en);*/
+
+ /* //n_oe delay time set
+ if (pmu_pwrnoe_time < 1000)
+ pmu_pwrnoe_time = 128;
+ if (pmu_pwrnoe_time > 3000)
+ pmu_pwrnoe_time = 3000;
+ axp_read(charger->master,POWER15_OFF_CTL,&val);
+ val &= 0xfc;
+ val |= ((pmu_pwrnoe_time) / 1000);
+ axp_write(charger->master,POWER15_OFF_CTL,val);
+ DBG_PSY_MSG("%d-->0x%x\n",__LINE__,val);
+
+ // pek open time set
+ axp_read(charger->master,POWER15_PEK_SET,&val);
+ if (pmu_pekon_time < 1000)
+ val &= 0x3f;
+ else if(pmu_pekon_time < 2000){
+ val &= 0x3f;
+ val |= 0x80;
+ }
+ else if(pmu_pekon_time < 3000){
+ val &= 0x3f;
+ val |= 0xc0;
+ }
+ else {
+ val &= 0x3f;
+ val |= 0x40;
+ }
+ axp_write(charger->master,POWER15_PEK_SET,val);
+ printk("POWER15_PEK_SET:%d-->0x%x\n",__LINE__,val);
+
+ // pek long time set
+ if(pmu_peklong_time < 1000)
+ pmu_peklong_time = 1000;
+ if(pmu_peklong_time > 2500)
+ pmu_peklong_time = 2500;
+ axp_read(charger->master,POWER15_PEK_SET,&val);
+ val &= 0xcf;
+ val |= (((pmu_peklong_time - 1000) / 500) << 4);
+ axp_write(charger->master,POWER15_PEK_SET,val);
+ printk("POWER15_PEK_SET:%d-->0x%x\n",__LINE__,val);
+
+ // pek en set
+ if(pmu_pekoff_en)
+ pmu_pekoff_en = 1;
+ axp_read(charger->master,POWER15_PEK_SET,&val);
+ val &= 0xf7;
+ val |= (pmu_pekoff_en << 3);
+ axp_write(charger->master,POWER15_PEK_SET,val);
+ printk("POWER15_PEK_SET:%d-->0x%x\n",__LINE__,val);
+
+ // pek delay set
+ if(pmu_pwrok_time <= 8)
+ pmu_pwrok_time = 0;
+ else
+ pmu_pwrok_time = 1;
+ axp_read(charger->master,POWER15_PEK_SET,&val);
+ val &= 0xfb;
+ val |= pmu_pwrok_time << 2;
+ axp_write(charger->master,POWER15_PEK_SET,val);
+ printk("POWER15_PEK_SET:%d-->0x%x\n",__LINE__,val);
+
+ // pek off time set
+ if(pmu_pekoff_time < 4000)
+ pmu_pekoff_time = 4000;
+ if(pmu_pekoff_time > 10000)
+ pmu_pekoff_time =10000;
+ pmu_pekoff_time = (pmu_pekoff_time - 4000) / 2000 ;
+ axp_read(charger->master,POWER15_PEK_SET,&val);
+ val &= 0xfc;
+ val |= pmu_pekoff_time ;
+ axp_write(charger->master,POWER15_PEK_SET,val);
+ printk("POWER15_PEK_SET:%d-->0x%x\n",__LINE__,val);
+
+ // enable overtemperture off
+ if(pmu_intotp_en)
+ pmu_intotp_en = 1;
+ axp_read(charger->master,POWER15_HOTOVER_CTL,&val);
+ val &= 0xfb;
+ val |= pmu_intotp_en << 2;
+ axp_write(charger->master,POWER15_HOTOVER_CTL,val);
+ printk("POWER15_HOTOVER_CTL:%d-->0x%x\n",__LINE__,val);
+
+ // disable
+ axp_set_bits(charger->master,AXP15_CAP,0x80);
+ axp_clr_bits(charger->master,0xBA,0x80);
+ axp_reads(charger->master,0xbA,2,v);
+ rdc = (((v[0] & 0x1F) << 8) | v[1]) * 10742 / 10000;
+ axp_read(charger->master,AXP15_DATA_BUFFER0,&val1);
+ if((((val1 >> 7) & 0x1) == 0)||(rdc > pmu_battery_rdc * 2)){
+ rdc = (pmu_battery_rdc * 10000 + 5371) / 10742;
+ axp_write(charger->master,0xBB,rdc & 0x00FF);
+ axp_update(charger->master, 0xBA, (rdc >> 8), 0x1F);
+ }
+ axp_clr_bits(charger->master,AXP15_CAP,0x80);
+
+ axp_set_bits(charger->master,0x8F,0x88);
+ axp_clr_bits(charger->master,0x81,0x04);
+
+ axp_charger_update_state(charger);
+ axp_charger_update(charger);
+
+ axp_read(charger->master,AXP15_DATA_BUFFER1,&val1);
+ charger->rest_vol = (int) (val1 & 0x7F);
+
+ axp_read(charger->master, AXP15_CAP,&val2);
+
+ Cur_CoulombCounter = ABS(Get_Bat_Coulomb_Count(charger));
+ printk("Cur_CoulombCounter = %d\n",Cur_CoulombCounter);
+ //if(ABS(charger->rest_vol-(val2 & 0x7F)) >= 3 && (val1 >> 7)){
+ if((!(val1 >> 7))|| ABS(charger->rest_vol-(val2 & 0x7F)) >= 10 || Cur_CoulombCounter > 20){
+ charger->rest_vol = (val2 & 0x7F)? (val2 & 0x7F): 1;
+ }
+ if((charger->bat_det == 0) || (charger->rest_vol == 127)){
+ charger->rest_vol = 100;
+ }
+ if(((charger->vbat) >= 4100) && !charger->is_on && charger->ext_valid && charger->charge_on){
+ charger->rest_vol = 100;
+ }
+
+ printk("last_rest_vol = %d, now_rest_vol = %d\n",(val1 & 0x7F),(val2 & 0x7F));
+ memset(Bat_Cap_Buffer, 0, sizeof(Bat_Cap_Buffer));
+ for(k = 0;k < AXP15_VOL_MAX; k++){
+ Bat_Cap_Buffer[k] = charger->rest_vol;
+ }
+ Total_Cap = charger->rest_vol * AXP15_VOL_MAX;
+
+ charger->interval = msecs_to_jiffies(10 * 1000);
+ INIT_DELAYED_WORK(&charger->work, axp_charging_monitor);
+ schedule_delayed_work(&charger->work, charger->interval);
+ // set usb cur-vol limit
+ INIT_DELAYED_WORK(&usbwork, axp_usb);
+ if(charger->usb_valid){
+ schedule_delayed_work(&usbwork, msecs_to_jiffies(7 * 1000));
+ }
+
+ var = script_parser_fetch("pmu_para", "pmu_used2", &pmu_used2, sizeof(int));
+ if (var)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_used2 = 0;
+ printk("pmu_used2 = %d\n",pmu_used2);
+ }
+
+ var = script_parser_fetch("pmu_para", "pmu_earlysuspend_chgcur", &pmu_earlysuspend_chgcur, sizeof(int));
+ if (var)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_earlysuspend_chgcur = pmu_suspend_chgcur / 1000;
+ printk("pmu_earlysuspend_chgcur = %d\n",pmu_earlysuspend_chgcur);
+ }
+ pmu_earlysuspend_chgcur = pmu_earlysuspend_chgcur * 1000;
+
+ var = script_parser_fetch("pmu_para", "pmu_batdeten", &pmu_batdeten, sizeof(int));
+ if (var)
+ {
+ printk("axp driver uning configuration failed(%d)\n", __LINE__);
+ pmu_batdeten = 1;
+ printk("pmu_batdeten = %d\n",pmu_batdeten);
+ }
+ if(!pmu_batdeten)
+ axp_clr_bits(charger->master,0x32,0x40);
+ else
+ axp_set_bits(charger->master,0x32,0x40);
+
+ //axp usb-pc limite
+ var = script_parser_fetch("pmu_para", "pmu_usbvol_pc", &pmu_usbvolnew, sizeof(int));
+ if (var)
+ {
+ printk("axp driver uning configuration failed-pmu_usbvol_pc\n");
+ pmu_usbvolnew = 4000;
+ printk("pmu_usbvolnew = %d\n",pmu_usbvolnew);
+ }
+ else
+ {
+ // usb current and voltage limit
+ if(pmu_usbvolnew){
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ var = pmu_usbvolnew * 1000;
+ if(var >= 4000000 && var <=4700000){
+ tmp = (var - 4000000)/100000;
+ axp_read(charger->master, AXP15_CHARGE_VBUS,&val);
+ val &= 0xC7;
+ val |= tmp << 3;
+ axp_write(charger->master, AXP15_CHARGE_VBUS,val);
+ }
+ }
+ else
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x40);
+ }
+
+ var = script_parser_fetch("pmu_para", "pmu_usbcur_pc", &pmu_usbcurnew, sizeof(int));
+ if (var)
+ {
+ printk("axp driver uning configuration failed-pmu_usbcurnew\n");
+ pmu_usbcurnew = 500;
+ printk("pmu_usbcurnew = %d\n",pmu_usbcurnew);
+ }
+ else
+ {
+ if(pmu_usbcurnew){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ var = pmu_usbcurnew * 1000;
+ if(var >= 900000)
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ else if ((var >= 500000)&& (var < 900000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ }
+ else if ((var >= 100000)&& (var < 500000)){
+ axp_clr_bits(charger->master, AXP15_CHARGE_VBUS, 0x01);
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x02);
+ }
+ }
+ else
+ axp_set_bits(charger->master, AXP15_CHARGE_VBUS, 0x03);
+ }
+
+*/
+
+//}
+
+static int axp_battery_remove(struct platform_device *dev)
+{
+ struct axp_charger *charger = platform_get_drvdata(dev);
+
+ if(main_task){
+ kthread_stop(main_task);
+ main_task = NULL;
+ }
+
+ axp_unregister_notifier(charger->master, &charger->nb, AXP15_NOTIFIER_ON);
+ cancel_delayed_work_sync(&charger->work);
+ power_supply_unregister(&charger->usb);
+ power_supply_unregister(&charger->ac);
+ power_supply_unregister(&charger->batt);
+
+ kfree(charger);
+ input_unregister_device(powerkeydev);
+ kfree(powerkeydev);
+
+ return 0;
+}
+
+
+static int axp15_suspend(struct platform_device *dev, pm_message_t state)
+{
+ uint8_t irq_w[5];
+ uint8_t tmp;
+
+ struct axp_charger *charger = platform_get_drvdata(dev);
+
+
+ cancel_delayed_work_sync(&charger->work);
+
+ /*clear all irqs events*/
+ irq_w[0] = 0xff;
+ irq_w[1] = POWER15_INTSTS2;
+ irq_w[2] = 0xff;
+ irq_w[3] = POWER15_INTSTS3;
+ irq_w[4] = 0xff;
+
+ axp_writes(charger->master, POWER15_INTSTS1, 5, irq_w);
+
+ /* close all irqs*/
+ axp_unregister_notifier(charger->master, &charger->nb, AXP15_NOTIFIER_ON);
+
+/*
+ // timer
+ axp_write(charger->master, 0x8A, 0x80);
+ axp_write(charger->master, 0x8A, 0x02);
+
+ // clear and enable coulomb
+ tmp = 0xff;
+ axp_read(charger->master, POWER15_COULOMB_CTL, &tmp);
+
+ //tmp |= 0x20;
+ tmp &= 0x3f;
+
+ axp_write(charger->master, POWER15_COULOMB_CTL, tmp);
+ tmp |= 0x80;
+ tmp &= 0xbf;
+
+ axp_write(charger->master, POWER15_COULOMB_CTL, tmp);
+*/
+ return 0;
+}
+
+static int axp15_resume(struct platform_device *dev)
+{
+ struct axp_charger *charger = platform_get_drvdata(dev);
+
+ int pre_rest_vol,k;
+ uint8_t val,val1,tmp;
+ uint8_t v[2];
+ int rt_rest_vol;
+ int Cur_CoulombCounter;
+
+ axp_register_notifier(charger->master, &charger->nb, AXP15_NOTIFIER_ON);
+
+ axp_charger_update_state(charger);
+
+
+
+ charger->rest_vol = 100;
+
+ schedule_delayed_work(&charger->work, charger->interval);
+
+ return 0;
+}
+
+static void axp15_shutdown(struct platform_device *dev)
+{
+ uint8_t tmp;
+ struct axp_charger *charger = platform_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&charger->work);
+ //axp_clr_bits(charger->master,AXP15_CAP,0x80);
+ /*
+
+#if defined (CONFIG_AXP_CHGCHANGE)
+ if(pmu_shutdown_chgcur == 0)
+ axp_clr_bits(charger->master,AXP15_CHARGE_CONTROL1,0x80);
+ else
+ axp_set_bits(charger->master,AXP15_CHARGE_CONTROL1,0x80);
+
+ printk("pmu_shutdown_chgcur = %d\n", pmu_shutdown_chgcur);
+
+ if(pmu_shutdown_chgcur >= 300000 && pmu_shutdown_chgcur <= 1800000){
+ tmp = (pmu_shutdown_chgcur -200001)/100000;
+ charger->chgcur = tmp *100000 + 300000;
+ axp_update(charger->master, AXP15_CHARGE_CONTROL1, tmp, 0x0F);
+ }
+
+#endif*/
+}
+
+static struct platform_driver axp_battery_driver = {
+ .driver = {
+ .name = "axp15-supplyer",
+ .owner = THIS_MODULE,
+ },
+ .probe = axp_battery_probe,
+ .remove = axp_battery_remove,
+ .suspend = axp15_suspend,
+ .resume = axp15_resume,
+ .shutdown = axp15_shutdown,
+};
+
+static int axp_battery_init(void)
+{
+ return platform_driver_register(&axp_battery_driver);
+}
+
+static void axp_battery_exit(void)
+{
+ platform_driver_unregister(&axp_battery_driver);
+}
+
+module_init(axp_battery_init);
+module_exit(axp_battery_exit);
+
+MODULE_DESCRIPTION("axp15 battery charger driver");
+MODULE_AUTHOR("Kyle Cheung, X-power");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/axp_power/virtual15.c b/drivers/power/axp_power/virtual15.c
new file mode 100755
index 0000000..8e9c4e4
--- /dev/null
+++ b/drivers/power/axp_power/virtual15.c
@@ -0,0 +1,427 @@
+/*
+ * reg-virtual-consumer.c
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <
bro...@opensource.wolfsonmicro.com>
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+struct virtual_consumer_data {
+ struct mutex lock;
+ struct regulator *regulator;
+ int enabled;
+ int min_uV;
+ int max_uV;
+ int min_uA;
+ int max_uA;
+ unsigned int mode;
+};
+
+static void update_voltage_constraints(struct virtual_consumer_data *data)
+{
+ int ret;
+
+ if (data->min_uV && data->max_uV
+ && data->min_uV <= data->max_uV) {
+ ret = regulator_set_voltage(data->regulator,
+ data->min_uV, data->max_uV);
+ printk("%s,line=%d,%d,%d\n",__func__,__LINE__,data->min_uV,data->max_uV);
+ if (ret != 0) {
+ printk(KERN_ERR "regulator_set_voltage() failed: %d\n",
+ ret);
+ return;
+ }
+ }
+
+ if (data->min_uV && data->max_uV && !data->enabled) {
+ ret = regulator_enable(data->regulator);
+ if (ret == 0)
+ data->enabled = 1;
+ else
+ printk(KERN_ERR "regulator_enable() failed: %d\n",
+ ret);
+ }
+
+ if (!(data->min_uV && data->max_uV) && data->enabled) {
+ ret = regulator_disable(data->regulator);
+ if (ret == 0)
+ data->enabled = 0;
+ else
+ printk(KERN_ERR "regulator_disable() failed: %d\n",
+ ret);
+ }
+}
+
+static void update_current_limit_constraints(struct virtual_consumer_data
+ *data)
+{
+ int ret;
+
+ if (data->max_uA
+ && data->min_uA <= data->max_uA) {
+ ret = regulator_set_current_limit(data->regulator,
+ data->min_uA, data->max_uA);
+ if (ret != 0) {
+ pr_err("regulator_set_current_limit() failed: %d\n",
+ ret);
+ return;
+ }
+ }
+
+ if (data->max_uA && !data->enabled) {
+ ret = regulator_enable(data->regulator);
+ if (ret == 0)
+ data->enabled = 1;
+ else
+ printk(KERN_ERR "regulator_enable() failed: %d\n",
+ ret);
+ }
+
+ if (!(data->min_uA && data->max_uA) && data->enabled) {
+ ret = regulator_disable(data->regulator);
+ if (ret == 0)
+ data->enabled = 0;
+ else
+ printk(KERN_ERR "regulator_disable() failed: %d\n",
+ ret);
+ }
+}
+
+static ssize_t show_min_uV(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return sprintf(buf, "%d\n", data->min_uV);
+}
+
+static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+printk("%s,line:%d\n", __func__, __LINE__);
+ mutex_lock(&data->lock);
+
+ data->min_uV = val;
+ update_voltage_constraints(data);
+ printk("%s,line:%d\n", __func__, __LINE__);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_max_uV(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return sprintf(buf, "%d\n", data->max_uV);
+}
+
+static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ long val;
+
+printk("%s,line:%d\n", __func__, __LINE__);
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+
+ mutex_lock(&data->lock);
+
+ data->max_uV = val;
+ update_voltage_constraints(data);
+printk("%s,line:%d\n", __func__, __LINE__);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_min_uA(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ printk("%s,line:%d\n", __func__, __LINE__);
+ return sprintf(buf, "%d\n", data->min_uA);
+}
+
+static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+printk("%s,line:%d\n", __func__, __LINE__);
+ mutex_lock(&data->lock);
+
+ data->min_uA = val;
+ update_current_limit_constraints(data);
+ printk("%s,line:%d\n", __func__, __LINE__);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_max_uA(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", data->max_uA);
+}
+
+static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ long val;
+
+ if (strict_strtol(buf, 10, &val) != 0)
+ return count;
+
+ mutex_lock(&data->lock);
+
+ data->max_uA = val;
+ update_current_limit_constraints(data);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+
+ switch (data->mode) {
+ case REGULATOR_MODE_FAST:
+ return sprintf(buf, "fast\n");
+ case REGULATOR_MODE_NORMAL:
+ return sprintf(buf, "normal\n");
+ case REGULATOR_MODE_IDLE:
+ return sprintf(buf, "idle\n");
+ case REGULATOR_MODE_STANDBY:
+ return sprintf(buf, "standby\n");
+ default:
+ return sprintf(buf, "unknown\n");
+ }
+}
+
+static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct virtual_consumer_data *data = dev_get_drvdata(dev);
+ unsigned int mode;
+ int ret;
+
+ if (strncmp(buf, "fast", strlen("fast")) == 0)
+ mode = REGULATOR_MODE_FAST;
+ else if (strncmp(buf, "normal", strlen("normal")) == 0)
+ mode = REGULATOR_MODE_NORMAL;
+ else if (strncmp(buf, "idle", strlen("idle")) == 0)
+ mode = REGULATOR_MODE_IDLE;
+ else if (strncmp(buf, "standby", strlen("standby")) == 0)
+ mode = REGULATOR_MODE_STANDBY;
+ else {
+ dev_err(dev, "Configuring invalid mode\n");
+ return count;
+ }
+
+ mutex_lock(&data->lock);
+ ret = regulator_set_mode(data->regulator, mode);
+ if (ret == 0)
+ data->mode = mode;
+ else
+ dev_err(dev, "Failed to configure mode: %d\n", ret);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV);
+static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV);
+static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
+static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
+static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
+
+struct device_attribute *attributes_virtual[] = {
+ &dev_attr_min_microvolts,
+ &dev_attr_max_microvolts,
+ &dev_attr_min_microamps,
+ &dev_attr_max_microamps,
+ &dev_attr_mode,
+};
+
+static int regulator_virtual_consumer_probe(struct platform_device *pdev)
+{
+ char *reg_id = pdev->dev.platform_data;
+ struct virtual_consumer_data *drvdata;
+ int ret, i;
+
+ drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
+ if (drvdata == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ mutex_init(&drvdata->lock);
+
+ //drvdata->regulator = regulator_get(&pdev->dev, reg_id);
+ drvdata->regulator = regulator_get(NULL, reg_id);
+ //drvdata->regulator = regulator_get(NULL, "axp20_analog/fm");
+ if (IS_ERR(drvdata->regulator)) {
+ ret = PTR_ERR(drvdata->regulator);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(attributes_virtual); i++) {
+ ret = device_create_file(&pdev->dev, attributes_virtual[i]);
+ if (ret != 0)
+ goto err;
+ }
+
+ drvdata->mode = regulator_get_mode(drvdata->regulator);
+
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0;
+
+err:
+ for (i = 0; i < ARRAY_SIZE(attributes_virtual); i++)
+ device_remove_file(&pdev->dev, attributes_virtual[i]);
+ kfree(drvdata);
+ return ret;
+}
+
+static int regulator_virtual_consumer_remove(struct platform_device *pdev)
+{
+ struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(attributes_virtual); i++)
+ device_remove_file(&pdev->dev, attributes_virtual[i]);
+ if (drvdata->enabled)
+ regulator_disable(drvdata->regulator);
+ regulator_put(drvdata->regulator);
+
+ kfree(drvdata);
+
+ return 0;
+}
+
+static struct platform_driver regulator_virtual_consumer_driver[] = {
+ {
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-aldo1",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-aldo2",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-dldo1",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-dldo2",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-ldoio0",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-gpiodldo",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-buck1",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-buck2",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-buck3",
+ },
+ },{
+ .probe = regulator_virtual_consumer_probe,
+ .remove = regulator_virtual_consumer_remove,
+ .driver = {
+ .name = "reg-15-cs-buck4",
+ },
+ },
+};
+
+
+static int __init regulator_virtual_consumer_init(void)
+{
+ int j,ret;
+ for (j = 0; j < ARRAY_SIZE(regulator_virtual_consumer_driver); j++){
+ ret = platform_driver_register(®ulator_virtual_consumer_driver[j]);
+ if (ret)
+ goto creat_drivers_failed;
+ }
+ return ret;
+
+creat_drivers_failed:
+ while (j--)
+ platform_driver_unregister(®ulator_virtual_consumer_driver[j]);
+ return ret;
+}
+module_init(regulator_virtual_consumer_init);
+
+static void __exit regulator_virtual_consumer_exit(void)
+{
+ int j;
+ for (j = ARRAY_SIZE(regulator_virtual_consumer_driver) - 1; j >= 0; j--){
+ platform_driver_unregister(®ulator_virtual_consumer_driver[j]);
+ }
+}
+module_exit(regulator_virtual_consumer_exit);
+
+MODULE_AUTHOR("Kyle Cheung");
+MODULE_DESCRIPTION("Virtual regulator consumer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/axp_power/virtual15_dev.c b/drivers/power/axp_power/virtual15_dev.c
new file mode 100755
index 0000000..4c63043
--- /dev/null
+++ b/drivers/power/axp_power/virtual15_dev.c
@@ -0,0 +1,125 @@
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <mach/irqs.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/axp-mfd.h>
+
+
+#include "axp-cfg.h"
+
+
+static struct platform_device virt[]={
+
+ {
+ .name = "reg-15-cs-ldo0",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_ldo0",
+ }
+
+ },{
+ .name = "reg-15-cs-rtcldo",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_rtc",
+ }
+ },{
+ .name = "reg-15-cs-aldo1",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_analog/fm",
+ }
+ },{
+ .name = "reg-15-cs-aldo2",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_analog/fm2",
+ }
+ },{
+ .name = "reg-15-cs-dldo1",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_pll/sdram",
+ }
+ },{
+ .name = "reg-15-cs-dldo2",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_pll/hdmi",
+ }
+ },{
+ .name = "reg-15-cs-gpioldo",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_gpio",
+ }
+ },{
+ .name = "reg-15-cs-buck1",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_io",
+ }
+ },{
+ .name = "reg-15-cs-buck2",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_core",
+ }
+ },{
+ .name = "reg-15-cs-buck3",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_ddr",
+ }
+ },{
+ .name = "reg-15-cs-buck4",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_ddr2",
+ }
+ },{
+ .name = "reg-15-cs-ldoio0",
+ .id = -1,
+ .dev = {
+ .platform_data = "axp15_mic",
+ }
+ },
+};
+
+
+
+ static int __init virtual_init(void)
+{
+ int j,ret;
+ for (j = 0; j < ARRAY_SIZE(virt); j++){
+ ret = platform_device_register(&virt[j]);
+ if (ret)
+ goto creat_devices_failed;
+ }
+
+ return ret;
+
+creat_devices_failed:
+ while (j--)
+ platform_device_register(&virt[j]);
+ return ret;
+
+}
+
+module_init(virtual_init);
+
+static void __exit virtual_exit(void)
+{
+ int j;
+ for (j = ARRAY_SIZE(virt) - 1; j >= 0; j--){
+ platform_device_unregister(&virt[j]);
+ }
+}
+module_exit(virtual_exit);
+
+MODULE_DESCRIPTION("Axp regulator test");
+MODULE_AUTHOR("Kyle Cheung");
+MODULE_LICENSE("GPL");
\ No newline at end of file
--
1.8.1