rk312x:pmic:rt5036:support pmic rt5036 drivers
author张晴 <zhangqing@rock-chips.com>
Thu, 11 Sep 2014 06:28:23 +0000 (14:28 +0800)
committer张晴 <zhangqing@rock-chips.com>
Thu, 11 Sep 2014 06:28:23 +0000 (14:28 +0800)
30 files changed:
arch/arm/boot/dts/rk312x-sdk.dtsi
arch/arm/boot/dts/rt5036.dtsi [new file with mode: 0755]
arch/arm/configs/rockchip_defconfig [changed mode: 0644->0755]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/rt5025-i2c.c
drivers/mfd/rt5036-core.c [new file with mode: 0755]
drivers/mfd/rt5036-debug.c [new file with mode: 0755]
drivers/mfd/rt5036-i2c.c [new file with mode: 0755]
drivers/mfd/rt5036-irq.c [new file with mode: 0755]
drivers/mfd/rt5036-misc.c [new file with mode: 0755]
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/rt-battery.c [new file with mode: 0755]
drivers/power/rt-power.c [changed mode: 0755->0644]
drivers/power/rt5036-charger.c [new file with mode: 0755]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/rt5036-regulator.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-rt5036.c [new file with mode: 0755]
include/linux/mfd/rt5036/rt5036-irq.h [new file with mode: 0755]
include/linux/mfd/rt5036/rt5036-misc.h [new file with mode: 0755]
include/linux/mfd/rt5036/rt5036.h [new file with mode: 0644]
include/linux/power/rt-battery.h [new file with mode: 0755]
include/linux/power/rt-power.h [changed mode: 0755->0644]
include/linux/power/rt5036-charger.h [new file with mode: 0755]
include/linux/regulator/rt5036-regulator.h [new file with mode: 0755]
include/linux/rtc/rtc-rt5036.h [new file with mode: 0755]

index 7d364c78fda8ef459628675db70473792ef46519..78318f99edf65e1431e642c4ab0e0194d28a8640 100755 (executable)
        rt5025: rt5025@35 {
                        compatible = "rt,rt5025";
                        reg = <0x35>;
-                       status = "okay";
+                       status = "disabled";
+       };
+       rt5036: rt5036@38 {
+                       compatible = "rt,rt5036";
+                       reg = <0x38>;
+                       status = "disabled";
        };
 };
 
        };
 };
 
