xref: /rk3399_rockchip-uboot/drivers/rtc/rk8xx_rtc.c (revision 063fcc919b3240627577bda8d106e539c8b167d6)
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