mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 22:14:04 +02:00
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:
parent
9ad514e0ea
commit
01afa13ceb
196
Documentation/devicetree/bindings/mfd/rk805.txt
Normal file
196
Documentation/devicetree/bindings/mfd/rk805.txt
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
262
drivers/gpio/gpio-rk8xx.c
Normal 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>");
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
144
drivers/input/misc/rk8xx-pwrkey.c
Normal file
144
drivers/input/misc/rk8xx-pwrkey.c
Normal 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>");
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
®_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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user