+/include/ "rt5036.dtsi"
+&rt5036 {
+
+                       rt5036_dcdc1: regulator_0 {
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = < 800000>;
+                               regulator-max-microvolt = <3300000>;
+                               qcom,comsumer-supplies = "vdd_arm", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <950000>; 
+                       };
+
+                       rt5036_dcdc2: regulator_1 {
+                               regulator-name = "vdd_logic";
+                               regulator-min-microvolt = < 800000>;
+                               regulator-max-microvolt = <3300000>;
+                               qcom,comsumer-supplies = "vdd_logic", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <950000>; 
+                       };
+
+                       rt5036_dcdc3: regulator_2 {
+                               regulator-name = "rt5036-dcdc3";
+                               regulator-min-microvolt = < 800000>;
+                               regulator-max-microvolt = <3300000>;
+                               qcom,comsumer-supplies = "rt5036-dcdc3", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <2800000>; 
+                       };
+
+                       rt5036_dcdc4: regulator_3 {
+                               regulator-name = "rt5036-dcdc4";
+                               regulator-min-microvolt = < 800000>;
+                               regulator-max-microvolt = <3300000>;
+                               qcom,comsumer-supplies = "rt5036-dcdc4", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <1200000>; 
+                       };
+
+                       rt5036_ldo1: regulator_4 {
+                               regulator-name = "rt5036-ldo1";
+                               regulator-min-microvolt = < 3000000>;
+                               regulator-max-microvolt = <3000000>;
+                               qcom,comsumer-supplies = "rt5036-ldo1", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <3000000>; 
+                       };
+
+                       rt5036_ldo2: regulator_5 {
+                               regulator-name = "rt5036-ldo2";
+                               regulator-min-microvolt = < 1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               qcom,comsumer-supplies = "rt5036-ldo2", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <1100000>; 
+                       };
+
+                       rt5036_ldo3: regulator_6 {
+                               regulator-name = "rt5036-ldo3";
+                               regulator-min-microvolt = < 1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               qcom,comsumer-supplies = "rt5036-ldo3", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <1800000>; 
+                       };
+
+                       rt5036_ldo4: regulator_7 {
+                               regulator-name = "rt5036-ldo4";
+                               regulator-min-microvolt = < 1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               qcom,comsumer-supplies = "rt5036-ldo4", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                               rt,standby_vol = <1800000>; 
+                       };
+
+                       rt5036_ldo5: regulator_8 {
+                               regulator-name = "rt5036-ldo5";
+                               qcom,comsumer-supplies = "rt5036-ldo5", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                       };
+
+                       rt5036_ldo6: regulator_9 {
+                               regulator-name = "rt5036-ldo6";
+                               qcom,comsumer-supplies = "rt5036-ldo6", "";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               rt,standby_enabled;
+                       };
+
+                       rt5036-irq {
+                               compatible = "rt,rt5036-irq";
+                               rt,irq-gpio = <&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>;
+                       };
+
+                       rt5036-charger {
+                               compatible = "rt,rt5036-charger";
+                               rt,te_en;
+                               rt,iprec = <0x2>;
+                               rt,ieoc = <0x3>;
+                               rt,vprec = <0xA>;
+                               rt,batlv = <0x4>;
+                               rt,vrechg = <1>;
+                               rt,chg_volt = <4200>;
+                               rt,otg_volt = <5025>;
+                               rt,acchg_icc = <2000>;
+                               rt,usbtachg_icc = <2000>;
+                               rt,usbchg_icc = <900>;
+                               /*rt,acdet_gpio = <&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>;*/
+                               /*rt,usbdet_gpio = <&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>;*/
+                       };
+};
+
 /include/ "rk818.dtsi"
 &rk818 {
        gpios =<&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>,<&gpio1 GPIO_A1 GPIO_ACTIVE_LOW>;
 &clk_core_dvfs_table {
        operating-points = <
                /* KHz    uV */
-               408000 1250000
-               600000 1250000
-               696000 1250000
-               816000 1250000
-               1008000 1250000
+               408000 1300000
+               600000 1300000
+               696000 1300000
+               816000 1300000
+               1008000 1300000
                >;
        status="okay";
 };
diff --git a/arch/arm/boot/dts/rt5036.dtsi b/arch/arm/boot/dts/rt5036.dtsi
new file mode 100755 (executable)
index 0000000..fd59ded
--- /dev/null
@@ -0,0 +1,108 @@
+/* Copyright (c) 2014, 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.
+ */
+
+&rt5036 {
+       compatible = "rt,rt5036";
+
+                       rt5036_dcdc1: regulator_0 {
+                               compatible = "rt,rt5036-dcdc1";
+                               cell-index = <0>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_dcdc2: regulator_1 {
+                               compatible = "rt,rt5036-dcdc2";
+                               cell-index = <1>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_dcdc3: regulator_2 {
+                               compatible = "rt,rt5036-dcdc3";
+                               cell-index = <2>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_dcdc4: regulator_3 {
+                               compatible = "rt,rt5036-dcdc4";
+                               cell-index = <3>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_ldo1: regulator_4 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-ldo1";
+                               cell-index = <4>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_ldo2: regulator_5 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-ldo2";
+                               cell-index = <5>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_ldo3: regulator_6 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-ldo3";
+                               cell-index = <6>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_ldo4: regulator_7 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-ldo4";
+                               cell-index = <7>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_lsw1: regulator_8 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-lsw1";
+                               cell-index = <8>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036_lsw2: regulator_9 {
+                               supply-regulator = "rt5036-dcdc3";
+                               compatible = "rt,rt5036-lsw2";
+                               cell-index = <9>;
+                               rt,nramp_sel = <0x00>;
+                               rt,sramp_sel = <0x00>;
+                               rt,allow_mode_mask;
+                       };
+                       rt5036-rtc {
+                               compatible = "rt,rt5036-rtc";
+                       };
+                       rt5036-misc {
+                               compatible = "rt,rt5036-misc";
+                               rt,shdn_press = <0x1>;
+                               rt,stb_en = <1>;
+                               rt,lp_enshdn;
+                               rt,vsysuvlo = <0x2>;
+                               rt,syslv_enshdn;
+                               rt,system-power-controller;
+                       };
+                       rt5036-debug {
+                               compatible = "rt,rt5036-debug";
+                       };
+       };
+
old mode 100644 (file)
new mode 100755 (executable)
index bd288d7..929d664
@@ -329,12 +329,23 @@ CONFIG_SPI_ROCKCHIP_DMA=y
 CONFIG_SPI_ROCKCHIP_TEST=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_CHARGER_RT5025=y
+CONFIG_BATTERY_RT5025=y
+CONFIG_CHARGER_RT5036=y
+CONFIG_RT_POWER=y
 CONFIG_BATTERY_RICOH619=y
 CONFIG_BATTERY_BQ24296=y
 CONFIG_BATTERY_BQ27320=y
 CONFIG_CW2015_BATTERY=y
 CONFIG_SENSORS_ROCKCHIP_TSADC=y
 CONFIG_THERMAL=y
+CONFIG_MFD_RT5025=y
+CONFIG_MISC_RT5025=y
+CONFIG_IRQ_RT5025=y
+CONFIG_DEBUG_RT5025=y
+CONFIG_MFD_RT5036=y
+CONFIG_MISC_RT5036=y
+CONFIG_IRQ_RT5036=y
 CONFIG_MFD_RK808=y
 CONFIG_MFD_RK818=y
 CONFIG_MFD_RICOH619=y
@@ -342,6 +353,8 @@ CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_REGULATOR_ACT8846=y
 CONFIG_ACT8846_SUPPORT_RESET=y
+CONFIG_REGULATOR_RT5025=y
+CONFIG_REGULATOR_RT5036=y
 CONFIG_ROCKCHIP_PWM_REGULATOR=y
 CONFIG_REGULATOR_SYR82X=y
 CONFIG_REGULATOR_RICOH619=y
@@ -509,6 +522,7 @@ CONFIG_SWITCH=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HYM8563=y
 CONFIG_RK808_RTC=y
+CONFIG_RTC_RT5036=y
 CONFIG_RTC_DRV_RC5T619=y
 CONFIG_STAGING=y
 CONFIG_ZSMALLOC=y
index 9fda3302945728e5bcecdf8b65eaa00972881e12..e2422f44a4c1ffa3e69dd1c2619d143c3b459b48 100755 (executable)
@@ -205,6 +205,49 @@ config MFD_RT_SHOW_INFO
        help
          Enable the RT5025 PMIC debug log.
 
+config MFD_RT5036
+       bool "Richtek RT5036 PMIC support"
+       select MFD_CORE
+       default n
+       help
+         Enable the RT5036 MFD driver.
+
+config MFD_RT5036_DBGINFO
+       bool "Richtek RT5036 debug message enable."
+       depends on MFD_RT5036
+       default n
+       help
+         Enable the RT5036 debug log.
+
+config MISC_RT5036
+       bool "Richtek RT5036 MISC option driver support"
+       depends on MFD_RT5036
+       default n
+       help
+         Enable the RT5036 Misc option driver support.
+
+config MISC_RT5036_PWRKEY
+       bool "Richtek RT5036 Power key report in Misc module"
+       depends on MISC_RT5036
+       default n
+       help
+         Enable the RT5036 Power Key report in Misc module.
+
+config IRQ_RT5036
+       bool "Richtek RT5036 irq option driver support"
+       depends on MFD_RT5036
+       default n
+       help
+         Enable the Rt5036 IRQ option driver support.
+
+config DEBUG_RT5036
+       bool "Richtek RT5036 PMIC DEBUGFS Support"
+       depends on DEBUG_FS && MFD_RT5036
+       default n
+       help
+         Enable the RT5036 debugfs node that support
+         read/write registers.
+
 config HTC_EGPIO
        bool "HTC EGPIO support"
        depends on GENERIC_HARDIRQS && GPIOLIB && ARM
index 1a69560d8dcbc53377191a265bff1d0db866d307..ff346f12f533e36a05a34a74f91b632c48125eb8 100755 (executable)
@@ -60,6 +60,11 @@ obj-$(CONFIG_MISC_RT5025)    += rt5025-misc.o
 obj-$(CONFIG_IRQ_RT5025)       += rt5025-irq.o
 obj-$(CONFIG_DEBUG_RT5025)     += rt5025-debug.o
 
+obj-$(CONFIG_MFD_RT5036)       += rt5036-i2c.o rt5036-core.o
+obj-$(CONFIG_MISC_RT5036)      += rt5036-misc.o
+obj-$(CONFIG_IRQ_RT5036)       += rt5036-irq.o
+obj-$(CONFIG_DEBUG_RT5036)     += rt5036-debug.o
+
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
index 5690e050403ebac71fb4e78d2655b5a0e0f0c7dd..18ec6e5c4e2410b74ba7867ae334434791a29d5a 100755 (executable)
@@ -205,24 +205,31 @@ static int rt5025_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
-static int rt5025_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int rt5025_i2c_suspend(struct device *dev)
 {
-       struct rt5025_chip *chip = i2c_get_clientdata(client);
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct rt5025_chip *chip = i2c_get_clientdata(i2c);
 
-       chip->suspend = 1;
        RTINFO("\n");
+       chip->suspend = 1;
        return 0;
 }
 
-static int rt5025_i2c_resume(struct i2c_client *client)
+static int rt5025_i2c_resume(struct device *dev)
 {
-       struct rt5025_chip *chip = i2c_get_clientdata(client);
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct rt5025_chip *chip = i2c_get_clientdata(i2c);
 
-       chip->suspend = 0;
        RTINFO("\n");
+       chip->suspend = 0;
        return 0;
 }
 
+static const struct dev_pm_ops rt5025_pm_ops = {
+       .suspend = rt5025_i2c_suspend,
+       .resume =  rt5025_i2c_resume,
+};
+
 static const struct i2c_device_id rt5025_id_table[] = {
        { RT5025_DEV_NAME, 0 },
        { },
@@ -238,12 +245,11 @@ static struct i2c_driver rt5025_i2c_driver = {
        .driver = {
                .name   = RT5025_DEV_NAME,
                .owner  = THIS_MODULE,
+                .pm = &rt5025_pm_ops,
                .of_match_table = rt_match_table,
        },
        .probe          = rt5025_i2c_probe,
        .remove         = rt5025_i2c_remove,
-       .suspend        = rt5025_i2c_suspend,
-       .resume         = rt5025_i2c_resume,
        .id_table       = rt5025_id_table,
 };
 
diff --git a/drivers/mfd/rt5036-core.c b/drivers/mfd/rt5036-core.c
new file mode 100755 (executable)
index 0000000..2560be6
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ *  drivers/mfd/rt5036-core.c
+ *  Driver for Richtek RT5036 Core PMIC
+ *
+ *  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/version.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/rt5036/rt5036.h>
+
+#ifdef CONFIG_REGULATOR_RT5036
+#ifdef CONFIG_OF
+#define RT5036_BUCKVR_DEVS(_id, _idx)                          \
+{                                                              \
+       .name           = RT5036_DEV_NAME "-regulator",         \
+       .num_resources  = 0,                                    \
+       .of_compatible  = "rt," RT5036_DEV_NAME "-dcdc" #_idx, \
+       .id             = RT5036_ID_##_id,                      \
+}
+
+#define RT5036_LDOVR_DEVS(_id, _idx)                           \
+{                                                              \
+       .name           = RT5036_DEV_NAME "-regulator",         \
+       .num_resources  = 0,                                    \
+       .of_compatible  = "rt," RT5036_DEV_NAME "-ldo" #_idx,   \
+       .id             = RT5036_ID_##_id,                      \
+}
+
+#define RT5036_LSWVR_DEVS(_id, _idx)                           \
+{                                                              \
+       .name = RT5036_DEV_NAME "-regulator",                   \
+       .num_resources = 0,                                     \
+       .of_compatible  = "rt," RT5036_DEV_NAME "-lsw" #_idx,   \
+       .id             = RT5036_ID_##_id,                      \
+}
+#else
+#define RT5036_BUCKVR_DEVS(_id, _idx)                          \
+{                                                              \
+       .name           = RT5036_DEV_NAME "-regulator",         \
+       .num_resources  = 0,                                    \
+       .id             = RT5036_ID_##_id,                      \
+}
+
+#define RT5036_LDOVR_DEVS(_id, _idx)                           \
+{                                                              \
+       .name           = RT5036_DEV_NAME "-regulator",         \
+       .num_resources  = 0,                                    \
+       .id             = RT5036_ID_##_id,                      \
+}
+
+#define RT5036_LSWVR_DEVS(_id, _idx)                           \
+{                                                              \
+       .name = RT5036_DEV_NAME "-regulator",                   \
+       .num_resources = 0,                                     \
+       .id             = RT5036_ID_##_id,                      \
+}
+#endif /* #ifdef CONFIG_OF */
+
+static struct mfd_cell regulator_devs[] = {
+       RT5036_BUCKVR_DEVS(DCDC1, 1),
+       RT5036_BUCKVR_DEVS(DCDC2, 2),
+       RT5036_BUCKVR_DEVS(DCDC3, 3),
+       RT5036_BUCKVR_DEVS(DCDC4, 4),
+       RT5036_LDOVR_DEVS(LDO1, 1),
+       RT5036_LDOVR_DEVS(LDO2, 2),
+       RT5036_LDOVR_DEVS(LDO3, 3),
+       RT5036_LDOVR_DEVS(LDO4, 4),
+       RT5036_LSWVR_DEVS(LSW1, 1),
+       RT5036_LSWVR_DEVS(LSW2, 2),
+};
+#endif /* CONFIG_REGULATOR_RT5036 */
+
+#ifdef CONFIG_CHARGER_RT5036
+static struct mfd_cell chg_devs[] = {
+       {
+        .name = RT5036_DEV_NAME "-charger",
+        .id = -1,
+        .num_resources = 0,
+#ifdef CONFIG_OF
+        .of_compatible = "rt," RT5036_DEV_NAME "-charger",
+#endif /*#ifdef CONFIG_OF */
+        },
+};
+#endif /* CONFIG_CHARGER_RT5036 */
+
+#ifdef CONFIG_RTC_RT5036
+static struct mfd_cell rtc_devs[] = {
+       {
+        .name = RT5036_DEV_NAME "-rtc",
+        .id = -1,
+        .num_resources = 0,
+#ifdef CONFIG_OF
+        .of_compatible = "rt," RT5036_DEV_NAME "-rtc",
+#endif /*#ifdef CONFIG_OF */
+        },
+};
+#endif /* CONFIG_RTC_RT5036 */
+
+#ifdef CONFIG_MISC_RT5036
+static struct mfd_cell misc_devs[] = {
+       {
+        .name = RT5036_DEV_NAME "-misc",
+        .id = -1,
+        .num_resources = 0,
+#ifdef CONFIG_OF
+        .of_compatible = "rt," RT5036_DEV_NAME "-misc",
+#endif /*#ifdef CONFIG_OF */
+        },
+};
+#endif /* CONFIG_MISC_RT5036 */
+
+#ifdef CONFIG_IRQ_RT5036
+static struct mfd_cell irq_devs[] = {
+       {
+        .name = RT5036_DEV_NAME "-irq",
+        .id = -1,
+        .num_resources = 0,
+#ifdef CONFIG_OF
+        .of_compatible = "rt," RT5036_DEV_NAME "-irq",
+#endif /*#ifdef CONFIG_OF */
+        },
+};
+#endif /* CONFIG_IRQ_RT5036 */
+
+#ifdef CONFIG_DEBUG_RT5036
+static struct mfd_cell debug_devs[] = {
+       {
+        .name = RT5036_DEV_NAME "-debug",
+        .id = -1,
+        .num_resources = 0,
+#ifdef CONFIG_OF
+        .of_compatible = "rt," RT5036_DEV_NAME "-debug",
+#endif /*#ifdef CONFIG_OF */
+        },
+};
+#endif /* CONFIG_DEBUG_RT5036 */
+
+int rt5036_core_init(struct device *dev,
+                              struct rt5036_platform_data *pdata)
+{
+       int ret = 0;
+
+       RTINFO("Start to initialize all device\n");
+#ifdef CONFIG_REGULATOR_RT5036
+       if (dev->of_node || (pdata && pdata->regulator[0])) {
+               RTINFO("mfd add regulators dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+               ret = mfd_add_devices(dev, 0, &regulator_devs[0],
+                                     ARRAY_SIZE(regulator_devs),
+                                     NULL, 0, NULL);
+#else
+               ret = mfd_add_devices(dev, 0, &regulator_devs[0],
+                                     ARRAY_SIZE(regulator_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(dev, "Failed to add regulator subdev\n");
+                       goto out_dev;
+               }
+       }
+#endif /* CONFIG_REGULATOR_RT5036 */
+
+#ifdef CONFIG_CHARGER_RT5036
+       if (dev->of_node || (pdata && pdata->chg_pdata)) {
+               RTINFO("mfd add charger dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+               ret = mfd_add_devices(dev, 0, &chg_devs[0],
+                                     ARRAY_SIZE(chg_devs), NULL, 0, NULL);
+#else
+               ret = mfd_add_devices(dev, 0, &chg_devs[0],
+                                     ARRAY_SIZE(chg_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(dev, "Failed to add charger subdev\n");
+                       goto out_dev;
+               }
+       }
+#endif /* CONFIG_CHARGER_RT5036 */
+
+#ifdef CONFIG_RTC_RT5036
+       if (dev->of_node || pdata) {
+               RTINFO("mfd add rtc dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+               ret = mfd_add_devices(dev, 0, &rtc_devs[0],
+                                     ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
+#else
+               ret = mfd_add_devices(dev, 0, &rtc_devs[0],
+                                     ARRAY_SIZE(rtc_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(dev, "Failed to add rtc subdev\n");
+                       goto out_dev;
+               }
+       }
+#endif /* CONFIG_RTC_RT5036 */
+
+#ifdef CONFIG_MISC_RT5036
+       if (dev->of_node || (pdata && pdata->misc_pdata)) {
+               RTINFO("mfd add misc dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+               ret = mfd_add_devices(dev, 0, &misc_devs[0],
+                                     ARRAY_SIZE(misc_devs), NULL, 0, NULL);
+#else
+               ret = mfd_add_devices(dev, 0, &misc_devs[0],
+                                     ARRAY_SIZE(misc_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(dev, "Failed to add misc subdev\n");
+                       goto out_dev;
+               }
+       }
+#endif /* CONFIG_MISC_RT5036 */
+
+#ifdef CONFIG_IRQ_RT5036
+       if (dev->of_node || (pdata && pdata->irq_pdata)) {
+               RTINFO("mfd add irq dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+               ret = mfd_add_devices(dev, 0, &irq_devs[0],
+                                     ARRAY_SIZE(irq_devs), NULL, 0, NULL);
+#else
+               ret = mfd_add_devices(dev, 0, &irq_devs[0],
+                                     ARRAY_SIZE(irq_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+               if (ret < 0) {
+                       dev_err(dev, "Failed to add irq subdev\n");
+                       goto out_dev;
+               }
+       }
+#endif /* CONFIG_IRQ_RT5036 */
+
+#ifdef CONFIG_DEBUG_RT5036
+       RTINFO("mfd add debug dev\n");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+       ret = mfd_add_devices(dev, 0, &debug_devs[0],
+                             ARRAY_SIZE(debug_devs), NULL, 0, NULL);
+#else
+       ret = mfd_add_devices(dev, 0, &debug_devs[0],
+                             ARRAY_SIZE(debug_devs), NULL, 0);
+#endif /* LINUX_VERSION_CODE>=KERNL_VERSION(3,6,0) */
+       if (ret < 0) {
+               dev_err(dev, "Failed to add debug subdev\n");
+               goto out_dev;
+       }
+#endif /* CONFIG_DEBUG_RT5036 */
+
+       RTINFO("Initialize all device successfully\n");
+       return ret;
+out_dev:
+       mfd_remove_devices(dev);
+       return ret;
+}
+EXPORT_SYMBOL(rt5036_core_init);
+
+int rt5036_core_deinit(struct device *dev)
+{
+       mfd_remove_devices(dev);
+       return 0;
+}
+EXPORT_SYMBOL(rt5036_core_deinit);
diff --git a/drivers/mfd/rt5036-debug.c b/drivers/mfd/rt5036-debug.c
new file mode 100755 (executable)
index 0000000..6f81c29
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *  drivers/mfd/rt5036-debug.c
+ *  Driver for Richtek RT5036 PMIC debug
+ *
+ *  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/err.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <linux/mfd/rt5036/rt5036.h>
+
+struct rt5036_debug_info {
+       struct i2c_client *i2c;
+       unsigned char reg_addr;
+       unsigned char reg_data;
+};
+
+struct rt_debug_st {
+       void *info;
+       int id;
+};
+
+enum {
+       RT5036_DBG_REG,
+       RT5036_DBG_DATA,
+       RT5036_DBG_REGS,
+       RT5036_DBG_MAX
+};
+
+static struct dentry *debugfs_rt_dent;
+static struct dentry *debugfs_file[RT5036_DBG_MAX];
+static struct rt_debug_st rtdbg_data[RT5036_DBG_MAX];
+
+static int reg_debug_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static int get_parameters(char *buf, long int *param1, int num_of_par)
+{
+       char *token;
+       int base, cnt;
+
+       token = strsep(&buf, " ");
+
+       for (cnt = 0; cnt < num_of_par; cnt++) {
+               if (token != NULL) {
+                       if ((token[1] == 'x') || (token[1] == 'X'))
+                               base = 16;
+                       else
+                               base = 10;
+
+                       if (kstrtoul(token, base, &param1[cnt]) != 0)
+                               return -EINVAL;
+
+                       token = strsep(&buf, " ");
+               } else {
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static ssize_t reg_debug_read(struct file *filp, char __user *ubuf,
+                             size_t count, loff_t *ppos)
+{
+       struct rt_debug_st *st = filp->private_data;
+       struct rt5036_debug_info *di = st->info;
+       char lbuf[1000];
+       int i = 0, j = 0;
+
+       lbuf[0] = '\0';
+       switch (st->id) {
+       case RT5036_DBG_REG:
+               snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_addr);
+               break;
+       case RT5036_DBG_DATA:
+               di->reg_data =
+                   (unsigned char)rt5036_reg_read(di->i2c, di->reg_addr);
+               snprintf(lbuf, sizeof(lbuf), "0x%x\n", di->reg_data);
+               break;
+       case RT5036_DBG_REGS:
+               for (i = RT5036_REG_RANGE1START; i <= RT5036_REG_RANGE1END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               for (i = RT5036_REG_RANGE2START; i <= RT5036_REG_RANGE2END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               for (i = RT5036_REG_RANGE3START; i <= RT5036_REG_RANGE3END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               for (i = RT5036_REG_RANGE4START; i <= RT5036_REG_RANGE4END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               for (i = RT5036_REG_RANGE5START; i <= RT5036_REG_RANGE5END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               for (i = RT5036_REG_RANGE6START; i <= RT5036_REG_RANGE6END; i++)
+                       j += sprintf(lbuf + j, "reg_%02x:%02x\n", i,
+                                    rt5036_reg_read(di->i2c, i));
+               break;
+       default:
+               return -EINVAL;
+       }
+       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)
+{
+       struct rt_debug_st *st = filp->private_data;
+       struct rt5036_debug_info *di = st->info;
+       char lbuf[32];
+       int rc;
+       long int param[5];
+
+       if (cnt > sizeof(lbuf) - 1)
+               return -EINVAL;
+
+       rc = copy_from_user(lbuf, ubuf, cnt);
+       if (rc)
+               return -EFAULT;
+
+       lbuf[cnt] = '\0';
+
+       switch (st->id) {
+       case RT5036_DBG_REG:
+               rc = get_parameters(lbuf, param, 1);
+               if ((param[0] < RT5036_REG_MAX) && (rc == 0)) {
+                       if ((param[0] >= RT5036_REG_RANGE1START
+                            && param[0] <= RT5036_REG_RANGE1END)
+                           || (param[0] >= RT5036_REG_RANGE2START
+                               && param[0] <= RT5036_REG_RANGE2END)
+                           || (param[0] >= RT5036_REG_RANGE3START
+                               && param[0] <= RT5036_REG_RANGE3END)
+                           || (param[0] >= RT5036_REG_RANGE4START
+                               && param[0] <= RT5036_REG_RANGE4END)
+                           || (param[0] >= RT5036_REG_RANGE5START
+                               && param[0] <= RT5036_REG_RANGE5END))
+                               di->reg_addr = (unsigned char)param[0];
+                       else
+                               rc = -EINVAL;
+               } else
+                       rc = -EINVAL;
+               break;
+       case RT5036_DBG_DATA:
+               rc = get_parameters(lbuf, param, 1);
+               if ((param[0] <= 0xff) && (rc == 0))
+                       rt5036_reg_write(di->i2c, di->reg_addr, param[0]);
+               else
+                       rc = -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (rc == 0)
+               rc = cnt;
+       return rc;
+}
+
+static const struct file_operations reg_debug_ops = {
+       .open = reg_debug_open,
+       .write = reg_debug_write,
+       .read = reg_debug_read
+};
+
+static int rt5036_debug_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_debug_info *di;
+
+       di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->i2c = chip->i2c;
+
+       RTINFO("add debugfs for RT5036");
+       debugfs_rt_dent = debugfs_create_dir("rt5036_dbg", 0);
+       if (!IS_ERR(debugfs_rt_dent)) {
+               rtdbg_data[0].info = di;
+               rtdbg_data[0].id = RT5036_DBG_REG;
+               debugfs_file[0] = debugfs_create_file("reg",
+                                                     S_IFREG | S_IRUGO,
+                                                     debugfs_rt_dent,
+                                                     (void *)&rtdbg_data[0],
+                                                     &reg_debug_ops);
+
+               rtdbg_data[1].info = di;
+               rtdbg_data[1].id = RT5036_DBG_DATA;
+               debugfs_file[1] = debugfs_create_file("data",
+                                                     S_IFREG | S_IRUGO,
+                                                     debugfs_rt_dent,
+                                                     (void *)&rtdbg_data[1],
+                                                     &reg_debug_ops);
+
+               rtdbg_data[2].info = di;
+               rtdbg_data[2].id = RT5036_DBG_REGS;
+               debugfs_file[2] = debugfs_create_file("regs",
+                                                     S_IFREG | S_IRUGO,
+                                                     debugfs_rt_dent,
+                                                     (void *)&rtdbg_data[2],
+                                                     &reg_debug_ops);
+       }
+       platform_set_drvdata(pdev, di);
+       return 0;
+}
+
+static int rt5036_debug_remove(struct platform_device *pdev)
+{
+       if (!IS_ERR(debugfs_rt_dent))
+               debugfs_remove_recursive(debugfs_rt_dent);
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-debug",},
+       {},
+};
+
+static struct platform_driver rt5036_debug_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-debug",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_debug_probe,
+       .remove = rt5036_debug_remove,
+};
+
+static int __init rt5036_debug_init(void)
+{
+       return platform_driver_register(&rt5036_debug_driver);
+}
+module_init(rt5036_debug_init);
+
+static void __exit rt5036_debug_exit(void)
+{
+       platform_driver_unregister(&rt5036_debug_driver);
+}
+module_exit(rt5036_debug_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Debugfs driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-debug");
+MODULE_VERSION(RT5036_DRV_VER);
diff --git a/drivers/mfd/rt5036-i2c.c b/drivers/mfd/rt5036-i2c.c
new file mode 100755 (executable)
index 0000000..1d2d616
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ *  drivers/mfd/rt5036-i2c.c
+ *  Source file for Richtek RT5036
+ *
+ *  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/i2c.h>
+#include <linux/mutex.h>
+
+#include <linux/mfd/rt5036/rt5036.h>
+
+static inline int rt5036_read_device(struct i2c_client *i2c,
+                                    int reg, int bytes, void *dest)
+{
+       int ret;
+
+       if (bytes > 1) {
+               ret = i2c_smbus_read_i2c_block_data(i2c, reg, bytes, dest);
+       } else {
+               ret = i2c_smbus_read_byte_data(i2c, reg);
+               if (ret < 0)
+                       return ret;
+               *(unsigned char *)dest = (unsigned char)ret;
+       }
+       return ret;
+}
+
+int rt5036_reg_block_read(struct i2c_client *i2c,
+                         int reg, int bytes, void *dest)
+{
+       return rt5036_read_device(i2c, reg, bytes, dest);
+}
+EXPORT_SYMBOL(rt5036_reg_block_read);
+
+static inline int rt5036_write_device(struct i2c_client *i2c,
+                                     int reg, int bytes, void *dest)
+{
+       int ret;
+
+       if (bytes > 1) {
+               ret = i2c_smbus_write_i2c_block_data(i2c, reg, bytes, dest);
+       } else {
+               ret = i2c_smbus_write_byte_data(i2c, reg, *(u8 *) dest);
+               if (ret < 0)
+                       return ret;
+       }
+       return ret;
+}
+
+int rt5036_reg_block_write(struct i2c_client *i2c,
+                          int reg, int bytes, void *dest)
+{
+       return rt5036_write_device(i2c, reg, bytes, dest);
+}
+EXPORT_SYMBOL(rt5036_reg_block_write);
+
+int rt5036_reg_read(struct i2c_client *i2c, int reg)
+{
+       struct rt5036_chip *chip = i2c_get_clientdata(i2c);
+       int ret;
+
+       RTINFO("I2C Read (client : 0x%x) reg = 0x%x\n",
+              (unsigned int)i2c, (unsigned int)reg);
+       mutex_lock(&chip->io_lock);
+       ret = i2c_smbus_read_byte_data(i2c, reg);
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(rt5036_reg_read);
+
+int rt5036_reg_write(struct i2c_client *i2c, int reg, unsigned char data)
+{
+       struct rt5036_chip *chip = i2c_get_clientdata(i2c);
+       int ret;
+
+       RTINFO("I2C Write (client : 0x%x) reg = 0x%x, data = 0x%x\n",
+              (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);
+       return ret;
+}
+EXPORT_SYMBOL(rt5036_reg_write);
+
+int rt5036_assign_bits(struct i2c_client *i2c, int reg,
+                      unsigned char mask, unsigned char data)
+{
+       struct rt5036_chip *chip = i2c_get_clientdata(i2c);
+       unsigned char value;
+       int ret;
+
+       mutex_lock(&chip->io_lock);
+       ret = rt5036_read_device(i2c, reg, 1, &value);
+
+       if (ret < 0)
+               goto out;
+       value &= ~mask;
+       value |= (data & mask);
+       ret = i2c_smbus_write_byte_data(i2c, reg, value);
+out:
+       mutex_unlock(&chip->io_lock);
+       return ret;
+}
+EXPORT_SYMBOL(rt5036_assign_bits);
+
+int rt5036_set_bits(struct i2c_client *i2c, int reg, unsigned char mask)
+{
+       return rt5036_assign_bits(i2c, reg, mask, mask);
+}
+EXPORT_SYMBOL(rt5036_set_bits);
+
+int rt5036_clr_bits(struct i2c_client *i2c, int reg, unsigned char mask)
+{
+       return rt5036_assign_bits(i2c, reg, mask, 0);
+}
+EXPORT_SYMBOL(rt5036_clr_bits);
+
+static int rt_parse_dt(struct rt5036_chip *chip, struct device *dev)
+{
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_pdata(struct rt5036_chip *chip,
+                                   struct device *dev)
+{
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt5036_i2c_probe(struct i2c_client *client,
+                                     const struct i2c_device_id *id)
+{
+       struct rt5036_platform_data *pdata = client->dev.platform_data;
+       struct rt5036_chip *chip;
+       bool use_dt = client->dev.of_node;
+       int val, ret = 0;
+
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->i2c = client;
+       mutex_init(&chip->io_lock);
+       i2c_set_clientdata(client, chip);
+
+       val = rt5036_reg_read(client, RT5036_REG_DEVID);
+       if (val < 0) {
+               ret = -EIO;
+               goto out_err;
+       } else {
+               if (val != 0x36) {
+                       dev_err(&client->dev, "id 0x%02x is not correct\n",
+                               val);
+                       ret = ENODEV;
+                       goto out_err;
+               }
+               val = rt5036_reg_read(client, RT5036_REG_ONOFFEVENT);
+               dev_info(&client->dev, "last onoff event %02x\n", val);
+               /*set ldo lsw vrc to default enable*/
+               rt5036_reg_write(client, 0x4D, 0xF0);
+               rt5036_reg_write(client, 0x7D, 0xF0);
+               rt5036_reg_write(client, 0x85, 0xCC);
+       }
+
+       if (use_dt) {
+               rt_parse_dt(chip, &client->dev);
+       } else {
+               if (!pdata) {
+                       dev_err(&client->dev, "no platform data included\n");
+                       ret = -EINVAL;
+                       goto out_err;
+               }
+               rt_parse_pdata(chip, &client->dev);
+       }
+
+       ret = rt5036_core_init(&client->dev, pdata);
+       if (ret < 0) {
+               ret = -EINVAL;
+               goto out_err;
+       }
+
+       if (pdata && pdata->pre_init) {
+               ret = pdata->pre_init(chip);
+               if (ret != 0)
+                       dev_err(&client->dev, "pre_init() failed: %d\n", ret);
+       }
+       if (pdata && pdata->post_init) {
+               ret = pdata->post_init();
+               if (ret != 0)
+                       dev_err(&client->dev, "post_init() failed: %d\n", ret);
+       }
+       dev_info(&client->dev, "driver successfully loaded\n");
+       return 0;
+out_err:
+       return ret;
+}
+
+static int rt5036_i2c_remove(struct i2c_client *client)
+{
+       RTINFO("\n");
+       rt5036_core_deinit(&client->dev);
+       return 0;
+}
+
+static int rt5036_i2c_suspend(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct rt5036_chip *chip = i2c_get_clientdata(i2c);
+
+       RTINFO("\n");
+       chip->suspend = 1;
+       return 0;
+}
+
+static int rt5036_i2c_resume(struct device *dev)
+{
+       struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+       struct rt5036_chip *chip = i2c_get_clientdata(i2c);
+
+       RTINFO("\n");
+       chip->suspend = 0;
+       return 0;
+}
+
+static const struct dev_pm_ops rt5036_pm_ops = {
+       .suspend = rt5036_i2c_suspend,
+       .resume =  rt5036_i2c_resume,
+};
+
+static const struct i2c_device_id rt5036_id_table[] = {
+       {RT5036_DEV_NAME, 0},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, rt5036_id_table);
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036",},
+       {},
+};
+
+static struct i2c_driver rt5036_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME,
+                  .owner = THIS_MODULE,
+                  .pm = &rt5036_pm_ops,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_i2c_probe,
+       .remove = rt5036_i2c_remove,
+       .id_table = rt5036_id_table,
+};
+
+static int __init rt5036_i2c_init(void)
+{
+       return i2c_add_driver(&rt5036_driver);
+}
+subsys_initcall_sync(rt5036_i2c_init);
+
+static void __exit rt5036_i2c_exit(void)
+{
+       i2c_del_driver(&rt5036_driver);
+}
+module_exit(rt5036_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("I2C Driver for Richtek RT5036");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
+MODULE_VERSION(RT5036_DRV_VER);
diff --git a/drivers/mfd/rt5036-irq.c b/drivers/mfd/rt5036-irq.c
new file mode 100755 (executable)
index 0000000..68df9af
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *  drivers/mfd/rt5036-irq.c
+ *  Driver for Richtek RT5036 PMIC IRQ 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/err.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/rt5036/rt5036.h>
+#include <linux/mfd/rt5036/rt5036-irq.h>
+
+struct rt5036_irq_info {
+       struct i2c_client *i2c;
+       struct rt5036_chip *chip;
+       struct device *dev;
+       int irq;
+       unsigned char suspend:1;
+       struct delayed_work irq_delayed_work;
+};
+
+static irqreturn_t rt5036_irq_handler(int irqno, void *param)
+{
+       struct rt5036_irq_info *ii = param;
+       unsigned char regval[3];
+       unsigned int irq_event;
+       int ret = 0;
+
+       if (ii->suspend) {
+               schedule_delayed_work(&ii->irq_delayed_work,
+                                     msecs_to_jiffies(10));
+               goto irq_fin;
+       }
+
+       ret =
+           rt5036_reg_block_read(ii->i2c, RT5036_REG_CHGIRQ1,
+                                 ARRAY_SIZE(regval), regval);
+       if (ret < 0) {
+               dev_err(ii->dev, "read charger irq event fail\n");
+       } else {
+               irq_event = regval[0] << 16 | regval[1] << 8 | regval[2];
+               RTINFO("chg event %06x\n", irq_event);
+#ifdef CONFIG_CHARGER_RT5036
+               if (irq_event && ii->chip->chg_info)
+                       rt5036_charger_irq_handler(ii->chip->chg_info,
+                                                  irq_event);
+#endif /* #ifdef CONFIG_CHARGER_RT5036 */
+       }
+
+       ret =
+           rt5036_reg_block_read(ii->i2c, RT5036_REG_BUCKLDOIRQ,
+                                 ARRAY_SIZE(regval), regval);
+       if (ret < 0) {
+               dev_err(ii->dev, "read misc irq event fail\n");
+       } else {
+               irq_event = regval[0] << 16 | regval[1] << 8 | regval[2];
+               RTINFO("misc event %06x\n", irq_event);
+#ifdef CONFIG_MISC_RT5036
+               if (irq_event && ii->chip->misc_info)
+                       rt5036_misc_irq_handler(ii->chip->misc_info, irq_event);
+#endif /* #ifdef CONFIG_MISC_RT5036 */
+       }
+
+       ret = rt5036_reg_read(ii->i2c, RT5036_REG_STBWACKIRQ);
+       if (ret < 0) {
+               dev_err(ii->dev, "read rtc irq event fail\n");
+       } else {
+               irq_event = ret;
+               RTINFO("rtc event %02x\n", irq_event);
+#ifdef CONFIG_RTC_RT5036
+               if (irq_event && ii->chip->rtc_info)
+                       rt5036_rtc_irq_handler(ii->chip->rtc_info, irq_event);
+#endif /* #ifdef CONFIG_RTC_RT5036 */
+       }
+       rt5036_set_bits(ii->i2c, RT5036_REG_BUCKVN1, RT5036_IRQPREZ_MASK);
+irq_fin:
+       return IRQ_HANDLED;
+}
+
+static void rt5036_irq_delayed_work(struct work_struct *work)
+{
+       struct rt5036_irq_info *ii =
+           (struct rt5036_irq_info *)container_of(work, struct rt5036_irq_info,
+                                                  irq_delayed_work.work);
+       rt5036_irq_handler(ii->irq, ii);
+}
+
+static int rt_parse_dt(struct rt5036_irq_info *ii, struct device *dev)
+{
+#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, "rt5036_irq") >= 0) {
+                       gpio_direction_input(val);
+                       ii->irq = gpio_to_irq(val);
+               } else {
+                       ii->irq = -1;
+               }
+       } else {
+               ii->irq = -1;
+       }
+#endif /* #ifdef CONFIG_OF */
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_pdata(struct rt5036_irq_info *ii,
+                                   struct device *dev)
+{
+       struct rt5036_irq_data *pdata = dev->platform_data;
+
+       if (gpio_is_valid(pdata->irq_gpio)) {
+               if (gpio_request(pdata->irq_gpio, "rt5036_irq") >= 0) {
+                       gpio_direction_input(pdata->irq_gpio);
+                       ii->irq = gpio_to_irq(pdata->irq_gpio);
+               } else {
+                       ii->irq = -1;
+               }
+       } else {
+               ii->irq = -1;
+       }
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt5036_irq_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_platform_data *pdata = (pdev->dev.parent)->platform_data;
+       struct rt5036_irq_info *ii;
+       bool use_dt = pdev->dev.of_node;
+
+       ii = devm_kzalloc(&pdev->dev, sizeof(*ii), GFP_KERNEL);
+       if (!ii)
+               return -ENOMEM;
+
+       ii->i2c = chip->i2c;
+       ii->chip = chip;
+       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);
+       }
+       INIT_DELAYED_WORK(&ii->irq_delayed_work, rt5036_irq_delayed_work);
+
+       platform_set_drvdata(pdev, ii);
+       if (ii->irq >= 0) {
+               if (devm_request_irq
+                   (&pdev->dev, ii->irq, rt5036_irq_handler,
+                    IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND | IRQF_DISABLED,
+                    "rt5036_irq", ii)) {
+                       dev_err(&pdev->dev, "request threaded irq fail\n");
+                       goto out_dev;
+               }
+               enable_irq_wake(ii->irq);
+               schedule_delayed_work(&ii->irq_delayed_work,
+                                     msecs_to_jiffies(500));
+       }
+       dev_info(&pdev->dev, "driver successfully loaded\n");
+       return 0;
+out_dev:
+       return -EINVAL;
+}
+
+static int rt5036_irq_remove(struct platform_device *pdev)
+{
+       struct rt5036_irq_info *ii = platform_get_drvdata(pdev);
+
+       if (ii->irq >= 0)
+               devm_free_irq(&pdev->dev, ii->irq, ii);
+       return 0;
+}
+
+static int rt5036_irq_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rt5036_irq_info *ii = platform_get_drvdata(pdev);
+
+       ii->suspend = 1;
+       return 0;
+}
+
+static int rt5036_irq_resume(struct platform_device *pdev)
+{
+       struct rt5036_irq_info *ii = platform_get_drvdata(pdev);
+
+       ii->suspend = 0;
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-irq",},
+       {},
+};
+
+static struct platform_driver rt5036_irq_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-irq",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_irq_probe,
+       .remove = rt5036_irq_remove,
+       .suspend = rt5036_irq_suspend,
+       .resume = rt5036_irq_resume,
+};
+
+static int __init rt5036_irq_init(void)
+{
+       return platform_driver_register(&rt5036_irq_driver);
+}
+subsys_initcall_sync(rt5036_irq_init);
+
+static void __exit rt5036_irq_exit(void)
+{
+       platform_driver_unregister(&rt5036_irq_driver);
+}
+module_exit(rt5036_irq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("IRQ driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-irq");
+MODULE_VERSION(RT5036_DRV_VER);
diff --git a/drivers/mfd/rt5036-misc.c b/drivers/mfd/rt5036-misc.c
new file mode 100755 (executable)
index 0000000..9dd6ad6
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  drivers/mfd/rt5036-misc.c
+ *  Driver for Richtek RT5036 PMIC misc option
+ *
+ *  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/err.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+#include <linux/input.h>
+#endif /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+
+#include <linux/mfd/rt5036/rt5036.h>
+#include <linux/mfd/rt5036/rt5036-misc.h>
+
+static struct i2c_client *g_shdn;
+
+static unsigned char misc_init_regval[] = {
+       0xA8,                   /*REG 0x51*/
+       0x96,                   /*REG 0x52*/
+       0x48,                   /*REG 0x53*/
+       0x00,                   /*REG 0x54*/
+       0x06,                   /*REG 0x55*/
+       0xA0,                   /*REG 0x65*/
+       0xFF,                   /*REG 0x5A*/
+       0xE0,                   /*REG 0x5B*/
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+       0x18,                   /*REG 0x5C*/
+#else
+       0x78,                   /*REG 0x5C*/
+#endif /* #ifdef CONFIG_RT5036_PWRKEY */
+};
+
+int rt5036_vin_exist(void)
+{
+       int ret = 0;
+#ifdef CONFIG_CHARGER_RT5036
+       union power_supply_propval pval;
+       struct power_supply *psy = power_supply_get_by_name("rt-charger");
+
+       if (psy) {
+               ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+               if (ret < 0)
+                       ret = 0;
+               else
+                       ret = pval.intval;
+       } else {
+               pr_err("couldn't get rt-charger psy\n");
+       }
+       return ret;
+#else
+       if (g_shdn)
+               ret = rt5036_reg_read(g_shdn, RT5036_REG_CHGSTAT2);
+       return ret < 0 ? 0 : ret & RT5036_PWRRDY_MASK;
+#endif /* #ifdef CONFIG_CHARGER_RT5036 */
+}
+EXPORT_SYMBOL(rt5036_vin_exist);
+static bool rt_pm_off;
+void rt5036_chip_shutdown(void)
+{
+       if (g_shdn) {
+               rt5036_set_bits(g_shdn, RT5036_REG_MISC3, RT5036_CHIPSHDN_MASK);
+               rt5036_clr_bits(g_shdn, RT5036_REG_MISC3, RT5036_CHIPSHDN_MASK);
+       }
+}
+EXPORT_SYMBOL(rt5036_chip_shutdown);
+
+static void rt5036_general_irq_handler(void *info, int eventno)
+{
+       struct rt5036_misc_info *mi = info;
+
+       dev_info(mi->dev, "eventno=%02d\n", eventno);
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+       switch (eventno) {
+       case MISCEVENT_PWRONF:
+               if (!mi->pwr_key_pressed) {
+                       input_report_key(mi->pwr_key, KEY_POWER, 1);
+                       input_sync(mi->pwr_key);
+                       mi->pwr_key_pressed = 1;
+               }
+               break;
+       case MISCEVENT_PWRONR:
+               if (mi->pwr_key_pressed) {
+                       input_report_key(mi->pwr_key, KEY_POWER, 0);
+                       input_sync(mi->pwr_key);
+                       mi->pwr_key_pressed = 0;
+               }
+               break;
+       default:
+               break;
+       }
+#endif /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+}
+
+static rt_irq_handler rt_miscirq_handler[MISCEVENT_MAX] = {
+       [MISCEVENT_PWRONLP] = rt5036_general_irq_handler,
+       [MISCEVENT_PWRONSP] = rt5036_general_irq_handler,
+       [MISCEVENT_PWRONF] = rt5036_general_irq_handler,
+       [MISCEVENT_PWRONR] = rt5036_general_irq_handler,
+       [MISCEVENT_KPSHDN] = rt5036_general_irq_handler,
+       [MISCEVENT_VDDALV] = rt5036_general_irq_handler,
+       [MISCEVNET_OTM] = rt5036_general_irq_handler,
+       [MISCEVENT_PMICSYSLV] = rt5036_general_irq_handler,
+       [MISCEVENT_LSW2LV] = rt5036_general_irq_handler,
+       [MISCEVENT_LSW1LV] = rt5036_general_irq_handler,
+       [MISCEVENT_LDO4LV] = rt5036_general_irq_handler,
+       [MISCEVENT_LDO3LV] = rt5036_general_irq_handler,
+       [MISCEVENT_LDO2LV] = rt5036_general_irq_handler,
+       [MISCEVENT_LDO1LV] = rt5036_general_irq_handler,
+       [MISCEVENT_BUCK4LV] = rt5036_general_irq_handler,
+       [MISCEVENT_BUCK3LV] = rt5036_general_irq_handler,
+       [MISCEVENT_BUCK2LV] = rt5036_general_irq_handler,
+       [MISCEVENT_BUCK1LV] = rt5036_general_irq_handler,
+};
+
+void rt5036_misc_irq_handler(struct rt5036_misc_info *mi, unsigned int irqevent)
+{
+       int i;
+       unsigned int masked_irq_event =
+           (misc_init_regval[6] << 16) | (misc_init_regval[7] << 8) |
+           misc_init_regval[8];
+       unsigned int final_irq_event = irqevent & (~masked_irq_event);
+
+       for (i = 0; i < MISCEVENT_MAX; i++) {
+               if ((final_irq_event & (1 << i)) && rt_miscirq_handler[i])
+                       rt_miscirq_handler[i] (mi, i);
+       }
+}
+EXPORT_SYMBOL(rt5036_misc_irq_handler);
+
+static int rt5036_misc_reginit(struct i2c_client *i2c)
+{
+       rt5036_reg_write(i2c, RT5036_REG_MISC6, misc_init_regval[5]);
+       rt5036_reg_block_write(i2c, RT5036_REG_MISC1, 5, misc_init_regval);
+       rt5036_reg_block_write(i2c, RT5036_REG_BUCKLDOIRQMASK,
+                              3, &misc_init_regval[6]);
+       /*always clear at the first time*/
+       rt5036_reg_read(i2c, RT5036_REG_BUCKLDOIRQ);
+       rt5036_reg_read(i2c, RT5036_REG_LSWBASEIRQ);
+       rt5036_reg_read(i2c, RT5036_REG_PWRKEYIRQ);
+       return 0;
+}
+
+static int rt_parse_dt(struct rt5036_misc_info *mi,
+                                struct device *dev)
+{
+#ifdef CONFIG_OF
+       struct device_node *np = dev->of_node;
+       u32 val;
+
+       if (of_property_read_u32(np, "rt,shdn_press", &val)) {
+               dev_info(dev,
+                        "no shut_lpress property, use the default value\n");
+       } else {
+               if (val > RT5036_SHDNPRESS_MASK)
+                       val = RT5036_SHDNPRESS_MAX;
+               misc_init_regval[1] &= (~RT5036_SHDNPRESS_MASK);
+               misc_init_regval[1] |= (val << RT5036_SHDNPRESS_SHIFT);
+       }
+
+       if (of_property_read_u32(np, "rt,stb_en", &val)) {
+               dev_info(dev, "no stb_en prpperty , use the default value\n");
+       } else {
+               if (val > RT5036_STB_MAX)
+                       val = RT5036_STB_MAX;
+               misc_init_regval[2] &= (~RT5036_STBEN_MASK);
+               misc_init_regval[2] |= (val << RT5036_STBEN_SHIFT);
+       }
+
+       if (of_property_read_bool(np, "rt,lp_enshdn"))
+               misc_init_regval[4] |= RT5036_LPSHDNEN_MASK;
+       else
+               misc_init_regval[4] &= (~RT5036_LPSHDNEN_MASK);
+
+       if (of_property_read_u32(np, "rt,vsysuvlo", &val)) {
+               dev_info(dev, "no vsysuvlo prpperty , use the default value\n");
+       } else {
+               if (val > RT5036_SYSLV_MAX)
+                       val = RT5036_SYSLV_MAX;
+               misc_init_regval[5] &= (~RT5036_SYSUVLO_MASK);
+               misc_init_regval[5] |= (val << RT5036_SYSUVLO_SHIFT);
+       }
+
+       if (of_property_read_bool(np, "rt,syslv_enshdn"))
+               misc_init_regval[4] |= RT5036_SYSLVENSHDN_MASK;
+       else
+               misc_init_regval[4] &= (~RT5036_SYSLVENSHDN_MASK);
+
+       rt_pm_off = of_property_read_bool(np, "rt,system-power-controller");
+#endif /* #ifdef CONFIG_OF */
+       rt5036_misc_reginit(mi->i2c);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_pdata(struct rt5036_misc_info *mi,
+                                   struct device *dev)
+{
+       struct rt5036_misc_data *misc_pdata = dev->platform_data;
+       /*SHDN_PRESS_TIME property*/
+       misc_init_regval[1] &= (~RT5036_SHDNPRESS_MASK);
+       misc_init_regval[1] |=
+           (misc_pdata->shdn_press << RT5036_SHDNPRESS_SHIFT);
+       /*STB_EN property*/
+       misc_init_regval[2] &= (~RT5036_STBEN_MASK);
+       misc_init_regval[2] |= (misc_pdata->stb_en << RT5036_STBEN_SHIFT);
+       /*LP_ENSHEN property*/
+       if (misc_pdata->lp_enshdn)
+               misc_init_regval[4] |= RT5036_LPSHDNEN_MASK;
+       else
+               misc_init_regval[4] &= (~RT5036_LPSHDNEN_MASK);
+
+       misc_init_regval[5] &= (~RT5036_SYSUVLO_MASK);
+       misc_init_regval[5] |= (misc_pdata->vsysuvlo << RT5036_SYSUVLO_SHIFT);
+
+       if (misc_pdata->syslv_enshdn)
+               misc_init_regval[4] |= RT5036_SYSLVENSHDN_MASK;
+       else
+               misc_init_regval[4] &= (~RT5036_SYSLVENSHDN_MASK);
+
+       rt5036_misc_reginit(mi->i2c);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt5036_misc_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_platform_data *pdata = (pdev->dev.parent)->platform_data;
+       struct rt5036_misc_info *mi;
+       bool use_dt = pdev->dev.of_node;
+
+       mi = devm_kzalloc(&pdev->dev, sizeof(*mi), GFP_KERNEL);
+       if (!mi)
+               return -ENOMEM;
+
+       mi->i2c = chip->i2c;
+       if (use_dt) {
+               rt_parse_dt(mi, &pdev->dev);
+       } else {
+               if (!pdata)
+                       goto out_dev;
+               pdev->dev.platform_data = pdata->misc_pdata;
+               rt_parse_pdata(mi, &pdev->dev);
+       }
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+       mi->pwr_key = input_allocate_device();
+       if (!mi->pwr_key) {
+               dev_err(&pdev->dev, "Allocate pwr_key input fail\n");
+               goto out_dev;
+       }
+       input_set_capability(mi->pwr_key, EV_KEY, KEY_POWER);
+       mi->pwr_key->name = "rt5036_pwr_key";
+       mi->pwr_key->phys = "rt5036_pwr_key/input0";
+       mi->pwr_key->dev.parent = &pdev->dev;
+       if (input_register_device(mi->pwr_key)) {
+               dev_err(&pdev->dev, "register pwr key fail\n");
+               goto free_input;
+       }
+#endif /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+       mi->dev = &pdev->dev;
+       g_shdn = mi->i2c;
+       chip->misc_info = mi;
+       platform_set_drvdata(pdev, mi);
+
+       if (rt_pm_off && !pm_power_off)
+               pm_power_off = rt5036_chip_shutdown;
+
+       dev_info(&pdev->dev, "driver successfully loaded\n");
+       return 0;
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+free_input:
+       input_free_device(mi->pwr_key);
+#endif /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+out_dev:
+       return -EINVAL;
+}
+
+static int rt5036_misc_remove(struct platform_device *pdev)
+{
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+       struct rt5036_misc_info *mi = platform_get_drvdata(pdev);
+
+       input_unregister_device(mi->pwr_key);
+       input_free_device(mi->pwr_key);
+#endif /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-misc",},
+       {},
+};
+
+static struct platform_driver rt5036_misc_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-misc",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_misc_probe,
+       .remove = rt5036_misc_remove,
+};
+
+static int __init rt5036_misc_init(void)
+{
+       return platform_driver_register(&rt5036_misc_driver);
+}
+subsys_initcall(rt5036_misc_init);
+
+static void __exit rt5036_misc_exit(void)
+{
+       platform_driver_unregister(&rt5036_misc_driver);
+}
+module_exit(rt5036_misc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Misc driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-misc");
+MODULE_VERSION(RT5036_DRV_VER);
index f20a5fc493110b228054133b852708347ef05d78..b4efe9ae988f4de08df51331ec8e91a0e1a366c6 100755 (executable)
@@ -71,9 +71,30 @@ config CHARGER_RT5025
        help
          Enable RT5025 Charger driver.
 
+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 CHARGER_RT5036
+       bool "RT5036 charger support"
+       depends on MFD_RT5036
+       default n
+       help
+         Say Y here to enable support for RT5036 chip charger subdevice.
+
 config RT_POWER
-       bool "RT5025 PMIC cable report"
-       depends on CHARGER_RT5025
+       bool "RT PMIC cable report"
+       depends on CHARGER_RT5036 || CHARGER_RT5025
        default n
        help
          Enable AC/USB report.
@@ -86,20 +107,12 @@ config RT_SUPPORT_ACUSB_DUALIN
          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
+config RT_BATTERY
+       bool "RT Test Battery"
+       depends on CHARGER_RT5036
        default n
        help
-         Say Y here to remove Jeita function.
-
+         Enable Test Battery report.
 
 config BATTERY_RICOH619
        tristate "Ricoh RC5T619 PMIC battery driver"
index b2f1409e0e901ca4435842a6a593c39e72c54e03..e29ceac95b8a55fbe97f7c129b5f37a893715e14 100755 (executable)
@@ -63,3 +63,5 @@ 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
+obj-$(CONFIG_CHARGER_RT5036)   += rt5036-charger.o
+obj-$(CONFIG_RT_BATTERY)       += rt-battery.o
diff --git a/drivers/power/rt-battery.c b/drivers/power/rt-battery.c
new file mode 100755 (executable)
index 0000000..93175ad
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  drivers/power/rt-battery.c
+ *  Driver for Richtek RT Test Battery 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/power/rt-battery.h>
+
+struct rt_battery_info {
+       struct device *dev;
+       struct power_supply psy;
+       int chg_status;
+       unsigned char batt_present:1;
+       unsigned char suspend:1;
+};
+
+static enum power_supply_property rt_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static int rt_battery_set_property(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  const union power_supply_propval *val)
+{
+       struct rt_battery_info *rbi = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               rbi->chg_status = val->intval;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               rbi->batt_present = val->intval;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+       case POWER_SUPPLY_PROP_HEALTH:
+       case POWER_SUPPLY_PROP_ONLINE:
+       case POWER_SUPPLY_PROP_CAPACITY:
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int rt_battery_get_property(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  union power_supply_propval *val)
+{
+       struct rt_battery_info *rbi = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = rbi->chg_status;
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               val->intval = POWER_SUPPLY_HEALTH_GOOD;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = rbi->batt_present;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = 4000 * 1000;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               if (rbi->chg_status == POWER_SUPPLY_STATUS_FULL)
+                       val->intval = 100;
+               else
+                       val->intval = 50;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int rt_battery_probe(struct platform_device *pdev)
+{
+       struct rt_battery_info *rbi;
+       int ret;
+
+       rbi = devm_kzalloc(&pdev->dev, sizeof(*rbi), GFP_KERNEL);
+       if (!rbi)
+               return -ENOMEM;
+       rbi->dev = &pdev->dev;
+       rbi->chg_status = POWER_SUPPLY_STATUS_DISCHARGING;
+       rbi->batt_present = 1;
+       platform_set_drvdata(pdev, rbi);
+
+       rbi->psy.name = RT_BATT_NAME;
+       rbi->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+       rbi->psy.set_property = rt_battery_set_property;
+       rbi->psy.get_property = rt_battery_get_property;
+       rbi->psy.properties = rt_battery_props;
+       rbi->psy.num_properties = ARRAY_SIZE(rt_battery_props);
+       ret = power_supply_register(&pdev->dev, &rbi->psy);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "battery supply registered fail\n");
+               goto out_dev;
+       }
+       dev_info(&pdev->dev, "driver successfully loaded\n");
+       return 0;
+out_dev:
+       return ret;
+}
+
+static int rt_battery_remove(struct platform_device *pdev)
+{
+       struct rt_battery_info *rbi = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&rbi->psy);
+       return 0;
+}
+
+static int rt_battery_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct rt_battery_info *rbi = platform_get_drvdata(pdev);
+
+       rbi->suspend = 1;
+       return 0;
+}
+
+static int rt_battery_resume(struct platform_device *pdev)
+{
+       struct rt_battery_info *rbi = platform_get_drvdata(pdev);
+
+       rbi->suspend = 0;
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt-battery",},
+       {},
+};
+
+static struct platform_driver rt_battery_driver = {
+       .driver = {
+                  .name = "rt-battery",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt_battery_probe,
+       .remove = rt_battery_remove,
+       .suspend = rt_battery_suspend,
+       .resume = rt_battery_resume,
+};
+
+static int __init rt_battery_init(void)
+{
+       return platform_driver_register(&rt_battery_driver);
+}
+subsys_initcall(rt_battery_init);
+
+static void __exit rt_battery_exit(void)
+{
+       platform_driver_unregister(&rt_battery_driver);
+}
+module_exit(rt_battery_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("RT Test Battery driver");
+MODULE_ALIAS("platform:rt-battery");
+MODULE_VERSION("1.0.0_G");
old mode 100755 (executable)
new mode 100644 (file)
index 22fc92c..055d54e
@@ -58,135 +58,164 @@ static int rtpower_set_charger(struct rt_power_info *pi)
 
        chg_psy = power_supply_get_by_name("rt-charger");
        if (chg_psy) {
-               rc = chg_psy->get_property(chg_psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+               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);
+                       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);
+                       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);
+                       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,\
+                               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");
+                                       dev_err(pi->dev,
+                                               "set chg voltage fail\n");
                                pval.intval = 1;
-                               rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
+                               rc = chg_psy->set_property(chg_psy,
+                                       POWER_SUPPLY_PROP_ONLINE,
                                        &pval);
                                if (rc < 0)
-                                       dev_err(pi->dev, "set charger online fail\n");
+                                       dev_err(pi->dev,
+                                               "set charger online fail\n");
                        }
                        pval.intval = 1;
-                       rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
-                               &pval);
+                       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);
+                       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);
+                       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);
+                       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);
+                               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");
+                                       dev_err(pi->dev,
+                                               "set chg voltage fail\n");
                                pval.intval = 1;
-                               rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
-                                       &pval);
+                               rc = chg_psy->set_property(chg_psy,
+                                               POWER_SUPPLY_PROP_ONLINE,
+                                               &pval);
                                if (rc < 0)
-                                       dev_err(pi->dev, "set charger online fail\n");
+                                       dev_err(pi->dev,
+                                               "set charger online fail\n");
                        }
                        pval.intval = 1;
-                       rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
-                               &pval);
+                       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);
+                       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);
+                       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);
+                       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);
+                               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");
+                                       dev_err(pi->dev,
+                                               "set chg voltage fail\n");
                                pval.intval = 1;
-                               rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_ONLINE,\
-                                       &pval);
+                               rc = chg_psy->set_property(chg_psy,
+                                               POWER_SUPPLY_PROP_ONLINE,
+                                               &pval);
                                if (rc < 0)
-                                       dev_err(pi->dev, "set charger online fail\n");
+                                       dev_err(pi->dev,
+                                               "set charger online fail\n");
                        }
                        pval.intval = 1;
-                       rc = chg_psy->set_property(chg_psy, POWER_SUPPLY_PROP_PRESENT,\
-                               &pval);
+                       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);
+                       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);
+                       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);
+                       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);
+                       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);
+                       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");
                }
