diff --git a/drivers/power/pmic/rk8xx.c b/drivers/power/pmic/rk8xx.c index f8c4f6166a..96ce4809df 100644 --- a/drivers/power/pmic/rk8xx.c +++ b/drivers/power/pmic/rk8xx.c @@ -8,11 +8,142 @@ #include #include #include +#include #include #include DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_IRQ) && !defined(CONFIG_SPL_BUILD) +/* RK805 */ +static const struct virq_reg rk805_irqs[] = { + [RK8XX_IRQ_PWRON_FALL] = { + .mask = RK805_IRQ_PWRON_FALL_MSK, + .reg_offset = 0, + }, + [RK8XX_IRQ_PWRON_RISE] = { + .mask = RK805_IRQ_PWRON_RISE_MSK, + .reg_offset = 0, + }, +}; + +static struct virq_chip rk805_irq_chip = { + .status_base = RK805_INT_STS_REG, + .mask_base = RK805_INT_MSK_REG, + .num_regs = 1, + .i2c_read = pmic_reg_read, + .i2c_write = pmic_reg_write, + .irqs = rk805_irqs, + .num_irqs = ARRAY_SIZE(rk805_irqs), +}; + +/* RK808 */ +static const struct virq_reg rk808_irqs[] = { + [RK8XX_IRQ_PLUG_OUT] = { + .mask = RK808_IRQ_PLUG_OUT_MSK, + .reg_offset = 1, + }, +}; + +static struct virq_chip rk808_irq_chip = { + .status_base = RK808_INT_STS_REG1, + .mask_base = RK808_INT_MSK_REG1, + .irq_reg_stride = 2, + .num_regs = 2, + .i2c_read = pmic_reg_read, + .i2c_write = pmic_reg_write, + .irqs = rk808_irqs, + .num_irqs = ARRAY_SIZE(rk808_irqs), +}; + +/* RK816 */ +static const struct virq_reg rk816_irqs[] = { + [RK8XX_IRQ_PWRON_FALL] = { + .mask = RK816_IRQ_PWRON_FALL_MSK, + .reg_offset = 0, + }, + [RK8XX_IRQ_PWRON_RISE] = { + .mask = RK816_IRQ_PWRON_RISE_MSK, + .reg_offset = 0, + }, + [RK8XX_IRQ_PLUG_OUT] = { + .mask = RK816_IRQ_PLUG_OUT_MSK, + .reg_offset = 2, + }, + [RK8XX_IRQ_CHG_OK] = { + .mask = RK816_IRQ_CHR_OK_MSK, + .reg_offset = 2, + }, +}; + +static struct virq_chip rk816_irq_chip = { + .status_base = RK816_INT_STS_REG1, + .mask_base = RK816_INT_MSK_REG1, + .irq_unalign_reg_idx = 1, /* idx <= 1, stride = 3 */ + .irq_unalign_reg_stride = 3, + .irq_reg_stride = 2, /* idx > 1, stride = 2 */ + .num_regs = 3, + .i2c_read = pmic_reg_read, + .i2c_write = pmic_reg_write, + .irqs = rk816_irqs, + .num_irqs = ARRAY_SIZE(rk816_irqs), +}; + +/* RK818 */ +static const struct virq_reg rk818_irqs[] = { + [RK8XX_IRQ_PLUG_OUT] = { + .mask = RK818_IRQ_PLUG_OUT_MSK, + .reg_offset = 1, + }, + [RK8XX_IRQ_CHG_OK] = { + .mask = RK818_IRQ_CHR_OK_MSK, + .reg_offset = 1, + }, +}; + +static struct virq_chip rk818_irq_chip = { + .status_base = RK818_INT_STS_REG1, + .mask_base = RK818_INT_MSK_REG1, + .irq_reg_stride = 2, + .num_regs = 2, + .i2c_read = pmic_reg_read, + .i2c_write = pmic_reg_write, + .irqs = rk818_irqs, + .num_irqs = ARRAY_SIZE(rk818_irqs), +}; + +/* RK817/RK809 */ +static const struct virq_reg rk817_irqs[] = { + [RK8XX_IRQ_PWRON_FALL] = { + .mask = RK817_IRQ_PWRON_FALL_MSK, + .reg_offset = 0, + }, + [RK8XX_IRQ_PWRON_RISE] = { + .mask = RK817_IRQ_PWRON_RISE_MSK, + .reg_offset = 0, + }, + [RK8XX_IRQ_PLUG_OUT] = { + .mask = RK817_IRQ_PLUG_OUT_MSK, + .reg_offset = 1, + }, + [RK8XX_IRQ_PLUG_IN] = { + .mask = RK817_IRQ_PLUG_IN_MSK, + .reg_offset = 1, + }, +}; + +static struct virq_chip rk817_irq_chip = { + .status_base = RK817_INT_STS_REG0, + .mask_base = RK817_INT_MSK_REG0, + .irq_reg_stride = 2, + .num_regs = 3, + .i2c_read = pmic_reg_read, + .i2c_write = pmic_reg_write, + .irqs = rk817_irqs, + .num_irqs = ARRAY_SIZE(rk817_irqs), +}; +#endif + static struct reg_data rk817_init_reg[] = { /* enable the under-voltage protection, * the under-voltage protection will shutdown the LDO3 and reset the PMIC @@ -119,20 +250,33 @@ static int rk8xx_shutdown(struct udevice *dev) ret = dm_i2c_read(dev, devctrl_reg, &val, 1); if (ret) { - printf("%s: read reg 0x%02x failed, ret=%d\n", __func__, devctrl_reg, ret); + printf("%s: read reg 0x%02x failed, ret=%d\n", + __func__, devctrl_reg, ret); return ret; } val |= dev_off; ret = dm_i2c_write(dev, devctrl_reg, &val, 1); if (ret) { - printf("%s: write reg 0x%02x failed, ret=%d\n", __func__, devctrl_reg, ret); + printf("%s: write reg 0x%02x failed, ret=%d\n", + __func__, devctrl_reg, ret); return ret; } return 0; } +/* + * When system suspend during U-Boot charge, make sure the plugout event + * be able to wakeup cpu in wfi/wfe state. + */ +#ifdef CONFIG_DM_CHARGE_DISPLAY +static void rk8xx_plug_out_handler(int irq, void *data) +{ + printf("Plug out interrupt\n"); +} +#endif + #if CONFIG_IS_ENABLED(PMIC_CHILDREN) static int rk8xx_bind(struct udevice *dev) { @@ -173,6 +317,91 @@ static int rk8xx_bind(struct udevice *dev) } #endif +#if defined(CONFIG_IRQ) && !defined(CONFIG_SPL_BUILD) +static int rk8xx_ofdata_to_platdata(struct udevice *dev) +{ + struct rk8xx_priv *rk8xx = dev_get_priv(dev); + u32 interrupt, phandle; + int ret; + + 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 rk8xx->irq; + } + + return 0; +} + +static int rk8xx_irq_chip_init(struct udevice *dev) +{ + struct rk8xx_priv *priv = dev_get_priv(dev); + struct virq_chip *irq_chip = NULL; + int ret; + + switch (priv->variant) { + case RK808_ID: + irq_chip = &rk808_irq_chip; + break; + case RK805_ID: + irq_chip = &rk805_irq_chip; + break; + case RK816_ID: + irq_chip = &rk816_irq_chip; + break; + case RK818_ID: + irq_chip = &rk818_irq_chip; + break; + case RK809_ID: + case RK817_ID: + irq_chip = &rk817_irq_chip; + break; + default: + return -EINVAL; + } + + if (irq_chip) { + ret = virq_add_chip(dev, irq_chip, priv->irq, 1); + if (ret) { + printf("Failed to add irqchip(irq=%d), ret=%d\n", + priv->irq, ret); + return ret; + } + + priv->irq_chip = irq_chip; + +#ifdef CONFIG_DM_CHARGE_DISPLAY + int irq; + + irq = virq_to_irq(irq_chip, RK8XX_IRQ_PLUG_OUT); + if (irq < 0) { + printf("Failed to register plugout irq, ret=%d\n", irq); + return irq; + } + irq_install_handler(irq, rk8xx_plug_out_handler, dev); + irq_handler_enable_suspend_only(irq); +#endif + } + + return 0; +} +#else +static inline int rk8xx_ofdata_to_platdata(struct udevice *dev) { return 0; } +static inline int rk8xx_irq_chip_init(struct udevice *dev) { return 0; } +#endif + static int rk8xx_probe(struct udevice *dev) { struct rk8xx_priv *priv = dev_get_priv(dev); @@ -256,6 +485,12 @@ static int rk8xx_probe(struct udevice *dev) pmic_reg_read(dev, off_source)); printf("\n"); + ret = rk8xx_irq_chip_init(dev); + if (ret) { + printf("IRQ chip initial failed\n"); + return ret; + } + return 0; } @@ -283,7 +518,8 @@ U_BOOT_DRIVER(pmic_rk8xx) = { #if CONFIG_IS_ENABLED(PMIC_CHILDREN) .bind = rk8xx_bind, #endif - .priv_auto_alloc_size = sizeof(struct rk8xx_priv), + .ofdata_to_platdata = rk8xx_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct rk8xx_priv), .probe = rk8xx_probe, .ops = &rk8xx_ops, }; diff --git a/include/power/rk8xx_pmic.h b/include/power/rk8xx_pmic.h index 80bf923732..0a15bd431e 100644 --- a/include/power/rk8xx_pmic.h +++ b/include/power/rk8xx_pmic.h @@ -215,6 +215,43 @@ enum { #define RK817_ON_SOURCE 0xf5 #define RK817_OFF_SOURCE 0xf6 +/* IRQ definitions */ +#define RK8XX_IRQ_PWRON_FALL 0 +#define RK8XX_IRQ_PWRON_RISE 1 +#define RK8XX_IRQ_PLUG_OUT 2 +#define RK8XX_IRQ_PLUG_IN 3 +#define RK8XX_IRQ_CHG_OK 4 + +#define RK808_INT_STS_REG1 0x4c +#define RK808_INT_MSK_REG1 0x4d +#define RK808_IRQ_PLUG_OUT_MSK BIT(1) + +#define RK805_INT_STS_REG 0x4c +#define RK805_INT_MSK_REG 0x4d +#define RK805_IRQ_PWRON_FALL_MSK BIT(7) +#define RK805_IRQ_PWRON_RISE_MSK BIT(0) + +#define RK816_INT_STS_REG1 0x49 +#define RK816_INT_MSK_REG1 0x4a +#define RK816_INT_STS_REG3 0x4e +#define RK816_INT_STS_MSK_REG3 0x4f +#define RK816_IRQ_PWRON_RISE_MSK BIT(6) +#define RK816_IRQ_PWRON_FALL_MSK BIT(5) +#define RK816_IRQ_PLUG_OUT_MSK BIT(1) +#define RK816_IRQ_CHR_OK_MSK BIT(2) + +#define RK818_INT_STS_REG1 0x4c +#define RK818_INT_MSK_REG1 0x4d +#define RK818_IRQ_PLUG_OUT_MSK BIT(1) +#define RK818_IRQ_CHR_OK_MSK BIT(2) + +#define RK817_INT_STS_REG0 0xf8 +#define RK817_INT_MSK_REG0 0xf9 +#define RK817_IRQ_PWRON_FALL_MSK BIT(0) +#define RK817_IRQ_PWRON_RISE_MSK BIT(1) +#define RK817_IRQ_PLUG_OUT_MSK BIT(1) +#define RK817_IRQ_PLUG_IN_MSK BIT(0) + struct reg_data { u8 reg; u8 val; @@ -229,6 +266,8 @@ struct rk8xx_reg_table { struct rk8xx_priv { int variant; + int irq; + struct virq_chip *irq_chip; }; int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt);