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

Lee Jones lee at kernel.org
Thu Mar 28 04:55:10 PDT 2024


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 at gmail.com>
> ---
> 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 [李琼斯]



More information about the Linux-rockchip mailing list