mfd: rk808: add rk805 support
authorJianhong Chen <chenjh@rock-chips.com>
Fri, 6 Jan 2017 08:52:49 +0000 (16:52 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 18 Jan 2017 11:05:27 +0000 (19:05 +0800)
include sub modules: regulator, rtc, gpio, pwrkey

Change-Id: I19796e2a94764f95588d4b90bca1f3bc616f4f56
Signed-off-by: Jianhong Chen <chenjh@rock-chips.com>
Documentation/devicetree/bindings/mfd/rk805.txt [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-rk8xx.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/rk8xx-pwrkey.c [new file with mode: 0644]
drivers/mfd/rk808.c
drivers/regulator/rk818-regulator.c
drivers/rtc/rtc-rk808.c
include/linux/mfd/rk808.h

diff --git a/Documentation/devicetree/bindings/mfd/rk805.txt b/Documentation/devicetree/bindings/mfd/rk805.txt
new file mode 100644 (file)
index 0000000..33ccefb
--- /dev/null
@@ -0,0 +1,196 @@
+RK805 Power Management Integrated Circuit
+
+Required properties:
+- compatible: "rockchip,rk805"
+- reg: I2C slave address
+- interrupt-parent: The parent interrupt controller.
+- interrupts: the interrupt outputs of the controller.
+
+Optional properties:
+- rockchip,system-power-controller: Telling whether or not this pmic is controlling
+  the system power.
+- gpio-controller: Specifies that the node is a gpio controller when you attemp to
+  use the OUT1 or OUT2 pin of RK805 by GPIO general interface.
+- #gpio-cells: Should be two. The first cell is the GPIO number and the second cell
+  is used to specify the GPIO polarity.
+- wakeup-source: Flag to indicate this device can wake system (suspend/resume)
+- vcc1-supply:  The input supply for RK805_DCDC_REG1
+- vcc2-supply:  The input supply for RK805_DCDC_REG2
+- vcc3-supply:  The input supply for RK805_DCDC_REG3
+- vcc4-supply:  The input supply for RK805_DCDC_REG4
+- vcc5-supply:  The input supply for RK805_LDO_REG1, RK805_LDO_REG2
+- vcc6-supply:  The input supply for RK805_LDO_REG3
+
+Regulators: All the regulators of RK805 to be instantiated shall be
+listed in a child node named 'regulators'. Each regulator is represented
+by a child node of the 'regulators' node.
+
+       regulator-name {
+               /* standard regulator bindings here */
+       };
+
+Following regulators of the RK805 PMIC block are supported. Note that
+the 'n' in regulator name, as in RK805_DCDC_REGn or RK805_LDOn, represents the DCDC
+or LDO number as described in RK805 datasheet.
+
+       - RK805_DCDC_REGn
+               - valid values for n are 1 to 4.
+       - RK805_LDO_REGn
+               - valid values for n are 1 to 3.
+
+Standard regulator bindings are used inside regulator subnodes. Check
+  Documentation/devicetree/bindings/regulator/regulator.txt
+for more details
+
+Gpio, Rtc, Pwrkey: the node are represented like below. When you attemp to enable
+  the module, setting the "status" to be "okay", otherwise "disabled".
+
+               rtc {
+                       status = "okay";
+               };
+
+               pwrkey {
+                       status = "okay";
+               };
+
+               gpio {
+                       status = "okay";
+               };
+
+Example:
+       rk805: pmic@1c {
+               compatible = "rockchip,rk805";
+               status = "okay";
+               reg = <0x18>;
+               interrupt-parent = <&gpio2>;
+               interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pmic_int_l>;
+               rockchip,system-power-controller;
+               wakeup-source;
+               gpio-controller;
+               #gpio-cells = <2>;
+
+               vcc1-supply = <&vcc_sys>;
+               vcc2-supply = <&vcc_sys>;
+               vcc3-supply = <&vcc_sys>;
+               vcc4-supply = <&vcc_sys>;
+               vcc5-supply = <&vcc_sys>;
+               vcc6-supply = <&vcc_sys>;
+
+               rtc {
+                       status = "okay";
+               };
+
+               pwrkey {
+                       status = "okay";
+               };
+
+               gpio {
+                       status = "okay";
+               };
+
+               regulators {
+                       compatible = "rk805-regulator";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       vdd_logic: RK805_DCDC1@0 {
+                               regulator-compatible = "RK805_DCDC1";
+                               regulator-name = "vdd_logic";
+                               regulator-min-microvolt = <712500>;
+                               regulator-max-microvolt = <1450000>;
+                               regulator-initial-mode = <0x1>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-mode = <0x2>;
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1000000>;
+                               };
+                       };
+
+                       vdd_arm: RK805_DCDC2@1 {
+                               regulator-compatible = "RK805_DCDC2";
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = <712500>;
+                               regulator-max-microvolt = <1450000>;
+                               regulator-initial-mode = <0x1>;
+                               regulator-ramp-delay = <12500>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-mode = <0x2>;
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <950000>;
+                               };
+                       };
+
+                       vcc_ddr: RK805_DCDC3@2 {
+                               regulator-compatible = "RK805_DCDC3";
+                               regulator-name = "vcc_ddr";
+                               regulator-initial-mode = <0x1>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-mode = <0x2>;
+                                       regulator-on-in-suspend;
+                               };
+                       };
+
+                       vcc_io: RK805_DCDC4@3 {
+                               regulator-compatible = "RK805_DCDC4";
+                               regulator-name = "vcc_io";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                               regulator-initial-mode = <0x1>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-mode = <0x2>;
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <3300000>;
+                               };
+                       };
+
+                       vdd_18: RK805_LDO1@4 {
+                               regulator-compatible = "RK805_LDO1";
+                               regulator-name = "vdd_18";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vcc_18emmc: RK805_LDO2@5 {
+                               regulator-compatible = "RK805_LDO2";
+                               regulator-name = "vcc_18emmc";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <1800000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1800000>;
+                               };
+                       };
+
+                       vdd_10: RK805_LDO3@6 {
+                               regulator-compatible = "RK805_LDO3";
+                               regulator-name = "vdd_10";
+                               regulator-min-microvolt = <1000000>;
+                               regulator-max-microvolt = <1000000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-state-mem {
+                                       regulator-on-in-suspend;
+                                       regulator-suspend-microvolt = <1000000>;
+                               };
+                       };
+               };
+       };
\ No newline at end of file
index 469dc378adeb9476585c784676ecf5523877e59e..e7d1cc2591e8f4eae3fecdf9b6b1b85b87835ac2 100644 (file)
@@ -815,6 +815,12 @@ config GPIO_RC5T583
          This driver provides the support for driving/reading the gpio pins
          of RC5T583 device through standard gpio library.
 
+config GPIO_RK8XX
+       tristate "Rockchip RK8XX gpio driver"
+       depends on MFD_RK808
+       help
+         Select this option to enable the gpio module of Rockchip RK8XX PMIC.
+
 config GPIO_STMPE
        bool "STMPE GPIOs"
        depends on MFD_STMPE
index 986dbd838ceaceb03c42ffc15a704bf5f180b09d..1a29d53e92d1d6770fd62a4f8b0134f81e9ff878 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_GPIO_PXA)                += gpio-pxa.o
 obj-$(CONFIG_GPIO_RC5T583)     += gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)     += gpio-rdc321x.o
 obj-$(CONFIG_GPIO_RCAR)                += gpio-rcar.o
+obj-$(CONFIG_GPIO_RK8XX)       += gpio-rk8xx.o
 obj-$(CONFIG_GPIO_SAMSUNG)     += gpio-samsung.o
 obj-$(CONFIG_ARCH_SA1100)      += gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)         += gpio-sch.o
