Skip to content

Commit 210f418

Browse files
srelag-linaro
authored andcommitted
mfd: rk8xx: Add rk806 support
Add support for SPI connected rk806, which is used by the RK3588 evaluation boards. The PMIC is advertised to support I2C and SPI, but the evaluation boards all use SPI. Thus only SPI support is added here. Tested-by: Diederik de Haas <didi.debian@cknow.org> # Rock64, Quartz64 Model A + B Tested-by: Vincent Legoll <vincent.legoll@gmail.com> # Pine64 QuartzPro64 Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com> Link: https://lore.kernel.org/r/20230504173618.142075-9-sebastian.reichel@collabora.com Signed-off-by: Lee Jones <lee@kernel.org>
1 parent 706a414 commit 210f418

5 files changed

Lines changed: 614 additions & 3 deletions

File tree

drivers/mfd/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,20 @@ config MFD_RK8XX_I2C
12011201
through I2C interface. The device supports multiple sub-devices
12021202
including interrupts, RTC, LDO & DCDC regulators, and onkey.
12031203

1204+
config MFD_RK8XX_SPI
1205+
tristate "Rockchip RK806 Power Management Chip"
1206+
depends on SPI && OF
1207+
select MFD_CORE
1208+
select REGMAP_SPI
1209+
select REGMAP_IRQ
1210+
select MFD_RK8XX
1211+
help
1212+
If you say yes here you get support for the RK806 Power Management
1213+
chip.
1214+
This driver provides common support for accessing the device
1215+
through an SPI interface. The device supports multiple sub-devices
1216+
including interrupts, LDO & DCDC regulators, and power on-key.
1217+
12041218
config MFD_RN5T618
12051219
tristate "Ricoh RN5T567/618 PMIC"
12061220
depends on I2C

drivers/mfd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ obj-$(CONFIG_MFD_NTXEC) += ntxec.o
216216
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
217217
obj-$(CONFIG_MFD_RK8XX) += rk8xx-core.o
218218
obj-$(CONFIG_MFD_RK8XX_I2C) += rk8xx-i2c.o
219+
obj-$(CONFIG_MFD_RK8XX_SPI) += rk8xx-spi.o
219220
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
220221
obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
221222
obj-$(CONFIG_MFD_SYSCON) += syscon.o

drivers/mfd/rk8xx-core.c

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ static const struct resource rk805_key_resources[] = {
3737
DEFINE_RES_IRQ(RK805_IRQ_PWRON_FALL),
3838
};
3939

40+
static struct resource rk806_pwrkey_resources[] = {
41+
DEFINE_RES_IRQ(RK806_IRQ_PWRON_FALL),
42+
DEFINE_RES_IRQ(RK806_IRQ_PWRON_RISE),
43+
};
44+
4045
static const struct resource rk817_pwrkey_resources[] = {
4146
DEFINE_RES_IRQ(RK817_IRQ_PWRON_RISE),
4247
DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL),
@@ -64,6 +69,17 @@ static const struct mfd_cell rk805s[] = {
6469
},
6570
};
6671

