mfd: rk806: Add RK806 support

The RK806 are a Power Management IC (PMIC) for multimedia
and handheld devices. They contains the following components:
- Regulators
- Pinctrl
- PowerKey

Signed-off-by: shengfei Xu <xsf@rock-chips.com>
Change-Id: Iee9c521d52c53752286238c93b39afb5eb32e9b2
This commit is contained in:
shengfei Xu 2021-09-16 14:50:37 +08:00 committed by Tao Huang
parent 52b779b7f4
commit 94a2726fb4
11 changed files with 3161 additions and 0 deletions

View File

@ -1138,6 +1138,25 @@ config MFD_RK630_SPI
if you say yes here you get support for the RK630 when controlled
using SPI.
config MFD_RK806
tristate "Rockchip RK806 Power Management Chip"
select MFD_CORE
select REGMAP
select REGMAP_IRQ
help
If you say yes here you get support for the RK806 Power Management chips.
This driver provides common support for accessing the device
through SPI interface. The device supports multiple sub-devices
including interrupts, LDO & DCDC regulators, and onkey.
config MFD_RK806_SPI
tristate "RK806 Power Management chip with SPI"
select MFD_RK806
select REGMAP_SPI
depends on SPI_MASTER
help
If you say yes here you get support for the RK806 PM chips with SPI interface.
config MFD_RK808
tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power Management Chip"
depends on I2C && OF

View File

@ -222,6 +222,8 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
obj-$(CONFIG_MFD_RK630) += rk630.o
obj-$(CONFIG_MFD_RK630_I2C) += rk630-i2c.o
obj-$(CONFIG_MFD_RK630_SPI) += rk630-spi.o
obj-$(CONFIG_MFD_RK806) += rk806-core.o
obj-$(CONFIG_MFD_RK806_SPI) += rk806-spi.o
obj-$(CONFIG_MFD_RK808) += rk808.o
obj-$(CONFIG_MFD_RK1000) += rk1000-core.o
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o

637
drivers/mfd/rk806-core.c Normal file
View File