diff --git a/drivers/gpio/gpio-rk8xx.c b/drivers/gpio/gpio-rk8xx.c
new file mode 100644 (file)
index 0000000..e7707e2
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * drivers/gpio/gpio-rk8xx.c
+ * Driver for Rockchip RK8xx PMIC GPIO
+ *
+ * Copyright (C) 2017, Rockchip Technology Co., Ltd.
+ * Author: Chen Jianhong <chenjh@rock-chips.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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mfd/rk808.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define RK805_GPIO_REG         RK805_OUT_REG
+#define RK805_OUT0_VALMASK     BIT(0)
+#define RK805_OUT1_VALMASK     BIT(1)
+
+struct rk8xx_gpio_reg {
+       u8 reg;
+       u8 dir_msk;
+       u8 val_msk;
+       u8 fun_msk;
+};
+
+struct rk8xx_gpio_info {
+       struct rk808 *rk8xx;
+       struct gpio_chip gpio_chip;
+       struct rk8xx_gpio_reg *gpio_reg;
+       int gpio_nr;
+};
+
+static int rk8xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       int err;
+       struct rk8xx_gpio_info *gi = dev_get_drvdata(chip->dev);
+
+       /* iomux */
+       if (gi->gpio_reg[offset].fun_msk) {
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].fun_msk,
+                                        gi->gpio_reg[offset].fun_msk);
+               if (err) {
+                       dev_err(chip->dev, "set gpio%d func fail: %d\n",
+                               offset, err);
+                       return err;
+               }
+       }
+
+       /* direction */
+       if (gi->gpio_reg[offset].dir_msk) {
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].dir_msk,
+                                        0);
+               if (err) {
+                       dev_err(chip->dev, "set gpio%d input fail: %d\n",
+                               offset, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int rk8xx_gpio_direction_output(struct gpio_chip *chip,
+                                      unsigned offset, int value)
+{
+       int err;
+       struct rk8xx_gpio_info *gi = dev_get_drvdata(chip->dev);
+
+       /* iomux */
+       if (gi->gpio_reg[offset].fun_msk) {
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].fun_msk,
+                                        gi->gpio_reg[offset].fun_msk);
+               if (err) {
+                       dev_err(chip->dev, "set gpio%d func fail: %d\n",
+                               offset, err);
+                       return err;
+               }
+       }
+
+       /* direction */
+       if (gi->gpio_reg[offset].dir_msk) {
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].dir_msk,
+                                        gi->gpio_reg[offset].dir_msk);
+               if (err) {
+                       dev_err(chip->dev,
+                               "set gpio%d output fail: %d\n", offset, err);
+                       return err;
+               }
+       }
+
+       if (value)
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].val_msk,
+                                        gi->gpio_reg[offset].val_msk);
+       else
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].val_msk,
+                                        0);
+       if (err) {
+               dev_err(chip->dev, "set gpio%d value fail: %d\n", offset, err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int rk8xx_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+       int err;
+       unsigned int val;
+       struct rk8xx_gpio_info *gi = dev_get_drvdata(chip->dev);
+
+       err = regmap_read(gi->rk8xx->regmap, gi->gpio_reg[offset].reg, &val);
+       if (err) {
+               dev_err(chip->dev, "get gpio%d value fail: %d\n", offset, err);
+               return err;
+       }
+
+       return (val & gi->gpio_reg[offset].val_msk) ? 1 : 0;
+}
+
+static void rk8xx_gpio_set_value(struct gpio_chip *chip,
+                                unsigned offset, int value)
+{
+       int err;
+       struct rk8xx_gpio_info *gi = dev_get_drvdata(chip->dev);
+
+       if (value)
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].val_msk,
+                                        gi->gpio_reg[offset].val_msk);
+       else
+               err = regmap_update_bits(gi->rk8xx->regmap,
+                                        gi->gpio_reg[offset].reg,
+                                        gi->gpio_reg[offset].val_msk,
+                                        0);
+       if (err)
+               dev_err(chip->dev, "set gpio%d value fail: %d\n", offset, err);
+}
+
+/* rk805: two gpio: output only */
+static struct rk8xx_gpio_reg rk805_gpio_reg[] = {
+       {
+               .reg = RK805_GPIO_REG,
+               .val_msk = RK805_OUT0_VALMASK,
+       },
+       {
+               .reg = RK805_GPIO_REG,
+               .val_msk = RK805_OUT1_VALMASK,
+       },
+};
+
+static int rk8xx_gpio_probe(struct platform_device *pdev)
+{
+       struct rk808 *rk8xx = dev_get_drvdata(pdev->dev.parent);
+       struct rk8xx_gpio_info *gi;
+       struct device_node *np;
+       int ret;
+
+       np = of_find_node_by_name(pdev->dev.parent->of_node, "gpio");
+       if (np) {
+               if (!of_device_is_available(np)) {
+                       dev_info(&pdev->dev, "device is disabled\n");
+                       return -EINVAL;
+               }
+       }
+
+       gi = devm_kzalloc(&pdev->dev, sizeof(*gi), GFP_KERNEL);
+       if (!gi)
+               return -ENOMEM;
+
+       switch (rk8xx->variant) {
+       case RK805_ID:
+               gi->gpio_reg = rk805_gpio_reg;
+               gi->gpio_nr = ARRAY_SIZE(rk805_gpio_reg);
+               break;
+       default:
+               dev_err(&pdev->dev, "unsupported RK8XX ID %lu\n",
+                       rk8xx->variant);
+               return -EINVAL;
+       }
+
+       gi->rk8xx = rk8xx;
+       gi->gpio_chip.base = -1;
+       gi->gpio_chip.can_sleep = true;
+       gi->gpio_chip.dev = &pdev->dev;
+       gi->gpio_chip.ngpio = gi->gpio_nr;
+       gi->gpio_chip.label = pdev->name;
+       gi->gpio_chip.get = rk8xx_gpio_get_value;
+       gi->gpio_chip.set = rk8xx_gpio_set_value;
+       gi->gpio_chip.direction_input = rk8xx_gpio_direction_input;
+       gi->gpio_chip.direction_output = rk8xx_gpio_direction_output;
+       gi->gpio_chip.owner = THIS_MODULE;
+#ifdef CONFIG_OF_GPIO
+       gi->gpio_chip.of_node = rk8xx->i2c->dev.of_node;
+#endif
+       platform_set_drvdata(pdev, gi);
+
+       ret = gpiochip_add(&gi->gpio_chip);
+       if (ret)
+               dev_err(&pdev->dev, "register rk8xx gpiochip fail: %d\n", ret);
+
+       return ret;
+}
+
+static int rk8xx_gpio_remove(struct platform_device *pdev)
+{
+       struct rk8xx_gpio_info *gi = platform_get_drvdata(pdev);
+
+       gpiochip_remove(&gi->gpio_chip);
+
+       return 0;
+}
+
+static struct platform_driver rk8xx_gpio_driver = {
+       .probe = rk8xx_gpio_probe,
+       .remove = rk8xx_gpio_remove,
+       .driver = {
+               .name = "rk8xx-gpio",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int rk8xx_gpio_init(void)
+{
+       return platform_driver_register(&rk8xx_gpio_driver);
+}
+subsys_initcall(rk8xx_gpio_init);
+
+static void rk8xx_gpio_exit(void)
+{
+       platform_driver_unregister(&rk8xx_gpio_driver);
+}
+module_exit(rk8xx_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("RK8xx GPIO driver");
+MODULE_AUTHOR("Chen Jianhong <chenjh@rock-chips.com>");
index 25ac47b9a1806e2d04066b57cfb806b4e0d5c3b9..0fd4e48f64505edbf7d78a57753ce74b5d9e3c14 100644 (file)
@@ -449,6 +449,12 @@ config INPUT_RETU_PWRBUTTON
          To compile this driver as a module, choose M here. The module will
          be called retu-pwrbutton.
 
+config INPUT_RK8XX_PWRKEY
+       tristate "Rockchip RK8XX pwrkey driver"
+       depends on MFD_RK808
+       help
+         Select this option to enable the pwrkey module of Rockchip RK8XX PMIC.
+
 config INPUT_TPS65218_PWRBUTTON
        tristate "TPS65218 Power button driver"
        depends on MFD_TPS65218
index 66c3cc9f181cb390089af9f13f825ad2ded1f1ac..02cc87f3ca4c3563634159b5cee26939c93b6806 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_INPUT_PWM_BEEPER)                += pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)       += rb532_button.o
 obj-$(CONFIG_INPUT_REGULATOR_HAPTIC)   += regulator-haptic.o
 obj-$(CONFIG_INPUT_RETU_PWRBUTTON)     += retu-pwrbutton.o
+obj-$(CONFIG_INPUT_RK8XX_PWRKEY)       += rk8xx-pwrkey.o
 obj-$(CONFIG_INPUT_AXP20X_PEK)         += axp20x-pek.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)        += rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)           += sgi_btns.o