@@ -198,8 +227,9 @@ static int rtpower_set_charger(struct rt_power_info *pi)
        return rc;
 }
 
-static int rtpower_get_property(struct power_supply *psy, enum power_supply_property psp, \
-                       union power_supply_propval *val)
+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;
@@ -207,7 +237,8 @@ static int rtpower_get_property(struct power_supply *psy, enum power_supply_prop
        switch (psp) {
        case POWER_SUPPLY_PROP_ONLINE:
                if (psy->type == POWER_SUPPLY_TYPE_MAINS)
-                       val->intval = (pi->ac_online || pi->usbta_online)?1 : 0;
+                       val->intval = (pi->ac_online
+                                      || pi->usbta_online) ? 1 : 0;
                else if (psy->type == POWER_SUPPLY_TYPE_USB)
                        val->intval = pi->usb_online;
                else
@@ -220,7 +251,8 @@ static int rtpower_get_property(struct power_supply *psy, enum power_supply_prop
        return rc;
 }
 
-static int rtpower_set_property(struct power_supply *psy, enum power_supply_property psp, \
+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);
@@ -239,13 +271,16 @@ static int rtpower_set_property(struct power_supply *psy, enum power_supply_prop
                                if (val->intval) {
                                        pi->usbcnt = 0;
                                        wake_lock(&pi->usbdet_wakelock);
-                                       schedule_delayed_work(&pi->usbdet_work, 1*HZ);
+                                       schedule_delayed_work(&pi->usbdet_work,
+                                                             1 * HZ);
                                } else {
                                        pi->usbcnt = RT_USBCNT_MAX;
-                                       schedule_delayed_work(&pi->usbdet_work, 0);
+                                       schedule_delayed_work(&pi->usbdet_work,
+                                                             0);
                                        if (pi->usbta_online) {
                                                pi->usbta_online = 0;
-                                               power_supply_changed(&pi->ac_psy);
+                                               power_supply_changed
+                                                   (&pi->ac_psy);
                                        }
                                }
                                rc = rtpower_set_charger(pi);
diff --git a/drivers/power/rt5036-charger.c b/drivers/power/rt5036-charger.c
new file mode 100755 (executable)
index 0000000..8583078
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ *  drivers/power/rt5036-charger.c
+ *  Driver for Richtek RT5036 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/workqueue.h>
+#include <linux/of.h>
+#include <linux/power_supply.h>
+#include <linux/delay.h>
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+#include <linux/of_gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+
+#include <linux/mfd/rt5036/rt5036.h>
+#include <linux/power/rt5036-charger.h>
+#ifdef CONFIG_RT_POWER
+#include <linux/power/rt-power.h>
+#endif /* #ifdef CONFIG_RT_POWER */
+#ifdef CONFIG_RT_BATTERY
+#include <linux/power/rt-battery.h>
+#endif /* #ifdef CONFIG_RT_BATTERY */
+
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+#define RT5036_ACIN_LEVEL      0
+#define RT5036_USBIN_LEVEL     1
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+
+static unsigned char chg_init_regval[] = {
+       0xb0,                   /*REG 0x01*/
+       0x58,                   /*REG 0x02*/
+       0x00,                   /*REG 0x03*/
+       0xFE,                   /*REG 0x04*/
+       0x93,                   /*REG 0x05*/
+       0xAD,                   /*REG 0x06*/
+       0xB4,                   /*REG 0x07*/
+       0x01,                   /*REG 0x08*/
+       0x0C,                   /*REG 0x13*/
+       0x80,                   /*REG 0x14*/
+       0x00,                   /*REG 0x15*/
+       0x70,                   /*REG 0x18*/
+};
+
+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_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 int rt_charger_get_property(struct power_supply *psy,
+                                  enum power_supply_property psp,
+                                  union power_supply_propval *val)
+{
+       struct rt5036_charger_info *ci = dev_get_drvdata(psy->dev->parent);
+       int ret = 0;
+       int regval = 0;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               val->intval = ci->online;
+               break;
+       case POWER_SUPPLY_PROP_STATUS:
+               regval = rt5036_reg_read(ci->i2c, RT5036_REG_CHGSTAT1);
+               if (regval < 0) {
+                       ret = -EINVAL;
+               } else {
+                       regval &= RT5036_CHGSTAT_MASK;
+                       regval >>= RT5036_CHGSTAT_SHIFT;
+                       switch (regval) {
+                       case 0:
+                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                               break;
+                       case 1:
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                               break;
+                       case 2:
+                               val->intval = POWER_SUPPLY_STATUS_FULL;
+                               break;
+                       case 3:
+                               val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                               break;
+                       }
+               }
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               regval = rt5036_reg_read(ci->i2c, RT5036_REG_CHGSTAT1);
+               if (regval < 0) {
+                       ret = -EINVAL;
+               } else {
+                       if (regval & RT5036_CHGDIS_MASK)
+                               val->intval = 0;
+                       else
+                               val->intval = 1;
+               }
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               val->intval = ci->charge_cable;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_MAX:
+               val->intval = 2000;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               regval = rt5036_reg_read(ci->i2c, RT5036_REG_CHGCTL1);
+               if (regval < 0) {
+                       ret = -EINVAL;
+               } else {
+                       regval &= RT5036_CHGAICR_MASK;
+                       regval >>= RT5036_CHGAICR_SHIFT;
+                       switch (regval) {
+                       case 0:
+                               val->intval = 0;
+                               break;
+                       case 1:
+                               val->intval = 100;
+                               break;
+                       case 2:
+                               val->intval = 500;
+                               break;
+                       case 3:
+                               val->intval = 700;
+                               break;
+                       case 4:
+                               val->intval = 900;
+                               break;
+                       case 5:
+                               val->intval = 1000;
+                               break;
+                       case 6:
+                               val->intval = 1500;
+                               break;
+                       case 7:
+                               val->intval = 2000;
+                               break;
+                       }
+               }
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               regval = rt5036_reg_read(ci->i2c, RT5036_REG_CHGSTAT1);
+               if (regval < 0) {
+                       ret = -EINVAL;
+               } else {
+                       if (regval & RT5036_CHGOPASTAT_MASK) {
+                               val->intval = -1;
+                       } else {
+                               regval =
+                                   rt5036_reg_read(ci->i2c,
+                                                   RT5036_REG_CHGCTL5);
+                               if (regval < 0) {
+                                       ret = -EINVAL;
+                               } else {
+                                       regval &= RT5036_CHGICC_MASK;
+                                       regval >>= RT5036_CHGICC_SHIFT;
+                                       val->intval = 500 + regval * 100;
+                               }
+                       }
+               }
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               regval = rt5036_reg_read(ci->i2c, RT5036_REG_CHGCTL2);
+               if (regval < 0) {
+                       ret = -EINVAL;
+               } else {
+                       regval &= RT5036_CHGCV_MASK;
+                       regval >>= RT5036_CHGCV_SHIFT;
+                       val->intval = regval * 25 + 3650;
+               }
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+               val->intval = 3650;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+               val->intval = 4400;
+               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 rt5036_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) {
+#ifdef CONFIG_RT_BATTERY
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_BATT_NAME);
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get RT battery\n");
+                       }
+#else
+#ifdef CONFIG_RT9420_FUELGAUGE
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name("rt-fuelgauge");
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev,
+                                       "couldn't get rt fuelgauge battery\n");
+                               }
+#else
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name("battery");
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get battery\n");
+                               }
+#endif /* #ifdef CONFIG_RT9420_FUELGAUGE */
+#endif /* #ifdef CONFIG_RT_BATTERY */
+                       if (ci->te_en)
+                               ret =
+                                   rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                                   RT5036_CHGTEEN_MASK);
+               } else {
+#ifdef CONFIG_RT_BATTERY
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_BATT_NAME);
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get RT battery\n");
+                       }
+#else
+#ifdef CONFIG_RT9420_FUELGAUGE
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name("rt-fuelgauge");
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev,
+                                       "couldn't get rt fuelgauge battery\n");
+                       }
+#else
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name("battery");
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_DISCHARGING;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get battery\n");
+                       }
+#endif /* #ifdef CONFIG_RT9420_FUELGAUGE */
+#endif /* #ifdef CONFIG_RT_BATTERY */
+                       if (ci->te_en) {
+                               ret =
+                                   rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                                   RT5036_CHGTEEN_MASK);
+                               /* te rst workaround */
+                               rt5036_set_bits(ci->i2c, 0x20,
+                                               RT5036_TERST_MASK);
+                               rt5036_clr_bits(ci->i2c, 0x20,
+                                               RT5036_TERST_MASK);
+                       }
+               }
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               if (ci->online && val->intval) {
+                       int icc = 0;
+                       union power_supply_propval pval;
+
+                       if (ci->charge_cable == POWER_SUPPLY_TYPE_MAINS)
+                               icc = ci->acchg_icc;
+                       else if (ci->charge_cable == POWER_SUPPLY_TYPE_USB_DCP)
+                               icc = ci->usbtachg_icc;
+                       else
+                               icc = ci->usbchg_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->charge_cable = val->intval;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_AVG:
+               if (val->intval <= 0)
+                       regval = 0;
+               else if (val->intval <= 100)
+                       regval = 1;
+               else if (val->intval <= 500)
+                       regval = 2;
+               else if (val->intval <= 700)
+                       regval = 3;
+               else if (val->intval <= 900)
+                       regval = 4;
+               else if (val->intval <= 1000)
+                       regval = 5;
+               else if (val->intval <= 1500)
+                       regval = 6;
+               else if (val->intval <= 2000)
+                       regval = 7;
+               else
+                       regval = 0;
+               if (!ci->batabs)
+                       ret = rt5036_assign_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                                RT5036_CHGAICR_MASK,
+                                                regval <<
+                                                RT5036_CHGAICR_SHIFT);
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               if (val->intval < 0) {
+                       union power_supply_propval pval;
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_USB_NAME);
+                       pval.intval = 0;
+                       psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+                       power_supply_changed(psy);
+                       ci->otg_en = 1;
+                       if (ci->charge_cable != POWER_SUPPLY_TYPE_MAINS) {
+                               /* otg drop fix */
+                               rt5036_set_bits(ci->i2c, 0x23, 0x3);
+                               pval.intval = ci->otg_volt;
+                               ci->psy.set_property(&ci->psy,
+                                       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+                                       &pval);
+                               ret =
+                                   rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                                   RT5036_CHGOPAMODE_MASK);
+                               /* otg drop fix */
+                               mdelay(10);
+                               rt5036_clr_bits(ci->i2c, 0x23, 0x3);
+                       }
+#else
+                       ci->otg_en = 1;
+                       /* otg drop fix */
+                       rt5036_set_bits(ci->i2c, 0x23, 0x3);
+                       pval.intval = ci->otg_volt;
+                       ci->psy.set_property(&ci->psy,
+                                            POWER_SUPPLY_PROP_VOLTAGE_NOW,
+                                            &pval);
+                       ret =
+                           rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                           RT5036_CHGOPAMODE_MASK);
+                       /* otg drop fix */
+                       mdelay(10);
+                       rt5036_clr_bits(ci->i2c, 0x23, 0x3);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+               } else if (val->intval == 0) {
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+                       if (ci->charge_cable != POWER_SUPPLY_TYPE_MAINS)
+                               ret =
+                                   rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                                   RT5036_CHGOPAMODE_MASK);
+#else
+                       ret =
+                           rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                           RT5036_CHGOPAMODE_MASK);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+                       ci->otg_en = 0;
+               } else if (val->intval < 500)
+                       regval = 0;
+               else if (val->intval > 2000)
+                       regval = 15;
+               else
+                       regval = (val->intval - 500) / 100;
+               regval += 5;
+               if (regval > 15)
+                       regval = 15;
+               if (!ci->batabs && val->intval > 0)
+                       ret =
+                           rt5036_assign_bits(ci->i2c, RT5036_REG_CHGCTL5,
+                                              RT5036_CHGICC_MASK,
+                                              regval << RT5036_CHGICC_SHIFT);
+               rt5036_reg_write(ci->i2c, RT5036_REG_CHGCTL4,
+                                chg_init_regval[4]);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               if (val->intval < 3650)
+                       regval = 0;
+               else if (val->intval > 5225)
+                       regval = 0x3F;
+               else
+                       regval = (val->intval - 3650) / 25;
+               ret =
+                   rt5036_assign_bits(ci->i2c, RT5036_REG_CHGCTL2,
+                                      RT5036_CHGCV_MASK,
+                                      regval << RT5036_CHGCV_SHIFT);
+               break;
+       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;
+}
+
+static void rt5036_stat2alrt_irq_handler(void *info, int eventno)
+{
+       struct rt5036_charger_info *ci = info;
+       unsigned char old_stat, new_stat;
+       int ret;
+
+       old_stat = ci->stat2;
+       ret = rt5036_reg_read(ci->i2c, RT5036_REG_CHGSTAT2);
+       if (ret < 0) {
+               dev_err(ci->dev, "read stat io fail\n");
+               return;
+       }
+       new_stat = ret;
+       /*cablein status change*/
+       if ((old_stat ^ new_stat) & RT5036_PWRRDY_MASK) {
+               if (new_stat & RT5036_PWRRDY_MASK) {
+#ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_USB_NAME);
+                       if (psy) {
+                               pval.intval = 1;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get RT usb\n");
+                       }
+#endif /* #ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+                       dev_info(ci->dev, "cable in\n");
+               } else {
+#ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+                       union power_supply_propval pval;
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_USB_NAME);
+                       if (psy) {
+                               pval.intval = 0;
+                               psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get RT usb\n");
+                       }
+#endif /* #ifndef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+                       dev_info(ci->dev, "cable out\n");
+               }
+       }
+       /*jeita status change*/
+       old_stat = new_stat & RT5036_TSEVENT_MASK;
+       if (old_stat & RT5036_TSWC_MASK) {
+               dev_info(ci->dev, "warm or cool parameter\n");
+               rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL7,
+                               RT5036_CCJEITA_MASK);
+       } else if (old_stat & RT5036_TSHC_MASK) {
+               dev_info(ci->dev, "hot or cold temperature\n");
+               rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL7,
+                               RT5036_CCJEITA_MASK);
+       } else {
+               dev_info(ci->dev, "normal temperature\n");
+               rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL7,
+                               RT5036_CCJEITA_MASK);
+       }
+       ci->stat2 = new_stat;
+}
+
+static void rt5036_batabs_irq_handler(void *info, int eventno)
+{
+       struct rt5036_charger_info *ci = info;
+       struct power_supply *psy = &ci->psy;
+       union power_supply_propval val;
+       int ret;
+       /*disable battery detection*/
+       ret = rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL6, RT5036_BATDEN_MASK);
+       if (ret < 0)
+               dev_err(ci->dev, "set battary detection disable fail\n");
+       /*set aicr to 2000*/
+       val.intval = 2000;
+       ret = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_AVG, &val);
+       if (ret < 0)
+               dev_err(ci->dev, "set aicr to 2000 fail\n");
+       /*set icc to 2000*/
+       val.intval = 2000;
+       ret = psy->set_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &val);
+       if (ret < 0)
+               dev_err(ci->dev, "set icc to 2000 fail\n");
+       /*set charger offline*/
+       val.intval = 0;
+       ret = psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+       if (ret < 0)
+               dev_err(ci->dev, "set charger offline fail\n");
+#ifdef CONFIG_RT_BATTERY
+       psy = power_supply_get_by_name(RT_BATT_NAME);
+       if (psy) {
+               val.intval = 0;
+               ret = psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &val);
+               if (ret < 0)
+                       dev_err(ci->dev, "set battery not present fail\n");
+       } else {
+               dev_err(ci->dev, "couldn't get batt psy\n");
+               }
+#else
+#ifdef CONFIG_RT9420_FUELGAUGE
+       psy = power_supply_get_by_name("rt-fuelgauge");
+       if (psy) {
+               val.intval = 0;
+               ret = psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &val);
+               if (ret < 0)
+                       dev_err(ci->dev, "set battery not present fail\n");
+       } else {
+               dev_err(ci->dev, "couldn't get rt fuelgauge psy\n");
+               }
+#else
+       psy = power_supply_get_by_name("battery");
+       if (psy) {
+               val.intval = 0;
+               ret = psy->set_property(psy, POWER_SUPPLY_PROP_PRESENT, &val);
+               if (ret < 0)
+                       dev_err(ci->dev, "set battery not present fail\n");
+       } else {
+               dev_err(ci->dev, "couldn't get battery psy\n");
+               }
+#endif /* #ifdef CONFIG_RT9420_FUELGAUGE */
+#endif /* #ifdef CONFIG_RT_BATTERY */
+       ci->batabs = 1;
+}
+
+static void rt5036_general_irq_handler(void *info, int eventno)
+{
+       struct rt5036_charger_info *ci = info;
+
+       RTINFO("eventno=%02d\n", eventno);
+       switch (eventno) {
+       case CHGEVENT_CHTMRFI:
+               rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL3,
+                               RT5036_CHGOTGEN_MASK);
+               msleep(5);
+               rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL3,
+                               RT5036_CHGOTGEN_MASK);
+               break;
+       case CHGEVENT_CHRCHGI:
+               if (!ci->online) {
+                       dev_warn(ci->dev, "recharge false alarm\n");
+               } else {
+#ifdef CONFIG_RT_BATTERY
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_BATT_NAME);
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get batt psy\n");
+                               }
+#else
+#ifdef CONFIG_RT9420_FUELGAUGE
+                       struct power_supply *psy =
+                           power_supply_get_by_name("rt-fuelgauge");
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev,
+                                       "couldn't get rt fuelgauge psy\n");
+                               }
+#else
+                       struct power_supply *psy =
+                           power_supply_get_by_name("battery");
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_CHARGING;
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get battery psy\n");
+                               }
+#endif /* #ifdef CONFIG_RT9420_FUELGAUGE */
+#endif /* #ifdfef CONFIG_RT_BATTERY */
+                       dev_info(ci->dev, "recharge occur\n");
+               }
+               break;
+       case CHGEVENT_IEOCI:
+               if (!ci->online) {
+                       dev_warn(ci->dev, "eoc false alarm\n");
+               } else {
+#ifdef CONFIG_RT_BATTERY
+                       struct power_supply *psy =
+                           power_supply_get_by_name(RT_BATT_NAME);
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_FULL;
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get batt psy\n");
+                               }
+#else
+#ifdef CONFIG_RT9420_FUELGAUGE
+                       struct power_supply *psy =
+                           power_supply_get_by_name("rt-fuelgauge");
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev,
+                                       "couldn't get rt fuelgauge psy\n");
+                               }
+#else
+                       struct power_supply *psy =
+                           power_supply_get_by_name("battery");
+                       union power_supply_propval pval;
+
+                       if (psy) {
+                               pval.intval = POWER_SUPPLY_STATUS_FULL;
+                               /*set battery status*/
+                               psy->set_property(psy, POWER_SUPPLY_PROP_STATUS,
+                                                 &pval);
+                               power_supply_changed(psy);
+                       } else {
+                               dev_err(ci->dev, "couldn't get battery psy\n");
+                               }
+#endif /* #ifdef CONFIG_RT9420_FUELGAUGE */
+#endif /* #ifdfef CONFIG_RT_BATTERY */
+                       dev_info(ci->dev, "eoc really occur\n");
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static rt_irq_handler rt_chgirq_handler[CHGEVENT_MAX] = {
+       [CHGEVENT_STAT2ALT] = rt5036_stat2alrt_irq_handler,
+       [CHGEVENT_CHBSTLOWVI] = rt5036_general_irq_handler,
+       [CHGEVENT_BSTOLI] = rt5036_general_irq_handler,
+       [CHGEVENT_BSTVIMIDOVP] = rt5036_general_irq_handler,
+       [CHGEVENT_CHTMRFI] = rt5036_general_irq_handler,
+       [CHGEVENT_CHRCHGI] = rt5036_general_irq_handler,
+       [CHGEVENT_CHTERMI] = rt5036_general_irq_handler,
+       [CHGEVENT_CHBATOVI] = rt5036_general_irq_handler,
+       [CHGEVENT_CHRVPI] = rt5036_general_irq_handler,
+       [CHGEVENT_BATABSENSE] = rt5036_batabs_irq_handler,
+       [CHGEVENT_CHBADADPI] = rt5036_general_irq_handler,
+       [CHGEVENT_VINCHGPLUGOUT] = rt5036_general_irq_handler,
+       [CHGEVENT_VINCHGPLUGIN] = rt5036_general_irq_handler,
+       [CHGEVENT_PPBATLVI] = rt5036_general_irq_handler,
+       [CHGEVENT_IEOCI] = rt5036_general_irq_handler,
+       [CHGEVENT_VINOVPI] = rt5036_general_irq_handler,
+};
+
+void rt5036_charger_irq_handler(struct rt5036_charger_info *ci,
+                               unsigned int irqevent)
+{
+       int i;
+       unsigned int masked_irq_event =
+           (chg_init_regval[8] << 16) | (chg_init_regval[9] << 8) |
+           chg_init_regval[10];
+       unsigned int final_irq_event = irqevent & (~masked_irq_event);
+
+       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(rt5036_charger_irq_handler);
+
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+static irqreturn_t rt5036_acdet_irq_handler(int irqno, void *param)
+{
+       struct rt5036_charger_info *ci = param;
+
+       if (RT5036_ACIN_LEVEL == gpio_get_value(ci->acdet_gpio)) {
+               union power_supply_propval pval;
+               struct power_supply *psy = power_supply_get_by_name(RT_AC_NAME);
+
+               if (RT5036_ACIN_LEVEL)
+                       irq_set_irq_type(ci->acdet_irq, IRQF_TRIGGER_FALLING);
+               else
+                       irq_set_irq_type(ci->acdet_irq, IRQF_TRIGGER_RISING);
+               if (psy) {
+                       if (ci->otg_en)
+                               rt5036_clr_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                               RT5036_CHGOPAMODE_MASK);
+                       pval.intval = 1;
+                       psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+                       power_supply_changed(psy);
+               } else {
+                       dev_err(ci->dev, "couldn't get RT ac\n");
+                       }
+               dev_info(ci->dev, "ac in\n");
+       } else {
+               union power_supply_propval pval;
+               struct power_supply *psy = power_supply_get_by_name(RT_AC_NAME);
+
+               if (RT5036_ACIN_LEVEL)
+                       irq_set_irq_type(ci->acdet_irq, IRQF_TRIGGER_RISING);
+               else
+                       irq_set_irq_type(ci->acdet_irq, IRQF_TRIGGER_FALLING);
+               if (psy) {
+                       pval.intval = 0;
+                       psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+                       power_supply_changed(psy);
+                       if (ci->otg_en) {
+                               /*set otg voltage*/
+                               pval.intval = ci->otg_volt;
+                               ci->psy.set_property(&ci->psy,
+                                       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+                                       &pval);
+                               rt5036_set_bits(ci->i2c, RT5036_REG_CHGCTL1,
+                                               RT5036_CHGOPAMODE_MASK);
+                       }
+               } else {
+                       dev_err(ci->dev, "couldn't get RT ac\n");
+                       }
+               dev_info(ci->dev, "ac out\n");
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rt5036_usbdet_irq_handler(int irqno, void *param)
+{
+       struct rt5036_charger_info *ci = param;
+
+       if (ci->otg_en) {
+               dev_info(ci->dev, "currently in otg mode\n");
+               goto usb_out;
+       }
+       if (RT5036_USBIN_LEVEL == gpio_get_value(ci->usbdet_gpio)) {
+               union power_supply_propval pval;
+               struct power_supply *psy =
+                   power_supply_get_by_name(RT_USB_NAME);
+               if (RT5036_USBIN_LEVEL)
+                       irq_set_irq_type(ci->usbdet_irq, IRQF_TRIGGER_FALLING);
+               else
+                       irq_set_irq_type(ci->usbdet_irq, IRQF_TRIGGER_RISING);
+               if (psy) {
+                       pval.intval = 1;
+                       psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+                       power_supply_changed(psy);
+               } else {
+                       dev_err(ci->dev, "couldn't get RT usb\n");
+                       }
+               dev_info(ci->dev, "usb in\n");
+       } else {
+               union power_supply_propval pval;
+               struct power_supply *psy =
+                   power_supply_get_by_name(RT_USB_NAME);
+               if (RT5036_USBIN_LEVEL)
+                       irq_set_irq_type(ci->usbdet_irq, IRQF_TRIGGER_RISING);
+               else
+                       irq_set_irq_type(ci->usbdet_irq, IRQF_TRIGGER_FALLING);
+               if (psy) {
+                       pval.intval = 0;
+                       psy->set_property(psy, POWER_SUPPLY_PROP_ONLINE, &pval);
+                       power_supply_changed(psy);
+               } else {
+                       dev_err(ci->dev, "couldn't get RT usb\n");
+                       }
+               dev_info(ci->dev, "usb out\n");
+       }
+usb_out:
+       return IRQ_HANDLED;
+}
+
+static int rt5036_acusb_irqinit(struct rt5036_charger_info *ci)
+{
+       int rc = 0;
+
+       if (gpio_is_valid(ci->acdet_gpio) && gpio_is_valid(ci->usbdet_gpio)) {
+               rc = gpio_request(ci->acdet_gpio, "rt5036_acdet_gpio");
+               if (rc < 0) {
+                       dev_err(ci->dev, "request acdet gpio fail\n");
+                       goto irq_out;
+               }
+               rc = gpio_request(ci->usbdet_gpio, "rt5036_usbdet_gpio");
+               if (rc < 0) {
+                       dev_err(ci->dev, "request usbdet gpio fail\n");
+                       goto irq_out;
+               }
+               gpio_direction_input(ci->acdet_gpio);
+               gpio_direction_input(ci->usbdet_gpio);
+
+               ci->acdet_irq = gpio_to_irq(ci->acdet_gpio);
+               ci->usbdet_irq = gpio_to_irq(ci->usbdet_gpio);
+
+               rc = devm_request_threaded_irq(ci->dev, ci->acdet_irq, NULL,
+                                              rt5036_acdet_irq_handler,
+                                              IRQF_TRIGGER_FALLING |
+                                              IRQF_DISABLED,
+                                              "rt5036_acdet_irq", ci);
+               if (rc < 0) {
+                       dev_err(ci->dev, "request acdet irq fail\n");
+                       goto irq_out;
+               }
+               rc = devm_request_threaded_irq(ci->dev, ci->usbdet_irq, NULL,
+                                              rt5036_usbdet_irq_handler,
+                                              IRQF_TRIGGER_FALLING |
+                                              IRQF_DISABLED,
+                                              "rt5036_usbdet_irq", ci);
+               if (rc < 0) {
+                       dev_err(ci->dev, "request usbdet irq fail\n");
+                       goto irq_out;
+               }
+               enable_irq_wake(ci->acdet_irq);
+               enable_irq_wake(ci->usbdet_irq);
+       } else {
+               rc = -EINVAL;
+               }
+irq_out:
+       return rc;
+}
+
+static void rt5036_acusb_irqdeinit(struct rt5036_charger_info *ci)
+{
+       devm_free_irq(ci->dev, ci->acdet_irq, ci);
+       devm_free_irq(ci->dev, ci->usbdet_irq, ci);
+       gpio_free(ci->acdet_gpio);
+       gpio_free(ci->usbdet_gpio);
+}
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+
+static void rt5036_chg_dwork_func(struct work_struct *work)
+{
+       struct rt5036_charger_info *ci =
+           container_of(work, struct rt5036_charger_info,
+                        dwork.work);
+       rt5036_stat2alrt_irq_handler(ci, 0);
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       rt5036_acdet_irq_handler(ci->acdet_irq, ci);
+       rt5036_usbdet_irq_handler(ci->usbdet_irq, ci);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+}
+
+static int rt5036_charger_reginit(struct i2c_client *client)
+{
+       /*thermal HGM*/
+       rt5036_set_bits(client, 0x20, 0x40);
+       /*charger fix in rev D IC*/
+       rt5036_reg_write(client, 0x22, 0xE0);
+       /*write charger init val*/
+       rt5036_reg_block_write(client, RT5036_REG_CHGCTL1, 8, chg_init_regval);
+       rt5036_reg_block_write(client, RT5036_REG_CHGIRQMASK1, 3,
+                              &chg_init_regval[8]);
+       rt5036_reg_write(client, RT5036_REG_CHGSTAT2MASK, chg_init_regval[11]);
+       /*always read at first time*/
+       rt5036_reg_read(client, RT5036_REG_CHGIRQ1);
+       rt5036_reg_read(client, RT5036_REG_CHGIRQ2);
+       rt5036_reg_read(client, RT5036_REG_CHGIRQ3);
+       rt5036_set_bits(client, 0x20, RT5036_TERST_MASK);
+       rt5036_clr_bits(client, 0x20, RT5036_TERST_MASK);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_dt(struct rt5036_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 the default value\n");
+       } else {
+               if (val > RT5036_IPREC_MAX)
+                       val = RT5036_IPREC_MAX;
+               chg_init_regval[4] &= (~RT5036_CHGIPREC_MASK);
+               chg_init_regval[4] |= (val << RT5036_CHGIPREC_SHIFT);
+       }
+
+       if (of_property_read_u32(np, "rt,ieoc", &val)) {
+               dev_info(dev, "no ieoc property, use the default value\n");
+       } else {
+               if (val > RT5036_IEOC_MAX)
+                       val = RT5036_IEOC_MAX;
+               chg_init_regval[4] &= (~RT5036_CHGIEOC_MASK);
+               chg_init_regval[4] |= val;
+       }
+
+       if (of_property_read_u32(np, "rt,vprec", &val)) {
+               dev_info(dev, "no vprec property, use the default value\n");
+       } else {
+               if (val > RT5036_VPREC_MAX)
+                       val = RT5036_VPREC_MAX;
+               chg_init_regval[5] &= (~RT5036_CHGVPREC_MASK);
+               chg_init_regval[5] |= val;
+       }
+
+       if (of_property_read_u32(np, "rt,batlv", &val)) {
+               dev_info(dev, "no batlv property, use the default value\n");
+       } else {
+               if (val > RT5036_BATLV_MAX)
+                       val = RT5036_BATLV_MAX;
+               chg_init_regval[6] &= (~RT5036_CHGBATLV_MASK);
+               chg_init_regval[6] |= val;
+       }
+
+       if (of_property_read_u32(np, "rt,vrechg", &val)) {
+               dev_info(dev, "no vrechg property, use the default value\n");
+       } else {
+               if (val > RT5036_VRECHG_MAX)
+                       val = RT5036_VRECHG_MAX;
+               chg_init_regval[7] &= (~RT5036_CHGVRECHG_MASK);
+               chg_init_regval[7] |= (val << RT5036_CHGVRECHG_SHIFT);
+       }
+
+       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,otg_volt", &val)) {
+               dev_info(dev,
+                        "no otg_volt property, use 5025 as the default value\n");
+               ci->otg_volt = 5025;
+       } else {
+               ci->otg_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;
+               }
+
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       ci->acdet_gpio = of_get_named_gpio(np, "rt,acdet_gpio", 0);
+       ci->usbdet_gpio = of_get_named_gpio(np, "rt,usbdet_gpio", 0);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+#endif /* #ifdef CONFIG_OF */
+       rt5036_charger_reginit(ci->i2c);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_pdata(struct rt5036_charger_info *ci,
+                                   struct device *dev)
+{
+       struct rt5036_chg_data *pdata = dev->platform_data;
+
+       if (pdata->te_en)
+               ci->te_en = 1;
+
+       chg_init_regval[4] &= (~RT5036_CHGIPREC_MASK);
+       chg_init_regval[4] |= (pdata->iprec << RT5036_CHGIPREC_SHIFT);
+
+       chg_init_regval[4] &= (~RT5036_CHGIEOC_MASK);
+       chg_init_regval[4] |= pdata->ieoc;
+
+       chg_init_regval[5] &= (~RT5036_CHGVPREC_MASK);
+       chg_init_regval[5] |= pdata->vprec;
+
+       chg_init_regval[6] &= (~RT5036_CHGBATLV_MASK);
+       chg_init_regval[6] |= pdata->batlv;
+
+       chg_init_regval[7] &= (~RT5036_CHGVRECHG_MASK);
+       chg_init_regval[7] |= (pdata->vrechg << RT5036_CHGVRECHG_SHIFT);
+
+       ci->chg_volt = pdata->chg_volt;
+       ci->otg_volt = pdata->otg_volt;
+       ci->acchg_icc = pdata->acchg_icc;
+       ci->usbtachg_icc = pdata->usbtachg_icc;
+       ci->usbchg_icc = pdata->usbchg_icc;
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       ci->acdet_gpio = pdata->acdet_gpio;
+       ci->usbdet_gpio = pdata->usbdet_gpio;
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+       rt5036_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_RT_BATTERY
+static struct platform_device rt_battery_dev = {
+       .name = "rt-battery",
+       .id = -1,
+};
+#endif /* #ifdef CONFIG_RT_BATTERY */
+
+static int rt5036_charger_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_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 rt5036_charger_info *ci;
+       bool use_dt = pdev->dev.of_node;
+       int ret = 0;
+
+       ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
+       if (!ci)
+               return -ENOMEM;
+
+       ci->i2c = chip->i2c;
+       if (use_dt) {
+               rt_parse_dt(ci, &pdev->dev);
+       } else {
+               if (!pdata) {
+                       dev_err(&pdev->dev, "platform data invalid\n");
+                       ret = -EINVAL;
+                       goto out_dev;
+               }
+               pdev->dev.platform_data = pdata->chg_pdata;
+               rt_parse_pdata(ci, &pdev->dev);
+       }
+
+       ci->dev = &pdev->dev;
+       INIT_DELAYED_WORK(&ci->dwork, rt5036_chg_dwork_func);
+
+       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_RT_BATTERY
+       rt_battery_dev.dev.parent = &pdev->dev;
+       ret = platform_device_register(&rt_battery_dev);
+       if (ret < 0)
+               goto out_dev;
+#endif /* #ifdef CONFIG_RT_BATTERY */
+
+#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 */
+
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       ret = rt5036_acusb_irqinit(ci);
+       if (ret < 0)
+               goto out_all;
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+
+       schedule_delayed_work(&ci->dwork, msecs_to_jiffies(100));
+       chip->chg_info = ci;
+       dev_info(&pdev->dev, "driver successfully loaded\n");
+       return 0;
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+out_all:
+       platform_device_unregister(&rt_power_dev);
+       devm_kfree(&pdev->dev, rt_power_pdata);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+#ifdef CONFIG_RT_POWER
+out_psy:
+#endif /* #ifdef CONFIG_RT_POEWR */
+#ifdef CONFIG_RT_BATTERY
+       platform_device_unregister(&rt_battery_dev);
+#endif /* #ifdef CONFIG_RT_BATTERY */
+       power_supply_unregister(&ci->psy);
+out_dev:
+       return ret;
+}
+
+static int rt5036_charger_remove(struct platform_device *pdev)
+{
+       struct rt5036_charger_info *ci = platform_get_drvdata(pdev);
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       rt5036_acusb_irqdeinit(ci);
+#endif /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+#ifdef CONFIG_RT_POWER
+       platform_device_unregister(&rt_power_dev);
+#endif /* #ifdef CONFIG_RT_POWER */
+#ifdef CONFIG_RT_BATTERY
+       platform_device_unregister(&rt_battery_dev);
+#endif /* #ifdef CONFIG_RT_BATTERY */
+       power_supply_unregister(&ci->psy);
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-charger",},
+       {},
+};
+
+static struct platform_driver rt5036_charger_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-charger",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_charger_probe,
+       .remove = rt5036_charger_remove,
+};
+
+static int __init rt5036_charger_init(void)
+{
+       return platform_driver_register(&rt5036_charger_driver);
+}
+subsys_initcall(rt5036_charger_init);
+
+static void __exit rt5036_charger_exit(void)
+{
+       platform_driver_unregister(&rt5036_charger_driver);
+}
+module_exit(rt5036_charger_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Charger driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-charger");
+MODULE_VERSION(RT5036_DRV_VER);
index 13e1a2f433c7012116025322d8e426e7b5d5de27..0e3d77db3a5dc80bb5b658831c4083ccd6f43512 100755 (executable)
@@ -269,6 +269,12 @@ config REGULATOR_RT5025
        help
          This driver supports voltage regulator in RT5025 PMIC chips.
 
+config REGULATOR_RT5036
+       bool "RT5036 regulator support"
+       depends on MFD_RT5036
+       help
+         This driver support voltage regulator in Richtek RT5036.
+
 config ROCKCHIP_PWM_REGULATOR
        tristate "rockchip pwm voltage regulator for discrete dcdc or ldo"
        help
index 153030939736b3498e1337db500071746ae41d03..efdfb9b86d34495ec20ffa4f4c91393296f434a2 100755 (executable)
@@ -77,6 +77,7 @@ 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_REGULATOR_RT5036) += rt5036-regulator.o
 
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip_io_vol_domain.o
 
diff --git a/drivers/regulator/rt5036-regulator.c b/drivers/regulator/rt5036-regulator.c
new file mode 100644 (file)
index 0000000..28bd28e
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+ *  drivers/regulator/rt5036-regulator.c
+ *  Driver for Richtek RT5036 PMIC Regulator
+ *
+ *  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/err.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.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/rt5036/rt5036.h>
+#include <linux/regulator/rt5036-regulator.h>
+
+struct rt5036_regulator_info {
+       struct regulator_desc desc;
+       struct regulator_dev *regulator;
+       struct i2c_client *i2c;
+       const unsigned int *vol_output_list;
+       const int vol_output_size;
+       int min_uV;
+       int max_uV;
+       unsigned char nvol_reg;
+       unsigned char nvol_shift;
+       unsigned char nvol_mask;
+       unsigned char nenable_reg;
+       unsigned char nenable_bit;
+       unsigned char nmode_reg;
+       unsigned char nmode_bit;
+       unsigned char nramp_reg;
+       unsigned char nramp_bit;
+       unsigned char nramp_shift;
+       unsigned char svol_reg;
+       unsigned char svol_shift;
+       unsigned char svol_mask;
+       unsigned char senable_reg;
+       unsigned char senable_bit;
+       unsigned char smode_reg;
+       unsigned char smode_bit;
+       unsigned char sramp_reg;
+       unsigned char sramp_bit;
+       unsigned char sramp_shift;
+};
+
+/*For DCDC1~4 and LDO1~4 and LSW1~2*/
+static const unsigned int rt5036_vol_output_list[] = {
+       /*0~7 */
+       800 * 1000, 825 * 1000, 850 * 1000, 875 * 1000, 900 * 1000, 925 * 1000,
+           950 * 1000, 975 * 1000,
+       /*8~15 */
+       1000 * 1000, 1025 * 1000, 1050 * 1000, 1075 * 1000, 1100 * 1000,
+           1125 * 1000, 1150 * 1000, 1175 * 1000,
+       /*16~23 */
+       1200 * 1000, 1225 * 1000, 1250 * 1000, 1275 * 1000, 1300 * 1000,
+           1325 * 1000, 1350 * 1000, 1375 * 1000,
+       /*24~31 */
+       1400 * 1000, 1425 * 1000, 1450 * 1000, 1475 * 1000, 1500 * 1000,
+           1525 * 1000, 1550 * 1000, 1575 * 1000,
+       /*32~39 */
+       1600 * 1000, 1625 * 1000, 1650 * 1000, 1675 * 1000, 1700 * 1000,
+           1725 * 1000, 1750 * 1000, 1775 * 1000,
+       /*40~47 */
+       1800 * 1000, 1825 * 1000, 1850 * 1000, 1875 * 1000, 1900 * 1000,
+           1925 * 1000, 1950 * 1000, 1975 * 1000,
+       /*48~55 */
+       2000 * 1000, 2025 * 1000, 2050 * 1000, 2075 * 1000, 2100 * 1000,
+           2125 * 1000, 2150 * 1000, 2175 * 1000,
+       /*56~63 */
+       2200 * 1000, 2225 * 1000, 2250 * 1000, 2275 * 1000, 2300 * 1000,
+           2325 * 1000, 2350 * 1000, 2375 * 1000,
+       /*64~71 */
+       2400 * 1000, 2425 * 1000, 2450 * 1000, 2475 * 1000, 2500 * 1000,
+           2525 * 1000, 2550 * 1000, 2575 * 1000,
+       /*72~79 */
+       2600 * 1000, 2625 * 1000, 2650 * 1000, 2675 * 1000, 2700 * 1000,
+           2725 * 1000, 2750 * 1000, 2775 * 1000,
+       /*80~87 */
+       2800 * 1000, 2825 * 1000, 2850 * 1000, 2875 * 1000, 2900 * 1000,
+           2925 * 1000, 2950 * 1000, 2975 * 1000,
+       /*88~95 */
+       3000 * 1000, 3025 * 1000, 3050 * 1000, 3075 * 1000, 3100 * 1000,
+           3125 * 1000, 3150 * 1000, 3175 * 1000,
+       /*96~103 */
+       3200 * 1000, 3225 * 1000, 3250 * 1000, 3275 * 1000, 3300 * 1000,
+           3300 * 1000, 3300 * 1000, 3300 * 1000,
+       /*104~111 */
+       3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000,
+           3300 * 1000, 3300 * 1000, 3300 * 1000,
+       /*112~119 */
+       3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000,
+           3300 * 1000, 3300 * 1000, 3300 * 1000,
+       /*120~127 */
+       3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000, 3300 * 1000,
+           3300 * 1000, 3300 * 1000, 3300 * 1000,
+};
+
+#define rt5036_vol_output_size ARRAY_SIZE(rt5036_vol_output_list)
+
+static inline int check_range(struct rt5036_regulator_info *info,
+                             int min_uV, int max_uV)
+{
+       if (min_uV < info->min_uV || min_uV > info->max_uV)
+               return -EINVAL;
+       return 0;
+}
+
+static int rt5036_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return (index >= info->vol_output_size) ?
+           -EINVAL : info->vol_output_list[index];
+}
+
+static int rt5036_find_voltage(struct regulator_dev *rdev,
+                              int min_uV, int max_uV)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       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))
+                       return i;
+       }
+       return -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38))
+static int rt5036_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned char data;
+       const int count = info->vol_output_size;
+
+       if (selector > count)
+               return -EINVAL;
+       data = (unsigned char)selector;
+       data <<= info->nvol_shift;
+       return rt5036_assign_bits(info->i2c, info->nvol_reg, info->nvol_mask,
+                                 data);
+}
+
+static int rt5036_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = rt5036_reg_read(info->i2c, info->nvol_reg);
+       if (ret < 0)
+               return ret;
+       return (ret & info->nvol_mask) >> info->nvol_shift;
+}
+#else
+
+static int rt5036_set_voltage(struct regulator_dev *rdev,
+                             int min_uV, int max_uV, unsigned *selector)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned char data;
+
+       if (check_range(info, min_uV, max_uV)) {
+               dev_err(&rdev->dev, "invalid voltage range (%d, %d) uV\n",
+                       min_uV, max_uV);
+               return -EINVAL;
+       }
+       data = rt5036_find_voltage(rdev, min_uV, max_uV);
+       data <<= info->nvol_shift;
+       return rt5036_assign_bits(info->i2c, info->nvol_reg, info->nvol_mask,
+                                 data);
+}
+
+static int rt5036_get_voltage(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = rt5036_reg_read(info->i2c, info->nvol_reg);
+       if (ret < 0)
+               return ret;
+       ret = (ret & info->nvol_mask) >> info->nvol_shift;
+       return rt5036_list_voltage(rdev, ret);
+}
+#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+
+static int rt5036_enable(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5036_set_bits(info->i2c, info->nenable_reg, info->nenable_bit);
+}
+
+static int rt5036_disable(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5036_clr_bits(info->i2c, info->nenable_reg, info->nenable_bit);
+}
+
+static int rt5036_is_enabled(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = rt5036_reg_read(info->i2c, info->nenable_reg);
+       if (ret < 0)
+               return ret;
+       return (ret & info->nenable_bit) ? 1 : 0;
+}
+
+static int rt5036_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               ret =
+                   rt5036_set_bits(info->i2c, info->nmode_reg,
+                                   info->nmode_bit);
+               break;
+       case REGULATOR_MODE_FAST:
+               ret =
+                   rt5036_clr_bits(info->i2c, info->nmode_reg,
+                                   info->nmode_bit);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static unsigned int rt5036_get_mode(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned int mode;
+       int data;
+
+       data = rt5036_reg_read(info->i2c, info->nmode_reg);
+       mode =
+           (data & info->nmode_bit) ? REGULATOR_MODE_NORMAL :
+           REGULATOR_MODE_FAST;
+       return mode;
+}
+
+static int rt5036_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       unsigned char data;
+
+       if (check_range(info, uV, uV)) {
+               dev_err(&rdev->dev, "invalid voltage range (%d, %d) uV\n",
+                       uV, uV);
+               return -EINVAL;
+       }
+       data = rt5036_find_voltage(rdev, uV, uV);
+       data <<= info->svol_shift;
+       return rt5036_assign_bits(info->i2c, info->svol_reg, info->svol_mask,
+                                 data);
+}
+
+static int rt5036_set_suspend_enable(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5036_set_bits(info->i2c, info->senable_reg, info->senable_bit);
+}
+
+static int rt5036_set_suspend_disable(struct regulator_dev *rdev)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+
+       return rt5036_clr_bits(info->i2c, info->senable_reg, info->senable_bit);
+}
+
+static int rt5036_set_suspend_mode(struct regulator_dev *rdev,
+                                  unsigned int mode)
+{
+       struct rt5036_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               ret =
+                   rt5036_set_bits(info->i2c, info->smode_reg,
+                                   info->smode_bit);
+               break;
+       case REGULATOR_MODE_FAST:
+               ret =
+                   rt5036_clr_bits(info->i2c, info->smode_reg,
+                                   info->smode_bit);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static struct regulator_ops rt5036_regulator_ops = {
+       .list_voltage = rt5036_list_voltage,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38))
+       .get_voltage_sel = rt5036_get_voltage_sel,
+       .set_voltage_sel = rt5036_set_voltage_sel,
+#else
+       .set_voltage = rt5036_set_voltage,
+       .get_voltage = rt5036_get_voltage,
+#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,38) */
+       .enable = rt5036_enable,
+       .disable = rt5036_disable,
+       .is_enabled = rt5036_is_enabled,
+       .set_mode = rt5036_set_mode,
+       .get_mode = rt5036_get_mode,
+       .set_suspend_voltage = rt5036_set_suspend_voltage,
+       .set_suspend_enable = rt5036_set_suspend_enable,
+       .set_suspend_disable = rt5036_set_suspend_disable,
+       .set_suspend_mode = rt5036_set_suspend_mode,
+};
+
+#define RT5036_VOUT_LIST rt5036_vol_output_list
+#define RT5036_VOUT_SIZE rt5036_vol_output_size
+
+#define RT5036_DCDC(_id, min, max)                             \
+{                                                              \
+       .desc   = {                                             \
+               .name   = "rt5036-dcdc" #_id,                   \
+               .n_voltages = RT5036_VOUT_SIZE,                 \
+               .ops    = &rt5036_regulator_ops,                \
+               .type   = REGULATOR_VOLTAGE,                    \
+               .id     = RT5036_ID_DCDC##_id,                  \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .vol_output_list = RT5036_VOUT_LIST,                    \
+       .vol_output_size = RT5036_VOUT_SIZE,                    \
+       .min_uV         = min * 1000,                           \
+       .max_uV         = max * 1000,                           \
+       .nvol_reg       = RT5036_REG_BUCKVN##_id,               \
+       .nvol_shift     = RT5036_DCDCVOUT_SHIFT##_id,           \
+       .nvol_mask      = RT5036_DCDCVOUT_MASK##_id,            \
+       .nenable_reg    = RT5036_REG_BUCKLDONEN,                \
+       .nenable_bit    = RT5036_DCDCEN_MASK##_id,              \
+       .nmode_reg      = RT5036_REG_BUCKVRCNEN,                \
+       .nmode_bit      = RT5036_DCDCMODE_MASK##_id,            \
+       .nramp_reg      = RT5036_REG_BUCKVRCN,                  \
+       .nramp_bit      = RT5036_DCDCRAMP_MASK##_id,            \
+       .nramp_shift    = RT5036_DCDCRAMP_SHIFT##_id,           \
+       .svol_reg       = RT5036_REG_BUCKVS##_id,               \
+       .svol_shift     = RT5036_DCDCVOUT_SHIFT##_id,           \
+       .svol_mask      = RT5036_DCDCVOUT_MASK##_id,            \
+       .senable_reg    = RT5036_REG_BUCKLDOSEN,                \
+       .senable_bit    = RT5036_DCDCEN_MASK##_id,              \
+       .smode_reg      = RT5036_REG_BUCKVRCSEN,                \
+       .smode_bit      = RT5036_DCDCMODE_MASK##_id,            \
+       .sramp_reg      = RT5036_REG_BUCKVRCS,                  \
+       .sramp_bit      = RT5036_DCDCRAMP_MASK##_id,            \
+       .sramp_shift    = RT5036_DCDCRAMP_SHIFT##_id,           \
+}
+
+#define RT5036_LDO(_id, min, max)                              \
+{                                                              \
+       .desc   = {                                             \
+               .name   = "rt5036-ldo" #_id,                    \
+               .n_voltages = RT5036_VOUT_SIZE,                 \
+               .ops    = &rt5036_regulator_ops,                \
+               .type   = REGULATOR_VOLTAGE,                    \
+               .id     = RT5036_ID_LDO##_id,                   \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .vol_output_list = RT5036_VOUT_LIST,                    \
+       .vol_output_size = RT5036_VOUT_SIZE,                    \
+       .min_uV         = min * 1000,                           \
+       .max_uV         = max * 1000,                           \
+       .nvol_reg       = RT5036_REG_LDOVN##_id,                \
+       .nvol_shift     = RT5036_LDOVOUT_SHIFT##_id,            \
+       .nvol_mask      = RT5036_LDOVOUT_MASK##_id,             \
+       .nenable_reg    = RT5036_REG_BUCKLDONEN,                \
+       .nenable_bit    = RT5036_LDOEN_MASK##_id,               \
+       .nmode_reg      = RT5036_REG_LDOVRCNEN,                 \
+       .nmode_bit      = RT5036_LDOMODE_MASK##_id,             \
+       .nramp_reg      = RT5036_REG_LDOVRCN,                   \
+       .nramp_bit      = RT5036_LDORAMP_MASK##_id,             \
+       .nramp_shift    = RT5036_LDORAMP_SHIFT##_id,            \
+       .svol_reg       = RT5036_REG_LDOVS##_id,                \
+       .svol_shift     = RT5036_LDOVOUT_SHIFT##_id,            \
+       .svol_mask      = RT5036_LDOVOUT_MASK##_id,             \
+       .senable_reg    = RT5036_REG_BUCKLDOSEN,                \
+       .senable_bit    = RT5036_LDOEN_MASK##_id,               \
+       .smode_reg      = RT5036_REG_LDOVRCSEN,                 \
+       .smode_bit      = RT5036_LDOMODE_MASK##_id,             \
+       .sramp_reg      = RT5036_REG_LDOVRCS,                   \
+       .sramp_bit      = RT5036_LDORAMP_MASK##_id,             \
+       .sramp_shift    = RT5036_LDORAMP_SHIFT##_id,            \
+}
+
+#define RT5036_LSW(_id, min, max)                              \
+{                                                              \
+       .desc   = {                                             \
+               .name   = "rt5036-lsw" #_id,                    \
+               .n_voltages = RT5036_VOUT_SIZE,                 \
+               .ops    = &rt5036_regulator_ops,                \
+               .type   = REGULATOR_VOLTAGE,                    \
+               .id     = RT5036_ID_LSW##_id,                   \
+               .owner  = THIS_MODULE,                          \
+       },                                                      \
+       .vol_output_list = RT5036_VOUT_LIST,                    \
+       .vol_output_size = RT5036_VOUT_SIZE,                    \
+       .min_uV         = min * 1000,                           \
+       .max_uV         = max * 1000,                           \
+       .nvol_reg       = RT5036_REG_LSWVN##_id,                \
+       .nvol_shift     = RT5036_LSWVOUT_SHIFT##_id,            \
+       .nvol_mask      = RT5036_LSWVOUT_MASK##_id,             \
+       .nenable_reg    = RT5036_REG_LSWEN,                     \
+       .nenable_bit    = RT5036_LSWNEN_MASK##_id,              \
+       .nmode_reg      = RT5036_REG_LSWVRCEN,                  \
+       .nmode_bit      = RT5036_LSWNMODE_MASK##_id,            \
+       .nramp_reg      = RT5036_REG_LSWVRC,                    \
+       .nramp_bit      = RT5036_LSWNRAMP_MASK##_id,            \
+       .nramp_shift    = RT5036_LSWNRAMP_SHIFT##_id,           \
+       .svol_reg       = RT5036_REG_LSWVS##_id,                \
+       .svol_shift     = RT5036_LSWVOUT_SHIFT##_id,            \
+       .svol_mask      = RT5036_LSWVOUT_MASK##_id,             \
+       .senable_reg    = RT5036_REG_LSWEN,                     \
+       .senable_bit    = RT5036_LSWSEN_MASK##_id,              \
+       .smode_reg      = RT5036_REG_LSWVRCEN,                  \
+       .smode_bit      = RT5036_LSWSMODE_MASK##_id,            \
+       .sramp_reg      = RT5036_REG_LSWVRC,                    \
+       .sramp_bit      = RT5036_LSWSRAMP_MASK##_id,            \
+       .sramp_shift    = RT5036_LSWSRAMP_SHIFT##_id,           \
+}
+
+static struct rt5036_regulator_info rt5036_regulator_info[] = {
+       RT5036_DCDC(1, 800, 3300),
+       RT5036_DCDC(2, 800, 3300),
+       RT5036_DCDC(3, 800, 3300),
+       RT5036_DCDC(4, 800, 3300),
+       RT5036_LDO(1, 800, 3300),
+       RT5036_LDO(2, 800, 3300),
+       RT5036_LDO(3, 800, 3300),
+       RT5036_LDO(4, 800, 3300),
+       RT5036_LSW(1, 800, 3300),
+       RT5036_LSW(2, 800, 3300),
+};
+
+static struct rt5036_regulator_info *find_regulator_info(int id)
+{
+       struct rt5036_regulator_info *ri;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rt5036_regulator_info); i++) {
+               ri = &rt5036_regulator_info[i];
+               if (ri->desc.id == id)
+                       return ri;
+       }
+       return NULL;
+}
+
+inline struct regulator_dev *rt5036_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,
+               .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);
+#endif /* LINUX_VERSION_CODE>=KERNEL_VERSION(3,5,0)) */
+}
+
+static struct regulator_init_data *rt_parse_dt(struct
+                                                        rt5036_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_KERNEL_VERSION >= KERNEL_VERSION(3,3,0)) */
+
+       if (init_data) {
+               init_data->supply_regulator = (char *)of_get_property(np,
+                                                       "supply-regulator",
+                                                       NULL);
+               rc = of_property_read_u32(np, "rt,standby_vol", &tmp);
+               if (rc)
+                       dev_info(dev, "no standby voltage specified\n");
+               else
+                       init_data->constraints.state_standby.uV = tmp;
+               if (of_property_read_bool(np, "rt,standby_enabled")) {
+                       init_data->constraints.state_standby.enabled = 1;
+                       init_data->constraints.initial_state =
+                           PM_SUSPEND_STANDBY;
+               }
+               if (of_property_read_bool(np, "rt,standby_disabled")) {
+                       init_data->constraints.state_standby.disabled = 1;
+                       init_data->constraints.initial_state =
+                           PM_SUSPEND_STANDBY;
+               }
+       }
+
+       rc = of_property_read_u32(np, "rt,nramp_sel", &tmp);
+       if (rc) {
+               dev_info(dev, "no nramp_sel property, use default value\n");
+       } else {
+               if (tmp > RT5036_RAMP_MAX)
+                       tmp = RT5036_RAMP_MAX;
+               rt5036_assign_bits(ri->i2c, ri->nramp_reg, ri->nramp_bit,
+                                  tmp << ri->nramp_shift);
+       }
+
+       rc = of_property_read_u32(np, "rt,sramp_sel", &tmp);
+       if (rc) {
+               dev_info(dev, "no sramp_sel property, use default value\n");
+       } else {
+               if (tmp > RT5036_RAMP_MAX)
+                       tmp = RT5036_RAMP_MAX;
+               rt5036_assign_bits(ri->i2c, ri->sramp_reg, ri->sramp_bit,
+                                  tmp << ri->sramp_shift);
+       }
+
+       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 rt5036_regulator_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_platform_data *pdata = (pdev->dev.parent)->platform_data;
+       struct rt5036_regulator_info *ri;
+       struct rt5036_regulator_ramp *ramp;
+       struct regulator_dev *rdev;
+       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;
+       }
+
+       ri->i2c = chip->i2c;
+       if (use_dt) {
+               init_data = rt_parse_dt(ri, &pdev->dev);
+       } else {
+               if (!pdata)
+                       return -EINVAL;
+               init_data = pdata->regulator[pdev->id];
+               ramp = init_data ? init_data->driver_data : NULL;
+               if (ramp) {
+                       rt5036_assign_bits(ri->i2c, ri->nramp_reg,
+                                          ri->nramp_bit,
+                                          ramp->nramp_sel << ri->nramp_shift);
+                       rt5036_assign_bits(ri->i2c, ri->sramp_reg,
+                                          ri->sramp_bit,
+                                          ramp->sramp_sel << ri->sramp_shift);
+               }
+       }
+
+       if (!init_data) {
+               dev_err(&pdev->dev, "no initializing data\n");
+               return -EINVAL;
+       }
+
+       rdev = rt5036_regulator_register(&ri->desc, &pdev->dev, init_data, ri);
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "failed to register regulator %s\n",
+                       ri->desc.name);
+               return PTR_ERR(rdev);
+       }
+
+       platform_set_drvdata(pdev, rdev);
+       /*dev_info(&pdev->dev, "regulator successfully registered\n");*/
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt5036_regulator_remove(struct platform_device *pdev)
+{
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+       regulator_unregister(rdev);
+       RTINFO("\n");
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-dcdc1",},
+       {.compatible = "rt,rt5036-dcdc2",},
+       {.compatible = "rt,rt5036-dcdc3",},
+       {.compatible = "rt,rt5036-dcdc4",},
+       {.compatible = "rt,rt5036-ldo1",},
+       {.compatible = "rt,rt5036-ldo2",},
+       {.compatible = "rt,rt5036-ldo3",},
+       {.compatible = "rt,rt5036-ldo4",},
+       {.compatible = "rt,rt5036-lsw1",},
+       {.compatible = "rt,rt5036-lsw2",},
+       {},
+};
+
+static struct platform_driver rt5036_regulator_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-regulator",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_regulator_probe,
+       .remove = rt5036_regulator_remove,
+};
+
+static int __init rt5036_regulator_init(void)
+{
+       return platform_driver_register(&rt5036_regulator_driver);
+}
+subsys_initcall(rt5036_regulator_init);
+
+static void __exit rt5036_regulator_exit(void)
+{
+       platform_driver_unregister(&rt5036_regulator_driver);
+}
+module_exit(rt5036_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("Regulator driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-regulator");
+MODULE_VERSION(RT5036_DRV_VER);
index 9eb29e7582068036cfde3ccd2952b2c0154e863f..87d6c4f6911e72feec0de47912bb7be15d750f21 100755 (executable)
@@ -435,6 +435,13 @@ config  RK818_RTC
        help
                enable rk818 rtc for system
 
+config RTC_RT5036
+       bool "RT5036 RTC driver support"
+       depends on MFD_RT5036
+       default n
+       help
+         Say Y here if you want to support Richtek RT5036 RTC.
+
 config RTC_DRV_TPS80031
        tristate "TI TPS80031/TPS80032 RTC driver"
        depends on MFD_TPS80031
index 00df76aaabd9b75c43815866487f4fcc450b5ab3..026c58c6b1b38182090b4ede46dd250b984f70ce 100755 (executable)
@@ -129,6 +129,7 @@ obj-$(CONFIG_RTC_DRV_VT8500)        += rtc-vt8500.o
 obj-$(CONFIG_RTC_DRV_WM831X)   += rtc-wm831x.o
 obj-$(CONFIG_RK808_RTC)  += rtc-rk808.o
 obj-$(CONFIG_RK818_RTC)  += rtc-rk818.o
+obj-$(CONFIG_RTC_RT5036)       += rtc-rt5036.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_RC5T619)  += rtc-ricoh619.o
diff --git a/drivers/rtc/rtc-rt5036.c b/drivers/rtc/rtc-rt5036.c
new file mode 100755 (executable)
index 0000000..9755820
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ *  drivers/rtc/rt5036-rtc.c
+ *  Driver for Richtek RT5036 PMIC RTC 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/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+
+#include <linux/mfd/rt5036/rt5036.h>
+#include <linux/rtc/rtc-rt5036.h>
+
+static unsigned char rtc_init_regval[] = {
+       0x1,                    /*REG 0x97*/
+       0x3,                    /*REG 0xA5*/
+};
+
+static int rt5036_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rt5036_rtc_info *ri = dev_get_drvdata(dev);
+       unsigned char val[6];
+       int rc;
+
+       RTINFO("\n");
+       rc = rt5036_reg_block_read(ri->i2c, RT5036_REG_RTCTSEC, ARRAY_SIZE(val),
+                                  val);
+       if (rc < 0) {
+               dev_err(dev, "reading rtc time io error\n");
+       } else {
+               tm->tm_sec = val[0] & RT5036_RTC_SECMASK;
+               tm->tm_min = val[1] & RT5036_RTC_MINMASK;
+               tm->tm_hour = val[2] & RT5036_RTC_HOURMASK;
+               tm->tm_year = (val[3] & RT5036_RTC_YEARMASK) + 100;
+               tm->tm_mon = (val[4] & RT5036_RTC_MONMASK) - 1;
+               tm->tm_mday = val[5] & RT5036_RTC_DAYMASK;
+               RTINFO("%04d:%02d:%02d, %02d:%02d:%02d\n", tm->tm_year + 1900,
+                      tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+                      tm->tm_sec);
+               rc = rtc_valid_tm(tm);
+               if (rc < 0) {
+                       dev_err(dev, "not invalid time reading from RT5036\n");
+                       return -EINVAL;
+               }
+       }
+       return rc;
+}
+
+static int rt5036_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct rt5036_rtc_info *ri = dev_get_drvdata(dev);
+       unsigned char val[6];
+       int rc;
+
+       RTINFO("\n");
+       rc = rt5036_reg_block_read(ri->i2c, RT5036_REG_RTCTSEC, ARRAY_SIZE(val),
+                                  val);
+       if (rc < 0) {
+               dev_err(dev, "reading rtc time io error\n");
+       } else {
+               val[0] &= ~RT5036_RTC_SECMASK;
+               val[0] |= (tm->tm_sec & RT5036_RTC_SECMASK);
+               val[1] &= ~RT5036_RTC_MINMASK;
+               val[1] |= (tm->tm_min & RT5036_RTC_MINMASK);
+               val[2] &= ~RT5036_RTC_HOURMASK;
+               val[2] |= (tm->tm_hour & RT5036_RTC_HOURMASK);
+               val[3] &= ~RT5036_RTC_YEARMASK;
+               val[3] |= ((tm->tm_year - 100) & RT5036_RTC_YEARMASK);
+               val[4] &= ~RT5036_RTC_MONMASK;
+               val[4] |= ((tm->tm_mon + 1) & RT5036_RTC_MONMASK);
+               val[5] &= ~RT5036_RTC_DAYMASK;
+               val[5] |= (tm->tm_mday & RT5036_RTC_DAYMASK);
+               val[5] &= ~RT5036_RTC_WEEKMASK;
+               val[5] |=
+                   ((tm->
+                     tm_wday & RT5036_RTC_WEEKMASK) << RT5036_RTC_WEEKSHIFT);
+               RTINFO("%04d:%02d:%02d, %02d:%02d:%02d\n", tm->tm_year + 1900,
+                      tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+                      tm->tm_sec);
+
+               if (tm->tm_year < 100)
+                       return -EINVAL;
+
+               rc = rt5036_reg_block_write(ri->i2c, RT5036_REG_RTCTSEC,
+                                           ARRAY_SIZE(val), val);
+               if (rc < 0) {
+                       dev_err(dev, "writing rtc time io error\n");
+                       return rc;
+               }
+       }
+       return rc;
+}
+
+static int rt5036_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rt5036_rtc_info *ri = dev_get_drvdata(dev);
+       struct rtc_time *tm = &(alarm->time);
+       unsigned char val[6];
+       int rc;
+
+       RTINFO("\n");
+       rc = rt5036_reg_block_read(ri->i2c, RT5036_REG_RTCASEC, ARRAY_SIZE(val),
+                                  val);
+       if (rc < 0) {
+               dev_err(dev, "reading alarm time io error\n");
+       } else {
+               tm->tm_sec = val[0] & RT5036_RTC_SECMASK;
+               tm->tm_min = val[1] & RT5036_RTC_MINMASK;
+               tm->tm_hour = val[2] & RT5036_RTC_HOURMASK;
+               tm->tm_year = (val[3] & RT5036_RTC_YEARMASK) + 100;
+               tm->tm_mon = (val[4] & RT5036_RTC_MONMASK) - 1;
+               tm->tm_mday = val[5] & RT5036_RTC_DAYMASK;
+               RTINFO("%04d_%02d_%02d, %02d:%02d:%02d\n", tm->tm_year + 1900,
+                      tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+                      tm->tm_sec);
+               rc = rtc_valid_tm(tm);
+               if (rc < 0) {
+                       dev_err(dev, "not invalid alarm reading from RT5036\n");
+                       return -EINVAL;
+               }
+       }
+       return rc;
+}
+
+static int rt5036_alarm_irq_enable(struct device *dev, unsigned int enabled);
+
+static int rt5036_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct rt5036_rtc_info *ri = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alarm->time;
+       unsigned char val[6];
+       int rc;
+
+       RTINFO("\n");
+       rt5036_alarm_irq_enable(ri->dev, 0);
+       rc = rt5036_reg_block_read(ri->i2c, RT5036_REG_RTCASEC, ARRAY_SIZE(val),
+                                  val);
+       if (rc < 0) {
+               dev_err(dev, "reading rtc time io error\n");
+       } else {
+               val[0] &= ~RT5036_RTC_SECMASK;
+               val[0] |= (tm->tm_sec & RT5036_RTC_SECMASK);
+               val[1] &= ~RT5036_RTC_MINMASK;
+               val[1] |= (tm->tm_min & RT5036_RTC_MINMASK);
+               val[2] &= ~RT5036_RTC_HOURMASK;
+               val[2] |= (tm->tm_hour & RT5036_RTC_HOURMASK);
+               val[3] &= ~RT5036_RTC_YEARMASK;
+               val[3] |= ((tm->tm_year - 100) & RT5036_RTC_YEARMASK);
+               val[4] &= ~RT5036_RTC_MONMASK;
+               val[4] |= ((tm->tm_mon + 1) & RT5036_RTC_MONMASK);
+               val[5] &= ~RT5036_RTC_DAYMASK;
+               val[5] |= (tm->tm_mday & RT5036_RTC_DAYMASK);
+               RTINFO("%04d:%02d:%02d, %02d:%02d:%02d\n", tm->tm_year + 1900,
+                      tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+                      tm->tm_sec);
+
+               if (tm->tm_year < 100)
+                       return -EINVAL;
+
+               rc = rt5036_reg_block_write(ri->i2c, RT5036_REG_RTCASEC,
+                                           ARRAY_SIZE(val), val);
+               if (rc < 0) {
+                       dev_err(dev, "writing alarm time io error\n");
+                       return rc;
+               }
+       }
+       rt5036_alarm_irq_enable(ri->dev, alarm->enabled);
+       return rc;
+}
+
+static int rt5036_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct rt5036_rtc_info *ri = dev_get_drvdata(dev);
+
+       RTINFO("enable=%d\n", enabled);
+       if (enabled) {
+               rt5036_clr_bits(ri->i2c, RT5036_REG_STBWACKIRQMASK,
+                               RT5036_RTCAIRQ_MASK);
+               rt5036_set_bits(ri->i2c, RT5036_REG_STBMODE,
+                               RT5036_RTCAEN_MASK);
+       } else {
+               rt5036_clr_bits(ri->i2c, RT5036_REG_STBMODE,
+                               RT5036_RTCAEN_MASK);
+               rt5036_set_bits(ri->i2c, RT5036_REG_STBWACKIRQMASK,
+                               RT5036_RTCAIRQ_MASK);
+       }
+       return 0;
+}
+
+static const struct rtc_class_ops rt5036_rtc_ops = {
+       .read_time = rt5036_read_time,
+       .set_time = rt5036_set_time,
+       .read_alarm = rt5036_read_alarm,
+       .set_alarm = rt5036_set_alarm,
+       .alarm_irq_enable = rt5036_alarm_irq_enable,
+};
+
+static void rt5036_general_irq_handler(void *info, int eventno)
+{
+       struct rt5036_rtc_info *ri = info;
+
+       dev_info(ri->dev, "eventno=%02d\n", eventno);
+       switch (eventno) {
+       case RTCEVENT_CAIRQ:
+               rt5036_alarm_irq_enable(ri->dev, 0);
+               break;
+       default:
+               break;
+       }
+}
+
+static rt_irq_handler rt_rtcirq_handler[RTCEVENT_MAX] = {
+       [RTCEVENT_CAIRQ] = rt5036_general_irq_handler,
+       [RTCEVENT_CDIRQ] = rt5036_general_irq_handler,
+};
+
+void rt5036_rtc_irq_handler(struct rt5036_rtc_info *ri, unsigned int irqevent)
+{
+       int i;
+
+       for (i = 0; i < RTCEVENT_MAX; i++) {
+               if ((irqevent & (1 << i)) && rt_rtcirq_handler[i])
+                       rt_rtcirq_handler[i] (ri, i);
+       }
+}
+EXPORT_SYMBOL(rt5036_rtc_irq_handler);
+
+static int rt5036_rtc_reginit(struct i2c_client *i2c)
+{
+       rt5036_reg_write(i2c, RT5036_REG_STBMODE, rtc_init_regval[0]);
+       rt5036_reg_write(i2c, RT5036_REG_STBWACKIRQMASK, rtc_init_regval[1]);
+       /*always clear at the fist time*/
+       rt5036_reg_read(i2c, RT5036_REG_STBWACKIRQ);
+       return 0;
+}
+
+static int rt_parse_dt(struct rt5036_rtc_info *ri, struct device *dev)
+{
+       rt5036_rtc_reginit(ri->i2c);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt_parse_pdata(struct rt5036_rtc_info *ri,
+                                   struct device *dev)
+{
+       rt5036_rtc_reginit(ri->i2c);
+       RTINFO("\n");
+       return 0;
+}
+
+static int rt5036_rtc_probe(struct platform_device *pdev)
+{
+       struct rt5036_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct rt5036_rtc_info *ri;
+       bool use_dt = pdev->dev.of_node;
+
+       ri = devm_kzalloc(&pdev->dev, sizeof(*ri), GFP_KERNEL);
+       if (!ri)
+               return -ENOMEM;
+
+       ri->i2c = chip->i2c;
+       if (use_dt)
+               rt_parse_dt(ri, &pdev->dev);
+       else
+               rt_parse_pdata(ri, &pdev->dev);
+
+       ri->dev = &pdev->dev;
+       platform_set_drvdata(pdev, ri);
+
+       ri->rtc = rtc_device_register("rt5036-rtc", &pdev->dev,
+                                     &rt5036_rtc_ops, THIS_MODULE);
+       if (IS_ERR(ri->rtc)) {
+               dev_err(&pdev->dev, "rtc device register failed\n");
+               goto out_dev;
+       }
+       chip->rtc_info = ri;
+       device_init_wakeup(&pdev->dev, 1);
+       dev_info(&pdev->dev, "driver successfully loaded\n");
+       return 0;
+out_dev:
+       return -EINVAL;
+}
+
+static int rt5036_rtc_remove(struct platform_device *pdev)
+{
+       struct rt5036_rtc_info *ri = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(ri->rtc);
+       return 0;
+}
+
+static const struct of_device_id rt_match_table[] = {
+       {.compatible = "rt,rt5036-rtc",},
+       {},
+};
+
+static struct platform_driver rt5036_rtc_driver = {
+       .driver = {
+                  .name = RT5036_DEV_NAME "-rtc",
+                  .owner = THIS_MODULE,
+                  .of_match_table = rt_match_table,
+                  },
+       .probe = rt5036_rtc_probe,
+       .remove = rt5036_rtc_remove,
+};
+
+static int __init rt5036_rtc_init(void)
+{
+       return platform_driver_register(&rt5036_rtc_driver);
+}
+subsys_initcall(rt5036_rtc_init);
+
+static void __exit rt5036_rtc_exit(void)
+{
+       platform_driver_unregister(&rt5036_rtc_driver);
+}
+module_exit(rt5036_rtc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("CY Huang <cy_huang@richtek.com");
+MODULE_DESCRIPTION("RTC driver for RT5036");
+MODULE_ALIAS("platform:" RT5036_DEV_NAME "-rtc");
+MODULE_VERSION(RT5036_DRV_VER);
diff --git a/include/linux/mfd/rt5036/rt5036-irq.h b/include/linux/mfd/rt5036/rt5036-irq.h
new file mode 100755 (executable)
index 0000000..2de886f
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  include/linux/mfd/rt5036/rt5036-irq.h
+ *  Include header file for Richtek RT5036 irq option 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_MFD_RT5036_IRQ_H
+#define _LINUX_MFD_RT5036_IRQ_H
+
+#define RT5036_IRQPREZ_MASK 0x80
+
+#endif /* #ifndef _LINUX_MFD_RT5036_IRQ_H */
diff --git a/include/linux/mfd/rt5036/rt5036-misc.h b/include/linux/mfd/rt5036/rt5036-misc.h
new file mode 100755 (executable)
index 0000000..3533539
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  include/linux/mfd/rt5036/rt5036-misc.h
+ *  Include header file for Richtek RT5036 Misc option
+ *
+ *  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_MFD_RT5036_MISC_H
+#define _LINUX_MFD_RT5036_MISC_H
+
+enum {
+       MISCEVENT_PWRONLP = 3,
+       MISCEVENT_PWRONSP,
+       MISCEVENT_PWRONF,
+       MISCEVENT_PWRONR,
+       MISCEVENT_KPSHDN,
+       MISCEVENT_VDDALV,
+       MISCEVNET_OTM,
+       MISCEVENT_PMICSYSLV = 13,
+       MISCEVENT_LSW2LV,
+       MISCEVENT_LSW1LV,
+       MISCEVENT_LDO4LV,
+       MISCEVENT_LDO3LV,
+       MISCEVENT_LDO2LV,
+       MISCEVENT_LDO1LV,
+       MISCEVENT_BUCK4LV,
+       MISCEVENT_BUCK3LV,
+       MISCEVENT_BUCK2LV,
+       MISCEVENT_BUCK1LV,
+       MISCEVENT_MAX,
+};
+
+#define RT5036_SHDNPRESS_MASK  0x0C
+#define RT5036_SHDNPRESS_SHIFT 2
+
+#define RT5036_STBEN_MASK      0x06
+#define RT5036_STBEN_SHIFT     1
+
+#define RT5036_LPSHDNEN_MASK   0x04
+#define RT5036_CHIPSHDN_MASK   0x80
+#define RT5036_SYSUVLO_SHIFT   5
+#define RT5036_SYSUVLO_MASK    0xE0
+#define RT5036_SYSLVENSHDN_MASK        0x20
+#define RT5036_PWRRDY_MASK     0x80
+
+extern int rt5036_vin_exist(void);
+extern void rt5036_chip_shutdown(void);
+
+#endif /* #ifndef _LINUX_MFD_RT5036_MISC_H */
diff --git a/include/linux/mfd/rt5036/rt5036.h b/include/linux/mfd/rt5036/rt5036.h
new file mode 100644 (file)
index 0000000..2b56d41
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ *  include/linux/mfd/rt5036/rt5036.h
+ *  Include header file for Richtek RT5036 Core file
+ *
+ *  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_MFD_RT5036_H
+#define _LINUX_MFD_RT5036_H
+#include <linux/power_supply.h>
+
+#define RT5036_DEV_NAME                "rt5036"
+#define RT5036_DRV_VER         "1.0.8_R"
+
+enum {
+       RT5036_ID_DCDC1,
+       RT5036_ID_DCDC2,
+       RT5036_ID_DCDC3,
+       RT5036_ID_DCDC4,
+       RT5036_ID_LDO1,
+       RT5036_ID_LDO2,
+       RT5036_ID_LDO3,
+       RT5036_ID_LDO4,
+       RT5036_ID_LSW1,
+       RT5036_ID_LSW2,
+       RT5036_MAX_REGULATOR,
+};
+
+enum {
+       RT5036_REG_DEVID,
+       RT5036_REG_RANGE1START = RT5036_REG_DEVID,
+       RT5036_REG_CHGCTL1,
+       RT5036_REG_CHGCTL2,
+       RT5036_REG_RESV1,
+       RT5036_REG_CHGCTL3,
+       RT5036_REG_CHGCTL4,
+       RT5036_REG_CHGCTL5,
+       RT5036_REG_CHGCTL6,
+       RT5036_REG_CHGCTL7,
+       RT5036_REG_RSTCHG,
+       RT5036_REG_RANGE1END = RT5036_REG_RSTCHG,
+       RT5036_REG_CHGIRQ1 = 0x10,
+       RT5036_REG_RANGE2START = RT5036_REG_CHGIRQ1,
+       RT5036_REG_CHGIRQ2,
+       RT5036_REG_CHGIRQ3,
+       RT5036_REG_CHGIRQMASK1,
+       RT5036_REG_CHGIRQMASK2,
+       RT5036_REG_CHGIRQMASK3,
+       RT5036_REG_CHGSTAT1,
+       RT5036_REG_CHGSTAT2,
+       RT5036_REG_CHGSTAT2MASK,
+       RT5036_REG_RANGE2END = RT5036_REG_CHGSTAT2MASK,
+       RT5036_REG_BUCKVN1 = 0x41,
+       RT5036_REG_RANGE3START = RT5036_REG_BUCKVN1,
+       RT5036_REG_BUCKVN2,
+       RT5036_REG_BUCKVN3,
+       RT5036_REG_BUCKVN4,
+       RT5036_REG_BUCKVRCN,
+       RT5036_REG_BUCKVRCNEN,
+       RT5036_REG_BUCKMODE,
+       RT5036_REG_LDOVN1,
+       RT5036_REG_LDOVN2,
+       RT5036_REG_LDOVN3,
+       RT5036_REG_LDOVN4,
+       RT5036_REG_LDOVRCN,
+       RT5036_REG_LDOVRCNEN,
+       RT5036_REG_LDOMODE,
+       RT5036_REG_BUCKLDONEN,
+       RT5036_REG_LSWEN,
+       RT5036_REG_MISC1,
+       RT5036_REG_MISC2,
+       RT5036_REG_MISC3,
+       RT5036_REG_MISC4,
+       RT5036_REG_MISC5,
+       RT5036_REG_ONOFFEVENT,
+       RT5036_REG_BUCKLDOIRQ,
+       RT5036_REG_LSWBASEIRQ,
+       RT5036_REG_PWRKEYIRQ,
+       RT5036_REG_BUCKLDOIRQMASK,
+       RT5036_REG_LSWBASEIRQMASK,
+       RT5036_REG_PWRKEYIRQMASK,
+       RT5036_REG_RANGE3END = RT5036_REG_PWRKEYIRQMASK,
+       RT5036_REG_MISC6 = 0x65,
+       RT5036_REG_RANGE4START = RT5036_REG_MISC6,
+       RT5036_REG_RANGE4END = RT5036_REG_MISC6,
+       RT5036_REG_BUCKVS1 = 0x71,
+       RT5036_REG_RANGE5START = RT5036_REG_BUCKVS1,
+       RT5036_REG_BUCKVS2,
+       RT5036_REG_BUCKVS3,
+       RT5036_REG_BUCKVS4,
+       RT5036_REG_BUCKVRCS,
+       RT5036_REG_BUCKVRCSEN,
+       RT5036_REG_RESV2,
+       RT5036_REG_LDOVS1,
+       RT5036_REG_LDOVS2,
+       RT5036_REG_LDOVS3,
+       RT5036_REG_LDOVS4,
+       RT5036_REG_LDOVRCS,
+       RT5036_REG_LDOVRCSEN,
+       RT5036_REG_RESV3,
+       RT5036_REG_BUCKLDOSEN,
+       RT5036_REG_LSWVN2,
+       RT5036_REG_LSWVN1,
+       RT5036_REG_LSWVS2,
+       RT5036_REG_LSWVS1,
+       RT5036_REG_LSWVRC,
+       RT5036_REG_LSWVRCEN,
+       RT5036_REG_BUCKOCPSEL,
+       RT5036_REG_RANGE5END = RT5036_REG_BUCKOCPSEL,
+       RT5036_REG_RTCADJ = 0x90,
+       RT5036_REG_RANGE6START = RT5036_REG_RTCADJ,
+       RT5036_REG_RTCTSEC,
+       RT5036_REG_RTCTMINUTE,
+       RT5036_REG_RTCTHOUR,
+       RT5036_REG_RTCTYEAR,
+       RT5036_REG_RTCTMON,
+       RT5036_REG_RTCTDATEW,
+       RT5036_REG_STBMODE,
+       RT5036_REG_RTCASEC,
+       RT5036_REG_RTCAMINUTE,
+       RT5036_REG_RTCAHOUR,
+       RT5036_REG_RTCAYEAR,
+       RT5036_REG_RTCAMONTH,
+       RT5036_REG_RTCADATE,
+       RT5036_REG_STBCDSEC,
+       RT5036_REG_STBCDMINUTE,
+       RT5036_REG_STBCDHOUR,
+       RT5036_REG_STBCDDATEL,
+       RT5036_REG_STBCDDATEH,
+       RT5036_REG_RESV4,
+       RT5036_REG_STBWACKIRQ,
+       RT5036_REG_STBWACKIRQMASK,
+       RT5036_REG_RANGE6END = RT5036_REG_STBWACKIRQMASK,
+       RT5036_REG_MAX,
+};
+
+enum {
+       RT5036_RAMP_25mV,
+       RT5036_RAMP_50mV,
+       RT5036_RAMP_75mV,
+       RT5036_RAMP_100mV,
+       RT5036_RAMP_MAX = RT5036_RAMP_100mV,
+};
+
+enum {
+       RT5036_SHDHPRESS_4S,
+       RT5036_SHDNPRESS_6S,
+       RT5036_SHDNPRESS_8S,
+       RT5036_SHDNPRESS_10S,
+       RT5036_SHDNPRESS_MAX = RT5036_SHDNPRESS_10S,
+};
+
+enum {
+       RT5036_STB_DISABLE,
+       RT5036_STB_EN1MS,
+       RT5036_STB_EN2MS,
+       RT5036_STB_EN4MS,
+       RT5036_STB_MAX = RT5036_STB_EN4MS,
+};
+
+enum {
+       RT5036_SYSLV_2P8V,
+       RT5036_SYSLV_2P9V,
+       RT5036_SYSLV_3P0V,
+       RT5036_SYSLV_3P1V,
+       RT5036_SYSLV_3P2V,
+       RT5036_SYSLV_3P3V,
+       RT5036_SYSLV_3P4V,
+       RT5036_SYSLV_3P5V,
+       RT5036_SYSLV_MAX = RT5036_SYSLV_3P5V
+};
+
+enum {
+       RT5036_IPREC_150mA,
+       RT5036_IPREC_250mA,
+       RT5036_IPREC_350mA,
+       RT5036_IPREC_450mA,
+       RT5036_IPREC_MAX = RT5036_IPREC_450mA,
+};
+
+enum {
+       RT5036_IEOC_DISABLE,
+       RT5036_IEOC_150mA,
+       RT5036_IEOC_200mA,
+       RT5036_IEOC_250mA,
+       RT5036_IEOC_300mA,
+       RT5036_IEOC_400mA,
+       RT5036_IEOC_500mA,
+       RT5036_IEOC_600mA,
+       RT5036_IEOC_MAX = RT5036_IEOC_600mA,
+};
+
+enum {
+       RT5036_VPREC_2P3V,
+       RT5036_VPREC_2P4V,
+       RT5036_VPREC_2P5V,
+       RT5036_VPREC_2P6V,
+       RT5036_VPREC_2P7V,
+       RT5036_VPREC_2P8V,
+       RT5036_VPREC_2P9V,
+       RT5036_VPREC_3P0V,
+       RT5036_VPREC_3P1V,
+       RT5036_VPREC_3P2V,
+       RT5036_VPREC_3P3V,
+       RT5036_VPREC_3P4V,
+       RT5036_VPREC_3P5V,
+       RT5036_VPREC_3P6V,
+       RT5036_VPREC_3P7V,
+       RT5036_VPREC_3P8V,
+       RT5036_VPREC_MAX = RT5036_VPREC_3P8V,
+};
+
+enum {
+       RT5036_BATLV_2P4V,
+       RT5036_BATLV_2P5V,
+       RT5036_BATLV_2P6V,
+       RT5036_BATLV_2P7V,
+       RT5036_BATLV_2P8V,
+       RT5036_BATLV_2P9V,
+       RT5036_BATLV_3P0V,
+       RT5036_BATLV_3P1V,
+       RT5036_BATLV_MAX = RT5036_BATLV_3P1V,
+};
+
+enum {
+       RT5036_VRECHG_0P1V,
+       RT5036_VRECHG_0P2V,
+       RT5036_VRECHG_0P3V,
+       RT5036_VRECHG_0P3V_1,
+       RT5036_VRECHG_MAX = RT5036_VRECHG_0P3V_1,
+};
+
+typedef void (*rt_irq_handler) (void *info, int eventno);
+
+struct rt5036_regulator_ramp {
+       unsigned char nramp_sel:2;
+       unsigned char sramp_sel:2;
+};
+
+struct rt5036_chg_data {
+       int chg_volt;
+       int otg_volt;
+       int acchg_icc;
+       int usbtachg_icc;
+       int usbchg_icc;
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       int acdet_gpio;
+       int usbdet_gpio;
+#endif                         /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+       u16 te_en:1;
+       u16 iprec:2;
+       u16 ieoc:3;
+       u16 vprec:4;
+       u16 batlv:3;
+       u16 vrechg:2;
+};
+
+struct rt5036_misc_data {
+       u16 shdn_press:2;
+       u16 stb_en:2;
+       u16 lp_enshdn:1;
+       u16 vsysuvlo:3;
+       u16 syslv_enshdn:1;
+};
+
+struct rt5036_irq_data {
+       int irq_gpio;
+};
+
+struct rt5036_chip;
+struct rt5036_platform_data {
+       struct regulator_init_data *regulator[RT5036_MAX_REGULATOR];
+       struct rt5036_chg_data *chg_pdata;
+       struct rt5036_misc_data *misc_pdata;
+       struct rt5036_irq_data *irq_pdata;
+       int (*pre_init)(struct rt5036_chip *rt5036_chip);
+       int (*post_init)(void);
+};
+
+struct rt5036_charger_info {
+       struct i2c_client *i2c;
+       struct device *dev;
+       struct power_supply psy;
+       struct delayed_work dwork;
+       int chg_volt;
+       int otg_volt;
+       int acchg_icc;
+       int usbtachg_icc;
+       int usbchg_icc;
+       int charge_cable;
+#ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN
+       int acdet_gpio;
+       int usbdet_gpio;
+       int acdet_irq;
+       int usbdet_irq;
+       unsigned char usbinit_delay:1;
+#endif                         /* #ifdef CONFIG_RT_SUPPORT_ACUSB_DUALIN */
+       unsigned char online:1;
+       unsigned char batabs:1;
+       unsigned char te_en:1;
+       unsigned char otg_en:1;
+       unsigned char stat2;
+};
+
+struct rt5036_misc_info {
+       struct i2c_client *i2c;
+       struct device *dev;
+#ifdef CONFIG_MISC_RT5036_PWRKEY
+       struct input_dev *pwr_key;
+       unsigned char pwr_key_pressed:1;
+#endif                         /* #ifdef CONFIG_MISC_RT5036_PWRKEY */
+};
+
+struct rt5036_rtc_info {
+       struct i2c_client *i2c;
+       struct device *dev;
+       struct rtc_device *rtc;
+};
+
+struct rt5036_chip {
+       struct i2c_client *i2c;
+       struct rt5036_charger_info *chg_info;
+       struct rt5036_misc_info *misc_info;
+       struct rt5036_rtc_info *rtc_info;
+       struct mutex io_lock;
+       unsigned char suspend:1;
+};
+
+#ifdef CONFIG_CHARGER_RT5036
+void rt5036_charger_irq_handler(struct rt5036_charger_info *ci,
+                               unsigned int event);
+#endif /* #ifdef CONFIG_CHARGER_RT5036 */
+#ifdef CONFIG_MISC_RT5036
+void rt5036_misc_irq_handler(struct rt5036_misc_info *mi, unsigned int event);
+#endif /* #ifdef CONFIG_MISC_RT5036 */
+#ifdef CONFIG_RTC_RT5036
+void rt5036_rtc_irq_handler(struct rt5036_rtc_info *ri, unsigned int event);
+#endif /* #ifdef CONFIG_RTC_RT5036 */
+
+extern int rt5036_reg_block_read(struct i2c_client *i2c, int reg, int byte,
+                                void *dest);
+extern int rt5036_reg_block_write(struct i2c_client *i2c, int reg, int byte,
+                                 void *dest);
+extern int rt5036_reg_read(struct i2c_client *i2c, int reg);
+extern int rt5036_reg_write(struct i2c_client *i2c, int reg,
+                           unsigned char data);
+extern int rt5036_assign_bits(struct i2c_client *i2c, int reg,
+                             unsigned char mask, unsigned char data);
+extern int rt5036_set_bits(struct i2c_client *i2c, int reg, unsigned char mask);
+extern int rt5036_clr_bits(struct i2c_client *i2c, int reg, unsigned char mask);
+
+extern int rt5036_core_init(struct device *dev,
+                           struct rt5036_platform_data *pdata);
+extern int rt5036_core_deinit(struct device *dev);
+
+#ifdef CONFIG_MFD_RT5036_DBGINFO
+#define RTINFO(format, args...) \
+       pr_info("%s:%s() line-%d: " format, RT5036_DEV_NAME, __func__, \
+               __LINE__, ##args)
+#else
+#define RTINFO(format, args...)
+#endif /* CONFIG_MFD_RT5036_DBGINFO */
+#endif /* #ifndef _LINUX_MFD_RT5036_H */
diff --git a/include/linux/power/rt-battery.h b/include/linux/power/rt-battery.h
new file mode 100755 (executable)
index 0000000..ab0c7da
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ *  include/linux/power/rt-battery.h
+ *  Include header file for Richtek Richtek Battery 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_BATTERY_H
+#define __LINUX_RT_BATTERY_H
+
+#define RT_BATT_NAME   "rt-battery"
+
+#endif /* #ifndef __LINUX_RT_BATTERY_H */
old mode 100755 (executable)
new mode 100644 (file)
index 7c5b64a..7533548
@@ -1,6 +1,6 @@
 /*
- *  include/linux/power/rt5025/rt-power.h
- *  Include header file for Richtek RT5025 Core charger Driver
+ *  include/linux/power/rt-power.h
+ *  Include header file for Richtek Richtek Power Driver
  *
  *  Copyright (C) 2014 Richtek Technology Corp.
  *  cy_huang <cy_huang@richtek.com>
diff --git a/include/linux/power/rt5036-charger.h b/include/linux/power/rt5036-charger.h
new file mode 100755 (executable)
index 0000000..6ea60e3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  include/linux/power/rt5036-charger.h
+ *  Include header file for Richtek RT5036 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_POWER_RT5036_CHARGER_H
+#define _LINUX_POWER_RT5036_CHARGER_H
+
+enum {
+       CHGEVENT_STAT2ALT,
+       CHGEVENT_CHBSTLOWVI = 5,
+       CHGEVENT_BSTOLI,
+       CHGEVENT_BSTVIMIDOVP,
+       CHGEVENT_CHTMRFI = 10,
+       CHGEVENT_CHRCHGI,
+       CHGEVENT_CHTERMI,
+       CHGEVENT_CHBATOVI,
+       CHGEVENT_CHRVPI = 15,
+       CHGEVENT_BATABSENSE,
+       CHGEVENT_CHBADADPI,
+       CHGEVENT_VINCHGPLUGOUT,
+       CHGEVENT_VINCHGPLUGIN,
+       CHGEVENT_PPBATLVI,
+       CHGEVENT_IEOCI,
+       CHGEVENT_VINOVPI,
+       CHGEVENT_MAX,
+};
+
+#define RT5036_CHGTEEN_MASK    0x08
+
+#define RT5036_CHGIPREC_MASK   0x18
+#define RT5036_CHGIPREC_SHIFT  3
+
+#define RT5036_CHGIEOC_MASK    0x07
+
+#define RT5036_CHGVPREC_MASK   0x0F
+
+#define RT5036_CHGBATLV_MASK   0x07
+
+#define RT5036_CHGVRECHG_MASK  0x0C
+#define RT5036_CHGVRECHG_SHIFT 2
+
+#define RT5036_CHGSTAT_MASK    0x30
+#define RT5036_CHGSTAT_SHIFT   4
+#define RT5036_CHGDIS_MASK     0x01
+#define RT5036_CHGAICR_MASK    0xE0
+#define RT5036_CHGAICR_SHIFT   5
+#define RT5036_CHGICC_MASK     0xF0
+#define RT5036_CHGICC_SHIFT    4
+#define RT5036_CHGCV_MASK      0xFC
+#define RT5036_CHGCV_SHIFT     2
+#define RT5036_CHGOPAMODE_MASK 0x01
+#define RT5036_CHGOPASTAT_MASK 0x08
+
+#define RT5036_PWRRDY_MASK     0x80
+#define RT5036_TSEVENT_MASK    0x0F
+#define RT5036_TSWC_MASK       0x06
+#define RT5036_TSHC_MASK       0x09
+#define RT5036_CCJEITA_MASK    0x80
+#define RT5036_CHGOTGEN_MASK   0x40
+#define RT5036_BATDEN_MASK     0x80
+#define RT5036_TERST_MASK      0x10
+
+#endif /* #ifndef _LINUX_POWER_RT5036_CHARGER_H */
diff --git a/include/linux/regulator/rt5036-regulator.h b/include/linux/regulator/rt5036-regulator.h
new file mode 100755 (executable)
index 0000000..e6578b7
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ *  include/linux/regulator/rt5036-regulator.h
+ *  Include header file to Richtek RT5036 Regulator 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_RT5036_REGULATOR_H
+#define __LINUX_RT5036_REGULATOR_H
+
+/*BUCK*/
+#define RT5036_DCDCVOUT_SHIFT1 0
+#define RT5036_DCDCVOUT_MASK1  0x7F
+#define RT5036_DCDCVOUT_SHIFT2 0
+#define RT5036_DCDCVOUT_MASK2  0x7F
+#define RT5036_DCDCVOUT_SHIFT3 0
+#define RT5036_DCDCVOUT_MASK3  0x7F
+#define RT5036_DCDCVOUT_SHIFT4 0
+#define RT5036_DCDCVOUT_MASK4  0x7F
+#define RT5036_DCDCEN_MASK1    0x08
+#define RT5036_DCDCEN_MASK2    0x04
+#define RT5036_DCDCEN_MASK3    0x02
+#define RT5036_DCDCEN_MASK4    0x01
+#define RT5036_DCDCMODE_MASK1  0x80
+#define RT5036_DCDCMODE_MASK2  0x40
+#define RT5036_DCDCMODE_MASK3  0x20
+#define RT5036_DCDCMODE_MASK4  0x10
+#define RT5036_DCDCRAMP_MASK1  0xC0
+#define RT5036_DCDCRAMP_SHIFT1 6
+#define RT5036_DCDCRAMP_MASK2  0x30
+#define RT5036_DCDCRAMP_SHIFT2 4
+#define RT5036_DCDCRAMP_MASK3  0x0C
+#define RT5036_DCDCRAMP_SHIFT3 2
+#define RT5036_DCDCRAMP_MASK4  0x03
+#define RT5036_DCDCRAMP_SHIFT4 0
+
+/*LDO*/
+#define RT5036_LDOVOUT_SHIFT1  0
+#define RT5036_LDOVOUT_MASK1   0x7F
+#define RT5036_LDOVOUT_SHIFT2  0
+#define RT5036_LDOVOUT_MASK2   0x7F
+#define RT5036_LDOVOUT_SHIFT3  0
+#define RT5036_LDOVOUT_MASK3   0x7F
+#define RT5036_LDOVOUT_SHIFT4  0
+#define RT5036_LDOVOUT_MASK4   0x7F
+#define RT5036_LDOEN_MASK1     0x80
+#define RT5036_LDOEN_MASK2     0x40
+#define RT5036_LDOEN_MASK3     0x20
+#define RT5036_LDOEN_MASK4     0x10
+#define RT5036_LDOMODE_MASK1   0x80
+#define RT5036_LDOMODE_MASK2   0x40
+#define RT5036_LDOMODE_MASK3   0x20
+#define RT5036_LDOMODE_MASK4   0x10
+#define RT5036_LDORAMP_MASK1   0xC0
+#define RT5036_LDORAMP_SHIFT1  6
+#define RT5036_LDORAMP_MASK2   0x30
+#define RT5036_LDORAMP_SHIFT2  4
+#define RT5036_LDORAMP_MASK3   0x0C
+#define RT5036_LDORAMP_SHIFT3  2
+#define RT5036_LDORAMP_MASK4   0x03
+#define RT5036_LDORAMP_SHIFT4  0
+
+/*LSW*/
+#define RT5036_LSWVOUT_SHIFT1  0
+#define RT5036_LSWVOUT_MASK1   0x7F
+#define RT5036_LSWVOUT_SHIFT2  0
+#define RT5036_LSWVOUT_MASK2   0x7F
+#define RT5036_LSWNEN_MASK2    0x02
+#define RT5036_LSWNEN_MASK1    0x01
+#define RT5036_LSWSEN_MASK2    0x08
+#define RT5036_LSWSEN_MASK1    0x04
+#define RT5036_LSWNMODE_MASK2  0x80
+#define RT5036_LSWNMODE_MASK1  0x40
+#define RT5036_LSWSMODE_MASK2  0x08
+#define RT5036_LSWSMODE_MASK1  0x04
+#define RT5036_LSWNRAMP_MASK2  0xC0
+#define RT5036_LSWNRAMP_SHIFT2 6
+#define RT5036_LSWNRAMP_MASK1  0x30
+#define RT5036_LSWNRAMP_SHIFT1 4
+#define RT5036_LSWSRAMP_MASK2  0x0C
+#define RT5036_LSWSRAMP_SHIFT2 2
+#define RT5036_LSWSRAMP_MASK1  0x03
+#define RT5036_LSWSRAMP_SHIFT1 0
+
+#endif /* __LINUX_RT5036_REGULATOR_H */
diff --git a/include/linux/rtc/rtc-rt5036.h b/include/linux/rtc/rtc-rt5036.h
new file mode 100755 (executable)
index 0000000..2ddb801
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  include/linux/rtc/rt5036-rtc.h
+ *  Include header file for Richtek RT5036 RTC 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_RTC_RT5036_RTC_H
+#define _LINUX_RTC_RT5036_RTC_H
+
+enum {
+       RTCEVENT_CAIRQ,
+       RTCEVENT_CDIRQ,
+       RTCEVENT_MAX,
+};
+
+#define RT5036_RTC_SECMASK     0x3F
+#define RT5036_RTC_MINMASK     0x3F
+#define RT5036_RTC_HOURMASK    0x1F
+#define RT5036_RTC_YEARMASK    0x7F
+#define RT5036_RTC_MONMASK     0x0F
+#define RT5036_RTC_DAYMASK     0x1F
+#define RT5036_RTC_WEEKMASK    0xE0
+#define RT5036_RTC_WEEKSHIFT   5
+
+#define RT5036_STBCTL_MASK     0x01
+#define RT5036_RTCCDEN_MASK    0x02
+#define RT5036_RTCAEN_MASK     0x04
+
+#define RT5036_RTCCDIRQ_MASK   0x02
+#define RT5036_RTCAIRQ_MASK    0x01
+
+#endif /* #ifndef _LINUX_RTC_RT5036_RTC_H */