1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * MOXA ART RTC driver. |
4 | * |
5 | * Copyright (C) 2013 Jonas Jensen |
6 | * |
7 | * Jonas Jensen <jonas.jensen@gmail.com> |
8 | * |
9 | * Based on code from |
10 | * Moxa Technology Co., Ltd. <www.moxa.com> |
11 | */ |
12 | |
13 | #include <linux/err.h> |
14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/rtc.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/module.h> |
20 | #include <linux/mod_devicetable.h> |
21 | #include <linux/gpio/consumer.h> |
22 | |
23 | #define GPIO_RTC_RESERVED 0x0C |
24 | #define GPIO_RTC_DATA_SET 0x10 |
25 | #define GPIO_RTC_DATA_CLEAR 0x14 |
26 | #define GPIO_RTC_PIN_PULL_ENABLE 0x18 |
27 | #define GPIO_RTC_PIN_PULL_TYPE 0x1C |
28 | #define GPIO_RTC_INT_ENABLE 0x20 |
29 | #define GPIO_RTC_INT_RAW_STATE 0x24 |
30 | #define GPIO_RTC_INT_MASKED_STATE 0x28 |
31 | #define GPIO_RTC_INT_MASK 0x2C |
32 | #define GPIO_RTC_INT_CLEAR 0x30 |
33 | #define GPIO_RTC_INT_TRIGGER 0x34 |
34 | #define GPIO_RTC_INT_BOTH 0x38 |
35 | #define GPIO_RTC_INT_RISE_NEG 0x3C |
36 | #define GPIO_RTC_BOUNCE_ENABLE 0x40 |
37 | #define GPIO_RTC_BOUNCE_PRE_SCALE 0x44 |
38 | #define GPIO_RTC_PROTECT_W 0x8E |
39 | #define GPIO_RTC_PROTECT_R 0x8F |
40 | #define GPIO_RTC_YEAR_W 0x8C |
41 | #define GPIO_RTC_YEAR_R 0x8D |
42 | #define GPIO_RTC_DAY_W 0x8A |
43 | #define GPIO_RTC_DAY_R 0x8B |
44 | #define GPIO_RTC_MONTH_W 0x88 |
45 | #define GPIO_RTC_MONTH_R 0x89 |
46 | #define GPIO_RTC_DATE_W 0x86 |
47 | #define GPIO_RTC_DATE_R 0x87 |
48 | #define GPIO_RTC_HOURS_W 0x84 |
49 | #define GPIO_RTC_HOURS_R 0x85 |
50 | #define GPIO_RTC_MINUTES_W 0x82 |
51 | #define GPIO_RTC_MINUTES_R 0x83 |
52 | #define GPIO_RTC_SECONDS_W 0x80 |
53 | #define GPIO_RTC_SECONDS_R 0x81 |
54 | #define GPIO_RTC_DELAY_TIME 8 |
55 | |
56 | struct moxart_rtc { |
57 | struct rtc_device *rtc; |
58 | spinlock_t rtc_lock; |
59 | struct gpio_desc *gpio_data; |
60 | struct gpio_desc *gpio_sclk; |
61 | struct gpio_desc *gpio_reset; |
62 | }; |
63 | |
64 | static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, |
65 | 212, 243, 273, 304, 334 }; |
66 | |
67 | static void moxart_rtc_write_byte(struct device *dev, u8 data) |
68 | { |
69 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
70 | int i; |
71 | |
72 | for (i = 0; i < 8; i++, data >>= 1) { |
73 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 0); |
74 | gpiod_set_value(desc: moxart_rtc->gpio_data, value: ((data & 1) == 1)); |
75 | udelay(GPIO_RTC_DELAY_TIME); |
76 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 1); |
77 | udelay(GPIO_RTC_DELAY_TIME); |
78 | } |
79 | } |
80 | |
81 | static u8 moxart_rtc_read_byte(struct device *dev) |
82 | { |
83 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
84 | int i; |
85 | u8 data = 0; |
86 | |
87 | for (i = 0; i < 8; i++) { |
88 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 0); |
89 | udelay(GPIO_RTC_DELAY_TIME); |
90 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 1); |
91 | udelay(GPIO_RTC_DELAY_TIME); |
92 | if (gpiod_get_value(desc: moxart_rtc->gpio_data)) |
93 | data |= (1 << i); |
94 | udelay(GPIO_RTC_DELAY_TIME); |
95 | } |
96 | return data; |
97 | } |
98 | |
99 | static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) |
100 | { |
101 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
102 | u8 data; |
103 | unsigned long flags; |
104 | |
105 | local_irq_save(flags); |
106 | |
107 | gpiod_direction_output(desc: moxart_rtc->gpio_data, value: 0); |
108 | gpiod_set_value(desc: moxart_rtc->gpio_reset, value: 1); |
109 | udelay(GPIO_RTC_DELAY_TIME); |
110 | moxart_rtc_write_byte(dev, data: cmd); |
111 | gpiod_direction_input(desc: moxart_rtc->gpio_data); |
112 | udelay(GPIO_RTC_DELAY_TIME); |
113 | data = moxart_rtc_read_byte(dev); |
114 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 0); |
115 | gpiod_set_value(desc: moxart_rtc->gpio_reset, value: 0); |
116 | udelay(GPIO_RTC_DELAY_TIME); |
117 | |
118 | local_irq_restore(flags); |
119 | |
120 | return data; |
121 | } |
122 | |
123 | static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) |
124 | { |
125 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
126 | unsigned long flags; |
127 | |
128 | local_irq_save(flags); |
129 | |
130 | gpiod_direction_output(desc: moxart_rtc->gpio_data, value: 0); |
131 | gpiod_set_value(desc: moxart_rtc->gpio_reset, value: 1); |
132 | udelay(GPIO_RTC_DELAY_TIME); |
133 | moxart_rtc_write_byte(dev, data: cmd); |
134 | moxart_rtc_write_byte(dev, data); |
135 | gpiod_set_value(desc: moxart_rtc->gpio_sclk, value: 0); |
136 | gpiod_set_value(desc: moxart_rtc->gpio_reset, value: 0); |
137 | udelay(GPIO_RTC_DELAY_TIME); |
138 | |
139 | local_irq_restore(flags); |
140 | } |
141 | |
142 | static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm) |
143 | { |
144 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
145 | |
146 | spin_lock_irq(lock: &moxart_rtc->rtc_lock); |
147 | |
148 | moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, data: 0); |
149 | moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W, |
150 | data: (((tm->tm_year - 100) / 10) << 4) | |
151 | ((tm->tm_year - 100) % 10)); |
152 | |
153 | moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W, |
154 | data: (((tm->tm_mon + 1) / 10) << 4) | |
155 | ((tm->tm_mon + 1) % 10)); |
156 | |
157 | moxart_rtc_write_register(dev, GPIO_RTC_DATE_W, |
158 | data: ((tm->tm_mday / 10) << 4) | |
159 | (tm->tm_mday % 10)); |
160 | |
161 | moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W, |
162 | data: ((tm->tm_hour / 10) << 4) | |
163 | (tm->tm_hour % 10)); |
164 | |
165 | moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W, |
166 | data: ((tm->tm_min / 10) << 4) | |
167 | (tm->tm_min % 10)); |
168 | |
169 | moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W, |
170 | data: ((tm->tm_sec / 10) << 4) | |
171 | (tm->tm_sec % 10)); |
172 | |
173 | moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, data: 0x80); |
174 | |
175 | spin_unlock_irq(lock: &moxart_rtc->rtc_lock); |
176 | |
177 | dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n" |
178 | "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n" , |
179 | __func__, tm->tm_year, tm->tm_mon, tm->tm_mday, |
180 | tm->tm_hour, tm->tm_min, tm->tm_sec); |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm) |
186 | { |
187 | struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev); |
188 | unsigned char v; |
189 | |
190 | spin_lock_irq(lock: &moxart_rtc->rtc_lock); |
191 | |
192 | v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R); |
193 | tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F); |
194 | |
195 | v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R); |
196 | tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F); |
197 | |
198 | v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R); |
199 | if (v & 0x80) { /* 12-hour mode */ |
200 | tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F); |
201 | if (v & 0x20) { /* PM mode */ |
202 | tm->tm_hour += 12; |
203 | if (tm->tm_hour >= 24) |
204 | tm->tm_hour = 0; |
205 | } |
206 | } else { /* 24-hour mode */ |
207 | tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F); |
208 | } |
209 | |
210 | v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R); |
211 | tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F); |
212 | |
213 | v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R); |
214 | tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F); |
215 | tm->tm_mon--; |
216 | |
217 | v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R); |
218 | tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F); |
219 | tm->tm_year += 100; |
220 | if (tm->tm_year <= 69) |
221 | tm->tm_year += 100; |
222 | |
223 | v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R); |
224 | tm->tm_wday = (v & 0x0f) - 1; |
225 | tm->tm_yday = day_of_year[tm->tm_mon]; |
226 | tm->tm_yday += (tm->tm_mday - 1); |
227 | if (tm->tm_mon >= 2) { |
228 | if (!(tm->tm_year % 4) && (tm->tm_year % 100)) |
229 | tm->tm_yday++; |
230 | } |
231 | |
232 | tm->tm_isdst = 0; |
233 | |
234 | spin_unlock_irq(lock: &moxart_rtc->rtc_lock); |
235 | |
236 | return 0; |
237 | } |
238 | |
239 | static const struct rtc_class_ops moxart_rtc_ops = { |
240 | .read_time = moxart_rtc_read_time, |
241 | .set_time = moxart_rtc_set_time, |
242 | }; |
243 | |
244 | static int moxart_rtc_probe(struct platform_device *pdev) |
245 | { |
246 | struct moxart_rtc *moxart_rtc; |
247 | int ret = 0; |
248 | |
249 | moxart_rtc = devm_kzalloc(dev: &pdev->dev, size: sizeof(*moxart_rtc), GFP_KERNEL); |
250 | if (!moxart_rtc) |
251 | return -ENOMEM; |
252 | |
253 | moxart_rtc->gpio_data = devm_gpiod_get(dev: &pdev->dev, con_id: "rtc-data" , |
254 | flags: GPIOD_IN); |
255 | ret = PTR_ERR_OR_ZERO(ptr: moxart_rtc->gpio_data); |
256 | if (ret) { |
257 | dev_err(&pdev->dev, "can't get rtc data gpio: %d\n" , ret); |
258 | return ret; |
259 | } |
260 | |
261 | moxart_rtc->gpio_sclk = devm_gpiod_get(dev: &pdev->dev, con_id: "rtc-sclk" , |
262 | flags: GPIOD_ASIS); |
263 | ret = PTR_ERR_OR_ZERO(ptr: moxart_rtc->gpio_sclk); |
264 | if (ret) { |
265 | dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n" , ret); |
266 | return ret; |
267 | } |
268 | |
269 | moxart_rtc->gpio_reset = devm_gpiod_get(dev: &pdev->dev, con_id: "rtc-reset" , |
270 | flags: GPIOD_ASIS); |
271 | ret = PTR_ERR_OR_ZERO(ptr: moxart_rtc->gpio_reset); |
272 | if (ret) { |
273 | dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n" , ret); |
274 | return ret; |
275 | } |
276 | |
277 | spin_lock_init(&moxart_rtc->rtc_lock); |
278 | platform_set_drvdata(pdev, data: moxart_rtc); |
279 | |
280 | moxart_rtc->rtc = devm_rtc_device_register(dev: &pdev->dev, name: pdev->name, |
281 | ops: &moxart_rtc_ops, |
282 | THIS_MODULE); |
283 | if (IS_ERR(ptr: moxart_rtc->rtc)) { |
284 | dev_err(&pdev->dev, "devm_rtc_device_register failed\n" ); |
285 | return PTR_ERR(ptr: moxart_rtc->rtc); |
286 | } |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static const struct of_device_id moxart_rtc_match[] = { |
292 | { .compatible = "moxa,moxart-rtc" }, |
293 | { }, |
294 | }; |
295 | MODULE_DEVICE_TABLE(of, moxart_rtc_match); |
296 | |
297 | static struct platform_driver moxart_rtc_driver = { |
298 | .probe = moxart_rtc_probe, |
299 | .driver = { |
300 | .name = "moxart-rtc" , |
301 | .of_match_table = moxart_rtc_match, |
302 | }, |
303 | }; |
304 | module_platform_driver(moxart_rtc_driver); |
305 | |
306 | MODULE_DESCRIPTION("MOXART RTC driver" ); |
307 | MODULE_LICENSE("GPL" ); |
308 | MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>" ); |
309 | |