@ -0,0 +1,637 @@
// SPDX-License-Identifier: GPL-2.0
/*
* MFD core driver for Rockchip RK806
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*
* Author: Xu Shengfei <xsf@rock-chips.com>
*/
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rk806.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#define TSD_TEMP_140 0x00
#define TSD_TEMP_160 0x01
#define VB_LO_ACT_SD 0x00
#define VB_LO_ACT_INT 0x01
static const struct reg_field rk806_reg_fields[] = {
[POWER_EN0] = REG_FIELD(0x00, 0, 7),
[POWER_EN1] = REG_FIELD(0x01, 0, 7),
[POWER_EN2] = REG_FIELD(0x02, 0, 7),
[POWER_EN3] = REG_FIELD(0x03, 0, 7),
[POWER_EN4] = REG_FIELD(0x04, 0, 7),
[POWER_EN5] = REG_FIELD(0x05, 0, 7),
[BUCK4_EN_MASK] = REG_FIELD(0x00, 7, 7),
[BUCK3_EN_MASK] = REG_FIELD(0x00, 6, 6),
[BUCK2_EN_MASK] = REG_FIELD(0x00, 5, 5),
[BUCK1_EN_MASK] = REG_FIELD(0x00, 4, 4),
[BUCK4_EN] = REG_FIELD(0X00, 3, 3),
[BUCK3_EN] = REG_FIELD(0X00, 2, 2),
[BUCK2_EN] = REG_FIELD(0X00, 1, 1),
[BUCK1_EN] = REG_FIELD(0X00, 0, 0),
[BUCK8_EN_MASK] = REG_FIELD(0x01, 7, 7),
[BUCK7_EN_MASK] = REG_FIELD(0x01, 6, 6),
[BUCK6_EN_MASK] = REG_FIELD(0x01, 5, 5),
[BUCK5_EN_MASK] = REG_FIELD(0x01, 4, 4),
[BUCK8_EN] = REG_FIELD(0x01, 3, 3),
[BUCK7_EN] = REG_FIELD(0x01, 2, 2),
[BUCK6_EN] = REG_FIELD(0x01, 1, 1),
[BUCK5_EN] = REG_FIELD(0x01, 0, 0),
[BUCK10_EN_MASK] = REG_FIELD(0x02, 5, 5),
[BUCK9_EN_MASK] = REG_FIELD(0x02, 4, 4),
[BUCK10_EN] = REG_FIELD(0x02, 1, 1),
[BUCK9_EN] = REG_FIELD(0x02, 0, 0),
[NLDO4_EN_MASK] = REG_FIELD(0x03, 7, 7),
[NLDO3_EN_MASK] = REG_FIELD(0x03, 6, 6),
[NLDO2_EN_MASK] = REG_FIELD(0x03, 5, 5),
[NLDO1_EN_MASK] = REG_FIELD(0x03, 4, 4),
[NLDO4_EN] = REG_FIELD(0x03, 3, 3),
[NLDO3_EN] = REG_FIELD(0x03, 2, 2),
[NLDO2_EN] = REG_FIELD(0x03, 1, 1),
[NLDO1_EN] = REG_FIELD(0x03, 0, 0),
[PLDO4_EN_MASK] = REG_FIELD(0x04, 7, 7),
[PLDO3_EN_MASK] = REG_FIELD(0x04, 6, 6),
[PLDO2_EN_MASK] = REG_FIELD(0x04, 5, 5),
[PLDO1_EN_MASK] = REG_FIELD(0x04, 4, 4),
[PLDO4_EN] = REG_FIELD(0x04, 3, 3),
[PLDO3_EN] = REG_FIELD(0x04, 2, 2),
[PLDO2_EN] = REG_FIELD(0x04, 1, 1),
[PLDO1_EN] = REG_FIELD(0x04, 0, 0),
[NLDO5_EN_MASK] = REG_FIELD(0x05, 6, 6),
[PLDO6_EN_MASK] = REG_FIELD(0x05, 5, 5),
[PLDO5_EN_MASK] = REG_FIELD(0x05, 4, 4),
[NLDO5_EN] = REG_FIELD(0x05, 3, 3),
[PLDO6_EN] = REG_FIELD(0x05, 2, 2),
[PLDO5_EN] = REG_FIELD(0x05, 1, 1),
[BUCK8_SLP_EN] = REG_FIELD(0x06, 7, 7),
[BUCK7_SLP_EN] = REG_FIELD(0x06, 6, 6),
[BUCK6_SLP_EN] = REG_FIELD(0x06, 5, 5),
[BUCK5_SLP_EN] = REG_FIELD(0x06, 4, 4),
[BUCK4_SLP_EN] = REG_FIELD(0x06, 3, 3),
[BUCK3_SLP_EN] = REG_FIELD(0x06, 2, 2),
[BUCK2_SLP_EN] = REG_FIELD(0x06, 1, 1),
[BUCK1_SLP_EN] = REG_FIELD(0x06, 0, 0),
[BUCK10_SLP_EN] = REG_FIELD(0x07, 7, 7),
[BUCK9_SLP_EN] = REG_FIELD(0x07, 6, 6),
[NLDO5_SLP_EN] = REG_FIELD(0x07, 4, 4),
[NLDO4_SLP_EN] = REG_FIELD(0x07, 3, 3),
[NLDO3_SLP_EN] = REG_FIELD(0x07, 2, 2),
[NLDO2_SLP_EN] = REG_FIELD(0x07, 1, 1),
[NLDO1_SLP_EN] = REG_FIELD(0x07, 0, 0),
[PLDO6_SLP_EN] = REG_FIELD(0x08, 5, 5),
[PLDO5_SLP_EN] = REG_FIELD(0x08, 4, 4),
[PLDO4_SLP_EN] = REG_FIELD(0x08, 3, 3),
[PLDO3_SLP_EN] = REG_FIELD(0x08, 2, 2),
[PLDO2_SLP_EN] = REG_FIELD(0x08, 1, 1),
[PLDO1_SLP_EN] = REG_FIELD(0x08, 0, 0),
[BUCK1_RATE] = REG_FIELD(0x10, 6, 7),
[BUCK2_RATE] = REG_FIELD(0x11, 6, 7),
[BUCK3_RATE] = REG_FIELD(0x12, 6, 7),
[BUCK4_RATE] = REG_FIELD(0x13, 6, 7),
[BUCK5_RATE] = REG_FIELD(0x14, 6, 7),
[BUCK6_RATE] = REG_FIELD(0x15, 6, 7),
[BUCK7_RATE] = REG_FIELD(0x16, 6, 7),
[BUCK8_RATE] = REG_FIELD(0x17, 6, 7),
[BUCK9_RATE] = REG_FIELD(0x18, 6, 7),
[BUCK10_RATE] = REG_FIELD(0x19, 6, 7),
[BUCK1_ON_VSEL] = REG_FIELD(0x1A, 0, 7),
[BUCK2_ON_VSEL] = REG_FIELD(0x1B, 0, 7),
[BUCK3_ON_VSEL] = REG_FIELD(0x1C, 0, 7),
[BUCK4_ON_VSEL] = REG_FIELD(0x1D, 0, 7),
[BUCK5_ON_VSEL] = REG_FIELD(0x1E, 0, 7),
[BUCK6_ON_VSEL] = REG_FIELD(0x1F, 0, 7),
[BUCK7_ON_VSEL] = REG_FIELD(0x20, 0, 7),
[BUCK8_ON_VSEL] = REG_FIELD(0x21, 0, 7),
[BUCK9_ON_VSEL] = REG_FIELD(0x22, 0, 7),
[BUCK10_ON_VSEL] = REG_FIELD(0x23, 0, 7),
[BUCK1_SLP_VSEL] = REG_FIELD(0x24, 0, 7),
[BUCK2_SLP_VSEL] = REG_FIELD(0x25, 0, 7),
[BUCK3_SLP_VSEL] = REG_FIELD(0x26, 0, 7),
[BUCK4_SLP_VSEL] = REG_FIELD(0x27, 0, 7),
[BUCK5_SLP_VSEL] = REG_FIELD(0x28, 0, 7),
[BUCK6_SLP_VSEL] = REG_FIELD(0x29, 0, 7),
[BUCK7_SLP_VSEL] = REG_FIELD(0x2A, 0, 7),
[BUCK8_SLP_VSEL] = REG_FIELD(0x2B, 0, 7),
[BUCK9_SLP_VSEL] = REG_FIELD(0x2C, 0, 7),
[BUCK10_SLP_VSEL] = REG_FIELD(0x2D, 0, 7),
[NLDO1_ON_VSEL] = REG_FIELD(0x43, 0, 7),
[NLDO2_ON_VSEL] = REG_FIELD(0x44, 0, 7),
[NLDO3_ON_VSEL] = REG_FIELD(0x45, 0, 7),
[NLDO4_ON_VSEL] = REG_FIELD(0x46, 0, 7),
[NLDO5_ON_VSEL] = REG_FIELD(0x47, 0, 7),
[NLDO1_SLP_VSEL] = REG_FIELD(0x48, 0, 7),
[NLDO2_SLP_VSEL] = REG_FIELD(0x49, 0, 7),
[NLDO3_SLP_VSEL] = REG_FIELD(0x4A, 0, 7),
[NLDO4_SLP_VSEL] = REG_FIELD(0x4B, 0, 7),
[NLDO5_SLP_VSEL] = REG_FIELD(0x4C, 0, 7),
[PLDO1_ON_VSEL] = REG_FIELD(0x4E, 0, 7),
[PLDO2_ON_VSEL] = REG_FIELD(0x4F, 0, 7),
[PLDO3_ON_VSEL] = REG_FIELD(0x50, 0, 7),
[PLDO4_ON_VSEL] = REG_FIELD(0x51, 0, 7),
[PLDO5_ON_VSEL] = REG_FIELD(0x52, 0, 7),
[PLDO6_ON_VSEL] = REG_FIELD(0x53, 0, 7),
[PLDO1_SLP_VSEL] = REG_FIELD(0x54, 0, 7),
[PLDO2_SLP_VSEL] = REG_FIELD(0x55, 0, 7),
[PLDO3_SLP_VSEL] = REG_FIELD(0x56, 0, 7),
[PLDO4_SLP_VSEL] = REG_FIELD(0x57, 0, 7),
[PLDO5_SLP_VSEL] = REG_FIELD(0x58, 0, 7),
[PLDO6_SLP_VSEL] = REG_FIELD(0x59, 0, 7),
[CHIP_NAME_H] = REG_FIELD(0x5A, 0, 7),
[CHIP_NAME_L] = REG_FIELD(0x5B, 4, 7),
[CHIP_VER] = REG_FIELD(0x5B, 0, 3),
[OTP_VER] = REG_FIELD(0x5C, 0, 3),
/* SYS_STS */
[PWRON_STS] = REG_FIELD(0x5D, 7, 7),
[VDC_STS] = REG_FIELD(0x5D, 6, 6),
[VB_UV_STSS] = REG_FIELD(0x5D, 5, 5),
[VB_LO_STS] = REG_FIELD(0x5D, 4, 4),
[HOTDIE_STS] = REG_FIELD(0x5D, 3, 3),
[TSD_STS] = REG_FIELD(0x5D, 2, 2),
[VB_OV_STS] = REG_FIELD(0x5D, 0, 0),
/* SYS_CFG0 */
[VB_UV_DLY] = REG_FIELD(0x5E, 7, 7),
[VB_UV_SEL] = REG_FIELD(0x5E, 4, 6),
[VB_LO_ACT] = REG_FIELD(0x5E, 3, 3),
[VB_LO_SEL] = REG_FIELD(0x5E, 0, 2),
/* SYS_CFG1 */
[TSD_TEMP] = REG_FIELD(0x5F, 6, 6),
[HOTDIE_TMP] = REG_FIELD(0x5F, 4, 5),
[VPREREG_SEL] = REG_FIELD(0x5F, 0, 1),
/* SYS_OPTION */
[VCCXDET_DIS] = REG_FIELD(0x61, 4, 5),
[OSC_TC] = REG_FIELD(0x61, 2, 3),
[ENB2_2M] = REG_FIELD(0x61, 1, 1),
[ENB_32K] = REG_FIELD(0x61, 0, 0),
/* SLEEP_CONFIG0 */
[SLP2_POL] = REG_FIELD(0x62, 7, 7),
[SLP2_FUN] = REG_FIELD(0x62, 4, 6),
[SLP1_POL] = REG_FIELD(0x62, 3, 3),
[SLP1_FUN] = REG_FIELD(0x62, 0, 2),
/* SLEEP_CONFIG1 */
[SLP3_POL] = REG_FIELD(0x63, 3, 3),
[SLP3_FUN] = REG_FIELD(0x63, 0, 2),
/* SLEEP_SLP_CTR_SEL0 */
[BUCK4_SLP_CTR_SEL] = REG_FIELD(0x65, 4, 5),
[BUCK3_SLP_CTR_SEL] = REG_FIELD(0x65, 0, 1),
[BUCK2_SLP_CTR_SEL] = REG_FIELD(0x64, 4, 5),
[BUCK1_SLP_CTR_SEL] = REG_FIELD(0x64, 0, 1),
/* SLEEP_SLP_CTR_SEL1 */
[BUCK8_SLP_CTR_SEL] = REG_FIELD(0x67, 4, 5),
[BUCK7_SLP_CTR_SEL] = REG_FIELD(0x67, 0, 1),
[BUCK6_SLP_CTR_SEL] = REG_FIELD(0x66, 4, 5),
[BUCK5_SLP_CTR_SEL] = REG_FIELD(0x66, 0, 1),
/* SLEEP_SLP_CTR_SEL2 */
[NLDO2_SLP_CTR_SEL] = REG_FIELD(0x69, 4, 5),
[NLDO1_SLP_CTR_SEL] = REG_FIELD(0x69, 0, 1),
[BUCK10_SLP_CTR_SEL] = REG_FIELD(0x68, 4, 5),
[BUCK9_SLP_CTR_SEL] = REG_FIELD(0x68, 0, 1),
/* SLEEP_SLP_CTR_SEL3 */
[NLDO5_SLP_CTR_SEL] = REG_FIELD(0x6b, 0, 1),
[NLDO4_SLP_CTR_SEL] = REG_FIELD(0x6a, 4, 5),
[NLDO3_SLP_CTR_SEL] = REG_FIELD(0x6a, 0, 1),
/* SLEEP_SLP_CTR_SEL4 */
[PLDO4_SLP_CTR_SEL] = REG_FIELD(0x6d, 4, 5),
[PLDO3_SLP_CTR_SEL] = REG_FIELD(0x6d, 0, 0),
[PLDO2_SLP_CTR_SEL] = REG_FIELD(0x6c, 4, 5),
[PLDO1_SLP_CTR_SEL] = REG_FIELD(0x6c, 0, 1),
/* SLEEP_SLP_CTR_SEL5 */
[PLDO6_SLP_CTR_SEL] = REG_FIELD(0x6e, 4, 5),
[PLDO5_SLP_CTR_SEL] = REG_FIELD(0x6e, 0, 1),
/* DVS_CTRL_SEL0 */
[BUCK4_DVS_CTR_SEL] = REG_FIELD(0x65, 6, 7),
[BUCK3_DVS_CTR_SEL] = REG_FIELD(0x65, 2, 3),
[BUCK2_DVS_CTR_SEL] = REG_FIELD(0x64, 6, 7),
[BUCK1_DVS_CTR_SEL] = REG_FIELD(0x64, 2, 3),
/* DVS_CTRL_SEL1*/
[BUCK8_DVS_CTR_SEL] = REG_FIELD(0x67, 6, 7),
[BUCK7_DVS_CTR_SEL] = REG_FIELD(0x67, 2, 3),
[BUCK6_DVS_CTR_SEL] = REG_FIELD(0x66, 6, 7),
[BUCK5_DVS_CTR_SEL] = REG_FIELD(0x66, 2, 3),
/* DVS_CTRL_SEL2 */
[NLDO2_DVS_CTR_SEL] = REG_FIELD(0x69, 6, 7),
[NLDO1_DVS_CTR_SEL] = REG_FIELD(0x69, 2, 3),
[BUCK10_DVS_CTR_SEL] = REG_FIELD(0x68, 6, 7),
[BUCK9_DVS_CTR_SEL] = REG_FIELD(0x68, 2, 3),
/* DVS_CTRL_SEL3 */
[NLDO5_DVS_CTR_SEL] = REG_FIELD(0x6b, 2, 3),
[NLDO4_DVS_CTR_SEL] = REG_FIELD(0x6a, 6, 7),
[NLDO3_DVS_CTR_SEL] = REG_FIELD(0x6a, 2, 3),
/* DVS_CTRL_SEL4 */
[PLDO4_DVS_CTR_SEL] = REG_FIELD(0x6d, 6, 7),
[PLDO3_DVS_CTR_SEL] = REG_FIELD(0x6d, 2, 3),
[PLDO2_DVS_CTR_SEL] = REG_FIELD(0x6c, 6, 7),
[PLDO1_DVS_CTR_SEL] = REG_FIELD(0x6c, 2, 3),
/* DVS_CTRL_SEL5 */
[PLDO6_DVS_CTR_SEL] = REG_FIELD(0x6e, 6, 7),
[PLDO5_DVS_CTR_SEL] = REG_FIELD(0x6e, 2, 3),
/* DVS_START_CTRL */
[DVS_START3] = REG_FIELD(0x70, 2, 2),
[DVS_START2] = REG_FIELD(0x70, 1, 1),
[DVS_START1] = REG_FIELD(0x70, 0, 0),
/* SLEEP_GPIO */
[SLP3_DATA] = REG_FIELD(0x71, 6, 6),
[SLP2_DATA] = REG_FIELD(0x71, 5, 5),
[SLP1_DATA] = REG_FIELD(0x71, 4, 4),
[SLP3_DR] = REG_FIELD(0x71, 2, 2),
[SLP2_DR] = REG_FIELD(0x71, 1, 1),
[SLP1_DR] = REG_FIELD(0x71, 0, 0),
/* SYS_CFG3 */
[RST_FUN] = REG_FIELD(0x72, 6, 7),
[DEV_RST] = REG_FIELD(0x72, 5, 5),
[DEV_SLP] = REG_FIELD(0x72, 4, 4),
[SLAVE_RESTART_FUN] = REG_FIELD(0x72, 1, 1),
[DEV_OFF] = REG_FIELD(0x72, 0, 0),
[WDT_CLR] = REG_FIELD(0x73, 4, 4),
[WDT_EN] = REG_FIELD(0x73, 3, 3),
[WDT_SET] = REG_FIELD(0x73, 0, 3),
/* PWRON_KEY */
[PWRON_ON_TIME] = REG_FIELD(0x76, 7, 7),
[PWRON_LP_ACT] = REG_FIELD(0x76, 6, 6),
[PWRON_LP_OFF_TIME] = REG_FIELD(0x76, 4, 5),
[PWRON_LP_TM_SEL] = REG_FIELD(0x76, 2, 3),
[PWRON_DB_SEL] = REG_FIELD(0x76, 0, 1),
/* GPIO_INT_CONFIG */
[INT_FUNCTION] = REG_FIELD(0x7b, 2, 2),
[INT_POL] = REG_FIELD(0x7b, 1, 1),
[INT_FC_EN] = REG_FIELD(0x7b, 0, 0),
[BUCK9_RATE2] = REG_FIELD(0xEA, 0, 0),
[BUCK10_RATE2] = REG_FIELD(0xEA, 1, 1),
[LDO_RATE] = REG_FIELD(0xEA, 3, 5),
[BUCK1_RATE2] = REG_FIELD(0xEB, 0, 0),
[BUCK2_RATE2] = REG_FIELD(0xEB, 1, 1),
[BUCK3_RATE2] = REG_FIELD(0xEB, 2, 2),
[BUCK4_RATE2] = REG_FIELD(0xEB, 3, 3),
[BUCK5_RATE2] = REG_FIELD(0xEB, 4, 4),
[BUCK6_RATE2] = REG_FIELD(0xEB, 5, 5),
[BUCK7_RATE2] = REG_FIELD(0xEB, 6, 6),
[BUCK8_RATE2] = REG_FIELD(0xEB, 7, 7),
};
static struct resource rk806_pwrkey_resources[] = {
DEFINE_RES_IRQ(RK806_IRQ_PWRON_FALL),
DEFINE_RES_IRQ(RK806_IRQ_PWRON_RISE),
};
static const struct mfd_cell rk806_cells[] = {
{ .name = "rk806-regulator", },
{
.name = "rk805-pwrkey",
.num_resources = ARRAY_SIZE(rk806_pwrkey_resources),
.resources = &rk806_pwrkey_resources[0],
},
{ .name = "rk806-pinctrl", },
};
static const struct regmap_irq rk806_irqs[] = {
/* INT_STS0 IRQs */
REGMAP_IRQ_REG(RK806_IRQ_PWRON_FALL, 0, RK806_INT_STS_PWRON_FALL),
REGMAP_IRQ_REG(RK806_IRQ_PWRON_RISE, 0, RK806_INT_STS_PWRON_RISE),
REGMAP_IRQ_REG(RK806_IRQ_PWRON, 0, RK806_INT_STS_PWRON),
REGMAP_IRQ_REG(RK806_IRQ_PWRON_LP, 0, RK806_INT_STS_PWRON_LP),
REGMAP_IRQ_REG(RK806_IRQ_HOTDIE, 0, RK806_INT_STS_HOTDIE),
REGMAP_IRQ_REG(RK806_IRQ_VDC_RISE, 0, RK806_INT_STS_VDC_RISE),
REGMAP_IRQ_REG(RK806_IRQ_VDC_FALL, 0, RK806_INT_STS_VDC_FALL),
REGMAP_IRQ_REG(RK806_IRQ_VB_LO, 0, RK806_INT_STS_VB_LO),
/* INT_STS1 IRQs */
REGMAP_IRQ_REG(RK806_IRQ_REV0, 1, RK806_INT_STS_REV0),
REGMAP_IRQ_REG(RK806_IRQ_REV1, 1, RK806_INT_STS_REV1),
REGMAP_IRQ_REG(RK806_IRQ_REV2, 1, RK806_INT_STS_REV2),
REGMAP_IRQ_REG(RK806_IRQ_SLP3_GPIO, 1, RK806_INT_STS_SLP3_GPIO),
REGMAP_IRQ_REG(RK806_IRQ_SLP2_GPIO, 1, RK806_INT_STS_SLP2_GPIO),
REGMAP_IRQ_REG(RK806_IRQ_SLP1_GPIO, 1, RK806_INT_STS_SLP1_GPIO),
REGMAP_IRQ_REG(RK806_IRQ_WDT, 1, RK806_INT_STS_WDT),
};
static struct regmap_irq_chip rk806_irq_chip = {
.name = "rk806",
.irqs = rk806_irqs,
.num_irqs = ARRAY_SIZE(rk806_irqs),
.num_regs = 2,
.irq_reg_stride = 2,
.mask_base = RK806_INT_MSK0,
.status_base = RK806_INT_STS0,
.ack_base = RK806_INT_STS0,
.init_ack_masked = true,
};
static const struct regmap_range rk806_yes_ranges[] = {
/* regmap_reg_range(RK806_INT_STS0, RK806_GPIO_INT_CONFIG), */
regmap_reg_range(0x00, 0xff),
};
static const struct regmap_access_table rk806_volatile_table = {
.yes_ranges = rk806_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(rk806_yes_ranges),
};
const struct regmap_config rk806_regmap_config_spi = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.volatile_table = &rk806_volatile_table,
};
EXPORT_SYMBOL_GPL(rk806_regmap_config_spi);
int rk806_field_read(struct rk806 *rk806,
enum rk806_fields field_id)
{
int ret;
int val;
ret = regmap_field_read(rk806->rmap_fields[field_id], &val);
if (ret < 0)
return ret;
return val;
}
EXPORT_SYMBOL_GPL(rk806_field_read);
int rk806_field_write(struct rk806 *rk806,
enum rk806_fields field_id,
unsigned int val)
{
return regmap_field_write(rk806->rmap_fields[field_id], val);
}
EXPORT_SYMBOL_GPL(rk806_field_write);
static void rk806_irq_init(struct rk806 *rk806)
{
/* INT pin polarity active low */
rk806_field_write(rk806, INT_POL, RK806_INT_POL_LOW);
}
static int rk806_pinctrl_init(struct rk806 *rk806)
{
struct device *dev = rk806->dev;
rk806->pins = devm_kzalloc(dev,
sizeof(struct rk806_pin_info),
GFP_KERNEL);
if (!rk806->pins)
return -ENOMEM;
rk806->pins->p = devm_pinctrl_get(dev);
if (IS_ERR(rk806->pins->p)) {
rk806->pins->p = NULL;
dev_err(dev, "no pinctrl handle\n");
return 0;
}
rk806->pins->default_st = pinctrl_lookup_state(rk806->pins->p,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(rk806->pins->default_st))
dev_err(dev, "no default pinctrl state\n");
rk806->pins->power_off = pinctrl_lookup_state(rk806->pins->p,
"pmic-power-off");
if (IS_ERR(rk806->pins->power_off)) {
rk806->pins->power_off = NULL;
dev_err(dev, "no power-off pinctrl state\n");
}
rk806->pins->sleep = pinctrl_lookup_state(rk806->pins->p,
"pmic-sleep");
if (IS_ERR(rk806->pins->sleep)) {
rk806->pins->sleep = NULL;
dev_err(dev, "no sleep-setting state\n");
}
rk806->pins->reset = pinctrl_lookup_state(rk806->pins->p,
"pmic-reset");
if (IS_ERR(rk806->pins->reset)) {
rk806->pins->reset = NULL;
dev_err(dev, "no reset-setting pinctrl state\n");
}
rk806->pins->dvs = pinctrl_lookup_state(rk806->pins->p,
"pmic-dvs");
if (IS_ERR(rk806->pins->dvs)) {
rk806->pins->dvs = NULL;
dev_err(dev, "no dvs-setting pinctrl state\n");
}
return 0;
}
static irqreturn_t rk806_vb_low_irq(int irq, void *rk806)
{
return IRQ_HANDLED;
}
static int rk806_low_power_irqs(struct rk806 *rk806)
{
struct rk806_platform_data *pdata;
int ret, vb_lo_irq;
pdata = rk806->pdata;
if (!pdata->low_voltage_threshold)
return 0;
rk806_field_write(rk806, VB_LO_ACT, VB_LO_ACT_INT);
rk806_field_write(rk806, VB_LO_SEL,
(pdata->low_voltage_threshold - 2800) / 100);
vb_lo_irq = regmap_irq_get_virq(rk806->irq_data, RK806_IRQ_VB_LO);
if (vb_lo_irq < 0) {
dev_err(rk806->dev, "vb_lo_irq request failed!\n");
return vb_lo_irq;
}
ret = devm_request_threaded_irq(rk806->dev, vb_lo_irq,
NULL,
rk806_vb_low_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"rk806_vb_low", rk806);
if (ret) {
dev_err(rk806->dev, "vb_lo_irq request failed!\n");
return ret;
}
rk806->vb_lo_irq = vb_lo_irq;
disable_irq(rk806->vb_lo_irq);
enable_irq_wake(vb_lo_irq);
return 0;
}
static int rk806_parse_dt(struct rk806 *rk806)
{
struct rk806_platform_data *pdata;
struct device *dev = rk806->dev;
int ret;
pdata = rk806->pdata;
pdata->shutdown_voltage_threshold = 2700;
pdata->shutdown_temperture_threshold = 160;
pdata->hotdie_temperture_threshold = 115;
pdata->force_shutdown_enable = 1;
ret = device_property_read_u32(dev,
"low_voltage_threshold",
&pdata->low_voltage_threshold);
if (ret < 0) {
pdata->low_voltage_threshold = 0;
dev_info(dev, "low_voltage_threshold missing!\n");
} else {
if ((pdata->low_voltage_threshold > 3500) ||
(pdata->low_voltage_threshold < 2800)) {
dev_err(dev, "low_voltage_threshold out [2800 3500]!\n");
pdata->low_voltage_threshold = 2800;
}
}
ret = device_property_read_u32(dev,
"shutdown_voltage_threshold",
&pdata->shutdown_voltage_threshold);
if (ret < 0) {
pdata->force_shutdown_enable = 0;
dev_info(dev, "shutdown_voltage_threshold missing!\n");
}
if ((pdata->shutdown_voltage_threshold > 3400) ||
(pdata->shutdown_voltage_threshold < 2700)) {
dev_err(dev, "shutdown_voltage_threshold out [2700 3400]!\n");
pdata->shutdown_voltage_threshold = 2700;
}
ret = device_property_read_u32(dev,
"shutdown_temperture_threshold",
&pdata->shutdown_temperture_threshold);
if (ret < 0)
dev_info(dev, "shutdown_temperture_threshold missing!\n");
ret = device_property_read_u32(dev,
"hotdie_temperture_threshold",
&pdata->hotdie_temperture_threshold);
if (ret < 0)
dev_info(dev, "hotdie_temperture_threshold missing!\n");
return 0;
}
static int rk806_init(struct rk806 *rk806)
{
struct rk806_platform_data *pdata;
int vb_uv_sel;
pdata = rk806->pdata;
if (pdata->force_shutdown_enable) {
if (pdata->shutdown_voltage_threshold <= 2700)
vb_uv_sel = VB_UV_SEL_2700;
else
vb_uv_sel = (pdata->shutdown_voltage_threshold - 2700) / 100;
rk806_field_write(rk806, VB_UV_SEL, vb_uv_sel);
}
if (pdata->hotdie_temperture_threshold >= 160)
rk806_field_write(rk806, TSD_TEMP, TSD_TEMP_160);
rk806_low_power_irqs(rk806);
return 0;
}
int rk806_device_init(struct rk806 *rk806)
{
struct rk806_platform_data *pdata;
int name_h, name_l, chip_ver, otp_ver;
int on_source, off_source;
int ret;
int i;
pdata = devm_kzalloc(rk806->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
rk806->pdata = pdata;
for (i = 0; i < ARRAY_SIZE(rk806_reg_fields); i++) {
const struct reg_field *reg_fields = rk806_reg_fields;
rk806->rmap_fields[i] =
devm_regmap_field_alloc(rk806->dev,
rk806->regmap,
reg_fields[i]);
if (IS_ERR(rk806->rmap_fields[i])) {
dev_err(rk806->dev, "cannot allocate regmap field\n");
return PTR_ERR(rk806->rmap_fields[i]);
}
}
name_h = rk806_field_read(rk806, CHIP_NAME_H);
name_l = rk806_field_read(rk806, CHIP_NAME_L);
chip_ver = rk806_field_read(rk806, CHIP_VER);
otp_ver = rk806_field_read(rk806, OTP_VER);
dev_info(rk806->dev, "chip id: RK%x%x,ver:0x%x, 0x%x\n",
name_h, name_l, chip_ver, otp_ver);
on_source = regmap_read(rk806->regmap, RK806_ON_SOURCE, &on_source);
off_source = regmap_read(rk806->regmap, RK806_OFF_SOURCE, &off_source);
dev_info(rk806->dev, "ON: 0x%x OFF:0x%x\n", on_source, off_source);
rk806_parse_dt(rk806);
rk806_irq_init(rk806);
ret = devm_regmap_add_irq_chip(rk806->dev,
rk806->regmap,
rk806->irq,
IRQF_ONESHOT | IRQF_SHARED,
0,
&rk806_irq_chip,
&rk806->irq_data);
if (ret) {
dev_err(rk806->dev, "Failed to add IRQ chip: err = %d\n", ret);
return ret;
}
ret = devm_mfd_add_devices(rk806->dev,
PLATFORM_DEVID_AUTO,
rk806_cells,
ARRAY_SIZE(rk806_cells),
NULL,
0,
regmap_irq_get_domain(rk806->irq_data));
if (ret < 0) {
dev_err(rk806->dev, "mfd_add_devices failed: %d\n", ret);
return ret;
}
rk806_pinctrl_init(rk806);
rk806_init(rk806);
return 0;
}
EXPORT_SYMBOL_GPL(rk806_device_init);
int rk806_device_exit(struct rk806 *rk806)
{
return 0;
}
EXPORT_SYMBOL_GPL(rk806_device_exit);
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_DESCRIPTION("rk806 MFD Driver");
MODULE_LICENSE("GPL v2");

157
drivers/mfd/rk806-spi.c Normal file
View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0
/*
* SPI access driver for rockchip rk806
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*
* Author: Xu Shengfei <xsf@rock-chips.com>
*/
#include <linux/mfd/rk806.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
static const struct of_device_id rk806_spi_of_match_table[] = {
{ .compatible = "rockchip,rk806", },
{ }
};
MODULE_DEVICE_TABLE(of, rk806_spi_of_match_table);
static int rk806_spi_write(struct spi_device *spi,
char addr,
const char *data,
size_t data_len)
{
char write_cmd = RK806_CMD_WRITE | (data_len - 1);
char addrh = RK806_REG_H;
struct spi_message m;
char addrl = addr;
int ret = 0;
struct spi_transfer write_cmd_packet = {
.tx_buf = &write_cmd,
.len = sizeof(write_cmd),
};
struct spi_transfer addrl_packet = {
.tx_buf = &addrl,
.len = sizeof(addrl),
};
struct spi_transfer addrh_packet = {
.tx_buf = &addrh,
.len = sizeof(addrh),
};
struct spi_transfer data_packet = {
.tx_buf = data,
.len = data_len,
};
spi_message_init(&m);
spi_message_add_tail(&write_cmd_packet, &m);
spi_message_add_tail(&addrl_packet, &m);
spi_message_add_tail(&addrh_packet, &m);
spi_message_add_tail(&data_packet, &m);
ret = spi_sync(spi, &m);
return ret;
}
static int rk806_spi_bus_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
char buf[2];
if (count < 2) {
dev_err(&spi->dev, "regmap write err!\n");
return -EINVAL;
}
memcpy(buf, data, 2);
return rk806_spi_write(spi, buf[0], &buf[1], (count - 1));
}
static int rk806_spi_bus_read(void *context,
const void *reg,
size_t reg_size,
void *val,
size_t val_size)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
char addr;
char txbuf[3] = { 0 };
if (reg_size != sizeof(char) || val_size < 1)
return -EINVAL;
/* Copy address to read from into first element of SPI buffer. */
memcpy(&addr, reg, sizeof(char));
txbuf[0] = RK806_CMD_READ | (val_size - 1);
txbuf[1] = addr;
txbuf[2] = RK806_REG_H;
return spi_write_then_read(spi, txbuf, 3, val, val_size);
}
static const struct regmap_bus rk806_regmap_bus_spi = {
.write = rk806_spi_bus_write,
.read = rk806_spi_bus_read,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
static int rk806_spi_probe(struct spi_device *spi)
{
struct rk806 *rk806;
rk806 = devm_kzalloc(&spi->dev, sizeof(*rk806), GFP_KERNEL);
if (!rk806)
return -ENOMEM;
spi_set_drvdata(spi, rk806);
rk806->dev = &spi->dev;
rk806->irq = spi->irq;
rk806->regmap = devm_regmap_init(&spi->dev,
&rk806_regmap_bus_spi,
&spi->dev,
&rk806_regmap_config_spi);
if (IS_ERR(rk806->regmap)) {
dev_err(rk806->dev, "Failed to initialize register map\n");
return PTR_ERR(rk806->regmap);
}
return rk806_device_init(rk806);
}
static int rk806_spi_remove(struct spi_device *spi)
{
struct rk806 *rk806 = spi_get_drvdata(spi);
return rk806_device_exit(rk806);
}
static const struct spi_device_id rk806_spi_id_table[] = {
{ "rk806", 0 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, rk806_spi_id_table);
static struct spi_driver rk806_spi_driver = {
.driver = {
.name = "rk806",
.owner = THIS_MODULE,
.of_match_table = rk806_spi_of_match_table,
},
.probe = rk806_spi_probe,
.remove = rk806_spi_remove,
.id_table = rk806_spi_id_table,
};
module_spi_driver(rk806_spi_driver);
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_DESCRIPTION("RK806 SPI Interface Driver");
MODULE_LICENSE("GPL v2");

View File

@ -367,6 +367,15 @@ config PINCTRL_RK805
help
This selects the pinctrl driver for RK805.
config PINCTRL_RK806
tristate "Pinctrl and GPIO driver for RK806 PMIC"
depends on MFD_RK806
select GPIOLIB
select PINMUX
select GENERIC_PINCONF
help
This selects the pinctrl driver for RK806
config PINCTRL_OCELOT
bool "Pinctrl driver for the Microsemi Ocelot and Jaguar2 SoCs"
depends on OF

View File

@ -45,6 +45,7 @@ obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
obj-$(CONFIG_PINCTRL_RK806) += pinctrl-rk806.o
obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o
obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o

View File

@ -0,0 +1,577 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Pinctrl driver for Rockchip RK806 PMIC
*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*
* Author: Xu Shengfei <xsf@rock-chips.com>
*/
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/mfd/rk806.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include "pinctrl-utils.h"
struct rk806_pin_function {
const char *name;
const char *const *groups;
unsigned int ngroups;
int mux_option;
};
struct rk806_pin_group {
const char *name;
const unsigned int pins[1];
unsigned int npins;
};
/*
* @reg: gpio setting register;
* @fun_mask: functions select mask value, when set is gpio;
* @dir_mask: input or output mask value, when set is output, otherwise input;
* @val_mask: gpio set value, when set is level high, otherwise low;
*
* Different PMIC has different pin features, belowing 3 mask members are not
* all necessary for every PMIC. For example, RK805 has 2 pins that can be used
* as output only GPIOs, so func_mask and dir_mask are not needed. RK816 has 1
* pin that can be used as TS/GPIO, so fun_mask, dir_mask and val_mask are all
* necessary.
*/
struct rk806_pin_config {
u8 fun_reg;
u8 fun_msk;
u8 reg;
u8 dir_msk;
u8 val_msk;
};
struct rk806_pctrl_info {
struct rk806 *rk806;
struct device *dev;
struct pinctrl_dev *pctl;
struct gpio_chip gpio_chip;
struct pinctrl_desc pinctrl_desc;
const struct rk806_pin_function *functions;
unsigned int num_functions;
const struct rk806_pin_group *groups;
int num_pin_groups;
const struct pinctrl_pin_desc *pins;
unsigned int num_pins;
const struct rk806_pin_config *pin_cfg;
};
#define RK806_PWRCTRL1_DR BIT(0)
#define RK806_PWRCTRL2_DR BIT(1)
#define RK806_PWRCTRL3_DR BIT(2)
#define RK806_PWRCTRL1_DATA BIT(4)
#define RK806_PWRCTRL2_DATA BIT(5)
#define RK806_PWRCTRL3_DATA BIT(6)
#define RK806_PWRCTRL1_FUN 0x07
#define RK806_PWRCTRL2_FUN 0x70
#define RK806_PWRCTRL3_FUN 0x07
enum rk806_pinmux_option {
RK806_PINMUX_FUN0 = 0,
RK806_PINMUX_FUN1,
RK806_PINMUX_FUN2,
RK806_PINMUX_FUN3,
RK806_PINMUX_FUN4,
RK806_PINMUX_FUN5,
};
enum {
RK806_GPIO_DVS1,
RK806_GPIO_DVS2,
RK806_GPIO_DVS3
};
static const char *const rk806_gpio_groups[] = {
"gpio_pwrctrl1",
"gpio_pwrctrl2",
"gpio_pwrctrl3",
};
static const struct pinctrl_pin_desc rk806_pins_desc[] = {
PINCTRL_PIN(RK806_GPIO_DVS1, "gpio_pwrctrl1"), /* dvs1 pin */
PINCTRL_PIN(RK806_GPIO_DVS2, "gpio_pwrctrl2"), /* dvs2 pin */
PINCTRL_PIN(RK806_GPIO_DVS3, "gpio_pwrctrl3") /* dvs3 pin */
};
static const struct rk806_pin_function rk806_pin_functions[] = {
{
.name = "pin_fun0",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN0,
},
{
.name = "pin_fun1",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN1,
},
{
.name = "pin_fun2",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN2,
},
{
.name = "pin_fun3",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN3,
},
{
.name = "pin_fun4",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN4,
},
{
.name = "pin_fun5",
.groups = rk806_gpio_groups,
.ngroups = ARRAY_SIZE(rk806_gpio_groups),
.mux_option = RK806_PINMUX_FUN5,
},
};
static const struct rk806_pin_group rk806_pin_groups[] = {
{
.name = "gpio_pwrctrl1",
.pins = { RK806_GPIO_DVS1 },
.npins = 1,
},
{
.name = "gpio_pwrctrl2",
.pins = { RK806_GPIO_DVS2 },
.npins = 1,
},
{
.name = "gpio_pwrctrl3",
.pins = { RK806_GPIO_DVS3 },
.npins = 1,
}
};
static struct rk806_pin_config rk806_gpio_cfgs[] = {
{
.fun_reg = RK806_SLEEP_CONFIG0,
.fun_msk = RK806_PWRCTRL1_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL1_DATA,
.dir_msk = RK806_PWRCTRL1_DR,
},
{
.fun_reg = RK806_SLEEP_CONFIG0,
.fun_msk = RK806_PWRCTRL2_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL2_DATA,
.dir_msk = RK806_PWRCTRL2_DR,
},
{
.fun_reg = RK806_SLEEP_CONFIG1,
.fun_msk = RK806_PWRCTRL3_FUN,
.reg = RK806_SLEEP_GPIO,
.val_msk = RK806_PWRCTRL3_DATA,
.dir_msk = RK806_PWRCTRL3_DR,
}
};
/* generic gpio chip */
static int rk806_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct rk806_pctrl_info *pci = gpiochip_get_data(chip);
int ret, val;
if (!pci->pin_cfg[offset].val_msk) {
dev_dbg(pci->dev, "getting gpio%d value is not support\n",
offset);
return -1;
}
ret = regmap_read(pci->rk806->regmap, pci->pin_cfg[offset].reg, &val);
if (ret) {
dev_err(pci->dev, "get gpio%d value failed\n", offset);
return ret;
}
return !!(val & pci->pin_cfg[offset].val_msk);
}
static void rk806_gpio_set(struct gpio_chip *chip,
unsigned int offset,
int value)
{
struct rk806_pctrl_info *pci = gpiochip_get_data(chip);
int ret;
if (!pci->pin_cfg[offset].val_msk)
return;
ret = regmap_update_bits(pci->rk806->regmap,
pci->pin_cfg[offset].reg,
pci->pin_cfg[offset].val_msk,
value ? pci->pin_cfg[offset].val_msk : 0);
if (ret)
dev_err(pci->dev, "set gpio%d value %d failed\n",
offset, value);
}
static int rk806_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
return pinctrl_gpio_direction_input(chip->base + offset);
}
static int rk806_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset,
int value)
{
rk806_gpio_set(chip, offset, value);
return pinctrl_gpio_direction_output(chip->base + offset);
}
static int rk806_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct rk806_pctrl_info *pci = gpiochip_get_data(chip);
unsigned int val;
int ret;
/* default output */
if (!pci->pin_cfg[offset].dir_msk)
return 0;
ret = regmap_read(pci->rk806->regmap,
pci->pin_cfg[offset].reg,
&val);
if (ret) {
dev_err(pci->dev, "get gpio%d direction failed\n", offset);
return ret;
}
return !(val & pci->pin_cfg[offset].dir_msk);
}
static struct gpio_chip rk806_gpio_chip = {
.label = "rk806-gpio",
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.get_direction = rk806_gpio_get_direction,
.get = rk806_gpio_get,
.set = rk806_gpio_set,
.direction_input = rk806_gpio_direction_input,
.direction_output = rk806_gpio_direction_output,
.can_sleep = true,
.base = -1,
.owner = THIS_MODULE,
};
/* generic pinctrl */
static int rk806_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
return pci->num_pin_groups;
}
static const char *rk806_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int group)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
return pci->groups[group].name;
}
static int rk806_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int group,
const unsigned int **pins,
unsigned int *num_pins)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
*pins = pci->groups[group].pins;
*num_pins = pci->groups[group].npins;
return 0;
}
static const struct pinctrl_ops rk806_pinctrl_ops = {
.get_groups_count = rk806_pinctrl_get_groups_count,
.get_group_name = rk806_pinctrl_get_group_name,
.get_group_pins = rk806_pinctrl_get_group_pins,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_free_map,
};
static int rk806_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
return pci->num_functions;
}
static const char *rk806_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
unsigned int function)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
return pci->functions[function].name;
}
static int rk806_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
unsigned int function,
const char *const **groups,
unsigned int *const num_groups)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
*groups = pci->functions[function].groups;
*num_groups = pci->functions[function].ngroups;
return 0;
}
static int _rk806_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned int offset,
int mux)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
int ret;
if (!pci->pin_cfg[offset].fun_msk)
return 0;
mux <<= ffs(pci->pin_cfg[offset].fun_msk) - 1;
ret = regmap_update_bits(pci->rk806->regmap,
pci->pin_cfg[offset].fun_reg,
pci->pin_cfg[offset].fun_msk, mux);
if (ret)
dev_err(pci->dev, "set gpio%d func%d failed\n", offset, mux);
return ret;
}
static int rk806_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned int function,
unsigned int group)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
int mux = pci->functions[function].mux_option;
int offset = group;
return _rk806_pinctrl_set_mux(pctldev, offset, mux);
}
static int rk806_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset, bool input)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
int ret;
/* set direction */
if (!pci->pin_cfg[offset].dir_msk)
return 0;
ret = regmap_update_bits(pci->rk806->regmap,
pci->pin_cfg[offset].reg,
pci->pin_cfg[offset].dir_msk,
input ? 0 : pci->pin_cfg[offset].dir_msk);
if (ret) {
dev_err(pci->dev, "set gpio%d direction failed\n", offset);
return ret;
}
return ret;
}
static int rk806_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset)
{
return _rk806_pinctrl_set_mux(pctldev, offset, RK806_PINMUX_FUN5);
}
static const struct pinmux_ops rk806_pinmux_ops = {
.gpio_request_enable = rk806_pinctrl_gpio_request_enable,
.get_functions_count = rk806_pinctrl_get_funcs_count,
.get_function_name = rk806_pinctrl_get_func_name,
.get_function_groups = rk806_pinctrl_get_func_groups,
.set_mux = rk806_pinctrl_set_mux,
.gpio_set_direction = rk806_pmx_gpio_set_direction,
};
static int rk806_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int pin,
unsigned long *config)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
u32 arg = 0;
switch (param) {
case PIN_CONFIG_OUTPUT:
case PIN_CONFIG_INPUT_ENABLE:
arg = rk806_gpio_get(&pci->gpio_chip, pin);
break;
default:
dev_err(pci->dev, "Properties not supported\n");
return -EOPNOTSUPP;
}
*config = pinconf_to_config_packed(param, (u16)arg);
return 0;
}
static int rk806_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin,
unsigned long *configs,
unsigned int num_configs)
{
struct rk806_pctrl_info *pci = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u32 i, arg = 0;
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
switch (param) {
case PIN_CONFIG_OUTPUT:
rk806_pmx_gpio_set_direction(pctldev, NULL, pin, false);
rk806_gpio_set(&pci->gpio_chip, pin, arg);
break;
case PIN_CONFIG_INPUT_ENABLE:
if (arg)
rk806_pmx_gpio_set_direction(pctldev,
NULL,
pin,
true);
break;
default:
dev_err(pci->dev, "Properties not supported\n");
return -EOPNOTSUPP;
}
}
return 0;
}
static const struct pinconf_ops rk806_pinconf_ops = {
.pin_config_get = rk806_pinconf_get,
.pin_config_set = rk806_pinconf_set,
};
static struct pinctrl_desc rk806_pinctrl_desc = {
.name = "rk806-pinctrl",
.pctlops = &rk806_pinctrl_ops,
.pmxops = &rk806_pinmux_ops,
.confops = &rk806_pinconf_ops,
.owner = THIS_MODULE,
};
static int rk806_pinctrl_probe(struct platform_device *pdev)
{
struct rk806_pctrl_info *pci;
struct device_node *np;
int ret;
pci = devm_kzalloc(&pdev->dev, sizeof(*pci), GFP_KERNEL);
if (!pci)
return -ENOMEM;
pci->dev = &pdev->dev;
np = of_get_child_by_name(pdev->dev.parent->of_node, "pinctrl_rk806");
if (np)
pci->dev->of_node = np;
else
pci->dev->of_node = pdev->dev.parent->of_node;
pci->rk806 = dev_get_drvdata(pdev->dev.parent);
platform_set_drvdata(pdev, pci);
pci->pinctrl_desc = rk806_pinctrl_desc;
pci->gpio_chip = rk806_gpio_chip;
pci->pins = rk806_pins_desc;
pci->num_pins = ARRAY_SIZE(rk806_pins_desc);
pci->functions = rk806_pin_functions;
pci->num_functions = ARRAY_SIZE(rk806_pin_functions);
pci->groups = rk806_pin_groups;
pci->num_pin_groups = ARRAY_SIZE(rk806_pin_groups);
pci->pinctrl_desc.pins = rk806_pins_desc;
pci->pinctrl_desc.npins = ARRAY_SIZE(rk806_pins_desc);
pci->pin_cfg = rk806_gpio_cfgs;
pci->gpio_chip.ngpio = ARRAY_SIZE(rk806_gpio_cfgs);
pci->gpio_chip.parent = &pdev->dev;
if (np)
pci->gpio_chip.of_node = np;
else
pci->gpio_chip.of_node = pdev->dev.parent->of_node;
/* Add gpiochip */
ret = devm_gpiochip_add_data(&pdev->dev, &pci->gpio_chip, pci);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't add gpiochip\n");
return ret;
}
/* Add pinctrl */
pci->pctl = devm_pinctrl_register(&pdev->dev, &pci->pinctrl_desc, pci);
if (IS_ERR(pci->pctl)) {
dev_err(&pdev->dev, "Couldn't add pinctrl\n");
return PTR_ERR(pci->pctl);
}
/* Add pin range */
ret = gpiochip_add_pin_range(&pci->gpio_chip,
dev_name(&pdev->dev),
0,
0,
pci->gpio_chip.ngpio);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't add gpiochip pin range\n");
return ret;
}
return 0;
}
static struct platform_driver rk806_pinctrl_driver = {
.probe = rk806_pinctrl_probe,
.driver = {
.name = "rk806-pinctrl",
},
};
static int __init rk806_pinctrl_driver_register(void)
{
return platform_driver_register(&rk806_pinctrl_driver);
}
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
subsys_initcall(rk806_pinctrl_driver_register);
#else
fs_initcall_sync(rk806_pinctrl_driver_register);
#endif
MODULE_DESCRIPTION("RK806 pin control and GPIO driver");
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
MODULE_LICENSE("GPL v2");