72+
static const struct mfd_cell rk806s[] = {
73+
{ .name = "rk805-pinctrl", .id = PLATFORM_DEVID_AUTO, },
74+
{ .name = "rk808-regulator", .id = PLATFORM_DEVID_AUTO, },
75+
{
76+
.name = "rk805-pwrkey",
77+
.resources = rk806_pwrkey_resources,
78+
.num_resources = ARRAY_SIZE(rk806_pwrkey_resources),
79+
.id = PLATFORM_DEVID_AUTO,
80+
},
81+
};
82+
6783
static const struct mfd_cell rk808s[] = {
6884
{ .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
6985
{ .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
@@ -123,6 +139,12 @@ static const struct rk808_reg_data rk805_pre_init_reg[] = {
123139
{RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
124140
};
125141

142+
static const struct rk808_reg_data rk806_pre_init_reg[] = {
143+
{ RK806_GPIO_INT_CONFIG, RK806_INT_POL_MSK, RK806_INT_POL_L },
144+
{ RK806_SYS_CFG3, RK806_SLAVE_RESTART_FUN_MSK, RK806_SLAVE_RESTART_FUN_EN },
145+
{ RK806_SYS_OPTION, RK806_SYS_ENB2_2M_MSK, RK806_SYS_ENB2_2M_EN },
146+
};
147+
126148
static const struct rk808_reg_data rk808_pre_init_reg[] = {
127149
{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA },
128150
{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA },
@@ -273,6 +295,27 @@ static const struct regmap_irq rk805_irqs[] = {
273295
},
274296
};
275297

298+
static const struct regmap_irq rk806_irqs[] = {
299+
/* INT_STS0 IRQs */
300+
REGMAP_IRQ_REG(RK806_IRQ_PWRON_FALL, 0, RK806_INT_STS_PWRON_FALL),
301+
REGMAP_IRQ_REG(RK806_IRQ_PWRON_RISE, 0, RK806_INT_STS_PWRON_RISE),
302+
REGMAP_IRQ_REG(RK806_IRQ_PWRON, 0, RK806_INT_STS_PWRON),
303+
REGMAP_IRQ_REG(RK806_IRQ_PWRON_LP, 0, RK806_INT_STS_PWRON_LP),
304+
REGMAP_IRQ_REG(RK806_IRQ_HOTDIE, 0, RK806_INT_STS_HOTDIE),
305+
REGMAP_IRQ_REG(RK806_IRQ_VDC_RISE, 0, RK806_INT_STS_VDC_RISE),
306+
REGMAP_IRQ_REG(RK806_IRQ_VDC_FALL, 0, RK806_INT_STS_VDC_FALL),
307+
REGMAP_IRQ_REG(RK806_IRQ_VB_LO, 0, RK806_INT_STS_VB_LO),
308+
/* INT_STS1 IRQs */
309+
REGMAP_IRQ_REG(RK806_IRQ_REV0, 1, RK806_INT_STS_REV0),
310+
REGMAP_IRQ_REG(RK806_IRQ_REV1, 1, RK806_INT_STS_REV1),
311+
REGMAP_IRQ_REG(RK806_IRQ_REV2, 1, RK806_INT_STS_REV2),
312+
REGMAP_IRQ_REG(RK806_IRQ_CRC_ERROR, 1, RK806_INT_STS_CRC_ERROR),
313+
REGMAP_IRQ_REG(RK806_IRQ_SLP3_GPIO, 1, RK806_INT_STS_SLP3_GPIO),
314+
REGMAP_IRQ_REG(RK806_IRQ_SLP2_GPIO, 1, RK806_INT_STS_SLP2_GPIO),
315+
REGMAP_IRQ_REG(RK806_IRQ_SLP1_GPIO, 1, RK806_INT_STS_SLP1_GPIO),
316+
REGMAP_IRQ_REG(RK806_IRQ_WDT, 1, RK806_INT_STS_WDT),
317+
};
318+
276319
static const struct regmap_irq rk808_irqs[] = {
277320
/* INT_STS */
278321
[RK808_IRQ_VOUT_LO] = {
@@ -423,6 +466,18 @@ static struct regmap_irq_chip rk805_irq_chip = {
423466
.init_ack_masked = true,
424467
};
425468

469+
static struct regmap_irq_chip rk806_irq_chip = {
470+
.name = "rk806",
471+
.irqs = rk806_irqs,
472+
.num_irqs = ARRAY_SIZE(rk806_irqs),
473+
.num_regs = 2,
474+
.irq_reg_stride = 2,
475+
.mask_base = RK806_INT_MSK0,
476+
.status_base = RK806_INT_STS0,
477+
.ack_base = RK806_INT_STS0,
478+
.init_ack_masked = true,
479+
};
480+
426481
static const struct regmap_irq_chip rk808_irq_chip = {
427482
.name = "rk808",
428483
.irqs = rk808_irqs,
@@ -549,6 +604,7 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
549604
struct rk808 *rk808;
550605
const struct rk808_reg_data *pre_init_reg;
551606
const struct mfd_cell *cells;
607+
int dual_support = 0;
552608
int nr_pre_init_regs;
553609
int nr_cells;
554610
int ret;
@@ -570,6 +626,14 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
570626
cells = rk805s;
571627
nr_cells = ARRAY_SIZE(rk805s);
572628
break;
629+
case RK806_ID:
630+
rk808->regmap_irq_chip = &rk806_irq_chip;
631+
pre_init_reg = rk806_pre_init_reg;
632+
nr_pre_init_regs = ARRAY_SIZE(rk806_pre_init_reg);
633+
cells = rk806s;
634+
nr_cells = ARRAY_SIZE(rk806s);
635+
dual_support = IRQF_SHARED;
636+
break;
573637
case RK808_ID:
574638
rk808->regmap_irq_chip = &rk808_irq_chip;
575639
pre_init_reg = rk808_pre_init_reg;
@@ -601,7 +665,7 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
601665
return dev_err_probe(dev, -EINVAL, "No interrupt support, no core IRQ\n");
602666

603667
ret = devm_regmap_add_irq_chip(dev, rk808->regmap, irq,
604-
IRQF_ONESHOT, -1,
668+
IRQF_ONESHOT | dual_support, -1,
605669
rk808->regmap_irq_chip, &rk808->irq_data);
606670
if (ret)
607671
return dev_err_probe(dev, ret, "Failed to add irq_chip\n");
@@ -616,8 +680,7 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
616680
pre_init_reg[i].addr);
617681
}
618682

619-
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
620-
cells, nr_cells, NULL, 0,
683+
ret = devm_mfd_add_devices(dev, 0, cells, nr_cells, NULL, 0,
621684
regmap_irq_get_domain(rk808->irq_data));
622685
if (ret)
623686
return dev_err_probe(dev, ret, "failed to add MFD devices\n");

drivers/mfd/rk8xx-spi.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Rockchip RK806 Core (SPI) driver
4+
*
5+
* Copyright (c) 2021 Rockchip Electronics Co., Ltd.
6+
* Copyright (c) 2023 Collabora Ltd.
7+
*
8+
* Author: Xu Shengfei <xsf@rock-chips.com>
9+
* Author: Sebastian Reichel <sebastian.reichel@collabora.com>
10+
*/
11+
12+
#include <linux/interrupt.h>
13+
#include <linux/mfd/core.h>
14+
#include <linux/mfd/rk808.h>
15+
#include <linux/module.h>
16+
#include <linux/regmap.h>
17+
#include <linux/spi/spi.h>
18+
19+
#define RK806_ADDR_SIZE 2
20+
#define RK806_CMD_WITH_SIZE(CMD, VALUE_BYTES) \
21+
(RK806_CMD_##CMD | RK806_CMD_CRC_DIS | (VALUE_BYTES - 1))
22+
23+
static const struct regmap_range rk806_volatile_ranges[] = {
24+
regmap_reg_range(RK806_POWER_EN0, RK806_POWER_EN5),
25+
regmap_reg_range(RK806_DVS_START_CTRL, RK806_INT_MSK1),
26+
};
27+
28+
static const struct regmap_access_table rk806_volatile_table = {
29+
.yes_ranges = rk806_volatile_ranges,
30+
.n_yes_ranges = ARRAY_SIZE(rk806_volatile_ranges),
31+
};
32+
33+
static const struct regmap_config rk806_regmap_config_spi = {
34+
.reg_bits = 16,
35+
.val_bits = 8,
36+
.max_register = RK806_BUCK_RSERVE_REG5,
37+
.cache_type = REGCACHE_RBTREE,
38+
.volatile_table = &rk806_volatile_table,
39+
};
40+
41+
static int rk806_spi_bus_write(void *context, const void *vdata, size_t count)
42+
{
43+
struct device *dev = context;
44+
struct spi_device *spi = to_spi_device(dev);
45+
struct spi_transfer xfer[2] = { 0 };
46+
/* data and thus count includes the register address */
47+
size_t val_size = count - RK806_ADDR_SIZE;
48+
char cmd;
49+
50+
if (val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))
51+
return -EINVAL;
52+
53+
cmd = RK806_CMD_WITH_SIZE(WRITE, val_size);
54+
55+
xfer[0].tx_buf = &cmd;
56+
xfer[0].len = sizeof(cmd);
57+
xfer[1].tx_buf = vdata;
58+
xfer[1].len = count;
59+
60+
return spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));
61+
}
62+
63+
static int rk806_spi_bus_read(void *context, const void *vreg, size_t reg_size,
64+
void *val, size_t val_size)
65+
{
66+
struct device *dev = context;
67+
struct spi_device *spi = to_spi_device(dev);
68+
char txbuf[3] = { 0 };
69+
70+
if (reg_size != RK806_ADDR_SIZE ||
71+
val_size < 1 || val_size > (RK806_CMD_LEN_MSK + 1))
72+
return -EINVAL;
73+
74+
/* TX buffer contains command byte followed by two address bytes */
75+
txbuf[0] = RK806_CMD_WITH_SIZE(READ, val_size);
76+
memcpy(txbuf+1, vreg, reg_size);
77+
78+
return spi_write_then_read(spi, txbuf, sizeof(txbuf), val, val_size);
79+
}
80+
81+
static const struct regmap_bus rk806_regmap_bus_spi = {
82+
.write = rk806_spi_bus_write,
83+
.read = rk806_spi_bus_read,
84+
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
85+
};
86+
87+
static int rk8xx_spi_probe(struct spi_device *spi)
88+
{
89+
struct regmap *regmap;
90+
91+
regmap = devm_regmap_init(&spi->dev, &rk806_regmap_bus_spi,
92+
&spi->dev, &rk806_regmap_config_spi);
93+
if (IS_ERR(regmap))
94+
return dev_err_probe(&spi->dev, PTR_ERR(regmap),
95+
"Failed to init regmap\n");
96+
97+
return rk8xx_probe(&spi->dev, RK806_ID, spi->irq, regmap);
98+
}
99+
100+
static const struct of_device_id rk8xx_spi_of_match[] = {
101+
{ .compatible = "rockchip,rk806", },
102+
{ }
103+
};
104+
MODULE_DEVICE_TABLE(of, rk8xx_spi_of_match);
105+
106+
static const struct spi_device_id rk8xx_spi_id_table[] = {
107+
{ "rk806", 0 },
108+
{ }
109+
};
110+
MODULE_DEVICE_TABLE(spi, rk8xx_spi_id_table);
111+
112+
static struct spi_driver rk8xx_spi_driver = {
113+
.driver = {
114+
.name = "rk8xx-spi",
115+
.of_match_table = rk8xx_spi_of_match,
116+
},
117+
.probe = rk8xx_spi_probe,
118+
.id_table = rk8xx_spi_id_table,
119+
};
120+
module_spi_driver(rk8xx_spi_driver);
121+
122+
MODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
123+
MODULE_DESCRIPTION("RK8xx SPI PMIC driver");
124+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)