diff --git a/drivers/input/misc/rk8xx-pwrkey.c b/drivers/input/misc/rk8xx-pwrkey.c
new file mode 100644 (file)
index 0000000..6901c40
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * driver/input/misc/rk8xx-pwrkey.c
+ * Power Key driver for RK8xx PMIC Power Button.
+ *
+ * Copyright (C) 2017, Rockchip Technology Co., Ltd.
+ * Author: Chen Jianhong <chenjh@rock-chips.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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rk808.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct rk8xx_pwrkey {
+       struct rk808 *rk8xx;
+       struct input_dev *input_dev;
+       int report_key;
+};
+
+static irqreturn_t rk8xx_pwrkey_irq_falling(int irq, void *data)
+{
+       struct rk8xx_pwrkey *pwr = data;
+
+       input_report_key(pwr->input_dev, pwr->report_key, 1);
+       input_sync(pwr->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rk8xx_pwrkey_irq_rising(int irq, void *data)
+{
+       struct rk8xx_pwrkey *pwr = data;
+
+       input_report_key(pwr->input_dev, pwr->report_key, 0);
+       input_sync(pwr->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int rk8xx_pwrkey_probe(struct platform_device *pdev)
+{
+       struct rk808 *rk8xx = dev_get_drvdata(pdev->dev.parent);
+       struct rk8xx_pwrkey *pwrkey;
+       int fall_irq, rise_irq, err;
+       struct device_node *np;
+
+       np = of_find_node_by_name(pdev->dev.parent->of_node, "pwrkey");
+       if (np) {
+               if (!of_device_is_available(np)) {
+                       dev_info(&pdev->dev, "device is disabled\n");
+                       return -EINVAL;
+               }
+       }
+
+       pwrkey = devm_kzalloc(&pdev->dev,
+                             sizeof(struct rk8xx_pwrkey), GFP_KERNEL);
+       if (!pwrkey)
+               return -ENOMEM;
+
+       pwrkey->input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!pwrkey->input_dev) {
+               dev_err(&pdev->dev, "Can't allocate power button\n");
+               return -ENOMEM;
+       }
+
+       /* init struct input_dev */
+       pwrkey->rk8xx = rk8xx;
+       pwrkey->report_key = KEY_POWER;
+       pwrkey->input_dev->name = "rk8xx_pwrkey";
+       pwrkey->input_dev->phys = "rk8xx_pwrkey/input0";
+       pwrkey->input_dev->dev.parent = pdev->dev.parent;
+       pwrkey->input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       pwrkey->input_dev->keybit[BIT_WORD(pwrkey->report_key)] =
+                                       BIT_MASK(pwrkey->report_key);
+       platform_set_drvdata(pdev, pwrkey);
+
+       /* requeset rise and fall irqs */
+       rise_irq = platform_get_irq(pdev, 0);
+       if (rise_irq < 0) {
+               dev_err(&pdev->dev, "no IRQ for rise: %d\n", rise_irq);
+               return rise_irq;
+       }
+
+       fall_irq = platform_get_irq(pdev, 1);
+       if (fall_irq < 0) {
+               dev_err(&pdev->dev, "no IRQ for fall: %d\n", fall_irq);
+               return fall_irq;
+       }
+
+       err = devm_request_threaded_irq(&pdev->dev, fall_irq,
+                                       NULL, rk8xx_pwrkey_irq_falling,
+                                       IRQF_TRIGGER_FALLING,
+                                       "rk8xx_pwrkey_fall", pwrkey);
+       if (err) {
+               dev_err(&pdev->dev, "Can't get fall irq for pwrkey: %d\n", err);
+               return err;
+       }
+       err = devm_request_threaded_irq(&pdev->dev, rise_irq,
+                                       NULL, rk8xx_pwrkey_irq_rising,
+                                       IRQF_TRIGGER_RISING,
+                                       "rk8xx_pwrkey_rise", pwrkey);
+       if (err) {
+               dev_err(&pdev->dev, "Can't get rise irq for pwrkey: %d\n", err);
+               return err;
+       }
+
+       /* register input device */
+       err = input_register_device(pwrkey->input_dev);
+       if (err) {
+               dev_err(&pdev->dev, "Can't register power button: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static struct platform_driver rk8xx_pwrkey_driver = {
+       .probe = rk8xx_pwrkey_probe,
+       .driver         = {
+               .name   = "rk8xx-pwrkey",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(rk8xx_pwrkey_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("RK8xx Power Button");
+MODULE_AUTHOR("Chen Jianhong <chenjh@rock-chips.com>");
index 0db26cd7876e2debf966c0a26395873879a3c5ea..9d9327828ca571be0864ccc14caea23d77a268b8 100644 (file)
 
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/mfd/rk808.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
-#include <linux/regmap.h>
 #include <linux/of_device.h>
+#include <linux/regmap.h>
 
 struct rk808_reg_data {
        int addr;
@@ -30,17 +31,6 @@ struct rk808_reg_data {
        int value;
 };
 
-struct rk8xx_power_data {
-       char *name;
-       const struct rk808_reg_data *rk8xx_pre_init_reg;
-       int reg_num;
-       const struct regmap_config *rk8xx_regmap_config;
-       const struct mfd_cell *rk8xx_cell;
-       int cell_num;
-       struct regmap_irq_chip *rk8xx_irq_chip;
-       int (*pm_shutdown)(struct regmap *regmap);
-};
-
 static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
 {
        /*
@@ -89,6 +79,25 @@ static int rk818_shutdown(struct regmap *regmap)
        return ret;
 }
 
+static int rk805_shutdown_prepare(struct regmap *regmap)
+{
+       int ret;
+
+       /* close rtc int when power off */
+       regmap_update_bits(regmap,
+                          RK808_INT_STS_MSK_REG1,
+                          (0x3 << 5), (0x3 << 5));
+       regmap_update_bits(regmap,
+                          RK808_RTC_INT_REG,
+                          (0x3 << 2), (0x0 << 2));
+
+       /* pmic sleep shutdown function */
+       ret = regmap_update_bits(regmap,
+                                RK805_GPIO_IO_POL_REG,
+                                SLP_SD_MSK, SHUTDOWN_FUN);
+       return ret;
+}
+
 static bool rk818_is_volatile_reg(struct device *dev, unsigned int reg)
 {
        /*
@@ -129,6 +138,14 @@ static const struct regmap_config rk808_regmap_config = {
        .volatile_reg = rk808_is_volatile_reg,
 };
 
+static const struct regmap_config rk805_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = RK805_OFF_SOURCE_REG,
+       .cache_type = REGCACHE_RBTREE,
+       .volatile_reg = rk808_is_volatile_reg,
+};
+
 static struct resource rtc_resources[] = {
        {
                .start  = RK808_IRQ_RTC_ALARM,
@@ -137,6 +154,19 @@ static struct resource rtc_resources[] = {
        }
 };
 
+static struct resource pwrkey_resources[] = {
+       {
+               .start  = RK805_IRQ_PWRON_RISE,
+               .end    = RK805_IRQ_PWRON_RISE,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = RK805_IRQ_PWRON_FALL,
+               .end    = RK805_IRQ_PWRON_FALL,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static const struct mfd_cell rk808s[] = {
        { .name = "rk808-clkout", },
        { .name = "rk808-regulator", },
@@ -147,7 +177,7 @@ static const struct mfd_cell rk808s[] = {
        },
 };
 
-static const struct rk808_reg_data pre_init_reg[] = {
+static const struct rk808_reg_data rk808_pre_init_reg[] = {
        { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_150MA },
        { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_200MA },
        { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
@@ -322,31 +352,96 @@ static struct regmap_irq_chip rk818_irq_chip = {
        .init_ack_masked = true,
 };
 
-static struct rk8xx_power_data rk808_power_data = {
-       .name = "rk808",
-       .rk8xx_pre_init_reg = pre_init_reg,
-       .reg_num = ARRAY_SIZE(pre_init_reg),
-       .rk8xx_regmap_config = &rk808_regmap_config,
-       .rk8xx_cell = rk808s,
-       .cell_num = ARRAY_SIZE(rk808s),
-       .rk8xx_irq_chip = &rk808_irq_chip,
-       .pm_shutdown = rk808_shutdown,
+static const struct regmap_irq rk805_irqs[] = {
+       [RK805_IRQ_PWRON_RISE] = {
+               .mask = RK805_IRQ_PWRON_RISE_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_VB_LOW] = {
+               .mask = RK805_IRQ_VB_LOW_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_PWRON] = {
+               .mask = RK805_IRQ_PWRON_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_PWRON_LP] = {
+               .mask = RK805_IRQ_PWRON_LP_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_HOTDIE] = {
+               .mask = RK805_IRQ_HOTDIE_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_RTC_ALARM] = {
+               .mask = RK805_IRQ_RTC_ALARM_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_RTC_PERIOD] = {
+               .mask = RK805_IRQ_RTC_PERIOD_MSK,
+               .reg_offset = 0,
+       },
+       [RK805_IRQ_PWRON_FALL] = {
+               .mask = RK805_IRQ_PWRON_FALL_MSK,
+               .reg_offset = 0,
+       },
 };
 
-static struct rk8xx_power_data rk818_power_data = {
-       .name = "rk818",
-       .rk8xx_pre_init_reg = rk818_pre_init_reg,
-       .reg_num = ARRAY_SIZE(rk818_pre_init_reg),
-       .rk8xx_regmap_config = &rk818_regmap_config,
-       .rk8xx_cell = rk818s,
-       .cell_num = ARRAY_SIZE(rk818s),
-       .rk8xx_irq_chip = &rk818_irq_chip,
-       .pm_shutdown = rk818_shutdown,
+static struct regmap_irq_chip rk805_irq_chip = {
+       .name = "rk805",
+       .irqs = rk805_irqs,
+       .num_irqs = ARRAY_SIZE(rk805_irqs),
+       .num_regs = 1,
+       .status_base = RK805_INT_STS_REG,
+       .mask_base = RK805_INT_STS_MSK_REG,
+       .ack_base = RK805_INT_STS_REG,
+       .init_ack_masked = true,
+};
+
+static const struct mfd_cell rk805s[] = {
+       { .name = "rk818-regulator", },
+       { .name = "rk8xx-gpio", },
+       {
+               .name = "rk8xx-pwrkey",
+               .num_resources = ARRAY_SIZE(pwrkey_resources),
+               .resources = &pwrkey_resources[0],
+       },
+       {
+               .name = "rk808-rtc",
+               .num_resources = ARRAY_SIZE(rtc_resources),
+               .resources = &rtc_resources[0],
+       },
+};
+
+static const struct rk808_reg_data rk805_pre_init_reg[] = {
+       {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
+       {RK805_GPIO_IO_POL_REG, SLP_SD_MSK, SLEEP_FUN},
+       {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
 };
 
 static int (*pm_shutdown)(struct regmap *regmap);
+static int (*pm_shutdown_prepare)(struct regmap *regmap);
 static struct i2c_client *rk808_i2c_client;
 
+static void rk808_device_shutdown_prepare(void)
+{
+       int ret;
+       struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
+
+       if (!rk808) {
+               dev_warn(&rk808_i2c_client->dev,
+                        "have no rk808, so do nothing here\n");
+               return;
+       }
+
+       if (pm_shutdown_prepare) {
+               ret = pm_shutdown_prepare(rk808->regmap);
+               if (ret)
+                       dev_err(&rk808_i2c_client->dev,
+                               "power off prepare error!\n");
+       }
+}
+
 static void rk808_device_shutdown(void)
 {
        int ret;
@@ -365,42 +460,37 @@ static void rk808_device_shutdown(void)
        regmap_update_bits(rk808->regmap,
                           RK808_RTC_INT_REG,
                           (0x3 << 2), (0x0 << 2));
-
-       ret = pm_shutdown(rk808->regmap);
-       if (ret)
-               dev_err(&rk808_i2c_client->dev, "power off error!\n");
+       if (pm_shutdown) {
+               ret = pm_shutdown(rk808->regmap);
+               if (ret)
+                       dev_err(&rk808_i2c_client->dev, "power off error!\n");
+       }
 }
 
 static const struct of_device_id rk808_of_match[] = {
-       {
-               .compatible = "rockchip,rk808",
-               .data = &rk808_power_data,
-       },
-       {
-               .compatible = "rockchip,rk818",
-               .data = &rk818_power_data,
-       },
+       { .compatible = "rockchip,rk805" },
+       { .compatible = "rockchip,rk808" },
+       { .compatible = "rockchip,rk818" },
        { },
 };
+
 MODULE_DEVICE_TABLE(of, rk808_of_match);
 
 static int rk808_probe(struct i2c_client *client,
                       const struct i2c_device_id *id)
 {
-       const struct of_device_id *of_id =
-                       of_match_device(rk808_of_match, &client->dev);
-       const struct rk8xx_power_data *pdata = of_id->data;
        struct device_node *np = client->dev.of_node;
        struct rk808 *rk808;
-       int pm_off = 0;
-       int ret;
-       int i;
-       int on_source, off_source;
-
-       if (!of_id) {
-               dev_err(&client->dev, "Failed to find matching dt id\n");
-               return -ENODEV;
-       }
+       int (*pm_shutdown_fn)(struct regmap *regmap) = NULL;
+       int (*pm_shutdown_prepare_fn)(struct regmap *regmap) = NULL;
+       const struct rk808_reg_data *pre_init_reg;
+       const struct regmap_config *regmap_config;
+       const struct regmap_irq_chip *irq_chip;
+       const struct mfd_cell *cell;
+       u8 on_source = 0, off_source = 0;
+       int msb, lsb, reg_num, cell_num;
+       int ret, i, pm_off = 0;
+       unsigned int on, off;
 
        if (!client->irq) {
                dev_err(&client->dev, "No interrupt support, no core IRQ\n");
@@ -411,46 +501,103 @@ static int rk808_probe(struct i2c_client *client,
        if (!rk808)
                return -ENOMEM;
 
-       rk808->regmap = devm_regmap_init_i2c(client,
-                                            pdata->rk8xx_regmap_config);
+       /* read Chip variant */
+       msb = i2c_smbus_read_byte_data(client, RK808_ID_MSB);
+       if (msb < 0) {
+               dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
+                       RK808_ID_MSB);
+               return msb;
+       }
+
+       lsb = i2c_smbus_read_byte_data(client, RK808_ID_LSB);
+       if (lsb < 0) {
+               dev_err(&client->dev, "failed to read the chip id at 0x%x\n",
+                       RK808_ID_LSB);
+               return lsb;
+       }
+
+       rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+       dev_info(&client->dev, "Pmic Chip id: 0x%lx\n", rk808->variant);
+
+       /* set Chip platform init data*/
+       switch (rk808->variant) {
+       case RK818_ID:
+               cell = rk818s;
+               cell_num = ARRAY_SIZE(rk818s);
+               pre_init_reg = rk818_pre_init_reg;
+               reg_num = ARRAY_SIZE(rk818_pre_init_reg);
+               regmap_config = &rk818_regmap_config;
+               irq_chip = &rk818_irq_chip;
+               pm_shutdown_fn = rk818_shutdown;
+               on_source = RK818_ON_SOURCE_REG;
+               off_source = RK818_OFF_SOURCE_REG;
+               break;
+       case RK808_ID:
+               cell = rk808s;
+               cell_num = ARRAY_SIZE(rk808s);
+               pre_init_reg = rk808_pre_init_reg;
+               reg_num = ARRAY_SIZE(rk808_pre_init_reg);
+               regmap_config = &rk808_regmap_config;
+               irq_chip = &rk808_irq_chip;
+               pm_shutdown_fn = rk808_shutdown;
+               break;
+       case RK805_ID:
+               cell = rk805s;
+               cell_num = ARRAY_SIZE(rk805s);
+               pre_init_reg = rk805_pre_init_reg;
+               reg_num = ARRAY_SIZE(rk805_pre_init_reg);
+               regmap_config = &rk805_regmap_config;
+               irq_chip = &rk805_irq_chip;
+               pm_shutdown_prepare_fn = rk805_shutdown_prepare;
+               on_source = RK805_ON_SOURCE_REG;
+               off_source = RK805_OFF_SOURCE_REG;
+               break;
+       default:
+               dev_err(&client->dev, "unsupported RK8XX ID 0x%lx\n",
+                       rk808->variant);
+               return -EINVAL;
+       }
+
+       rk808->regmap = devm_regmap_init_i2c(client, regmap_config);
        if (IS_ERR(rk808->regmap)) {
                dev_err(&client->dev, "regmap initialization failed\n");
                return PTR_ERR(rk808->regmap);
        }
 
-       pm_shutdown = pdata->pm_shutdown;
-       if (!pm_shutdown) {
-               dev_err(&client->dev, "shutdown initialization failed\n");
-               return -EINVAL;
-       }
+       /* on & off source */
+       if (on_source && off_source) {
+               ret = regmap_read(rk808->regmap, on_source, &on);
+               if (ret) {
+                       dev_err(&client->dev, "read 0x%x failed\n", on_source);
+                       return ret;
+               }
 
-       if (strcmp(pdata->name, "rk818") == 0) {
-               ret = regmap_read(rk808->regmap, RK818_ON_SOURCE_REG, &on_source);
-               if (ret)
-                       dev_err(&client->dev, "read reg:0x%x failed\n", RK818_ON_SOURCE_REG);
-               ret = regmap_read(rk808->regmap, RK818_OFF_SOURCE_REG, &off_source);
-               if (ret)
-                       dev_err(&client->dev, "read reg:0x%x failed\n", RK818_OFF_SOURCE_REG);
-               dev_info(&client->dev, "ON_SOURCE:0x%02x OFF_SOURCE:0x%02x\n",
-                                       on_source, off_source);
+               ret = regmap_read(rk808->regmap, off_source, &off);
+               if (ret) {
+                       dev_err(&client->dev, "read 0x%x failed\n", off_source);
+                       return ret;
+               }
+
+               dev_info(&client->dev, "source: on=0x%02x, off=0x%02x\n",
+                        on, off);
        }
 
-       for (i = 0; i < pdata->reg_num; i++) {
+       for (i = 0; i < reg_num; i++) {
                ret = regmap_update_bits(rk808->regmap,
-                                        pdata->rk8xx_pre_init_reg[i].addr,
-                                        pdata->rk8xx_pre_init_reg[i].mask,
-                                        pdata->rk8xx_pre_init_reg[i].value);
+                                        pre_init_reg[i].addr,
+                                        pre_init_reg[i].mask,
+                                        pre_init_reg[i].value);
                if (ret) {
                        dev_err(&client->dev,
                                "0x%x write err\n",
-                               pdata->rk8xx_pre_init_reg[i].addr);
+                               pre_init_reg[i].addr);
                        return ret;
                }
        }
 
        ret = regmap_add_irq_chip(rk808->regmap, client->irq,
                                  IRQF_ONESHOT, -1,
-                                 pdata->rk8xx_irq_chip, &rk808->irq_data);
+                                 irq_chip, &rk808->irq_data);
        if (ret) {
                dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
                return ret;
@@ -460,7 +607,7 @@ static int rk808_probe(struct i2c_client *client,
        i2c_set_clientdata(client, rk808);
 
        ret = mfd_add_devices(&client->dev, -1,
-                             pdata->rk8xx_cell, pdata->cell_num,
+                             cell, cell_num,
                              NULL, 0, regmap_irq_get_domain(rk808->irq_data));
        if (ret) {
                dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
@@ -471,7 +618,14 @@ static int rk808_probe(struct i2c_client *client,
                                "rockchip,system-power-controller");
        if (pm_off) {
                rk808_i2c_client = client;
-               pm_power_off = rk808_device_shutdown;
+               if (pm_shutdown_prepare_fn) {
+                       pm_shutdown_prepare = pm_shutdown_prepare_fn;
+                       pm_power_off_prepare = rk808_device_shutdown_prepare;
+               }
+               if (pm_shutdown_fn) {
+                       pm_shutdown = pm_shutdown_fn;
+                       pm_power_off = rk808_device_shutdown;
+               }
        }
 
        return 0;
@@ -487,12 +641,16 @@ static int rk808_remove(struct i2c_client *client)
 
        regmap_del_irq_chip(client->irq, rk808->irq_data);
        mfd_remove_devices(&client->dev);
-       pm_power_off = NULL;
+       if (pm_power_off == rk808_device_shutdown)
+               pm_power_off = NULL;
+       if (pm_power_off_prepare == rk808_device_shutdown_prepare)
+               pm_power_off_prepare = NULL;
 
        return 0;
 }
 
 static const struct i2c_device_id rk808_ids[] = {
+       { "rk805" },
        { "rk808" },
        { "rk818" },
        { },
@@ -514,4 +672,5 @@ module_i2c_driver(rk808_i2c_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
 MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
+MODULE_AUTHOR("Chen jianhong <chenjh@rock-chips.com>");
 MODULE_DESCRIPTION("RK808 PMIC driver");
index 6fe92365498aed931fc13ddcb5ee8964ccce0881..e7ffb2e643bbb838cb2f316b0a3f45ebfd3619f0 100644 (file)
 #define RK818_RAMP_RATE_6MV_PER_US     (2 << RK818_RAMP_RATE_OFFSET)
 #define RK818_RAMP_RATE_10MV_PER_US    (3 << RK818_RAMP_RATE_OFFSET)
 
+#define RK805_RAMP_RATE_OFFSET         3
+#define RK805_RAMP_RATE_MASK           (3 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_3MV_PER_US     (0 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_6MV_PER_US     (1 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_12_5MV_PER_US  (2 << RK805_RAMP_RATE_OFFSET)
+#define RK805_RAMP_RATE_25MV_PER_US    (3 << RK805_RAMP_RATE_OFFSET)
+
 /* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */
 #define RK818_SLP_REG_OFFSET 1
 
 /* Offset from XXX_EN_REG to SLEEP_SET_OFF_XXX */
 #define RK818_SLP_SET_OFF_REG_OFFSET 2
 
+#define RK805_SLP_LDO_EN_OFFSET                -1
+#define RK805_SLP_DCDC_EN_OFFSET       2
+
 /* max steps for increase voltage of Buck1/2, equal 100mv*/
 #define MAX_STEPS_ONE_TIME 8
 
@@ -57,6 +67,26 @@ static const int rk818_buck_config_regs[] = {
        RK818_BUCK4_CONFIG_REG,
 };
 
+/* rk805 */
+#define ENABLE_MASK(id)        (BIT(id) | BIT(4 + (id)))
+#define DISABLE_VAL(id)        (BIT(4 + (id)))
+
+static const struct regulator_linear_range rk805_buck_voltage_ranges[] = {
+       REGULATOR_LINEAR_RANGE(712500, 0, 59, 12500),   /* 0.7125v - 1.45v */
+       REGULATOR_LINEAR_RANGE(1800000, 60, 62, 200000),/* 1.8v - 2.2v */
+       REGULATOR_LINEAR_RANGE(2300000, 63, 63, 0),     /* 2.3v - 2.3v */
+};
+
+static const struct regulator_linear_range rk805_buck4_voltage_ranges[] = {
+       REGULATOR_LINEAR_RANGE(800000, 0, 26, 100000),  /* 0.8v - 3.4 */
+       REGULATOR_LINEAR_RANGE(3500000, 27, 31, 0),     /* 3.5v */
+};
+
+static const struct regulator_linear_range rk805_ldo_voltage_ranges[] = {
+       REGULATOR_LINEAR_RANGE(800000, 0, 26, 100000),  /* 0.8v - 3.4 */
+};
+
+/* rk818 */
 static const struct regulator_linear_range rk818_buck_voltage_ranges[] = {
        REGULATOR_LINEAR_RANGE(712500, 0, 63, 12500),
 };
@@ -80,25 +110,53 @@ static const struct regulator_linear_range rk818_ldo6_voltage_ranges[] = {
 
 static int rk818_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
 {
+       struct rk808 *rk818 = rdev->reg_data;
        unsigned int ramp_value = RK818_RAMP_RATE_10MV_PER_US;
        unsigned int reg = rk818_buck_config_regs[rdev->desc->id -
                                                  RK818_ID_DCDC1];
 
-       switch (ramp_delay) {
-       case 1 ... 2000:
-               ramp_value = RK818_RAMP_RATE_2MV_PER_US;
-               break;
-       case 2001 ... 4000:
-               ramp_value = RK818_RAMP_RATE_4MV_PER_US;
-               break;
-       case 4001 ... 6000:
-               ramp_value = RK818_RAMP_RATE_6MV_PER_US;
+       switch (rk818->variant) {
+       case RK818_ID:
+               switch (ramp_delay) {
+               case 1 ... 2000:
+                       ramp_value = RK818_RAMP_RATE_2MV_PER_US;
+                       break;
+               case 2001 ... 4000:
+                       ramp_value = RK818_RAMP_RATE_4MV_PER_US;
+                       break;
+               case 4001 ... 6000:
+                       ramp_value = RK818_RAMP_RATE_6MV_PER_US;
+                       break;
+               case 6001 ... 10000:
+                       break;
+               default:
+                       pr_warn("%s ramp_delay: %d not supported, set 10000\n",
+                               rdev->desc->name, ramp_delay);
+               }
                break;
-       case 6001 ... 10000:
+       case RK805_ID:
+               switch (ramp_delay) {
+               case 3000:
+                       ramp_value = RK805_RAMP_RATE_3MV_PER_US;
+                       break;
+               case 6000:
+                       ramp_value = RK805_RAMP_RATE_6MV_PER_US;
+                       break;
+               case 12500:
+                       ramp_value = RK805_RAMP_RATE_12_5MV_PER_US;
+                       break;
+               case 25000:
+                       ramp_value = RK805_RAMP_RATE_25MV_PER_US;
+                       break;
+               default:
+                       pr_warn("%s ramp_delay: %d not supported\n",
+                               rdev->desc->name, ramp_delay);
+               }
                break;
        default:
-               pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
-                       rdev->desc->name, ramp_delay);
+               dev_err(&rdev->dev, "%s: unsupported RK8XX ID %lu\n",
+                       __func__, rk818->variant);
+               return -EINVAL;
        }
 
        return regmap_update_bits(rdev->regmap, reg,
@@ -122,24 +180,124 @@ static int rk818_set_suspend_voltage(struct regulator_dev *rdev, int uv)
 
 static int rk818_set_suspend_enable(struct regulator_dev *rdev)
 {
-       unsigned int reg;
+       unsigned int reg, enable_val;
+       int offset = 0;
+       struct rk808 *rk818 = rdev->reg_data;
+
+       switch (rk818->variant) {
+       case RK818_ID:
+               offset = RK818_SLP_SET_OFF_REG_OFFSET;
+               enable_val = 0;
+               break;
+       case RK805_ID:
+               if (rdev->desc->id >= RK805_ID_LDO1)
+                       offset = RK805_SLP_LDO_EN_OFFSET;
+               else
+                       offset = RK805_SLP_DCDC_EN_OFFSET;
+               enable_val = rdev->desc->enable_mask;
+               break;
+       default:
+               dev_err(&rdev->dev, "not define sleep en reg offset!!\n");
+               return -EINVAL;
+       }
 
-       reg = rdev->desc->enable_reg + RK818_SLP_SET_OFF_REG_OFFSET;
+       reg = rdev->desc->enable_reg + offset;
 
        return regmap_update_bits(rdev->regmap, reg,
                                  rdev->desc->enable_mask,
-                                 0);
+                                 enable_val);
 }
 
 static int rk818_set_suspend_disable(struct regulator_dev *rdev)
 {
-       unsigned int reg;
+       int offset = 0;
+       unsigned int reg, disable_val;
+       struct rk808 *rk818 = rdev->reg_data;
+
+       switch (rk818->variant) {
+       case RK818_ID:
+               offset = RK818_SLP_SET_OFF_REG_OFFSET;
+               disable_val = rdev->desc->enable_mask;
+               break;
+       case RK805_ID:
+               if (rdev->desc->id >= RK805_ID_LDO1)
+                       offset = RK805_SLP_LDO_EN_OFFSET;
+               else
+                       offset = RK805_SLP_DCDC_EN_OFFSET;
+               disable_val = 0;
+               break;
+       default:
+               dev_err(&rdev->dev, "not define sleep en reg offset!!\n");
+               return -EINVAL;
+       }
 
-       reg = rdev->desc->enable_reg + RK818_SLP_SET_OFF_REG_OFFSET;
+       reg = rdev->desc->enable_reg + offset;
 
        return regmap_update_bits(rdev->regmap, reg,
                                  rdev->desc->enable_mask,
-                                 rdev->desc->enable_mask);
+                                 disable_val);
+}
+
+static int rk818_set_suspend_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       unsigned int reg;
+
+       reg = rdev->desc->vsel_reg + RK818_SLP_REG_OFFSET;
+
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               return regmap_update_bits(rdev->regmap, reg,
+                                         FPWM_MODE, FPWM_MODE);
+       case REGULATOR_MODE_NORMAL:
+               return regmap_update_bits(rdev->regmap, reg, FPWM_MODE, 0);
+       default:
+               pr_err("do not support this mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rk818_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+                                         FPWM_MODE, FPWM_MODE);
+       case REGULATOR_MODE_NORMAL:
+               return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+                                         FPWM_MODE, 0);
+       default:
+               pr_err("do not support this mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned int rk818_get_mode(struct regulator_dev *rdev)
+{
+       unsigned int val;
+       int err;
+
+       err = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+       if (err)
+               return err;
+
+       if (val & FPWM_MODE)
+               return REGULATOR_MODE_FAST;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static unsigned int rk818_regulator_of_map_mode(unsigned int mode)
+{
+       if (mode == 1)
+               return REGULATOR_MODE_FAST;
+       if (mode == 2)
+               return REGULATOR_MODE_NORMAL;
+
+       return -EINVAL;
 }
 
 static struct regulator_ops rk818_buck1_2_ops = {
@@ -151,7 +309,10 @@ static struct regulator_ops rk818_buck1_2_ops = {
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_mode               = rk818_set_mode,
+       .get_mode               = rk818_get_mode,
        .set_ramp_delay         = rk818_set_ramp_delay,
+       .set_suspend_mode       = rk818_set_suspend_mode,
        .set_suspend_voltage    = rk818_set_suspend_voltage,
        .set_suspend_enable     = rk818_set_suspend_enable,
        .set_suspend_disable    = rk818_set_suspend_disable,
@@ -164,7 +325,10 @@ static struct regulator_ops rk818_reg_ops = {
        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
+       .set_mode               = rk818_set_mode,
+       .get_mode               = rk818_get_mode,
        .is_enabled             = regulator_is_enabled_regmap,
+       .set_suspend_mode       = rk818_set_suspend_mode,
        .set_suspend_voltage    = rk818_set_suspend_voltage,
        .set_suspend_enable     = rk818_set_suspend_enable,
        .set_suspend_disable    = rk818_set_suspend_disable,
@@ -176,9 +340,12 @@ static struct regulator_ops rk818_switch_ops = {
        .is_enabled             = regulator_is_enabled_regmap,
        .set_suspend_enable     = rk818_set_suspend_enable,
        .set_suspend_disable    = rk818_set_suspend_disable,
+       .set_mode               = rk818_set_mode,
+       .get_mode               = rk818_get_mode,
+       .set_suspend_mode       = rk818_set_suspend_mode,
 };
 
-static const struct regulator_desc rk818_reg[] = {
+static const struct regulator_desc rk818_desc[] = {
        {
                .name = "DCDC_REG1",
                .supply_name = "vcc1",
@@ -395,9 +562,145 @@ static struct of_regulator_match rk818_reg_matches[] = {
        [RK818_ID_SWITCH]       = { .name = "SWITCH_REG" },
 };
 
+static const struct regulator_desc rk805_desc[] = {
+       {
+               .name = "DCDC_REG1",
+               .supply_name = "vcc1",
+               .id = RK805_ID_DCDC1,
+               .ops = &rk818_buck1_2_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 64,
+               .linear_ranges = rk805_buck_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_buck_voltage_ranges),
+               .vsel_reg = RK805_BUCK1_ON_VSEL_REG,
+               .vsel_mask = RK818_BUCK_VSEL_MASK,
+               .enable_reg = RK805_DCDC_EN_REG,
+               .enable_mask = ENABLE_MASK(0),
+               .disable_val = DISABLE_VAL(0),
+               .of_map_mode = rk818_regulator_of_map_mode,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "DCDC_REG2",
+               .supply_name = "vcc2",
+               .id = RK805_ID_DCDC2,
+               .ops = &rk818_buck1_2_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 64,
+               .linear_ranges = rk805_buck_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_buck_voltage_ranges),
+               .vsel_reg = RK805_BUCK2_ON_VSEL_REG,
+               .vsel_mask = RK818_BUCK_VSEL_MASK,
+               .enable_reg = RK805_DCDC_EN_REG,
+               .enable_mask = ENABLE_MASK(1),
+               .disable_val = DISABLE_VAL(1),
+               .of_map_mode = rk818_regulator_of_map_mode,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "DCDC_REG3",
+               .supply_name = "vcc3",
+               .id = RK805_ID_DCDC3,
+               .ops = &rk818_switch_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 1,
+               .enable_reg = RK805_DCDC_EN_REG,
+               .enable_mask = ENABLE_MASK(2),
+               .disable_val = DISABLE_VAL(2),
+               .of_map_mode = rk818_regulator_of_map_mode,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "DCDC_REG4",
+               .supply_name = "vcc4",
+               .id = RK805_ID_DCDC4,
+               .ops = &rk818_reg_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 32,
+               .linear_ranges = rk805_buck4_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_buck4_voltage_ranges),
+               .vsel_reg = RK805_BUCK4_ON_VSEL_REG,
+               .vsel_mask = RK818_BUCK4_VSEL_MASK,
+               .enable_reg = RK805_DCDC_EN_REG,
+               .enable_mask = ENABLE_MASK(3),
+               .disable_val = DISABLE_VAL(3),
+               .of_map_mode = rk818_regulator_of_map_mode,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "LDO_REG1",
+               .supply_name = "vcc5",
+               .id = RK805_ID_LDO1,
+               .ops = &rk818_reg_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 27,
+               .linear_ranges = rk805_ldo_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_ldo_voltage_ranges),
+               .vsel_reg = RK805_LDO1_ON_VSEL_REG,
+               .vsel_mask = RK818_LDO_VSEL_MASK,
+               .enable_reg = RK805_LDO_EN_REG,
+               .enable_mask = ENABLE_MASK(0),
+               .disable_val = DISABLE_VAL(0),
+               .enable_time = 400,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "LDO_REG2",
+               .supply_name = "vcc5",
+               .id = RK805_ID_LDO2,
+               .ops = &rk818_reg_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 27,
+               .linear_ranges = rk805_ldo_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_ldo_voltage_ranges),
+               .vsel_reg = RK805_LDO2_ON_VSEL_REG,
+               .vsel_mask = RK818_LDO_VSEL_MASK,
+               .enable_reg = RK805_LDO_EN_REG,
+               .enable_mask = ENABLE_MASK(1),
+               .disable_val = DISABLE_VAL(1),
+               .enable_time = 400,
+               .owner = THIS_MODULE,
+       }, {
+               .name = "LDO_REG3",
+               .supply_name = "vcc6",
+               .id = RK805_ID_LDO3,
+               .ops = &rk818_reg_ops,
+               .type = REGULATOR_VOLTAGE,
+               .n_voltages = 27,
+               .linear_ranges = rk805_ldo_voltage_ranges,
+               .n_linear_ranges = ARRAY_SIZE(rk805_ldo_voltage_ranges),
+               .vsel_reg = RK805_LDO3_ON_VSEL_REG,
+               .vsel_mask = RK818_LDO_VSEL_MASK,
+               .enable_reg = RK805_LDO_EN_REG,
+               .enable_mask = ENABLE_MASK(2),
+               .disable_val = DISABLE_VAL(2),
+               .enable_time = 400,
+               .owner = THIS_MODULE,
+       },
+};
+
+static struct of_regulator_match rk805_reg_matches[] = {
+       [RK805_ID_DCDC1] = {
+               .name = "RK805_DCDC1",
+               .desc = &rk805_desc[RK805_ID_DCDC1] /* for of_map_node */
+       },
+       [RK805_ID_DCDC2] = {
+               .name = "RK805_DCDC2",
+               .desc = &rk805_desc[RK805_ID_DCDC2]
+       },
+       [RK805_ID_DCDC3] = {
+               .name = "RK805_DCDC3",
+               .desc = &rk805_desc[RK805_ID_DCDC3]
+       },
+       [RK805_ID_DCDC4] = {
+               .name = "RK805_DCDC4",
+               .desc = &rk805_desc[RK805_ID_DCDC4]
+       },
+       [RK805_ID_LDO1] = { .name = "RK805_LDO1", },
+       [RK805_ID_LDO2] = { .name = "RK805_LDO2", },
+       [RK805_ID_LDO3] = { .name = "RK805_LDO3", },
+};
+
 static int rk818_regulator_dt_parse_pdata(struct device *dev,
                                          struct device *client_dev,
-                                         struct regmap *map)
+                                         struct regmap *map,
+                                         struct of_regulator_match *reg_matches,
+                                         int regulator_nr)
 {
        struct device_node *np;
        int ret;
@@ -406,8 +709,7 @@ static int rk818_regulator_dt_parse_pdata(struct device *dev,
        if (!np)
                return -ENXIO;
 
-       ret = of_regulator_match(dev, np, rk818_reg_matches,
-                                RK818_NUM_REGULATORS);
+       ret = of_regulator_match(dev, np, reg_matches, regulator_nr);
 
        of_node_put(np);
        return ret;
@@ -419,26 +721,47 @@ static int rk818_regulator_probe(struct platform_device *pdev)
        struct i2c_client *client = rk818->i2c;
        struct regulator_config config = {};
        struct regulator_dev *rk818_rdev;
-       int ret, i;
+       int ret, i, reg_nr;
+       const struct regulator_desc *reg_desc;
+       struct of_regulator_match *reg_matches;
+
+       switch (rk818->variant) {
+       case RK818_ID:
+               reg_desc = rk818_desc;
+               reg_matches = rk818_reg_matches;
+               reg_nr = RK818_NUM_REGULATORS;
+               break;
+       case RK805_ID:
+               reg_desc = rk805_desc;
+               reg_matches = rk805_reg_matches;
+               reg_nr = RK805_NUM_REGULATORS;
+               break;
+       default:
+               dev_err(&client->dev, "unsupported RK8XX ID %lu\n",
+                       rk818->variant);
+               return -EINVAL;
+       }
 
        ret = rk818_regulator_dt_parse_pdata(&pdev->dev, &client->dev,
-                                            rk818->regmap);
+                                            rk818->regmap,
+                                            reg_matches, reg_nr);
        if (ret < 0)
                return ret;
 
        /* Instantiate the regulators */
-       for (i = 0; i < RK818_NUM_REGULATORS; i++) {
-               if (!rk818_reg_matches[i].init_data ||
-                   !rk818_reg_matches[i].of_node)
+       for (i = 0; i < reg_nr; i++) {
+               if (!reg_matches[i].init_data ||
+                   !reg_matches[i].of_node)
                        continue;
 
+               config.driver_data = rk818;
                config.dev = &client->dev;
                config.regmap = rk818->regmap;
-               config.of_node = rk818_reg_matches[i].of_node;
-               config.init_data = rk818_reg_matches[i].init_data;
-
+               config.of_node = reg_matches[i].of_node;
+               config.init_data = reg_matches[i].init_data;
                rk818_rdev = devm_regulator_register(&pdev->dev,
-                                                    &rk818_reg[i], &config);
+                                                    &reg_desc[i],
+                                                    &config);
                if (IS_ERR(rk818_rdev)) {
                        dev_err(&client->dev,
                                "failed to register %d regulator\n", i);
@@ -446,6 +769,8 @@ static int rk818_regulator_probe(struct platform_device *pdev)
                }
        }
 
+       dev_info(&client->dev, "register rk%lx regulators\n", rk818->variant);
+
        return 0;
 }
 
@@ -462,6 +787,7 @@ module_platform_driver(rk818_regulator_driver);
 MODULE_DESCRIPTION("regulator driver for the rk818 series PMICs");
 MODULE_AUTHOR("xsf<xsf@rock-chips.com>");
 MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
+MODULE_AUTHOR("chen Jianhong<chenjh@rock-chips.com>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rk818-regulator");
 
index 35c9aada07c8ef3a19f44cf8d4a3e8811f484e3f..55406c4302323c15d971721b7f49105cf6e31ed9 100644 (file)
@@ -376,8 +376,21 @@ static int rk808_rtc_probe(struct platform_device *pdev)
        struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
        struct rk808_rtc *rk808_rtc;
        struct rtc_time tm;
+       struct device_node *np;
        int ret;
 
+       switch (rk808->variant) {
+       case RK805_ID:
+               np = of_find_node_by_name(pdev->dev.parent->of_node, "rtc");
+               if (np && !of_device_is_available(np)) {
+                       dev_info(&pdev->dev, "device is disabled\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               break;
+       }
+
        rk808_rtc = devm_kzalloc(&pdev->dev, sizeof(*rk808_rtc), GFP_KERNEL);
        if (rk808_rtc == NULL)
                return -ENOMEM;
index d1ee93ef6823e3d0ddd53e3c78be085902e8942a..59aa1eeb2845d17379a85f3b22b662a3015fde2f 100644 (file)
@@ -64,6 +64,16 @@ enum rk818_reg {
        RK818_ID_SWITCH,
 };
 
+enum rk805_reg {
+       RK805_ID_DCDC1,
+       RK805_ID_DCDC2,
+       RK805_ID_DCDC3,
+       RK805_ID_DCDC4,
+       RK805_ID_LDO1,
+       RK805_ID_LDO2,
+       RK805_ID_LDO3,
+};
+
 #define RK808_SECONDS_REG      0x00
 #define RK808_MINUTES_REG      0x01
 #define RK808_HOURS_REG                0x02
@@ -82,6 +92,8 @@ enum rk818_reg {
 #define RK808_RTC_INT_REG      0x12
 #define RK808_RTC_COMP_LSB_REG 0x13
 #define RK808_RTC_COMP_MSB_REG 0x14
+#define RK808_ID_MSB           0x17
+#define RK808_ID_LSB           0x18
 #define RK808_CLK32OUT_REG     0x20
 #define RK808_VB_MON_REG       0x21
 #define RK808_THERMAL_REG      0x22
@@ -441,6 +453,86 @@ enum rk818_reg {
 #define CHG_CVTLIM_ENABLE      BIT(6)
 #define DISCHG_ILIM_ENABLE     BIT(7)
 
+/* IRQ Definitions */
+#define RK805_IRQ_PWRON_RISE           0
+#define RK805_IRQ_VB_LOW               1
+#define RK805_IRQ_PWRON                        2
+#define RK805_IRQ_PWRON_LP             3
+#define RK805_IRQ_HOTDIE               4
+#define RK805_IRQ_RTC_ALARM            5
+#define RK805_IRQ_RTC_PERIOD           6
+#define RK805_IRQ_PWRON_FALL           7
+
+#define RK805_IRQ_PWRON_RISE_MSK       BIT(0)
+#define RK805_IRQ_VB_LOW_MSK           BIT(1)
+#define RK805_IRQ_PWRON_MSK            BIT(2)
+#define RK805_IRQ_PWRON_LP_MSK         BIT(3)
+#define RK805_IRQ_HOTDIE_MSK           BIT(4)
+#define RK805_IRQ_RTC_ALARM_MSK                BIT(5)
+#define RK805_IRQ_RTC_PERIOD_MSK       BIT(6)
+#define RK805_IRQ_PWRON_FALL_MSK       BIT(7)
+
+#define RK805_PWR_RISE_INT_STATUS      BIT(0)
+#define RK805_VB_LOW_INT_STATUS                BIT(1)
+#define RK805_PWRON_INT_STATUS         BIT(2)
+#define RK805_PWRON_LP_INT_STATUS      BIT(3)
+#define RK805_HOTDIE_INT_STATUS                BIT(4)
+#define RK805_ALARM_INT_STATUS         BIT(5)
+#define RK805_PERIOD_INT_STATUS                BIT(6)
+#define RK805_PWR_FALL_INT_STATUS      BIT(7)
+
+/*INTERRUPT REGISTER*/
+#define RK805_INT_STS_REG              0x4C
+#define RK805_INT_STS_MSK_REG          0x4D
+#define RK805_GPIO_IO_POL_REG          0x50
+#define RK805_OUT_REG                  0x52
+#define RK805_ON_SOURCE_REG            0xAE
+#define RK805_OFF_SOURCE_REG           0xAF
+
+/*POWER CHANNELS ENABLE REGISTER*/
+#define RK805_DCDC_EN_REG              0x23
+#define RK805_SLP_DCDC_EN_REG          0x25
+#define RK805_SLP_LDO_EN_REG           0x26
+#define RK805_LDO_EN_REG               0x27
+
+/*CONFIG REGISTER*/
+#define RK805_THERMAL_REG              0x22
+
+/*BUCK AND LDO CONFIG REGISTER*/
+#define RK805_BUCK_LDO_SLP_LP_EN_REG   0x2A
+#define RK805_BUCK1_CONFIG_REG         0x2E
+#define RK805_BUCK1_ON_VSEL_REG                0x2F
+#define RK805_BUCK1_SLP_VSEL_REG       0x30
+#define RK805_BUCK2_CONFIG_REG         0x32
+#define RK805_BUCK2_ON_VSEL_REG                0x33
+#define RK805_BUCK2_SLP_VSEL_REG       0x34
+#define RK805_BUCK3_CONFIG_REG         0x36
+#define RK805_BUCK4_CONFIG_REG         0x37
+#define RK805_BUCK4_ON_VSEL_REG                0x38
+#define RK805_BUCK4_SLP_VSEL_REG       0x39
+#define RK805_LDO1_ON_VSEL_REG         0x3B
+#define RK805_LDO1_SLP_VSEL_REG                0x3C
+#define RK805_LDO2_ON_VSEL_REG         0x3D
+#define RK805_LDO2_SLP_VSEL_REG                0x3E
+#define RK805_LDO3_ON_VSEL_REG         0x3F
+#define RK805_LDO3_SLP_VSEL_REG                0x40
+#define RK805_OUT_REG                  0x52
+#define RK805_ON_SOURCE_REG            0xAE
+#define RK805_OFF_SOURCE_REG           0xAF
+
+#define RK805_NUM_REGULATORS           7
+
+#define RK805_PWRON_FALL_RISE_INT_EN   0x0
+#define RK805_PWRON_FALL_RISE_INT_MSK  0x81
+
+#define TEMP115C                       0x0c
+#define TEMP_HOTDIE_MSK                        0x0c
+#define SLP_SD_MSK                     (0x3 << 2)
+#define SHUTDOWN_FUN                   (0x2 << 2)
+#define SLEEP_FUN                      (0x1 << 2)
+#define RK8XX_ID_MSK                   0xfff0
+#define FPWM_MODE                      BIT(7)
+
 enum {
        BUCK_ILMIN_50MA,
        BUCK_ILMIN_100MA,
@@ -467,5 +559,13 @@ struct rk808 {
        struct i2c_client *i2c;
        struct regmap_irq_chip_data *irq_data;
        struct regmap *regmap;
+       long variant;
 };
+
+enum {
+       RK805_ID = 0x8050,
+       RK808_ID = 0x0000,
+       RK818_ID = 0x8180,
+};
+
 #endif /* __LINUX_REGULATOR_rk808_H */