blob: c202261e99990ea2392b864fce4a98707d9c9454 [file] [log] [blame]
Sergei Antonov34d09ef2022-12-09 19:15:30 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Holtek HT1380/HT1381 Serial Timekeeper Chip
4 *
5 * Communication with the chip is vendor-specific.
6 * It is done via 3 GPIO pins: reset, clock, and data.
7 * Describe in .dts this way:
8 *
9 * rtc {
10 * compatible = "holtek,ht1380";
11 * rst-gpios = <&gpio 19 GPIO_ACTIVE_LOW>;
12 * clk-gpios = <&gpio 20 GPIO_ACTIVE_HIGH>;
13 * dat-gpios = <&gpio 21 GPIO_ACTIVE_HIGH>;
14 * };
15 *
16 */
17
Sergei Antonov34d09ef2022-12-09 19:15:30 +030018#include <dm.h>
19#include <rtc.h>
20#include <bcd.h>
21#include <asm/gpio.h>
22#include <linux/delay.h>
23
24struct ht1380_priv {
25 struct gpio_desc rst_desc;
26 struct gpio_desc clk_desc;
27 struct gpio_desc dat_desc;
28};
29
30enum registers {
31 SEC,
32 MIN,
33 HOUR,
34 MDAY,
35 MONTH,
36 WDAY,
37 YEAR,
38 WP,
39 N_REGS
40};
41
42enum hour_mode {
43 AMPM_MODE = 0x80, /* RTC is in AM/PM mode */
44 PM_NOW = 0x20, /* set if PM, clear if AM */
45};
46
47static const int BURST = 0xbe;
48static const int READ = 1;
49
50static void ht1380_half_period_delay(void)
51{
52 /*
53 * Delay for half a period. 1 us complies with the 500 KHz maximum
54 * input serial clock limit given by the datasheet.
55 */
56 udelay(1);
57}
58
59static int ht1380_send_byte(struct ht1380_priv *priv, int byte)
60{
61 int ret;
62
63 for (int bit = 0; bit < 8; bit++) {
64 ret = dm_gpio_set_value(&priv->dat_desc, byte >> bit & 1);
65 if (ret)
66 break;
67 ht1380_half_period_delay();
68
69 ret = dm_gpio_set_value(&priv->clk_desc, 1);
70 if (ret)
71 break;
72 ht1380_half_period_delay();
73
74 ret = dm_gpio_set_value(&priv->clk_desc, 0);
75 if (ret)
76 break;
77 }
78
79 return ret;
80}
81
82/*
83 * Leave reset state. The transfer operation can then be started.
84 */
85static int ht1380_reset_off(struct ht1380_priv *priv)
86{
87 const unsigned int T_CC = 4; /* us, Reset to Clock Setup */
88 int ret;
89
90 /*
91 * Leave RESET state.
92 * Make sure we make the minimal delay required by the datasheet.
93 */
94 ret = dm_gpio_set_value(&priv->rst_desc, 0);
95 udelay(T_CC);
96
97 return ret;
98}
99
100/*
101 * Enter reset state. Completes the transfer operation.
102 */
103static int ht1380_reset_on(struct ht1380_priv *priv)
104{
105 const unsigned int T_CWH = 4; /* us, Reset Inactive Time */
106 int ret;
107
108 /*
109 * Enter RESET state.
110 * Make sure we make the minimal delay required by the datasheet.
111 */
112 ret = dm_gpio_set_value(&priv->rst_desc, 1);
113 udelay(T_CWH);
114
115 return ret;
116}
117
118static int ht1380_rtc_get(struct udevice *dev, struct rtc_time *tm)
119{
120 struct ht1380_priv *priv = dev_get_priv(dev);
121 int ret, i, bit, reg[N_REGS];
122
123 ret = dm_gpio_set_value(&priv->clk_desc, 0);
124 if (ret)
125 return ret;
126
127 ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_OUT);
128 if (ret)
129 return ret;
130
131 ret = ht1380_reset_off(priv);
132 if (ret)
133 goto exit;
134
135 ret = ht1380_send_byte(priv, BURST + READ);
136 if (ret)
137 goto exit;
138
139 ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_IN);
140 if (ret)
141 goto exit;
142
143 for (i = 0; i < N_REGS; i++) {
144 reg[i] = 0;
145
146 for (bit = 0; bit < 8; bit++) {
147 ht1380_half_period_delay();
148
149 ret = dm_gpio_set_value(&priv->clk_desc, 1);
150 if (ret)
151 goto exit;
152 ht1380_half_period_delay();
153
154 reg[i] |= dm_gpio_get_value(&priv->dat_desc) << bit;
155 ret = dm_gpio_set_value(&priv->clk_desc, 0);
156 if (ret)
157 goto exit;
158 }
159 }
160
161 ret = -EINVAL;
162
163 /* Correctness check: some bits are always zero */
164 if (reg[MIN] & 0x80 || reg[HOUR] & 0x40 || reg[MDAY] & 0xc0 ||
165 reg[MONTH] & 0xe0 || reg[WDAY] & 0xf8 || reg[WP] & 0x7f)
166 goto exit;
167
168 /* Correctness check: some registers are always non-zero */
169 if (!reg[MDAY] || !reg[MONTH] || !reg[WDAY])
170 goto exit;
171
172 tm->tm_sec = bcd2bin(reg[SEC]);
173 tm->tm_min = bcd2bin(reg[MIN]);
174 if (reg[HOUR] & AMPM_MODE) {
175 /* AM-PM Mode, range is 01-12 */
176 tm->tm_hour = bcd2bin(reg[HOUR] & 0x1f) % 12;
177 if (reg[HOUR] & PM_NOW) {
178 /* it is PM (otherwise AM) */
179 tm->tm_hour += 12;
180 }
181 } else {
182 /* 24-hour Mode, range is 0-23 */
183 tm->tm_hour = bcd2bin(reg[HOUR]);
184 }
185 tm->tm_mday = bcd2bin(reg[MDAY]);
186 tm->tm_mon = bcd2bin(reg[MONTH]);
187 tm->tm_year = 2000 + bcd2bin(reg[YEAR]);
188 tm->tm_wday = bcd2bin(reg[WDAY]) - 1;
189 tm->tm_yday = 0;
190 tm->tm_isdst = 0;
191
192 ret = 0;
193
194exit:
195 ht1380_reset_on(priv);
196
197 return ret;
198}
199
200static int ht1380_write_protection_off(struct ht1380_priv *priv)
201{
202 int ret;
203 const int PROTECT = 0x8e;
204
205 ret = ht1380_reset_off(priv);
206 if (ret)
207 return ret;
208
209 ret = ht1380_send_byte(priv, PROTECT);
210 if (ret)
211 return ret;
212 ret = ht1380_send_byte(priv, 0); /* WP bit is 0 */
213 if (ret)
214 return ret;
215
216 return ht1380_reset_on(priv);
217}
218
219static int ht1380_rtc_set(struct udevice *dev, const struct rtc_time *tm)
220{
221 struct ht1380_priv *priv = dev_get_priv(dev);
222 int ret, i, reg[N_REGS];
223
224 ret = dm_gpio_set_value(&priv->clk_desc, 0);
225 if (ret)
226 return ret;
227
228 ret = dm_gpio_set_dir_flags(&priv->dat_desc, GPIOD_IS_OUT);
229 if (ret)
230 goto exit;
231
232 ret = ht1380_write_protection_off(priv);
233 if (ret)
234 goto exit;
235
236 reg[SEC] = bin2bcd(tm->tm_sec);
237 reg[MIN] = bin2bcd(tm->tm_min);
238 reg[HOUR] = bin2bcd(tm->tm_hour);
239 reg[MDAY] = bin2bcd(tm->tm_mday);
240 reg[MONTH] = bin2bcd(tm->tm_mon);
241 reg[WDAY] = bin2bcd(tm->tm_wday) + 1;
242 reg[YEAR] = bin2bcd(tm->tm_year - 2000);
243 reg[WP] = 0x80; /* WP bit is 1 */
244
245 ret = ht1380_reset_off(priv);
246 if (ret)
247 goto exit;
248
249 ret = ht1380_send_byte(priv, BURST);
250 for (i = 0; i < N_REGS && ret; i++)
251 ret = ht1380_send_byte(priv, reg[i]);
252
253exit:
254 ht1380_reset_on(priv);
255
256 return ret;
257}
258
259static int ht1380_probe(struct udevice *dev)
260{
261 int ret;
262 struct ht1380_priv *priv;
263
264 priv = dev_get_priv(dev);
265 if (!priv)
266 return -EINVAL;
267
268 ret = gpio_request_by_name(dev, "rst-gpios", 0,
269 &priv->rst_desc, GPIOD_IS_OUT);
270 if (ret)
271 goto fail_rst;
272
273 ret = gpio_request_by_name(dev, "clk-gpios", 0,
274 &priv->clk_desc, GPIOD_IS_OUT);
275 if (ret)
276 goto fail_clk;
277
278 ret = gpio_request_by_name(dev, "dat-gpios", 0,
279 &priv->dat_desc, 0);
280 if (ret)
281 goto fail_dat;
282
283 ret = ht1380_reset_on(priv);
284 if (ret)
285 goto fail;
286
287 return 0;
288
289fail:
290 dm_gpio_free(dev, &priv->dat_desc);
291fail_dat:
292 dm_gpio_free(dev, &priv->clk_desc);
293fail_clk:
294 dm_gpio_free(dev, &priv->rst_desc);
295fail_rst:
296 return ret;
297}
298
299static int ht1380_remove(struct udevice *dev)
300{
301 struct ht1380_priv *priv = dev_get_priv(dev);
302
303 dm_gpio_free(dev, &priv->rst_desc);
304 dm_gpio_free(dev, &priv->clk_desc);
305 dm_gpio_free(dev, &priv->dat_desc);
306
307 return 0;
308}
309
310static const struct rtc_ops ht1380_rtc_ops = {
311 .get = ht1380_rtc_get,
312 .set = ht1380_rtc_set,
313};
314
315static const struct udevice_id ht1380_rtc_ids[] = {
316 { .compatible = "holtek,ht1380" },
317 { }
318};
319
320U_BOOT_DRIVER(rtc_ht1380) = {
321 .name = "rtc-ht1380",
322 .id = UCLASS_RTC,
323 .probe = ht1380_probe,
324 .remove = ht1380_remove,
325 .of_match = ht1380_rtc_ids,
326 .ops = &ht1380_rtc_ops,
327 .priv_auto = sizeof(struct ht1380_priv),
328};