Re: [PATCH v3 2/5] mfd: rk8xx: Add RK816 support

From: Lee Jones
Date: Thu Mar 28 2024 - 07:55:24 EST


On Sat, 23 Mar 2024, Alex Bee wrote:

> This integrates RK816 support in the this existing rk8xx mfd driver.
>
> This version has unaligned interrupt registers, which requires to define a
> separate get_irq_reg callback for the regmap. Apart from that the
> integration is straightforward and the existing structures can be used as
> is. The initialization sequence has been taken from vendor kernel.
>
> Signed-off-by: Alex Bee <knaerzche@xxxxxxxxx>
> ---
> chnages since v1:
> - un-constify rk816_get_irq_reg's return type
>
> drivers/mfd/Kconfig | 4 +-
> drivers/mfd/rk8xx-core.c | 103 ++++++++++++++++++++++++++++
> drivers/mfd/rk8xx-i2c.c | 45 +++++++++++-
> include/linux/mfd/rk808.h | 141 ++++++++++++++++++++++++++++++++++++++
> 4 files changed, 290 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 4b023ee229cf..2e7286cc98e4 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1225,7 +1225,7 @@ config MFD_RK8XX
> select MFD_CORE
>
> config MFD_RK8XX_I2C
> - tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip"
> + tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power Management Chip"
> depends on I2C && OF
> select MFD_CORE
> select REGMAP_I2C
> @@ -1233,7 +1233,7 @@ config MFD_RK8XX_I2C
> select MFD_RK8XX
> help
> If you say yes here you get support for the RK805, RK808, RK809,
> - RK817 and RK818 Power Management chips.
> + RK816, RK817 and RK818 Power Management chips.
> This driver provides common support for accessing the device
> through I2C interface. The device supports multiple sub-devices
> including interrupts, RTC, LDO & DCDC regulators, and onkey.
> diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c
> index e2261b68b844..c68a380332e7 100644
> --- a/drivers/mfd/rk8xx-core.c
> +++ b/drivers/mfd/rk8xx-core.c
> @@ -28,6 +28,10 @@ static const struct resource rtc_resources[] = {
> DEFINE_RES_IRQ(RK808_IRQ_RTC_ALARM),
> };
>
> +static const struct resource rk816_rtc_resources[] = {
> + DEFINE_RES_IRQ(RK816_IRQ_RTC_ALARM),
> +};
> +
> static const struct resource rk817_rtc_resources[] = {
> DEFINE_RES_IRQ(RK817_IRQ_RTC_ALARM),
> };
> @@ -87,6 +91,21 @@ static const struct mfd_cell rk808s[] = {
> },
> };
>
> +static const struct mfd_cell rk816s[] = {
> + { .name = "rk805-pinctrl", },
> + { .name = "rk808-clkout", },
> + { .name = "rk808-regulator", },
> + { .name = "rk805-pwrkey",

Newline after the '{'.

> + .num_resources = ARRAY_SIZE(rk805_key_resources),
> + .resources = rk805_key_resources,
> + },
> + {
> + .name = "rk808-rtc",
> + .num_resources = ARRAY_SIZE(rk816_rtc_resources),
> + .resources = rk816_rtc_resources,
> + },
> +};
> +
> static const struct mfd_cell rk817s[] = {
> { .name = "rk808-clkout", },
> { .name = "rk808-regulator", },
> @@ -148,6 +167,17 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = {
> VB_LO_SEL_3500MV },
> };
>
> +static const struct rk808_reg_data rk816_pre_init_reg[] = {
> + { RK818_BUCK1_CONFIG_REG, RK817_RAMP_RATE_MASK,
> + RK817_RAMP_RATE_12_5MV_PER_US },
> + { RK818_BUCK2_CONFIG_REG, RK817_RAMP_RATE_MASK,
> + RK817_RAMP_RATE_12_5MV_PER_US },
> + { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA },
> + { RK808_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP105C},
> + { RK808_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK,
> + RK808_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN },
> +};
> +
> static const struct rk808_reg_data rk817_pre_init_reg[] = {
> {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
> /* Codec specific registers */
> @@ -350,6 +380,59 @@ static const struct regmap_irq rk808_irqs[] = {
> },
> };
>
> +static const unsigned int rk816_irq_status_offsets[] = {
> + (RK816_INT_STS_REG1 - RK816_INT_STS_REG1),

Turn this into a macro please.

> + (RK816_INT_STS_REG2 - RK816_INT_STS_REG1),
> + (RK816_INT_STS_REG3 - RK816_INT_STS_REG1),
> +};
> +
> +static const unsigned int rk816_irq_mask_offsets[] = {
> + (RK816_INT_STS_MSK_REG1 - RK816_INT_STS_MSK_REG1),
> + (RK816_INT_STS_MSK_REG2 - RK816_INT_STS_MSK_REG1),
> + (RK816_INT_STS_MSK_REG3 - RK816_INT_STS_MSK_REG1),
> +};
> +
> +static unsigned int rk816_get_irq_reg(struct regmap_irq_chip_data *data,
> + unsigned int base, int index)
> +{
> + unsigned int irq_reg = base;
> +
> + switch (base) {
> + case RK816_INT_STS_REG1:
> + irq_reg += rk816_irq_status_offsets[index];
> + break;
> + case RK816_INT_STS_MSK_REG1:
> + irq_reg += rk816_irq_mask_offsets[index];
> + break;
> + }
> +
> + return irq_reg;
> +};
> +
> +static const struct regmap_irq rk816_irqs[] = {
> + /* INT_STS_REG1 IRQs */
> + REGMAP_IRQ_REG(RK816_IRQ_PWRON_FALL, 0, RK816_INT_STS_PWRON_FALL),
> + REGMAP_IRQ_REG(RK816_IRQ_PWRON_RISE, 0, RK816_INT_STS_PWRON_RISE),
> +
> + /* INT_STS_REG2 IRQs */
> + REGMAP_IRQ_REG(RK816_IRQ_VB_LOW, 1, RK816_INT_STS_VB_LOW),
> + REGMAP_IRQ_REG(RK816_IRQ_PWRON, 1, RK816_INT_STS_PWRON),
> + REGMAP_IRQ_REG(RK816_IRQ_PWRON_LP, 1, RK816_INT_STS_PWRON_LP),
> + REGMAP_IRQ_REG(RK816_IRQ_HOTDIE, 1, RK816_INT_STS_HOTDIE),
> + REGMAP_IRQ_REG(RK816_IRQ_RTC_ALARM, 1, RK816_INT_STS_RTC_ALARM),
> + REGMAP_IRQ_REG(RK816_IRQ_RTC_PERIOD, 1, RK816_INT_STS_RTC_PERIOD),
> + REGMAP_IRQ_REG(RK816_IRQ_USB_OV, 1, RK816_INT_STS_USB_OV),
> +
> + /* INT_STS3 IRQs */
> + REGMAP_IRQ_REG(RK816_IRQ_PLUG_IN, 2, RK816_INT_STS_PLUG_IN),
> + REGMAP_IRQ_REG(RK816_IRQ_PLUG_OUT, 2, RK816_INT_STS_PLUG_OUT),
> + REGMAP_IRQ_REG(RK816_IRQ_CHG_OK, 2, RK816_INT_STS_CHG_OK),
> + REGMAP_IRQ_REG(RK816_IRQ_CHG_TE, 2, RK816_INT_STS_CHG_TE),
> + REGMAP_IRQ_REG(RK816_IRQ_CHG_TS, 2, RK816_INT_STS_CHG_TS),
> + REGMAP_IRQ_REG(RK816_IRQ_CHG_CVTLIM, 2, RK816_INT_STS_CHG_CVTLIM),
> + REGMAP_IRQ_REG(RK816_IRQ_DISCHG_ILIM, 2, RK816_INT_STS_DISCHG_ILIM),
> +};
> +
> static const struct regmap_irq rk818_irqs[] = {
> /* INT_STS */
> [RK818_IRQ_VOUT_LO] = {
> @@ -482,6 +565,18 @@ static const struct regmap_irq_chip rk808_irq_chip = {
> .init_ack_masked = true,
> };
>
> +static const struct regmap_irq_chip rk816_irq_chip = {
> + .name = "rk816",
> + .irqs = rk816_irqs,
> + .num_irqs = ARRAY_SIZE(rk816_irqs),
> + .num_regs = 3,
> + .get_irq_reg = rk816_get_irq_reg,
> + .status_base = RK816_INT_STS_REG1,
> + .mask_base = RK816_INT_STS_MSK_REG1,
> + .ack_base = RK816_INT_STS_REG1,
> + .init_ack_masked = true,
> +};
> +
> static struct regmap_irq_chip rk817_irq_chip = {
> .name = "rk817",
> .irqs = rk817_irqs,
> @@ -530,6 +625,7 @@ static int rk808_power_off(struct sys_off_data *data)
> reg = RK817_SYS_CFG(3);
> bit = DEV_OFF;
> break;
> + case RK816_ID:
> case RK818_ID:
> reg = RK818_DEVCTRL_REG;
> bit = DEV_OFF;
> @@ -637,6 +733,13 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
> cells = rk808s;
> nr_cells = ARRAY_SIZE(rk808s);
> break;
> + case RK816_ID:
> + rk808->regmap_irq_chip = &rk816_irq_chip;
> + pre_init_reg = rk816_pre_init_reg;
> + nr_pre_init_regs = ARRAY_SIZE(rk816_pre_init_reg);
> + cells = rk816s;
> + nr_cells = ARRAY_SIZE(rk816s);
> + break;
> case RK818_ID:
> rk808->regmap_irq_chip = &rk818_irq_chip;
> pre_init_reg = rk818_pre_init_reg;
> diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c
> index 75b5cf09d5a0..69a6b297d723 100644
> --- a/drivers/mfd/rk8xx-i2c.c
> +++ b/drivers/mfd/rk8xx-i2c.c
> @@ -1,6 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0-only
> /*
> - * Rockchip RK808/RK818 Core (I2C) driver
> + * Rockchip RK805/RK808/RK816/RK817/RK818 Core (I2C) driver
> *
> * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> * Copyright (C) 2016 PHYTEC Messtechnik GmbH
> @@ -49,6 +49,35 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
> return false;
> }
>
> +static bool rk816_is_volatile_reg(struct device *dev, unsigned int reg)
> +{
> + /*
> + * Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but
> + * we don't use that feature. It's better to cache.
> + */
> +
> + switch (reg) {
> + case RK808_SECONDS_REG ... RK808_WEEKS_REG:
> + case RK808_RTC_STATUS_REG:
> + case RK808_VB_MON_REG:
> + case RK808_THERMAL_REG:
> + case RK816_DCDC_EN_REG1:
> + case RK816_DCDC_EN_REG2:
> + case RK816_INT_STS_REG1:
> + case RK816_INT_STS_REG2:
> + case RK816_INT_STS_REG3:
> + case RK808_DEVCTRL_REG:
> + case RK816_SUP_STS_REG:
> + case RK816_GGSTS_REG:
> + case RK816_ZERO_CUR_ADC_REGH:
> + case RK816_ZERO_CUR_ADC_REGL:
> + case RK816_GASCNT_REG(0) ... RK816_BAT_VOL_REGL:
> + return true;
> + }
> +
> + return false;
> +}
> +
> static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
> {
> /*
> @@ -100,6 +129,14 @@ static const struct regmap_config rk808_regmap_config = {
> .volatile_reg = rk808_is_volatile_reg,
> };
>
> +static const struct regmap_config rk816_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = RK816_DATA_REG(18),
> + .cache_type = REGCACHE_MAPLE,
> + .volatile_reg = rk816_is_volatile_reg,
> +};
> +
> static const struct regmap_config rk817_regmap_config = {
> .reg_bits = 8,
> .val_bits = 8,
> @@ -123,6 +160,11 @@ static const struct rk8xx_i2c_platform_data rk809_data = {
> .variant = RK809_ID,
> };
>
> +static const struct rk8xx_i2c_platform_data rk816_data = {
> + .regmap_cfg = &rk816_regmap_config,
> + .variant = RK816_ID,
> +};
> +
> static const struct rk8xx_i2c_platform_data rk817_data = {
> .regmap_cfg = &rk817_regmap_config,
> .variant = RK817_ID,
> @@ -161,6 +203,7 @@ static const struct of_device_id rk8xx_i2c_of_match[] = {
> { .compatible = "rockchip,rk805", .data = &rk805_data },
> { .compatible = "rockchip,rk808", .data = &rk808_data },
> { .compatible = "rockchip,rk809", .data = &rk809_data },
> + { .compatible = "rockchip,rk816", .data = &rk816_data },
> { .compatible = "rockchip,rk817", .data = &rk817_data },
> { .compatible = "rockchip,rk818", .data = &rk818_data },
> { },
> diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
> index 78e167a92483..b90d1c278790 100644
> --- a/include/linux/mfd/rk808.h
> +++ b/include/linux/mfd/rk808.h
> @@ -113,6 +113,145 @@ enum rk808_reg {
> #define RK808_INT_STS_MSK_REG2 0x4f
> #define RK808_IO_POL_REG 0x50
>
> +/* RK816 */
> +enum rk816_reg {
> + RK816_ID_DCDC1,
> + RK816_ID_DCDC2,
> + RK816_ID_DCDC3,
> + RK816_ID_DCDC4,
> + RK816_ID_LDO1,
> + RK816_ID_LDO2,
> + RK816_ID_LDO3,
> + RK816_ID_LDO4,
> + RK816_ID_LDO5,
> + RK816_ID_LDO6,
> + RK816_ID_BOOST,
> + RK816_ID_OTG_SW,
> +};
> +
> +enum rk816_irqs {
> + /* INT_STS_REG1 */
> + RK816_IRQ_PWRON_FALL,
> + RK816_IRQ_PWRON_RISE,
> +
> + /* INT_STS_REG2 */
> + RK816_IRQ_VB_LOW,
> + RK816_IRQ_PWRON,
> + RK816_IRQ_PWRON_LP,
> + RK816_IRQ_HOTDIE,
> + RK816_IRQ_RTC_ALARM,
> + RK816_IRQ_RTC_PERIOD,
> + RK816_IRQ_USB_OV,
> +
> + /* INT_STS_REG3 */
> + RK816_IRQ_PLUG_IN,
> + RK816_IRQ_PLUG_OUT,
> + RK816_IRQ_CHG_OK,
> + RK816_IRQ_CHG_TE,
> + RK816_IRQ_CHG_TS,
> + RK816_IRQ_CHG_CVTLIM,
> + RK816_IRQ_DISCHG_ILIM,
> +};
> +
> +/* power channel registers */
> +#define RK816_DCDC_EN_REG1 0x23
> +
> +#define RK816_DCDC_EN_REG2 0x24
> +#define RK816_BOOST_EN BIT(1)
> +#define RK816_OTG_EN BIT(2)
> +#define RK816_BOOST_EN_MSK BIT(5)
> +#define RK816_OTG_EN_MSK BIT(6)
> +#define RK816_BUCK_DVS_CONFIRM BIT(7)
> +
> +#define RK816_LDO_EN_REG1 0x27
> +
> +#define RK816_LDO_EN_REG2 0x28
> +
> +/* interrupt registers and irq definitions */
> +#define RK816_INT_STS_REG1 0x49
> +#define RK816_INT_STS_MSK_REG1 0x4a
> +#define RK816_INT_STS_PWRON_FALL BIT(5)
> +#define RK816_INT_STS_PWRON_RISE BIT(6)
> +
> +#define RK816_INT_STS_REG2 0x4c
> +#define RK816_INT_STS_MSK_REG2 0x4d
> +#define RK816_INT_STS_VB_LOW BIT(1)
> +#define RK816_INT_STS_PWRON BIT(2)
> +#define RK816_INT_STS_PWRON_LP BIT(3)
> +#define RK816_INT_STS_HOTDIE BIT(4)
> +#define RK816_INT_STS_RTC_ALARM BIT(5)
> +#define RK816_INT_STS_RTC_PERIOD BIT(6)
> +#define RK816_INT_STS_USB_OV BIT(7)
> +
> +#define RK816_INT_STS_REG3 0x4e
> +#define RK816_INT_STS_MSK_REG3 0x4f
> +#define RK816_INT_STS_PLUG_IN BIT(0)
> +#define RK816_INT_STS_PLUG_OUT BIT(1)
> +#define RK816_INT_STS_CHG_OK BIT(2)
> +#define RK816_INT_STS_CHG_TE BIT(3)
> +#define RK816_INT_STS_CHG_TS BIT(4)
> +#define RK816_INT_STS_CHG_CVTLIM BIT(6)
> +#define RK816_INT_STS_DISCHG_ILIM BIT(7)
> +
> +/* charger, boost and OTG registers */
> +#define RK816_OTG_BUCK_LDO_CONFIG_REG 0x2a
> +#define RK816_CHRG_CONFIG_REG 0x2b
> +#define RK816_BOOST_ON_VESL_REG 0x54
> +#define RK816_BOOST_SLP_VSEL_REG 0x55
> +#define RK816_CHRG_BOOST_CONFIG_REG 0x9a
> +#define RK816_SUP_STS_REG 0xa0
> +#define RK816_USB_CTRL_REG 0xa1
> +#define RK816_CHRG_CTRL(x) (0xa3 + (x))
> +#define RK816_BAT_CTRL_REG 0xa6
> +#define RK816_BAT_HTS_TS_REG 0xa8
> +#define RK816_BAT_LTS_TS_REG 0xa9
> +
> +/* adc and fuel gauge registers */
> +#define RK816_TS_CTRL_REG 0xac
> +#define RK816_ADC_CTRL_REG 0xad
> +#define RK816_GGCON_REG 0xb0
> +#define RK816_GGSTS_REG 0xb1
> +#define RK816_ZERO_CUR_ADC_REGH 0xb2
> +#define RK816_ZERO_CUR_ADC_REGL 0xb3
> +#define RK816_GASCNT_CAL_REG(x) (0xb7 - (x))
> +#define RK816_GASCNT_REG(x) (0xbb - (x))
> +#define RK816_BAT_CUR_AVG_REGH 0xbc
> +#define RK816_BAT_CUR_AVG_REGL 0xbd
> +#define RK816_TS_ADC_REGH 0xbe
> +#define RK816_TS_ADC_REGL 0xbf
> +#define RK816_USB_ADC_REGH 0xc0
> +#define RK816_USB_ADC_REGL 0xc1
> +#define RK816_BAT_OCV_REGH 0xc2
> +#define RK816_BAT_OCV_REGL 0xc3
> +#define RK816_BAT_VOL_REGH 0xc4
> +#define RK816_BAT_VOL_REGL 0xc5
> +#define RK816_RELAX_ENTRY_THRES_REGH 0xc6
> +#define RK816_RELAX_ENTRY_THRES_REGL 0xc7
> +#define RK816_RELAX_EXIT_THRES_REGH 0xc8
> +#define RK816_RELAX_EXIT_THRES_REGL 0xc9
> +#define RK816_RELAX_VOL1_REGH 0xca
> +#define RK816_RELAX_VOL1_REGL 0xcb
> +#define RK816_RELAX_VOL2_REGH 0xcc
> +#define RK816_RELAX_VOL2_REGL 0xcd
> +#define RK816_RELAX_CUR1_REGH 0xce
> +#define RK816_RELAX_CUR1_REGL 0xcf
> +#define RK816_RELAX_CUR2_REGH 0xd0
> +#define RK816_RELAX_CUR2_REGL 0xd1
> +#define RK816_CAL_OFFSET_REGH 0xd2
> +#define RK816_CAL_OFFSET_REGL 0xd3
> +#define RK816_NON_ACT_TIMER_CNT_REG 0xd4
> +#define RK816_VCALIB0_REGH 0xd5
> +#define RK816_VCALIB0_REGL 0xd6
> +#define RK816_VCALIB1_REGH 0xd7
> +#define RK816_VCALIB1_REGL 0xd8
> +#define RK816_FCC_GASCNT_REG(x) (0xdc - (x))
> +#define RK816_IOFFSET_REGH 0xdd
> +#define RK816_IOFFSET_REGL 0xde
> +#define RK816_SLEEP_CON_SAMP_CUR_REG 0xdf
> +
> +/* general purpose data registers 0xe0 ~ 0xf2 */
> +#define RK816_DATA_REG(x) (0xe0 + (x))
> +
> /* RK818 */
> #define RK818_DCDC1 0
> #define RK818_LDO1 4
> @@ -791,6 +930,7 @@ enum rk806_dvs_mode {
> #define VOUT_LO_INT BIT(0)
> #define CLK32KOUT2_EN BIT(0)
>
> +#define TEMP105C 0x08
> #define TEMP115C 0x0c
> #define TEMP_HOTDIE_MSK 0x0c
> #define SLP_SD_MSK (0x3 << 2)
> @@ -1191,6 +1331,7 @@ enum {
> RK806_ID = 0x8060,
> RK808_ID = 0x0000,
> RK809_ID = 0x8090,
> + RK816_ID = 0x8160,
> RK817_ID = 0x8170,
> RK818_ID = 0x8180,
> };
> --
> 2.43.2
>

--
Lee Jones [李琼斯]