You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

483 lines
11 KiB

/*
**Copyright (C) 2021 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <irq-generic.h>
#include <power/rk8xx_pmic.h>
#include <power/pmic.h>
#include <spi.h>
DECLARE_GLOBAL_DATA_PTR;
#define RK806_CHIP_NAME 0x5A
#define RK806_CHIP_VER 0x5B
#define RK806_HW_VER 0x21
#define HW_DUAL_PMIC 0x28
#define HW_SINGLE_PMIC 0xe8
#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
#define RK806_SYS_CFG1 0x5f
#define RK806_PWRCTRL_CONFIG0 0x62
#define RK806_PWRCTRL_CONFIG1 0x63
#define RK806_VSEL_CTR_SEL0 0x64
#define RK806_DVS_CTR_SEL4 0x6e
#define RK806_SYS_CFG3 0x72
#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_ON_SOURCE 0xf4
#define RK806_OFF_SOURCE 0xf5
#define RK806_IRQ_PWRON_FALL_MSK BIT(0)
#define RK806_IRQ_PWRON_RISE_MSK BIT(1)
#define RK806_DEV_OFF BIT(0)
#define RK806_RST_MODE1 0x01
#define RK806_RST_MODE2 0x02
#define RK806_PWRCTRL_FUN_MSK 0x88
#define RK806_VSEL_CTRL_MSK 0xcc
#define RK806_VSEL_PWRCTRL1 0x11
#define RK806_ENABLE_PWRCTRL 0x04
#define VERSION_AB 0x01
#if CONFIG_IS_ENABLED(IRQ)
/* RK805 */
static const struct virq_reg rk806_irqs[] = {
[RK8XX_IRQ_PWRON_FALL] = {
.mask = RK806_IRQ_PWRON_FALL_MSK,
.reg_offset = 0,
},
[RK8XX_IRQ_PWRON_RISE] = {
.mask = RK806_IRQ_PWRON_RISE_MSK,
.reg_offset = 0,
},
};
static struct virq_chip rk806_irq_chip = {
.status_base = RK806_INT_STS0,
.mask_base = RK806_INT_MSK0,
.num_regs = 1,
.read = pmic_reg_read,
.write = pmic_reg_write,
.irqs = rk806_irqs,
.num_irqs = ARRAY_SIZE(rk806_irqs),
};
#endif
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "DCDC", .driver = "rk8xx_spi_buck"},
{ .prefix = "NLDO", .driver = "rk8xx_spi_ldo"},
{ .prefix = "PLDO", .driver = "rk8xx_spi_pldo"},
{ },
};
static const struct pmic_child_info power_key_info[] = {
{ .prefix = "pwrkey", .driver = "rk8xx_pwrkey"},
{ },
};
static int _spi_read(struct udevice *dev, u32 reg, u8 *buffer, int len)
{
struct rk8xx_priv *priv = dev_get_priv(dev);
u8 txbuf[3];
int ret;
if (spi_claim_bus(priv->slave))
return -EBUSY;
txbuf[0] = RK806_CMD_READ;
txbuf[1] = reg;
txbuf[2] = RK806_REG_H;
ret = spi_write_then_read(priv->slave, txbuf, 3, NULL, buffer, 1);
spi_release_bus(priv->slave);
return ret;
}
static int _spi_write(struct udevice *dev, uint reg, const u8 *buffer, int len)
{
struct rk8xx_priv *priv = dev_get_priv(dev);
u8 txbuf[4];
int ret;
if (len < 1) {
dev_err(dev, "rk806 write error: len < 1\n");
return -EINVAL;
}
if (spi_claim_bus(priv->slave))
return -EBUSY;
txbuf[0] = RK806_CMD_WRITE;
txbuf[1] = reg;
txbuf[2] = RK806_REG_H;
txbuf[3] = *buffer;
ret = spi_write_then_read(priv->slave, txbuf, 4, NULL, NULL, 0);
spi_release_bus(priv->slave);
return ret;
}
static int rk806_spi_read(struct udevice *dev,
uint reg,
u8 *buffer,
int len)
{
int ret;
ret = _spi_read(dev, reg, buffer, len);
if (ret)
dev_err(dev, "rk806 read reg(0x%x) error: %d\n", reg, ret);
return ret;
}
static int rk806_spi_write(struct udevice *dev,
uint reg,
const u8 *buffer,
int len)
{
int ret;
ret = _spi_write(dev, reg, buffer, len);
if (ret)
dev_err(dev, "rk806 write reg(0x%x) error: %d\n", reg, ret);
return ret;
}
static int rk8xx_spi_reg_count(struct udevice *dev)
{
return 0xff;
}
#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
static int rk8xx_spi_bind(struct udevice *dev)
{
ofnode regulators_node;
int children;
regulators_node = dev_read_subnode(dev, "regulators");
if (!ofnode_valid(regulators_node)) {
debug("%s: %s regulators subnode not found!\n", __func__,
dev->name);
return -ENXIO;
}
children = pmic_bind_children(dev, regulators_node, pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
children = pmic_bind_children(dev, dev->node, power_key_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
return 0;
}
#endif
#if CONFIG_IS_ENABLED(IRQ)
static int rk8xx_spi_ofdata_to_platdata(struct udevice *dev)
{
struct rk8xx_priv *rk8xx = dev_get_priv(dev);
u32 interrupt, phandle;
int ret;
rk8xx->rst_fun = dev_read_u32_default(dev, "pmic-reset-func", 0);
phandle = dev_read_u32_default(dev, "interrupt-parent", -ENODATA);
if (phandle == -ENODATA) {
printf("Read 'interrupt-parent' failed, ret=%d\n", phandle);
return phandle;
}
ret = dev_read_u32_array(dev, "interrupts", &interrupt, 1);
if (ret) {
printf("Read 'interrupts' failed, ret=%d\n", ret);
return ret;
}
rk8xx->irq = phandle_gpio_to_irq(phandle, interrupt);
if (rk8xx->irq < 0)
printf("Failed to request rk8xx irq, ret=%d\n", rk8xx->irq);
return 0;
}
static int rk8xx_spi_irq_chip_init(struct udevice *dev)
{
struct rk8xx_priv *priv = dev_get_priv(dev);
struct virq_chip *irq_chip = NULL;
u8 value;
int ret;
value = 0xff;
rk806_spi_write(dev, RK806_INT_STS0, &value, 1);
rk806_spi_write(dev, RK806_INT_STS1, &value, 1);
rk806_spi_write(dev, RK806_INT_MSK0, &value, 1);
rk806_spi_write(dev, RK806_INT_MSK1, &value, 1);
value = 0x00;
rk806_spi_write(dev, RK806_GPIO_INT_CONFIG, &value, 1);
irq_chip = &rk806_irq_chip;
if (irq_chip && priv->irq > 0) {
ret = virq_add_chip(dev, irq_chip, priv->irq);
if (ret) {
printf("Failed to add irqchip(irq=%d), ret=%d\n",
priv->irq, ret);
return ret;
}
priv->irq_chip = irq_chip;
}
return 0;
}
#else
static inline int rk8xx_spi_ofdata_to_platdata(struct udevice *dev)
{
return 0;
}
static inline int rk8xx_spi_irq_chip_init(struct udevice *dev)
{
return 0;
}
#endif
static int rk8xx_spi_probe(struct udevice *dev)
{
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct rk8xx_priv *priv = dev_get_priv(dev);
struct udevice *spi = dev_get_parent(dev);
struct spi_slave *slave = NULL;
u8 on_source, off_source;
u8 msb, lsb, value = 0;
int ret;
if (spi->seq < 0) {
dev_err(dev, "Failed to configure the spi num\n");
return -EINVAL;
}
slave = spi_setup_slave(spi->seq, plat->cs, plat->max_hz,
plat->mode);
if (!slave)
return -ENODEV;
priv->slave = slave;
/* read Chip variant */
ret = rk806_spi_read(dev, RK806_CHIP_NAME, &msb, 1);
if (ret) {
dev_err(dev, "rk806 name read error: %d\n", ret);
return ret;
}
ret = rk806_spi_read(dev, RK806_CHIP_VER, &lsb, 1);
if (ret) {
dev_err(dev, "rk806 version read error: %d\n", ret);
return ret;
}
priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
printf("spi%d: RK%x%x: %d\n", spi->seq, msb, (lsb >> 4), lsb & 0x0f);
rk806_spi_read(dev, RK806_ON_SOURCE, &on_source, 1);
rk806_spi_read(dev, RK806_OFF_SOURCE, &off_source, 1);
printf("ON=0x%02x, OFF=0x%02x\n", on_source, off_source);
ret = rk806_spi_read(dev, RK806_HW_VER, &value, 1);
if (ret)
panic("RK806: read RK806_HW_VER error!\n");
/* dual rk806 dev name: "rk806master@0", "rk806slave@1"
* single rk806 dev name: " rk806single@0"
*/
if ((!strcmp(dev->name, "rk806master@0")) || (!strcmp(dev->name, "rk806slave@1"))) {
if (value != HW_DUAL_PMIC) {
dev_err(dev, "HW single pmic, the firmware dual pmic(0x%x)!\n", value);
run_command("download", 0);
}
} else {
if (value != HW_SINGLE_PMIC) {
dev_err(dev, "HW dual pmic, the firmware single pmic(0x%x)!\n", value);
run_command("download", 0);
}
}
if ((lsb & 0x0f) == VERSION_AB) {
ret = rk806_spi_read(dev, RK806_SYS_CFG1, &value, 1);
if (ret) {
dev_err(dev, "rk806 RK806_SYS_CFG1 read error: %d\n", ret);
return ret;
}
value |= 0x80;
rk806_spi_write(dev, RK806_SYS_CFG1, &value, 1);
}
if (priv->rst_fun) {
rk806_spi_read(dev, RK806_SYS_CFG3, &value, 1);
value &= 0x3f;
if (priv->rst_fun == RK806_RST_MODE1) {
value |= (RK806_RST_MODE1 << 6);
rk806_spi_write(dev, RK806_SYS_CFG3, &value, 1);
} else if (priv->rst_fun == RK806_RST_MODE2) {
value |= (RK806_RST_MODE2 << 6);
rk806_spi_write(dev, RK806_SYS_CFG3, &value, 1);
}
}
rk8xx_spi_irq_chip_init(dev);
return 0;
}
static int rk8xx_spi_shutdown(struct udevice *dev)
{
u8 dev_off;
int ret = 0;
ret = rk806_spi_read(dev, RK806_SYS_CFG3, &dev_off, 1);
if (ret)
return ret;
dev_off |= RK806_DEV_OFF;
ret = rk806_spi_write(dev, RK806_SYS_CFG3, &dev_off, 1);
if (ret) {
dev_err(dev, "rk806 shutdown error: %d\n", ret);
return ret;
}
while (1)
;
return 0;
}
static int rk806_suspend(struct udevice *dev)
{
int ret = 0;
u8 i, val;
ret = rk806_spi_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
val &= RK806_PWRCTRL_FUN_MSK;
ret = rk806_spi_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
ret = rk806_spi_read(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
if (ret)
return ret;
val &= RK806_PWRCTRL_FUN_MSK;
ret = rk806_spi_write(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
if (ret)
return ret;
for (i = RK806_VSEL_CTR_SEL0; i <= 0x6e; i++) {
ret = rk806_spi_read(dev, i, &val, 1);
if (ret)
return ret;
val &= RK806_VSEL_CTRL_MSK;
ret = rk806_spi_write(dev, i, &val, 1);
if (ret)
return ret;
}
ret = rk806_spi_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
val &= RK806_PWRCTRL_FUN_MSK;
val |= RK806_ENABLE_PWRCTRL;
ret = rk806_spi_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
ret = rk806_spi_read(dev, i, &val, 1);
if (ret)
return ret;
val &= RK806_VSEL_CTRL_MSK;
val |= RK806_VSEL_PWRCTRL1;
ret = rk806_spi_write(dev, i, &val, 1);
if (ret)
return ret;
}
return ret;
}
static int rk806_resume(struct udevice *dev)
{
int ret = 0;
u8 i, val;
for (i = RK806_VSEL_CTR_SEL0; i <= RK806_DVS_CTR_SEL4; i++) {
ret = rk806_spi_read(dev, i, &val, 1);
if (ret)
return ret;
val &= RK806_VSEL_CTRL_MSK;
ret = rk806_spi_write(dev, i, &val, 1);
if (ret)
return ret;
}
ret = rk806_spi_read(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
val &= RK806_PWRCTRL_FUN_MSK;
ret = rk806_spi_write(dev, RK806_PWRCTRL_CONFIG0, &val, 1);
if (ret)
return ret;
ret = rk806_spi_read(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
if (ret)
return ret;
val &= RK806_PWRCTRL_FUN_MSK;
ret = rk806_spi_write(dev, RK806_PWRCTRL_CONFIG1, &val, 1);
if (ret)
return ret;
return ret;
}
static struct dm_pmic_ops rk8xx_spi_ops = {
.reg_count = rk8xx_spi_reg_count,
.read = rk806_spi_read,
.write = rk806_spi_write,
.shutdown = rk8xx_spi_shutdown,
.suspend = rk806_suspend,
.resume = rk806_resume,
};
static const struct udevice_id rk8xx_spi_ids[] = {
{ .compatible = "rockchip,rk806" },
{ }
};
U_BOOT_DRIVER(pmic_rk8xx_spi) = {
.name = "rk806-pmic",
.id = UCLASS_PMIC,
.of_match = rk8xx_spi_ids,
#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
.bind = rk8xx_spi_bind,
#endif
.ofdata_to_platdata = rk8xx_spi_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct rk8xx_priv),
.probe = rk8xx_spi_probe,
.ops = &rk8xx_spi_ops,
};