147bc0dadSElaine Zhang /*
247bc0dadSElaine Zhang * (C) Copyright 2019 Rockchip Electronics Co., Ltd
347bc0dadSElaine Zhang *
447bc0dadSElaine Zhang * SPDX-License-Identifier: GPL-2.0+
547bc0dadSElaine Zhang */
647bc0dadSElaine Zhang
747bc0dadSElaine Zhang #include <common.h>
847bc0dadSElaine Zhang #include <dm.h>
947bc0dadSElaine Zhang #include <power/pmic.h>
1047bc0dadSElaine Zhang #include <power/rk8xx_pmic.h>
1147bc0dadSElaine Zhang #include <irq-generic.h>
1247bc0dadSElaine Zhang #include <asm/arch/periph.h>
1347bc0dadSElaine Zhang #include <dm/pinctrl.h>
1447bc0dadSElaine Zhang #include <rtc.h>
1547bc0dadSElaine Zhang
1647bc0dadSElaine Zhang #define RK817_INT_STS_REG0 0xf8
1747bc0dadSElaine Zhang #define RK817_INT_MSK_REG0 0xf9
1847bc0dadSElaine Zhang
1947bc0dadSElaine Zhang #define RK816_INT_STS_REG2 0x4c
2047bc0dadSElaine Zhang #define RK816_INT_MSK_REG2 0x4d
2147bc0dadSElaine Zhang
2247bc0dadSElaine Zhang #define RK808_INT_STS_REG1 0x4c
2347bc0dadSElaine Zhang #define RK808_INT_MSK_REG1 0x4d
2447bc0dadSElaine Zhang
2547bc0dadSElaine Zhang #define RK805_INT_STS_REG 0x4c
2647bc0dadSElaine Zhang #define RK805_INT_MSK_REG 0x4d
2747bc0dadSElaine Zhang
2847bc0dadSElaine Zhang #define RK808_RTC_CTRL_REG 0x10
2947bc0dadSElaine Zhang #define RK808_RTC_STATUS_REG 0x11
3047bc0dadSElaine Zhang #define RK808_RTC_INT_REG 0x12
3147bc0dadSElaine Zhang
3247bc0dadSElaine Zhang #define RK817_RTC_CTRL_REG 0x0d
3347bc0dadSElaine Zhang #define RK817_RTC_STATUS_REG 0x0e
3447bc0dadSElaine Zhang #define RK817_RTC_INT_REG 0x0f
3547bc0dadSElaine Zhang
3647bc0dadSElaine Zhang #define RTC_ALARM_EN 5
3747bc0dadSElaine Zhang #define RTC_ALARM_STATUS BIT(6)
3847bc0dadSElaine Zhang
3947bc0dadSElaine Zhang struct rk8xx_rtc_priv {
4047bc0dadSElaine Zhang u8 rtc_int_sts_reg;
4147bc0dadSElaine Zhang u8 rtc_int_msk_reg;
4247bc0dadSElaine Zhang u8 int_sts_reg;
4347bc0dadSElaine Zhang u8 int_msk_reg;
4447bc0dadSElaine Zhang int rtc_alarm_trigger;
4547bc0dadSElaine Zhang int irq_is_busy;
4647bc0dadSElaine Zhang };
4747bc0dadSElaine Zhang
rtc_irq_handler(int irq,void * data)4847bc0dadSElaine Zhang static void rtc_irq_handler(int irq, void *data)
4947bc0dadSElaine Zhang {
5047bc0dadSElaine Zhang struct udevice *dev = data;
5147bc0dadSElaine Zhang struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
5247bc0dadSElaine Zhang int ret, val;
5347bc0dadSElaine Zhang
5447bc0dadSElaine Zhang debug("%s: irq = %d\n", __func__, irq);
5547bc0dadSElaine Zhang
5647bc0dadSElaine Zhang if (priv->rtc_int_sts_reg) {
5747bc0dadSElaine Zhang val = pmic_reg_read(dev->parent, priv->rtc_int_sts_reg);
5847bc0dadSElaine Zhang if (val < 0) {
5947bc0dadSElaine Zhang printf("%s: i2c read reg 0x%x failed, ret=%d\n",
6047bc0dadSElaine Zhang __func__, priv->rtc_int_sts_reg, val);
6147bc0dadSElaine Zhang return;
6247bc0dadSElaine Zhang }
6347bc0dadSElaine Zhang
6447bc0dadSElaine Zhang if (val & RTC_ALARM_STATUS) {
6547bc0dadSElaine Zhang priv->rtc_alarm_trigger = 1;
6647bc0dadSElaine Zhang printf("RTC: alarm interrupt\n");
6747bc0dadSElaine Zhang }
6847bc0dadSElaine Zhang
6947bc0dadSElaine Zhang ret = pmic_reg_write(dev->parent,
7047bc0dadSElaine Zhang priv->rtc_int_sts_reg, 0xfe);
7147bc0dadSElaine Zhang if (ret < 0) {
7247bc0dadSElaine Zhang printf("%s: i2c write reg 0x%x failed, ret=%d\n",
7347bc0dadSElaine Zhang __func__, priv->rtc_int_sts_reg, ret);
7447bc0dadSElaine Zhang return;
7547bc0dadSElaine Zhang }
7647bc0dadSElaine Zhang }
7747bc0dadSElaine Zhang }
7847bc0dadSElaine Zhang
rtc_interrupt_init(struct udevice * dev)7947bc0dadSElaine Zhang static int rtc_interrupt_init(struct udevice *dev)
8047bc0dadSElaine Zhang {
81*063fcc91SShengfei Xu struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
8247bc0dadSElaine Zhang struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
83*063fcc91SShengfei Xu int irq;
8447bc0dadSElaine Zhang
85*063fcc91SShengfei Xu if (!rk8xx->irq_chip) {
86*063fcc91SShengfei Xu printf("Failed to get parent irq chip\n");
87*063fcc91SShengfei Xu return -ENOENT;
8847bc0dadSElaine Zhang }
8947bc0dadSElaine Zhang
90*063fcc91SShengfei Xu irq = virq_to_irq(rk8xx->irq_chip, RK8XX_IRQ_RTC_ALARM);
9147bc0dadSElaine Zhang if (irq < 0) {
9247bc0dadSElaine Zhang if (irq == -EBUSY) {
9347bc0dadSElaine Zhang priv->irq_is_busy = 1;
9447bc0dadSElaine Zhang return 0;
9547bc0dadSElaine Zhang }
9647bc0dadSElaine Zhang return irq;
9747bc0dadSElaine Zhang }
9847bc0dadSElaine Zhang irq_install_handler(irq, rtc_irq_handler, dev);
9947bc0dadSElaine Zhang irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
10047bc0dadSElaine Zhang irq_handler_enable(irq);
10147bc0dadSElaine Zhang
10247bc0dadSElaine Zhang return 0;
10347bc0dadSElaine Zhang }
10447bc0dadSElaine Zhang
rk8xx_rtc_alarm_trigger(struct udevice * dev)10547bc0dadSElaine Zhang static int rk8xx_rtc_alarm_trigger(struct udevice *dev)
10647bc0dadSElaine Zhang {
10747bc0dadSElaine Zhang struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
10847bc0dadSElaine Zhang int val, ret, alarm_trigger = 0;
10947bc0dadSElaine Zhang
11047bc0dadSElaine Zhang if (priv->irq_is_busy) {
11147bc0dadSElaine Zhang val = pmic_reg_read(dev->parent, priv->rtc_int_sts_reg);
11247bc0dadSElaine Zhang if (val < 0) {
11347bc0dadSElaine Zhang printf("%s: i2c read reg 0x%x failed, ret=%d\n",
11447bc0dadSElaine Zhang __func__, priv->rtc_int_sts_reg, val);
11547bc0dadSElaine Zhang return val;
11647bc0dadSElaine Zhang }
11747bc0dadSElaine Zhang if (val & RTC_ALARM_STATUS) {
11847bc0dadSElaine Zhang alarm_trigger = 1;
11947bc0dadSElaine Zhang printf("rtc alarm interrupt\n");
12047bc0dadSElaine Zhang }
12147bc0dadSElaine Zhang ret = pmic_reg_write(dev->parent,
12247bc0dadSElaine Zhang priv->rtc_int_sts_reg, 0xfe);
12347bc0dadSElaine Zhang if (ret < 0) {
12447bc0dadSElaine Zhang printf("%s: i2c write reg 0x%x failed, ret=%d\n",
12547bc0dadSElaine Zhang __func__, priv->rtc_int_sts_reg, ret);
12647bc0dadSElaine Zhang return ret;
12747bc0dadSElaine Zhang }
12847bc0dadSElaine Zhang return alarm_trigger;
12947bc0dadSElaine Zhang } else {
13047bc0dadSElaine Zhang return priv->rtc_alarm_trigger;
13147bc0dadSElaine Zhang }
13247bc0dadSElaine Zhang }
13347bc0dadSElaine Zhang
13447bc0dadSElaine Zhang static struct rtc_ops rk8xx_rtc_ops = {
13547bc0dadSElaine Zhang .alarm_trigger = rk8xx_rtc_alarm_trigger,
13647bc0dadSElaine Zhang };
13747bc0dadSElaine Zhang
rk8xx_rtc_probe(struct udevice * dev)13847bc0dadSElaine Zhang static int rk8xx_rtc_probe(struct udevice *dev)
13947bc0dadSElaine Zhang {
14047bc0dadSElaine Zhang struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
14147bc0dadSElaine Zhang struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
142*063fcc91SShengfei Xu int ret, val, mask_val;
14347bc0dadSElaine Zhang
14447bc0dadSElaine Zhang priv->rtc_int_sts_reg = RK808_RTC_STATUS_REG;
14547bc0dadSElaine Zhang priv->rtc_int_msk_reg = RK808_RTC_INT_REG;
14647bc0dadSElaine Zhang switch (rk8xx->variant) {
14747bc0dadSElaine Zhang case RK808_ID:
14847bc0dadSElaine Zhang case RK818_ID:
14947bc0dadSElaine Zhang priv->int_msk_reg = RK808_INT_MSK_REG1;
15047bc0dadSElaine Zhang priv->int_sts_reg = RK808_INT_STS_REG1;
151*063fcc91SShengfei Xu mask_val = RK808_IRQ_RTC_PERIOD_MSK | RK808_IRQ_VOUT_LOW_MSK;
15247bc0dadSElaine Zhang break;
15347bc0dadSElaine Zhang case RK805_ID:
15447bc0dadSElaine Zhang priv->int_msk_reg = RK805_INT_MSK_REG;
15547bc0dadSElaine Zhang priv->int_sts_reg = RK805_INT_STS_REG;
156*063fcc91SShengfei Xu mask_val = RK805_IRQ_RTC_PERIOD_MSK;
15747bc0dadSElaine Zhang break;
15847bc0dadSElaine Zhang case RK816_ID:
15947bc0dadSElaine Zhang priv->int_msk_reg = RK816_INT_MSK_REG2;
16047bc0dadSElaine Zhang priv->int_sts_reg = RK816_INT_STS_REG2;
161*063fcc91SShengfei Xu mask_val = RK816_IRQ_RTC_PERIOD_MSK;
16247bc0dadSElaine Zhang break;
16347bc0dadSElaine Zhang case RK809_ID:
16447bc0dadSElaine Zhang case RK817_ID:
16547bc0dadSElaine Zhang priv->rtc_int_sts_reg = RK817_RTC_STATUS_REG;
16647bc0dadSElaine Zhang priv->rtc_int_msk_reg = RK817_RTC_INT_REG;
16747bc0dadSElaine Zhang priv->int_msk_reg = RK817_INT_MSK_REG0;
16847bc0dadSElaine Zhang priv->int_sts_reg = RK817_INT_STS_REG0;
169*063fcc91SShengfei Xu mask_val = RK817_IRQ_RTC_PERIOD_MSK;
17047bc0dadSElaine Zhang break;
17147bc0dadSElaine Zhang default:
17247bc0dadSElaine Zhang return -EINVAL;
17347bc0dadSElaine Zhang }
17447bc0dadSElaine Zhang
17547bc0dadSElaine Zhang priv->rtc_alarm_trigger = 0;
17647bc0dadSElaine Zhang priv->irq_is_busy = 0;
17747bc0dadSElaine Zhang /* mask and clear interrupt */
17847bc0dadSElaine Zhang val = pmic_reg_read(dev->parent, priv->int_msk_reg);
17947bc0dadSElaine Zhang if (val < 0) {
18047bc0dadSElaine Zhang printf("%s: i2c read reg 0x%x failed, ret=%d\n",
18147bc0dadSElaine Zhang __func__, priv->int_msk_reg, val);
18247bc0dadSElaine Zhang return val;
18347bc0dadSElaine Zhang }
18447bc0dadSElaine Zhang ret = pmic_reg_write(dev->parent,
185*063fcc91SShengfei Xu priv->int_msk_reg, val | mask_val);
18647bc0dadSElaine Zhang if (ret < 0) {
18747bc0dadSElaine Zhang printf("%s: i2c write reg 0x%x failed, ret=%d\n",
18847bc0dadSElaine Zhang __func__, priv->int_msk_reg, ret);
18947bc0dadSElaine Zhang return ret;
19047bc0dadSElaine Zhang }
19147bc0dadSElaine Zhang val = pmic_reg_read(dev->parent, priv->int_sts_reg);
19247bc0dadSElaine Zhang if (val < 0) {
19347bc0dadSElaine Zhang printf("%s: i2c read reg 0x%x failed, ret=%d\n",
19447bc0dadSElaine Zhang __func__, priv->int_sts_reg, val);
19547bc0dadSElaine Zhang return val;
19647bc0dadSElaine Zhang }
19747bc0dadSElaine Zhang ret = pmic_reg_write(dev->parent,
19847bc0dadSElaine Zhang priv->int_sts_reg,
19947bc0dadSElaine Zhang val | (1 << RTC_ALARM_EN));
20047bc0dadSElaine Zhang if (ret < 0) {
20147bc0dadSElaine Zhang printf("%s: i2c write reg 0x%x failed, ret=%d\n",
20247bc0dadSElaine Zhang __func__, priv->int_sts_reg, ret);
20347bc0dadSElaine Zhang return ret;
20447bc0dadSElaine Zhang }
20547bc0dadSElaine Zhang debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->int_msk_reg,
20647bc0dadSElaine Zhang pmic_reg_read(dev->parent, priv->int_msk_reg));
20747bc0dadSElaine Zhang debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->int_sts_reg,
20847bc0dadSElaine Zhang pmic_reg_read(dev->parent, priv->int_sts_reg));
20947bc0dadSElaine Zhang
21047bc0dadSElaine Zhang return rtc_interrupt_init(dev);
21147bc0dadSElaine Zhang }
21247bc0dadSElaine Zhang
21347bc0dadSElaine Zhang U_BOOT_DRIVER(rk8xx_rtc) = {
21447bc0dadSElaine Zhang .name = "rk8xx_rtc",
21547bc0dadSElaine Zhang .id = UCLASS_RTC,
21647bc0dadSElaine Zhang .probe = rk8xx_rtc_probe,
21747bc0dadSElaine Zhang .ops = &rk8xx_rtc_ops,
21847bc0dadSElaine Zhang .priv_auto_alloc_size = sizeof(struct rk8xx_rtc_priv),
21947bc0dadSElaine Zhang };
220