mfd: rk808: add rk805 support

include sub modules: regulator, rtc, gpio, pwrkey

Change-Id: I19796e2a94764f95588d4b90bca1f3bc616f4f56
Signed-off-by: Jianhong Chen <chenjh@rock-chips.com>
This commit is contained in:
Jianhong Chen 2017-01-06 16:52:49 +08:00 committed by Huang, Tao
parent 9ad514e0ea
commit 01afa13ceb
11 changed files with 1326 additions and 112 deletions

View File

@ -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>;
};
};
};
};

View 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

View 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

262
drivers/gpio/gpio-rk8xx.c Normal file
View File

@ -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>");

View 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

View 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

View File

@ -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>");

View File

@ -18,11 +18,12 @@
#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;
}
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);
}
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);
}
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");

View File

@ -41,12 +41,22 @@
#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;
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 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:
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;
reg = rdev->desc->enable_reg + RK818_SLP_SET_OFF_REG_OFFSET;
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 + 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;
reg = rdev->desc->enable_reg + RK818_SLP_SET_OFF_REG_OFFSET;
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 + 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");

View 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;

View 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 */