--- /dev/null
+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";
+ };
--- /dev/null
+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";
+};
--- /dev/null
+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>;
+ };
+
--- /dev/null
+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", "";
+ };
reg = <0x1c>;
status = "okay";
};
+ rt5025: rt5025@35 {
+ compatible = "rt,rt5025";
+ reg = <0x35>;
+ status = "okay";
+ };
};
&i2c2 {
status = "okay";
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>;
--- /dev/null
+/* 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";
+ };
+};
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
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
--- /dev/null
+/*
+ * drivers/gpio/rt5025-gpio.c
+ * Driver foo Richtek RT5025 PMIC GPIO
+ *
+ * Copyright (C) 2014 Richtek Technologh Corp.
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include <linux/mfd/rt5025.h>
+#include <linux/mfd/rt5025-gpio.h>
+
+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;
+ }
+ return ret;
+}
+
+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) {
+ 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) {
+ dev_err(chip->dev, "set gpio input fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+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) {
+ 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) {
+ dev_err(chip->dev, "clr gpio direction fail\n");
+ return ret;
+ }
+
+ ret = rt5025_set_bits(gi->i2c, gpio_reg,
+ RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
+ if (ret < 0) {
+ dev_err(chip->dev, "set gpio output dir fail\n");
+ return ret;
+ }
+
+ if (value)
+ ret = rt5025_set_bits(gi->i2c, gpio_reg,
+ RT5025_GPIO_OVALUEMASK);
+ else
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg,
+ RT5025_GPIO_OVALUEMASK);
+
+ if (ret < 0) {
+ dev_err(chip->dev, "set gpio output value fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+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) {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return ret;
+ }
+
+ ret = rt5025_reg_read(gi->i2c, gpio_reg);
+ if (ret < 0) {
+ dev_err(chip->dev, "read gpio register fail\n");
+ return ret;
+ }
+
+ return (ret&RT5025_GPIO_IVALUEMASK)?1 : 0;
+}
+
+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) {
+ dev_err(chip->dev, "not a valid gpio index\n");
+ return;
+ }
+
+ if (value)
+ ret = rt5025_set_bits(gi->i2c, gpio_reg,
+ RT5025_GPIO_OVALUEMASK);
+ else
+ ret = rt5025_clr_bits(gi->i2c, gpio_reg,
+ RT5025_GPIO_OVALUEMASK);
+
+ if (ret < 0)
+ dev_err(chip->dev, "read gpio register fail\n");
+}
+
+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 = (pdev->dev.parent)->platform_data;
+ struct rt5025_gpio_info *gi;
+ bool use_dt = pdev->dev.of_node;
+ int rc = 0;
+
+ gi = devm_kzalloc(&pdev->dev, sizeof(*gi), GFP_KERNEL);
+ if (!gi)
+ return -ENOMEM;
+
+
+ gi->i2c = chip->i2c;
+ 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;
+ gi->gpio_chip.get = rt5025_gpio_get_value;
+ gi->gpio_chip.set = rt5025_gpio_set_value;
+ gi->gpio_chip.can_sleep = 0;
+
+ 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;
+
+ rc = gpiochip_add(&gi->gpio_chip);
+ if (rc)
+ goto out_dev;
+
+ platform_set_drvdata(pdev, gi);
+ dev_info(&pdev->dev, "driver successfully loaded\n");
+ return rc;
+out_dev:
+ return rc;
+}
+
+static int rt5025_gpio_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct rt5025_gpio_info *gi = platform_get_drvdata(pdev);
+
+ rc = gpiochip_remove(&gi->gpio_chip);
+ dev_info(&pdev->dev, "\n");
+ return 0;
+}
+
+static struct of_device_id rt_match_table[] = {
+ { .compatible = "rt,rt5025-gpio",},
+ {},
+};
+
+static struct platform_driver rt5025_gpio_driver = {
+ .driver = {
+ .name = RT5025_DEV_NAME "-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = rt_match_table,
+ },
+ .probe = rt5025_gpio_probe,
+ .remove = rt5025_gpio_remove,
+};
+
+static int rt5025_gpio_init(void)
+{
+ return platform_driver_register(&rt5025_gpio_driver);
+}
+fs_initcall_sync(rt5025_gpio_init);
+
+static void rt5025_gpio_exit(void)
+{
+ platform_driver_unregister(&rt5025_gpio_driver);
+}
+module_exit(rt5025_gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("GPIO driver for RT5025");
+MODULE_ALIAS("platform:" RT5025_DEV_NAME "-gpio");
+MODULE_VERSION(RT5025_DRV_VER);
+++ /dev/null
-/*
- * drivers/gpio/rt5025-gpio.c
- * Driver foo Richtek RT5025 PMIC GPIO
- *
- * Copyright (C) 2013 Richtek Electronics
- * cy_huang <cy_huang@richtek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-#include <linux/mfd/rt5025.h>
-#include <linux/mfd/rt5025-gpio.h>
-
-struct rt5025_gpio_info {
- struct i2c_client *i2c;
- unsigned gpio_base;
- unsigned irq_base;
- 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;
- }
- return ret;
-}
-
-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)
- {
- 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)
- {
- dev_err(chip->dev, "set gpio input fail\n");
- return ret;
- }
-
- return 0;
-}
-
-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)
- {
- 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)
- {
- dev_err(chip->dev, "clr gpio direction fail\n");
- return ret;
- }
-
- ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OUTPUT<<RT5025_GPIO_DIRSHIFT);
- if (ret<0)
- {
- dev_err(chip->dev, "set gpio output dir fail\n");
- return ret;
- }
-
- if (value)
- ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
- else
- ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
-
- if (ret<0)
- {
- dev_err(chip->dev, "set gpio output value fail\n");
- return ret;
- }
-
- return 0;
-}
-
-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)
- {
- dev_err(chip->dev, "not a valid gpio index\n");
- return ret;
- }
-
- ret = rt5025_reg_read(gi->i2c, gpio_reg);
- if (ret<0)
- {
- dev_err(chip->dev, "read gpio register fail\n");
- return ret;
- }
-
- return (ret&RT5025_GPIO_IVALUEMASK)?1:0;
-}
-
-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)
- {
- dev_err(chip->dev, "not a valid gpio index\n");
- return;
- }
-
- if (value)
- ret = rt5025_set_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
- else
- ret = rt5025_clr_bits(gi->i2c, gpio_reg, RT5025_GPIO_OVALUEMASK);
-
- if (ret<0)
- {
- dev_err(chip->dev, "read gpio register fail\n");
- }
-}
-
-static int __devinit 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_gpio_info *gi;
- int ret = 0;
-
- gi = kzalloc(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;
-
- gi->gpio_chip.direction_input = rt5025_gpio_direction_input;
- gi->gpio_chip.direction_output = rt5025_gpio_direction_output;
- gi->gpio_chip.get = rt5025_gpio_get_value;
- 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.label = pdev->name;
- gi->gpio_chip.dev = &pdev->dev;
- gi->gpio_chip.owner = THIS_MODULE;
-
- ret = gpiochip_add(&gi->gpio_chip);
- if (ret)
- goto out_dev;
-
- platform_set_drvdata(pdev, gi);
- return ret;
-out_dev:
- kfree(gi);
- return ret;
-}
-
-static int __devexit rt5025_gpio_remove(struct platform_device *pdev)
-{
- int ret;
- struct rt5025_gpio_info *gi = platform_get_drvdata(pdev);
-
- ret = gpiochip_remove(&gi->gpio_chip);
- kfree(gi);
-
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-static struct platform_driver rt5025_gpio_driver =
-{
- .driver = {
- .name = RT5025_DEVICE_NAME "-gpio",
- .owner = THIS_MODULE,
- },
- .probe = rt5025_gpio_probe,
- .remove = __devexit_p(rt5025_gpio_remove),
-};
-
-static int __init rt5025_gpio_init(void)
-{
- return platform_driver_register(&rt5025_gpio_driver);
-}
-subsys_initcall_sync(rt5025_gpio_init);
-
-static void __exit rt5025_gpio_exit(void)
-{
- platform_driver_unregister(&rt5025_gpio_driver);
-}
-module_exit(rt5025_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
-MODULE_DESCRIPTION("GPIO driver for RT5025");
-MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-gpio");
-MODULE_VERSION(RT5025_DRV_VER);
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
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
* drivers/mfd/rt5025-core.c
* Driver for Richtek RT5025 Core PMIC
*
- * Copyright (C) 2013 Richtek Electronics
+ * Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
-
#include <linux/mfd/rt5025.h>
#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);
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) {
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);
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);
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);
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);
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;
}
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;
* drivers/mfd/rt5025-debug.c
* Driver foo Richtek RT5025 PMIC Debug
*
- * Copyright (C) 2013 Richtek Electronics
+ * Copyright (C) 2013 Richtek Technologh Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/uaccess.h>
#include <linux/debugfs.h>
-#include <linux/string.h>
+#include <linux/uaccess.h>
#include <linux/mfd/rt5025.h>
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)
{
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];
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;
}
.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 <cy_huang@richtek.com");
MODULE_DESCRIPTION("Debug driver for RT5025");
-MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-debug");
+MODULE_ALIAS("platform:" RT5025_DEV_NAME "-debug");
MODULE_VERSION(RT5025_DRV_VER);
* I2C Driver for Richtek RT5025
* Multi function device - multi functional baseband PMIC
*
- * Copyright (C) 2013
+ * Copyright (C) 2014 Richtek Technology Corp.
* Author: CY Huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
-#include <linux/slab.h>
#include <linux/mfd/rt5025.h>
-#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;
}
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;
}
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);
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);
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;
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;
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 <cy_huang@richtek.com>");
MODULE_VERSION(RT5025_DRV_VER);
/*
* 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/init.h>
#include <linux/err.h>
-#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/wakelock.h>
-#include <linux/delay.h>
-
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
#include <linux/workqueue.h>
+#include <linux/interrupt.h>
#include <linux/mfd/rt5025.h>
#include <linux/mfd/rt5025-irq.h>
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;
}
{
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 <cy_huang@richtek.com");
MODULE_DESCRIPTION("IRQ driver for RT5025");
-MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-irq");
+MODULE_ALIAS("platform:"RT5025_DEV_NAME "-irq");
MODULE_VERSION(RT5025_DRV_VER);
* drivers/mfd/rt5025-misc.c
* Driver foo Richtek RT5025 PMIC Misc Part
*
- * Copyright (C) 2013 Richtek Electronics
+ * Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
#include <linux/mfd/rt5025.h>
#include <linux/mfd/rt5025-misc.h>
-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 <cy_huang@richtek.com");
MODULE_DESCRIPTION("Misc driver for RT5025");
-MODULE_ALIAS("platform:" RT5025_DEVICE_NAME "-misc");
+MODULE_ALIAS("platform:" RT5025_DEV_NAME "-misc");
MODULE_VERSION(RT5025_DRV_VER);
Say Y here to enable support for the power management unit
provided by the Wolfson Microelectronics WM8350 PMIC.
+config CHARGER_RT5025
+ bool "RT5025 Charger Driver"
+ depends on MFD_RT5025
+ default n
+ help
+ Enable RT5025 Charger driver.
+
+config RT_POWER
+ bool "RT5025 PMIC cable report"
+ depends on CHARGER_RT5025
+ default n
+ help
+ Enable AC/USB report.
+
+config RT_SUPPORT_ACUSB_DUALIN
+ bool "RT AC/USB Dualin Option"
+ depends on RT_POWER
+ default n
+ help
+ Say Y here to enable dualin, otherwise
+ N is just singlein.
+
+config BATTERY_RT5025
+ bool "RT5025 PMIC ADC Type gauge driver"
+ depends on MFD_RT5025
+ default n
+ help
+ Enable the RT5025 ADC Fuelgauge driver.
+
+config RT_JEITA_REMOVE
+ bool "RT Jeita function remobe"
+ depends on CHARGER_RT5025 && BATTERY_RT5025
+ default n
+ help
+ Say Y here to remove Jeita function.
+
+
config BATTERY_RICOH619
tristate "Ricoh RC5T619 PMIC battery driver"
depends on MFD_RICOH619 && I2C && GENERIC_HARDIRQS
obj-$(CONFIG_CHARGER_DISPLAY) += rk29_charger_display.o
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o
+obj-$(CONFIG_CHARGER_RT5025) += rt5025-charger.o
+obj-$(CONFIG_RT_POWER) += rt-power.o
+obj-$(CONFIG_BATTERY_RT5025) += rt5025-battery.o
--- /dev/null
+/*
+ * drivers/power/rt-power.c
+ * Driver for Richtek RT PMIC Power driver
+ *
+ * Copyright (C) 2014 Richtek Technology Corp.
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+
+#include <linux/power/rt-power.h>
+
+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 <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("RT Power driver");
+MODULE_ALIAS("platform:rt-power");
+MODULE_VERSION("1.0.0_G");
* 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 <nick_hung@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
-#include <linux/android_alarm.h>
+#include <linux/alarmtimer.h>
#include <linux/mfd/rt5025.h>
#include <linux/power/rt5025-battery.h>
+
#define VOLTAGE_ALERT 0
#define TEMPERATURE_ALERT 0
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;
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
}
{
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);
}
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__);
}
{
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)
/* 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;
}
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++;
}
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++;
}
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);
}
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;
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;
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;
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);
}
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;
//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);
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;
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 <nick_hung@richtek.com");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nick Hung <nick_hung@richtek.com>");
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);
--- /dev/null
+/*
+ * drivers/power/rt5025-charger.c
+ * Driver for Richtek RT5025 PMIC Charger driver
+ *
+ * Copyright (C) 2014 Richtek Technology Corp.
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif /* #ifdef CONFIG_HAS_EARLYSUSPEND */
+
+#include <linux/mfd/rt5025.h>
+#include <linux/power/rt5025-charger.h>
+#ifdef CONFIG_RT_POWER
+#include <linux/power/rt-power.h>
+#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<<RT5025_CHGICC_SHFT);
+
+ if (val->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<<CHGEVENT_CHSLPI_INAC);
+ else
+ final_irq_event &= ~(1<<CHGEVENT_INAC_PLUGIN);
+ }
+ /*usbin+usbout*/
+ if (final_irq_event & (1 << CHGEVENT_INUSB_PLUGIN) && \
+ final_irq_event & (1 << CHGEVENT_CHSLPI_INUSB)) {
+ if (i & RT5025_USBUSABLE_MASK)
+ final_irq_event &= ~(1 << CHGEVENT_CHSLPI_INUSB);
+ else
+ final_irq_event &= ~(1 << CHGEVENT_INUSB_PLUGIN);
+ }
+ for (i = 0; i < CHGEVENT_MAX; i++) {
+ if ((final_irq_event & (1 << i)) && rt_chgirq_handler[i])
+ rt_chgirq_handler[i](ci, i);
+ }
+}
+EXPORT_SYMBOL(rt5025_charger_irq_handler);
+
+static void rt5025_tempmon_work(struct work_struct *work)
+{
+ struct rt5025_charger_info *ci = container_of(work, \
+ struct rt5025_charger_info, tempmon_work.work);
+ #ifdef CONFIG_BATTERY_RT5025
+ struct power_supply *psy = power_supply_get_by_name(RT_BATT_NAME);
+ union power_supply_propval pval;
+ int inttemp_region;
+ #endif
+
+ RTINFO("\n");
+ #ifdef CONFIG_BATTERY_RT5025
+ if (!psy) {
+ dev_err(ci->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 <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Charger driver for RT5025");
+MODULE_ALIAS("platform:"RT5025_DEV_NAME "-charger");
+MODULE_VERSION(RT5025_DRV_VER);
#include <linux/mfd/rt5025.h>
#include <linux/power/rt5025-swjeita.h>
-#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);
if (cur_value < 500)
data = 0;
else if (cur_value > 2000)
- data = 0xf<<RT5025_CHGICC_SHIFT;
+ data = 0xf << RT5025_CHGICC_SHIFT;
else
- data = ((cur_value-500)/100)<<RT5025_CHGICC_SHIFT;
+ data = ((cur_value - 500) / 100) << RT5025_CHGICC_SHIFT;
ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL4, RT5025_CHGICC_MASK, data);
if (voltage < 3500)
data = 0;
else if (voltage > 4440)
- data = 0x2f<<RT5025_CHGCV_SHIFT;
+ data = 0x2f << RT5025_CHGCV_SHIFT;
else
- data = ((voltage-3500)/20)<<RT5025_CHGCV_SHIFT;
+ data = ((voltage - 3500) / 20) << RT5025_CHGCV_SHIFT;
ret = rt5025_assign_bits(i2c, RT5025_REG_CHGCTL3, RT5025_CHGCV_MASK, data);
return ret;
u8 data[2];
long int temp;
int sect_index;
-
+
RTINFO("\n");
if (rt5025_reg_block_read(swji->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;
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)
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;
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;
{
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;
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);
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;
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;
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;
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);
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;
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,
.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);
}
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
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
* drivers/regulator/rt5025-regulator.c
* Driver foo Richtek RT5025 PMIC Regulator
*
- * Copyright (C) 2013 Richtek Electronics
+ * Copyright (C) 2014 Richtek Technology Corp.
* cy_huang <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/driver.h>
#include <linux/version.h>
+#ifdef CONFIG_OF
+#include <linux/regulator/of_regulator.h>
+#endif /* #ifdef CONFIG_OF */
+
#include <linux/mfd/rt5025.h>
#include <linux/regulator/rt5025-regulator.h>
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;
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,
};
#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,
};
#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,
};
#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,
{
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;
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;i<count;i++)
- {
- if ((info->vol_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;
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);
}
{
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;
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;
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
#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) \
.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;
}
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);
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 <cy_huang@richtek.com");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
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);
/*
- * 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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
/*
- * 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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 */
/*
- * 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.
#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 */
/*
- * 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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 <linux/power_supply.h>
-#include <linux/android_alarm.h>
+#include <linux/alarmtimer.h>
+#include <linux/wakelock.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#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 {
RT5025_VOFF_3P3V,
RT5025_VOFF_3P4V,
RT5025_VOFF_3P5V,
+ RT5025_VOFF_MAX = RT5025_VOFF_3P5V,
};
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 {
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 {
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 {
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;
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;
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 *);
#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 */
-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},
};
--- /dev/null
+/*
+ * include/linux/power/rt5025/rt-power.h
+ * Include header file for Richtek RT5025 Core charger Driver
+ *
+ * Copyright (C) 2014 Richtek Technology Corp.
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation; 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 */
+
/*
- * 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
*/
#ifndef __LINUX_RT5025_BATTERY_H
#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)
#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,
TEMP_RLS,
VOLT_RLS,
LAST_TYPE,
-}alert_type;
+} alert_type;
#if defined(ROCKCHIP_BATTERY_6900MAH)
#include <linux/power/rockchip-6900ma-bat.h>
#include <linux/power/rockchip-general-bat.h>
#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 */
--- /dev/null
+/*
+ * include/linux/power/rt5025/rt5025-charger.h
+ * Include header file for Richtek RT5025 Core charger Driver
+ *
+ * Copyright (C) 2014 Richtek Technology Corp.
+ * cy_huang <cy_huang@richtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation; 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 */
* 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 <cy_huang@richtek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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 */