hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * (C) Copyright 2019 Rockchip Electronics Co., Ltd
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */
 
#include <common.h>
#include <dm.h>
#include <power/pmic.h>
#include <power/rk8xx_pmic.h>
#include <irq-generic.h>
#include <asm/arch/periph.h>
#include <dm/pinctrl.h>
#include <rtc.h>
 
#define    RK817_INT_STS_REG0    0xf8
#define    RK817_INT_MSK_REG0    0xf9
 
#define    RK816_INT_STS_REG2    0x4c
#define    RK816_INT_MSK_REG2    0x4d
 
#define    RK808_INT_STS_REG1    0x4c
#define    RK808_INT_MSK_REG1    0x4d
 
#define    RK805_INT_STS_REG    0x4c
#define    RK805_INT_MSK_REG    0x4d
 
#define RK808_RTC_CTRL_REG    0x10
#define RK808_RTC_STATUS_REG    0x11
#define RK808_RTC_INT_REG    0x12
 
#define RK817_RTC_CTRL_REG    0x0d
#define RK817_RTC_STATUS_REG    0x0e
#define RK817_RTC_INT_REG    0x0f
 
#define RTC_ALARM_EN        5
#define RTC_ALARM_STATUS    BIT(6)
 
struct rk8xx_rtc_priv {
   u8 rtc_int_sts_reg;
   u8 rtc_int_msk_reg;
   u8 int_sts_reg;
   u8 int_msk_reg;
   int rtc_alarm_trigger;
   int irq_is_busy;
};
 
static void rtc_irq_handler(int irq, void *data)
{
   struct udevice *dev = data;
   struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
   int ret, val;
 
   debug("%s: irq = %d\n", __func__, irq);
 
   if (priv->rtc_int_sts_reg) {
       val = pmic_reg_read(dev->parent, priv->rtc_int_sts_reg);
       if (val < 0) {
           printf("%s: i2c read reg 0x%x failed, ret=%d\n",
                  __func__, priv->rtc_int_sts_reg, val);
           return;
       }
 
       if (val & RTC_ALARM_STATUS) {
           priv->rtc_alarm_trigger = 1;
           printf("RTC: alarm interrupt\n");
       }
 
       ret = pmic_reg_write(dev->parent,
                    priv->rtc_int_sts_reg, 0xfe);
       if (ret < 0) {
           printf("%s: i2c write reg 0x%x failed, ret=%d\n",
                  __func__, priv->rtc_int_sts_reg, ret);
           return;
       }
   }
 
   ret = pmic_reg_write(dev->parent,
                priv->int_sts_reg, 0xff);
   if (ret < 0) {
       printf("%s: i2c write reg 0x%x failed, ret=%d\n",
              __func__, priv->int_sts_reg, ret);
       return;
   }
   debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->int_sts_reg,
         pmic_reg_read(dev->parent, priv->int_sts_reg));
}
 
static int rtc_interrupt_init(struct udevice *dev)
{
   struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
   u32 interrupt[2], phandle;
   int irq, ret;
 
   phandle = dev_read_u32_default(dev->parent, "interrupt-parent", -1);
   if (phandle < 0) {
       printf("failed get 'interrupt-parent', ret=%d\n", phandle);
       return phandle;
   }
 
   ret = dev_read_u32_array(dev->parent, "interrupts", interrupt, 2);
   if (ret) {
       printf("failed get 'interrupt', ret=%d\n", ret);
       return ret;
   }
 
   irq = phandle_gpio_to_irq(phandle, interrupt[0]);
   if (irq < 0) {
       if (irq == -EBUSY) {
           priv->irq_is_busy = 1;
           return 0;
       }
       return irq;
   }
   irq_install_handler(irq, rtc_irq_handler, dev);
   irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
   irq_handler_enable(irq);
 
   return 0;
}
 
