From 476cbef83038d42fe34a22376ac7a5af3afe619f Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Fri, 22 Aug 2014 10:01:21 +0800 Subject: [PATCH] rk312x:rt5025:support pmic rt5025 --- .../devicetree/bindings/mfd/rt5025.txt | 74 + .../bindings/power/rt5025-battery.txt | 14 + .../bindings/power/rt5025-charger.txt | 41 + .../bindings/regulator/rt5025-regulator.txt | 27 + arch/arm/boot/dts/rk312x-sdk.dtsi | 105 + arch/arm/boot/dts/rt5025.dtsi | 113 + drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/{rt5025-gpio.c => gpio-rt5025.c} | 183 +- drivers/mfd/Kconfig | 36 + drivers/mfd/Makefile | 5 + drivers/mfd/rt5025-core.c | 201 +- drivers/mfd/rt5025-debug.c | 220 +- drivers/mfd/rt5025-i2c.c | 246 +- drivers/mfd/rt5025-irq.c | 410 +-- drivers/mfd/rt5025-misc.c | 294 +- drivers/power/Kconfig | 37 + drivers/power/Makefile | 3 + drivers/power/rt-power.c | 407 +++ drivers/power/rt5025-battery.c | 2470 +++++++++-------- drivers/power/rt5025-charger.c | 1224 ++++++++ drivers/power/rt5025-power.c | 0 drivers/power/rt5025-swjeita.c | 328 ++- drivers/regulator/Kconfig | 7 + drivers/regulator/Makefile | 1 + drivers/regulator/rt5025-regulator.c | 287 +- include/linux/mfd/rt5025-gpio.h | 17 +- include/linux/mfd/rt5025-irq.h | 30 +- include/linux/mfd/rt5025-misc.h | 37 +- include/linux/mfd/rt5025.h | 848 +++--- include/linux/power/rockchip-general-bat.h | 40 +- include/linux/power/rt-power.h | 27 + include/linux/power/rt5025-battery.h | 125 +- include/linux/power/rt5025-charger.h | 86 + include/linux/regulator/rt5025-regulator.h | 123 +- 35 files changed, 5116 insertions(+), 2958 deletions(-) create mode 100755 Documentation/devicetree/bindings/mfd/rt5025.txt create mode 100755 Documentation/devicetree/bindings/power/rt5025-battery.txt create mode 100755 Documentation/devicetree/bindings/power/rt5025-charger.txt create mode 100755 Documentation/devicetree/bindings/regulator/rt5025-regulator.txt create mode 100755 arch/arm/boot/dts/rt5025.dtsi rename drivers/gpio/{rt5025-gpio.c => gpio-rt5025.c} (55%) mode change 100644 => 100755 drivers/mfd/rt5025-core.c mode change 100644 => 100755 drivers/mfd/rt5025-debug.c mode change 100644 => 100755 drivers/mfd/rt5025-i2c.c mode change 100644 => 100755 drivers/mfd/rt5025-irq.c mode change 100644 => 100755 drivers/mfd/rt5025-misc.c create mode 100755 drivers/power/rt-power.c mode change 100644 => 100755 drivers/power/rt5025-battery.c create mode 100755 drivers/power/rt5025-charger.c mode change 100644 => 100755 drivers/power/rt5025-power.c mode change 100644 => 100755 drivers/power/rt5025-swjeita.c mode change 100644 => 100755 include/linux/mfd/rt5025-irq.h mode change 100644 => 100755 include/linux/mfd/rt5025-misc.h mode change 100644 => 100755 include/linux/mfd/rt5025.h create mode 100755 include/linux/power/rt-power.h mode change 100644 => 100755 include/linux/power/rt5025-battery.h create mode 100755 include/linux/power/rt5025-charger.h mode change 100644 => 100755 include/linux/regulator/rt5025-regulator.h diff --git a/Documentation/devicetree/bindings/mfd/rt5025.txt b/Documentation/devicetree/bindings/mfd/rt5025.txt new file mode 100755 index 000000000000..8b0865fd4e32 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rt5025.txt @@ -0,0 +1,74 @@ +Richtek RT5025 Multi-functional device + +The RT5025 are Integrated Power Management Chips. +These chips are connected to an i2c bus. + + +Required properties: +- compatible : Must be "rt,rt5025"; +- interrupts : This i2c device has an IRQ line connected to the main SoC +- interrupt-parent : The parent interrupt controller. + +Optional node: +- Child nodes contain in the RT5025. The twl family is made of several variants + that support a different number of features. + + +Example: +rt5025@35 { + compatible = "rt,rt5025"; + reg = <0x35>; + interrupt-parent = <&msmgpio>; + interrupts = <73 0>; + + rt5025_dcdc1: regulator_0 { + compatible = "rt,rt5025-dcdc1"; + cell-index = <0>; + regulator-name = "rt5025-dcdc1"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <2275000>; + rt,ramp_sel = <0x00>; + rt,allow_mode_mask; + qcom,comsumer-supplies = "rt5025-dcdc1", ""; + }; + + rt5025-charger { + compatible = "rt,rt5025-charger"; + rt,te_en; + //rt,screenon_adjust; + rt,iprec = <0x00>; + rt,ieoc = <0x00>; + rt,vprec = <0x05>; + rt,vdpm = <0x02>; + rt,chg_volt = <4200>; + rt,acchg_icc = <2000>; + rt,usbtachg_icc = <2000>; + rt,usbchg_icc = <500>; + rt,screenon_icc = <500>; + rt,temp = <0 150 500 600>; + rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>; + }; + + rt5025_gpiop: rt5025-gpio { + compatible = "rt,rt5025-gpio"; + gpio-controller; + #gpio-cells = <2>; + rt,ngpio = <3>; + }; + + rt5025-irq { + compatible = "rt,rt5025-irq"; + rt,irq-gpio = <&msmgpio 73 0x00>; + }; + + rt5025-misc { + compatible = "rt,rt5025-misc"; + rt,system_lv = <0x02>; + rt,shdn_lpress = <0x01>; + rt,start_lpress = <0x00>; + rt,syslv_enshutdown; + }; + + rt5025-debug { + compatible = "rt,rt5025-debug"; + }; diff --git a/Documentation/devicetree/bindings/power/rt5025-battery.txt b/Documentation/devicetree/bindings/power/rt5025-battery.txt new file mode 100755 index 000000000000..2b9f4a9b829f --- /dev/null +++ b/Documentation/devicetree/bindings/power/rt5025-battery.txt @@ -0,0 +1,14 @@ +Richtek RT5025 battery/fuelgauge function + +The RT5025 battery is responsible to report the battery voltage/current +, capacity, etc. + +Required properties: + + - compatible : Must be "rt,rt5025-battery". + +Example: + +rt5025-battery { + compatible = "rt,rt5025-battery"; +}; diff --git a/Documentation/devicetree/bindings/power/rt5025-charger.txt b/Documentation/devicetree/bindings/power/rt5025-charger.txt new file mode 100755 index 000000000000..b94e36c8dd1a --- /dev/null +++ b/Documentation/devicetree/bindings/power/rt5025-charger.txt @@ -0,0 +1,41 @@ +Richtek RT5025 Charger part + +The RT5025 charger part is responsible to change the charging current/voltage, etc. + +Required properties: + + - compatible : Must be "rt,rt5025-charger". + - rt,chg_volt : default charging voltage. + - rt,ieoc : 0x0 is 10%, 0x1 is 20%. + - rt,vdpm : 0x0 is 4V, 0x1 is 4.25V, 0x2 is 4.5V, 0x3 is disable. + - rt,vprec: precharge voltage. + - rt,iprec: precharge current. + - rt,acchg_icc: rt-power ac charge current. + - rt,usbtachg_icc: rt-power usbta charge current. + - rt,ustchg_icc: rt-power normal usb charge current. + - rt,screenon_icc: screen on charge current. + - rt,te_en: enable terminate function. + - rt,screenon_adjust: enable screen on lower charge current, + screen off recovery to the default charge current. + - rt,temp: jeita temperature, unit 0.1'c + - rt,temp_scalar: jeita temperature scalar according to NTC spec. + +Example: + + rt5025-charger { + compatible = "rt,rt5025-charger"; + rt,te_en; + //rt,screenon_adjust; + rt,iprec = <0x00>; + rt,ieoc = <0x00>; + rt,vprec = <0x05>; + rt,vdpm = <0x02>; + rt,chg_volt = <4200>; + rt,acchg_icc = <2000>; + rt,usbtachg_icc = <2000>; + rt,usbchg_icc = <500>; + rt,screenon_icc = <500>; + rt,temp = <0 150 500 600>; + rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>; + }; + diff --git a/Documentation/devicetree/bindings/regulator/rt5025-regulator.txt b/Documentation/devicetree/bindings/regulator/rt5025-regulator.txt new file mode 100755 index 000000000000..d9073c729dd8 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rt5025-regulator.txt @@ -0,0 +1,27 @@ +Richtek RT5025 of regulators + +Required properties: +For rt5025 regulators/LDOs +- compatible: + - "rt,rt5025-dcdc1" for Buck1 + - "rt,rt5025-dcdc2" for Buck2 + - "rt,rt5025-dcdc3" for Buck3 + - "rt,rt5025-dcdc4" for Buck4/Boost + - "rt,rt5025-ldo1" for Ldo1 + - "rt,rt5025-ldo2" for Ldo2 + - "rt,rt5025-ldo3" for Ldo3 + - "rt,rt5025-ldo4" for Ldo4 + - "rt,rt5025-ldo5" for Ldo5 + - "rt,rt5025-ldo6" for Ldo6 + +Example: + + rt5025-dcdc1: regulator_0@0 { + compatible = "rt,rt5025-dcdc1"; + cell-index = <0>; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <2275000>; + rt,ramp_sel = <0x00>; + rt,allow_mode_mask; + qcom,consumer-supplies = "rt5025-dcdc1", ""; + }; diff --git a/arch/arm/boot/dts/rk312x-sdk.dtsi b/arch/arm/boot/dts/rk312x-sdk.dtsi index 6e305d4063f9..35c23765dd79 100755 --- a/arch/arm/boot/dts/rk312x-sdk.dtsi +++ b/arch/arm/boot/dts/rk312x-sdk.dtsi @@ -168,6 +168,11 @@ reg = <0x1c>; status = "okay"; }; + rt5025: rt5025@35 { + compatible = "rt,rt5025"; + reg = <0x35>; + status = "okay"; + }; }; &i2c2 { status = "okay"; @@ -201,6 +206,106 @@ status = "okay"; }; +/include/ "rt5025.dtsi" +&rt5025 { + + rt5025_dcdc1: regulator_0 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1500000>; + qcom,comsumer-supplies = "vdd_arm", ""; + regulator-always-on; + regulator-boot-on; + + }; + + rt5025_dcdc2: regulator_1 { + regulator-name = "vdd_logic"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1500000>; + qcom,comsumer-supplies = "vdd_logic", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_dcdc3: regulator_2 { + regulator-name = "rt5025-dcdc3"; + regulator-min-microvolt = < 1800000>; + regulator-max-microvolt = <3300000>; + qcom,comsumer-supplies = "rt5025-dcdc3", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_dcdc4: regulator_3 { + regulator-name = "rt5025-dcdc4"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + qcom,comsumer-supplies = "rt5025-dcdc4", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo1: regulator_4 { + regulator-name = "rt5025-ldo1"; + regulator-min-microvolt = < 1800000>; + regulator-max-microvolt = <1800000>; + qcom,comsumer-supplies = "rt5025-ldo1", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo2: regulator_5 { + regulator-name = "rt5025-ldo2"; + regulator-min-microvolt = < 1200000>; + regulator-max-microvolt = <1200000>; + qcom,comsumer-supplies = "rt5025-ldo2", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo3: regulator_6 { + regulator-name = "rt5025-ldo3"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,comsumer-supplies = "rt5025-ldo3", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo4: regulator_7 { + regulator-name = "rt5025-ldo4"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + qcom,comsumer-supplies = "rt5025-ldo4", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo5: regulator_8 { + regulator-name = "rt5025-ldo5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,comsumer-supplies = "rt5025-ldo5", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025_ldo6: regulator_9 { + regulator-name = "rt5025-ldo6"; + regulator-min-microvolt = <330000>; + regulator-max-microvolt = <3300000>; + qcom,comsumer-supplies = "rt5025-ldo6", ""; + regulator-always-on; + regulator-boot-on; + }; + + rt5025-irq { + compatible = "rt,rt5025-irq"; + rt,irq-gpio = <&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>; + }; +}; + /include/ "rk818.dtsi" &rk818 { gpios =<&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>,<&gpio1 GPIO_A1 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/rt5025.dtsi b/arch/arm/boot/dts/rt5025.dtsi new file mode 100755 index 000000000000..d78f0dcb52e3 --- /dev/null +++ b/arch/arm/boot/dts/rt5025.dtsi @@ -0,0 +1,113 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&rt5025 { + compatible = "rt,rt5025"; +// reg = <0x35>; + + rt5025_dcdc1: regulator_0 { + compatible = "rt,rt5025-dcdc1"; + cell-index = <0>; + rt,ramp_sel = <0x00>; + rt,allow_mode_mask; + }; + + rt5025_dcdc2: regulator_1 { + compatible = "rt,rt5025-dcdc2"; + cell-index = <1>; + rt,ramp_sel = <0x00>; + rt,allow_mode_mask; + }; + + rt5025_dcdc3: regulator_2 { + compatible = "rt,rt5025-dcdc3"; + cell-index = <2>; + rt,ramp_sel = <0x00>; + rt,allow_mode_mask; + }; + + rt5025_dcdc4: regulator_3 { + compatible = "rt,rt5025-dcdc4"; + cell-index = <3>; + }; + + rt5025_ldo1: regulator_4 { + compatible = "rt,rt5025-ldo1"; + cell-index = <4>; + }; + + rt5025_ldo2: regulator_5 { + compatible = "rt,rt5025-ldo2"; + cell-index = <5>; + }; + + rt5025_ldo3: regulator_6 { + compatible = "rt,rt5025-ldo3"; + cell-index = <6>; + }; + + rt5025_ldo4: regulator_7 { + compatible = "rt,rt5025-ldo4"; + cell-index = <7>; + }; + + rt5025_ldo5: regulator_8 { + compatible = "rt,rt5025-ldo5"; + cell-index = <8>; + }; + + rt5025_ldo6: regulator_9 { + compatible = "rt,rt5025-ldo6"; + cell-index = <9>; + }; + + rt5025-charger { + compatible = "rt,rt5025-charger"; + rt,te_en; + //rt,screenon_adjust; + rt,iprec = <0x00>; + rt,ieoc = <0x00>; + rt,vprec = <0x05>; + rt,vdpm = <0x02>; + rt,chg_volt = <4200>; + rt,acchg_icc = <2000>; + rt,usbtachg_icc = <2000>; + rt,usbchg_icc = <500>; + rt,screenon_icc = <500>; + rt,temp = <0 150 500 600>; + rt,temp_scalar = <0x30 0x2b 0x28 0x22 0x15 0x10 0x10 0x0d>; + }; + + rt5025-battery { + compatible = "rt,rt5025-battery"; + }; + + rt5025_gpio: rt5025-gpio { + compatible = "rt,rt5025-gpio"; + gpio-controller; + #gpio-cells = <2>; + rt,ngpio = <3>; + }; + rt5025-misc { + compatible = "rt,rt5025-misc"; + rt,vsyslv = <0x02>; + rt,shdnlpress_time = <0x01>; + rt,startlpress_time = <0x00>; + rt,vsyslv_enshdn; + rt,system-power-controller; + + }; + + rt5025-debug { + compatible = "rt,rt5025-debug"; + }; +}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573c449c49b9..6dc75d5c2ed1 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -209,6 +209,13 @@ config GPIO_RCAR help Say yes here to support GPIO on Renesas R-Car SoCs. +config GPIO_RT5025 + bool "Richtek RT5025 GPIO support" + depends on MFD_RT5025 + default n + help + This is the gpio driver for RT5025 PMIC. + config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0cb2d656ad16..39585cb14392 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -87,3 +87,4 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o +obj-$(CONFIG_GPIO_RT5025) += gpio-rt5025.o diff --git a/drivers/gpio/rt5025-gpio.c b/drivers/gpio/gpio-rt5025.c similarity index 55% rename from drivers/gpio/rt5025-gpio.c rename to drivers/gpio/gpio-rt5025.c index 97bebcd597c1..f033b322ff2f 100755 --- a/drivers/gpio/rt5025-gpio.c +++ b/drivers/gpio/gpio-rt5025.c @@ -2,12 +2,13 @@ * drivers/gpio/rt5025-gpio.c * Driver foo Richtek RT5025 PMIC GPIO * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2014 Richtek Technologh Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -16,8 +17,8 @@ #include #include #include -#include #include +#include #include #include @@ -26,21 +27,22 @@ struct rt5025_gpio_info { struct i2c_client *i2c; unsigned gpio_base; unsigned irq_base; + int ngpio; struct gpio_chip gpio_chip; }; static inline int find_rt5025_gpioreg(unsigned off, int *gpio_reg) { int ret = 0; - switch (off) - { - case 0: - case 1: - case 2: - *gpio_reg = RT5025_REG_GPIO0 + off; - break; - default: - ret = -EINVAL; + + switch (off) { + case 0: + case 1: + case 2: + *gpio_reg = RT5025_REG_GPIO0 + off; + break; + default: + ret = -EINVAL; } return ret; } @@ -50,17 +52,15 @@ static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset) struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev); int gpio_reg = 0; int ret = 0; - + ret = find_rt5025_gpioreg(offset , &gpio_reg); - if (ret < 0) - { + if (ret < 0) { dev_err(chip->dev, "not a valid gpio index\n"); return ret; } ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRMASK); - if (ret<0) - { + if (ret < 0) { dev_err(chip->dev, "set gpio input fail\n"); return ret; } @@ -68,40 +68,40 @@ static int rt5025_gpio_direction_input(struct gpio_chip *chip, unsigned offset) return 0; } -static int rt5025_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) +static int rt5025_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) { struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev); int gpio_reg = 0; int ret = 0; - + ret = find_rt5025_gpioreg(offset, &gpio_reg); - if (ret < 0) - { + if (ret < 0) { dev_err(chip->dev, "not a valid gpio index\n"); return ret; } - + ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_DIRSHIFT); - if (ret<0) - { + if (ret < 0) { dev_err(chip->dev, "clr gpio direction fail\n"); return ret; } - ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OUTPUT<i2c, gpio_reg, + RT5025_GPIO_OUTPUT<dev, "set gpio output dir fail\n"); return ret; } if (value) - ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK); + ret = rt5025_set_bits(gi->i2c, gpio_reg, + RT5025_GPIO_OVALUEMASK); else - ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK); + ret = rt5025_clr_bits(gi->i2c, gpio_reg, + RT5025_GPIO_OVALUEMASK); - if (ret<0) - { + if (ret < 0) { dev_err(chip->dev, "set gpio output value fail\n"); return ret; } @@ -114,62 +114,88 @@ static int rt5025_gpio_get_value(struct gpio_chip *chip, unsigned offset) struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev); int gpio_reg = 0; int ret = 0; - + ret = find_rt5025_gpioreg(offset, &gpio_reg); - if (ret < 0) - { + if (ret < 0) { dev_err(chip->dev, "not a valid gpio index\n"); return ret; } - + ret = rt5025_reg_read(gi->i2c, gpio_reg); - if (ret<0) - { + if (ret < 0) { dev_err(chip->dev, "read gpio register fail\n"); return ret; } - return (ret&RT5025_GPIO_IVALUEMASK)?1:0; + return (ret&RT5025_GPIO_IVALUEMASK)?1 : 0; } -static void rt5025_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value) +static void rt5025_gpio_set_value(struct gpio_chip *chip, + unsigned offset, int value) { struct rt5025_gpio_info *gi = dev_get_drvdata(chip->dev); int gpio_reg = 0; int ret = 0; - + ret = find_rt5025_gpioreg(offset, &gpio_reg); - if (ret < 0) - { + if (ret < 0) { dev_err(chip->dev, "not a valid gpio index\n"); return; } if (value) - ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK); + ret = rt5025_set_bits(gi->i2c, gpio_reg, + RT5025_GPIO_OVALUEMASK); else - ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK); + ret = rt5025_clr_bits(gi->i2c, gpio_reg, + RT5025_GPIO_OVALUEMASK); - if (ret<0) - { + if (ret < 0) dev_err(chip->dev, "read gpio register fail\n"); - } } -static int __devinit rt5025_gpio_probe(struct platform_device *pdev) +static int rt_parse_dt(struct rt5025_gpio_info *gi, struct device *dev) +{ + #ifdef CONFIG_OF + struct device_node *np = dev->of_node; + + of_property_read_u32(np, "rt,ngpio", &gi->ngpio); + #endif /* #ifdef CONFIG_OF */ + return 0; +} + +static int rt_parse_pdata(struct rt5025_gpio_info *gi, struct device *dev) +{ + struct rt5025_gpio_data *gpio_pdata = dev->platform_data; + + gi->ngpio = gpio_pdata->ngpio; + return 0; +} + +static int rt5025_gpio_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_gpio_info *gi; - int ret = 0; + bool use_dt = pdev->dev.of_node; + int rc = 0; - gi = kzalloc(sizeof(*gi), GFP_KERNEL); + gi = devm_kzalloc(&pdev->dev, sizeof(*gi), GFP_KERNEL); if (!gi) return -ENOMEM; + gi->i2c = chip->i2c; - gi->gpio_base = pdata->gpio_data->gpio_base; - gi->irq_base = pdata->gpio_data->irq_base; + if (use_dt) { + rt_parse_dt(gi, &pdev->dev); + } else { + if (!pdata) { + rc = -EINVAL; + goto out_dev; + } + pdev->dev.platform_data = pdata->gpio_pdata; + rt_parse_pdata(gi, &pdev->dev); + } gi->gpio_chip.direction_input = rt5025_gpio_direction_input; gi->gpio_chip.direction_output = rt5025_gpio_direction_output; @@ -177,59 +203,62 @@ static int __devinit rt5025_gpio_probe(struct platform_device *pdev) gi->gpio_chip.set = rt5025_gpio_set_value; gi->gpio_chip.can_sleep = 0; - gi->gpio_chip.base = gi->gpio_base; - gi->gpio_chip.ngpio = RT5025_GPIO_NR; + gi->gpio_chip.base = -1; + gi->gpio_chip.ngpio = gi->ngpio; gi->gpio_chip.label = pdev->name; gi->gpio_chip.dev = &pdev->dev; gi->gpio_chip.owner = THIS_MODULE; - ret = gpiochip_add(&gi->gpio_chip); - if (ret) + rc = gpiochip_add(&gi->gpio_chip); + if (rc) goto out_dev; - + platform_set_drvdata(pdev, gi); - return ret; + dev_info(&pdev->dev, "driver successfully loaded\n"); + return rc; out_dev: - kfree(gi); - return ret; + return rc; } -static int __devexit rt5025_gpio_remove(struct platform_device *pdev) +static int rt5025_gpio_remove(struct platform_device *pdev) { - int ret; + int rc = 0; struct rt5025_gpio_info *gi = platform_get_drvdata(pdev); - ret = gpiochip_remove(&gi->gpio_chip); - kfree(gi); - - platform_set_drvdata(pdev, NULL); + rc = gpiochip_remove(&gi->gpio_chip); + dev_info(&pdev->dev, "\n"); return 0; } -static struct platform_driver rt5025_gpio_driver = -{ +static struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-gpio",}, + {}, +}; + +static struct platform_driver rt5025_gpio_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-gpio", + .name = RT5025_DEV_NAME "-gpio", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_gpio_probe, - .remove = __devexit_p(rt5025_gpio_remove), + .remove = rt5025_gpio_remove, }; -static int __init rt5025_gpio_init(void) +static int rt5025_gpio_init(void) { return platform_driver_register(&rt5025_gpio_driver); } -subsys_initcall_sync(rt5025_gpio_init); +fs_initcall_sync(rt5025_gpio_init); -static void __exit rt5025_gpio_exit(void) +static void rt5025_gpio_exit(void) { platform_driver_unregister(&rt5025_gpio_driver); } module_exit(rt5025_gpio_exit); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("CY Huang "); MODULE_DESCRIPTION("GPIO driver for RT5025"); -MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-gpio"); +MODULE_ALIAS("platform:" RT5025_DEV_NAME "-gpio"); MODULE_VERSION(RT5025_DRV_VER); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8fd1c29eccfa..d57c5cfa7c59 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -169,6 +169,42 @@ config MFD_MC13XXX_I2C help Select this if your MC13xxx is connected via an I2C bus. +config MFD_RT5025 + bool "RT5025 PMIC Chip Core driver" + depends on I2C + select MFD_CORE + default n + help + Enable RT5025 core driver. + +config MISC_RT5025 + bool "RT5025 PMIC chip misc configuration" + depends on MFD_RT5025 + default n + help + Enable RT5025 Misc configuration. + +config IRQ_RT5025 + bool "RT5025_PMIC chip irq driver" + depends on MFD_RT5025 + default n + help + Enable RT5025 IRQ configuration and interrupt. + +config DEBUG_RT5025 + bool "RT5025 PMIC Chip Core Debug" + depends on MFD_RT5025 && DEBUG_FS + default n + help + Enable RT5025 core debug driver. + +config MFD_RT_SHOW_INFO + bool "RT5025 PMIC Debug log Flag" + depends on MFD_RT5025 + default n + help + Enable the RT5025 PMIC debug log. + config HTC_EGPIO bool "HTC EGPIO support" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 160e4d908873..1a69560d8dcb 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -55,6 +55,11 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o +obj-$(CONFIG_MFD_RT5025) += rt5025-i2c.o rt5025-core.o +obj-$(CONFIG_MISC_RT5025) += rt5025-misc.o +obj-$(CONFIG_IRQ_RT5025) += rt5025-irq.o +obj-$(CONFIG_DEBUG_RT5025) += rt5025-debug.o + obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o diff --git a/drivers/mfd/rt5025-core.c b/drivers/mfd/rt5025-core.c old mode 100644 new mode 100755 index 245c1c0c9f63..02b46a4d643b --- a/drivers/mfd/rt5025-core.c +++ b/drivers/mfd/rt5025-core.c @@ -2,12 +2,13 @@ * drivers/mfd/rt5025-core.c * Driver for Richtek RT5025 Core PMIC * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2014 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -15,101 +16,144 @@ #include #include #include - #include #ifdef CONFIG_REGULATOR_RT5025 -#define RT5025_VR_DEVS(_id) \ +#ifdef CONFIG_OF +#define RT5025_BUCKVR_DEVS(_id, _idx) \ { \ - .name = RT5025_DEVICE_NAME "-regulator", \ + .name = RT5025_DEV_NAME "-regulator", \ .num_resources = 0, \ + .of_compatible = "rt," RT5025_DEV_NAME "-dcdc" #_idx , \ .id = RT5025_ID_##_id, \ } +#define RT5025_LDOVR_DEVS(_id, _idx) \ +{ \ + .name = RT5025_DEV_NAME "-regulator", \ + .num_resources = 0, \ + .of_compatible = "rt," RT5025_DEV_NAME "-ldo" #_idx , \ + .id = RT5025_ID_##_id, \ +} +#else +#define RT5025_BUCKVR_DEVS(_id, _idx) \ +{ \ + .name = RT5025_DEV_NAME "-regulator", \ + .num_resources = 0, \ + .id = RT5025_ID_##_id, \ +} + +#define RT5025_LDOVR_DEVS(_id, _idx) \ +{ \ + .name = RT5025_DEV_NAME "-regulator", \ + .num_resources = 0, \ + .id = RT5025_ID_##_id, \ +} +#endif /* #ifdef CONFIG_OF */ static struct mfd_cell regulator_devs[] = { - RT5025_VR_DEVS(DCDC1), - RT5025_VR_DEVS(DCDC2), - RT5025_VR_DEVS(DCDC3), - RT5025_VR_DEVS(DCDC4), - RT5025_VR_DEVS(LDO1), - RT5025_VR_DEVS(LDO2), - RT5025_VR_DEVS(LDO3), - RT5025_VR_DEVS(LDO4), - RT5025_VR_DEVS(LDO5), - RT5025_VR_DEVS(LDO6), + RT5025_BUCKVR_DEVS(DCDC1, 1), + RT5025_BUCKVR_DEVS(DCDC2, 2), + RT5025_BUCKVR_DEVS(DCDC3, 3), + RT5025_BUCKVR_DEVS(DCDC4, 4), + RT5025_LDOVR_DEVS(LDO1, 1), + RT5025_LDOVR_DEVS(LDO2, 2), + RT5025_LDOVR_DEVS(LDO3, 3), + RT5025_LDOVR_DEVS(LDO4, 4), + RT5025_LDOVR_DEVS(LDO5, 5), + RT5025_LDOVR_DEVS(LDO6, 6), }; -#endif /* CONFIG_REGULATOR_RT5025 */ +#endif /* #ifdef CONFIG_REGULATOR_RT5025 */ -#ifdef CONFIG_POWER_RT5025 -static struct mfd_cell power_devs[] = { -{ - .name = RT5025_DEVICE_NAME "-power", - .id = -1, - .num_resources = 0, -}, +#ifdef CONFIG_CHARGER_RT5025 +static struct mfd_cell chg_devs[] = { { - .name = RT5025_DEVICE_NAME "-swjeita", + .name = RT5025_DEV_NAME "-charger", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-charger" , +#endif /*#ifdef CONFIG_OF */ }, +}; +#endif /* #ifdef CONFIG_CHARGER_RT5025 */ + +#ifdef CONFIG_BATTERY_RT5025 +static struct mfd_cell fg_devs[] = { { - .name = RT5025_DEVICE_NAME "-battery", + .name = RT5025_DEV_NAME "-battery", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-battery" , +#endif /*#ifdef CONFIG_OF */ }, }; -#endif /* CONFIG_POWER_RT5025 */ +#endif /* #ifdef CONFIG_BATTERY_RT5025 */ #ifdef CONFIG_GPIO_RT5025 static struct mfd_cell gpio_devs[] = { { - .name = RT5025_DEVICE_NAME "-gpio", + .name = RT5025_DEV_NAME "-gpio", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-gpio" , +#endif /*#ifdef CONFIG_OF */ }, }; -#endif /* CONFIG_GPIO_RT5025 */ +#endif /* #ifdef CONFIG_GPIO_RT5025 */ -#ifdef CONFIG_MFD_RT5025_MISC +#ifdef CONFIG_MISC_RT5025 static struct mfd_cell misc_devs[] = { { - .name = RT5025_DEVICE_NAME "-misc", + .name = RT5025_DEV_NAME "-misc", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-misc" , +#endif /*#ifdef CONFIG_OF */ }, }; -#endif /* CONFIG_MFD_RT5025_MISC */ +#endif /* #ifdef CONFIG_MISC_RT5025 */ -#ifdef CONFIG_MFD_RT5025_IRQ +#ifdef CONFIG_IRQ_RT5025 static struct mfd_cell irq_devs[] = { { - .name = RT5025_DEVICE_NAME "-irq", + .name = RT5025_DEV_NAME "-irq", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-irq" , +#endif /*#ifdef CONFIG_OF */ }, }; -#endif /* CONFIG_MFD_RT5025_IRQ */ +#endif /* #ifdef CONFIG_IRQ_RT5025 */ -#ifdef CONFIG_MFD_RT5025_DEBUG +#ifdef CONFIG_DEBUG_RT5025 static struct mfd_cell debug_devs[] = { { - .name = RT5025_DEVICE_NAME "-debug", + .name = RT5025_DEV_NAME "-debug", .id = -1, .num_resources = 0, +#ifdef CONFIG_OF + .of_compatible = "rt," RT5025_DEV_NAME "-debug" , +#endif /*#ifdef CONFIG_OF */ }, }; -#endif /* CONFIG_MFD_RT5025_DEBUG */ +#endif /* #ifdef CONFIG_DEBUG_RT5025 */ -int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_data *pdata) +int rt5025_core_init(struct rt5025_chip *chip, + struct rt5025_platform_data *pdata) { int ret = 0; + bool use_dt = chip->dev->of_node; RTINFO("Start to initialize all device\n"); #ifdef CONFIG_REGULATOR_RT5025 - if (pdata && pdata->regulator[0]) { + if (use_dt || (pdata && pdata->regulator[0])) { RTINFO("mfd add regulators dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], ARRAY_SIZE(regulator_devs), NULL, 0, NULL); @@ -117,24 +161,43 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], ARRAY_SIZE(regulator_devs), NULL, 0); - #endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */ + #endif /* LINUX_VERSION_CODE >= KERNL_VERSION(3,6,0) */ if (ret < 0) { dev_err(chip->dev, "Failed to add regulator subdev\n"); goto out_dev; } } - #endif /* CONFIG_REGULATOR_RT5025 */ - - #ifdef CONFIG_POWER_RT5025 - if (pdata && pdata->power_data && pdata->jeita_data) { - RTINFO("mfd add power dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) - ret = mfd_add_devices(chip->dev, 0, &power_devs[0], - ARRAY_SIZE(power_devs), - NULL, 0,NULL); + #endif /* #ifdef CONFIG_REGULATOR_RT5025 */ + + #ifdef CONFIG_CHARGER_RT5025 + if (use_dt || (pdata && pdata->chg_pdata)) { + RTINFO("mfd add charger dev\n"); + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + ret = mfd_add_devices(chip->dev, 0, &chg_devs[0], + ARRAY_SIZE(chg_devs), + NULL, 0, NULL); + #else + ret = mfd_add_devices(chip->dev, 0, &chg_devs[0], + ARRAY_SIZE(chg_devs), + NULL, 0); + #endif + if (ret < 0) { + dev_err(chip->dev, "Failed to add power supply subdev\n"); + goto out_dev; + } + } + #endif /* #ifdef CONFIG_CHARGER_RT5025 */ + + #ifdef CONFIG_BATTERY_RT5025 + if (use_dt || (pdata)) { + RTINFO("mfd add fuelgauge dev\n"); + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + ret = mfd_add_devices(chip->dev, 0, &fg_devs[0], + ARRAY_SIZE(fg_devs), + NULL, 0, NULL); #else - ret = mfd_add_devices(chip->dev, 0, &power_devs[0], - ARRAY_SIZE(power_devs), + ret = mfd_add_devices(chip->dev, 0, &fg_devs[0], + ARRAY_SIZE(fg_devs), NULL, 0); #endif if (ret < 0) { @@ -143,13 +206,13 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ goto out_dev; } } - #endif /* CONFIG_MFD_RT5025 */ + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ - //Initialize the RT5025_GPIO + /*Initialize the RT5025_GPIO*/ #ifdef CONFIG_GPIO_RT5025 - if (pdata && pdata->gpio_data) { + if (use_dt || (pdata && pdata->gpio_pdata)) { RTINFO("mfd add gpios dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ret = mfd_add_devices(chip->dev, 0, &gpio_devs[0], ARRAY_SIZE(gpio_devs), NULL, 0, NULL); @@ -163,12 +226,12 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ goto out_dev; } } - #endif /* CONFIG_GPIO_RT5025 */ + #endif /* #ifdef CONFIG_GPIO_RT5025 */ - #ifdef CONFIG_MFD_RT5025_MISC - if (pdata && pdata->misc_data) { + #ifdef CONFIG_MISC_RT5025 + if (use_dt || (pdata && pdata->misc_pdata)) { RTINFO("mfd add misc dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ret = mfd_add_devices(chip->dev, 0, &misc_devs[0], ARRAY_SIZE(misc_devs), NULL, 0, NULL); @@ -182,12 +245,12 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ goto out_dev; } } - #endif /* CONFIG_MFD_RT5025_MISC */ + #endif /* #ifdef CONFIG_MISC_RT5025 */ - #ifdef CONFIG_MFD_RT5025_IRQ - if (pdata && pdata->irq_data) { + #ifdef CONFIG_IRQ_RT5025 + if (use_dt || (pdata && pdata->irq_pdata)) { RTINFO("mfd add irq dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ret = mfd_add_devices(chip->dev, 0, &irq_devs[0], ARRAY_SIZE(irq_devs), NULL, 0, NULL); @@ -201,11 +264,11 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ goto out_dev; } } - #endif /* CONFIG_MFD_RT5025_IRQ */ + #endif /* #ifdef CONFIG_IRQ_RT5025 */ - #ifdef CONFIG_MFD_RT5025_DEBUG + #ifdef CONFIG_DEBUG_RT5025 RTINFO("mfd add debug dev\n"); - #if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,6,0)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) ret = mfd_add_devices(chip->dev, 0, &debug_devs[0], ARRAY_SIZE(debug_devs), NULL, 0, NULL); @@ -218,7 +281,7 @@ int __devinit rt5025_core_init(struct rt5025_chip *chip, struct rt5025_platform_ dev_err(chip->dev, "Failed to add debug subdev\n"); goto out_dev; } - #endif /* CONFIG_MFD_RT5025_DEBUG */ + #endif /* CONFIG_DEBUG_RT5025 */ RTINFO("Initialize all device successfully\n"); return ret; @@ -228,7 +291,7 @@ out_dev: } EXPORT_SYMBOL(rt5025_core_init); -int __devexit rt5025_core_deinit(struct rt5025_chip *chip) +int rt5025_core_deinit(struct rt5025_chip *chip) { mfd_remove_devices(chip->dev); return 0; diff --git a/drivers/mfd/rt5025-debug.c b/drivers/mfd/rt5025-debug.c old mode 100644 new mode 100755 index 5f6d8167834e..d899fd946623 --- a/drivers/mfd/rt5025-debug.c +++ b/drivers/mfd/rt5025-debug.c @@ -2,12 +2,13 @@ * drivers/mfd/rt5025-debug.c * Driver foo Richtek RT5025 PMIC Debug * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2013 Richtek Technologh Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -15,26 +16,33 @@ #include #include #include -#include - -#include #include -#include +#include #include struct rt5025_debug_info { struct i2c_client *i2c; + struct device *dev; + unsigned char reg_addr; + unsigned char reg_data; }; -static struct i2c_client *client; -static struct dentry *debugfs_rt_dent; -static struct dentry *debugfs_peek; -static struct dentry *debugfs_poke; -static struct dentry *debugfs_regs; -static struct dentry *debugfs_reset_b; +struct rt_debug_st { + void *info; + int id; +}; -static unsigned char read_data[10]; +enum { + RT5025_DBG_REG, + RT5025_DBG_DATA, + RT5025_DBG_REGS, + RT5025_DBG_MAX +}; + +static struct dentry *debugfs_rt_dent; +static struct dentry *debugfs_file[RT5025_DBG_MAX]; +static struct rt_debug_st rtdbg_data[RT5025_DBG_MAX]; static int reg_debug_open(struct inode *inode, struct file *file) { @@ -60,37 +68,60 @@ static int get_parameters(char *buf, long int *param1, int num_of_par) return -EINVAL; token = strsep(&buf, " "); - } - else + } else { return -EINVAL; + } } return 0; } -#define LOG_FORMAT "0x%02x\n0x%02x\n0x%02x\n0x%02x\n0x%02x\n" - static ssize_t reg_debug_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) { - char *access_str = filp->private_data; - char lbuf[150]; - if (!strcmp(access_str, "regs")) - { - RTINFO("read regs file\n"); - /* read regs */ - snprintf(lbuf, sizeof(lbuf), LOG_FORMAT LOG_FORMAT, read_data[0], \ - read_data[1], read_data[2], read_data[3], read_data[4], read_data[5], \ - read_data[6], read_data[7], read_data[8], read_data[9]); + struct rt_debug_st *st = filp->private_data; + struct rt5025_debug_info *di = st->info; + char lbuf[1000]; + int i = 0, j = 0; + + lbuf[0] = '\0'; + switch (st->id) { + case RT5025_DBG_REG: + snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_addr); + break; + case RT5025_DBG_DATA: + di->reg_data = (unsigned char)rt5025_reg_read(di->i2c, + di->reg_addr); + snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_data); + break; + case RT5025_DBG_REGS: + for (i = RT5025_REG_RANGE1START; + i <= RT5025_REG_RANGE1END; i++) + j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \ + rt5025_reg_read(di->i2c, i)); + for (i = RT5025_REG_RANGE2START; + i <= RT5025_REG_RANGE2END; i++) + j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \ + rt5025_reg_read(di->i2c, i)); + for (i = RT5025_REG_RANGE3START; + i <= RT5025_REG_RANGE3END; i++) + j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \ + rt5025_reg_read(di->i2c, i)); + for (i = RT5025_REG_RANGE4START; + i <= RT5025_REG_RANGE4END; i++) + j += sprintf(lbuf+j, "0x%02x:%02x\n", i, \ + rt5025_reg_read(di->i2c, i)); + break; + default: + return -EINVAL; } - else - snprintf(lbuf, sizeof(lbuf), "0x%02x\n", read_data[0]); return simple_read_from_buffer(ubuf, count, ppos, lbuf, strlen(lbuf)); } static ssize_t reg_debug_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - char *access_str = filp->private_data; + struct rt_debug_st *st = filp->private_data; + struct rt5025_debug_info *di = st->info; char lbuf[32]; int rc; long int param[5]; @@ -104,56 +135,37 @@ static ssize_t reg_debug_write(struct file *filp, lbuf[cnt] = '\0'; - if (!strcmp(access_str, "poke")) { - /* write */ - rc = get_parameters(lbuf, param, 2); - if ((param[0] <= 0xFF) && (param[1] <= 0xFF) && (rc == 0)) - { - rt5025_reg_write(client, param[0], (unsigned char)param[1]); - } - else - rc = -EINVAL; - } else if (!strcmp(access_str, "peek")) { - /* read */ + switch (st->id) { + case RT5025_DBG_REG: rc = get_parameters(lbuf, param, 1); - if ((param[0] <= 0xFF) && (rc == 0)) - { - read_data[0] = rt5025_reg_read(client, param[0]); + if ((param[0] < RT5025_REG_MAX) && (rc == 0)) { + if ((param[0] >= RT5025_REG_RANGE1START && param[0] + <= RT5025_REG_RANGE1END) || \ + (param[0] >= RT5025_REG_RANGE2START && param[0] + <= RT5025_REG_RANGE2END) || \ + (param[0] >= RT5025_REG_RANGE3START && param[0] + <= RT5025_REG_RANGE3END) || \ + (param[0] >= RT5025_REG_RANGE4START && param[0] + <= RT5025_REG_RANGE4END)) + di->reg_addr = (unsigned char)param[0]; + else + rc = -EINVAL; + } else { + rc = -EINVAL; } - else - rc = -EINVAL; - } else if (!strcmp(access_str, "regs")) { - /* read */ + break; + case RT5025_DBG_DATA: rc = get_parameters(lbuf, param, 1); - if ((param[0] <= 0xFF) && (rc == 0)) - { - rt5025_reg_block_read(client, param[0], 10, read_data); - RTINFO("regs 0 = 0x%02x\n", read_data[0]); - RTINFO("regs 1 = 0x%02x\n", read_data[1]); - RTINFO("regs 2 = 0x%02x\n", read_data[2]); - RTINFO("regs 3 = 0x%02x\n", read_data[3]); - RTINFO("regs 4 = 0x%02x\n", read_data[4]); - RTINFO("regs 5 = 0x%02x\n", read_data[5]); - RTINFO("regs 6 = 0x%02x\n", read_data[6]); - RTINFO("regs 7 = 0x%02x\n", read_data[7]); - RTINFO("regs 8 = 0x%02x\n", read_data[8]); - RTINFO("regs 9 = 0x%02x\n", read_data[9]); - } + if ((param[0] <= 0xff) && (rc == 0)) + rt5025_reg_write(di->i2c, di->reg_addr, param[0]); else rc = -EINVAL; - } else if (!strcmp(access_str, "reset_b")) { - /* read */ - rc = get_parameters(lbuf, param, 1); - if (param[0] == 1 && rc == 0) - { - memset(lbuf, 0, 15); - rt5025_reg_block_write(client, 0x21, 15, lbuf); - } + break; + default: + return -EINVAL; } - if (rc == 0) rc = cnt; - return rc; } @@ -163,78 +175,84 @@ static const struct file_operations reg_debug_ops = { .read = reg_debug_read }; -static int __devinit rt5025_debug_probe(struct platform_device *pdev) +static int rt5025_debug_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); struct rt5025_debug_info *di; + int ret = 0; - di = kzalloc(sizeof(*di), GFP_KERNEL); + di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; di->i2c = chip->i2c; + di->dev = &pdev->dev; - RTINFO("add debugfs for core RT5025"); - client = chip->i2c; + RTINFO("add debugfs for RT5025"); debugfs_rt_dent = debugfs_create_dir("rt5025_dbg", 0); if (!IS_ERR(debugfs_rt_dent)) { - debugfs_peek = debugfs_create_file("peek", - S_IFREG | S_IRUGO, debugfs_rt_dent, - (void *) "peek", ®_debug_ops); - - debugfs_poke = debugfs_create_file("poke", + rtdbg_data[0].info = di; + rtdbg_data[0].id = RT5025_DBG_REG; + debugfs_file[0] = debugfs_create_file("reg", S_IFREG | S_IRUGO, debugfs_rt_dent, - (void *) "poke", ®_debug_ops); + (void *) &rtdbg_data[0], ®_debug_ops); - debugfs_regs = debugfs_create_file("regs", + rtdbg_data[1].info = di; + rtdbg_data[1].id = RT5025_DBG_DATA; + debugfs_file[1] = debugfs_create_file("data", S_IFREG | S_IRUGO, debugfs_rt_dent, - (void *) "regs", ®_debug_ops); + (void *) &rtdbg_data[1], ®_debug_ops); - debugfs_reset_b = debugfs_create_file("reset_b", + rtdbg_data[2].info = di; + rtdbg_data[2].id = RT5025_DBG_REGS; + debugfs_file[2] = debugfs_create_file("regs", S_IFREG | S_IRUGO, debugfs_rt_dent, - (void *) "reset_b", ®_debug_ops); + (void *) &rtdbg_data[2], ®_debug_ops); + } else { + dev_err(&pdev->dev, "create debugfs failed\n"); + ret = -EINVAL; + goto err_init; } - platform_set_drvdata(pdev, di); - return 0; +err_init: + return ret; } -static int __devexit rt5025_debug_remove(struct platform_device *pdev) +static int rt5025_debug_remove(struct platform_device *pdev) { - struct rt5025_debug_info *di = platform_get_drvdata(pdev); - if (!IS_ERR(debugfs_rt_dent)) debugfs_remove_recursive(debugfs_rt_dent); - - kfree(di); return 0; } -static struct platform_driver rt5025_debug_driver = -{ +static const struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-debug",}, + {}, +}; + +static struct platform_driver rt5025_debug_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-debug", + .name = RT5025_DEV_NAME "-debug", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_debug_probe, - .remove = __devexit_p(rt5025_debug_remove), + .remove = rt5025_debug_remove, }; -static int __init rt5025_debug_init(void) +static int rt5025_debug_init(void) { return platform_driver_register(&rt5025_debug_driver); } module_init(rt5025_debug_init); -static void __exit rt5025_debug_exit(void) +static void rt5025_debug_exit(void) { platform_driver_unregister(&rt5025_debug_driver); } module_exit(rt5025_debug_exit); - -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("CY Huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include #include #include -#include #include -#define ROCKCHIP_I2C_RATE (200*1000) - static inline int rt5025_read_device(struct i2c_client *i2c, int reg, int bytes, void *dest) { - #if 1 - int ret; - unsigned char reg_addr = reg; - struct i2c_msg i2c_msg[2]; - i2c_msg[0].addr = i2c->addr; - i2c_msg[0].flags = i2c->flags; - i2c_msg[0].len = 1; - i2c_msg[0].buf = ®_addr; - i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE; - i2c_msg[1].addr = i2c->addr; - i2c_msg[1].flags = i2c->flags | I2C_M_RD; - i2c_msg[1].len = bytes; - i2c_msg[1].buf = dest; - i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE; - ret = i2c_transfer(i2c->adapter, i2c_msg, 2); - #else int ret; - if (bytes > 1) + + if (bytes > 1) { ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest); - else { + } else { ret = i2c_smbus_read_byte_data(i2c, reg); if (ret < 0) return ret; *(unsigned char *)dest = (unsigned char)ret; } - #endif return ret; } @@ -60,30 +42,15 @@ EXPORT_SYMBOL(rt5025_reg_block_read); static inline int rt5025_write_device(struct i2c_client *i2c, int reg, int bytes, void *dest) { - #if 1 - int ret; - struct i2c_msg i2c_msg; - char *tx_buf = (char*)kmalloc(bytes+1, GFP_KERNEL); - tx_buf[0] = reg; - memcpy(tx_buf+1, dest, bytes); - i2c_msg.addr = i2c->addr; - i2c_msg.flags = i2c->flags; - i2c_msg.len = bytes + 1; - i2c_msg.buf = tx_buf; - i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; - ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); - kfree(tx_buf); - #else int ret; - if (bytes > 1) + + if (bytes > 1) { ret = i2c_smbus_write_i2c_block_data(i2c, reg, bytes, dest); - else { - ret = i2c_smbus_write_byte_data(i2c, reg, dest); + } else { + ret = i2c_smbus_write_byte_data(i2c, reg, *(u8 *)dest); if (ret < 0) return ret; - *(unsigned char *)dest = (unsigned char)ret; } - #endif return ret; } @@ -96,65 +63,28 @@ EXPORT_SYMBOL(rt5025_reg_block_write); int rt5025_reg_read(struct i2c_client *i2c, int reg) { - struct rt5025_chip* chip = i2c_get_clientdata(i2c); + struct rt5025_chip *chip = i2c_get_clientdata(i2c); int ret; - #if 1 - unsigned char reg_addr = reg; - unsigned char reg_data = 0; - struct i2c_msg i2c_msg[2]; - RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n", - (unsigned int)i2c,(unsigned int)reg); - mutex_lock(&chip->io_lock); - i2c_msg[0].addr = i2c->addr; - i2c_msg[0].flags = i2c->flags; - i2c_msg[0].len = 1; - i2c_msg[0].buf = ®_addr; - i2c_msg[0].scl_rate = ROCKCHIP_I2C_RATE; - i2c_msg[1].addr = i2c->addr; - i2c_msg[1].flags = i2c->flags | I2C_M_RD; - i2c_msg[1].len = 1; - i2c_msg[1].buf = ®_data; - i2c_msg[1].scl_rate = ROCKCHIP_I2C_RATE; - ret = i2c_transfer(i2c->adapter, i2c_msg, 2); - mutex_unlock(&chip->io_lock); - #else + RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n", - (unsigned int)i2c,(unsigned int)reg); + (unsigned int) i2c, (unsigned int) reg); mutex_lock(&chip->io_lock); ret = i2c_smbus_read_byte_data(i2c, reg); mutex_unlock(&chip->io_lock); - #endif - return reg_data; + return ret; } EXPORT_SYMBOL(rt5025_reg_read); int rt5025_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { - struct rt5025_chip* chip = i2c_get_clientdata(i2c); + struct rt5025_chip *chip = i2c_get_clientdata(i2c); int ret; - #if 1 - unsigned char xfer_data[2]; - struct i2c_msg i2c_msg; - RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", - (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); - xfer_data[0] = reg; - xfer_data[1] = data; - mutex_lock(&chip->io_lock); - i2c_msg.addr = i2c->addr; - i2c_msg.flags = i2c->flags; - i2c_msg.len = 2; - i2c_msg.buf = xfer_data; - i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; - ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); - mutex_unlock(&chip->io_lock); - #else + RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n", - (unsigned int)i2c,(unsigned int)reg,(unsigned int)data); + (unsigned int) i2c, (unsigned int) reg, (unsigned int) data); mutex_lock(&chip->io_lock); ret = i2c_smbus_write_byte_data(i2c, reg, data); mutex_unlock(&chip->io_lock); - #endif - return ret; } EXPORT_SYMBOL(rt5025_reg_write); @@ -165,25 +95,7 @@ int rt5025_assign_bits(struct i2c_client *i2c, int reg, struct rt5025_chip *chip = i2c_get_clientdata(i2c); unsigned char value; int ret; - #if 1 - struct i2c_msg i2c_msg; - u8 xfer_data[2] = {0}; - mutex_lock(&chip->io_lock); - ret = rt5025_read_device(i2c, reg, 1, &value); - if (ret < 0) - goto out; - - value &= ~mask; - value |= (data&mask); - xfer_data[0] = reg; - xfer_data[1] = value; - i2c_msg.addr = i2c->addr; - i2c_msg.flags = i2c->flags; - i2c_msg.len = 2; - i2c_msg.buf = xfer_data; - i2c_msg.scl_rate = ROCKCHIP_I2C_RATE; - ret = i2c_transfer(i2c->adapter, &i2c_msg, 1); - #else + mutex_lock(&chip->io_lock); ret = rt5025_read_device(i2c, reg, 1, &value); @@ -192,8 +104,7 @@ int rt5025_assign_bits(struct i2c_client *i2c, int reg, goto out; value &= ~mask; value |= (data&mask); - ret = i2c_smbus_write_byte_data(i2c,reg,value); - #endif + ret = i2c_smbus_write_byte_data(i2c, reg, value); out: mutex_unlock(&chip->io_lock); return ret; @@ -203,90 +114,101 @@ EXPORT_SYMBOL(rt5025_assign_bits); int rt5025_set_bits(struct i2c_client *i2c, int reg, unsigned char mask) { - return rt5025_assign_bits(i2c,reg,mask,mask); + return rt5025_assign_bits(i2c, reg, mask, mask); } EXPORT_SYMBOL(rt5025_set_bits); int rt5025_clr_bits(struct i2c_client *i2c, int reg, unsigned char mask) { - return rt5025_assign_bits(i2c,reg,mask,0); + return rt5025_assign_bits(i2c, reg, mask, 0); } EXPORT_SYMBOL(rt5025_clr_bits); -static int __devinit rt5025_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int rt_parse_dt(struct rt5025_chip *chip, struct device *dev) +{ + return 0; +} + +static int rt_parse_pdata(struct rt5025_chip *chip, struct device *dev) +{ + return 0; +} + +static int rt5025_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct rt5025_platform_data *pdata = client->dev.platform_data; struct rt5025_chip *chip; + bool use_dt = client->dev.of_node; int ret = 0; - u8 val; - - if (!pdata) - return -EINVAL; + u8 val = 0; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - chip->irq = client->irq; - chip->i2c = client; - chip->dev = &client->dev; - -#if 0 - if (pdata->event_callback) - { - chip->event_callback = kzalloc(sizeof(struct rt5025_event_callback), GFP_KERNEL); - memcpy(chip->event_callback, pdata->event_callback, sizeof(struct rt5025_event_callback)); + if (use_dt) { + rt_parse_dt(chip, &client->dev); + } else { + if (!pdata) { + ret = -EINVAL; + goto err_init; + } + rt_parse_pdata(chip, &client->dev); } -#endif /* #if 0 */ - i2c_set_clientdata(client, chip); + chip->i2c = client; + chip->dev = &client->dev; mutex_init(&chip->io_lock); - - rt5025_read_device(client,0x00,1,&val); - if (val != 0x81){ - printk("The PMIC is not RT5025\n"); + i2c_set_clientdata(client, chip); + /* off event */ + rt5025_read_device(client, 0x20, 1, &val); + RTINFO("off event = %d\n", val); + + rt5025_read_device(client, 0x00, 1, &val); + if (val != 0x81) { + dev_info(&client->dev, "The PMIC is not RT5025\n"); return -ENODEV; } + ret = rt5025_core_init(chip, pdata); - if (ret < 0) - dev_err(chip->dev, "rt5025_core_init_fail\n"); - else - pr_info("RT5025 Initialize successfully\n"); + if (ret < 0) { + dev_err(&client->dev, "rt5025_core_init_fail\n"); + goto err_init; + } + dev_info(&client->dev, "driver successfully probed\n"); if (pdata && pdata->pre_init) { ret = pdata->pre_init(chip); - if (ret != 0) { + if (ret != 0) dev_err(chip->dev, "pre_init() failed: %d\n", ret); - } } - + if (pdata && pdata->post_init) { ret = pdata->post_init(); - if (ret != 0) { + if (ret != 0) dev_err(chip->dev, "post_init() failed: %d\n", ret); - } } - + return 0; +err_init: return ret; } -static int __devexit rt5025_i2c_remove(struct i2c_client *client) +static int rt5025_i2c_remove(struct i2c_client *client) { struct rt5025_chip *chip = i2c_get_clientdata(client); + rt5025_core_deinit(chip); - #if 0 - if (chip->event_callback) - kfree(chip->event_callback); - #endif - kfree(chip); + dev_info(&client->dev, "%s\n", __func__); return 0; } static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg) { struct rt5025_chip *chip = i2c_get_clientdata(client); + chip->suspend = 1; RTINFO("\n"); return 0; @@ -295,47 +217,49 @@ static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg) static int rt5025_i2c_resume(struct i2c_client *client) { struct rt5025_chip *chip = i2c_get_clientdata(client); + chip->suspend = 0; RTINFO("\n"); return 0; } static const struct i2c_device_id rt5025_id_table[] = { - { RT5025_DEVICE_NAME, 0 }, + { RT5025_DEV_NAME, 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, rt5025_id_table); -static struct i2c_driver rt5025_driver = { +static struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025",}, + {}, +}; + +static struct i2c_driver rt5025_i2c_driver = { .driver = { - .name = RT5025_DEVICE_NAME, + .name = RT5025_DEV_NAME, .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_i2c_probe, - .remove = __devexit_p(rt5025_i2c_remove), + .remove = rt5025_i2c_remove, .suspend = rt5025_i2c_suspend, .resume = rt5025_i2c_resume, .id_table = rt5025_id_table, }; -static int __init rt5025_i2c_init(void) +static int rt5025_i2c_init(void) { - int ret; - - ret = i2c_add_driver(&rt5025_driver); - if (ret != 0) - pr_err("Failed to register RT5025 I2C driver: %d\n", ret); - return ret; + return i2c_add_driver(&rt5025_i2c_driver); } subsys_initcall_sync(rt5025_i2c_init); -static void __exit rt5025_i2c_exit(void) +static void rt5025_i2c_exit(void) { - i2c_del_driver(&rt5025_driver); + i2c_del_driver(&rt5025_i2c_driver); } module_exit(rt5025_i2c_exit); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("I2C Driver for Richtek RT5025"); MODULE_AUTHOR("CY Huang "); MODULE_VERSION(RT5025_DRV_VER); diff --git a/drivers/mfd/rt5025-irq.c b/drivers/mfd/rt5025-irq.c old mode 100644 new mode 100755 index 7a324c251a34..67d8a82bd973 --- a/drivers/mfd/rt5025-irq.c +++ b/drivers/mfd/rt5025-irq.c @@ -1,336 +1,204 @@ /* * drivers/mfd/rt5025-irq.c - * Driver foo Richtek RT5025 PMIC irq + * Driver for Richtek RT5025 PMIC IRQ driver * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2014 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include #include +#include #include -#include #include -#include -#include -#include - -#include -#include -#include +#include +#include #include +#include #include #include struct rt5025_irq_info { struct i2c_client *i2c; - struct device *dev; struct rt5025_chip *chip; - struct workqueue_struct *wq; - struct rt5025_event_callback *event_cb; - struct delayed_work delayed_work; - struct wake_lock irq_wake_lock; - int intr_pin; + struct device *dev; int irq; - int suspend; - int acin_cnt; - int usbin_cnt; + unsigned char suspend:1; + struct delayed_work irq_delayed_work; }; -static void rt5025_work_func(struct work_struct *work) +static irqreturn_t rt5025_irq_handler(int irqno, void *param) { - struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); - struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(delayed_work, struct rt5025_irq_info, delayed_work); - unsigned char irq_stat[6] = {0}; - unsigned char irq_enable[6] = {0}; - uint32_t chg_event = 0, pwr_event = 0; + struct rt5025_irq_info *ii = param; + unsigned char regval[6]; + unsigned int irq_event = 0; + int ret = 0; - //Add this to prevent i2c xfer before i2c chip is in suspend mode - if (ii->suspend) - { - queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(1)); - return; + if (ii->suspend) { + schedule_delayed_work(&ii->irq_delayed_work, + msecs_to_jiffies(10)); + goto irq_fin; } - #ifdef CONFIG_POWER_RT5025 - if (!ii->chip->power_info || !ii->chip->jeita_info || !ii->chip->battery_info) - { - queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(1)); - return; + ret = rt5025_reg_read(ii->i2c, RT5025_REG_IRQFLG); + if (ret < 0) { + dev_err(ii->dev, "read gauge irq event fail\n"); + } else { + irq_event = ret; + RTINFO("gauge event %02x\n", irq_event); + #ifdef CONFIG_BATTERY_RT5025 + if (irq_event) + rt5025_gauge_irq_handler(ii->chip->battery_info, + irq_event&(~RT5025_TALRT_MASK)); + #endif /* #ifdef CONFIG_RTC_RT5025 */ } - #endif - #if 0 - if (rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 10, irq_stat) >= 0) - { - #endif - /* backup the irq enable bit */ - irq_enable[0] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN1); - irq_enable[1] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN2); - irq_enable[2] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN3); - irq_enable[3] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN4); - irq_enable[4] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQEN5); - irq_enable[5] = rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQEN); - #if 1 - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]&(~RT5025_CHTERMI_MASK)); + ret = rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN1, 6, regval); + if (ret < 0) { + dev_err(ii->dev, "read charger irq event fail\n"); + } else { + #ifdef CONFIG_BATTERY_RT5025 + /*combine gauge talrt irq into charger event*/ + irq_event = irq_event&RT5025_TALRT_MASK; + irq_event <<= 24; + irq_event |= (regval[1] << 16 | regval[3] << 8 | regval[5]); #else - /* disable all irq enable bit first */ - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]&RT5025_ADAPIRQ_MASK); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, 0x00); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, 0x00); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, 0x00); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, 0x00); - rt5025_reg_write(ii->i2c, RT5025_REG_GAUGEIRQEN, 0x00); - #endif //#if 0 - /* read irq status bit */ - irq_stat[0] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS1); - irq_stat[1] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS2); - irq_stat[2] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS3); - irq_stat[3] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS4); - irq_stat[4] = rt5025_reg_read(ii->i2c, RT5025_REG_IRQSTATUS5); - irq_stat[5] = rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQFLG); - RTINFO("irq1->0x%02x, irq2->0x%02x, irq3->0x%02x\n", irq_stat[0], irq_stat[1], irq_stat[2]); - RTINFO("irq4->0x%02x, irq5->0x%02x, irq6->0x%02x\n", irq_stat[3], irq_stat[4], irq_stat[5]); - RTINFO("stat value = %02x\n", rt5025_reg_read(ii->i2c, RT5025_REG_CHGSTAT)); - - chg_event = irq_stat[0]<<16 | irq_stat[1]<<8 | irq_stat[2]; - pwr_event = irq_stat[3]<<8 | irq_stat[4]; - #ifdef CONFIG_POWER_RT5025 - if ((chg_event & CHARGER_DETECT_MASK)) - { - if (chg_event & CHG_EVENT_CHTERMI) - { - ii->chip->power_info->chg_term++; - if (ii->chip->power_info->chg_term > 3) - ii->chip->power_info->chg_term = 4; - } - - if (chg_event & CHG_EVENT_CHRCHGI) - ii->chip->power_info->chg_term = 0; - - if (chg_event & (CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB)) - { - ii->chip->power_info->chg_term = 0; - if (chg_event & CHG_EVENT_CHSLPI_INAC) - ii->acin_cnt = 0; - if (chg_event & CHG_EVENT_CHSLPI_INUSB) - ii->usbin_cnt = 0; - - } - - if (chg_event & (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN)) - { - RTINFO("acin_cnt %d, usbin_cnt %d\n", ii->acin_cnt, ii->usbin_cnt); - if (ii->acin_cnt == 0 && ii->usbin_cnt == 0) - { - #if 1 - rt5025_charger_reset_and_reinit(ii->chip->power_info); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]&(~RT5025_CHTERMI_MASK)); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_enable[2]); - #else - rt5025_set_charging_buck(ii->i2c, 0); - mdelay(50); - rt5025_set_charging_buck(ii->i2c, 1); - mdelay(100); - rt5025_set_charging_buck(ii->i2c, 0); - mdelay(50); - rt5025_set_charging_buck(ii->i2c, 1); - mdelay(400); - #endif /* #if 1 */ - } - - if (chg_event & CHG_EVENT_INAC_PLUGIN) - ii->acin_cnt = 1; - if (chg_event & CHG_EVENT_INUSB_PLUGIN) - ii->usbin_cnt = 1; - RTINFO("acin_cnt %d, usbin_cnt %d\n", ii->acin_cnt, ii->usbin_cnt); - } - - if (ii->chip->power_info->chg_term <= 3) - rt5025_power_charge_detect(ii->chip->power_info); - - } - #endif /* CONFIG_POWER_RT5025 */ - if (ii->event_cb) - { - if (chg_event) - ii->event_cb->charger_event_callback(chg_event); - if (pwr_event) - ii->event_cb->power_event_callkback(pwr_event); - } - #if 0 + irq_event = regval[1] << 16 | regval[3] << 8 | regval[5]; + #endif + RTINFO("chg event %08x\n", irq_event); + #ifdef CONFIG_CHARGER_RT5025 + if (irq_event) + rt5025_charger_irq_handler(ii->chip->charger_info, + irq_event); + #endif /* #ifdef CONFIG_CHARGER_RT5025 */ } - else - dev_err(ii->dev, "read irq stat io fail\n"); - #endif - - - #ifdef CONFIG_POWER_RT5025 - if (irq_stat[5] & RT5025_FLG_TEMP) - rt5025_swjeita_irq_handler(ii->chip->jeita_info, irq_stat[5] & RT5025_FLG_TEMP); - if (irq_stat[5] & RT5025_FLG_VOLT) - rt5025_gauge_irq_handler(ii->chip->battery_info, irq_stat[5] & RT5025_FLG_VOLT); - #endif /* CONFIG_POWER_RT5025 */ - #if 1 - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]); - #else - /* restore all irq enable bit */ - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_enable[0]); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_enable[1]); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_enable[2]); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_enable[3]); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_enable[4]); - if (rt5025_reg_read(ii->i2c, RT5025_REG_GAUGEIRQEN) == 0) - rt5025_reg_write(ii->i2c, RT5025_REG_GAUGEIRQEN, irq_enable[5]); - #endif //#if 0 - - //enable_irq(ii->irq); + ret = rt5025_reg_block_read(ii->i2c, RT5025_REG_IRQEN4, 4, regval); + if (ret < 0) { + dev_err(ii->dev, "read misc irq event fail\n"); + } else { + irq_event = regval[1] << 8 | regval[3]; + RTINFO("misc event %04x\n", irq_event); + #ifdef CONFIG_MISC_RT5025 + if (irq_event) + rt5025_misc_irq_handler(ii->chip->misc_info, irq_event); + #endif /* #ifdef CONFIG_MISC_RT5025 */ + } +irq_fin: + return IRQ_HANDLED; } -static irqreturn_t rt5025_interrupt(int irqno, void *param) +static void rt5025_irq_delayed_work(struct work_struct *work) { - struct rt5025_irq_info *ii = (struct rt5025_irq_info *)param; + struct rt5025_irq_info *ii = (struct rt5025_irq_info *)container_of(work, + struct rt5025_irq_info, irq_delayed_work.work); - //disable_irq_nosync(ii->irq); - wake_lock_timeout(&ii->irq_wake_lock, 1*HZ); - queue_delayed_work(ii->wq, &ii->delayed_work, 0); - return IRQ_HANDLED; + rt5025_irq_handler(ii->irq, ii); } -static int __devinit rt5025_interrupt_init(struct rt5025_irq_info* ii) +static int rt_parse_dt(struct rt5025_irq_info *ii, struct device *dev) { - int ret = 0; - - RTINFO("\n"); - ii->wq = create_workqueue("rt5025_wq"); - INIT_DELAYED_WORK(&ii->delayed_work, rt5025_work_func); - - #if 0 - if (gpio_is_valid(ii->intr_pin)) - { - ret = gpio_request(ii->intr_pin, "rt5025_interrupt"); - if (ret) - return ret; - - ret = gpio_direction_input(ii->intr_pin); - if (ret) - return ret; - #endif - - if (request_irq(ii->irq, rt5025_interrupt, IRQ_TYPE_EDGE_FALLING|IRQF_DISABLED, "RT5025_IRQ", ii)) - { - dev_err(ii->dev, "couldn't allocate IRQ_NO(%d) !\n", ii->irq); - return -EINVAL; - } - enable_irq_wake(ii->irq); - queue_delayed_work(ii->wq, &ii->delayed_work, msecs_to_jiffies(100)); - #if 0 - - if (!gpio_get_value(ii->intr_pin)) - { - //disable_irq_nosync(ii->irq); - queue_delayed_work(ii->wq, &ii->delayed_work, 0); + #ifdef CONFIG_OF + struct device_node *np = dev->of_node; + int val; + + val = of_get_named_gpio(np, "rt,irq-gpio", 0); + if (gpio_is_valid(val)) { + if (gpio_request(val, "rt5025-irq") >= 0) { + gpio_direction_input(val); + ii->irq = gpio_to_irq(val); + } else { + ii->irq = -1; } + } else { + ii->irq = -1; } - else - return -EINVAL; - #endif - - return ret; + #endif /* #ifdef CONFIG_OF */ + RTINFO("\n"); + return 0; } -static void __devexit rt5025_interrupt_deinit(struct rt5025_irq_info* ii) +static int rt_parse_pdata(struct rt5025_irq_info *ii, struct device *dev) { - if (ii->irq) - free_irq(ii->irq, ii); - - if (ii->wq) - { - cancel_delayed_work_sync(&ii->delayed_work); - flush_workqueue(ii->wq); - destroy_workqueue(ii->wq); + struct rt5025_irq_data *pdata = dev->platform_data; + + if (gpio_is_valid(pdata->irq_gpio)) { + if (gpio_request(pdata->irq_gpio, "rt5025-irq") >= 0) { + gpio_direction_input(pdata->irq_gpio); + ii->irq = gpio_to_irq(pdata->irq_gpio); + } else { + ii->irq = -1; + } + } else { + ii->irq = -1; } -} - -static int __devinit rt5025_irq_reg_init(struct rt5025_irq_info* ii, struct rt5025_irq_data* irq_data) -{ RTINFO("\n"); - // will just enable the interrupt that we want - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN1, irq_data->irq_enable1.val); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN2, irq_data->irq_enable2.val); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN3, irq_data->irq_enable3.val); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN4, irq_data->irq_enable4.val); - rt5025_reg_write(ii->i2c, RT5025_REG_IRQEN5, irq_data->irq_enable5.val); return 0; } -static int __devinit rt5025_irq_probe(struct platform_device *pdev) +static int rt5025_irq_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_irq_info *ii; + bool use_dt = pdev->dev.of_node; + int ret; - RTINFO("\n"); - ii = kzalloc(sizeof(*ii), GFP_KERNEL); + ii = devm_kzalloc(&pdev->dev, sizeof(*ii), GFP_KERNEL); if (!ii) return -ENOMEM; ii->i2c = chip->i2c; - ii->dev = &pdev->dev; ii->chip = chip; - ii->intr_pin = pdata->intr_pin; - ii->irq = chip->irq;//gpio_to_irq(pdata->intr_pin); - if (pdata->cb) - ii->event_cb = pdata->cb; - wake_lock_init(&ii->irq_wake_lock, WAKE_LOCK_SUSPEND, "rt_irq_wake"); + ii->dev = &pdev->dev; + if (use_dt) { + rt_parse_dt(ii, &pdev->dev); + } else { + if (!pdata) + goto out_dev; + pdev->dev.platform_data = pdata->irq_pdata; + rt_parse_pdata(ii, &pdev->dev); + dev_info(&pdev->dev, "ii->irq %d\n", ii->irq); + } - rt5025_irq_reg_init(ii, pdata->irq_data); - rt5025_interrupt_init(ii); + INIT_DELAYED_WORK(&ii->irq_delayed_work, rt5025_irq_delayed_work); platform_set_drvdata(pdev, ii); - RTINFO("\n"); + if (ii->irq >= 0) { + ret = devm_request_irq(&pdev->dev, ii->irq, rt5025_irq_handler, + IRQF_TRIGGER_FALLING|IRQF_NO_SUSPEND, "rt5025-irq", ii); + if (ret != 0) { + dev_err(&pdev->dev, "request threaded irq fail\n"); + goto out_dev; + } + enable_irq_wake(ii->irq); + schedule_delayed_work(&ii->irq_delayed_work, 1*HZ); + } + dev_info(&pdev->dev, "driver successfully loaded\n"); return 0; +out_dev: + return -EINVAL; } -static int __devexit rt5025_irq_remove(struct platform_device *pdev) +static int rt5025_irq_remove(struct platform_device *pdev) { struct rt5025_irq_info *ii = platform_get_drvdata(pdev); - wake_lock_destroy(&ii->irq_wake_lock); - rt5025_interrupt_deinit(ii); - platform_set_drvdata(pdev, NULL); - kfree(ii); - RTINFO("\n"); + if (ii->irq >= 0) + devm_free_irq(&pdev->dev, ii->irq, ii); return 0; } -static void rt5025_irq_shutdown(struct platform_device *pdev) -{ - struct rt5025_irq_info *ii = platform_get_drvdata(pdev); - - if (ii->irq) - free_irq(ii->irq, ii); - - if (ii->wq) - { - cancel_delayed_work_sync(&ii->delayed_work); - flush_workqueue(ii->wq); - } - RTINFO("\n"); -} - static int rt5025_irq_suspend(struct platform_device *pdev, pm_message_t state) { struct rt5025_irq_info *ii = platform_get_drvdata(pdev); - RTINFO("\n"); ii->suspend = 1; return 0; } @@ -339,38 +207,42 @@ static int rt5025_irq_resume(struct platform_device *pdev) { struct rt5025_irq_info *ii = platform_get_drvdata(pdev); - RTINFO("\n"); ii->suspend = 0; return 0; } -static struct platform_driver rt5025_irq_driver = -{ +static const struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-irq",}, + {}, +}; + +static struct platform_driver rt5025_irq_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-irq", + .name = RT5025_DEV_NAME "-irq", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_irq_probe, - .remove = __devexit_p(rt5025_irq_remove), - .shutdown = rt5025_irq_shutdown, + .remove = rt5025_irq_remove, .suspend = rt5025_irq_suspend, .resume = rt5025_irq_resume, }; -static int __init rt5025_irq_init(void) +static int rt5025_irq_init(void) { return platform_driver_register(&rt5025_irq_driver); } -module_init(rt5025_irq_init); +device_initcall(rt5025_irq_init); -static void __exit rt5025_irq_exit(void) +static void rt5025_irq_exit(void) { platform_driver_unregister(&rt5025_irq_driver); } + module_exit(rt5025_irq_exit); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_AUTHOR("CY Huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -15,105 +16,306 @@ #include #include #include -#include +#include +#include #include #include -struct rt5025_misc_info { - struct i2c_client *i2c; +static unsigned char misc_init_regval[] = { + 0x2A, /* reg 0x15 */ + 0x00, /* reg 0x16 */ + 0x60, /* reg 0x17 */ + 0x16, /* reg 0x19 */ + 0x60, /* reg 0x1A */ + 0x0C, /* reg 0x1B */ + 0xF3, /* reg 0x36 */ + 0x90, /* reg 0x38 */ }; static struct i2c_client *g_shdn; -void rt5025_power_off(void) +static bool rt_pm_off; +static void rt5025_power_off(void) { - rt5025_reg_write(g_shdn, RT5025_CHENH_REG, 0x00); - rt5025_reg_write(g_shdn, RT5025_CHENL_REG, 0x80); - rt5025_set_bits(g_shdn, RT5025_SHDNCTRL_REG, RT5025_SHDNCTRL_MASK); + rt5025_reg_write(g_shdn, RT5025_REG_CHANNELH, 0x00); + rt5025_reg_write(g_shdn, RT5025_REG_CHANNELL, 0x80); + rt5025_set_bits(g_shdn, RT5025_REG_MISC3, RT5025_SHDNCTRL_MASK); } EXPORT_SYMBOL(rt5025_power_off); int rt5025_cable_exist(void) { int ret = 0; - ret = rt5025_reg_read(g_shdn, 0x01); - if (ret < 0) - return 0; - else - { - if (ret&0x3) - return 1; - return 0; + #ifdef CONFIG_CHARGER_RT5025 + struct power_supply *psy = power_supply_get_by_name("rt-charger"); + union power_supply_propval pval; + + if (!psy) { + pr_err(" couldn't get charger power supply\n"); + } else { + ret = psy->get_property(psy, + POWER_SUPPLY_PROP_CHARGE_NOW, &pval); + if (ret < 0) { + ret = 0; + } else { + if (pval.intval > POWER_SUPPLY_TYPE_BATTERY) + ret = 1; + else + ret = 0; + } + } + #else + ret = rt5025_reg_read(g_shdn, RT5025_REG_CHGCTL1); + if (ret < 0) { + pr_err("couldn't get cable status\n"); + ret = 0; + } else { + if (ret & RT5025_CABLEIN_MASK) + ret = 1; + else + ret = 0; } + #endif /* #ifdef CONFIG_CHARGER_RT5025 */ + return ret; } EXPORT_SYMBOL(rt5025_cable_exist); -static int __devinit rt5025_misc_reg_init(struct i2c_client *client, struct rt5025_misc_data *md) +static void rt5025_general_irq_handler(void *info, int eventno) { - int ret = 0; - - rt5025_reg_write(client, RT5025_RESETCTRL_REG, md->RSTCtrl.val); - rt5025_assign_bits(client, RT5025_VSYSULVO_REG, RT5025_VSYSOFF_MASK, md->VSYSCtrl.val); - rt5025_reg_write(client, RT5025_PWRONCTRL_REG, md->PwrOnCfg.val); - rt5025_reg_write(client, RT5025_SHDNCTRL_REG, md->SHDNCtrl.val); - rt5025_reg_write(client, RT5025_PWROFFEN_REG, md->PwrOffCond.val); + struct rt5025_misc_info *mi = info; - return ret; + RTINFO("eventno=%02d\n", eventno); + + switch (eventno) { + case MISCEVENT_RESETB: + dev_warn(mi->dev, "RESETB event trigger\n"); + break; + case MISCEVENT_KPSHDN: + dev_warn(mi->dev, "PwrKey force shdn\n"); + break; + case MISCEVENT_SYSLV: + dev_warn(mi->dev, "syslv event trigger\n"); + break; + case MISCEVENT_DCDC4LVHV: + dev_warn(mi->dev, "DCDC4LVHV event trigger\n"); + break; + case MISCEVENT_DCDC3LV: + dev_warn(mi->dev, "DCDC3LV event trigger\n"); + break; + case MISCEVENT_DCDC2LV: + dev_warn(mi->dev, "DCDC2LV event trigger\n"); + break; + case MISCEVENT_DCDC1LV: + dev_warn(mi->dev, "DCDC2LV event trigger\n"); + break; + case MISCEVENT_OT: + dev_warn(mi->dev, "Over temperature event trigger\n"); + break; + default: + break; + } +} + +static rt_irq_handler rt_miscirq_handler[MISCEVENT_MAX] = { + [MISCEVENT_GPIO0_IE] = rt5025_general_irq_handler, + [MISCEVENT_GPIO1_IE] = rt5025_general_irq_handler, + [MISCEVENT_GPIO2_IE] = rt5025_general_irq_handler, + [MISCEVENT_RESETB] = rt5025_general_irq_handler, + [MISCEVENT_PWRONF] = rt5025_general_irq_handler, + [MISCEVENT_PWRONR] = rt5025_general_irq_handler, + [MISCEVENT_KPSHDN] = rt5025_general_irq_handler, + [MISCEVENT_SYSLV] = rt5025_general_irq_handler, + [MISCEVENT_DCDC4LVHV] = rt5025_general_irq_handler, + [MISCEVENT_PWRONLP_IRQ] = rt5025_general_irq_handler, + [MISCEVENT_PWRONSP_IRQ] = rt5025_general_irq_handler, + [MISCEVENT_DCDC3LV] = rt5025_general_irq_handler, + [MISCEVENT_DCDC2LV] = rt5025_general_irq_handler, + [MISCEVENT_DCDC1LV] = rt5025_general_irq_handler, + [MISCEVENT_OT] = rt5025_general_irq_handler, +}; + +void rt5025_misc_irq_handler(struct rt5025_misc_info *ci, unsigned int irqevent) +{ + int i; + unsigned int enable_irq_event = (misc_init_regval[6] << 8) | + misc_init_regval[7]; + unsigned int final_irq_event = irqevent&enable_irq_event; + + for (i = 0; i < MISCEVENT_MAX; i++) { + if ((final_irq_event&(1 << i)) && rt_miscirq_handler[i]) + rt_miscirq_handler[i](ci, i); + } +} +EXPORT_SYMBOL(rt5025_misc_irq_handler); + +static int rt5025_misc_reginit(struct i2c_client *client) +{ + rt5025_reg_write(client, RT5025_REG_MISC1, misc_init_regval[0]); + rt5025_reg_write(client, RT5025_REG_ONEVENT, misc_init_regval[1]); + rt5025_assign_bits(client, RT5025_REG_DCDCONOFF, + RT5025_VSYSOFF_MASK, misc_init_regval[2]); + rt5025_reg_write(client, RT5025_REG_MISC2, misc_init_regval[3]); + rt5025_reg_write(client, RT5025_REG_MISC3, misc_init_regval[4]); + rt5025_reg_write(client, RT5025_REG_MISC4, misc_init_regval[5]); + /*set all to be masked*/ + rt5025_reg_write(client, RT5025_REG_IRQEN4, 0x00); + rt5025_reg_write(client, RT5025_REG_IRQEN5, 0x00); + /*clear the old irq status*/ + rt5025_reg_read(client, RT5025_REG_IRQSTAT4); + rt5025_reg_read(client, RT5025_REG_IRQSTAT5); + /*set enable irqs as we want*/ + rt5025_reg_write(client, RT5025_REG_IRQEN4, misc_init_regval[6]); + rt5025_reg_write(client, RT5025_REG_IRQEN5, misc_init_regval[7]); + return 0; +} + +static int rt_parse_dt(struct rt5025_misc_info *mi, struct device *dev) +{ + int rc; + #ifdef CONFIG_OF + struct device_node *np = dev->of_node; + unsigned int val; + + rc = of_property_read_u32(np, "rt,vsyslv", &val); + if (rc < 0) { + dev_info(dev, "no system lv value, use default value\n"); + } else { + if (val > RT5025_VOFF_MAX) + val = RT5025_VOFF_MAX; + misc_init_regval[2] &= ~RT5025_VSYSOFF_MASK; + misc_init_regval[2] |= val << RT5025_VSYSOFF_SHFT; + } + + rc = of_property_read_u32(np, "rt,shdnlpress_time", &val); + if (rc < 0) { + dev_info(dev, "no shdnlpress time, use default value\n"); + } else { + if (val > RT5025_SHDNPRESS_MAX) + val = RT5025_SHDNPRESS_MAX; + misc_init_regval[3] &= ~RT5025_SHDNLPRESS_MASK; + misc_init_regval[3] |= val << RT5025_SHDNLPRESS_SHFT; + } + + rc = of_property_read_u32(np, "rt,startlpress_time", &val); + if (rc < 0) { + dev_err(dev, "no start_lpress, use default value\n"); + } else { + if (val > RT5025_STARTIME_MAX) + val = RT5025_STARTIME_MAX; + misc_init_regval[3] &= ~RT5025_STARTLPRESS_MASK; + misc_init_regval[3] |= val << RT5025_STARTLPRESS_SHFT; + } + + if (of_property_read_bool(np, "rt,vsyslv_enshdn")) + misc_init_regval[5] |= RT5025_VSYSLVSHDN_MASK; + else + misc_init_regval[5] &= ~RT5025_VSYSLVSHDN_MASK; + #endif + + rt_pm_off = of_property_read_bool(np, "rt,system-power-controller"); + /* #ifdef CONFIG_OF */ + rc = rt5025_misc_reginit(mi->i2c); + return rc; +} + +static int rt_parse_pdata(struct rt5025_misc_info *mi, struct device *dev) +{ + struct rt5025_misc_data *pdata = dev->platform_data; + int rc = 0; + + /*system low voltage*/ + misc_init_regval[2] &= ~RT5025_VSYSOFF_MASK; + misc_init_regval[2] |= (pdata->vsyslv << RT5025_VSYSOFF_SHFT); + /*shutdown long press time*/ + misc_init_regval[3] &= ~RT5025_SHDNLPRESS_MASK; + misc_init_regval[3] |= (pdata->shdnlpress_time << + RT5025_SHDNLPRESS_SHFT); + /*start long press time*/ + misc_init_regval[3] &= ~RT5025_STARTLPRESS_MASK; + misc_init_regval[3] |= (pdata->startlpress_time << + RT5025_STARTLPRESS_SHFT); + /*systemlv enable shutdown*/ + misc_init_regval[5] &= ~RT5025_VSYSLVSHDN_MASK; + misc_init_regval[5] |= (pdata->vsyslv_enshdn << + RT5025_VSYSLVSHDN_SHFT); + rc = rt5025_misc_reginit(mi->i2c); + return rc; } -static int __devinit rt5025_misc_probe(struct platform_device *pdev) +static int rt5025_misc_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_misc_info *mi; + bool use_dt = pdev->dev.of_node; + int ret = 0; - mi = kzalloc(sizeof(*mi), GFP_KERNEL); + mi = devm_kzalloc(&pdev->dev, sizeof(*mi), GFP_KERNEL); if (!mi) return -ENOMEM; mi->i2c = chip->i2c; - rt5025_misc_reg_init(mi->i2c, pdata->misc_data); - - //for shutdown control + mi->dev = &pdev->dev; + if (use_dt) { + rt_parse_dt(mi, &pdev->dev); + } else { + if (!pdata) { + dev_err(&pdev->dev, "no initial platform data\n"); + ret = -EINVAL; + goto err_init; + } + pdev->dev.platform_data = pdata->misc_pdata; + rt_parse_pdata(mi, &pdev->dev); + } + /*for shutdown control*/ g_shdn = chip->i2c; + if (rt_pm_off && !pm_power_off) + pm_power_off = rt5025_power_off; + platform_set_drvdata(pdev, mi); + chip->misc_info = mi; + dev_info(&pdev->dev, "driver successfully loaded\n"); return 0; +err_init: + return ret; } -static int __devexit rt5025_misc_remove(struct platform_device *pdev) +static int rt5025_misc_remove(struct platform_device *pdev) { - struct rt5025_misc_info *mi = platform_get_drvdata(pdev); - - kfree(mi); - platform_set_drvdata(pdev, NULL); + dev_info(&pdev->dev, "%s\n", __func__); return 0; } -static struct platform_driver rt5025_misc_driver = -{ +static struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-misc",}, + {}, +}; + +static struct platform_driver rt5025_misc_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-misc", + .name = RT5025_DEV_NAME "-misc", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_misc_probe, - .remove = __devexit_p(rt5025_misc_remove), + .remove = rt5025_misc_remove, }; -static int __init rt5025_misc_init(void) +static int rt5025_misc_init(void) { return platform_driver_register(&rt5025_misc_driver); } -module_init(rt5025_misc_init); +subsys_initcall(rt5025_misc_init); -static void __exit rt5025_misc_exit(void) +static void rt5025_misc_exit(void) { platform_driver_unregister(&rt5025_misc_driver); } module_exit(rt5025_misc_exit); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_AUTHOR("CY Huang + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct rt_power_info { + struct device *dev; + struct power_supply ac_psy; + struct power_supply usb_psy; + struct wake_lock usbdet_wakelock; + struct delayed_work usbdet_work; + int chg_volt; + int acchg_icc; + int usbtachg_icc; + int usbchg_icc; + unsigned char ac_online:1; + unsigned char usbta_online:1; + unsigned char usb_online:1; + unsigned char suspend:1; + unsigned char usbcnt; +}; + +#define RT_USBCNT_MAX 60 + +static char *rtpower_supply_list[] = { + "battery", +}; + +static enum power_supply_property rtpower_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static int rtpower_set_charger(struct rt_power_info *pi) +{ + struct power_supply *chg_psy; + union power_supply_propval pval; + int rc = 0, is_chg_on = 0; + + chg_psy = power_supply_get_by_name("rt-charger"); + if (chg_psy) { + rc = chg_psy->get_property(chg_psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(pi->dev, "get chg online prop fail\n"); + else + is_chg_on = pval.intval; + if (pi->ac_online) { + pval.intval = pi->acchg_icc; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set acchg aicr fail\n"); + pval.intval = 500; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set acchg icc fail\n"); + pval.intval = POWER_SUPPLY_TYPE_MAINS; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charge cable fail\n"); + if (!is_chg_on) { + pval.intval = pi->chg_volt; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg voltage fail\n"); + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger online fail\n"); + } + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger present fail\n"); + } else if (pi->usbta_online) { + pval.intval = pi->usbtachg_icc; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set usbtachg aicr fail\n"); + pval.intval = 500; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set usbtachg icc fail\n"); + pval.intval = POWER_SUPPLY_TYPE_USB_DCP; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charge cable fail\n"); + if (!is_chg_on) { + pval.intval = pi->chg_volt; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg voltage fail\n"); + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger online fail\n"); + } + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger present fail\n"); + } else if (pi->usb_online) { + pval.intval = pi->usbchg_icc; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set usbchg aicr fail\n"); + pval.intval = 500; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set usbchg icc fail\n"); + pval.intval = POWER_SUPPLY_TYPE_USB; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charge cable fail\n"); + if (!is_chg_on) { + pval.intval = pi->chg_volt; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg voltage fail\n"); + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger online fail\n"); + } + pval.intval = 1; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger present fail\n"); + + } else { + pval.intval = 0; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charger online fail\n"); + pval.intval = 0; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CHARGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set charge cable fail\n"); + pval.intval = pi->chg_volt; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg voltage fail\n"); + pval.intval = 500; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_AVG,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg aicr fail\n"); + pval.intval = 500; + rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_CURRENT_NOW,\ + &pval); + if (rc < 0) + dev_err(pi->dev, "set chg icc fail\n"); + } + power_supply_changed(chg_psy); + } else { + rc = -EINVAL; + dev_err(pi->dev, "cannot get rt-charger psy\n"); + } + return rc; +} + +static int rtpower_get_property(struct power_supply *psy, enum power_supply_property psp, \ + union power_supply_propval *val) +{ + struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) + val->intval = (pi->ac_online || pi->usbta_online)?1 : 0; + else if (psy->type == POWER_SUPPLY_TYPE_USB) + val->intval = pi->usb_online; + else + rc = -EINVAL; + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int rtpower_set_property(struct power_supply *psy, enum power_supply_property psp, \ + const union power_supply_propval *val) +{ + struct rt_power_info *pi = dev_get_drvdata(psy->dev->parent); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + if (psy->type == POWER_SUPPLY_TYPE_MAINS) { + if (pi->ac_online != val->intval) { + pi->ac_online = val->intval; + rc = rtpower_set_charger(pi); + } + } else if (psy->type == POWER_SUPPLY_TYPE_USB) { + if (pi->usb_online != val->intval) { + pi->usb_online = val->intval; + if (val->intval) { + pi->usbcnt = 0; + wake_lock(&pi->usbdet_wakelock); + schedule_delayed_work(&pi->usbdet_work, 1*HZ); + } else { + pi->usbcnt = RT_USBCNT_MAX; + schedule_delayed_work(&pi->usbdet_work, 0); + if (pi->usbta_online) { + pi->usbta_online = 0; + power_supply_changed(&pi->ac_psy); + } + } + rc = rtpower_set_charger(pi); + } + } else { + rc = -EINVAL; + } + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +extern int dwc_otg_check_dpdm(bool wait); +static void usbdet_work_func(struct work_struct *work) +{ + struct rt_power_info *pi = container_of(work, struct rt_power_info, \ + usbdet_work.work); + int usb_det = dwc_otg_check_dpdm(0); + + switch (usb_det) { + case 2: + dev_info(pi->dev, "usb ta checked\n"); + if (pi->usb_online) { + pi->usbta_online = 1; + rtpower_set_charger(pi); + power_supply_changed(&pi->ac_psy); + } + pi->usbcnt = RT_USBCNT_MAX; + break; + case 1: + case 0: + dev_info(pi->dev, "normal usb\n"); + break; + default: + break; + } + if (pi->usbcnt < RT_USBCNT_MAX) { + pi->usbcnt++; + schedule_delayed_work(&pi->usbdet_work, 1*HZ); + } else { + wake_unlock(&pi->usbdet_wakelock); + } +} + +static int rt_power_probe(struct platform_device *pdev) +{ + struct rt_power_info *pi; + struct rt_power_data *rt_power_pdata = pdev->dev.platform_data; + int ret = 0; + + pi = devm_kzalloc(&pdev->dev, sizeof(*pi), GFP_KERNEL); + if (!pi) + return -ENOMEM; + pi->dev = &pdev->dev; + wake_lock_init(&pi->usbdet_wakelock, WAKE_LOCK_SUSPEND, "rt-usb-det"); + INIT_DELAYED_WORK(&pi->usbdet_work, usbdet_work_func); + pi->chg_volt = rt_power_pdata->chg_volt; + pi->acchg_icc = rt_power_pdata->acchg_icc; + pi->usbtachg_icc = rt_power_pdata->usbtachg_icc; + pi->usbchg_icc = rt_power_pdata->usbchg_icc; + platform_set_drvdata(pdev, pi); + + /* ac power supply register*/ + pi->ac_psy.name = RT_AC_NAME; + pi->ac_psy.type = POWER_SUPPLY_TYPE_MAINS; + pi->ac_psy.supplied_to = rtpower_supply_list; + pi->ac_psy.properties = rtpower_props; + pi->ac_psy.num_properties = ARRAY_SIZE(rtpower_props); + pi->ac_psy.get_property = rtpower_get_property; + pi->ac_psy.set_property = rtpower_set_property; + ret = power_supply_register(&pdev->dev, &pi->ac_psy); + if (ret < 0) { + dev_err(&pdev->dev, " create ac power supply fail\n"); + goto err_init; + } + /*usb power supply register*/ + pi->usb_psy.name = RT_USB_NAME; + pi->usb_psy.type = POWER_SUPPLY_TYPE_USB; + pi->usb_psy.supplied_to = rtpower_supply_list; + pi->usb_psy.properties = rtpower_props; + pi->usb_psy.num_properties = ARRAY_SIZE(rtpower_props); + pi->usb_psy.get_property = rtpower_get_property; + pi->usb_psy.set_property = rtpower_set_property; + ret = power_supply_register(&pdev->dev, &pi->usb_psy); + if (ret < 0) { + dev_err(&pdev->dev, " create usb power supply fail\n"); + goto err_acpsy; + } + return 0; + +err_acpsy: + power_supply_unregister(&pi->ac_psy); +err_init: + wake_lock_destroy(&pi->usbdet_wakelock); + return ret; +} + +static int rt_power_remove(struct platform_device *pdev) +{ + struct rt_power_info *pi = platform_get_drvdata(pdev); + + power_supply_unregister(&pi->usb_psy); + power_supply_unregister(&pi->ac_psy); + wake_lock_destroy(&pi->usbdet_wakelock); + return 0; +} + +static int rt_power_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct rt_power_info *pi = platform_get_drvdata(pdev); + + pi->suspend = 1; + return 0; +} + +static int rt_power_resume(struct platform_device *pdev) +{ + struct rt_power_info *pi = platform_get_drvdata(pdev); + + pi->suspend = 0; + return 0; +} + +static const struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt-power",}, + {}, +}; + +static struct platform_driver rt_power_driver = { + .driver = { + .name = "rt-power", + .owner = THIS_MODULE, + .of_match_table = rt_match_table, + }, + .probe = rt_power_probe, + .remove = rt_power_remove, + .suspend = rt_power_suspend, + .resume = rt_power_resume, +}; +static int rt_power_init(void) +{ + return platform_driver_register(&rt_power_driver); +} +subsys_initcall(rt_power_init); + +static void rt_power_exit(void) +{ + platform_driver_unregister(&rt_power_driver); +} +module_exit(rt_power_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CY Huang "); +MODULE_DESCRIPTION("RT Power driver"); +MODULE_ALIAS("platform:rt-power"); +MODULE_VERSION("1.0.0_G"); diff --git a/drivers/power/rt5025-battery.c b/drivers/power/rt5025-battery.c old mode 100644 new mode 100755 index f6a290ebbba3..08d6a06a035c --- a/drivers/power/rt5025-battery.c +++ b/drivers/power/rt5025-battery.c @@ -2,12 +2,13 @@ * I2C Driver for Richtek RT5025 PMIC * Multi function device - multi functional baseband PMIC Battery part * - * Copyright (C) 2013 + * Copyright (C) 2014 Richtek Technology Corp. * Author: Nick Hung * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -24,10 +25,11 @@ #include #include #include -#include +#include #include #include + #define VOLTAGE_ALERT 0 #define TEMPERATURE_ALERT 0 @@ -37,277 +39,291 @@ u8 irq_thres[LAST_TYPE]; -static int rt5025_battery_parameter_backup(struct rt5025_battery_info *); +static unsigned char gauge_init_regval[] = { + 0xFF, /*REG 0x53*/ + 0x00, /*REG 0x54*/ + 0x00, /*REG 0x55*/ + 0xFF, /*REG 0x56*/ + 0x00, /*REG 0x57*/ +}; -void rt5025_gauge_set_status(struct rt5025_battery_info *bi, int status) -{ - bi->status = status; - if (status == POWER_SUPPLY_STATUS_FULL) - { - bi->tp_flag = true; - bi->last_tp_flag = true; - } - else - power_supply_changed(&bi->battery); - wake_lock_timeout(&bi->status_wake_lock, 1.5*HZ); - schedule_delayed_work(&bi->monitor_work, 0); -} -EXPORT_SYMBOL(rt5025_gauge_set_status); +static u16 crctab16[256] = { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, +}; -void rt5025_gauge_set_online(struct rt5025_battery_info *bi, bool present) -{ - bi->online = present; -} -EXPORT_SYMBOL(rt5025_gauge_set_online); +static int rt5025_battery_parameter_backup(struct rt5025_battery_info *); +static void rt5025_get_external_temp(struct rt5025_battery_info *); +static void rt5025_get_internal_temp(struct rt5025_battery_info *); +static void rt5025_get_vcell(struct rt5025_battery_info *); +static void rt5025_get_current(struct rt5025_battery_info *); +static void rt5025_temp_comp(struct rt5025_battery_info *); +/* 20140415 CY */ static int rt5025_read_reg(struct i2c_client *client, u8 reg, u8 *data, u8 len) { - #if 1 return rt5025_reg_block_read(client, reg, len, data); - #else - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msgs[2]; - int ret; - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = 1; - msgs[0].buf = ® - - msgs[1].addr = client->addr; - msgs[1].flags = client->flags | I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = data; - - ret = i2c_transfer(adap, msgs, 2); - - return (ret == 2)? len : ret; - #endif } static int rt5025_write_reg(struct i2c_client *client, u8 reg, u8 *data, u8 len) { - #if 1 return rt5025_reg_block_write(client, reg, len, data); - #else - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - int ret; - char *tx_buf = (char *)kmalloc(len + 1, GFP_KERNEL); - - if(!tx_buf) - return -ENOMEM; - tx_buf[0] = reg; - memcpy(tx_buf+1, data, len); - - msg.addr = client->addr; - msg.flags = client->flags; - msg.len = len + 1; - msg.buf = (char *)tx_buf; - - ret = i2c_transfer(adap, &msg, 1); - kfree(tx_buf); - return (ret == 1) ? len : ret; - #endif -} - -static void rt5025_gauge_alarm(struct alarm *alarm) -{ - struct rt5025_battery_info *bi = (struct rt5025_battery_info *)container_of(alarm, struct rt5025_battery_info, wakeup_alarm); - - //wake_lock(&bi->monitor_wake_lock); - schedule_delayed_work(&bi->monitor_work, 0); } -static void rt5025_program_alarm(struct rt5025_battery_info *bi) +static void rt5025_set_battery_led(struct rt5025_battery_info *bi, int status) { - ktime_t low_interval = ktime_set(bi->update_time, 0); - //ktime_t slack = ktime_set(20, 0); - ktime_t next; - - next = ktime_add(bi->last_poll, low_interval); - //alarm_start_range(&bi->wakeup_alarm, next, ktime_add(next, slack)); + switch (status) { + case POWER_SUPPLY_STATUS_CHARGING: + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + break; + case POWER_SUPPLY_STATUS_FULL: + break; + default: + break; + } } -#if 0 -static void rt5025_run_time(struct rt5025_battery_info *bi) +static int rt5025_set_property(struct power_supply *psy,\ + enum power_supply_property psp,\ + const union power_supply_propval *val) { - if(bi->curr <= 0) - { - bi->time_to_empty = bi->rm / (bi->curr*(-1)); + struct rt5025_battery_info *bi = dev_get_drvdata(psy->dev->parent); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (val->intval == POWER_SUPPLY_STATUS_FULL) { + bi->tp_flag = true; + pr_info("%s: Battery is full \n", __func__); + } else { + mutex_lock(&bi->status_change_lock); + bi->status = val->intval; + if (bi->status == POWER_SUPPLY_STATUS_DISCHARGING) + bi->tp_flag = false; + rt5025_set_battery_led(bi, bi->status); + mutex_unlock(&bi->status_change_lock); + } + wake_lock_timeout(&bi->status_wake_lock, 1.5*HZ); + schedule_delayed_work(&bi->monitor_work, msecs_to_jiffies(100)); + break; + case POWER_SUPPLY_PROP_PRESENT: + bi->batt_present = val->intval; + break; + default: + rc = -EINVAL; + break; } - else - { - bi->time_to_full = (bi->fcc * 3600 - bi->rm) / bi->curr; - } - RTINFO("RTTF = %d\n",bi->time_to_full); - RTINFO("RTTE = %d\n",bi->time_to_empty); + return rc; } -#endif static int rt5025_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - struct rt5025_battery_info *bi = dev_get_drvdata(psy->dev->parent); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = bi->status; - //val->intval = POWER_SUPPLY_STATUS_CHARGING; - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = bi->health; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = bi->present; - break; - case POWER_SUPPLY_PROP_TEMP: - val->intval = bi->ext_temp; - break; - case POWER_SUPPLY_PROP_ONLINE: - val->intval = bi->online; - break; - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = bi->vcell * 1000; //uV - break; - case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = bi->curr * 1000; //uA - break; - case POWER_SUPPLY_PROP_CAPACITY: - val->intval = bi->soc; - //val->intval = 50; - if (val->intval > 100) - val->intval = 100; - break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = POWER_SUPPLY_TECHNOLOGY_LION; - break; - #if 0 - case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: - val->intval = bi->time_to_empty; - break; - case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: - val->intval = bi->time_to_full; - #endif - break; - default: - return -EINVAL; - } - return 0; + struct rt5025_battery_info *bi = dev_get_drvdata(psy->dev->parent); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bi->status; + /*val->intval = POWER_SUPPLY_STATUS_CHARGING;*/ + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = bi->health; + /*If there's no battery, always show battery health to good.*/ + if (!bi->present || !bi->batt_present) + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bi->present; + break; + case POWER_SUPPLY_PROP_TEMP: + if (val->intval == 23) { + rt5025_get_external_temp(bi); + val->intval = bi->ext_temp; + } else { + /*If there's no battery, always show battery temperature to 25'c.*/ + if (!bi->present || !bi->batt_present) + val->intval = 250; + else + val->intval = bi->ext_temp; + } + break; + case POWER_SUPPLY_PROP_TEMP_AMBIENT: + rt5025_get_internal_temp(bi); + val->intval = bi->int_temp; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = bi->online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + rt5025_get_vcell(bi); + val->intval = bi->vcell * 1000; /*uv*/ + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rt5025_get_current(bi); + val->intval = bi->curr * 1000; /*uA*/ + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = bi->soc; + if (val->intval > 100) + val->intval = 100; + /*If there's no battery, always show capacity to 50*/ + if (!bi->present || !bi->batt_present) + val->intval = 50; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; +#if 0 + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + val->intval = bi->time_to_empty; + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + val->intval = bi->time_to_full; + break; +#endif + default: + return -EINVAL; + } + return 0; } static void rt5025_get_vcell(struct rt5025_battery_info *bi) { - u8 data[2]; - - if (bi->init_once) - { - rt5025_clr_bits(bi->client, 0x07, 0x10); - RTINFO("set_current switch off\n"); - mdelay(1000); - } - - if (rt5025_read_reg(bi->client, RT5025_REG_VCELL_MSB, data, 2) < 0){ - printk(KERN_ERR "%s: Failed to read Voltage\n", __func__); - } - - if (bi->init_once) - { - rt5025_set_bits(bi->client, 0x07, 0x10); - RTINFO("set_current switch on\n"); - } + u8 data[2]; - if (bi->avg_flag) - bi->vcell = ((data[0] << 8) + data[1]) * 61 / 100; - else - bi->vcell = (bi->vcell + ((data[0] << 8) + data[1]) * 61 / 100) / 2; + /* 20140415 CY */ +#if 0 + if (bi->init_cap) { + rt5025_clr_bits(bi->client, 0x07, 0x10); + RTINFO("set_current switch off\n"); + msleep(300); + } +#endif /* #if 0 */ + if (rt5025_read_reg(bi->client, RT5025_REG_VBATSH, data, 2) < 0) + pr_err("%s: Failed to read Voltage\n", __func__); + /* 20140415 CY */ +#if 0 + if (bi->init_cap) { + rt5025_set_bits(bi->client, 0x07, 0x10); + RTINFO("set_current switch on\n"); + } +#endif /* #if 0 */ + if (bi->avg_flag) + bi->vcell = ((data[0] << 8) + data[1]) * 61 / 100; + else + bi->vcell = (bi->vcell + ((data[0] << 8) + data[1]) * 61 / 100) / 2; #if RT5025_B - bi->curr_offset = (15444 * bi->vcell - 27444000) / 10000; -#else - if (37 * bi->vcell > 92000) + bi->curr_offset = 0; +#else + if (37 * bi->vcell > 92000) bi->curr_offset = (37 * bi->vcell - 92000) / 1000; else bi->curr_offset = 0; #endif - + #if RT5025_CSV - // if (!bi->avg_flag) - // pr_info("%d,%d,", bi->vcell, bi->curr_offset); -#else - if (bi->avg_flag) + /* if (!bi->avg_flag)*/ + /* pr_info("%d,%d,", bi->vcell, bi->curr_offset);*/ +#else + if (bi->avg_flag) RTINFO("vcell_pre: %d, offset: %d\n", bi->vcell, bi->curr_offset); - else + else RTINFO("vcell_avg: %d, offset: %d\n", bi->vcell, bi->curr_offset); #endif } static void rt5025_get_current(struct rt5025_battery_info *bi) { - u8 data[2]; - s32 temp; - int sign = 0; - u8 curr_region; + u8 data[2]; + s32 temp; + int sign = 0; + u8 curr_region; + + if (rt5025_read_reg(bi->client, RT5025_REG_CURRH, data, 2) < 0) + pr_err("%s: Failed to read CURRENT\n", __func__); - if (rt5025_read_reg(bi->client, RT5025_REG_CURRENT_MSB, data, 2) < 0) { - printk(KERN_ERR "%s: Failed to read CURRENT\n", __func__); - } #if RT5025_B - temp = (data[0]<<8) | data[1]; - bi->curr_raw = ((temp & 0x7FFF) * 3125) / 10000; - - if (data[0] & (1 << 7)) { - sign = 1; - temp = (((temp & 0x7FFF) * 3125) / 10 + bi->curr_offset) / 1000; - }else{ + temp = (data[0] << 8) | data[1]; + bi->curr_raw = ((temp & 0x7FFF) * 3125) / 10000; + + if (data[0] & (1 << 7)) { + sign = 1; + temp = (((temp & 0x7FFF) * 3125) / 10 + bi->curr_offset) / 1000; + } else { if ((temp * 3125) / 10 > bi->curr_offset) temp = ((temp * 3125) / 10 - bi->curr_offset) / 1000; } - - if (temp < DEADBAND) + if (temp < DEADBAND) temp = 0; - - if (sign){ - temp *= -1; - bi->curr_raw *= -1; + if (sign) { + temp *= -1; + bi->curr_raw *= -1; } #else - temp = (data[0]<<8) | data[1]; - if (data[0] & (1 << 7)) { - sign = 1; - temp = temp & 0x7FFF; - if(temp > bi->curr_offset) + temp = (data[0] << 8) | data[1]; + if (data[0] & (1 << 7)) { + sign = 1; + temp = temp & 0x7FFF; + if (temp > bi->curr_offset) temp = temp - bi->curr_offset; - }else { - temp = temp + bi->curr_offset; + } else { + temp = temp + bi->curr_offset; } - - temp = (temp * 37375) / 100000; //Unit: 0.3125mA - if (temp < DEADBAND) + temp = (temp * 37375) / 100000; /*Unit: 0.3125mA*/ + if (temp < DEADBAND) temp = 0; - - if (sign) - temp *= -1; + if (sign) + temp *= -1; #endif - if (bi->avg_flag) - bi->curr = temp; - else - bi->curr = (bi->curr + temp) / 2; - - if (bi->curr > -500) - curr_region = 0; - else if (bi->curr <= -500 && bi->curr > -1500) - curr_region = 1; - else - curr_region = 2; - - if (curr_region != bi->edv_region) - { - switch (curr_region) - { + if (bi->avg_flag) + bi->curr = temp; + else + bi->curr = (bi->curr + temp) / 2; + + if (bi->curr > -500) + curr_region = 0; + else if (bi->curr <= -500 && bi->curr > -1500) + curr_region = 1; + else + curr_region = 2; + + if (curr_region != bi->edv_region) { + switch (curr_region) { case 0: bi->empty_edv = rt5025_battery_param2[4].x; break; @@ -315,29 +331,30 @@ static void rt5025_get_current(struct rt5025_battery_info *bi) bi->empty_edv = rt5025_battery_param2[4].x - 75; break; case 2: - bi->empty_edv = rt5025_battery_param2[4].x - 100 ; + bi->empty_edv = rt5025_battery_param2[4].x - 100; break; - } + } bi->edv_region = curr_region; - } - RTINFO("empty_voltage=%d\n", bi->empty_edv); - - if(bi->curr > 0) - { - bi->internal_status = POWER_SUPPLY_STATUS_CHARGING; - bi->last_tp_flag = false; - } - else - bi->internal_status = POWER_SUPPLY_STATUS_DISCHARGING; - RTINFO("current=%d, internal_status=%d\n", bi->curr, bi->internal_status); + } + RTINFO("empty_voltage=%d\n", bi->empty_edv); + + if (bi->curr > 0) { + bi->internal_status = POWER_SUPPLY_STATUS_CHARGING; + bi->last_tp_flag = false; + /*b. add fcc update flag; 2013/12/18*/ + bi->fcc_update_flag = true; + } else { + bi->internal_status = POWER_SUPPLY_STATUS_DISCHARGING; + } + RTINFO("current=%d, internal_status=%d\n", bi->curr, bi->internal_status); #if RT5025_CSV - // if (!bi->avg_flag) - // pr_info("%d,",bi->curr); + /*if (!bi->avg_flag)*/ + /*pr_info("%d,",bi->curr);*/ #else - if (bi->avg_flag) + if (bi->avg_flag) RTINFO("current_pre: %d\n", bi->curr); - else + else RTINFO("current_avg: %d\n", bi->curr); #endif } @@ -346,241 +363,228 @@ static void rt5025_get_internal_temp(struct rt5025_battery_info *bi) { u8 data[2]; s32 temp; - if (rt5025_read_reg(bi->client, RT5025_REG_INT_TEMPERATUE_MSB, data, 2) < 0){ - printk(KERN_ERR "%s: Failed to read internal TEMPERATURE\n", __func__); - } - temp = ((data[0]&0x1F)<<8) + data[1]; + if (rt5025_read_reg(bi->client, RT5025_REG_INTEMPH, data, 2) < 0) + pr_err("%s: Failed to read internal TEMPERATURE\n", __func__); + + temp = ((data[0] & 0x1F) << 8) + data[1]; temp *= 15625; temp /= 100000; - temp = (data[0]&0x20)?-temp:temp; + temp = (data[0] & 0x20) ? -temp : temp; bi->int_temp = temp; RTINFO("internal temperature: %d\n", bi->int_temp); } - + static void rt5025_get_external_temp(struct rt5025_battery_info *bi) { - u8 data[2]; - s32 temp; + u8 data[2]; + s32 temp; + + if (rt5025_read_reg(bi->client, RT5025_REG_AINH, data, 2) < 0) + pr_err("%s: Failed to read TEMPERATURE\n", __func__); + bi->ain_volt = (data[0] * 256 + data[1]) * 61 / 100; + if (bi->ain_volt < 1150) + bi->present = 1; + else + bi->present = 0; + + temp = (bi->ain_volt * (-91738) + 81521000) / 100000; + bi->ext_temp = (int)temp; + /*test bi->ext_temp = 250;*/ - if (rt5025_read_reg(bi->client, RT5025_REG_EXT_TEMPERATUE_MSB, data, 2) < 0) { - printk(KERN_ERR "%s: Failed to read TEMPERATURE\n", __func__); - } - bi->ain_volt = (data[0] * 256 + data[1]) * 61 / 100; - if(bi->ain_volt < 1150) - { - bi->present = 1; - } - else - { - bi->present = 0; - } - - temp = (bi->ain_volt * (-91738) + 81521000) / 100000; - bi->ext_temp = (int)temp; - //test - //bi->ext_temp = 250; - if (bi->ext_temp >= HIGH_TEMP_THRES) { if (bi->health != POWER_SUPPLY_HEALTH_OVERHEAT) bi->temp_high_cnt++; - } else if (bi->ext_temp <= HIGH_TEMP_RECOVER && bi->ext_temp >= LOW_TEMP_RECOVER) { + } else if (bi->ext_temp <= HIGH_TEMP_RECOVER + && bi->ext_temp >= LOW_TEMP_RECOVER) { if (bi->health == POWER_SUPPLY_HEALTH_OVERHEAT || - bi->health == POWER_SUPPLY_HEALTH_COLD) + bi->health == POWER_SUPPLY_HEALTH_COLD) bi->temp_recover_cnt++; } else if (bi->ext_temp <= LOW_TEMP_THRES) { if (bi->health != POWER_SUPPLY_HEALTH_COLD) bi->temp_low_cnt++; - }else { - bi->temp_high_cnt = 0; - bi->temp_low_cnt = 0; - bi->temp_recover_cnt = 0; + } else { + bi->temp_high_cnt = 0; + bi->temp_low_cnt = 0; + bi->temp_recover_cnt = 0; } - + if (bi->temp_high_cnt >= TEMP_ABNORMAL_COUNT) { - bi->health = POWER_SUPPLY_HEALTH_OVERHEAT; - bi->temp_high_cnt = 0; + bi->health = POWER_SUPPLY_HEALTH_OVERHEAT; + bi->temp_high_cnt = 0; } else if (bi->temp_low_cnt >= TEMP_ABNORMAL_COUNT) { - bi->health = POWER_SUPPLY_HEALTH_COLD; - bi->temp_low_cnt = 0; + bi->health = POWER_SUPPLY_HEALTH_COLD; + bi->temp_low_cnt = 0; } else if (bi->temp_recover_cnt >= TEMP_ABNORMAL_COUNT) { - bi->health = POWER_SUPPLY_HEALTH_GOOD; - bi->temp_recover_cnt = 0; + bi->health = POWER_SUPPLY_HEALTH_GOOD; + bi->temp_recover_cnt = 0; } RTINFO("external temperature: %d\n", bi->ext_temp); } static void rt5025_clear_cc(struct rt5025_battery_info *bi, operation_mode mode) -{ - u8 data[2]; - - if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ - pr_err("%s: failed to read channel\n", __func__); - } +{ + u8 data[2]; + + if (rt5025_read_reg(bi->client, RT5025_REG_CHANNELH, data, 2) < 0) + pr_err("%s: failed to read channel\n", __func__); - if (mode == CHG) + if (mode == CHG) data[0] = data[0] | CHANNEL_H_BIT_CLRQCHG; else data[0] = data[0] | CHANNEL_H_BIT_CLRQDCHG; - - if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_MSB, data, 2) < 0){ - pr_err("%s: failed to write channel\n", __func__); - } + + if (rt5025_write_reg(bi->client, RT5025_REG_CHANNELH, data, 2) < 0) + pr_err("%s: failed to write channel\n", __func__); } static void rt5025_get_chg_cc(struct rt5025_battery_info *bi) { - u8 data[4]; - u32 qh_old,ql_old,qh_new,ql_new; - u32 cc_masec,offset=0; - - if (rt5025_read_reg(bi->client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ - pr_err("%s: Failed to read QCHG\n", __func__); - } - qh_old = (data[0]<<8) + data[1]; - ql_old = (data[2]<<8) + data[3]; - RTINFO("qh_old=%d, ql_old=%d\n", qh_old, ql_old); - - if (rt5025_read_reg(bi->client, RT5025_REG_QCHGH_MSB, data, 4) < 0){ - pr_err("%s: Failed to read QCHG\n", __func__); - } - qh_new = (data[0]<<8) + data[1]; - ql_new = (data[2]<<8) + data[3]; - RTINFO("qh_new=%d, ql_new=%d\n", qh_new, ql_new); + u8 data[4]; + u32 qh_old, ql_old, qh_new, ql_new; + u32 cc_masec, offset = 0; + + if (rt5025_read_reg(bi->client, RT5025_REG_QCHGHH, data, 4) < 0) + pr_err("%s: Failed to read QCHG\n", __func__); + + qh_old = (data[0]<<8) + data[1]; + ql_old = (data[2]<<8) + data[3]; + RTINFO("qh_old=%d, ql_old=%d\n", qh_old, ql_old); + + if (rt5025_read_reg(bi->client, RT5025_REG_QCHGHH, data, 4) < 0) + pr_err("%s: Failed to read QCHG\n", __func__); + + qh_new = (data[0]<<8) + data[1]; + ql_new = (data[2]<<8) + data[3]; + RTINFO("qh_new=%d, ql_new=%d\n", qh_new, ql_new); #if RT5025_B - if (qh_new > qh_old){ - //cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - //cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; - }else { - //cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; - cc_masec = qh_old*328558+(qh_old*1824+ql_old*50134)/10000; + if (qh_new > qh_old) { + /*cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;*/ + cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; + } else if (qh_new == qh_old) { + if (ql_new >= ql_old) { + /*cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;*/ + cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; + } else { + /*cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;*/ + cc_masec = qh_old*328558+(qh_old*1824+ql_old*50134)/10000; } - } - - if (!bi->init_once) - offset = bi->curr_offset * bi->time_interval; - - if (cc_masec > offset){ + } + + if (!bi->init_once) + offset = bi->curr_offset * bi->time_interval; + if (cc_masec > offset) cc_masec = cc_masec - (offset / 1000); +#else + if (qh_new > qh_old) { + cc_masec = (((qh_new << 16) + ql_new) * 5996) / 1000; + } else if (qh_new == qh_old) { + if (ql_new >= ql_old) + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + else + cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; } -#else - if (qh_new > qh_old){ - cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; - }else { - cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; - } - } - + offset = (bi->curr_offset * bi->time_interval * 37375) / 100000; - - if (cc_masec != 0){ + + if (cc_masec != 0) cc_masec = cc_masec - offset; - } #endif if (cc_masec < (DEADBAND * bi->time_interval)) cc_masec = 0; #if RT5025_CSV - //pr_info("%d,\n", cc_masec); #else RTINFO("chg_cc_mAsec: %d\n", cc_masec); #endif - //if (!bi->init_once) - bi->chg_cc = cc_masec; - //bi->chg_cc = (cc_masec + bi->chg_cc_unuse) / 3600; - //bi->chg_cc_unuse = (cc_masec + bi->chg_cc_unuse) % 3600; - rt5025_clear_cc(bi, CHG); + /*if (!bi->init_once)*/ + bi->chg_cc = cc_masec; + /*bi->chg_cc = (cc_masec + bi->chg_cc_unuse) / 3600;*/ + /*bi->chg_cc_unuse = (cc_masec + bi->chg_cc_unuse) % 3600;*/ + rt5025_clear_cc(bi, CHG); } static void rt5025_get_dchg_cc(struct rt5025_battery_info *bi) { - u8 data[4]; - u32 qh_old,ql_old,qh_new,ql_new; - u32 cc_masec,offset=0; - - if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); - } - qh_old = (data[0]<<8) + data[1]; - ql_old = (data[2]<<8) + data[3]; - - if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGH_MSB, data, 4) < 0){ - printk(KERN_ERR "%s: Failed to read QDCHG\n", __func__); - } - qh_new = (data[0]<<8) + data[1]; - ql_new = (data[2]<<8) + data[3]; - + u8 data[4]; + u32 qh_old, ql_old, qh_new, ql_new; + u32 cc_masec, offset = 0; + + if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGHH, data, 4) < 0) + pr_err("%s: Failed to read QDCHG\n", + __func__); + + qh_old = (data[0] << 8) + data[1]; + ql_old = (data[2] << 8) + data[3]; + + if (rt5025_read_reg(bi->client, RT5025_REG_QDCHGHH, data, 4) < 0) + pr_err("%s: Failed to read QDCHG\n", + __func__); + + qh_new = (data[0] << 8) + data[1]; + ql_new = (data[2] << 8) + data[3]; + #if RT5025_B - if (qh_new > qh_old){ - //cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - //cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10; - cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; - }else { - //cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10; - cc_masec = qh_old*328558+(qh_old*1824+ql_old*50134)/10000; + if (qh_new > qh_old) { + /*cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;*/ + cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; + } else if (qh_new == qh_old) { + if (ql_new >= ql_old) { + /*cc_masec = (((qh_new<<16) + ql_new) * 50134) / 10;*/ + cc_masec = qh_new*328558+(qh_new*1824+ql_new*50134)/10000; + } else { + /*cc_masec = (((qh_old<<16) + ql_old) * 50134) / 10;*/ + cc_masec = qh_old*328558+(qh_old*1824+ql_old*50134)/10000; } - } - - if (!bi->init_once) - offset = bi->curr_offset * bi->time_interval; - - if (cc_masec != 0){ + } + if (!bi->init_once) + offset = bi->curr_offset * bi->time_interval; + if (cc_masec != 0) cc_masec = cc_masec + (offset / 1000); +#else + if (qh_new > qh_old) { + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + } else if (qh_new == qh_old) { + if (ql_new >= ql_old) + cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; + else + cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; } -#else - if (qh_new > qh_old){ - cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; - }else if (qh_new == qh_old){ - if (ql_new >= ql_old){ - cc_masec = (((qh_new<<16) + ql_new) * 5996) / 1000; - }else { - cc_masec = (((qh_old<<16) + ql_old) * 5996) / 1000; - } - } - + offset = (bi->curr_offset * bi->time_interval * 37375) / 100000; - - if (cc_masec > offset){ + + if (cc_masec > offset) cc_masec = cc_masec - offset; - } #endif if (cc_masec < (DEADBAND * bi->time_interval)) cc_masec = 0; - + #if RT5025_CSV - //pr_info("%d,", cc_masec); #else RTINFO("dchg_cc_mAsec: %d\n", cc_masec); #endif bi->dchg_cc = cc_masec; - if (bi->last_tp_flag) + /*b. add fcc update flag; 2013/12/18*/ + if ((bi->last_tp_flag) && (bi->fcc_update_flag)) bi->cal_fcc += cc_masec; else bi->cal_fcc = 0; - RTINFO("bi->cal_fcc=%d, bi->last_tp_flag=%d\n", bi->cal_fcc, bi->last_tp_flag); - //bi->dchg_cc = (cc_masec + bi->dchg_cc_unuse) / 3600; - //bi->dchg_cc_unuse = (cc_masec + bi->dchg_cc_unuse) % 3600; + + RTINFO("bi->cal_fcc=%d, bi->last_tp_flag=%d\n", + bi->cal_fcc, bi->last_tp_flag); + /*bi->dchg_cc = (cc_masec + bi->dchg_cc_unuse) / 3600;*/ + /*bi->dchg_cc_unuse = (cc_masec + bi->dchg_cc_unuse) % 3600;*/ rt5025_clear_cc(bi, DCHG); - + } static void rt5025_cycle_count(struct rt5025_battery_info *bi) { bi->acc_dchg_cap += bi->dchg_cc; - if(bi->acc_dchg_cap >= (bi->dc * 3600)){ + if (bi->acc_dchg_cap >= (bi->dc * 3600)) { bi->cycle_cnt++; bi->acc_dchg_cap -= (bi->dc * 3600); } @@ -589,113 +593,118 @@ static void rt5025_cycle_count(struct rt5025_battery_info *bi) static void rt5025_get_irq_flag(struct rt5025_battery_info *bi, u8 flag) { #if 0 - u8 data[1]; + u8 data[1]; - if (rt5025_read_reg(bi->client, RT5025_REG_IRQ_FLAG, data, 1) < 0){ - pr_err("%s: Failed to read irq_flag\n", __func__); - } + if (rt5025_read_reg(bi->client, RT5025_REG_IRQ_FLAG, data, 1) < 0) + pr_err("%s: Failed to read irq_flag\n", __func__); #endif - - bi->irq_flag = flag; - //RTINFO("IRQ_FLG 0x%x\n", bi->irq_flag); + bi->irq_flag = flag; + /*RTINFO("IRQ_FLG 0x%x\n", bi->irq_flag);*/ } static void rt5025_get_timer(struct rt5025_battery_info *bi) { - u8 data[2]; - //frankie - //u16 gauge_timer; - - if (rt5025_read_reg(bi->client, RT5025_REG_TIMER, data, 2) < 0){ - pr_err("%s: Failed to read Timer\n", __func__); - } - - bi->gauge_timer = (data[0] << 8) + data[1]; - if (!bi->device_suspend){ - if (bi->gauge_timer > bi->pre_gauge_timer) - bi->time_interval = bi->gauge_timer - bi->pre_gauge_timer; - else - bi->time_interval = 65536 - bi->pre_gauge_timer + bi->gauge_timer; - } - - bi->pre_gauge_timer = bi->gauge_timer; + u8 data[2]; + + if (rt5025_read_reg(bi->client, RT5025_REG_TIMERH, data, 2) < 0) + pr_err("%s: Failed to read Timer\n", __func__); + + bi->gauge_timer = (data[0] << 8) + data[1]; + if (!bi->device_suspend) { + if (bi->gauge_timer > bi->pre_gauge_timer) + bi->time_interval = bi->gauge_timer - bi->pre_gauge_timer; + else + bi->time_interval = 65536 - bi->pre_gauge_timer + bi->gauge_timer; + } + + bi->pre_gauge_timer = bi->gauge_timer; #if RT5025_CSV - // pr_info("%d,%d,", bi->gauge_timer,bi->time_interval); + /*pr_info("%d,%d,", bi->gauge_timer,bi->time_interval);*/ #else - RTINFO("timer %d , interval %d\n", bi->gauge_timer,bi->time_interval); + RTINFO("timer %d , interval %d\n", bi->gauge_timer, bi->time_interval); #endif } -static void rt5025_alert_setting(struct rt5025_battery_info *bi, alert_type type, bool enable) +static void rt5025_alert_setting(struct rt5025_battery_info *bi, + alert_type type, bool enable) { u8 data[1]; - - if (rt5025_read_reg(bi->client, RT5025_REG_IRQ_CTL, data, 1) < 0){ - printk(KERN_ERR "%s: Failed to read CONFIG\n", __func__); - } - if(enable){ - switch(type){ - case MAXTEMP: - data[0] |= IRQ_CTL_BIT_TMX; //Enable max temperature alert - bi->max_temp_irq = true; - //RTDBG("Enable min temperature alert"); - break; - case MINTEMP: - data[0] |= IRQ_CTL_BIT_TMN; //Enable min temperature alert - bi->min_temp_irq = true; - //RTDBG("Enable max temperature alert"); - break; - case MAXVOLT: - data[0] |= IRQ_CTL_BIT_VMX; //Enable max voltage alert - bi->max_volt_irq = true; - //RTDBG("Enable max voltage alert"); - break; - case MINVOLT1: - data[0] |= IRQ_CTL_BIT_VMN1; //Enable min1 voltage alert - bi->min_volt1_irq = true; - //RTDBG("Enable min1 voltage alert"); - break; - case MINVOLT2: - data[0] |= IRQ_CTL_BIT_VMN2; //Enable min2 voltage alert - bi->min_volt2_irq = true; - //RTDBG("Enable min2 voltage alert"); - break; - default: - break; + if (rt5025_read_reg(bi->client, RT5025_REG_IRQCTL, data, 1) < 0) + pr_err("%s: Failed to read CONFIG\n", __func__); + + if (enable) { + switch (type) { + case MAXTEMP: + data[0] |= IRQ_CTL_BIT_TMX; + /*Enable max temperature alert*/ + bi->max_temp_irq = true; + /*RTDBG("Enable min temperature alert");*/ + break; + case MINTEMP: + data[0] |= IRQ_CTL_BIT_TMN; + /*Enable min temperature alert*/ + bi->min_temp_irq = true; + /*RTDBG("Enable max temperature alert");*/ + break; + case MAXVOLT: + data[0] |= IRQ_CTL_BIT_VMX; + /*Enable max voltage alert*/ + bi->max_volt_irq = true; + /*RTDBG("Enable max voltage alert");*/ + break; + case MINVOLT1: + data[0] |= IRQ_CTL_BIT_VMN1; + /*Enable min1 voltage alert*/ + bi->min_volt1_irq = true; + /*RTDBG("Enable min1 voltage alert");*/ + break; + case MINVOLT2: + data[0] |= IRQ_CTL_BIT_VMN2; + /*Enable min2 voltage alert*/ + bi->min_volt2_irq = true; + /*RTDBG("Enable min2 voltage alert");*/ + break; + default: + break; } - }else{ - switch(type){ - case MAXTEMP: - data[0] = data[0] &~ IRQ_CTL_BIT_TMX; //Disable max temperature alert - bi->max_temp_irq = false; - //RTDBG("Disable min temperature alert"); - break; - case MINTEMP: - data[0] = data[0] &~ IRQ_CTL_BIT_TMN; //Disable min temperature alert - bi->min_temp_irq = false; - //RTDBG("Disable max temperature alert"); - break; - case MAXVOLT: - data[0] = data[0] &~ IRQ_CTL_BIT_VMX; //Disable max voltage alert - bi->max_volt_irq = false; - //RTDBG("Disable max voltage alert"); - break; - case MINVOLT1: - data[0] = data[0] &~ IRQ_CTL_BIT_VMN1; //Disable min1 voltage alert - bi->min_volt1_irq = false; - //RTDBG("Disable min1 voltage alert"); - break; - case MINVOLT2: - data[0] = data[0] &~ IRQ_CTL_BIT_VMN2; //Disable min2 voltage alert - bi->min_volt2_irq = false; - //RTDBG("Disable min2 voltage alert"); - break; - default: - break; + } else { + switch (type) { + case MAXTEMP: + data[0] = data[0] & ~IRQ_CTL_BIT_TMX; + /*Disable max temperature alert*/ + bi->max_temp_irq = false; + /*RTDBG("Disable min temperature alert");*/ + break; + case MINTEMP: + data[0] = data[0] & ~IRQ_CTL_BIT_TMN; + /*Disable min temperature alert*/ + bi->min_temp_irq = false; + /*RTDBG("Disable max temperature alert");*/ + break; + case MAXVOLT: + data[0] = data[0] & ~IRQ_CTL_BIT_VMX; + /*Disable max voltage alert*/ + bi->max_volt_irq = false; + /*RTDBG("Disable max voltage alert");*/ + break; + case MINVOLT1: + data[0] = data[0] & ~IRQ_CTL_BIT_VMN1; + /*Disable min1 voltage alert*/ + bi->min_volt1_irq = false; + /*RTDBG("Disable min1 voltage alert");*/ + break; + case MINVOLT2: + data[0] = data[0] & ~IRQ_CTL_BIT_VMN2; + /*Disable min2 voltage alert*/ + bi->min_volt2_irq = false; + /*RTDBG("Disable min2 voltage alert");*/ + break; + default: + break; } } - if (rt5025_write_reg(bi->client, RT5025_REG_IRQ_CTL, data, 1) < 0) + if (rt5025_write_reg(bi->client, RT5025_REG_IRQCTL, data, 1) < 0) pr_err("%s: failed to write IRQ control\n", __func__); } @@ -703,28 +712,21 @@ static void rt5025_alert_threshold_init(struct i2c_client *client) { u8 data[1]; - #if 0 //change the operating right to jeita driver - /* TALRT MAX threshold setting */ - data[0] = irq_thres[MAXTEMP]; - if (rt5025_write_reg(client, RT5025_REG_TALRT_MAXTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write TALRT MAX threshold\n", __func__); - /* TALRT MIN threshold setting */ - data[0] = irq_thres[MINTEMP]; - if (rt5025_write_reg(client, RT5025_REG_TALRT_MINTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write TALRT MIN threshold\n", __func__); - #endif /* VALRT MAX threshold setting */ data[0] = irq_thres[MAXVOLT]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MAXTH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MAX threshold\n", __func__); + if (rt5025_write_reg(client, RT5025_REG_VALRTMAX, data, 1) < 0) + pr_err("%s: failed to write VALRT MAX threshold\n", + __func__); /* VALRT MIN1 threshold setting */ data[0] = irq_thres[MINVOLT1]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN1TH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MIN1 threshold\n", __func__); + if (rt5025_write_reg(client, RT5025_REG_VALRTMIN1, data, 1) < 0) + pr_err("%s: failed to write VALRT MIN1 threshold\n", + __func__); /* VALRT MIN2 threshold setting */ data[0] = irq_thres[MINVOLT2]; - if (rt5025_write_reg(client, RT5025_REG_VALRT_MIN2TH, data, 1) < 0) - printk(KERN_ERR "%s: failed to write VALRT MIN2 threshold\n", __func__); + if (rt5025_write_reg(client, RT5025_REG_VALRTMIN2, data, 1) < 0) + pr_err("%s: failed to write VALRT MIN2 threshold\n", + __func__); } static void rt5025_alert_init(struct rt5025_battery_info *bi) @@ -733,115 +735,146 @@ static void rt5025_alert_init(struct rt5025_battery_info *bi) /* Set RT5025 gauge alert configuration */ rt5025_alert_threshold_init(bi->client); /* Enable gauge alert function */ - //rt5025_alert_setting(bi, MINVOLT2,VOLTAGE_ALERT); + rt5025_alert_setting(bi, MINVOLT2, VOLTAGE_ALERT); } -void rt5025_gauge_irq_handler(struct rt5025_battery_info *bi, u8 irq_flag) +void rt5025_gauge_irq_handler(struct rt5025_battery_info *bi, + unsigned int irq_flag) { - rt5025_get_irq_flag(bi, irq_flag); + rt5025_get_irq_flag(bi, irq_flag); - if ((bi->irq_flag) & IRQ_FLG_BIT_TMX){ - //printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n"); - rt5025_alert_setting(bi,MAXTEMP,false); + if ((bi->irq_flag) & IRQ_FLG_BIT_TMX) { + /*printk(KERN_INFO "[RT5025]: Min temperature IRQ received\n");*/ + rt5025_alert_setting(bi, MAXTEMP, false); bi->max_temp_irq = false; } - if ((bi->irq_flag) & IRQ_FLG_BIT_TMN){ - //printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n"); - rt5025_alert_setting(bi,MINTEMP,false); - bi->min_temp_irq = false; + if ((bi->irq_flag) & IRQ_FLG_BIT_TMN) { + /*printk(KERN_INFO "[RT5025]: Max temperature IRQ received\n");*/ + rt5025_alert_setting(bi, MINTEMP, false); + bi->min_temp_irq = false; } - if ((bi->irq_flag) & IRQ_FLG_BIT_VMX){ - //printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n"); - rt5025_alert_setting(bi,MAXVOLT,false); + if ((bi->irq_flag) & IRQ_FLG_BIT_VMX) { + /*printk(KERN_INFO "[RT5025]: Max voltage IRQ received\n");*/ + rt5025_alert_setting(bi, MAXVOLT, false); bi->max_volt_irq = false; } - if ((bi->irq_flag) & IRQ_FLG_BIT_VMN1){ - //printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n"); - rt5025_alert_setting(bi,MINVOLT1,false); + if ((bi->irq_flag) & IRQ_FLG_BIT_VMN1) { + /*printk(KERN_INFO "[RT5025]: Min voltage1 IRQ received\n");*/ + rt5025_alert_setting(bi, MINVOLT1, false); bi->min_volt1_irq = false; } - if ((bi->irq_flag) & IRQ_FLG_BIT_VMN2){ - //printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n"); - rt5025_alert_setting(bi,MINVOLT2,false); + if ((bi->irq_flag) & IRQ_FLG_BIT_VMN2) { + /*printk(KERN_INFO "[RT5025]: Min voltage2 IRQ received\n");*/ + rt5025_alert_setting(bi, MINVOLT2, false); bi->min_volt2_irq = false; bi->min_volt2_alert = true; wake_lock_timeout(&bi->low_battery_wake_lock, msecs_to_jiffies(LOW_BAT_WAKE_LOK_TIME*MSEC_PER_SEC)); } - - //wake_lock(&bi->monitor_wake_lock); - wake_lock_timeout(&bi->status_wake_lock, 1.5*HZ); - schedule_delayed_work(&bi->monitor_work, 0); } EXPORT_SYMBOL(rt5025_gauge_irq_handler); static void rt5025_convert_masec_to_permille(struct rt5025_battery_info *bi) { - bi->permille = bi->rm / 3600 * 1000 / bi->fcc; - RTINFO("permille=%d\n", bi->permille); - return; + bi->permille = bi->rm / 3600 * 1000 / bi->fcc; + RTINFO("permille=%d\n", bi->permille); + /*return;*/ } static void rt5025_convert_permille_to_masec(struct rt5025_battery_info *bi) -{ - bi->rm = bi->permille * bi->fcc / 1000 * 3600; - return; +{ + bi->rm = bi->permille * bi->fcc / 1000 * 3600; + /*return;*/ } static void rt5025_init_capacity(struct rt5025_battery_info *bi) { - int i = 1; - int size; - int slope, const_term; - int delta_y, delta_x; - - size = ARRAY_SIZE(rt5025_battery_param1); - while((bi->vcell < rt5025_battery_param1[i].x) && - (i < (size - 1))){ - i++; - } + int i = 1; + int size; + int slope, const_term; + int delta_y, delta_x; - delta_x = rt5025_battery_param1[i-1].x - rt5025_battery_param1[i].x; - delta_y = (rt5025_battery_param1[i-1].y - rt5025_battery_param1[i].y); + size = ARRAY_SIZE(rt5025_battery_param1); + while ((bi->vcell < rt5025_battery_param1[i].x) && + (i < (size - 1))) { + i++; + } - slope = delta_y * 1000 / delta_x; + delta_x = rt5025_battery_param1[i-1].x - rt5025_battery_param1[i].x; + delta_y = (rt5025_battery_param1[i-1].y - rt5025_battery_param1[i].y); - const_term = (rt5025_battery_param1[i].y) - ((rt5025_battery_param1[i].x * slope) / 1000); + slope = delta_y * 1000 / delta_x; - if (bi->vcell >= rt5025_battery_param1[0].x) - bi->permille = rt5025_battery_param1[0].y; - else if (bi->vcell <= rt5025_battery_param1[size-1].x) - bi->permille = rt5025_battery_param1[size-1].y; - else - bi->permille = (bi->vcell * slope) / 1000 + const_term; - rt5025_convert_permille_to_masec(bi); - bi->soc = bi->rm /36/bi->fcc_aging; + const_term = (rt5025_battery_param1[i].y) - ((rt5025_battery_param1[i].x * slope) / 1000); + + if (bi->vcell >= rt5025_battery_param1[0].x) + bi->permille = rt5025_battery_param1[0].y; + else if (bi->vcell <= rt5025_battery_param1[size-1].x) + bi->permille = rt5025_battery_param1[size-1].y; + else + bi->permille = (bi->vcell * slope) / 1000 + const_term; + rt5025_convert_permille_to_masec(bi); + bi->soc = bi->rm / 36 / bi->fcc_aging; bi->init_cap = false; - rt5025_battery_parameter_backup(bi); + rt5025_battery_parameter_backup(bi); - //pr_err("[rt5025] i=%d, delta_x=%d, delta_y=%d, slope=%d, const_term=%d\n", i, delta_x, delta_y, slope, const_term); - RTINFO("voltage=%d, permille=%d, soc=%d, rm=%d\n", bi->vcell, bi->permille, bi->soc, bi->rm); - return; + RTINFO("voltage=%d, permille=%d, soc=%d, rm=%d\n", + bi->vcell, bi->permille, bi->soc, bi->rm); + /*return;*/ } static void rt5025_smooth_soc(struct rt5025_battery_info *bi) { - if ((bi->internal_status == POWER_SUPPLY_STATUS_CHARGING || bi->tp_flag == 1) && - (bi->soc < 100)) - { - bi->soc++; + if ((bi->internal_status == POWER_SUPPLY_STATUS_CHARGING || bi->tp_flag) && + (bi->soc < 100)) { + if (bi->last_suspend == true) { + bi->soc = 100; + bi->last_suspend = false; + } else { + bi->soc++; + } bi->rm = bi->fcc * bi->soc * 36; rt5025_convert_masec_to_permille(bi); - } - else if ((bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && - (bi->soc > 0)) - { - bi->soc--; + + if (bi->soc == 100) { + /*fcc update in soc smooth 100%.*/ + if (bi->cal_soc_offset != 0) { + bi->fcc_aging -= bi->cal_soc_offset; + if ((200 <= bi->ext_temp) && (bi->ext_temp <= 300)) { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc * bi->soc * 36; + } else { + rt5025_temp_comp(bi); + } + bi->cal_soc_offset = 0; + } + wake_unlock(&bi->smooth100_wake_lock); + bi->last_tp = true; + bi->tp_flag = false; + bi->pre_soc = bi->soc; + + /*c. Only EOC occurs and full discharge to update FCC; 2013/12/17*/ + bi->last_tp_flag = true; + mutex_lock(&bi->status_change_lock); + if (bi->status != POWER_SUPPLY_STATUS_DISCHARGING) { + bi->status = POWER_SUPPLY_STATUS_FULL; + rt5025_set_battery_led(bi, bi->status); + } + mutex_unlock(&bi->status_change_lock); + } + } else if ((bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && + (bi->soc > 0)) { + if (bi->last_suspend == true) { + bi->soc = 0; + bi->last_suspend = false; + } else { + bi->soc--; + } bi->rm = bi->fcc * bi->soc * 36; rt5025_convert_masec_to_permille(bi); - } - else - { + if (bi->soc == 0) + wake_unlock(&bi->smooth0_wake_lock); + } else { bi->smooth_flag = false; bi->update_time = NORMAL_POLL; } @@ -850,343 +883,289 @@ static void rt5025_smooth_soc(struct rt5025_battery_info *bi) static void rt5025_soc_irreversible(struct rt5025_battery_info *bi) { - // Prevent inverse - //if (!bi->init_cap){ - if (!bi->init_once){ - if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) - { + if (!bi->init_once) { + if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) { if (bi->soc < bi->pre_soc) bi->soc = bi->pre_soc; - } - else if ((bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && - (bi->tp_flag == 0)) - { - if (bi->soc > bi->pre_soc) + } else if ((bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && + (bi->tp_flag == 0)) { + if (bi->soc > bi->pre_soc) bi->soc = bi->pre_soc; } - } - else + } else { bi->init_once = false; + } if (bi->pre_soc != bi->soc) rt5025_battery_parameter_backup(bi); bi->pre_soc = bi->soc; - RTINFO("pre_soc=%d, soc=%d, internal status=%d\n", bi->pre_soc,bi->soc,bi->internal_status); + RTINFO("pre_soc=%d, soc=%d, internal status=%d\n", + bi->pre_soc, bi->soc, bi->internal_status); } static void rt5025_soc_lock(struct rt5025_battery_info *bi) { - // lock 99% - RTINFO("internal status=%d, tp_flag=%d, soc=%d\n", bi->internal_status, bi->tp_flag, bi->soc); - if (bi->soc >= 99) - { - if (bi->tp_flag) - bi->soc = 100; - else if(bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) - { - bi->soc = 99; - bi->pre_soc = 99; + /*lock 99%*/ + u16 eoc_fcc_new = 0; + + RTINFO("internal status=%d, tp_flag=%d, soc=%d, soc99_lock_cnt=%d\n", + bi->internal_status, bi->tp_flag, bi->soc, + bi->soc99_lock_cnt); + RTINFO("init_once=%d, rm=%d, soc=%d\n", + bi->init_once, bi->rm, bi->soc); + + if (bi->soc >= 99) { + if (bi->soc99_lock_cnt >= 3600) { + bi->soc = 100; + bi->permille = 1000; + /*eoc fcc update function: when flag is true, update FCC.*/ + if (bi->cal_eoc_fcc != 0) { + /*eoc fcc update function: fcc update limitation 3%*/ + eoc_fcc_new = bi->fcc_aging + bi->cal_eoc_fcc / 3600; + if (eoc_fcc_new > ((bi->fcc_aging * 103) / 100)) + bi->fcc_aging = (bi->fcc_aging * 103) / 100; + else + bi->fcc_aging = eoc_fcc_new; + + if ((200 <= bi->ext_temp) && (bi->ext_temp <= 300)) { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc * bi->permille * 36 / 10; + } else { + rt5025_temp_comp(bi); + } + bi->cal_eoc_fcc = 0; + } + wake_unlock(&bi->full_battery_wake_lock); + bi->soc99_lock_cnt = 0; + bi->last_tp = true; + bi->tp_flag = false; + bi->pre_soc = bi->soc; + /*b. add fcc update flag; 2013/12/18*/ + bi->fcc_update_flag = false; + + /*a. When SOC = 100, report battery status is full; 2013/12/17 + bi->status = POWER_SUPPLY_STATUS_FULL; + */ + } else if (bi->tp_flag) { + RTINFO("before_eoc_fcc_new=%d\n", eoc_fcc_new); + RTINFO("before_cal_eoc_fcc=%d\n", bi->cal_eoc_fcc); + RTINFO("before_fcc_aging=%d\n", bi->fcc_aging); + bi->soc = 100; + bi->permille = 1000; + if (bi->cal_eoc_fcc != 0) { + /*fcc update in eoc occurs. */ + eoc_fcc_new = bi->fcc_aging + bi->cal_eoc_fcc/3600; + if (eoc_fcc_new > ((bi->fcc_aging*103)/100)) + bi->fcc_aging = (bi->fcc_aging*103)/100; + else + bi->fcc_aging = eoc_fcc_new; + + RTINFO("after_eoc_fcc_new=%d\n", eoc_fcc_new); + RTINFO("after_cal_eoc_fcc=%d\n", bi->cal_eoc_fcc); + RTINFO("after_fcc_aging=%d\n", bi->fcc_aging); + if ((200 <= bi->ext_temp) && (bi->ext_temp <= 300)) { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc * bi->permille * 36 / 10; + } else { + rt5025_temp_comp(bi); + } + bi->cal_eoc_fcc = 0; + } else if (bi->cal_soc_offset != 0) { + bi->fcc_aging -= bi->cal_soc_offset; + if ((200 <= bi->ext_temp) && (bi->ext_temp <= 300)) { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc * bi->permille * 36 / 10; + } else { + rt5025_temp_comp(bi); + } + bi->cal_soc_offset = 0; + } + + wake_unlock(&bi->full_battery_wake_lock); + bi->soc99_lock_cnt = 0; + bi->last_tp = true; + bi->tp_flag = false; + bi->pre_soc = bi->soc; + + /*c. Only EOC occurs and full discharge to update FCC; 2013/12/17*/ + bi->last_tp_flag = true; + + mutex_lock(&bi->status_change_lock); + if (bi->status != POWER_SUPPLY_STATUS_DISCHARGING) { + bi->status = POWER_SUPPLY_STATUS_FULL; + rt5025_set_battery_led(bi, bi->status); + } + mutex_unlock(&bi->status_change_lock); + } else if ((bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) && + (bi->last_tp == false)) { + bi->soc = 99; + bi->pre_soc = 99; + bi->soc99_lock_cnt += bi->time_interval; } - } - else if ((bi->soc < 99) && (bi->tp_flag)) - { - if (!bi->last_suspend) - { - bi->update_time = SMOOTH_POLL; - bi->smooth_flag = true; - rt5025_smooth_soc(bi); + } else if ((bi->soc < 99) && (bi->tp_flag)) { + /*calculate soc offset */ + if (bi->cal_soc_offset == 0) { + bi->cal_soc_offset = bi->fcc*3600 - bi->rm; + if (bi->cal_soc_offset > (bi->fcc_aging*3/100)) + bi->cal_soc_offset = bi->fcc_aging*3/100; } - else - bi->last_suspend=false; - } - else - { + wake_lock(&bi->smooth100_wake_lock); + bi->update_time = SMOOTH_POLL; + bi->smooth_flag = true; + rt5025_smooth_soc(bi); + } else { + wake_unlock(&bi->smooth100_wake_lock); bi->tp_flag = false; - } - - // lock 1% - if ((bi->soc <= 1) && - (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING)){ - if (bi->edv_flag) - bi->soc = 0; - else - { - bi->soc = 1; - bi->pre_soc = 1; + bi->soc99_lock_cnt = 0; + } + /* a. When SOC = 100, report battery status is full; 2013/12/17 + /// a. judge charging status to check battery full condition; 2013/12/18*/ + if ((bi->soc == 100) && + (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING)) { + mutex_lock(&bi->status_change_lock); + if (bi->status != POWER_SUPPLY_STATUS_DISCHARGING) { + bi->status = POWER_SUPPLY_STATUS_FULL; + rt5025_set_battery_led(bi, bi->status); } - - }else if ((bi->soc > 1) && - (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && - (bi->edv_flag)){ - if (!bi->last_suspend) - { - bi->update_time = SMOOTH_POLL; - bi->smooth_flag = true; - rt5025_smooth_soc(bi); + mutex_unlock(&bi->status_change_lock); + } + + /*lock 1% */ + if ((bi->soc <= 1) && + (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING)) { + if (bi->edv_flag) { + bi->soc = 0; + } else { + if (bi->rm <= 0) { + bi->soc1_lock_cnt += bi->time_interval; + if (bi->soc1_lock_cnt >= 600) { + bi->soc = 0; + bi->soc1_lock_cnt = 0; + } else { + bi->soc = 1; + bi->pre_soc = 1; + } + } else { + bi->soc = 1; + bi->pre_soc = 1; + bi->soc1_lock_cnt = 0; + } } - else - bi->last_suspend=false; - }else{ + } else if ((bi->soc > 1) && + (bi->internal_status == POWER_SUPPLY_STATUS_DISCHARGING) && + (bi->edv_flag)) { + wake_lock(&bi->smooth0_wake_lock); + bi->update_time = SMOOTH_POLL; + bi->smooth_flag = true; + rt5025_smooth_soc(bi); + } else { bi->edv_flag = false; + wake_unlock(&bi->smooth0_wake_lock); } + RTINFO("cal_soc_offset=%d\n", bi->cal_soc_offset); } static void rt5025_get_soc(struct rt5025_battery_info *bi) { - if (bi->smooth_flag){ - bi->smooth_flag = false; - bi->update_time = NORMAL_POLL; - } + if (bi->smooth_flag) { + bi->smooth_flag = false; + bi->update_time = NORMAL_POLL; + } RTINFO("before rm=%d\n", bi->rm); - if ((!bi->tp_flag) && - (!bi->edv_flag)){ - bi->rm = (bi->rm + bi->chg_cc) > bi->dchg_cc ? - bi->rm + bi->chg_cc - bi->dchg_cc : 0; + if ((!bi->tp_flag) && (!bi->edv_flag)) { + bi->rm = (bi->rm + bi->chg_cc) > bi->dchg_cc ? + bi->rm + bi->chg_cc - bi->dchg_cc : 0; if (bi->rm > (bi->fcc * 3600)) - bi->rm = bi->fcc * 3600; + bi->rm = bi->fcc * 3600; + + /* accumulate coulomb counter when rm = fcc and enable flag = true.*/ + if (bi->rm == (bi->fcc * 3600)) + bi->cal_eoc_fcc += (bi->chg_cc - bi->dchg_cc); + else + bi->cal_eoc_fcc = 0; + + RTINFO("cal_eoc_fcc=%d\n", bi->cal_eoc_fcc); rt5025_convert_masec_to_permille(bi); + /*a. When SOC = 100, report battery status is full; 2113/12/17*/ bi->soc = DIV_ROUND_UP(bi->permille, 10); + } #if RT5025_CSV - bi->temp_soc = bi->soc; - //pr_info("%d", bi->soc); + bi->temp_soc = bi->soc; + /*pr_info("%d", bi->soc);*/ #else RTINFO("after rm=%d\n", bi->rm); - RTINFO("temp_soc=%d\n", bi->soc); + RTINFO("temp_soc=%d\n", bi->soc); #endif - } #if RT5025_CSV - RTINFO("soc=%d, permille=%d, rm=%d, fcc=%d, smooth_flag=%d\n", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag); - // pr_info("%d,%d,%d,%d,%d", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag); -#else - RTINFO("soc=%d, permille=%d, rm=%d, fcc=%d, smooth_flag=%d\n", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag); + RTINFO("soc=%d, permille=%d, rm=%d, fcc=%d, smooth_flag=%d\n", + bi->soc, bi->permille, bi->rm, + bi->fcc, bi->smooth_flag); + /*pr_info("%d,%d,%d,%d,%d", bi->soc,bi->permille,bi->rm,bi->fcc,bi->smooth_flag);*/ +#else + RTINFO("soc=%d, permille=%d, rm=%d, fcc=%d, smooth_flag=%d\n", + bi->soc, bi->permille, bi->rm, + bi->fcc, bi->smooth_flag); #endif - return; + /*return;*/ } static void rt5025_soc_relearn_check(struct rt5025_battery_info *bi) { - // TP relearn -/* if ((bi->vcell >= TP_VOLT) && - (bi->curr <= TP_CURR) && - (bi->status == POWER_SUPPLY_STATUS_CHARGING) && - (!bi->tp_flag)){ - bi->tp_cnt++; - bi->update_time = TP_POLL; - }else { - bi->tp_cnt = 0; - bi->update_time = NORMAL_POLL; - } - - if (bi->tp_cnt == TP_TOTAL_COUNT){ - bi->tp_cnt = 0; - bi->tp_flag = true; - bi->rm = bi->fcc * 3600; - rt5025_convert_masec_to_permille(); - bi->update_time = NORMAL_POLL; - }*/ - - // if EOC happened, the tp_flag should be set 1. - if(bi->tp_flag == true) - { + + if (bi->tp_flag == true) { bi->rm = bi->fcc * 3600; rt5025_convert_masec_to_permille(bi); bi->update_time = NORMAL_POLL; } - if (bi->vcell <= bi->empty_edv) - { + if (bi->vcell <= bi->empty_edv) { if (bi->edv_cnt < 2) bi->edv_cnt++; + } else { + bi->edv_cnt = 0; } - else - bi->edv_cnt=0; - - if(bi->empty_edv < bi->vcell && bi->vcell <= bi->empty_edv+300) - { + + if (bi->empty_edv < bi->vcell && bi->vcell <= bi->empty_edv + 300) { bi->update_time = EDV_POLL; bi->edv_detection = true; - } - else if((bi->vcell >= bi->empty_edv + 300 +EDV_HYS) && (bi->edv_detection == true)) - { + } else if ((bi->vcell >= bi->empty_edv + 300 + EDV_HYS) + && (bi->edv_detection == true)) { bi->update_time = NORMAL_POLL; - bi->edv_detection = false; - } - else if((bi->vcell <= bi->empty_edv && bi->edv_cnt == 2)) //&& (bi->min_volt2_alert == true)) - { + bi->edv_detection = false; + } else if ((bi->vcell <= bi->empty_edv && bi->edv_cnt == 2)) { bi->edv_flag = true; bi->rm = 0; rt5025_convert_masec_to_permille(bi); bi->edv_detection = false; bi->update_time = NORMAL_POLL; - } - else if((bi->vcell > bi->empty_edv + EDV_HYS)) //&& (bi->min_volt2_alert == true)) - { + } else if ((bi->vcell > bi->empty_edv + EDV_HYS)) { bi->min_volt2_alert = false; bi->edv_flag = false; } - - /*// EDV relearn - if (bi->vcell <= EDV_VOLT){ - if ((bi->curr <= EDV_CURR) || - (bi->vcell <= rt5025_battery_param2[4].x)) - bi->edv_cnt++; - else - { - bi->edv_cnt = 0; - } - bi->edv_detection = true; - bi->update_time = EDV_POLL; - }else if ((bi->vcell > (EDV_VOLT + EDV_HYS)) && - (bi->edv_detection)) { - bi->edv_cnt = 0; - bi->edv_detection = false; + + if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) bi->edv_flag = false; - bi->update_time = NORMAL_POLL; - } - else - { - bi->edv_cnt = 0; - } - - if (bi->edv_cnt == EDV_TOTAL_COUNT){ - bi->edv_cnt = 0; - bi->edv_flag = true; - bi->rm = 0; - rt5025_convert_masec_to_permille(); - bi->edv_detection = false; - bi->update_time = NORMAL_POLL; - } - if(bi->edv_detection) - { - bi->update_time = EDV_POLL; - }*/ - if (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING) - bi->edv_flag = false; - if (bi->status != POWER_SUPPLY_STATUS_FULL) - bi->tp_flag = false; #if RT5025_CSV - //pr_err("%d,%d,%d,%d,%d", - // bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag); -#else - RTINFO("tp_cnt=%d, tp_flag=%d, edv_detection=%d, edv_cnt=%d, edv_flag=%d\n", - bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag); -#endif - - return; -} - -#if 0 -static void rt5025_channel_cc(struct rt5025_battery_info *bi, bool enable) -{ - u8 data[1]; - - if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk(KERN_INFO "%s: failed to read channel\n", __func__); - } - - if (enable){ - data[0] = data[0] | 0x80; - }else { - data[0] = data[0] & 0x7F; - } - - if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ - printk(KERN_INFO "%s: failed to write channel\n", __func__); - } -} +#else + RTINFO("tp_cnt=%d, tp_flag=%d, edv_detection=%d, edv_cnt=%d, edv_flag=%d\n", + bi->tp_cnt, bi->tp_flag, bi->edv_detection, + bi->edv_cnt, bi->edv_flag); #endif -#if 0 -static void rt5025_pretrim(struct rt5025_battery_info *bi) -{ - u8 data0[2]; - u8 data1[1]; - - data0[0] = 0x55; - data0[1] = 0xAA; - if (rt5025_write_reg(bi->client, 0xF0, data0, 2) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - data0[0] = 0x07; - if (rt5025_write_reg(bi->client, 0xF1, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // write trim data D0 - data0[0] = 0xDE; - if (rt5025_write_reg(bi->client, 0xD0, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // Read back to verify - if (rt5025_read_reg(bi->client, 0xD0, data1, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - if (data1[0] != data0[0]) - printk(KERN_ERR "%s: 0xD0 write fail\n", __func__); - // write trim data D1 - data0[0] = 0x01; - if (rt5025_write_reg(bi->client, 0xD1, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // Read back to verify - if (rt5025_read_reg(bi->client, 0xD1, data1, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - if (data1[0] != data0[0]) - printk(KERN_ERR "%s: 0xD1 write fail\n", __func__); - // write trim data D2 - data0[0] = 0x10; - if (rt5025_write_reg(bi->client, 0xD2, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // Read back to verify - if (rt5025_read_reg(bi->client, 0xD2, data1, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - if(data1[0] != data0[0]) - printk(KERN_ERR "%s: 0xD2 write fail\n", __func__); - // write trim data D3 - data0[0] = 0x89; - if (rt5025_write_reg(bi->client, 0xD3, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // Read back to verify - if (rt5025_read_reg(bi->client, 0xD3, data1, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - if(data1[0] != data0[0]) - printk(KERN_ERR "%s: 0xD3 write fail\n", __func__); - // write trim data D4 - data0[0] = 0xF2; - if (rt5025_write_reg(bi->client, 0xD4, data0, 1) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } - // Read back to verify - if (rt5025_read_reg(bi->client, 0xD4, data1, 1) < 0){ - printk(KERN_ERR "%s: failed to read channel\n", __func__); - } - if (data1[0] != data0[0]) - printk(KERN_ERR "%s: 0xD4 write fail\n", __func__); - - data0[0] = 0x55; - data0[1] = 0x55; - if (rt5025_write_reg(bi->client, 0xF0, data0, 2) < 0){ - printk(KERN_ERR "%s: failed to write channel\n", __func__); - } + /* return;*/ } -#endif -static u16 get_crc16_value(u8* data, int size) +static u16 get_crc16_value(u8 *data, int size) { u16 fcs = 0xffff; int len = size; int i = 0; u16 temp = 0; - while (len > 0) - { - fcs = (u16)((fcs>>8)^crctab16[(fcs^data[i])&0xff]); + while (len > 0) { + fcs = (u16)((fcs >> 8) ^ crctab16[(fcs ^ data[i]) & 0xff]); len--; i++; } @@ -1194,15 +1173,14 @@ static u16 get_crc16_value(u8* data, int size) return temp; } -static int IsCrc16Good(u8* data, int size) +static int IsCrc16Good(u8 *data, int size) { u16 fcs = 0xffff; int len = size; int i = 0; - while (len>0) - { - fcs = (u16)((fcs>>8)^crctab16[((fcs^data[i])&0xff)]); + while (len > 0) { + fcs = (u16)((fcs >> 8) ^ crctab16[((fcs ^ data[i]) & 0xff)]); len--; i++; } @@ -1212,76 +1190,66 @@ static int IsCrc16Good(u8* data, int size) static int rt5025_battery_parameter_backup(struct rt5025_battery_info *bi) { u16 crc_value = 0; - u8 data[12]= {0}; + u8 data[15] = {0}; + RTINFO("\n"); - //backup fcc_aging, rm, cycle_count, acc_dchg_cap - //fcc_aging - data[0] = (bi->fcc_aging>>8)&0xff; - data[1] = (bi->fcc_aging)&0xff; - rt5025_write_reg(bi->client, 0x21, &data[0], 2); - //acc_dchg_cap - data[2] = (bi->acc_dchg_cap>>24)&0xff; - data[3] = (bi->acc_dchg_cap>>16)&0xff; - data[4] = (bi->acc_dchg_cap>>8)&0xff; - data[5] = (bi->acc_dchg_cap)&0xff; - rt5025_write_reg(bi->client, 0x23, &data[2], 4); - //cycle_count - data[6] = (bi->cycle_cnt)&0xff; - rt5025_write_reg(bi->client, 0x27, &data[6], 1); - //soc - data[7] = (bi->soc)&0xff; - rt5025_write_reg(bi->client, 0x28, &data[7], 1); - //gauge_timer - data[8] = (bi->pre_gauge_timer>>8)&0xff; - data[9] = bi->pre_gauge_timer&0xff; - rt5025_write_reg(bi->client, 0x29, &data[8], 2); - //CRC value - crc_value = get_crc16_value(data, 10); - data[10] = crc_value&0xff; - data[11] = (crc_value>>8)&0xff; - rt5025_write_reg(bi->client, 0x2b, &data[10], 2); + /*backup fcc_aging, rm, cycle_count, acc_dchg_cap*/ + /*fcc_aging*/ + data[0] = (bi->fcc_aging >> 8) & 0xff; + data[1] = (bi->fcc_aging) & 0xff; + /*acc_dchg_cap*/ + data[2] = (bi->acc_dchg_cap >> 24) & 0xff; + data[3] = (bi->acc_dchg_cap >> 16) & 0xff; + data[4] = (bi->acc_dchg_cap >> 8) & 0xff; + data[5] = (bi->acc_dchg_cap) & 0xff; + /*cycle_count*/ + data[6] = (bi->cycle_cnt) & 0xff; + /*soc*/ + data[7] = (bi->permille >> 8) & 0xff; + data[8] = (bi->permille) & 0xff; + /*gauge_timer*/ + data[9] = (bi->pre_gauge_timer >> 8) & 0xff; + data[10] = bi->pre_gauge_timer & 0xff; + /*CRC value*/ + crc_value = get_crc16_value(data, 13); + data[13] = crc_value & 0xff; + data[14] = (crc_value >> 8) & 0xff; + rt5025_write_reg(bi->client, RT5025_REG_RESV1, data, 15); return 0; } static int rt5025_battery_parameter_restore(struct rt5025_battery_info *bi) { - u8 data[4]; + u8 data[15]; + RTINFO("\n"); - //restore fcc_aging, rm ,cycle_count, acc_dchg_cap - //fcc_aging - rt5025_read_reg(bi->client, 0x21, data, 2); - bi->fcc = bi->fcc_aging = data[0]<<8 | data[1]; - //acc_dchg_cap - rt5025_read_reg(bi->client, 0x23, data, 4); - bi->acc_dchg_cap = data[0]<<24 | data[1]<<16 | data[2]<<8 | data[3]; - //cycle_count - rt5025_read_reg(bi->client, 0x27, data, 1); - bi->cycle_cnt = data[0]; - //soc - rt5025_read_reg(bi->client, 0x28, data, 1); - bi->soc = bi->pre_soc = data[0]; - //pre_gauge_timer - rt5025_read_reg(bi->client, 0x29, data, 2); - bi->pre_gauge_timer = bi->gauge_timer = (data[0]<<8) + data[1]; - + rt5025_read_reg(bi->client, RT5025_REG_RESV1, data, 15); + /*restore fcc_aging, rm ,cycle_count, acc_dchg_cap*/ + /*fcc_aging*/ + bi->fcc = bi->fcc_aging = data[0] << 8 | data[1]; + /*acc_dchg_cap*/ + bi->acc_dchg_cap = data[2] << 24 | data[3] << 16 | data[4] << 8 | data[5]; + /*cycle_count*/ + bi->cycle_cnt = data[6]; + /*soc*/ + bi->permille = data[7] << 8 | data[8]; + /*pre_gauge_timer*/ + bi->pre_gauge_timer = bi->gauge_timer = (data[9] << 8) + data[10]; + return 0; } - -// return value; 1-> initialized, 0-> no initial value +/*return value; 1-> initialized, 0-> no initial value*/ static int rt5025_battery_parameter_initcheck(struct rt5025_battery_info *bi) { - u8 data[12] = {0}; + u8 data[15] = {0}; int ret = 0; - if (rt5025_read_reg(bi->client, 0x21, data, 12)<0) - { + if (rt5025_read_reg(bi->client, RT5025_REG_RESV1, data, 15) < 0) { pr_err("%s: check initial value error\n", __func__); return 0; - } - else - { - ret = IsCrc16Good(data, 12); + } else { + ret = IsCrc16Good(data, 15); } RTINFO("initial check = %d\n", ret); @@ -1289,19 +1257,19 @@ static int rt5025_battery_parameter_initcheck(struct rt5025_battery_info *bi) } static void rt5025_register_init(struct rt5025_battery_info *bi) -{ +{ u8 data[1]; /* enable the channel of current,qc,ain,vbat and vadc */ - if (rt5025_read_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + if (rt5025_read_reg(bi->client, RT5025_REG_CHANNELL, data, 1) < 0) pr_err("%s: failed to read channel\n", __func__); - } + RTINFO("initial change enable=%02x\n", data[0]); data[0] = data[0] | CHANNEL_L_BIT_CADC_EN | CHANNEL_L_BIT_AINCH | \ CHANNEL_L_BIT_VBATSCH | CHANNEL_L_BIT_VADC_EN | CHANNEL_L_BIT_INTEMPCH; - if (rt5025_write_reg(bi->client, RT5025_REG_CHANNEL_LSB, data, 1) < 0){ + if (rt5025_write_reg(bi->client, RT5025_REG_CHANNELL, data, 1) < 0) pr_err("%s: failed to write channel\n", __func__); - } + /* set the alert threshold value */ irq_thres[MINVOLT2] = VALRTMIN2_VALUE; irq_thres[VOLT_RLS] = VRLS_VALUE; @@ -1310,9 +1278,10 @@ static void rt5025_register_init(struct rt5025_battery_info *bi) bi->dchg_cc_unuse = 0; bi->pre_gauge_timer = 0; bi->online = 1; + bi->batt_present = 1; bi->status = bi->internal_status = POWER_SUPPLY_STATUS_DISCHARGING; bi->health = POWER_SUPPLY_HEALTH_GOOD; - + bi->init_cap = true; bi->avg_flag = true; @@ -1328,19 +1297,22 @@ static void rt5025_register_init(struct rt5025_battery_info *bi) bi->tp_cnt = 0; bi->tp_flag = false; - + bi->acc_dchg_cap = 0; bi->cycle_cnt = 0; bi->empty_edv = rt5025_battery_param2[4].x; bi->edv_region = 0; + bi->soc1_lock_cnt = 0; + /*eoc fcc update function: initial variable. */ + bi->cal_eoc_fcc = 0; + bi->cal_soc_offset = 0; - // if has initial data, rewrite to the stored data - if (rt5025_battery_parameter_initcheck(bi)) - { + + /*if has initial data, rewrite to the stored data*/ + if (rt5025_battery_parameter_initcheck(bi)) { bi->init_cap = false; rt5025_battery_parameter_restore(bi); - //bi->soc = bi->rm/36/bi->fcc_aging; - bi->rm = bi->soc*bi->fcc_aging*36; + bi->rm = bi->permille*bi->fcc_aging * 36 / 10; } bi->update_time = NORMAL_POLL; @@ -1350,297 +1322,307 @@ static void rt5025_register_init(struct rt5025_battery_info *bi) static void rt5025_soc_aging(struct rt5025_battery_info *bi) { - if (bi->cycle_cnt >= rt5025_battery_param2[3].x) - { - bi->fcc_aging = bi->fcc_aging*(1000-rt5025_battery_param2[3].y)/1000; - bi->rm = bi->rm*(1000-rt5025_battery_param2[3].y)/1000; + if (bi->cycle_cnt >= rt5025_battery_param2[3].x) { + bi->fcc_aging = bi->fcc_aging * (1000 - rt5025_battery_param2[3].y) / 1000; + bi->rm = bi->rm * (1000 - rt5025_battery_param2[3].y) / 1000; bi->cycle_cnt -= rt5025_battery_param2[3].x; } - RTINFO("fcc_aging=%d, rm=%d, cycle_cnt=%d\n", bi->fcc_aging, bi->rm, bi->cycle_cnt); + RTINFO("fcc_aging=%d, rm=%d, cycle_cnt=%d\n", + bi->fcc_aging, bi->rm, bi->cycle_cnt); } static void rt5025_temp_comp(struct rt5025_battery_info *bi) { int i = 1; - int size; - int slope, const_term; - int delta_y, delta_x; - - size = 3; - while((bi->ext_temp < rt5025_battery_param2[i].x) && - (i < (size - 1))){ - i++; - } + int size; + int slope, const_term; + int delta_y, delta_x; + + size = 3; + while ((bi->ext_temp < rt5025_battery_param2[i].x) && + (i < (size - 1))) { + i++; + } - delta_x = rt5025_battery_param2[i-1].x - rt5025_battery_param2[i].x; - delta_y = (rt5025_battery_param2[i-1].y - rt5025_battery_param2[i].y); - - slope = delta_y * 1000 / delta_x; - - const_term = (rt5025_battery_param2[i].y) - ((rt5025_battery_param2[i].x * slope) / 1000); - - if (bi->ext_temp >= rt5025_battery_param2[0].x) - bi->tempcmp = rt5025_battery_param2[0].y; - else if (bi->ext_temp <= rt5025_battery_param2[size-1].x) - bi->tempcmp = rt5025_battery_param2[size-1].y; - else - bi->tempcmp = (bi->ext_temp * slope) / 1000 + const_term; - - bi->fcc = bi->fcc_aging + bi->fcc_aging * bi->tempcmp /1000; - if (bi->fcc >= (bi->dc*3>>1)) - bi->fcc = bi->dc*3>>1; - if (bi->fcc <= (bi->dc>>1)) - bi->fcc = bi->dc>>1; - bi->rm = bi->fcc * bi->soc * 36; - //pr_err("[rt5025] i=%d, delta_x=%d, delta_y=%d, slope=%d, const_term=%d\n", i, delta_x, delta_y, slope, const_term); - RTINFO("tempcmp=%d, ext_temp=%d, fcc=%d, rm=%d\n", bi->tempcmp, bi->ext_temp, bi->fcc, bi->rm); - return; + delta_x = rt5025_battery_param2[i-1].x - rt5025_battery_param2[i].x; + delta_y = (rt5025_battery_param2[i-1].y - rt5025_battery_param2[i].y); + + slope = delta_y * 1000 / delta_x; + + const_term = (rt5025_battery_param2[i].y) - ((rt5025_battery_param2[i].x * slope) / 1000); + + if (bi->ext_temp >= rt5025_battery_param2[0].x) + bi->tempcmp = rt5025_battery_param2[0].y; + else if (bi->ext_temp <= rt5025_battery_param2[size-1].x) + bi->tempcmp = rt5025_battery_param2[size-1].y; + else + bi->tempcmp = (bi->ext_temp * slope) / 1000 + const_term; + + bi->fcc = bi->fcc_aging + bi->fcc_aging * bi->tempcmp / 1000; + if (bi->fcc >= (bi->dc*3>>1)) + bi->fcc = bi->dc*3>>1; + if (bi->fcc <= (bi->dc>>1)) + bi->fcc = bi->dc>>1; + bi->rm = bi->fcc * bi->permille * 36 / 10; + RTINFO("tempcmp=%d, ext_temp=%d, fcc=%d, rm=%d\n", + bi->tempcmp, bi->ext_temp, bi->fcc, bi->rm); + /*return; */ } static void rt5025_soc_temp_comp(struct rt5025_battery_info *bi) { - RTINFO("soc->%d++\n", bi->soc); - bi->temp_range_0_5 = false; - bi->temp_range_5_10 = false; - bi->temp_range_10_15 = false; - bi->temp_range_15_20 = false; - bi->temp_range_20_30 = false; - bi->temp_range_30_35 = false; - bi->temp_range_35_40 = false; - bi->temp_range_40_45 = false; - bi->temp_range_45_50 = false; - - if (bi->ext_temp < 50) - bi->temp_range_0_5 = true; - else if (50 <= bi->ext_temp && bi->ext_temp < 100) - bi->temp_range_5_10 = true; - else if (100 <= bi->ext_temp && bi->ext_temp < 150) - bi->temp_range_10_15 = true; - else if (150 <= bi->ext_temp && bi->ext_temp < 200) - bi->temp_range_15_20 = true; - else if (200 <= bi->ext_temp && bi->ext_temp <= 300) - bi->temp_range_20_30 = true; - else if (300 < bi->ext_temp && bi->ext_temp <= 350) - bi->temp_range_30_35 = true; - else if (350 < bi->ext_temp && bi->ext_temp <= 400) - bi->temp_range_35_40 = true; - else if (400 < bi->ext_temp && bi->ext_temp <= 450) - bi->temp_range_40_45 = true; - else if (450 < bi->ext_temp) - bi->temp_range_45_50 = true; - - if((bi->temp_range_0_5 == true) && (bi->range_0_5_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = true; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_5_10 == true) && (bi->range_5_10_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = true; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_10_15 == true) && (bi->range_10_15_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = true; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_15_20 == true) && (bi->range_15_20_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = true; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_20_30 == true) && (bi->range_20_30_done == false)) - { - bi->fcc = bi->fcc_aging; - bi->rm = bi->fcc*bi->soc*36; - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = true; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_30_35 == true) && (bi->range_30_35_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = true; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_35_40 == true) && (bi->range_35_40_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = true; - bi->range_40_45_done = false; - bi->range_45_50_done = false; - } - else if((bi->temp_range_40_45 == true) && (bi->range_40_45_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = true; - bi->range_45_50_done = false; - } - else if((bi->temp_range_45_50 == true) && (bi->range_45_50_done == false)) - { - rt5025_temp_comp(bi); - bi->range_0_5_done = false; - bi->range_5_10_done = false; - bi->range_10_15_done = false; - bi->range_15_20_done = false; - bi->range_20_30_done = false; - bi->range_30_35_done = false; - bi->range_35_40_done = false; - bi->range_40_45_done = false; - bi->range_45_50_done = true; - } - RTINFO("soc->%d--\n", bi->soc); + RTINFO("soc->%d++\n", bi->soc); + bi->temp_range_0_5 = 0; + bi->temp_range_5_10 = 0; + bi->temp_range_10_15 = 0; + bi->temp_range_15_20 = 0; + bi->temp_range_20_30 = 0; + bi->temp_range_30_35 = 0; + bi->temp_range_35_40 = 0; + bi->temp_range_40_45 = 0; + bi->temp_range_45_50 = 0; + + if (bi->ext_temp < 50) + bi->temp_range_0_5 = 1; + else if (50 <= bi->ext_temp && bi->ext_temp < 100) + bi->temp_range_5_10 = 1; + else if (100 <= bi->ext_temp && bi->ext_temp < 150) + bi->temp_range_10_15 = 1; + else if (150 <= bi->ext_temp && bi->ext_temp < 200) + bi->temp_range_15_20 = 1; + else if (200 <= bi->ext_temp && bi->ext_temp <= 300) + bi->temp_range_20_30 = 1; + else if (300 < bi->ext_temp && bi->ext_temp <= 350) + bi->temp_range_30_35 = 1; + else if (350 < bi->ext_temp && bi->ext_temp <= 400) + bi->temp_range_35_40 = 1; + else if (400 < bi->ext_temp && bi->ext_temp <= 450) + bi->temp_range_40_45 = 1; + else if (450 < bi->ext_temp) + bi->temp_range_45_50 = 1; + + if ((bi->temp_range_0_5 == 1) && (bi->range_0_5_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 1; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_5_10 == 1) + && (bi->range_5_10_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 1; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_10_15 == 1) + && (bi->range_10_15_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 1; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_15_20 == 1) + && (bi->range_15_20_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 1; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_20_30 == 1) + && (bi->range_20_30_done == 0)) { + bi->fcc = bi->fcc_aging; + bi->rm = bi->fcc * bi->permille * 36 / 10; + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 1; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_30_35 == 1) + && (bi->range_30_35_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 1; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_35_40 == 1) + && (bi->range_35_40_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 1; + bi->range_40_45_done = 0; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_40_45 == 1) + && (bi->range_40_45_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 1; + bi->range_45_50_done = 0; + } else if ((bi->temp_range_45_50 == 1) + && (bi->range_45_50_done == 0)) { + rt5025_temp_comp(bi); + bi->range_0_5_done = 0; + bi->range_5_10_done = 0; + bi->range_10_15_done = 0; + bi->range_15_20_done = 0; + bi->range_20_30_done = 0; + bi->range_30_35_done = 0; + bi->range_35_40_done = 0; + bi->range_40_45_done = 0; + bi->range_45_50_done = 1; + } + RTINFO("soc->%d--\n", bi->soc); } static void rt5025_update(struct rt5025_battery_info *bi) { - /* Update voltage */ - rt5025_get_vcell(bi); - /* Update current */ - rt5025_get_current(bi); - /* Update internal temperature */ - rt5025_get_internal_temp(bi); - /* Update external temperature */ - rt5025_get_external_temp(bi); - /* Read timer */ - rt5025_get_timer(bi); - /* Update chg cc */ - rt5025_get_chg_cc(bi); - /* Update dchg cc */ - rt5025_get_dchg_cc(bi); - /* Update cycle count check */ - rt5025_cycle_count(bi); - /* Calculate cycle count */ - rt5025_soc_aging(bi); - /* calculate initial soc */ - if (bi->init_cap){ - rt5025_init_capacity(bi); -#if RT5025_CSV - pr_info("vcell,offset,current,timer,interval,QCHG,QDCHG,tp_cnt,tp_flag,edv_det,edv_cnt,edv_flag,soc,permille,RM,FCC,smooth_flag,acc_QD,cycle,update_time\n"); -#endif - } + int batt_type = 1; + /* Update voltage */ + rt5025_get_vcell(bi); + /* Update current */ + rt5025_get_current(bi); + /* Update internal temperature */ + rt5025_get_internal_temp(bi); + /* Update external temperature */ + rt5025_get_external_temp(bi); + /* Read timer */ + rt5025_get_timer(bi); + /* Update chg cc */ + rt5025_get_chg_cc(bi); + /* Update dchg cc */ + rt5025_get_dchg_cc(bi); + /* Update cycle count check */ + rt5025_cycle_count(bi); + /* Calculate cycle count */ + rt5025_soc_aging(bi); + /* calculate initial soc */ + if (bi->init_cap) { + rt5025_init_capacity(bi); + #if RT5025_CSV + pr_info("vcell,offset,current,timer,interval,QCHG,QDCHG,tp_cnt,tp_flag,edv_det,edv_cnt,edv_flag,soc,permille,RM,FCC,smooth_flag,acc_QD,cycle,update_time\n"); + #endif + } /* Relearn SOC */ rt5025_soc_relearn_check(bi); /* SOC_Temp_Comp*/ rt5025_soc_temp_comp(bi); - /* Update SOC */ - rt5025_get_soc(bi); - - /* SOC Control Process */ - rt5025_soc_lock(bi); - rt5025_soc_irreversible(bi); - - /* Update RTTF or RTTE */ - //rt5025_run_time(bi); - -#if TEMPERATURE_ALERT - if ((bi->max_temp_irq == false) && - (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - bi->ain_volt) > irq_thres[TEMP_RLS])){ - rt5025_alert_setting(bi,MAXTEMP,true); - }else if ((bi->min_temp_irq == false) && - ((bi->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])){ - rt5025_alert_setting(bi,MINTEMP,true); - } -#endif -#if 0 - }else if ((bi->min_volt1_irq == false) && - ((bi->vcell - ((irq_thres[MINVOLT1] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ - rt5025_alert_setting(bi,MINVOLT1,true); - }else if ((bi->min_volt2_irq == false) && - ((bi->vcell - ((irq_thres[MINVOLT2] * IRQ_THRES_UNIT) / 100)) > irq_thres[VOLT_RLS])){ - rt5025_alert_setting(bi,MINVOLT2,true); + /* Update SOC */ + rt5025_get_soc(bi); + + /* SOC Control Process */ + rt5025_soc_lock(bi); + rt5025_soc_irreversible(bi); + + if (bi->soc <= 99) + bi->last_tp = false; + + if (rt5025_battery_param1[0].x >= 4250) + batt_type = 0; + else if (rt5025_battery_param1[0].x >= 4100) + batt_type = 1; + + switch (batt_type) { + case 0: + if ((bi->vcell >= 4250) && (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING)) + wake_lock(&bi->full_battery_wake_lock); + else + wake_unlock(&bi->full_battery_wake_lock); + break; + case 1: + default: + if ((bi->vcell >= 4100) && (bi->internal_status == POWER_SUPPLY_STATUS_CHARGING)) + wake_lock(&bi->full_battery_wake_lock); + else + wake_unlock(&bi->full_battery_wake_lock); + break; + } + + /* Update RTTF or RTTE */ + +#if TEMPERATURE_ALERT + if ((bi->max_temp_irq == false) && + (((irq_thres[MAXTEMP] * IRQ_THRES_UNIT) / 100 - bi->ain_volt) > irq_thres[TEMP_RLS])) { + rt5025_alert_setting(bi, MAXTEMP, true); + } else if ((bi->min_temp_irq == false) && + ((bi->ain_volt - (irq_thres[MINTEMP] * IRQ_THRES_UNIT) / 100) > irq_thres[TEMP_RLS])) { + rt5025_alert_setting(bi, MINTEMP, true); } #endif - + #if VOLTAGE_ALERT if ((bi->min_volt2_irq == false) && - (bi->vcell > (bi->empty_edv + EDV_HYS))){ - rt5025_alert_setting(bi,MINVOLT2,true); - } + (bi->vcell > (bi->empty_edv + EDV_HYS))) + rt5025_alert_setting(bi, MINVOLT2, true); #endif + bi->last_suspend = false; #if RT5025_CSV - printk(KERN_INFO "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",bi->vcell,bi->curr_offset,bi->curr,bi->gauge_timer,bi->time_interval,bi->chg_cc, - bi->dchg_cc,bi->tp_cnt,bi->tp_flag,bi->edv_detection,bi->edv_cnt,bi->edv_flag,bi->soc, - bi->permille,bi->rm,bi->fcc,bi->smooth_flag,bi->acc_dchg_cap,bi->cycle_cnt,bi->update_time); + printk(KERN_INFO "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + bi->vcell, bi->curr_offset, bi->curr, bi->gauge_timer, + bi->time_interval, bi->chg_cc, bi->dchg_cc, + bi->tp_cnt, bi->tp_flag, bi->edv_detection, + bi->edv_cnt, bi->edv_flag, bi->soc, bi->permille, + bi->rm, bi->fcc, bi->smooth_flag, bi->acc_dchg_cap, + bi->cycle_cnt, bi->update_time); #else - RTINFO("[RT5025] update_time=%d\n",bi->update_time); - RTINFO("\n"); + RTINFO("[RT5025] update_time=%d\n", bi->update_time); + RTINFO("\n"); #endif } static void rt5025_update_work(struct work_struct *work) { - struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); - struct rt5025_battery_info *bi = (struct rt5025_battery_info *)container_of(delayed_work, struct rt5025_battery_info, monitor_work); + struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, + struct delayed_work, work); + struct rt5025_battery_info *bi = (struct rt5025_battery_info *)container_of(delayed_work, + struct rt5025_battery_info, monitor_work); unsigned long flags; - wake_lock(&bi->monitor_wake_lock); + wake_lock(&bi->monitor_wake_lock); rt5025_update(bi); power_supply_changed(&bi->battery); - + /* prevent suspend before starting the alarm */ local_irq_save(flags); - bi->last_poll = alarm_get_elapsed_realtime(); - rt5025_program_alarm(bi); local_irq_restore(flags); wake_unlock(&bi->monitor_wake_lock); @@ -1649,69 +1631,86 @@ static void rt5025_update_work(struct work_struct *work) } static enum power_supply_property rt5025_battery_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_TEMP, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_TECHNOLOGY, - #if 0 - POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, - POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, - #endif + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TEMP_AMBIENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_TECHNOLOGY, +#if 0 + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, +#endif }; -static int rt5025_battery_sleepvth_setting(struct rt5025_battery_info* bi) +static int rt5025_battery_sleepvth_setting(struct rt5025_battery_info *bi) { u32 temp; u8 vmax_th, vmin_th; u8 vbat[2]; + RTINFO("\n"); - rt5025_read_reg(bi->client, RT5025_REG_VCELL_MSB, vbat, 2); - temp = ((vbat[0]<<8) + vbat[1])*61; - vmax_th = (temp+5000)/1953; - vmin_th = (temp-5000)/1953; + rt5025_read_reg(bi->client, RT5025_REG_VBATSH, vbat, 2); + temp = ((vbat[0] << 8) + vbat[1]) * 61; + vmax_th = (temp + 5000) / 1953; + vmin_th = (temp - 5000) / 1953; - rt5025_write_reg(bi->client, RT5025_REG_VALRT_MAXTH, &vmax_th, 1); - rt5025_write_reg(bi->client, RT5025_REG_VALRT_MIN1TH, &vmin_th, 1); + rt5025_write_reg(bi->client, RT5025_REG_VALRTMAX, &vmax_th, 1); + rt5025_write_reg(bi->client, RT5025_REG_VALRTMIN1, &vmin_th, 1); RTINFO("vmax_th=0x%02x, vmin_th=0x%02x\n", vmax_th, vmin_th); return 0; } -static int rt5025_battery_suspend(struct platform_device *pdev, pm_message_t state) +static int rt5025_gauge_reginit(struct i2c_client *client) +{ + rt5025_reg_block_write(client, RT5025_REG_VALRTMAX, + 5, gauge_init_regval); + rt5025_reg_write(client, RT5025_REG_IRQCTL, 0x00); + rt5025_reg_read(client, RT5025_REG_IRQFLG); + RTINFO("\n"); + return 0; +} + +static int rt5025_battery_suspend(struct platform_device *pdev, + pm_message_t state) { struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + RTINFO("\n"); - //rt5025_get_timer(bi); - //bi->last_event = ktime_get(); + /*rt5025_get_timer(bi);*/ + /*bi->last_event = ktime_get();*/ bi->last_event = current_kernel_time(); - //cy add for battery parameter backup + /*cy add for battery parameter backup //rt5025_battery_parameter_backup(bi); //rt5025_channel_cc(bi, false); - //rt5025_update(bi); + //rt5025_update(bi);*/ bi->device_suspend = true; cancel_delayed_work_sync(&bi->monitor_work); /* prevent suspend before starting the alarm */ - //bi->update_time = SUSPEND_POLL; - rt5025_alert_setting(bi,MAXVOLT, false); - rt5025_alert_setting(bi,MINVOLT1,false); + /*bi->update_time = SUSPEND_POLL;*/ + rt5025_alert_setting(bi, MAXVOLT, false); + rt5025_alert_setting(bi, MINVOLT1, false); rt5025_battery_sleepvth_setting(bi); - rt5025_alert_setting(bi,MAXVOLT, true); - rt5025_alert_setting(bi,MINVOLT1,true); - RTINFO("RM=%d\n",bi->rm); + if (bi->status == POWER_SUPPLY_STATUS_CHARGING) + rt5025_alert_setting(bi, MAXVOLT, true); + else if (bi->status == POWER_SUPPLY_STATUS_DISCHARGING) + rt5025_alert_setting(bi, MINVOLT1, true); + RTINFO("RM=%d\n", bi->rm); return 0; } static int rt5025_battery_resume(struct platform_device *pdev) { struct rt5025_battery_info *bi = platform_get_drvdata(pdev); - //ktime_t now; + + /*ktime_t now; //struct timespec now = current_kernel_time(); //struct timeval tv; //long time_interval; @@ -1723,9 +1722,9 @@ static int rt5025_battery_resume(struct platform_device *pdev) //time_interval = now.tv_sec - bi->last_event.tv_sec; //bi->rm = bi->rm - (time_interval * SLEEP_CURRENT); - //RTINFO("Sleep time=%d, RM=%d",(int)time_interval,bi->rm); + //RTINFO("Sleep time=%d, RM=%d",(int)time_interval,bi->rm); - //rt5025_channel_cc(bi, true); + //rt5025_channel_cc(bi, true);*/ bi->last_suspend = true; bi->device_suspend = false; schedule_delayed_work(&bi->monitor_work, 0); @@ -1751,33 +1750,38 @@ static int rt5025_battery_probe(struct platform_device *pdev) struct rt5025_battery_info *bi; int ret; - bi = kzalloc(sizeof(*bi), GFP_KERNEL); - if (!bi) - return -ENOMEM; - - bi->client = chip->i2c; - bi->chip = chip; - + bi = devm_kzalloc(&pdev->dev, sizeof(*bi), GFP_KERNEL); + if (!bi) + return -ENOMEM; - bi->last_poll = alarm_get_elapsed_realtime(); - alarm_init(&bi->wakeup_alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, - rt5025_gauge_alarm); + bi->client = chip->i2c; INIT_DELAYED_WORK(&bi->monitor_work, rt5025_update_work); - - wake_lock_init(&bi->monitor_wake_lock, WAKE_LOCK_SUSPEND, "rt-battery-monitor"); - wake_lock_init(&bi->low_battery_wake_lock, WAKE_LOCK_SUSPEND, "low_battery_wake_lock"); - wake_lock_init(&bi->status_wake_lock, WAKE_LOCK_SUSPEND, "battery-status-changed"); + + wake_lock_init(&bi->monitor_wake_lock, + WAKE_LOCK_SUSPEND, "rt-battery-monitor"); + wake_lock_init(&bi->low_battery_wake_lock, + WAKE_LOCK_SUSPEND, "low_battery_wake_lock"); + wake_lock_init(&bi->status_wake_lock, + WAKE_LOCK_SUSPEND, "battery-status-changed"); + wake_lock_init(&bi->smooth100_wake_lock, + WAKE_LOCK_SUSPEND, "smooth100_soc_wake_lock"); + wake_lock_init(&bi->smooth0_wake_lock, + WAKE_LOCK_SUSPEND, "smooth0_soc_wake_lock"); + wake_lock_init(&bi->full_battery_wake_lock, + WAKE_LOCK_SUSPEND, "full_battery_wake_lock"); #if RT5025_TEST_WAKE_LOCK wake_lock_init(&bi->test_wake_lock, WAKE_LOCK_SUSPEND, "rt-test"); #endif - /* Write trimed data */ - //rt5025_pretrim(client); + mutex_init(&bi->status_change_lock); + /* Write trimed data */ + /*rt5025_pretrim(client);*/ + rt5025_gauge_reginit(bi->client); /* enable channel */ rt5025_register_init(bi); /* enable gauge IRQ */ rt5025_alert_init(bi); - + /* register callback functions */ /* chip->cb.rt5025_gauge_irq_handler = rt5025_irq_handler; @@ -1786,84 +1790,96 @@ static int rt5025_battery_probe(struct platform_device *pdev) chip->cb.rt5025_gauge_suspend = rt5025_gauge_suspend; chip->cb.rt5025_gauge_resume = rt5025_gauge_resume; chip->cb.rt5025_gauge_remove = rt5025_gauge_remove; - rt5025_register_gauge_callbacks(&chip->cb); */ platform_set_drvdata(pdev, bi); - bi->battery.name = "rt5025-battery"; + bi->battery.name = RT_BATT_NAME; bi->battery.type = POWER_SUPPLY_TYPE_BATTERY; + bi->battery.set_property = rt5025_set_property; bi->battery.get_property = rt5025_get_property; bi->battery.properties = rt5025_battery_props; bi->battery.num_properties = ARRAY_SIZE(rt5025_battery_props); - + ret = power_supply_register(&pdev->dev, &bi->battery); if (ret) { - printk(KERN_ERR "[RT5025] power supply register failed\n"); + pr_err("[RT5025] power supply register failed\n"); goto err_wake_lock; } - - //wake_lock(&bi->monitor_wake_lock); + /*wake_lock(&bi->monitor_wake_lock);*/ #if RT5025_TEST_WAKE_LOCK wake_lock(&bi->test_wake_lock); #endif - schedule_delayed_work(&bi->monitor_work, msecs_to_jiffies(INIT_POLL*MSEC_PER_SEC)); + schedule_delayed_work(&bi->monitor_work, INIT_POLL*HZ); chip->battery_info = bi; pr_info("rt5025-battery driver is successfully loaded\n"); - - return 0; + return 0; err_wake_lock: wake_lock_destroy(&bi->monitor_wake_lock); - kfree(bi); - return ret; } static void rt5025_battery_shutdown(struct platform_device *pdev) { struct rt5025_battery_info *bi = platform_get_drvdata(pdev); + RTINFO("\n"); - if (bi->soc == 0 && bi->cal_fcc != 0 ) - { - bi->fcc_aging = bi->cal_fcc/3600 - (bi->fcc -bi->fcc_aging); + if (bi->soc == 0 && bi->cal_fcc != 0) { + /*d. FCC update limitation +/-3%; 2013/12/27 + //bi->fcc_aging = bi->cal_fcc/3600 - (bi->fcc -bi->fcc_aging);*/ + u16 fcc_new = 0; + + fcc_new = bi->cal_fcc / 3600 - (bi->fcc - bi->fcc_aging); + if (fcc_new > ((bi->fcc_aging * 103) / 100)) + bi->fcc_aging = (bi->fcc_aging * 103) / 100; + else if (fcc_new < ((bi->fcc_aging * 97) / 100)) + bi->fcc_aging = (bi->fcc_aging * 97) / 100; + else + bi->fcc_aging = fcc_new; + RTINFO("bi->cal_fcc=%d\n", bi->cal_fcc); } rt5025_battery_parameter_backup(bi); RTINFO("\n"); } -static struct platform_driver rt5025_battery_driver = -{ +static struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-battery",}, + {}, +}; + +static struct platform_driver rt5025_battery_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-battery", + .name = RT5025_DEV_NAME "-battery", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_battery_probe, - .remove = __devexit_p(rt5025_battery_remove), + .remove = rt5025_battery_remove, .shutdown = rt5025_battery_shutdown, .suspend = rt5025_battery_suspend, .resume = rt5025_battery_resume, }; -static int __init rt5025_battery_init(void) +static int rt5025_battery_init(void) { return platform_driver_register(&rt5025_battery_driver); } -module_init(rt5025_battery_init); +fs_initcall_sync(rt5025_battery_init); -static void __exit rt5025_battery_exit(void) +static void rt5025_battery_exit(void) { platform_driver_unregister(&rt5025_battery_driver); } module_exit(rt5025_battery_exit); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Nick Hung "); MODULE_DESCRIPTION("battery gauge driver for RT5025"); -MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-battery"); +MODULE_ALIAS("platform:" RT5025_DEV_NAME "-battery"); MODULE_VERSION(RT5025_DRV_VER); diff --git a/drivers/power/rt5025-charger.c b/drivers/power/rt5025-charger.c new file mode 100755 index 000000000000..d7aee678401a --- /dev/null +++ b/drivers/power/rt5025-charger.c @@ -0,0 +1,1224 @@ +/* + * drivers/power/rt5025-charger.c + * Driver for Richtek RT5025 PMIC Charger driver + * + * Copyright (C) 2014 Richtek Technology Corp. + * cy_huang + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif /* #ifdef CONFIG_HAS_EARLYSUSPEND */ + +#include +#include +#ifdef CONFIG_RT_POWER +#include +#endif /* #ifdef CONFIG_RT_POWER */ + +static unsigned char chg_init_regval[] = { + 0x12, /*REG 0x02*/ + 0x8C, /*REG 0x03*/ + 0x03, /*REG 0x04*/ + 0x20, /*REG 0x05*/ + 0x14, /*REG 0x06*/ + 0x40, /*REG 0x07*/ + 0xDA, /*REG 0x30*/ + 0xDA, /*REG 0x32*/ + 0x43, /*REG 0x34*/ +}; + +static char *rtdef_chg_name = "rt-charger"; + +static char *rt_charger_supply_list[] = { + "none", +}; + +static enum power_supply_property rt_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, +}; + +static void rt_charger_set_batt_status(struct rt5025_charger_info *ci); + +static int rt_charger_get_property(struct power_supply *psy, enum power_supply_property psp, \ + union power_supply_propval *val) +{ + struct rt5025_charger_info *ci = dev_get_drvdata(psy->dev->parent); + int ret = 0; + int regval = 0; + #ifdef CONFIG_BATTERY_RT5025 + struct power_supply *bat_psy = power_supply_get_by_name(RT_BATT_NAME); + union power_supply_propval pval; + #endif + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ci->online; + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = ci->chg_status; + break; + case POWER_SUPPLY_PROP_PRESENT: + regval = rt5025_reg_read(ci->i2c, RT5025_REG_CHGCTL7); + if (regval < 0) { + ret = -EINVAL; + } else { + if (regval & RT5025_CHGCEN_MASK) + val->intval = 1; + else + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = 0; + #ifdef CONFIG_BATTERY_RT5025 + if (bat_psy) { + ret = bat_psy->get_property(bat_psy, POWER_SUPPLY_PROP_TEMP_AMBIENT,\ + &pval); + if (ret < 0) + dev_err(ci->dev, "get ic temp fail\n"); + else + val->intval = pval.intval; + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + val->intval = ci->charger_cable; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = 2000; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + regval = rt5025_reg_read(ci->i2c, RT5025_REG_CHGCTL4); + if (regval < 0) { + ret = -EINVAL; + } else { + regval &= RT5025_CHGAICR_MASK; + regval >>= RT5025_CHGAICR_SHFT; + switch (regval) { + case 0: + val->intval = 100; + break; + case 1: + val->intval = 500; + break; + case 2: + val->intval = 1000; + break; + case 3: + val->intval = 0; + break; + default: + ret = -EINVAL; + break; + } + } + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + regval = rt5025_reg_read(ci->i2c, RT5025_REG_CHGCTL4); + if (regval < 0) { + ret = -EINVAL; + } else { + regval &= RT5025_CHGICC_MASK; + regval >>= RT5025_CHGICC_SHFT; + val->intval = 500 + regval * 100; + } + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + regval = rt5025_reg_read(ci->i2c, RT5025_REG_CHGCTL3); + if (regval < 0) { + ret = -EINVAL; + } else { + regval &= RT5025_CHGCV_MASK; + regval >>= RT5025_CHGCV_SHFT; + val->intval = regval * 20 + 3500; + } + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = 3500; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = 4440; + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int rt_charger_set_property(struct power_supply *psy, enum power_supply_property psp, \ + const union power_supply_propval *val) +{ + struct rt5025_charger_info *ci = dev_get_drvdata(psy->dev->parent); + int ret = 0; + int regval = 0; + RTINFO("prop = %d, val->intval = %d\n", psp, val->intval); + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ci->online = val->intval; + if (ci->online) { + if (ci->te_en) { + ret = rt5025_set_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_CHGTEEN_MASK); + /*charger workaround*/ + mdelay(150); + /*turn on recharge irq enable*/ + chg_init_regval[8] |= RT5025_CHRCHGI_MASK; + rt5025_reg_write(ci->i2c, RT5025_REG_IRQEN3, chg_init_regval[8]); + /*turn on chterm irq enable*/ + chg_init_regval[7] |= RT5025_CHTERMI_MASK; + rt5025_reg_write(ci->i2c, RT5025_REG_IRQEN2, chg_init_regval[7]); + } + ci->chg_status = POWER_SUPPLY_STATUS_CHARGING; + rt_charger_set_batt_status(ci); + } else { + if (ci->te_en) { + ret = rt5025_clr_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_CHGTEEN_MASK); + /*charger workaround*/ + /*turn off chterm irq enable*/ + chg_init_regval[7] &= ~RT5025_CHTERMI_MASK; + rt5025_reg_write(ci->i2c, RT5025_REG_IRQEN2, chg_init_regval[7]); + /*turn off recharge irq enable*/ + chg_init_regval[8] &= ~RT5025_CHRCHGI_MASK; + rt5025_reg_write(ci->i2c, RT5025_REG_IRQEN3, chg_init_regval[8]); + } + ci->chg_status = POWER_SUPPLY_STATUS_DISCHARGING; + rt_charger_set_batt_status(ci); + } + break; + case POWER_SUPPLY_PROP_PRESENT: + if (ci->online && val->intval) { + int icc; + int battemp_icc; + int inttemp_icc; + union power_supply_propval pval; + + if (ci->charger_cable == POWER_SUPPLY_TYPE_MAINS) + battemp_icc = inttemp_icc = (ci->screen_on ?\ + ci->screenon_icc:ci->acchg_icc); + else if (ci->charger_cable == POWER_SUPPLY_TYPE_USB_DCP) + battemp_icc = inttemp_icc = (ci->screen_on ?\ + ci->screenon_icc:ci->usbtachg_icc); + else + battemp_icc = inttemp_icc = (ci->screen_on ?\ + ci->screenon_icc:ci->usbchg_icc); + if (ci->battemp_region == RT5025_BATTEMP_COLD ||\ + ci->battemp_region == RT5025_BATTEMP_HOT) + battemp_icc = 10; + else if (ci->battemp_region == RT5025_BATTEMP_COOL ||\ + ci->battemp_region == RT5025_BATTEMP_WARM) + battemp_icc /= 2; + + if (ci->inttemp_region == RT5025_INTTEMP_WARM) + inttemp_icc -= 300; + else if (ci->inttemp_region == RT5025_INTTEMP_HOT) + inttemp_icc -= 800; + + if (inttemp_icc < 0) + inttemp_icc = 10; + + icc = min(battemp_icc, inttemp_icc); + pval.intval = icc; + ret = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &pval); + if (ret < 0) + dev_err(ci->dev, "set final icc fail\n"); + } + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ci->charger_cable = val->intval; + break; + case POWER_SUPPLY_PROP_CURRENT_AVG: + if (0 < val->intval && val->intval <= 100) + regval = 0; + else if (val->intval <= 500) + regval = 1; + else if (val->intval <= 1000) + regval = 2; + else + regval = 3; + if (!ci->batabs) + ret = rt5025_assign_bits(ci->i2c, RT5025_REG_CHGCTL4, \ + RT5025_CHGAICR_MASK, regval << RT5025_CHGAICR_SHFT); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (val->intval < 0) { + ci->otg_en = 1; + regval = -1; + #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN + ret = rt5025_set_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_VBUSHZ_MASK); + if (ret < 0) + dev_err(ci->dev, "set vbus hz fail\n"); + #else + ret = rt5025_clr_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBCEN_MASK); + if (ret < 0) + dev_err(ci->dev, "shutdown chg buck fail\n"); + #endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */ + } else if (val->intval == 0) { + ci->otg_en = 0; + regval = -1; + #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN + ret = rt5025_clr_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_VBUSHZ_MASK); + if (ret < 0) + dev_err(ci->dev, "clear vbus hz fail\n"); + #else + ret = rt5025_set_bits(ci->i2c, RT5025_REG_CHGCTL2, RT5025_CHGBCEN_MASK); + if (ret < 0) + dev_err(ci->dev, "turnon chg buck fail\n"); + #endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */ + } else if (val->intval > 0 && val->intval < 500) { + regval = 0; + } else if (val->intval > 2000) { + regval = 15; + } else { + regval = (val->intval - 500) / 100; + } + + if (regval >= 0) + ret = rt5025_assign_bits(ci->i2c, RT5025_REG_CHGCTL4, RT5025_CHGICC_MASK, \ + regval<intval > 0 && val->intval < 500) + rt5025_clr_bits(ci->i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK); + else + rt5025_set_bits(ci->i2c, RT5025_REG_CHGCTL7, RT5025_CHGCEN_MASK); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (val->intval < 3500) + regval = 0; + else if (val->intval > 4440) + regval = 0x3A; + else + regval = (val->intval - 3500) / 20; + ret = rt5025_assign_bits(ci->i2c, RT5025_REG_CHGCTL3, RT5025_CHGCV_MASK, \ + regval << RT5025_CHGCV_SHFT); + break; + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_STATUS: + default: + ret = -EINVAL; + } + return ret; +} + +#ifdef CONFIG_BATTERY_RT5025 +static int rt5025_set_tempalrt(struct rt5025_charger_info *ci) +{ + int rc = 0; + + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMX_MASK|RT5025_TALRTMN_MASK, 0x00); + if (ci->battemp_region == RT5025_BATTEMP_HOT) { + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMAX, ci->temp_scalar[6]); + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMX_MASK, 0xFF); + } else if (ci->battemp_region == RT5025_BATTEMP_WARM) { + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMAX, ci->temp_scalar[4]); + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMIN, ci->temp_scalar[7]); + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMX_MASK|RT5025_TALRTMN_MASK, 0xFF); + } else if (ci->battemp_region == RT5025_BATTEMP_NORMAL) { + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMAX, ci->temp_scalar[2]); + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMIN, ci->temp_scalar[5]); + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMX_MASK|RT5025_TALRTMN_MASK, 0xFF); + } else if (ci->battemp_region == RT5025_BATTEMP_COOL) { + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMAX, ci->temp_scalar[0]); + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMIN, ci->temp_scalar[3]); + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMX_MASK|RT5025_TALRTMN_MASK, 0xFF); + } else { + rt5025_reg_write(ci->i2c, RT5025_REG_TALRTMIN, ci->temp_scalar[1]); + rt5025_assign_bits(ci->i2c, RT5025_REG_IRQCTL,\ + RT5025_TALRTMN_MASK, 0xFF); + } + return rc; +} +#endif /* #ifdef CONFIG_BATTERY_RT5025 */ + +static void rt_charger_set_batt_status(struct rt5025_charger_info *ci) +{ + #ifdef CONFIG_BATTERY_RT5025 + struct power_supply *psy = power_supply_get_by_name(RT_BATT_NAME); + union power_supply_propval pval; + int rc = 0; + + if (!psy) { + dev_err(ci->dev, "can't get battery supply\n"); + return; + } + pval.intval = ci->chg_status; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_STATUS, &pval); + if (rc < 0) + dev_err(ci->dev, "set battery status fail\n"); + power_supply_changed(psy); + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ +} + +static int rt_charger_check_battery_present(struct rt5025_charger_info *ci) +{ + int rc = 1; + #ifdef CONFIG_BATTERY_RT5025 + struct power_supply *psy = power_supply_get_by_name(RT_BATT_NAME); + union power_supply_propval pval; + + if (!psy) { + dev_err(ci->dev, "can't get battery supply\n"); + return rc; + } + rc = psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + if (rc < 0) { + dev_err(ci->dev, "get battery voltage fail\n"); + } else { + if (pval.intval < (ci->chg_volt - 200) * 1000) + rc = 0; + else + rc = 1; + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + return rc; +} + +static void rt5025_batabs_irq_handler(void *info, int eventno) +{ + struct rt5025_charger_info *ci = info; + struct power_supply *psy = &ci->psy; + union power_supply_propval pval; + int rc = 0; + + #ifdef CONFIG_BATTERY_RT5025 + struct power_supply *bat_psy = power_supply_get_by_name(RT_BATT_NAME); + + pval.intval = 0; + if (!bat_psy) { + dev_err(ci->dev, "get rt-battery supply fail\n"); + } else { + rc = bat_psy->set_property(bat_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) + dev_err(ci->dev, "set battery not present fail\n"); + power_supply_changed(bat_psy); + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + /*set aicr to disable*/ + pval.intval = 2000; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_AVG, &pval); + if (rc < 0) + dev_err(ci->dev, "set aicr to disable fail\n"); + /*set icc to 2000*/ + pval.intval = 2000; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &pval); + if (rc < 0) + dev_err(ci->dev, "set icc to 2000 fail\n"); + /*set online = 0, due to bat absense*/ + pval.intval = 0; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(ci->dev, "set charger offline fail\n"); + ci->batabs = 1; + ci->te_en = 0; +} + +static void rt5025_acin_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_RT_POWER + struct rt5025_charger_info *ci = info; + #ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN + struct power_supply *psy = power_supply_get_by_name(RT_USB_NAME); + #else + struct power_supply *psy = power_supply_get_by_name(RT_AC_NAME); + #endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */ + union power_supply_propval pval; + int rc = 0; + + if (!psy) { + dev_err(ci->dev, "could not get psy supply\n"); + return; + } + pval.intval = 1; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(ci->dev, "set ac online fail\n"); + power_supply_changed(psy); + dev_info(ci->dev, "%s\n", __func__); + #endif /* #ifdef CONFIG_RT_POWER */ +} + +static void rt5025_acout_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_RT_POWER + struct rt5025_charger_info *ci = info; + #ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN + struct power_supply *psy = power_supply_get_by_name(RT_USB_NAME); + #else + struct power_supply *psy = power_supply_get_by_name(RT_AC_NAME); + #endif /* ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */ + union power_supply_propval pval; + int rc = 0; + + if (!psy) { + dev_err(ci->dev, "could not get rt-usb supply\n"); + return; + } + pval.intval = 0; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(ci->dev, "set ac offline fail\n"); + power_supply_changed(psy); + dev_info(ci->dev, "%s\n", __func__); + #endif /* #ifdef CONFIG_RT_POWER */ +} + +static void rt5025_usbin_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_RT_POWER + struct rt5025_charger_info *ci = info; + struct power_supply *psy = power_supply_get_by_name(RT_USB_NAME); + union power_supply_propval pval; + int rc = 0; + + if (!psy) { + dev_err(ci->dev, "could not get rt-usb supply\n"); + return; + } + if (!ci->otg_en) { + pval.intval = 1; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(ci->dev, "set ac online fail\n"); + power_supply_changed(psy); + } + dev_info(ci->dev, "%s\n", __func__); + #endif /* #ifdef CONFIG_RT_POWER */ +} + +static void rt5025_usbout_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_RT_POWER + struct rt5025_charger_info *ci = info; + struct power_supply *psy = power_supply_get_by_name(RT_USB_NAME); + union power_supply_propval pval; + int rc = 0; + + if (!psy) { + dev_err(ci->dev, "could not get rt-usb supply\n"); + return; + } + if (!ci->otg_en) { + pval.intval = 0; + rc = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval); + if (rc < 0) + dev_err(ci->dev, "set ac offline fail\n"); + power_supply_changed(psy); + } + dev_info(ci->dev, "%s\n", __func__); + #endif /* #ifdef CONFIG_RT_POWER */ +} + +static void rt5025_talrtmax_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_BATTERY_RT5025 + struct rt5025_charger_info *ci = info; + union power_supply_propval pval; + int rc = 0; + + switch (ci->battemp_region) { + case RT5025_BATTEMP_COLD: + dev_warn(ci->dev, "cold than cold???\n"); + break; + case RT5025_BATTEMP_COOL: + dev_info(ci->dev, "cool-> cold\n"); + ci->battemp_region = RT5025_BATTEMP_COLD; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_NORMAL: + dev_info(ci->dev, "normal-> cool\n"); + ci->battemp_region = RT5025_BATTEMP_COOL; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_WARM: + dev_info(ci->dev, "warm-> normal\n"); + ci->battemp_region = RT5025_BATTEMP_NORMAL; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_HOT: + dev_info(ci->dev, "hot-> warm\n"); + ci->battemp_region = RT5025_BATTEMP_WARM; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + default: + break; + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ +} + +static void rt5025_talrtmin_irq_handler(void *info, int eventno) +{ + #ifdef CONFIG_BATTERY_RT5025 + struct rt5025_charger_info *ci = info; + union power_supply_propval pval; + int rc = 0; + + switch (ci->battemp_region) { + case RT5025_BATTEMP_COLD: + dev_info(ci->dev, "cold-> cool\n"); + ci->battemp_region = RT5025_BATTEMP_COOL; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_COOL: + dev_info(ci->dev, "cool-> normal\n"); + ci->battemp_region = RT5025_BATTEMP_NORMAL; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_NORMAL: + dev_info(ci->dev, "normal-> warm\n"); + ci->battemp_region = RT5025_BATTEMP_WARM; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, + POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_WARM: + dev_info(ci->dev, "warm-> hot\n"); + ci->battemp_region = RT5025_BATTEMP_HOT; + rt5025_set_tempalrt(ci); + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT,\ + &pval); + if (rc < 0) + dev_err(ci->dev, "set present fail\n"); + break; + case RT5025_BATTEMP_HOT: + dev_warn(ci->dev, "hot than hot???\n"); + break; + default: + break; + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ +} + +static void rt5025_general_irq_handler(void *info, int eventno) +{ + struct rt5025_charger_info *ci = info; + + RTINFO("eventno=%02d\n", eventno); + switch (eventno) { + case CHGEVENT_CHRCHGI: + if (!ci->online) { + dev_warn(ci->dev, "recharge false alarm\n"); + } else { + union power_supply_propval pval; + + dev_info(ci->dev, "recharge occur\n"); + ci->chg_status = POWER_SUPPLY_STATUS_CHARGING; + pval.intval = ci->chg_volt; + rt_charger_set_batt_status(ci); + ci->psy.set_property(&ci->psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + } + break; + case CHGEVENT_CHTERMI: + if (!ci->online) { + dev_warn(ci->dev, "eoc false alarm\n"); + } else { + if (rt_charger_check_battery_present(ci)) { + union power_supply_propval pval; + + if (ci->chg_status == POWER_SUPPLY_STATUS_FULL) + return; + dev_info(ci->dev, "eoc really occur\n"); + ci->chg_status = POWER_SUPPLY_STATUS_FULL; + rt_charger_set_batt_status(ci); + pval.intval = ci->chg_volt-50; + ci->psy.set_property(&ci->psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + } else { + dev_info(ci->dev, "no battery condition\n"); + rt5025_batabs_irq_handler(ci, eventno); + } + } + break; + case CHGEVENT_TALRTMAX: + #ifdef CONFIG_BATTERY_RT5025 + rt5025_set_tempalrt(ci); + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + break; + case CHGEVENT_TALRTMIN: + #ifdef CONFIG_BATTERY_RT5025 + rt5025_set_tempalrt(ci); + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + break; + default: + break; + } +} + +static rt_irq_handler rt_chgirq_handler[CHGEVENT_MAX] = { + [CHGEVENT_TIMEOUT_CC] = rt5025_general_irq_handler, + [CHGEVENT_TIMEOUT_PC] = rt5025_general_irq_handler, + [CHGEVENT_CHVSREGI] = rt5025_general_irq_handler, + [CHGEVENT_CHTREGI] = rt5025_general_irq_handler, + [CHGEVENT_CHRCHGI] = rt5025_general_irq_handler, + [CHGEVENT_CHTERMI] = rt5025_general_irq_handler, + [CHGEVENT_CHBATOVI] = rt5025_general_irq_handler, + [CHGEVENT_CHGOODI_INUSB] = rt5025_general_irq_handler, + [CHGEVENT_CHBADI_INUSB] = rt5025_general_irq_handler, + [CHGEVENT_CHSLPI_INUSB] = rt5025_usbout_irq_handler, + [CHGEVENT_CHGOODI_INAC] = rt5025_general_irq_handler, + [CHGEVENT_CHBADI_INAC] = rt5025_general_irq_handler, + [CHGEVENT_CHSLPI_INAC] = rt5025_acout_irq_handler, + [CHGEVENT_BATABS] = rt5025_batabs_irq_handler, + [CHGEVENT_INUSB_PLUGIN] = rt5025_usbin_irq_handler, + [CHGEVENT_INUSBOVP] = rt5025_general_irq_handler, + [CHGEVENT_INAC_PLUGIN] = rt5025_acin_irq_handler, + [CHGEVENT_INACOVP] = rt5025_general_irq_handler, + [CHGEVENT_TALRTMIN] = rt5025_talrtmin_irq_handler, + [CHGEVENT_TALRTMAX] = rt5025_talrtmax_irq_handler, +}; + +void rt5025_charger_irq_handler(struct rt5025_charger_info *ci, unsigned int irqevent) +{ + int i; + #ifdef CONFIG_BATTERY_RT5025 + unsigned int enable_irq_event = (RT5025_TALRTMX_MASK | RT5025_TALRTMN_MASK)<<24 | \ + (chg_init_regval[6] << 16) | (chg_init_regval[7] << 8) | chg_init_regval[8]; + #else + unsigned int enable_irq_event = (chg_init_regval[6] << 16) + | (chg_init_regval[7] << 8)| \ + chg_init_regval[8]; + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + unsigned int final_irq_event = irqevent&enable_irq_event; + + /*charger workaround (TE+RECHARGE)*/ + if (final_irq_event & (1 << CHGEVENT_CHTERMI) && \ + final_irq_event & (1 << CHGEVENT_CHRCHGI)) + final_irq_event &= ~((1 << CHGEVENT_CHTERMI) | (1 << CHGEVENT_CHRCHGI)); + i = rt5025_reg_read(ci->i2c, RT5025_REG_CHGCTL1); + if (i < 0) { + dev_err(ci->dev, "read CHGCTL1 fail\n"); + i = 0; + } + /*acin+acout*/ + if (final_irq_event & (1 << CHGEVENT_INAC_PLUGIN) && \ + final_irq_event & (1 << CHGEVENT_CHSLPI_INAC)) { + if (i & RT5025_ACUSABLE_MASK) + final_irq_event &= ~(1<dev, "could not get rt-battery psy\n"); + return; + } + if (!ci->init_once) { + /*battemp init*/ + int i = 0; + + pval.intval = 23; /* magic code*/ + psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &pval); + for (i = 3; i >= 0; i--) + if (pval.intval > ci->temp[i]) + break; + if (i == 3) + ci->battemp_region = RT5025_BATTEMP_HOT; + else if (i == 2) + ci->battemp_region = RT5025_BATTEMP_WARM; + else if (i == 1) + ci->battemp_region = RT5025_BATTEMP_NORMAL; + else if (i == 0) + ci->battemp_region = RT5025_BATTEMP_COOL; + else + ci->battemp_region = RT5025_BATTEMP_COLD; + rt5025_set_tempalrt(ci); + ci->init_once = 1; + } + + psy->get_property(psy, POWER_SUPPLY_PROP_TEMP_AMBIENT, &pval); + if (pval.intval > 1000) + inttemp_region = RT5025_INTTEMP_HOT; + else if (pval.intval > 750) + inttemp_region = RT5025_INTTEMP_WARM; + else + inttemp_region = RT5025_INTTEMP_NORMAL; + + if (inttemp_region != ci->inttemp_region) { + ci->inttemp_region = inttemp_region; + pval.intval = 1; + rt_charger_set_property(&ci->psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + } + #endif /* #ifdef CONFIG_BATTERY_RT5025 */ + if (!ci->suspend) + schedule_delayed_work(&ci->tempmon_work, 5*HZ); +} + +static int rt5025_charger_reginit(struct i2c_client *client) +{ + rt5025_reg_block_write(client, RT5025_REG_CHGCTL2, 6, chg_init_regval); + /*set all to be masked*/ + rt5025_reg_write(client, RT5025_REG_IRQEN1, 0x00); + rt5025_reg_write(client, RT5025_REG_IRQEN2, 0x00); + rt5025_reg_write(client, RT5025_REG_IRQEN3, 0x00); + /*just clear the old irq event*/ + rt5025_reg_read(client, RT5025_REG_IRQSTAT1); + rt5025_reg_read(client, RT5025_REG_IRQSTAT2); + rt5025_reg_read(client, RT5025_REG_IRQSTAT3); + /*set enable irqs as we want*/ + rt5025_reg_write(client, RT5025_REG_IRQEN1, chg_init_regval[6]); + rt5025_reg_write(client, RT5025_REG_IRQEN2, chg_init_regval[7]); + rt5025_reg_write(client, RT5025_REG_IRQEN3, chg_init_regval[8]); + RTINFO("\n"); + return 0; +} + +static int rt_parse_dt(struct rt5025_charger_info *ci, struct device *dev) +{ + #ifdef CONFIG_OF + struct device_node *np = dev->of_node; + u32 val; + + if (of_property_read_bool(np, "rt,te_en")) + ci->te_en = 1; + + if (of_property_read_u32(np, "rt,iprec", &val)) { + dev_info(dev, "no iprec property, use default value\n"); + } else{ + if (val > RT5025_IPREC_MAX) + val = RT5025_IPREC_MAX; + chg_init_regval[4] &= (~RT5025_CHGIPREC_MASK); + chg_init_regval[4] |= (val << RT5025_CHGIPREC_SHFT); + } + + if (of_property_read_u32(np, "rt,ieoc", &val)) { + dev_info(dev, "no ieoc property, use the default value\n"); + } else { + if (val > RT5025_IEOC_MAX) + val = RT5025_IEOC_MAX; + chg_init_regval[4] &= (~RT5025_CHGIEOC_MASK); + chg_init_regval[4] |= (val << RT5025_CHGIEOC_SHFT); + } + + if (of_property_read_u32(np, "rt,vprec", &val)) { + dev_info(dev, "no vprec property, use the default value\n"); + } else { + if (val > RT5025_VPREC_MAX) + val = RT5025_VPREC_MAX; + chg_init_regval[4] &= (~RT5025_CHGVPREC_MASK); + chg_init_regval[4] |= (val << RT5025_CHGVPREC_SHFT); + } + + if (of_property_read_u32(np, "rt,vdpm", &val)) { + dev_info(dev, "no vdpm property, use the default value\n"); + } else { + if (val > RT5025_VDPM_MAX) + val = RT5025_VDPM_MAX; + chg_init_regval[3] &= (~RT5025_CHGVDPM_MASK); + chg_init_regval[3] |= (val << RT5025_CHGVDPM_SHFT); + } + + if (of_property_read_u32(np, "rt,chg_volt", &val)) { + dev_info(dev, "no chg_volt property, use 4200 as the default value\n"); + ci->chg_volt = 4200; + } else { + ci->chg_volt = val; + } + + if (of_property_read_u32(np, "rt,acchg_icc", &val)) { + dev_info(dev, "no acchg_icc property, use 2000 as the default value\n"); + ci->acchg_icc = 2000; + } else { + ci->acchg_icc = val; + } + + if (of_property_read_u32(np, "rt,usbtachg_icc", &val)) { + dev_info(dev, "no usbtachg_icc property, use 2000 as the default value\n"); + ci->usbtachg_icc = 2000; + } else { + ci->usbtachg_icc = val; + } + + if (of_property_read_u32(np, "rt,usbchg_icc", &val)) { + dev_info(dev, "no usbchg_icc property, use 500 as the default value\n"); + ci->usbchg_icc = 500; + } else { + ci->usbchg_icc = val; + } + + if (of_property_read_u32(np, "rt,screenon_icc", &val)) { + dev_info(dev, "no screenon_icc property, use 500 as the default value\n"); + ci->screenon_icc = 500; + } else { + ci->screenon_icc = val; + } + + if (of_property_read_bool(np, "rt,screenon_adjust")) { + ci->screenon_adjust = 1; + ci->screen_on = 1; + } + + if (of_property_read_u32_array(np, "rt,temp", + ci->temp, 4)) { + dev_info(dev, "no temperature property, use default value\n"); + ci->temp[0] = 0; + ci->temp[1] = 150; + ci->temp[2] = 500; + ci->temp[3] = 600; + } + + if (of_property_read_u32_array(np, "rt,temp_scalar", + ci->temp_scalar, 8)) { + dev_info(dev, "no temp_scalar property, use default value\n"); + ci->temp_scalar[0] = 0x30; + ci->temp_scalar[1] = 0x2B; + ci->temp_scalar[2] = 0x28; + ci->temp_scalar[3] = 0x22; + ci->temp_scalar[4] = 0x15; + ci->temp_scalar[5] = 0x10; + ci->temp_scalar[6] = 0x10; + ci->temp_scalar[7] = 0x0D; + } + #endif /* #ifdef CONFIG_OF */ + rt5025_charger_reginit(ci->i2c); + RTINFO("\n"); + return 0; +} + +static int rt_parse_pdata(struct rt5025_charger_info *ci, struct device *dev) +{ + struct rt5025_charger_data *pdata = dev->platform_data; + int i = 0; + + if (pdata->te_en) + ci->te_en = 1; + + chg_init_regval[4] &= (~RT5025_CHGIPREC_MASK); + chg_init_regval[4] |= (pdata->iprec << RT5025_CHGIPREC_SHFT); + + chg_init_regval[4] &= (~RT5025_CHGIEOC_MASK); + chg_init_regval[4] |= (pdata->ieoc << RT5025_CHGIEOC_SHFT); + + chg_init_regval[4] &= (~RT5025_CHGVPREC_MASK); + chg_init_regval[4] |= (pdata->vprec << RT5025_CHGVPREC_SHFT); + + chg_init_regval[3] &= (~RT5025_CHGVDPM_MASK); + chg_init_regval[3] |= (pdata->vdpm << RT5025_CHGVDPM_SHFT); + + ci->chg_volt = pdata->chg_volt; + ci->acchg_icc = pdata->acchg_icc; + ci->usbtachg_icc = pdata->usbtachg_icc; + ci->usbchg_icc = pdata->usbchg_icc; + ci->screenon_icc = pdata->screenon_icc; + if (pdata->screenon_adjust) { + ci->screenon_adjust = 1; + /*default probe screen will on*/ + ci->screen_on = 1; + } + for (i = 0; i < 4; i++) + ci->temp[i] = pdata->temp[i]; + for (i = 0; i < 8; i++) + ci->temp_scalar[i] = pdata->temp_scalar[i]; + rt5025_charger_reginit(ci->i2c); + RTINFO("\n"); + return 0; +} + +#ifdef CONFIG_RT_POWER +static struct platform_device rt_power_dev = { + .name = "rt-power", + .id = -1, +}; +#endif /* #ifdef CONFIG_RT_POWER */ + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void rt5025_charger_earlysuspend(struct early_suspend *handler) +{ + struct rt5025_charger_info *ci = container_of(handler, \ + struct rt5025_charger_info, early_suspend); + union power_supply_propval pval; + int rc = 0; + + if (ci->screenon_adjust) { + ci->screen_on = 0; + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) + dev_err(ci->dev, "set charger present property fail\n"); + } +} + +static void rt5025_charger_earlyresume(struct early_suspend *handler) +{ + struct rt5025_charger_info *ci = container_of(handler, \ + struct rt5025_charger_info, early_suspend); + union power_supply_propval pval; + int rc = 0; + + if (ci->screenon_adjust) { + ci->screen_on = 1; + pval.intval = 1; + rc = ci->psy.set_property(&ci->psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + if (rc < 0) + dev_err(ci->dev, "set charger present property fail\n"); + } +} +#endif /* #ifdef CONFIG_HAS_EARLYSUSPEND */ + +static int rt5025_charger_probe(struct platform_device *pdev) +{ + struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct rt5025_platform_data *pdata = + (pdev->dev.parent)->platform_data; + #ifdef CONFIG_RT_POWER + struct rt_power_data *rt_power_pdata; + #endif /* #ifdef CONFIG_RT_POWER */ + struct rt5025_charger_info *ci; + bool use_dt = pdev->dev.of_node; + int ret = 0; + + ci = devm_kzalloc(chip->dev, sizeof(struct rt5025_charger_info), GFP_KERNEL); + if (!ci) + return -ENOMEM; + + ci->i2c = chip->i2c; + ci->dev = &pdev->dev; + ci->chg_status = POWER_SUPPLY_STATUS_DISCHARGING; + ci->battemp_region = RT5025_BATTEMP_NORMAL; + ci->inttemp_region = RT5025_INTTEMP_NORMAL; + #ifdef CONFIG_RT_JEITA_REMOVE + ci->init_once = 1; + #endif /* #ifdef RT_JEITA_REMOVE */ + + if (use_dt) { + rt_parse_dt(ci, &pdev->dev); + } else { + if (!pdata) { + ret = -EINVAL; + goto out_dev; + } + pdev->dev.platform_data = pdata->chg_pdata; + rt_parse_pdata(ci, &pdev->dev); + } + INIT_DELAYED_WORK(&ci->tempmon_work, rt5025_tempmon_work); + + platform_set_drvdata(pdev, ci); + /*power supply register*/ + ci->psy.name = rtdef_chg_name; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + ci->psy.type = POWER_SUPPLY_TYPE_UNKNOWN; + #else + ci->psy.type = -1; + #endif /* #ifdef (LINUX_VERSION_CODE */ + ci->psy.supplied_to = rt_charger_supply_list; + ci->psy.properties = rt_charger_props; + ci->psy.num_properties = ARRAY_SIZE(rt_charger_props); + ci->psy.get_property = rt_charger_get_property; + ci->psy.set_property = rt_charger_set_property; + ret = power_supply_register(&pdev->dev, &ci->psy); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't create power supply for rt-charger\n"); + goto out_dev; + } + + #ifdef CONFIG_HAS_EARLYSUSPEND + ci->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1; + ci->early_suspend.suspend = rt5025_charger_earlysuspend; + ci->early_suspend.resume = rt5025_charger_earlyresume; + register_early_suspend(&ci->early_suspend); + #endif /* CONFIG_HAS_EARLYSUSPEND */ + + #ifdef CONFIG_RT_POWER + rt_power_pdata = devm_kzalloc(&pdev->dev, + sizeof(*rt_power_pdata), GFP_KERNEL); + if (!rt_power_pdata) { + ret = -ENOMEM; + goto out_psy; + } + rt_power_pdata->chg_volt = ci->chg_volt; + rt_power_pdata->acchg_icc = ci->acchg_icc; + rt_power_pdata->usbtachg_icc = ci->usbtachg_icc; + rt_power_pdata->usbchg_icc = ci->usbchg_icc; + + rt_power_dev.dev.platform_data = rt_power_pdata; + rt_power_dev.dev.parent = &pdev->dev; + ret = platform_device_register(&rt_power_dev); + if (ret < 0) + goto out_psy; + #endif /* #ifdef CONFIG_RT_POWER */ + + chip->charger_info = ci; + schedule_delayed_work(&ci->tempmon_work, 1*HZ); + dev_info(&pdev->dev, "driver successfully loaded\n"); + return 0; +#ifdef CONFIG_RT_POWER +out_psy: +#endif /* #ifdef CONFIG_RT_POWER */ + #ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ci->early_suspend); + #endif /* #ifdef CONFIG_HAS_EARLYSUSPEND */ + power_supply_unregister(&ci->psy); +out_dev: + return ret; +} + +static int rt5025_charger_remove(struct platform_device *pdev) +{ + struct rt5025_charger_info *ci = platform_get_drvdata(pdev); + + power_supply_unregister(&ci->psy); + #ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&ci->early_suspend); + #endif /* #ifdef CONFIG_HAS_EARLYSUSPEND */ + #ifdef CONFIG_RT_POWER + platform_device_unregister(&rt_power_dev); + #endif /* #ifdef CONFIG_RT_POWER */ + return 0; +} + +static int rt5025_charger_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct rt5025_charger_info *ci = platform_get_drvdata(pdev); + union power_supply_propval pval; + + ci->suspend = 1; + cancel_delayed_work_sync(&ci->tempmon_work); + /*force inttemp to normal temp*/ + ci->inttemp_region = RT5025_INTTEMP_NORMAL; + pval.intval = 1; + rt_charger_set_property(&ci->psy, POWER_SUPPLY_PROP_PRESENT, &pval); + return 0; +} + +static int rt5025_charger_resume(struct platform_device *pdev) +{ + struct rt5025_charger_info *ci = platform_get_drvdata(pdev); + + ci->suspend = 0; + schedule_delayed_work(&ci->tempmon_work, msecs_to_jiffies(50)); + return 0; +} + +static const struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-charger",}, + {}, +}; + +static struct platform_driver rt5025_charger_driver = { + .driver = { + .name = RT5025_DEV_NAME "-charger", + .owner = THIS_MODULE, + .of_match_table = rt_match_table, + }, + .probe = rt5025_charger_probe, + .remove = rt5025_charger_remove, + .suspend = rt5025_charger_suspend, + .resume = rt5025_charger_resume, +}; + +static int rt5025_charger_init(void) +{ + return platform_driver_register(&rt5025_charger_driver); +} +fs_initcall_sync(rt5025_charger_init); + +static void rt5025_charger_exit(void) +{ + platform_driver_unregister(&rt5025_charger_driver); +} + +module_exit(rt5025_charger_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("CY Huang "); +MODULE_DESCRIPTION("Charger driver for RT5025"); +MODULE_ALIAS("platform:"RT5025_DEV_NAME "-charger"); +MODULE_VERSION(RT5025_DRV_VER); diff --git a/drivers/power/rt5025-power.c b/drivers/power/rt5025-power.c old mode 100644 new mode 100755 diff --git a/drivers/power/rt5025-swjeita.c b/drivers/power/rt5025-swjeita.c old mode 100644 new mode 100755 index 52e777c0044f..62041ad22cf2 --- a/drivers/power/rt5025-swjeita.c +++ b/drivers/power/rt5025-swjeita.c @@ -22,11 +22,12 @@ #include #include -#define TEMP_TOLERANCE 30 // 'c*10 gap for tolerance +#define TEMP_TOLERANCE 30 /*'c*10 gap for tolerance*/ static int rt5025_set_charging_cc_switch (struct i2c_client *i2c, int onoff) { int ret; + RTINFO("onoff = %d\n", onoff); if (onoff) ret = rt5025_set_bits(i2c, RT5025_REG_CHGCTL7, RT5025_CHGCCEN_MASK); @@ -44,9 +45,9 @@ static int rt5025_set_charging_cc(struct i2c_client *i2c, int cur_value) if (cur_value < 500) data = 0; else if (cur_value > 2000) - data = 0xf< 4440) - data = 0x2f<i2c, RT5025_REG_AINH, 2, data) < 0) pr_err("%s: failed to read ext_temp register\n", __func__); - temp = (data[0]*256+data[1])*61/100; - temp = (temp * (-91738) +81521000)/100000; + temp = (data[0] * 256 + data[1]) * 61 / 100; + temp = (temp * (-91738) + 81521000) / 100000; swji->cur_temp = temp; RTINFO("cur_section = %d, cur_temp = %d\n", swji->cur_section, swji->cur_temp); - switch (swji->cur_section) - { - case 0: - if (temp < swji->temp[0]+TEMP_TOLERANCE) - sect_index = rt5025_sel_external_temp_index(swji); - else - sect_index = swji->cur_section; - break; - case 1: - if (temp <= swji->temp[0]-TEMP_TOLERANCE || temp >= swji->temp[1]+TEMP_TOLERANCE) - sect_index = rt5025_sel_external_temp_index(swji); - else - sect_index = swji->cur_section; - break; - case 2: - if (temp <= swji->temp[1]-TEMP_TOLERANCE || temp >= swji->temp[2]+TEMP_TOLERANCE) - sect_index = rt5025_sel_external_temp_index(swji); - else - sect_index = swji->cur_section; - break; - case 3: - if (temp <= swji->temp[2]-TEMP_TOLERANCE || temp >= swji->temp[3]+TEMP_TOLERANCE) - sect_index = rt5025_sel_external_temp_index(swji); - else - sect_index = swji->cur_section; - break; - case 4: - if (temp <= swji->temp[3]-TEMP_TOLERANCE) - sect_index = rt5025_sel_external_temp_index(swji); - else - sect_index = swji->cur_section; - break; - default: - sect_index = swji->cur_section; - break; + switch (swji->cur_section) { + case 0: + if (temp < swji->temp[0] + TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 1: + if (temp <= swji->temp[0] - TEMP_TOLERANCE || temp >= swji->temp[1] + TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 2: + if (temp <= swji->temp[1] - TEMP_TOLERANCE || temp >= swji->temp[2] + TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 3: + if (temp <= swji->temp[2] - TEMP_TOLERANCE || temp >= swji->temp[3] + TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + case 4: + if (temp <= swji->temp[3] - TEMP_TOLERANCE) + sect_index = rt5025_sel_external_temp_index(swji); + else + sect_index = swji->cur_section; + break; + default: + sect_index = swji->cur_section; + break; } RTINFO("sect_index = %d\n", sect_index); return sect_index; @@ -185,65 +185,60 @@ static int rt5025_set_exttemp_alert(struct rt5025_swjeita_info *swji, int index) RTINFO("index = %d\n", index); - switch (index) - { + switch (index) { + case 0: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]); + break; + case 1: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]); + break; + case 2: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[5]); + break; + case 3: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[4]); + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[7]); + break; + case 4: + rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[6]); + break; + } + + return ret; +} + +static int rt5025_exttemp_alert_switch(struct rt5025_swjeita_info *swji, int onoff) +{ + if (!onoff) { + rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); + } else { + switch (swji->cur_section) { case 0: - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[1]); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 1: - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[0]); - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[3]); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 2: - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[2]); - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[5]); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 3: - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[4]); - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMIN, swji->temp_scalar[7]); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); break; case 4: - rt5025_reg_write(swji->i2c, RT5025_REG_TALRTMAX, swji->temp_scalar[6]); + rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); break; - } - - return ret; -} - -static int rt5025_exttemp_alert_switch(struct rt5025_swjeita_info *swji, int onoff) -{ - if (!onoff) - { - rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); - rt5025_clr_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); - } - else - { - switch (swji->cur_section) - { - case 0: - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); - break; - case 1: - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); - break; - case 2: - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); - break; - case 3: - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMNEN_MASK); - break; - case 4: - rt5025_set_bits(swji->i2c, RT5025_REG_IRQCTL, RT5025_TMXEN_MASK); - break; } } RTINFO("index=%d, onoff=%d\n", swji->cur_section, onoff); - return 0; + return 0; } int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_type) @@ -256,34 +251,32 @@ int rt5025_notify_charging_cable(struct rt5025_swjeita_info *swji, int cable_typ rt5025_exttemp_alert_switch(swji, 0); sect_index = rt5025_get_external_temp_index(swji); - if (swji->cur_section != sect_index || swji->init_once == 0) - { + if (swji->cur_section != sect_index || swji->init_once == 0) { rt5025_set_exttemp_alert(swji, sect_index); swji->cur_section = sect_index; swji->init_once = 1; } - switch (cable_type) - { - case JEITA_NORMAL_USB: - rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - - swji->dec_current); - rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); - break; - case JEITA_USB_TA: - rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - - swji->dec_current); - rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); - break; - case JEITA_AC_ADAPTER: - rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ - - swji->dec_current); - rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); - break; - case JEITA_NO_CHARGE: - rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); - rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); - break; + switch (cable_type) { + case JEITA_NORMAL_USB: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ + - swji->dec_current); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_USB_TA: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ + - swji->dec_current); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_AC_ADAPTER: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]\ + - swji->dec_current); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; + case JEITA_NO_CHARGE: + rt5025_set_charging_cc(swji->i2c, swji->temp_cc[cable_type][swji->cur_section]); + rt5025_set_charging_cv(swji->i2c, swji->temp_cv[cable_type][swji->cur_section]); + break; } swji->cur_cable = cable_type; @@ -298,7 +291,7 @@ int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *swji, unsigned char e int ret = 0; RTINFO("event = 0x%02x\n", event); - if (event&(RT5025_TMXEN_MASK|RT5025_TMNEN_MASK)) + if (event&(RT5025_TMXEN_MASK | RT5025_TMNEN_MASK)) rt5025_notify_charging_cable(swji, swji->cur_cable); return ret; @@ -309,54 +302,51 @@ static void rt5025_get_internal_temp(struct rt5025_swjeita_info *swji) { u8 data[2]; s32 temp; - if (rt5025_reg_block_read(swji->i2c, RT5025_REG_INTTEMP_MSB, 2, data) < 0){ + if (rt5025_reg_block_read(swji->i2c, RT5025_REG_INTTEMP_MSB, 2, data) < 0) pr_err("%s: Failed to read internal TEMPERATURE\n", __func__); - } - temp = ((data[0]&0x1F)<<8) + data[1]; + temp = ((data[0] & 0x1F) << 8) + data[1]; temp *= 15625; temp /= 100000; - temp = (data[0]&0x20)?-temp:temp; + temp = (data[0] & 0x20) ? -temp : temp; swji->cur_inttemp = temp; RTINFO("internal temperature: %d\n", temp); } - + static void thermal_reg_work_func(struct work_struct *work) { struct delayed_work *delayed_work = (struct delayed_work *)container_of(work, struct delayed_work, work); struct rt5025_swjeita_info *swji = (struct rt5025_swjeita_info *)container_of(delayed_work, struct rt5025_swjeita_info, thermal_reg_work); int therm_region = 0; - + RTINFO("%s ++", __func__); rt5025_get_internal_temp(swji); #if 1 - switch (swji->cur_therm_region) - { - case 0: - if (swji->cur_inttemp >=820) - therm_region = 1; - else - therm_region = 0; - break; - case 1: - if (swji->cur_inttemp <= 780) - therm_region = 0; - else if (swji->cur_inttemp >= 1020) - therm_region = 2; - else - therm_region = 1; - break; - case 2: - if (swji->cur_inttemp <= 980) - therm_region = 1; - else - therm_region = 2; - break; - - } + switch (swji->cur_therm_region) { + case 0: + if (swji->cur_inttemp >= 820) + therm_region = 1; + else + therm_region = 0; + break; + case 1: + if (swji->cur_inttemp <= 780) + therm_region = 0; + else if (swji->cur_inttemp >= 1020) + therm_region = 2; + else + therm_region = 1; + break; + case 2: + if (swji->cur_inttemp <= 980) + therm_region = 1; + else + therm_region = 2; + break; + } #else if (swji->cur_inttemp < 800) therm_region = 0; @@ -366,19 +356,17 @@ static void thermal_reg_work_func(struct work_struct *work) therm_region = 2; #endif /* #if 1*/ - if (therm_region != swji->cur_therm_region) - { - switch (therm_region) - { - case 0: - swji->dec_current = 0; - break; - case 1: - swji->dec_current = 300; - break; - case 2: - swji->dec_current = 800; - break; + if (therm_region != swji->cur_therm_region) { + switch (therm_region) { + case 0: + swji->dec_current = 0; + break; + case 1: + swji->dec_current = 300; + break; + case 2: + swji->dec_current = 800; + break; } swji->cur_therm_region = therm_region; rt5025_notify_charging_cable(swji, swji->cur_cable); @@ -390,10 +378,10 @@ static void thermal_reg_work_func(struct work_struct *work) RTINFO("%s --", __func__); } -static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) +static int rt5025_swjeita_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_platform_data *pdata = chip->dev->platform_data; struct rt5025_swjeita_info *swji; int ret = 0; @@ -401,23 +389,20 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) if (!swji) return -ENOMEM; - #if 0 // for debug pdata->jeita_data - for (ret=0; ret<4; ret++) + #if 0 /* for debug pdata->jeita_data*/ + for (ret = 0; ret < 4; ret++) RTINFO("jeita temp value %d\n", pdata->jeita_data->temp[ret]); - for (ret=0; ret<4; ret++) - { + for (ret = 0; ret < 4; ret++) { RTINFO("jeita temp_cc value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cc[ret][0], \ pdata->jeita_data->temp_cc[ret][1], pdata->jeita_data->temp_cc[ret][2], \ pdata->jeita_data->temp_cc[ret][3], pdata->jeita_data->temp_cc[ret][4]); } - for (ret=0; ret<4; ret++) - { + for (ret = 0; ret < 4; ret++) { RTINFO("jeita temp_cv value %d, %d, %d, %d, %d\n", pdata->jeita_data->temp_cv[ret][0], \ pdata->jeita_data->temp_cv[ret][1], pdata->jeita_data->temp_cv[ret][2], \ pdata->jeita_data->temp_cv[ret][3], pdata->jeita_data->temp_cv[ret][4]); } - for (ret=0; ret<8; ret++) - { + for (ret = 0; ret < 8; ret++) { RTINFO("temp_scalar[%d] = 0x%02x\n", ret, pdata->jeita_data->temp_scalar[ret]); } ret = 0; @@ -425,7 +410,8 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) swji->i2c = chip->i2c; swji->chip = chip; - swji->cur_section = 2; //initial as the normal temperature + swji->cur_section = 2; + /*initial as the normal temperature*/ swji->cur_cable = JEITA_NO_CHARGE; swji->temp = pdata->jeita_data->temp; swji->temp_scalar = pdata->jeita_data->temp_scalar; @@ -445,7 +431,7 @@ static int __devinit rt5025_swjeita_probe(struct platform_device *pdev) return ret; } -static int __devexit rt5025_swjeita_remove(struct platform_device *pdev) +static int rt5025_swjeita_remove(struct platform_device *pdev) { struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); @@ -458,6 +444,7 @@ static int __devexit rt5025_swjeita_remove(struct platform_device *pdev) static int rt5025_swjeita_suspend(struct platform_device *pdev, pm_message_t state) { struct rt5025_swjeita_info *swji = platform_get_drvdata(pdev); + swji->suspend = 1; cancel_delayed_work_sync(&swji->thermal_reg_work); swji->cur_therm_region = swji->dec_current = 0; @@ -476,8 +463,7 @@ static int rt5025_swjeita_resume(struct platform_device *pdev) return 0; } -static struct platform_driver rt5025_swjeita_driver = -{ +static struct platform_driver rt5025_swjeita_driver = { .driver = { .name = RT5025_DEVICE_NAME "-swjeita", .owner = THIS_MODULE, @@ -488,13 +474,13 @@ static struct platform_driver rt5025_swjeita_driver = .resume = rt5025_swjeita_resume, }; -static int __init rt5025_swjeita_init(void) +static int rt5025_swjeita_init(void) { return platform_driver_register(&rt5025_swjeita_driver); } module_init(rt5025_swjeita_init); -static void __exit rt5025_swjeita_exit(void) +static void rt5025_swjeita_exit(void) { platform_driver_unregister(&rt5025_swjeita_driver); } diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index a55583ce5012..13e1a2f433c7 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -262,6 +262,13 @@ config ACT8846_SUPPORT_RESET help Support short press key to restart. +config REGULATOR_RT5025 + bool "Richtek RT5025 PMIC Voltage regulstors" + depends on MFD_RT5025 + default n + help + This driver supports voltage regulator in RT5025 PMIC chips. + config ROCKCHIP_PWM_REGULATOR tristate "rockchip pwm voltage regulator for discrete dcdc or ldo" help diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e81fad7415c8..153030939736 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o obj-$(CONFIG_REGULATOR_ACT8846) += act8846.o obj-$(CONFIG_REGULATOR_SYR82X) += syr82x.o obj-$(CONFIG_REGULATOR_RICOH619) += ricoh619-regulator.o +obj-$(CONFIG_REGULATOR_RT5025) += rt5025-regulator.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip_io_vol_domain.o diff --git a/drivers/regulator/rt5025-regulator.c b/drivers/regulator/rt5025-regulator.c index 46f7c7a0bec5..eabbe5cce544 100755 --- a/drivers/regulator/rt5025-regulator.c +++ b/drivers/regulator/rt5025-regulator.c @@ -2,12 +2,13 @@ * drivers/regulator/rt5025-regulator.c * Driver foo Richtek RT5025 PMIC Regulator * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2014 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #include @@ -18,6 +19,10 @@ #include #include #include +#ifdef CONFIG_OF +#include +#endif /* #ifdef CONFIG_OF */ + #include #include @@ -25,7 +30,6 @@ struct rt5025_regulator_info { struct regulator_desc desc; struct regulator_dev *regulator; struct i2c_client *i2c; - struct rt5025_chip *chip; const unsigned int *vol_output_list; const int vol_output_size; int min_uV; @@ -37,11 +41,12 @@ struct rt5025_regulator_info { int enable_reg; int mode_bit; int mode_reg; + int ramp_bit; + int ramp_reg; }; -//for DCDC1 -static const unsigned int rt5025_vol_output_list1[] = -{ +/*for DCDC1*/ +static const unsigned int rt5025_vol_output_list1[] = { 700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000, 900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000, 1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000, @@ -53,9 +58,8 @@ static const unsigned int rt5025_vol_output_list1[] = }; #define rt5025_vol_output_size1 ARRAY_SIZE(rt5025_vol_output_list1) -//DCDC2, LDO1, LDO2 -static const unsigned int rt5025_vol_output_list2[] = -{ +/*DCDC2, LDO1, LDO2*/ +static const unsigned int rt5025_vol_output_list2[] = { 700*1000, 725*1000, 750*1000, 775*1000, 800*1000, 825*1000, 850*1000, 875*1000, 900*1000, 925*1000, 950*1000, 975*1000, 1000*1000, 1025*1000, 1050*1000, 1075*1000, 1100*1000, 1125*1000, 1150*1000, 1175*1000, 1200*1000, 1225*1000, 1250*1000, 1275*1000, @@ -75,9 +79,8 @@ static const unsigned int rt5025_vol_output_list2[] = }; #define rt5025_vol_output_size2 ARRAY_SIZE(rt5025_vol_output_list2) -//DCDC3 -static const unsigned int rt5025_vol_output_list3[] = -{ +/*DCDC3*/ +static const unsigned int rt5025_vol_output_list3[] = { 700*1000, 750*1000, 800*1000, 850*1000, 900*1000, 950*1000, 1000*1000, 1050*1000, 1100*1000, 1150*1000, 1200*1000, 1250*1000, 1300*1000, 1350*1000, 1400*1000, 1450*1000, 1500*1000, 1550*1000, 1600*1000, 1650*1000, 1700*1000, 1750*1000, 1800*1000, 1850*1000, @@ -89,17 +92,15 @@ static const unsigned int rt5025_vol_output_list3[] = }; #define rt5025_vol_output_size3 ARRAY_SIZE(rt5025_vol_output_list3) -//DCDC4 -static const unsigned int rt5025_vol_output_list4[] = -{ +/*DCDC4*/ +static const unsigned int rt5025_vol_output_list4[] = { 4500*1000, 4600*1000, 4700*1000, 4800*1000, 4900*1000, 5000*1000, 5100*1000, 5200*1000, 5300*1000, 5400*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, 5500*1000, }; #define rt5025_vol_output_size4 ARRAY_SIZE(rt5025_vol_output_list4) -//LDO3, LDO4, LDO5, LDO6 -static const unsigned int rt5025_vol_output_list5[] = -{ +/*LDO3, LDO4, LDO5, LDO6*/ +static const unsigned int rt5025_vol_output_list5[] = { 1000*1000, 1100*1000, 1200*1000, 1300*1000, 1400*1000, 1500*1000, 1600*1000, 1700*1000, 1800*1000, 1900*1000, 2000*1000, 2100*1000, 2200*1000, 2300*1000, 2400*1000, 2500*1000, 2600*1000, 2700*1000, 2800*1000, 2900*1000, 3000*1000, 3100*1000, 3200*1000, 3300*1000, @@ -121,29 +122,29 @@ static int rt5025_list_voltage(struct regulator_dev *rdev, unsigned index) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); - return (index>=info->vol_output_size)? \ - -EINVAL: \ - info->vol_output_list[index]; + return (index >= info->vol_output_size) ? -EINVAL : info->vol_output_list[index]; } -#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) static int rt5025_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data; const int count = info->vol_output_size; - if (selector>count) + if (selector > count) return -EINVAL; data = (unsigned char)selector; data <<= info->vol_shift; - return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data); + return rt5025_assign_bits(info->i2c, info->vol_reg, + info->vol_mask, data); } static int rt5025_get_voltage_sel(struct regulator_dev *rdev) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); int ret; + ret = rt5025_reg_read(info->i2c, info->vol_reg); if (ret < 0) return ret; @@ -154,12 +155,12 @@ static int rt5025_find_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); - int i=0; + int i = 0; const int count = info->vol_output_size; - for (i=0;ivol_output_list[i]>=min_uV) - && (info->vol_output_list[i]<=max_uV)) + + for (i = 0; i < count; i++) { + if ((info->vol_output_list[i] >= min_uV) + && (info->vol_output_list[i] <= max_uV)) return i; } return -EINVAL; @@ -167,20 +168,20 @@ static int rt5025_find_voltage(struct regulator_dev *rdev, static int rt5025_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) - { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data; if (check_range(info, min_uV, max_uV)) { - dev_err(info->chip->dev, "invalid voltage range (%d, %d) uV\n", + dev_err(&rdev->dev, "invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } - data = rt5025_find_voltage(rdev,min_uV,max_uV); + data = rt5025_find_voltage(rdev, min_uV, max_uV); data <<= info->vol_shift; - return rt5025_assign_bits(info->i2c, info->vol_reg, info->vol_mask, data); + return rt5025_assign_bits(info->i2c, info->vol_reg, + info->vol_mask, data); } @@ -188,6 +189,7 @@ static int rt5025_get_voltage(struct regulator_dev *rdev) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); int ret; + ret = rt5025_reg_read(info->i2c, info->vol_reg); if (ret < 0) return ret; @@ -220,29 +222,29 @@ static int rt5025_is_enabled(struct regulator_dev *rdev) ret = rt5025_reg_read(info->i2c, info->enable_reg); if (ret < 0) return ret; - - return (ret & (info->enable_bit))?1:0; + return (ret & (info->enable_bit))?1 : 0; } static int rt5025_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct rt5025_regulator_info *info = rdev_get_drvdata(rdev); int ret; - if (!info->mode_bit) + + if (!info->mode_bit) { ret = 0; - else - { - switch (mode) - { - case REGULATOR_MODE_NORMAL: - ret = rt5025_set_bits(info->i2c, info->mode_reg, info->mode_bit); - break; - case REGULATOR_MODE_FAST: - ret = rt5025_clr_bits(info->i2c, info->mode_reg, info->mode_bit); - break; - default: - ret = -EINVAL; - break; + } else { + switch (mode) { + case REGULATOR_MODE_NORMAL: + ret = rt5025_set_bits(info->i2c, info->mode_reg, + info->mode_bit); + break; + case REGULATOR_MODE_FAST: + ret = rt5025_clr_bits(info->i2c, info->mode_reg, + info->mode_bit); + break; + default: + ret = -EINVAL; + break; } } return ret; @@ -254,19 +256,18 @@ static unsigned int rt5025_get_mode(struct regulator_dev *rdev) unsigned int mode; int data; - if (!info->mode_bit) + if (!info->mode_bit) { mode = REGULATOR_MODE_NORMAL; - else - { + } else { data = rt5025_reg_read(info->i2c, info->mode_reg); - mode = (data & info->mode_bit)?REGULATOR_MODE_NORMAL:REGULATOR_MODE_FAST; + mode = (data & info->mode_bit)?REGULATOR_MODE_NORMAL : REGULATOR_MODE_FAST; } return mode; } static struct regulator_ops rt5025_regulator_ops = { .list_voltage = rt5025_list_voltage, -#if 0 //(LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) .get_voltage_sel = rt5025_get_voltage_sel, .set_voltage_sel = rt5025_set_voltage_sel, #else @@ -306,24 +307,26 @@ static struct regulator_ops rt5025_regulator_ops = { #define RT5025_DCDC(_id, min, max) \ { \ .desc = { \ - .name = "rt5025-dcdc" #_id, \ + .name = "rt5025-dcdc" #_id, \ .n_voltages = RT5025_DCDCVOUT_SIZE##_id, \ .ops = &rt5025_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .id = RT5025_ID_DCDC##_id, \ .owner = THIS_MODULE, \ }, \ - .vol_output_list= RT5025_DCDCVOUT_LIST##_id, \ - .vol_output_size= RT5025_DCDCVOUT_SIZE##_id, \ - .min_uV = min , \ - .max_uV = max , \ + .vol_output_list = RT5025_DCDCVOUT_LIST##_id, \ + .vol_output_size = RT5025_DCDCVOUT_SIZE##_id, \ + .min_uV = min * 1000, \ + .max_uV = max * 1000, \ .vol_reg = RT5025_DCDCVOUT##_id, \ .vol_shift = RT5025_DCDCVOUT_SHIFT##_id, \ .vol_mask = RT5025_DCDCVOUT_MASK##_id, \ - .enable_reg = RT5025_DCDC_OUTPUT_EN, \ + .enable_reg = RT5025_REG_DCDCONOFF, \ .enable_bit = RT5025_DCDCEN_MASK##_id, \ - .mode_reg = RT5025_REG_DCDCVRC, \ - .mode_bit = RT5025_DCDCMODE_MASK##_id \ + .mode_reg = RT5025_DCDCMODE_REG##_id, \ + .mode_bit = RT5025_DCDCMODE_MASK##_id, \ + .ramp_reg = RT5025_DCDCVOUT##_id, \ + .ramp_bit = RT5025_DCDCRAMP_MASK##_id, \ } #define RT5025_LDO(_id, min, max) \ @@ -336,34 +339,31 @@ static struct regulator_ops rt5025_regulator_ops = { .id = RT5025_ID_LDO##_id, \ .owner = THIS_MODULE, \ }, \ - .vol_output_list= RT5025_LDOVOUT_LIST##_id, \ - .vol_output_size= RT5025_LDOVOUT_SIZE##_id, \ - .min_uV = min , \ - .max_uV = max, \ + .vol_output_list = RT5025_LDOVOUT_LIST##_id, \ + .vol_output_size = RT5025_LDOVOUT_SIZE##_id, \ + .min_uV = min * 1000, \ + .max_uV = max * 1000, \ .vol_reg = RT5025_LDOVOUT##_id, \ .vol_shift = RT5025_LDOVOUT_SHIFT##_id, \ .vol_mask = RT5025_LDOVOUT_MASK##_id, \ - .enable_reg = RT5025_LDO_OUTPUT_EN, \ + .enable_reg = RT5025_REG_LDOONOFF, \ .enable_bit = RT5025_LDOEN_MASK##_id, \ - .mode_reg = RT5025_REG_LDOVRC, \ - .mode_bit = RT5025_LDOMODE_MASK##_id, \ } -static struct rt5025_regulator_info rt5025_regulator_info[] = -{ - RT5025_DCDC(1, 700000, 2275000), - RT5025_DCDC(2, 700000, 3500000), - RT5025_DCDC(3, 700000, 3500000), - RT5025_DCDC(4, 4500000, 5500000), - RT5025_LDO( 1, 700000, 3500000), - RT5025_LDO( 2, 700000, 3500000), - RT5025_LDO( 3, 1000000, 3300000), - RT5025_LDO( 4, 1000000, 3300000), - RT5025_LDO( 5, 1000000, 3300000), - RT5025_LDO( 6, 1000000, 3300000), +static struct rt5025_regulator_info rt5025_regulator_info[] = { + RT5025_DCDC(1, 700, 2275), + RT5025_DCDC(2, 700, 3500), + RT5025_DCDC(3, 700, 3500), + RT5025_DCDC(4, 4500, 5500), + RT5025_LDO(1, 700, 3500), + RT5025_LDO(2, 700, 3500), + RT5025_LDO(3, 1000, 3300), + RT5025_LDO(4, 1000, 3300), + RT5025_LDO(5, 1000, 3300), + RT5025_LDO(6, 1000, 3300), }; -static struct rt5025_regulator_info * __devinit find_regulator_info(int id) +static struct rt5025_regulator_info *find_regulator_info(int id) { struct rt5025_regulator_info *ri; int i; @@ -375,43 +375,87 @@ static struct rt5025_regulator_info * __devinit find_regulator_info(int id) } return NULL; } - -inline struct regulator_dev* rt5025_regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, - void *driver_data) +struct regulator_dev *rt5025_regulator_register(struct regulator_desc *regulator_desc, + struct device *dev, struct regulator_init_data *init_data, + void *driver_data) { -#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) - struct regulator_config config = { - .dev = dev, - .init_data = init_data, - .driver_data = driver_data, - }; - return regulator_register(®ulator_desc, &config); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) + struct regulator_config config = { + .dev = dev, + .init_data = init_data, + .driver_data = driver_data, + .of_node = dev->of_node, + }; + return regulator_register(regulator_desc, &config); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 37)) + return regulator_register(regulator_desc, dev, init_data, + driver_data, dev->of_node); #else - return regulator_register(regulator_desc,dev,init_data,driver_data); + return regulator_register(regulator_desc, dev, init_data, driver_data); #endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */ } -static int __devinit rt5025_regulator_probe(struct platform_device *pdev) +static struct regulator_init_data *of_parse_dt(struct rt5025_regulator_info *ri, + struct device *dev) +{ + struct regulator_init_data *init_data = NULL; + #ifdef CONFIG_OF + struct device_node *np = dev->of_node; + int rc; + u32 tmp; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) + init_data = of_get_regulator_init_data(dev, dev->of_node); + #else + init_data = of_get_regulator_init_data(dev); + #endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) */ + rc = of_property_read_u32(np, "rt,ramp_sel", &tmp); + if (rc) { + dev_info(dev, "no ramp_sel property, use default value\n"); + } else { + if (tmp > RT5025_DCDCRAMP_MAX) + tmp = RT5025_DCDCRAMP_MAX; + rt5025_assign_bits(ri->i2c, ri->ramp_reg, ri->ramp_bit, tmp); + } + + if (of_property_read_bool(np, "rt,allow_mode_mask")) { + init_data->constraints.valid_modes_mask |= + (REGULATOR_MODE_FAST|\ + REGULATOR_MODE_NORMAL); + init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; + } + #endif /* #ifdef CONFIG_OF */ + return init_data; +} + +static int rt5025_regulator_probe(struct platform_device *pdev) { struct rt5025_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct rt5025_platform_data *pdata = chip->dev->platform_data; + struct rt5025_platform_data *pdata = (pdev->dev.parent)->platform_data; struct rt5025_regulator_info *ri; + struct rt5025_regulator_ramp *ramp; struct regulator_dev *rdev; - struct regulator_init_data* init_data; + struct regulator_init_data *init_data; + bool use_dt = pdev->dev.of_node; ri = find_regulator_info(pdev->id); if (ri == NULL) { dev_err(&pdev->dev, "invalid regulator ID specified\n"); return -EINVAL; } - init_data = pdata->regulator[pdev->id]; - if (init_data == NULL) { + ri->i2c = chip->i2c; + if (use_dt) { + init_data = of_parse_dt(ri, &pdev->dev); + } else { + init_data = pdata->regulator[pdev->id]; + ramp = init_data->driver_data; + if (ramp) + rt5025_assign_bits(ri->i2c, ri->ramp_reg, + ri->ramp_bit, ramp->ramp_sel); + } + if (!init_data) { dev_err(&pdev->dev, "no initializing data\n"); return -EINVAL; } - ri->i2c = chip->i2c; - ri->chip = chip; rdev = rt5025_regulator_register(&ri->desc, &pdev->dev, init_data, ri); @@ -420,46 +464,59 @@ static int __devinit rt5025_regulator_probe(struct platform_device *pdev) ri->desc.name); return PTR_ERR(rdev); } - platform_set_drvdata(pdev, rdev); - +/* dev_info(&pdev->dev, "driver successfully loaded\n");*/ return 0; } -static int __devexit rt5025_regulator_remove(struct platform_device *pdev) +static int rt5025_regulator_remove(struct platform_device *pdev) { struct regulator_dev *rdev = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); regulator_unregister(rdev); - + dev_info(&pdev->dev, "%s\n", __func__); return 0; } -static struct platform_driver rt5025_regulator_driver = -{ +static struct of_device_id rt_match_table[] = { + { .compatible = "rt,rt5025-dcdc1",}, + { .compatible = "rt,rt5025-dcdc2",}, + { .compatible = "rt,rt5025-dcdc3",}, + { .compatible = "rt,rt5025-dcdc4",}, + { .compatible = "rt,rt5025-ldo1",}, + { .compatible = "rt,rt5025-ldo2",}, + { .compatible = "rt,rt5025-ldo3",}, + { .compatible = "rt,rt5025-ldo4",}, + { .compatible = "rt,rt5025-ldo5",}, + { .compatible = "rt,rt5025-ldo6",}, + {}, +}; + +static struct platform_driver rt5025_regulator_driver = { .driver = { - .name = RT5025_DEVICE_NAME "-regulator", + .name = RT5025_DEV_NAME "-regulator", .owner = THIS_MODULE, + .of_match_table = rt_match_table, }, .probe = rt5025_regulator_probe, - .remove = __devexit_p(rt5025_regulator_remove), + .remove = rt5025_regulator_remove, }; -static int __init rt5025_regulator_init(void) +static int rt5025_regulator_init(void) { return platform_driver_register(&rt5025_regulator_driver); } -subsys_initcall_sync(rt5025_regulator_init); +subsys_initcall(rt5025_regulator_init); -static void __exit rt5025_regulator_exit(void) +static void rt5025_regulator_exit(void) { platform_driver_unregister(&rt5025_regulator_driver); } module_exit(rt5025_regulator_exit); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("CY Huang "); MODULE_DESCRIPTION("Regulator driver for RT5025"); -MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-regulator"); +MODULE_ALIAS("platform:" RT5025_DEV_NAME "-regulator"); MODULE_VERSION(RT5025_DRV_VER); diff --git a/include/linux/mfd/rt5025-gpio.h b/include/linux/mfd/rt5025-gpio.h index 0215077a7978..04ba1370c67c 100755 --- a/include/linux/mfd/rt5025-gpio.h +++ b/include/linux/mfd/rt5025-gpio.h @@ -1,26 +1,21 @@ /* - * include/linux/mfd/rt5025-gpio.h + * include/linux/mfd/rt5025/rt5025-gpio.h * Include header file for Richtek RT5025 PMIC GPIO file * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2013 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #ifndef __LINUX_RT5025_GPIO_H #define __LINUX_RT5025_GPIO_H -#define RT5025_REG_GPIO0 0x1C -#define RT5025_REG_GPIO1 0x1D -#define RT5025_REG_GPIO2 0x1E - -#define RT5025_GPIO_NR 3 - -#define RT5025_GPIO_INPUT 0x00 -#define RT5025_GPIO_OUTPUT 0x02 +#define RT5025_GPIO_INPUT 0x00 +#define RT5025_GPIO_OUTPUT 0x02 #define RT5025_GPIO_DIRSHIFT 6 #define RT5025_GPIO_DIRMASK 0xC0 diff --git a/include/linux/mfd/rt5025-irq.h b/include/linux/mfd/rt5025-irq.h old mode 100644 new mode 100755 index d826b2fc625d..66a7f05b6eb6 --- a/include/linux/mfd/rt5025-irq.h +++ b/include/linux/mfd/rt5025-irq.h @@ -1,39 +1,19 @@ /* - * include/linux/mfd/rt5025-irq.h + * include/linux/mfd/rt5025/rt5025-irq.h * Include header file for Richtek RT5025 PMIC IRQ file * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2014 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #ifndef __LINUX_RT5025_IRQ_H #define __LINUX_RT5025_IRQ_H -#define RT5025_REG_CHGSTAT 0x01 - -#define RT5025_REG_IRQEN1 0x30 -#define RT5025_REG_IRQSTATUS1 0x31 -#define RT5025_REG_IRQEN2 0x32 -#define RT5025_REG_IRQSTATUS2 0x33 -#define RT5025_REG_IRQEN3 0x34 -#define RT5025_REG_IRQSTATUS3 0x35 -#define RT5025_REG_IRQEN4 0x36 -#define RT5025_REG_IRQSTATUS4 0x37 -#define RT5025_REG_IRQEN5 0x38 -#define RT5025_REG_IRQSTATUS5 0x39 - -#define RT5025_INACIRQ_MASK 0x40 -#define RT5025_INUSBIRQ_MASK 0x08 -#define RT5025_ADAPIRQ_MASK (RT5025_INACIRQ_MASK|RT5025_INUSBIRQ_MASK) -#define RT5025_CHTERMI_MASK 0x01 - -#define RT5025_REG_GAUGEIRQEN 0x50 -#define RT5025_REG_GAUGEIRQFLG 0x51 -#define RT5025_FLG_TEMP 0x30 -#define RT5025_FLG_VOLT 0x07 +#define RT5025_TALRT_MASK 0x30 #endif /* #ifndef __LINUX_RT5025_IRQ_H */ diff --git a/include/linux/mfd/rt5025-misc.h b/include/linux/mfd/rt5025-misc.h old mode 100644 new mode 100755 index 20cadd2684cd..8db2ab7a4a4f --- a/include/linux/mfd/rt5025-misc.h +++ b/include/linux/mfd/rt5025-misc.h @@ -1,5 +1,5 @@ /* - * include/linux/mfd/rt5025-misc.h + * include/linux/mfd/rt5025/rt5025-misc.h * Include header file for Richtek RT5025 PMIC Misc * * Copyright (C) 2013 Richtek Technology Corp. @@ -14,15 +14,36 @@ #ifndef __LINUX_RT5025_MISC_H #define __LINUX_RT5025_MISC_H -#define RT5025_RESETCTRL_REG 0x15 -#define RT5025_VSYSULVO_REG 0x17 -#define RT5025_PWRONCTRL_REG 0x19 -#define RT5025_SHDNCTRL_REG 0x1A -#define RT5025_PWROFFEN_REG 0x1B -#define RT5025_CHENH_REG 0x62 -#define RT5025_CHENL_REG 0x63 +enum { + MISCEVENT_GPIO0_IE = 1, + MISCEVENT_GPIO1_IE, + MISCEVENT_GPIO2_IE, + MISCEVENT_RESETB, + MISCEVENT_PWRONF, + MISCEVENT_PWRONR, + MISCEVENT_KPSHDN, + MISCEVENT_SYSLV, + MISCEVENT_DCDC4LVHV, + MISCEVENT_PWRONLP_IRQ, + MISCEVENT_PWRONSP_IRQ, + MISCEVENT_DCDC3LV, + MISCEVENT_DCDC2LV, + MISCEVENT_DCDC1LV, + MISCEVENT_OT, + MISCEVENT_MAX, +}; #define RT5025_SHDNCTRL_MASK 0x80 #define RT5025_VSYSOFF_MASK 0xE0 +#define RT5025_VSYSOFF_SHFT 5 +#define RT5025_SHDNLPRESS_MASK 0x0C +#define RT5025_SHDNLPRESS_SHFT 2 +#define RT5025_STARTLPRESS_MASK 0xC0 +#define RT5025_STARTLPRESS_SHFT 6 +#define RT5025_VSYSLVSHDN_MASK 0x80 +#define RT5025_VSYSLVSHDN_SHFT 7 +#define RT5025_CABLEIN_MASK 0x03 + +extern int rt5025_cable_exist(void); #endif /* #ifndef __LINUX_RT5025_MISC_H */ diff --git a/include/linux/mfd/rt5025.h b/include/linux/mfd/rt5025.h old mode 100644 new mode 100755 index 3d5ba95de0d9..961c639ecc5a --- a/include/linux/mfd/rt5025.h +++ b/include/linux/mfd/rt5025.h @@ -1,36 +1,147 @@ /* - * include/linux/mfd/rt5025.h + * include/linux/mfd/rt5025/rt5025.h * Include header file for Richtek RT5025 Core file * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2013 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #ifndef __LINUX_MFD_RT5025_H #define __LINUX_MFD_RT5025_H #include -#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif /* CONFIG_HAS_EARLYSUSPEND */ -#define RT5025_DEVICE_NAME "RT5025" -#define RT5025_DRV_VER "1.0.8_R" +#define RT5025_DEV_NAME "rt5025" +#define RT5025_DRV_VER "1.1.0_R" -enum { - RT5025_RSTDELAY1_100MS, - RT5025_RSTDELAY1_500MS, - RT5025_RSTDELAY1_1S, - RT5025_RSTDELAY1_2S, -}; +#define RT_BATT_NAME "rt-battery" enum { - RT5025_RSTDELAY2_100MS, - RT5025_RSTDELAY2_500MS, - RT5025_RSTDELAY2_1S, - RT5025_RSTDELAY2_2S, + RT5025_REG_DEVID, + RT5025_REG_RANGE1START = RT5025_REG_DEVID, + RT5025_REG_CHGCTL1, + RT5025_REG_CHGCTL2, + RT5025_REG_CHGCTL3, + RT5025_REG_CHGCTL4, + RT5025_REG_CHGCTL5, + RT5025_REG_CHGCTL6, + RT5025_REG_CHGCTL7, + RT5025_REG_DCDCCTL1, + RT5025_REG_DCDCCTL2, + RT5025_REG_DCDCCTL3, + RT5025_REG_VRCCTL, + RT5025_REG_DCDCCTL4, + RT5025_REG_LDOCTL1, + RT5025_REG_LDOCTL2, + RT5025_REG_LDOCTL3, + RT5025_REG_LDOCTL4, + RT5025_REG_LDOCTL5, + RT5025_REG_LDOCTL6, + RT5025_REG_RESV0, + RT5025_REG_LDOOMS, + RT5025_REG_MISC1, + RT5025_REG_ONEVENT, + RT5025_REG_DCDCONOFF, + RT5025_REG_LDOONOFF, + RT5025_REG_MISC2, + RT5025_REG_MISC3, + RT5025_REG_MISC4, + RT5025_REG_GPIO0, + RT5025_REG_GPIO1, + RT5025_REG_GPIO2, + RT5025_REG_RANGE1END = RT5025_REG_GPIO2, + RT5025_REG_OFFEVENT = 0x20, + RT5025_REG_RANGE2START = RT5025_REG_OFFEVENT, + RT5025_REG_RESV1, + RT5025_REG_RESV2, + RT5025_REG_RESV3, + RT5025_REG_RESV4, + RT5025_REG_RESV5, + RT5025_REG_RESV6, + RT5025_REG_RESV7, + RT5025_REG_RESV8, + RT5025_REG_RESV9, + RT5025_REG_RESV10, + RT5025_REG_RESV11, + RT5025_REG_RESV12, + RT5025_REG_RESV13, + RT5025_REG_RESV14, + RT5025_REG_RESV15, + RT5025_REG_IRQEN1, + RT5025_REG_IRQSTAT1, + RT5025_REG_IRQEN2, + RT5025_REG_IRQSTAT2, + RT5025_REG_IRQEN3, + RT5025_REG_IRQSTAT3, + RT5025_REG_IRQEN4, + RT5025_REG_IRQSTAT4, + RT5025_REG_IRQEN5, + RT5025_REG_IRQSTAT5, + RT5025_REG_RANGE2END = RT5025_REG_IRQSTAT5, + RT5025_REG_IRQCTL = 0x50, + RT5025_REG_RANGE3START = RT5025_REG_IRQCTL, + RT5025_REG_IRQFLG, + RT5025_REG_FGRESV1, + RT5025_REG_VALRTMAX, + RT5025_REG_VALRTMIN1, + RT5025_REG_VALRTMIN2, + RT5025_REG_TALRTMAX, + RT5025_REG_TALRTMIN, + RT5025_REG_VBATSH, + RT5025_REG_VBATSL, + RT5025_REG_INTEMPH, + RT5025_REG_INTEMPL, + RT5025_REG_FGRESV2, + RT5025_REG_CONFIG, + RT5025_REG_AINH, + RT5025_REG_AINL, + RT5025_REG_TIMERH, + RT5025_REG_TIMERL, + RT5025_REG_CHANNELH, + RT5025_REG_CHANNELL, + RT5025_REG_INACVLTH, + RT5025_REG_INACVLTL, + RT5025_REG_INUSBVLTH, + RT5025_REG_INUSBVLTL, + RT5025_REG_VSYSVLTH, + RT5025_REG_VSYSVLTL, + RT5025_REG_GPIO0VLTH, + RT5025_REG_GPIO0VLTL, + RT5025_REG_GPIO1VLTH, + RT5025_REG_GPIO1VLTL, + RT5025_REG_GPIO2VLTH, + RT5025_REG_GPIO2VLTL, + RT5025_REG_DCDC1VLTH, + RT5025_REG_DCDC1VLTL, + RT5025_REG_DCDC2VLTH, + RT5025_REG_DCDC2VLTL, + RT5025_REG_DCDC3VLTH, + RT5025_REG_DCDC3VLTL, + RT5025_REG_CURRH, + RT5025_REG_CURRL, + RT5025_REG_QCHGHH, + RT5025_REG_QCHGHL, + RT5025_REG_QCHGLH, + RT5025_REG_QCHGLL, + RT5025_REG_QDCHGHH, + RT5025_REG_QDCHGHL, + RT5025_REG_QDCHGLH, + RT5025_REG_QDCHGLL, + RT5025_REG_RANGE3END = RT5025_REG_QDCHGLL, + RT5025_REG_DCDC4OVP = 0xA9, + RT5025_REG_RANGE4START = RT5025_REG_DCDC4OVP, + RT5025_REG_RANGE4END = RT5025_REG_DCDC4OVP, + RT5025_REG_MAX, }; enum { @@ -42,6 +153,7 @@ enum { RT5025_VOFF_3P3V, RT5025_VOFF_3P4V, RT5025_VOFF_3P5V, + RT5025_VOFF_MAX = RT5025_VOFF_3P5V, }; enum { @@ -49,13 +161,7 @@ enum { RT5025_STARTIME_1S, RT5025_STARTIME_2S, RT5025_STARTIME_3S, -}; - -enum { - RT5025_LPRESS_1S, - RT5025_LPRESS_1P5S, - RT5025_LPRESS_2S, - RT5025_LPRESS_2P5S, + RT5025_STARTIME_MAX = RT5025_STARTIME_3S, }; enum { @@ -63,68 +169,21 @@ enum { RT5025_SHDNPRESS_6S, RT5025_SHDNPRESS_8S, RT5025_SHDNPRESS_10S, + RT5025_SHDNPRESS_MAX = RT5025_SHDNPRESS_10S, }; enum { - RT5025_PGDLY_10MS, - RT5025_PGDLY_50MS, - RT5025_PGDLY_100MS, - RT5025_PGDLY_200MS, -}; - -enum { - RT5025_SHDNDLY_100MS, - RT5025_SHDNDLY_500MS, - RT5025_SHDNDLY_1S, - RT5025_SHDNDLY_2S, -}; - -enum { - RT5025_CCCHG_TO_4H, - RT5025_CCCHG_TO_6H, - RT5025_CCCHG_TO_8H, - RT5025_CCCHG_TO_10H, + RT5025_VDPM_4V, + RT5025_VDPM_4P25V, + RT5025_VDPM_4P5V, + RT5025_VDPM_DIS, + RT5025_VDPM_MAX = RT5025_VDPM_DIS, }; enum { - RT5025_PRECHG_TO_30M, - RT5025_PRECHG_TO_40M, - RT5025_PRECHG_TO_50M, - RT5025_PRECHG_TO_60M, -}; - -enum { - RT5025_ICC_0P5A, - RT5025_ICC_0P6A, - RT5025_ICC_0P7A, - RT5025_ICC_0P8A, - RT5025_ICC_0P9A, - RT5025_ICC_1A, - RT5025_ICC_1P1A, - RT5025_ICC_1P2A, - RT5025_ICC_1P3A, - RT5025_ICC_1P4A, - RT5025_ICC_1P5A, - RT5025_ICC_1P6A, - RT5025_ICC_1P7A, - RT5025_ICC_1P8A, - RT5025_ICC_1P9A, - RT5025_ICC_2A, - RT5025_ICC_MAX, -}; - -enum { - RT5025_AICR_100MA, - RT5025_AICR_500MA, - RT5025_AICR_1A, - RT5025_AICR_NOLIMIT, -}; - -enum { - RT5025_DPM_4V, - RT5025_DPM_4P25V, - RT5025_DPM_4P5V, - RT5025_DPM_DIS, + RT5025_IEOC_10P, + RT5025_IEOC_20P, + RT5025_IEOC_MAX = RT5025_IEOC_20P, }; enum { @@ -134,18 +193,13 @@ enum { RT5025_VPREC_2P6V, RT5025_VPREC_2P8V, RT5025_VPREC_3V, - RT5025_VPREC_3V_1, - RT5025_VPREC_3V_2, -}; - -enum { - RT5025_IEOC_10P, - RT5025_IEOC_20P, + RT5025_VPREC_MAX = RT5025_VPREC_3V, }; enum { RT5025_IPREC_10P, RT5025_IPREC_20P, + RT5025_IPREC_MAX = RT5025_IPREC_20P, }; enum { @@ -162,306 +216,58 @@ enum { RT5025_MAX_REGULATOR, }; -struct rt5025_power_data { - union { - struct { - unsigned char Resv1:1; - unsigned char CHGBC_EN:1; - unsigned char TE:1; - unsigned char Resv2:1; - unsigned char CCCHG_TIMEOUT:2; - unsigned char PRECHG_TIMEOUT:2; - }bitfield; - unsigned char val; - }CHGControl2; - union { - struct { - unsigned char Resv:2; - unsigned char VOREG:6; - }bitfield; - unsigned char val; - }CHGControl3; - union { - struct { - unsigned char AICR_CON:1; - unsigned char AICR:2; - unsigned char ICC:4; - unsigned char CHG_RST:1; - }bitfield; - unsigned char val; - }CHGControl4; - union { - struct { - unsigned char Resv1:4; - unsigned char DPM:2; - unsigned char Resv2:2; - }bitfield; - unsigned char val; - }CHGControl5; - union { - struct { - unsigned char IPREC:1; - unsigned char IEOC:1; - unsigned char VPREC:3; - unsigned char Resv:3; - }bitfield; - unsigned char val; - }CHGControl6; - union { - struct { - unsigned char Resv1:4; - unsigned char CHGC_EN:1; - unsigned char CHG_DCDC_MODE:1; - unsigned char BATD_EN:1; - unsigned char Resv2:1; - }bitfield; - unsigned char val; - }CHGControl7; -}; - -struct rt5025_gpio_data { - unsigned gpio_base; - unsigned irq_base; -}; - -struct rt5025_misc_data { - union { - struct { - unsigned char Action:2; - unsigned char Delayed1:2; - unsigned char Delayed2:2; - unsigned char Resv:2; - }bitfield; - unsigned char val; - }RSTCtrl; - union { - struct { - unsigned char Resv:5; - unsigned char VOFF:3; - }bitfield; - unsigned char val; - }VSYSCtrl; - union { - struct { - unsigned char PG_DLY:2; - unsigned char SHDN_PRESS:2; - unsigned char LPRESS_TIME:2; - unsigned char START_TIME:2; - }bitfield; - unsigned char val; - }PwrOnCfg; - union { - struct { - unsigned char Resv:4; - unsigned char SHDN_DLYTIME:2; - unsigned char SHDN_TIMING:1; - unsigned char SHDN_CTRL:1; - }bitfield; - unsigned char val; - }SHDNCtrl; - union { - struct { - unsigned char Resv:2; - unsigned char OT_ENSHDN:1; - unsigned char PWRON_ENSHDN:1; - unsigned char DCDC3LV_ENSHDN:1; - unsigned char DCDC2LV_ENSHDN:1; - unsigned char DCDC1LV_ENSHDN:1; - unsigned char SYSLV_ENSHDN:1; - }bitfield; - unsigned char val; - }PwrOffCond; -}; - -struct rt5025_irq_data { - union { - struct { - unsigned char BATABS:1; - unsigned char Resv1:2; - unsigned char INUSB_PLUGIN:1; - unsigned char INUSBOVP:1; - unsigned char Resv2:1; - unsigned char INAC_PLUGIN:1; - unsigned char INACOVP:1; - }bitfield; - unsigned char val; - }irq_enable1; - union { - struct { - unsigned char CHTERMI:1; - unsigned char CHBATOVI:1; - unsigned char CHGOODI_INUSB:1; - unsigned char CHBADI_INUSB:1; - unsigned char CHSLPI_INUSB:1; - unsigned char CHGOODI_INAC:1; - unsigned char CHBADI_INAC:1; - unsigned char CHSLPI_INAC:1; - }bitfield; - unsigned char val; - }irq_enable2; - union { - struct { - unsigned char TIMEOUT_CC:1; - unsigned char TIMEOUT_PC:1; - unsigned char Resv:3; - unsigned char CHVSREGI:1; - unsigned char CHTREGI:1; - unsigned char CHRCHGI:1; - }bitfield; - unsigned char val; - }irq_enable3; - union { - struct { - unsigned char SYSLV:1; - unsigned char DCDC4LVHV:1; - unsigned char PWRONLP:1; - unsigned char PWRONSP:1; - unsigned char DCDC3LV:1; - unsigned char DCDC2LV:1; - unsigned char DCDC1LV:1; - unsigned char OT:1; - }bitfield; - unsigned char val; - }irq_enable4; - union { - struct { - unsigned char Resv:1; - unsigned char GPIO0_IE:1; - unsigned char GPIO1_IE:1; - unsigned char GPIO2_IE:1; - unsigned char RESETB:1; - unsigned char PWRONF:1; - unsigned char PWRONR:1; - unsigned char KPSHDN:1; - }bitfield; - unsigned char val; - }irq_enable5; -}; - -enum { - JEITA_NO_CHARGE, - JEITA_NORMAL_USB, - JEITA_USB_TA, - JEITA_AC_ADAPTER, - JEITA_CHARGER_MAX, -}; - -struct rt5025_jeita_data { - int* temp; - u8* temp_scalar; - int (*temp_cc)[5]; - int (*temp_cv)[5]; -}; +typedef void (*rt_irq_handler)(void *info, int eventno); -#define CHG_EVENT_INACOVP (0x80<<16) -#define CHG_EVENT_INAC_PLUGIN (0x40<<16) -#define CHG_EVENT_INUSBOVP (0x10<<16) -#define CHG_EVENT_INUSB_PLUGIN (0x08<<16) -#define CHG_EVENT_BAT_ABS (0x01<<16) - -#define CHG_EVENT_CHSLPI_INAC (0x80<<8) -#define CHG_EVENT_CHBADI_INAC (0x40<<8) -#define CHG_EVENT_CHGOODI_INAC (0x20<<8) -#define CHG_EVENT_CHSLPI_INUSB (0x10<<8) -#define CHG_EVENT_CHBADI_INUSB (0x08<<8) -#define CHG_EVENT_CHGOODI_INUSB (0x04<<8) -#define CHG_EVENT_CHBATOVI (0x02<<8) -#define CHG_EVENT_CHTERMI (0x01<<8) - -#define CHG_EVENT_CHRCHGI (0x80<<0) -#define CHG_EVENT_CHTREGI (0x40<<0) -#define CHG_EVENT_CHVSREGI (0x20<<0) -#define CHG_EVENT_TIMEOUTPC (0x02<<0) -#define CHG_EVENT_TIMEOUTCC (0x01<<0) - -#define CHARGER_DETECT_MASK (CHG_EVENT_INAC_PLUGIN | CHG_EVENT_INUSB_PLUGIN | \ - CHG_EVENT_CHSLPI_INAC | CHG_EVENT_CHSLPI_INUSB | \ - CHG_EVENT_CHBADI_INAC | CHG_EVENT_CHBADI_INUSB | \ - CHG_EVENT_CHTERMI | CHG_EVENT_CHRCHGI) - - -#define PWR_EVENT_OTIQ (0x80<<8) -#define PWR_EVENT_DCDC1LV (0x40<<8) -#define PWR_EVENT_DCDC2LV (0x20<<8) -#define PWR_EVENT_DCDC3LV (0x10<<8) -#define PWR_EVENT_PWRONSP (0x08<<8) -#define PWR_EVENT_PWRONLP (0x04<<8) -#define PWR_EVENT_DCDC4LVHV (0x02<<8) -#define PWR_EVENT_SYSLV (0x01<<8) - -#define PWR_EVENT_KPSHDN (0x80<<0) -#define PWR_EVNET_PWRONR (0x40<<0) -#define PWR_EVENT_PWRONF (0x20<<0) -#define PWR_EVENT_RESETB (0x10<<0) -#define PWR_EVENT_GPIO2IE (0x08<<0) -#define PWR_EVENT_GPIO1IE (0x04<<0) -#define PWR_EVENT_GPIO0IE (0x02<<0) - -struct rt5025_event_callback { - #if 1 - void (*charger_event_callback)(uint32_t detected); - void (*power_event_callkback)(uint32_t detected); - #else - void (*over_temperature_callback)(uint8_t detected); - void (*charging_complete_callback)(void); - void (*over_voltage_callback)(uint8_t detected); - void (*under_voltage_callback)(uint8_t detected); - void (*charge_fault_callback)(uint8_t detected); - void (*charge_warning_callback)(uint8_t detected); - #endif +#define RT5025_DCDCRAMP_MAX 0x03 +struct rt5025_regulator_ramp { + unsigned char ramp_sel:2; }; -struct rt5025_power_info { +struct rt5025_charger_info { struct i2c_client *i2c; struct device *dev; - struct rt5025_chip *chip; - //struct rt5025_gauge_callbacks *event_callback; - struct power_supply ac; - struct power_supply usb; - struct mutex var_lock; - struct delayed_work usb_detect_work; - int usb_cnt; - int chg_term; - int otg_en; - unsigned ac_online:1; - unsigned usb_online:1; - unsigned chg_stat:3; -}; - -struct rt5025_swjeita_info { - struct i2c_client *i2c; - struct rt5025_chip *chip; - struct delayed_work thermal_reg_work; - int *temp; - u8 *temp_scalar; - int (*temp_cc)[5]; - int (*temp_cv)[5]; - int dec_current; - int cur_section; - int cur_therm_region; - int cur_cable; - int cur_temp; - int cur_inttemp; - int init_once; - int suspend; + struct power_supply psy; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + struct delayed_work tempmon_work; + int temp[4]; + u32 temp_scalar[8]; + unsigned int te_en:1; + unsigned int online:1; + unsigned int batabs:1; + unsigned int battemp_region:3; + unsigned int inttemp_region:2; + unsigned int otg_en:1; + unsigned int init_once:1; + unsigned int suspend:1; + unsigned int screenon_adjust:1; + unsigned int screen_on:1; + int chg_status; + int charger_cable; + int chg_volt; + int acchg_icc; + int usbtachg_icc; + int usbchg_icc; + int screenon_icc; }; struct rt5025_battery_info { struct i2c_client *client; - struct rt5025_chip *chip; - //struct rt5025_gauge_callbacks cb; - struct power_supply battery; - struct delayed_work monitor_work; struct wake_lock monitor_wake_lock; struct wake_lock low_battery_wake_lock; struct wake_lock status_wake_lock; -//#if RT5025_TEST_WAKE_LOCK - struct wake_lock test_wake_lock; -//#endif + struct wake_lock smooth0_wake_lock; + struct wake_lock smooth100_wake_lock; + struct wake_lock full_battery_wake_lock; + /*#if RT5025_TEST_WAKE_LOCK + // struct wake_lock test_wake_lock; + //#endif*/ + struct mutex status_change_lock; struct alarm wakeup_alarm; - + bool temp_range_0_5; bool temp_range_5_10; bool temp_range_10_15; @@ -471,7 +277,7 @@ struct rt5025_battery_info { bool temp_range_35_40; bool temp_range_40_45; bool temp_range_45_50; - + bool range_0_5_done; bool range_5_10_done; bool range_10_15_done; @@ -481,159 +287,183 @@ struct rt5025_battery_info { bool range_35_40_done; bool range_40_45_done; bool range_45_50_done; - - - + bool suspend_poll; ktime_t last_poll; -// ktime_t last_event; - struct timespec last_event; - - u16 update_time; - - /* previous battery voltage */ - u16 pre_vcell; - /* previous battery current */ - s16 pre_curr; - /* battery voltage */ - u16 vcell; - /* battery current */ - s16 curr; - /* battery current offset */ - u16 curr_offset; - /* AIN voltage */ - u16 ain_volt; - /* battery internal temperature */ - s16 int_temp; - /* battery external temperature */ - s16 ext_temp; - /* charge coulomb counter */ - u32 chg_cc; - u32 chg_cc_unuse; - /* discharge coulomb counter */ - u32 dchg_cc; - u32 dchg_cc_unuse; - /* battery capacity */ - u16 soc; - u16 temp_soc; - u16 pre_soc; - - u16 time_interval; - u16 pre_gauge_timer; - - u8 online; - u8 status; - u8 internal_status; - u8 health; - u8 present; - - /* IRQ flag */ - u8 irq_flag; - - /* max voltage IRQ flag */ - bool max_volt_irq; - /* min voltage1 IRQ flag */ - bool min_volt1_irq; - /* min voltage2 IRQ flag */ - bool min_volt2_irq; - /* max temperature IRQ flag */ - bool max_temp_irq; - /* min temperature IRQ flag */ - bool min_temp_irq; - - bool min_volt2_alert; + /* ktime_t last_event;*/ + struct timespec last_event; + + u16 update_time; + + /* previous battery voltage */ + u16 pre_vcell; + /* previous battery current */ + s16 pre_curr; + /* battery voltage */ + u16 vcell; + /* battery current */ + s16 curr; + /* battery current offset */ + u16 curr_offset; + /* AIN voltage */ + u16 ain_volt; + /* battery internal temperature */ + s16 int_temp; + /* battery external temperature */ + s16 ext_temp; + /* charge coulomb counter */ + u32 chg_cc; + u32 chg_cc_unuse; + /* discharge coulomb counter */ + u32 dchg_cc; + u32 dchg_cc_unuse; + /* battery capacity */ + u16 soc; + u16 temp_soc; + u16 pre_soc; + + u16 time_interval; + u16 pre_gauge_timer; + + u8 online; + u8 status; + u8 internal_status; + u8 health; + u8 present; + u8 batt_present; + + /* IRQ flag */ + u8 irq_flag; + + /* max voltage IRQ flag */ + bool max_volt_irq; + /* min voltage1 IRQ flag */ + bool min_volt1_irq; + /* min voltage2 IRQ flag */ + bool min_volt2_irq; + /* max temperature IRQ flag */ + bool max_temp_irq; + /* min temperature IRQ flag */ + bool min_temp_irq; + + bool min_volt2_alert; u8 temp_high_cnt; u8 temp_low_cnt; u8 temp_recover_cnt; - + bool init_cap; bool avg_flag; - - /* remain capacity */ - u32 rm; - /* SOC permille */ - u16 permille; - /* full capccity */ - u16 fcc_aging; - u16 fcc; - u16 dc; - s16 tempcmp; - #if 0 - u32 time_to_empty; - u32 time_to_full; - #endif - - bool edv_flag; - bool edv_detection; - u8 edv_cnt; - - bool tp_flag; - u8 tp_cnt; - - u8 cycle_cnt; - u32 acc_dchg_cap; - - bool smooth_flag; - - u16 gauge_timer; - s16 curr_raw; - u32 empty_edv; - u8 edv_region; - - bool init_once; - bool device_suspend; - bool last_suspend; - bool last_tp_flag; - u32 cal_fcc; - u8 test_temp; + + /* remain capacity */ + u32 rm; + /* SOC permille */ + u16 permille; + /* full capccity */ + u16 fcc_aging; + u16 fcc; + u16 dc; + s16 tempcmp; + + bool edv_flag; + bool edv_detection; + u8 edv_cnt; + + bool tp_flag; + u8 tp_cnt; + + u8 cycle_cnt; + u32 acc_dchg_cap; + + bool smooth_flag; + + u16 gauge_timer; + s16 curr_raw; + u32 empty_edv; + u8 edv_region; + u32 soc1_lock_cnt; + u32 soc99_lock_cnt; + + bool init_once; + bool device_suspend; + bool last_suspend; + bool last_tp_flag; + bool fcc_update_flag; + u32 cal_fcc; + u8 test_temp; + u8 last_tp; + u32 cal_eoc_fcc; + u32 cal_soc_offset; }; -struct rt5025_chip { - struct i2c_client *i2c; - struct workqueue_struct *wq; - struct device *dev; - struct rt5025_power_info *power_info; - struct rt5025_swjeita_info *jeita_info; - struct rt5025_battery_info *battery_info; - int suspend; - int irq; - struct delayed_work delayed_work; - struct mutex io_lock; + +struct rt5025_charger_data { + int *temp; + u32 *temp_scalar; + int chg_volt; + int acchg_icc; + int usbtachg_icc; + int usbchg_icc; + int screenon_icc; + unsigned int ieoc:1; + unsigned int vdpm:2; + unsigned int te_en:1; + unsigned int vprec:3; + unsigned int iprec:1; + unsigned int screenon_adjust:1; }; +struct rt5025_gpio_data { + int ngpio; +}; + +struct rt5025_misc_data { + unsigned char vsyslv:3; + unsigned char shdnlpress_time:2; + unsigned char startlpress_time:2; + unsigned char vsyslv_enshdn:1; +}; + +struct rt5025_irq_data { + int irq_gpio; +}; + +struct rt5025_chip; struct rt5025_platform_data { - struct regulator_init_data* regulator[RT5025_MAX_REGULATOR]; - struct rt5025_power_data* power_data; - struct rt5025_gpio_data* gpio_data; - struct rt5025_misc_data* misc_data; - struct rt5025_irq_data* irq_data; - struct rt5025_jeita_data* jeita_data; - struct rt5025_event_callback *cb; + struct regulator_init_data *regulator[RT5025_MAX_REGULATOR]; + struct rt5025_charger_data *chg_pdata; + struct rt5025_gpio_data *gpio_pdata; + struct rt5025_misc_data *misc_pdata; + struct rt5025_irq_data *irq_pdata; int (*pre_init)(struct rt5025_chip *rt5025_chip); /** Called after subdevices are set up */ int (*post_init)(void); - int (*set_otg_enable)(int); - int intr_pin; }; -#ifdef CONFIG_MFD_RT5025_MISC -extern void rt5025_power_off(void); -extern int rt5025_cable_exist(void); -#endif /* CONFIG_MFD_RT5025_MISC */ - -#ifdef CONFIG_POWER_RT5025 -extern int rt5025_charger_reset_and_reinit(struct rt5025_power_info *); -extern int rt5025_ext_set_charging_buck(int); -extern int rt5025_set_charging_buck(struct i2c_client *, int); -extern int rt5025_set_charging_current_switch(struct i2c_client *, int); -extern void rt5025_gauge_set_status(struct rt5025_battery_info *, int); -extern void rt5025_gauge_set_online(struct rt5025_battery_info *, bool); -extern void rt5025_gauge_irq_handler(struct rt5025_battery_info *, u8); -extern int rt5025_power_charge_detect(struct rt5025_power_info *); -extern int rt5025_notify_charging_cable(struct rt5025_swjeita_info *, int); -extern int rt5025_swjeita_irq_handler(struct rt5025_swjeita_info *, unsigned char); -#endif /* CONFIG_POEWR_RT5025 */ +struct rt5025_misc_info { + struct i2c_client *i2c; + struct device *dev; +}; + +struct rt5025_chip { + struct i2c_client *i2c; + struct device *dev; + struct rt5025_charger_info *charger_info; + struct rt5025_battery_info *battery_info; + struct rt5025_misc_info *misc_info; + struct mutex io_lock; + int suspend; +}; + +#ifdef CONFIG_CHARGER_RT5025 +void rt5025_charger_irq_handler(struct rt5025_charger_info *ci, unsigned int event); +#endif /* #ifdef CONFIG_CHARGER_RT5025 */ +#ifdef CONFIG_MISC_RT5025 +void rt5025_misc_irq_handler(struct rt5025_misc_info *mi, unsigned int event); +#endif /* #ifdef CONFIG_MISC_RT5025 */ +#ifdef CONFIG_BATTERY_RT5025 +void rt5025_gauge_irq_handler(struct rt5025_battery_info *bi, unsigned int event); +#endif /* #ifdef CONFIG_BATTERY_RT5025 */ extern int rt5025_reg_block_read(struct i2c_client *, int, int, void *); extern int rt5025_reg_block_write(struct i2c_client *, int, int, void *); @@ -648,9 +478,9 @@ extern int rt5025_core_deinit(struct rt5025_chip *); #ifdef CONFIG_MFD_RT_SHOW_INFO #define RTINFO(format, args...) \ - printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEVICE_NAME,__FUNCTION__,__LINE__, ##args) + printk(KERN_INFO "%s:%s() line-%d: " format, RT5025_DEV_NAME, __FUNCTION__, __LINE__, ##args) #else -#define RTINFO(format,args...) +#define RTINFO(format, args...) #endif /* CONFIG_MFD_RT_SHOW_INFO */ #endif /* __LINUX_MFD_RT5025_H */ diff --git a/include/linux/power/rockchip-general-bat.h b/include/linux/power/rockchip-general-bat.h index 352be48c8bb6..ae5eb522627c 100755 --- a/include/linux/power/rockchip-general-bat.h +++ b/include/linux/power/rockchip-general-bat.h @@ -1,26 +1,24 @@ -battery_graph_prop rt5025_battery_param1[] = -{ +battery_graph_prop rt5025_battery_param1[] = { {4190, 1000}, - {4120, 980}, - {4037, 890}, - {3970, 800}, - {3914, 710}, - {3835, 580}, - {3796, 490}, - {3773, 400}, - {3736, 240}, - {3697, 140}, - {3665, 70}, - {3651, 50}, - {3545, 20}, - {3400, 0}, + {4153, 980}, + {4067, 890}, + {3991, 800}, + {3931, 710}, + {3845, 580}, + {3799, 490}, + {3776, 400}, + {3743, 240}, + {3695, 140}, + {3660, 70}, + {3642, 50}, + {3509, 20}, + {3300, 0}, }; -battery_graph_prop rt5025_battery_param2[] = -{ - {450,14}, +battery_graph_prop rt5025_battery_param2[] = { + {450, 30}, {250, 0}, - {50,-78}, - {50, 10}, - {3400, 3671}, + {50, -90}, + {50, 10}, + {3400, 6900}, }; diff --git a/include/linux/power/rt-power.h b/include/linux/power/rt-power.h new file mode 100755 index 000000000000..7c5b64af747c --- /dev/null +++ b/include/linux/power/rt-power.h @@ -0,0 +1,27 @@ +/* + * include/linux/power/rt5025/rt-power.h + * Include header file for Richtek RT5025 Core charger Driver + * + * Copyright (C) 2014 Richtek Technology Corp. + * cy_huang + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef __LINUX_RT_POWER_H +#define __LINUX_RT_POWER_H + +#define RT_AC_NAME "rt-ac" +#define RT_USB_NAME "rt-usb" + +struct rt_power_data { + int chg_volt; + int acchg_icc; + int usbtachg_icc; + int usbchg_icc; +}; +#endif /* #ifndef __LINUX_RT_POWER_H */ + diff --git a/include/linux/power/rt5025-battery.h b/include/linux/power/rt5025-battery.h old mode 100644 new mode 100755 index b9577459dc83..a1f1add202c2 --- a/include/linux/power/rt5025-battery.h +++ b/include/linux/power/rt5025-battery.h @@ -1,13 +1,14 @@ /* - * include/linux/power/rt5025-battery.h + * include/linux/power/rt5025/rt5025-battery.h * Include header file for Richtek RT5025 battery Driver * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2013 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #ifndef __LINUX_RT5025_BATTERY_H @@ -16,38 +17,38 @@ #undef ROCKCHIP_BATTERY_6900MAH #undef ROCKCHIP_BATTERY_4000MAH -#define RT5025_REG_IRQ_CTL 0x50 -#define RT5025_REG_IRQ_FLAG 0x51 -#define RT5025_REG_VALRT_MAXTH 0x53 -#define RT5025_REG_VALRT_MIN1TH 0x54 -#define RT5025_REG_VALRT_MIN2TH 0x55 -#define RT5025_REG_TALRT_MAXTH 0x56 -#define RT5025_REG_TALRT_MINTH 0x57 -#define RT5025_REG_VCELL_MSB 0x58 -#define RT5025_REG_VCELL_LSB 0x59 -#define RT5025_REG_INT_TEMPERATUE_MSB 0x5A -#define RT5025_REG_INT_TEMPERATUE_LSB 0x5B -#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E -#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F -#define RT5025_REG_TIMER 0x60 -#define RT5025_REG_CHANNEL_MSB 0x62 -#define RT5025_REG_CHANNEL_LSB 0x63 -#define RT5025_REG_CURRENT_MSB 0x76 -#define RT5025_REG_CURRENT_LSB 0x77 -#define RT5025_REG_QCHGH_MSB 0x78 -#define RT5025_REG_QCHGH_LSB 0x79 -#define RT5025_REG_QCHGL_MSB 0x7A -#define RT5025_REG_QCHGL_LSB 0x7B -#define RT5025_REG_QDCHGH_MSB 0x7C -#define RT5025_REG_QDCHGH_LSB 0x7D -#define RT5025_REG_QDCHGL_MSB 0x7E -#define RT5025_REG_QDCHGL_LSB 0x7F - -#define IRQ_CTL_BIT_TMX (1 << 5) -#define IRQ_CTL_BIT_TMN (1 << 4) -#define IRQ_CTL_BIT_VMX (1 << 2) -#define IRQ_CTL_BIT_VMN1 (1 << 1) -#define IRQ_CTL_BIT_VMN2 (1 << 0) +#define RT5025_REG_IRQ_CTL 0x50 +#define RT5025_REG_IRQ_FLAG 0x51 +#define RT5025_REG_VALRT_MAXTH 0x53 +#define RT5025_REG_VALRT_MIN1TH 0x54 +#define RT5025_REG_VALRT_MIN2TH 0x55 +#define RT5025_REG_TALRT_MAXTH 0x56 +#define RT5025_REG_TALRT_MINTH 0x57 +#define RT5025_REG_VCELL_MSB 0x58 +#define RT5025_REG_VCELL_LSB 0x59 +#define RT5025_REG_INT_TEMPERATUE_MSB 0x5A +#define RT5025_REG_INT_TEMPERATUE_LSB 0x5B +#define RT5025_REG_EXT_TEMPERATUE_MSB 0x5E +#define RT5025_REG_EXT_TEMPERATUE_LSB 0x5F +#define RT5025_REG_TIMER 0x60 +#define RT5025_REG_CHANNEL_MSB 0x62 +#define RT5025_REG_CHANNEL_LSB 0x63 +#define RT5025_REG_CURRENT_MSB 0x76 +#define RT5025_REG_CURRENT_LSB 0x77 +#define RT5025_REG_QCHGH_MSB 0x78 +#define RT5025_REG_QCHGH_LSB 0x79 +#define RT5025_REG_QCHGL_MSB 0x7A +#define RT5025_REG_QCHGL_LSB 0x7B +#define RT5025_REG_QDCHGH_MSB 0x7C +#define RT5025_REG_QDCHGH_LSB 0x7D +#define RT5025_REG_QDCHGL_MSB 0x7E +#define RT5025_REG_QDCHGL_LSB 0x7F + +#define IRQ_CTL_BIT_TMX (1 << 5) +#define IRQ_CTL_BIT_TMN (1 << 4) +#define IRQ_CTL_BIT_VMX (1 << 2) +#define IRQ_CTL_BIT_VMN1 (1 << 1) +#define IRQ_CTL_BIT_VMN2 (1 << 0) #define IRQ_FLG_BIT_TMX (1 << 5) #define IRQ_FLG_BIT_TMN (1 << 4) @@ -81,61 +82,25 @@ #define EDV_HYS 100 #define IRQ_THRES_UNIT 1953 -#define TALRTMAX_VALUE 0x38 //65.39'C -#define TALRTMIN_VALUE 0x9 //-18.75'C -#define TRLS_VALUE 55 //5'C ; unit:mV -#define VRLS_VALUE 100 //100mV +#define TALRTMAX_VALUE 0x38 /*65.39'C*/ +#define TALRTMIN_VALUE 0x9 /*-18.75'C*/ +#define TRLS_VALUE 55 /*5'C ; unit:mV*/ +#define VRLS_VALUE 100 /*100mV*/ #define DEADBAND 10 -//#define SLEEP_CURRENT 3 //mA - -u16 crctab16[256] = -{ - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, -}; +/*#define SLEEP_CURRENT 3 //mA*/ typedef enum{ CHG, DCHG -}operation_mode; +} operation_mode; typedef struct{ int x; int y; -}battery_graph_prop; +} battery_graph_prop; typedef enum { MAXTEMP, @@ -146,7 +111,7 @@ typedef enum { TEMP_RLS, VOLT_RLS, LAST_TYPE, -}alert_type; +} alert_type; #if defined(ROCKCHIP_BATTERY_6900MAH) #include @@ -156,6 +121,6 @@ typedef enum { #include #endif -#define VALRTMIN2_VALUE (rt5025_battery_param2[4].x * 100 / IRQ_THRES_UNIT + 1) //EDV0 voltage +#define VALRTMIN2_VALUE (rt5025_battery_param2[4].x * 100 / IRQ_THRES_UNIT + 1) /*EDV0 voltage*/ #endif /* #ifndef __LINUX_RT5025_BATTERY_H */ diff --git a/include/linux/power/rt5025-charger.h b/include/linux/power/rt5025-charger.h new file mode 100755 index 000000000000..85f83bc1df24 --- /dev/null +++ b/include/linux/power/rt5025-charger.h @@ -0,0 +1,86 @@ +/* + * include/linux/power/rt5025/rt5025-charger.h + * Include header file for Richtek RT5025 Core charger Driver + * + * Copyright (C) 2014 Richtek Technology Corp. + * cy_huang + * + * 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; either version 2 + * of the License, or (at your option) any later version. + */ + +#ifndef __LINUX_RT5025_CHARGER_H +#define __LINUX_RT5025_CHARGER_H + +enum { + CHGEVENT_TIMEOUT_CC, + CHGEVENT_TIMEOUT_PC, + CHGEVENT_CHVSREGI = 5, + CHGEVENT_CHTREGI, + CHGEVENT_CHRCHGI, + CHGEVENT_CHTERMI, + CHGEVENT_CHBATOVI, + CHGEVENT_CHGOODI_INUSB, + CHGEVENT_CHBADI_INUSB, + CHGEVENT_CHSLPI_INUSB, + CHGEVENT_CHGOODI_INAC, + CHGEVENT_CHBADI_INAC, + CHGEVENT_CHSLPI_INAC, + CHGEVENT_BATABS, + CHGEVENT_INUSB_PLUGIN = 19, + CHGEVENT_INUSBOVP, + CHGEVENT_INAC_PLUGIN = 22, + CHGEVENT_INACOVP, + /*append TALRT IRQ*/ + CHGEVENT_TALRTMIN = 28, + CHGEVENT_TALRTMAX = 29, + CHGEVENT_MAX, +}; + +enum { + RT5025_BATTEMP_COLD, + RT5025_BATTEMP_COOL, + RT5025_BATTEMP_NORMAL, + RT5025_BATTEMP_WARM, + RT5025_BATTEMP_HOT, + RT5025_BATTEMP_MAX, +}; + +enum { + RT5025_INTTEMP_NORMAL, + RT5025_INTTEMP_WARM, + RT5025_INTTEMP_HOT, + RT5025_INTTEMP_MAX, +}; + +#define RT5025_CHGIPREC_MASK 0x01 +#define RT5025_CHGIPREC_SHFT 0 +#define RT5025_CHGIEOC_MASK 0x02 +#define RT5025_CHGIEOC_SHFT 1 +#define RT5025_CHGVPREC_MASK 0x1C +#define RT5025_CHGVPREC_SHFT 2 +#define RT5025_CHGVDPM_MASK 0x30 +#define RT5025_CHGVDPM_SHFT 4 + +#define RT5025_CHGCEN_MASK 0x10 +#define RT5025_CHGAICR_MASK 0x06 +#define RT5025_CHGAICR_SHFT 1 +#define RT5025_CHGICC_MASK 0x78 +#define RT5025_CHGICC_SHFT 3 +#define RT5025_CHGCV_MASK 0xFC +#define RT5025_CHGCV_SHFT 2 +#define RT5025_CHGTEEN_MASK 0x04 +#define RT5025_BATDEN_MASK 0x40 +#define RT5025_VBUSHZ_MASK 0x01 +#define RT5025_CHGBCEN_MASK 0x02 +#define RT5025_CHRCHGI_MASK 0x80 +#define RT5025_CHTERMI_MASK 0x01 +#define RT5025_ACUSABLE_MASK 0x02 +#define RT5025_USBUSABLE_MASK 0x01 + +#define RT5025_TALRTMX_MASK 0x20 +#define RT5025_TALRTMN_MASK 0x10 + +#endif /* #ifndef __LINUX_RT5025_POWER_H */ diff --git a/include/linux/regulator/rt5025-regulator.h b/include/linux/regulator/rt5025-regulator.h old mode 100644 new mode 100755 index f9467830ef11..154b8c1da76b --- a/include/linux/regulator/rt5025-regulator.h +++ b/include/linux/regulator/rt5025-regulator.h @@ -2,88 +2,75 @@ * include/linux/regulator/rt5025-regulator.h * Include header file to Richtek RT5025 Regulator driver * - * Copyright (C) 2013 Richtek Electronics + * Copyright (C) 2013 Richtek Technology Corp. * cy_huang * * 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. + * published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. */ #ifndef __LINUX_RT5025_REGULATOR_H #define __LINUX_RT5025_REGULATOR_H -#define RT5025_REG_DCDCCTRL1 0x08 -#define RT5025_REG_DCDCCTRL2 0x09 -#define RT5025_REG_DCDCCTRL3 0x0A -#define RT5025_REG_DCDCCTRL4 0x0B -#define RT5025_REG_LDOCTRL1 0x0D -#define RT5025_REG_LDOCTRL2 0x0E -#define RT5025_REG_LDOCTRL3 0x0F -#define RT5025_REG_LDOCTRL4 0x10 -#define RT5025_REG_LDOCTRL5 0x11 -#define RT5025_REG_LDOCTRL6 0x12 -#define RT5025_REG_DCDCEN 0x17 -#define RT5025_REG_LDOEN 0x18 -#define RT5025_REG_DCDCVRC 0x0B -#define RT5025_REG_LDOVRC 0x00 +#define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTL1 +#define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTL2 +#define RT5025_DCDCVOUT3 RT5025_REG_DCDCCTL3 +#define RT5025_DCDCVOUT4 RT5025_REG_VRCCTL +#define RT5025_LDOVOUT1 RT5025_REG_LDOCTL1 +#define RT5025_LDOVOUT2 RT5025_REG_LDOCTL2 +#define RT5025_LDOVOUT3 RT5025_REG_LDOCTL3 +#define RT5025_LDOVOUT4 RT5025_REG_LDOCTL4 +#define RT5025_LDOVOUT5 RT5025_REG_LDOCTL5 +#define RT5025_LDOVOUT6 RT5025_REG_LDOCTL6 -#define RT5025_DCDCVOUT1 RT5025_REG_DCDCCTRL1 -#define RT5025_DCDCVOUT2 RT5025_REG_DCDCCTRL2 -#define RT5025_DCDCVOUT3 RT5025_REG_DCDCCTRL3 -#define RT5025_DCDCVOUT4 RT5025_REG_DCDCCTRL4 -#define RT5025_LDOVOUT1 RT5025_REG_LDOCTRL1 -#define RT5025_LDOVOUT2 RT5025_REG_LDOCTRL2 -#define RT5025_LDOVOUT3 RT5025_REG_LDOCTRL3 -#define RT5025_LDOVOUT4 RT5025_REG_LDOCTRL4 -#define RT5025_LDOVOUT5 RT5025_REG_LDOCTRL5 -#define RT5025_LDOVOUT6 RT5025_REG_LDOCTRL6 +#define RT5025_DCDCVOUT_SHIFT1 2 +#define RT5025_DCDCVOUT_SHIFT2 1 +#define RT5025_DCDCVOUT_SHIFT3 2 +#define RT5025_DCDCVOUT_SHIFT4 0 +#define RT5025_LDOVOUT_SHIFT1 0 +#define RT5025_LDOVOUT_SHIFT2 0 +#define RT5025_LDOVOUT_SHIFT3 3 +#define RT5025_LDOVOUT_SHIFT4 3 +#define RT5025_LDOVOUT_SHIFT5 3 +#define RT5025_LDOVOUT_SHIFT6 3 -#define RT5025_DCDCVOUT_SHIFT1 2 -#define RT5025_DCDCVOUT_SHIFT2 1 -#define RT5025_DCDCVOUT_SHIFT3 2 -#define RT5025_DCDCVOUT_SHIFT4 0 -#define RT5025_LDOVOUT_SHIFT1 0 -#define RT5025_LDOVOUT_SHIFT2 0 -#define RT5025_LDOVOUT_SHIFT3 3 -#define RT5025_LDOVOUT_SHIFT4 3 -#define RT5025_LDOVOUT_SHIFT5 3 -#define RT5025_LDOVOUT_SHIFT6 3 +#define RT5025_DCDCVOUT_MASK1 0xFC +#define RT5025_DCDCVOUT_MASK2 0xFE +#define RT5025_DCDCVOUT_MASK3 0xFC +#define RT5025_DCDCVOUT_MASK4 0x0F +#define RT5025_LDOVOUT_MASK1 0x7F +#define RT5025_LDOVOUT_MASK2 0x7F +#define RT5025_LDOVOUT_MASK3 0xF8 +#define RT5025_LDOVOUT_MASK4 0xF8 +#define RT5025_LDOVOUT_MASK5 0xF8 +#define RT5025_LDOVOUT_MASK6 0xF8 -#define RT5025_DCDCVOUT_MASK1 0xFC -#define RT5025_DCDCVOUT_MASK2 0xFE -#define RT5025_DCDCVOUT_MASK3 0xFC -#define RT5025_DCDCVOUT_MASK4 0x0F -#define RT5025_LDOVOUT_MASK1 0x7F -#define RT5025_LDOVOUT_MASK2 0x7F -#define RT5025_LDOVOUT_MASK3 0xF8 -#define RT5025_LDOVOUT_MASK4 0xF8 -#define RT5025_LDOVOUT_MASK5 0xF8 -#define RT5025_LDOVOUT_MASK6 0xF8 +#define RT5025_DCDCEN_MASK1 0x01 +#define RT5025_DCDCEN_MASK2 0x02 +#define RT5025_DCDCEN_MASK3 0x04 +#define RT5025_DCDCEN_MASK4 0x08 +#define RT5025_LDOEN_MASK1 0x01 +#define RT5025_LDOEN_MASK2 0x02 +#define RT5025_LDOEN_MASK3 0x04 +#define RT5025_LDOEN_MASK4 0x08 +#define RT5025_LDOEN_MASK5 0x10 +#define RT5025_LDOEN_MASK6 0x20 -#define RT5025_DCDC_OUTPUT_EN RT5025_REG_DCDCEN -#define RT5025_LDO_OUTPUT_EN RT5025_REG_LDOEN +#define RT5025_DCDCMODE_REG1 RT5025_REG_VRCCTL +#define RT5025_DCDCMODE_REG2 RT5025_REG_VRCCTL +#define RT5025_DCDCMODE_REG3 RT5025_REG_VRCCTL +#define RT5025_DCDCMODE_REG4 0 -#define RT5025_DCDCEN_MASK1 0x01 -#define RT5025_DCDCEN_MASK2 0x02 -#define RT5025_DCDCEN_MASK3 0x04 -#define RT5025_DCDCEN_MASK4 0x08 -#define RT5025_LDOEN_MASK1 0x01 -#define RT5025_LDOEN_MASK2 0x02 -#define RT5025_LDOEN_MASK3 0x04 -#define RT5025_LDOEN_MASK4 0x08 -#define RT5025_LDOEN_MASK5 0x10 -#define RT5025_LDOEN_MASK6 0x20 +#define RT5025_DCDCMODE_MASK1 0x40 +#define RT5025_DCDCMODE_MASK2 0x20 +#define RT5025_DCDCMODE_MASK3 0x10 +#define RT5025_DCDCMODE_MASK4 0x00 -#define RT5025_DCDCMODE_MASK1 0x40 -#define RT5025_DCDCMODE_MASK2 0x20 -#define RT5025_DCDCMODE_MASK3 0x10 -#define RT5025_DCDCMODE_MASK4 0x00 -#define RT5025_LDOMODE_MASK1 0x00 -#define RT5025_LDOMODE_MASK2 0x00 -#define RT5025_LDOMODE_MASK3 0x00 -#define RT5025_LDOMODE_MASK4 0x00 -#define RT5025_LDOMODE_MASK5 0x00 -#define RT5025_LDOMODE_MASK6 0x00 +#define RT5025_DCDCRAMP_MASK1 0x03 +#define RT5025_DCDCRAMP_MASK2 0x01 +#define RT5025_DCDCRAMP_MASK3 0x03 +#define RT5025_DCDCRAMP_MASK4 0x00 #endif /* __LINUX_RT5025_REGULATOR_H */ -- 2.34.1