1 // 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 
18 #include <dm.h>
19 #include <rtc.h>
20 #include <bcd.h>
21 #include <asm/gpio.h>
22 #include <linux/delay.h>
23 
24 struct ht1380_priv {
25 	struct gpio_desc rst_desc;
26 	struct gpio_desc clk_desc;
27 	struct gpio_desc dat_desc;
28 };
29 
30 enum registers {
31 	SEC,
32 	MIN,
33 	HOUR,
34 	MDAY,
35 	MONTH,
36 	WDAY,
37 	YEAR,
38 	WP,
39 	N_REGS
40 };
41 
42 enum hour_mode {
43 	AMPM_MODE = 0x80, /* RTC is in AM/PM mode */
44 	PM_NOW = 0x20,    /* set if PM, clear if AM */
45 };
46 
47 static const int BURST = 0xbe;
48 static const int READ = 1;
49 
ht1380_half_period_delay(void)50 static 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 
ht1380_send_byte(struct ht1380_priv * priv,int byte)59 static 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  */
ht1380_reset_off(struct ht1380_priv * priv)85 static 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  */
ht1380_reset_on(struct ht1380_priv * priv)103 static 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 
ht1380_rtc_get(struct udevice * dev,struct rtc_time * tm)118 static 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 
194 exit:
195 	ht1380_reset_on(priv);
196 
197 	return ret;
198 }
199 
ht1380_write_protection_off(struct ht1380_priv * priv)200 static 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 
ht1380_rtc_set(struct udevice * dev,const struct rtc_time * tm)219 static 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 
253 exit:
254 	ht1380_reset_on(priv);
255 
256 	return ret;
257 }
258 
ht1380_probe(struct udevice * dev)259 static 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 
289 fail:
290 	dm_gpio_free(dev, &priv->dat_desc);
291 fail_dat:
292 	dm_gpio_free(dev, &priv->clk_desc);
293 fail_clk:
294 	dm_gpio_free(dev, &priv->rst_desc);
295 fail_rst:
296 	return ret;
297 }
298 
ht1380_remove(struct udevice * dev)299 static 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 
310 static const struct rtc_ops ht1380_rtc_ops = {
311 	.get = ht1380_rtc_get,
312 	.set = ht1380_rtc_set,
313 };
314 
315 static const struct udevice_id ht1380_rtc_ids[] = {
316 	{ .compatible = "holtek,ht1380" },
317 	{ }
318 };
319 
320 U_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 };
329