static int rk8xx_rtc_alarm_trigger(struct udevice *dev)
{
   struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
   int val, ret, alarm_trigger = 0;
 
   if (priv->irq_is_busy) {
       val = pmic_reg_read(dev->parent, priv->rtc_int_sts_reg);
       if (val < 0) {
           printf("%s: i2c read reg 0x%x failed, ret=%d\n",
                  __func__, priv->rtc_int_sts_reg, val);
           return val;
       }
       if (val & RTC_ALARM_STATUS) {
           alarm_trigger = 1;
           printf("rtc alarm interrupt\n");
       }
       ret = pmic_reg_write(dev->parent,
                    priv->rtc_int_sts_reg, 0xfe);
       if (ret < 0) {
           printf("%s: i2c write reg 0x%x failed, ret=%d\n",
                  __func__, priv->rtc_int_sts_reg, ret);
           return ret;
       }
       return alarm_trigger;
   } else {
       return priv->rtc_alarm_trigger;
   }
}
 
static struct rtc_ops rk8xx_rtc_ops = {
   .alarm_trigger = rk8xx_rtc_alarm_trigger,
};
 
static int rk8xx_rtc_probe(struct udevice *dev)
{
   struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
   struct rk8xx_rtc_priv *priv = dev_get_priv(dev);
   int ret, val;
 
   priv->rtc_int_sts_reg = RK808_RTC_STATUS_REG;
   priv->rtc_int_msk_reg = RK808_RTC_INT_REG;
   switch (rk8xx->variant) {
   case RK808_ID:
   case RK818_ID:
       priv->int_msk_reg = RK808_INT_MSK_REG1;
       priv->int_sts_reg = RK808_INT_STS_REG1;
       break;
   case RK805_ID:
       priv->int_msk_reg = RK805_INT_MSK_REG;
       priv->int_sts_reg = RK805_INT_STS_REG;
       break;
   case RK816_ID:
       priv->int_msk_reg = RK816_INT_MSK_REG2;
       priv->int_sts_reg = RK816_INT_STS_REG2;
       break;
   case RK809_ID:
   case RK817_ID:
       priv->rtc_int_sts_reg = RK817_RTC_STATUS_REG;
       priv->rtc_int_msk_reg = RK817_RTC_INT_REG;
       priv->int_msk_reg = RK817_INT_MSK_REG0;
       priv->int_sts_reg = RK817_INT_STS_REG0;
       break;
   default:
       return -EINVAL;
   }
 
   priv->rtc_alarm_trigger = 0;
   priv->irq_is_busy = 0;
   /* mask and clear interrupt */
   val = pmic_reg_read(dev->parent, priv->int_msk_reg);
   if (val < 0) {
       printf("%s: i2c read reg 0x%x failed, ret=%d\n",
              __func__, priv->int_msk_reg, val);
       return val;
   }
   ret = pmic_reg_write(dev->parent,
                priv->int_msk_reg, val | 0xc1);
   if (ret < 0) {
       printf("%s: i2c write reg 0x%x failed, ret=%d\n",
              __func__, priv->int_msk_reg, ret);
       return ret;
   }
   val = pmic_reg_read(dev->parent, priv->int_sts_reg);
   if (val < 0) {
       printf("%s: i2c read reg 0x%x failed, ret=%d\n",
              __func__, priv->int_sts_reg, val);
       return val;
   }
   ret = pmic_reg_write(dev->parent,
                priv->int_sts_reg,
                val | (1 << RTC_ALARM_EN));
   if (ret < 0) {
       printf("%s: i2c write reg 0x%x failed, ret=%d\n",
              __func__, priv->int_sts_reg, ret);
       return ret;
   }
   debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->int_msk_reg,
         pmic_reg_read(dev->parent, priv->int_msk_reg));
   debug("%s: reg[0x%x] = 0x%x\n", __func__, priv->int_sts_reg,
         pmic_reg_read(dev->parent, priv->int_sts_reg));
 
   return rtc_interrupt_init(dev);
}
 
U_BOOT_DRIVER(rk8xx_rtc) = {
   .name   = "rk8xx_rtc",
   .id     = UCLASS_RTC,
   .probe  = rk8xx_rtc_probe,
   .ops    = &rk8xx_rtc_ops,
   .priv_auto_alloc_size = sizeof(struct rk8xx_rtc_priv),
};