--- /dev/null
+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
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
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
--- /dev/null
+/*
+ * 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>");
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
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
--- /dev/null
+/*
+ * 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>");
#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;
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)
{
/*
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)
{
/*
.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,
}
};
+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", },
},
};
-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 },
.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;
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");
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;
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);
"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;
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" },
{ },
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");
#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
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),
};
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,
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 = {
.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,
.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,
.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",
[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;
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;
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);
+ ®_desc[i],
+ &config);
if (IS_ERR(rk818_rdev)) {
dev_err(&client->dev,
"failed to register %d regulator\n", i);
}
}
+ dev_info(&client->dev, "register rk%lx regulators\n", rk818->variant);
+
return 0;
}
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");
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;
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
#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
#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,
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 */