View File

@ -929,6 +929,14 @@ config REGULATOR_RC5T583
through regulator interface. The device supports multiple DCDC/LDO
outputs which can be controlled by i2c communication.
config REGULATOR_RK806
tristate "Rockchip RK806 Power regulator"
depends on MFD_RK806
help
Select this option to enable the power regulator of ROCKCHIP
PMIC RK806. The device supports multiple DCDC/LDO
outputs which can be controlled by spi communication.
config REGULATOR_RK808
tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power regulators"
depends on MFD_RK808

View File

@ -114,6 +114,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY) += rpi-panel-attiny-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_RK806) += rk806-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o

File diff suppressed because it is too large Load Diff

521
include/linux/mfd/rk806.h Normal file
View File

@ -0,0 +1,521 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
*/
#ifndef __LINUX_REGULATOR_RK806_H
#define __LINUX_REGULATOR_RK806_H
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#define RK806_POWER_EN0 0x0
#define RK806_POWER_EN1 0x1
#define RK806_POWER_EN2 0x2
#define RK806_POWER_EN3 0x3
#define RK806_POWER_EN4 0x4
#define RK806_POWER_EN5 0x5
#define RK806_POWER_SLP_EN0 0x6
#define RK806_POWER_SLP_EN1 0x7
#define RK806_POWER_SLP_EN2 0x8
#define RK806_POWER_DISCHRG_EN0 0x9
#define RK806_POWER_DISCHRG_EN1 0xA
#define RK806_POWER_DISCHRG_EN2 0xB
#define RK806_BUCK_FB_CONFIG 0xC
#define RK806_SLP_LP_CONFIG 0xD
#define RK806_POWER_FPWM_EN0 0xE
#define RK806_POWER_FPWM_EN1 0xF
#define RK806_BUCK1_CONFIG 0x10
#define RK806_BUCK2_CONFIG 0x11
#define RK806_BUCK3_CONFIG 0x12
#define RK806_BUCK4_CONFIG 0x13
#define RK806_BUCK5_CONFIG 0x14
#define RK806_BUCK6_CONFIG 0x15
#define RK806_BUCK7_CONFIG 0x16
#define RK806_BUCK8_CONFIG 0x17
#define RK806_BUCK9_CONFIG 0x18
#define RK806_BUCK10_CONFIG 0x19
#define RK806_BUCK1_ON_VSEL 0x1A
#define RK806_BUCK2_ON_VSEL 0x1B
#define RK806_BUCK3_ON_VSEL 0x1C
#define RK806_BUCK4_ON_VSEL 0x1D
#define RK806_BUCK5_ON_VSEL 0x1E
#define RK806_BUCK6_ON_VSEL 0x1F
#define RK806_BUCK7_ON_VSEL 0x20
#define RK806_BUCK8_ON_VSEL 0x21
#define RK806_BUCK9_ON_VSEL 0x22
#define RK806_BUCK10_ON_VSEL 0x23
#define RK806_BUCK1_SLP_VSEL 0x24
#define RK806_BUCK2_SLP_VSEL 0x25
#define RK806_BUCK3_SLP_VSEL 0x26
#define RK806_BUCK4_SLP_VSEL 0x27
#define RK806_BUCK5_SLP_VSEL 0x28
#define RK806_BUCK6_SLP_VSEL 0x29
#define RK806_BUCK7_SLP_VSEL 0x2A
#define RK806_BUCK8_SLP_VSEL 0x2B
#define RK806_BUCK9_SLP_VSEL 0x2D
#define RK806_BUCK10_SLP_VSEL 0x2E
#define RK806_BUCK_DEBUG1 0x30
#define RK806_BUCK_DEBUG2 0x31
#define RK806_BUCK_DEBUG3 0x32
#define RK806_BUCK_DEBUG4 0x33
#define RK806_BUCK_DEBUG5 0x34
#define RK806_BUCK_DEBUG6 0x35
#define RK806_BUCK_DEBUG7 0x36
#define RK806_BUCK_DEBUG8 0x37
#define RK806_BUCK_DEBUG9 0x38
#define RK806_BUCK_DEBUG10 0x39
#define RK806_BUCK_DEBUG11 0x3A
#define RK806_BUCK_DEBUG12 0x3B
#define RK806_BUCK_DEBUG13 0x3C
#define RK806_BUCK_DEBUG14 0x3D
#define RK806_BUCK_DEBUG15 0x3E
#define RK806_BUCK_DEBUG16 0x3F
#define RK806_BUCK_DEBUG17 0x40
#define RK806_BUCK_DEBUG18 0x41
#define RK806_NLDO_IMAX 0x42
#define RK806_NLDO1_ON_VSEL 0x43
#define RK806_NLDO2_ON_VSEL 0x44
#define RK806_NLDO3_ON_VSEL 0x45
#define RK806_NLDO4_ON_VSEL 0x46
#define RK806_NLDO5_ON_VSEL 0x47
#define RK806_NLDO1_SLP_VSEL 0x48
#define RK806_NLDO2_SLP_VSEL 0x49
#define RK806_NLDO3_SLP_VSEL 0x4A
#define RK806_NLDO4_SLP_VSEL 0x4B
#define RK806_NLDO5_SLP_VSEL 0x4C
#define RK806_PLDO_IMAX 0x4D
#define RK806_PLDO1_ON_VSEL 0x4E
#define RK806_PLDO2_ON_VSEL 0x4F
#define RK806_PLDO3_ON_VSEL 0x50
#define RK806_PLDO4_ON_VSEL 0x51
#define RK806_PLDO5_ON_VSEL 0x52
#define RK806_PLDO6_ON_VSEL 0x53
#define RK806_PLDO1_SLP_VSEL 0x54
#define RK806_PLDO2_SLP_VSEL 0x55
#define RK806_PLDO3_SLP_VSEL 0x56
#define RK806_PLDO4_SLP_VSEL 0x57
#define RK806_PLDO5_SLP_VSEL 0x58
#define RK806_PLDO6_SLP_VSEL 0x59
#define RK806_CHIP_NAME 0x5A
#define RK806_CHIP_VER 0x5B
#define RK806_OTP_VER 0x5C
#define RK806_SYS_STS 0x5D
#define RK806_SYS_CFG0 0x5E
#define RK806_SYS_CFG1 0x5F
#define RK806_SYS_OPTION 0x61
#define RK806_SLEEP_CONFIG0 0x62
#define RK806_SLEEP_CONFIG1 0x63
#define RK806_SLEEP_CTR_SEL0 0x64
#define RK806_SLEEP_CTR_SEL1 0x65
#define RK806_SLEEP_CTR_SEL2 0x66
#define RK806_SLEEP_CTR_SEL3 0x67
#define RK806_SLEEP_CTR_SEL4 0x68
#define RK806_SLEEP_CTR_SEL5 0x69
#define RK806_DVS_CTRL_SEL0 0x6A
#define RK806_DVS_CTRL_SEL1 0x6B
#define RK806_DVS_CTRL_SEL2 0x6C
#define RK806_DVS_CTRL_SEL3 0x6D
#define RK806_DVS_CTRL_SEL4 0x6E
#define RK806_DVS_CTRL_SEL5 0x6F
#define RK806_DVS_START_CTRL 0x70
#define RK806_SLEEP_GPIO 0x71
#define RK806_SYS_CFG3 0x72
#define RK806_ON_SOURCE 0x74
#define RK806_OFF_SOURCE 0x75
#define RK806_PWRON_KEY 0x76
#define RK806_INT_STS0 0x77
#define RK806_INT_MSK0 0x78
#define RK806_INT_STS1 0x79
#define RK806_INT_MSK1 0x7A
#define RK806_GPIO_INT_CONFIG 0x7B
#define RK806_DATA_REG0 0x7C
#define RK806_DATA_REG1 0x7D
#define RK806_DATA_REG2 0x7E
#define RK806_DATA_REG3 0x7F
#define RK806_DATA_REG4 0x80
#define RK806_DATA_REG5 0x81
#define RK806_DATA_REG6 0x82
#define RK806_DATA_REG7 0x83
#define RK806_DATA_REG8 0x84
#define RK806_DATA_REG9 0x85
#define RK806_DATA_REG10 0x86
#define RK806_DATA_REG11 0x87
#define RK806_DATA_REG12 0x88
#define RK806_DATA_REG13 0x89
#define RK806_DATA_REG14 0x8A
#define RK806_DATA_REG15 0x8B
#define RK806_TM_REG 0x8C
#define RK806_OTP_EN_REG 0x8D
#define RK806_FUNC_OTP_EN_REG 0x8E
#define RK806_TEST_REG1 0x8F
#define RK806_TEST_REG2 0x90
#define RK806_TEST_REG3 0x91
#define RK806_TEST_REG4 0x92
#define RK806_TEST_REG5 0x93
#define RK806_BUCK_VSEL_OTP_REG0 0x94
#define RK806_BUCK_VSEL_OTP_REG1 0x95
#define RK806_BUCK_VSEL_OTP_REG2 0x96
#define RK806_BUCK_VSEL_OTP_REG3 0x97
#define RK806_BUCK_VSEL_OTP_REG4 0x98
#define RK806_BUCK_VSEL_OTP_REG5 0x99
#define RK806_BUCK_VSEL_OTP_REG6 0x9A
#define RK806_BUCK_VSEL_OTP_REG7 0x9B
#define RK806_BUCK_VSEL_OTP_REG8 0x9C
#define RK806_BUCK_VSEL_OTP_REG9 0x9D
#define RK806_NLDO1_VSEL_OTP_REG0 0x9E
#define RK806_NLDO1_VSEL_OTP_REG1 0x9F
#define RK806_NLDO1_VSEL_OTP_REG2 0xA0
#define RK806_NLDO1_VSEL_OTP_REG3 0xA1
#define RK806_NLDO1_VSEL_OTP_REG4 0xA2
#define RK806_PLDO_VSEL_OTP_REG0 0xA3
#define RK806_PLDO_VSEL_OTP_REG1 0xA4
#define RK806_PLDO_VSEL_OTP_REG2 0xA5
#define RK806_PLDO_VSEL_OTP_REG3 0xA6
#define RK806_PLDO_VSEL_OTP_REG4 0xA7
#define RK806_PLDO_VSEL_OTP_REG5 0xA8
#define RK806_BUCK_EN_OTP_REG1 0xA9
#define RK806_NLDO_EN_OTP_REG1 0xAA
#define RK806_PLDO_EN_OTP_REG1 0xAB
#define RK806_BUCK_FB_RES_OTP_REG1 0xAC
#define RK806_OTP_RESEV_REG0 0xAD
#define RK806_OTP_RESEV_REG1 0xAE
#define RK806_OTP_RESEV_REG2 0xAF
#define RK806_OTP_RESEV_REG3 0xB0
#define RK806_OTP_RESEV_REG4 0xB1
#define RK806_BUCK_SEQ_REG0 0xB2
#define RK806_BUCK_SEQ_REG1 0xB3
#define RK806_BUCK_SEQ_REG2 0xB4
#define RK806_BUCK_SEQ_REG3 0xB5
#define RK806_BUCK_SEQ_REG4 0xB6
#define RK806_BUCK_SEQ_REG5 0xB7
#define RK806_BUCK_SEQ_REG6 0xB8
#define RK806_BUCK_SEQ_REG7 0xB9
#define RK806_BUCK_SEQ_REG8 0xBA
#define RK806_BUCK_SEQ_REG9 0xBB
#define RK806_BUCK_SEQ_REG10 0xBC
#define RK806_BUCK_SEQ_REG11 0xBD
#define RK806_BUCK_SEQ_REG12 0xBE
#define RK806_BUCK_SEQ_REG13 0xBF
#define RK806_BUCK_SEQ_REG14 0xC0
#define RK806_BUCK_SEQ_REG15 0xC1
#define RK806_BUCK_SEQ_REG16 0xC2
#define RK806_BUCK_SEQ_REG17 0xC3
#define RK806_HK_TRIM_REG1 0xC4
#define RK806_HK_TRIM_REG2 0xC5
#define RK806_BUCK_REF_TRIM_REG1 0xC6
#define RK806_BUCK_REF_TRIM_REG2 0xC7
#define RK806_BUCK_REF_TRIM_REG3 0xC8
#define RK806_BUCK_REF_TRIM_REG4 0xC9
#define RK806_BUCK_REF_TRIM_REG5 0xCA
#define RK806_BUCK_OSC_TRIM_REG1 0xCB
#define RK806_BUCK_OSC_TRIM_REG2 0xCC
#define RK806_BUCK_OSC_TRIM_REG3 0xCD
#define RK806_BUCK_OSC_TRIM_REG4 0xCE
#define RK806_BUCK_OSC_TRIM_REG5 0xCF
#define RK806_BUCK_TRIM_ZCDIOS_REG1 0xD0
#define RK806_BUCK_TRIM_ZCDIOS_REG2 0xD1
#define RK806_NLDO_TRIM_REG1 0xD2
#define RK806_NLDO_TRIM_REG2 0xD3
#define RK806_NLDO_TRIM_REG3 0xD4
#define RK806_PLDO_TRIM_REG1 0xD5
#define RK806_PLDO_TRIM_REG2 0xD6
#define RK806_PLDO_TRIM_REG3 0xD7
#define RK806_TRIM_ICOMP_REG1 0xD8
#define RK806_TRIM_ICOMP_REG2 0xD9
#define RK806_EFUSE_CONTROL_REGH 0xDA
#define RK806_FUSE_PROG_REG 0xDB
#define RK806_MAIN_FSM_STS_REG 0xDD
#define RK806_FSM_REG 0xDE
#define RK806_TOP_RESEV_OFFR 0xEC
#define RK806_TOP_RESEV_POR 0xED
#define RK806_BUCK_VRSN_REG1 0xEE
#define RK806_BUCK_VRSN_REG2 0xEF
#define RK806_NLDO_RLOAD_SEL_REG1 0xF0
#define RK806_PLDO_RLOAD_SEL_REG1 0xF1
#define RK806_PLDO_RLOAD_SEL_REG2 0xF2
#define RK806_BUCK_CMIN_MX_REG1 0xF3
#define RK806_BUCK_CMIN_MX_REG2 0xF4
#define RK806_BUCK_FREQ_SET_REG1 0xF5
#define RK806_BUCK_FREQ_SET_REG2 0xF6
#define RK806_BUCK_RS_MEABS_REG1 0xF7
#define RK806_BUCK_RS_MEABS_REG2 0xF8
#define RK806_BUCK_RS_ZDLEB_REG1 0xF9
#define RK806_BUCK_RS_ZDLEB_REG2 0xFA
#define RK806_BUCK_RSERVE_REG1 0xFB
#define RK806_BUCK_RSERVE_REG2 0xFC
#define RK806_BUCK_RSERVE_REG3 0xFD
#define RK806_BUCK_RSERVE_REG4 0xFE
#define RK806_BUCK_RSERVE_REG5 0xFF
/* INT_STS Register field definitions */
#define RK806_INT_STS_PWRON_FALL BIT(0)
#define RK806_INT_STS_PWRON_RISE BIT(1)
#define RK806_INT_STS_PWRON BIT(2)
#define RK806_INT_STS_PWRON_LP BIT(3)
#define RK806_INT_STS_HOTDIE BIT(4)
#define RK806_INT_STS_VDC_RISE BIT(5)
#define RK806_INT_STS_VDC_FALL BIT(6)
#define RK806_INT_STS_VB_LO BIT(7)
#define RK806_INT_STS_REV0 BIT(0)
#define RK806_INT_STS_REV1 BIT(1)
#define RK806_INT_STS_REV2 BIT(2)
#define RK806_INT_STS_REV3 BIT(3)
#define RK806_INT_STS_SLP3_GPIO BIT(4)
#define RK806_INT_STS_SLP2_GPIO BIT(5)
#define RK806_INT_STS_SLP1_GPIO BIT(6)
#define RK806_INT_STS_WDT BIT(7)
/* spi command */
#define RK806_CMD_READ 0
#define RK806_CMD_WRITE BIT(7)
#define RK806_CMD_CRC_EN BIT(6)
#define RK806_CMD_CRC_DIS 0
#define RK806_CMD_LEN_MSK 0x0f
#define RK806_REG_H 0x00
enum rk806_reg_id {
RK806_ID_DCDC1 = 0,
RK806_ID_DCDC2,
RK806_ID_DCDC3,
RK806_ID_DCDC4,
RK806_ID_DCDC5,
RK806_ID_DCDC6,
RK806_ID_DCDC7,
RK806_ID_DCDC8,
RK806_ID_DCDC9,
RK806_ID_DCDC10,
RK806_ID_NLDO1,
RK806_ID_NLDO2,
RK806_ID_NLDO3,
RK806_ID_NLDO4,
RK806_ID_NLDO5,
RK806_ID_PLDO1,
RK806_ID_PLDO2,
RK806_ID_PLDO3,
RK806_ID_PLDO4,
RK806_ID_PLDO5,
RK806_ID_PLDO6,
RK806_ID_END,
};
/* Define the rk806 IRQ numbers */
enum rk806_irqs {
/* INT_STS0 registers */
RK806_IRQ_PWRON_FALL,
RK806_IRQ_PWRON_RISE,
RK806_IRQ_PWRON,
RK806_IRQ_PWRON_LP,
RK806_IRQ_HOTDIE,
RK806_IRQ_VDC_RISE,
RK806_IRQ_VDC_FALL,
RK806_IRQ_VB_LO,
/* INT_STS0 registers */
RK806_IRQ_REV0,
RK806_IRQ_REV1,
RK806_IRQ_REV2,
RK806_IRQ_REV3,
RK806_IRQ_SLP3_GPIO,
RK806_IRQ_SLP2_GPIO,
RK806_IRQ_SLP1_GPIO,
RK806_IRQ_WDT,
};
/* VCC1 low voltage threshold */
enum rk806_lv_sel {
VB_LO_SEL_2800,
VB_LO_SEL_2900,
VB_LO_SEL_3000,
VB_LO_SEL_3100,
VB_LO_SEL_3200,
VB_LO_SEL_3300,
VB_LO_SEL_3400,
VB_LO_SEL_3500,
};
/* system shut down voltage select */
enum rk806_uv_sel {
VB_UV_SEL_2700,
VB_UV_SEL_2800,
VB_UV_SEL_2900,
VB_UV_SEL_3000,
VB_UV_SEL_3100,
VB_UV_SEL_3200,
VB_UV_SEL_3300,
VB_UV_SEL_3400,
};
/* pin function */
enum rk806_pin_fun {
RK806_PIN_FUN_NULL,
RK806_PIN_FUN_SLP,
RK806_PIN_FUN_PWROFF,
RK806_PIN_FUN_RST,
RK806_PIN_FUN_DVS,
RK806_PIN_FUN_GPIO,
};
/* pin pol */
enum rk806_pin_level {
RK806_PIN_POL_LOW,
RK806_PIN_POL_HIGH,
};
enum rk806_pin_ctr_sel {
CTR_SEL_PIN1,
CTR_SEL_PIN2,
CTR_SEL_PIN3,
};
enum rk806_start_dvs_sel {
CTR_SEL_DVS_START1,
CTR_SEL_DVS_START2,
CTR_SEL_DVS_START3,
};
enum rk806_pin_dr_sel {
RK806_PIN_INPUT,
RK806_PIN_OUTPUT,
};
enum rk806_int_pol {
RK806_INT_POL_LOW,
RK806_INT_POL_HIGH,
};
enum rk806_int_fun {
RK806_INT_ONLY,
RK806_INT_ADN_WKUP,
};
enum rk806_dvs_mode {
RK806_DVS_NOT_SUPPORT,
RK806_DVS_BY_CTR_PIN1,
RK806_DVS_BY_CTR_PIN2,
RK806_DVS_BY_CTR_PIN3,
RK806_DVS_BY_CTR_START1,
RK806_DVS_BY_CTR_START2,
RK806_DVS_BY_CTR_START3,
RK806_DVS_END,
};
enum rk806_fields {
CHIP_NAME_H, CHIP_NAME_L, CHIP_VER, OTP_VER,
POWER_EN0, POWER_EN1, POWER_EN2, POWER_EN3, POWER_EN4, POWER_EN5,
BUCK4_EN_MASK, BUCK3_EN_MASK, BUCK2_EN_MASK, BUCK1_EN_MASK,
BUCK4_EN, BUCK3_EN, BUCK2_EN, BUCK1_EN,
BUCK8_EN_MASK, BUCK7_EN_MASK, BUCK6_EN_MASK, BUCK5_EN_MASK,
BUCK8_EN, BUCK7_EN, BUCK6_EN, BUCK5_EN,
BUCK10_EN_MASK, BUCK9_EN_MASK, BUCK10_EN, BUCK9_EN,
NLDO4_EN_MASK, NLDO3_EN_MASK, NLDO2_EN_MASK, NLDO1_EN_MASK,
NLDO4_EN, NLDO3_EN, NLDO2_EN, NLDO1_EN,
PLDO4_EN_MASK, PLDO3_EN_MASK, PLDO2_EN_MASK, PLDO1_EN_MASK,
PLDO4_EN, PLDO3_EN, PLDO2_EN, PLDO1_EN,
NLDO5_EN_MASK, PLDO6_EN_MASK, PLDO5_EN_MASK,
NLDO5_EN, PLDO6_EN, PLDO5_EN,
BUCK8_SLP_EN, BUCK7_SLP_EN, BUCK6_SLP_EN, BUCK5_SLP_EN, BUCK4_SLP_EN,
BUCK3_SLP_EN, BUCK2_SLP_EN, BUCK1_SLP_EN,
BUCK10_SLP_EN, BUCK9_SLP_EN, NLDO5_SLP_EN, NLDO4_SLP_EN, NLDO3_SLP_EN,
NLDO2_SLP_EN, NLDO1_SLP_EN,
PLDO6_SLP_EN, PLDO5_SLP_EN, PLDO4_SLP_EN, PLDO3_SLP_EN,
PLDO2_SLP_EN, PLDO1_SLP_EN,
BUCK1_ON_VSEL, BUCK2_ON_VSEL, BUCK3_ON_VSEL, BUCK4_ON_VSEL, BUCK5_ON_VSEL,
BUCK6_ON_VSEL, BUCK7_ON_VSEL, BUCK8_ON_VSEL, BUCK9_ON_VSEL, BUCK10_ON_VSEL,
BUCK1_SLP_VSEL, BUCK2_SLP_VSEL, BUCK3_SLP_VSEL, BUCK4_SLP_VSEL, BUCK5_SLP_VSEL,
BUCK6_SLP_VSEL, BUCK7_SLP_VSEL, BUCK8_SLP_VSEL, BUCK9_SLP_VSEL, BUCK10_SLP_VSEL,
NLDO1_ON_VSEL, NLDO2_ON_VSEL, NLDO3_ON_VSEL, NLDO4_ON_VSEL, NLDO5_ON_VSEL,
NLDO1_SLP_VSEL, NLDO2_SLP_VSEL, NLDO3_SLP_VSEL, NLDO4_SLP_VSEL, NLDO5_SLP_VSEL,
PLDO1_ON_VSEL, PLDO2_ON_VSEL, PLDO3_ON_VSEL, PLDO4_ON_VSEL, PLDO5_ON_VSEL,
PLDO6_ON_VSEL,
PLDO1_SLP_VSEL, PLDO2_SLP_VSEL, PLDO3_SLP_VSEL, PLDO4_SLP_VSEL, PLDO5_SLP_VSEL,
PLDO6_SLP_VSEL,
BUCK1_RATE, BUCK2_RATE, BUCK3_RATE, BUCK4_RATE, BUCK5_RATE, BUCK6_RATE,
BUCK7_RATE, BUCK8_RATE, BUCK9_RATE, BUCK10_RATE,
PWRON_STS, VDC_STS, VB_UV_STSS, VB_LO_STS, HOTDIE_STS, TSD_STS, VB_OV_STS,
VB_UV_DLY, VB_UV_SEL, VB_LO_ACT, VB_LO_SEL,
TSD_TEMP, HOTDIE_TMP, VPREREG_SEL,
VCCXDET_DIS, OSC_TC, ENB2_2M, ENB_32K,
SLP2_POL, SLP2_FUN, SLP1_POL, SLP1_FUN,
SLP3_POL, SLP3_FUN,
BUCK4_SLP_CTR_SEL, BUCK3_SLP_CTR_SEL, BUCK2_SLP_CTR_SEL, BUCK1_SLP_CTR_SEL,
BUCK8_SLP_CTR_SEL, BUCK7_SLP_CTR_SEL, BUCK6_SLP_CTR_SEL, BUCK5_SLP_CTR_SEL,
NLDO2_SLP_CTR_SEL, NLDO1_SLP_CTR_SEL, BUCK10_SLP_CTR_SEL, BUCK9_SLP_CTR_SEL,
NLDO5_SLP_CTR_SEL, NLDO4_SLP_CTR_SEL, NLDO3_SLP_CTR_SEL,
PLDO4_SLP_CTR_SEL, PLDO3_SLP_CTR_SEL, PLDO2_SLP_CTR_SEL, PLDO1_SLP_CTR_SEL,
PLDO6_SLP_CTR_SEL, PLDO5_SLP_CTR_SEL,
BUCK4_DVS_CTR_SEL, BUCK3_DVS_CTR_SEL, BUCK2_DVS_CTR_SEL, BUCK1_DVS_CTR_SEL,
BUCK8_DVS_CTR_SEL, BUCK7_DVS_CTR_SEL, BUCK6_DVS_CTR_SEL, BUCK5_DVS_CTR_SEL,
NLDO2_DVS_CTR_SEL, NLDO1_DVS_CTR_SEL, BUCK10_DVS_CTR_SEL, BUCK9_DVS_CTR_SEL,
NLDO5_DVS_CTR_SEL, NLDO4_DVS_CTR_SEL, NLDO3_DVS_CTR_SEL,
PLDO4_DVS_CTR_SEL, PLDO3_DVS_CTR_SEL, PLDO2_DVS_CTR_SEL, PLDO1_DVS_CTR_SEL,
PLDO6_DVS_CTR_SEL, PLDO5_DVS_CTR_SEL,
DVS_START3, DVS_START2, DVS_START1,
SLP3_DATA, SLP2_DATA, SLP1_DATA, SLP3_DR, SLP2_DR, SLP1_DR,
RST_FUN, DEV_RST, DEV_SLP, SLAVE_RESTART_FUN, DEV_OFF,
WDT_CLR, WDT_EN, WDT_SET,
ON_PWRON, ON_VDC, RESTART_RESETB, RESTART_PWRON_LP, RESTART_SLP,
RESTART_DEV_RST, RESTART_WDT,
OFF_SLP, VB_SYS_OV, OFF_TSD, OFF_DEV_OFF, OFF_PWRON_LP, OFF_VB_LO,
PWRON_ON_TIME, PWRON_LP_ACT, PWRON_LP_OFF_TIME, PWRON_LP_TM_SEL, PWRON_DB_SEL,
VB_LO_INT, VDC_FALL_INT, VDC_RISE_INT, HOTDIE_INT, PWRON_LP_INT, PWRON_INT,
PWRON_RISE_INT, PWRON_FALL_INT,
VB_LO_IM, VDC_FALL_INT_IM, VDC_RISE_IM, HOTDIE_IM, PWRON_LP_IM,
PWRON_IM, PWRON_RISE_INT_IM, PWRON_FALL_INT_IM,
WDT_INT, SLP1_GPIO_INT, SLP2_GPIO_INT, SLP3_GPIO_INT,
WDT_INT_IM, SLP1_GPIO_IM, SLP2_GPIO_IM, SLP3_GPIO_IM,
INT_FUNCTION, INT_POL, INT_FC_EN,
LDO_RATE, BUCK1_RATE2, BUCK2_RATE2, BUCK3_RATE2, BUCK4_RATE2,
BUCK5_RATE2, BUCK6_RATE2, BUCK7_RATE2, BUCK8_RATE2, BUCK9_RATE2,
BUCK10_RATE2,
F_MAX_FIELDS
};
struct rk806_platform_data {
int low_voltage_threshold;
int shutdown_voltage_threshold;
int force_shutdown_enable;
int shutdown_temperture_threshold;
int hotdie_temperture_threshold;
};
struct rk806_pin_info {
struct pinctrl *p;
struct pinctrl_state *default_st;
struct pinctrl_state *power_off;
struct pinctrl_state *reset;
struct pinctrl_state *sleep;
struct pinctrl_state *dvs;
};
/*
* struct rk806 - state holder for the rk806 driver
*
* Device data may be used to access the rk806 chip
*/
struct rk806 {
struct device *dev;
struct regmap *regmap;
struct regmap_field *rmap_fields[F_MAX_FIELDS];
/* IRQ Data */
int irq;
struct regmap_irq_chip_data *irq_data;
struct rk806_platform_data *pdata;
struct rk806_pin_info *pins;
int vb_lo_irq;
};
extern const struct regmap_config rk806_regmap_config_spi;
int rk806_device_init(struct rk806 *rk806);
int rk806_device_exit(struct rk806 *rk806);
int rk806_field_write(struct rk806 *rk806,
enum rk806_fields field_id,
unsigned int val);
int rk806_field_read(struct rk806 *rk806,
enum rk806_fields field_id);
#endif /* __LINUX_REGULATOR_RK806_H */