xref: /linux/drivers/rtc/rtc-nct6694.c (revision d5f74114114cb2cdbed75b91ca2fa4482c1d5611)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Nuvoton NCT6694 RTC driver based on USB interface.
4  *
5  * Copyright (C) 2025 Nuvoton Technology Corp.
6  */
7 
8 #include <linux/bcd.h>
9 #include <linux/irqdomain.h>
10 #include <linux/kernel.h>
11 #include <linux/mfd/nct6694.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/rtc.h>
15 #include <linux/slab.h>
16 
17 /*
18  * USB command module type for NCT6694 RTC controller.
19  * This defines the module type used for communication with the NCT6694
20  * RTC controller over the USB interface.
21  */
22 #define NCT6694_RTC_MOD		0x08
23 
24 /* Command 00h - RTC Time */
25 #define NCT6694_RTC_TIME	0x0000
26 #define NCT6694_RTC_TIME_SEL	0x00
27 
28 /* Command 01h - RTC Alarm */
29 #define NCT6694_RTC_ALARM	0x01
30 #define NCT6694_RTC_ALARM_SEL	0x00
31 
32 /* Command 02h - RTC Status */
33 #define NCT6694_RTC_STATUS	0x02
34 #define NCT6694_RTC_STATUS_SEL	0x00
35 
36 #define NCT6694_RTC_IRQ_INT_EN	BIT(0)	/* Transmit a USB INT-in when RTC alarm */
37 #define NCT6694_RTC_IRQ_GPO_EN	BIT(5)	/* Trigger a GPO Low Pulse when RTC alarm */
38 
39 #define NCT6694_RTC_IRQ_EN	(NCT6694_RTC_IRQ_INT_EN | NCT6694_RTC_IRQ_GPO_EN)
40 #define NCT6694_RTC_IRQ_STS	BIT(0)	/* Write 1 clear IRQ status */
41 
42 struct __packed nct6694_rtc_time {
43 	u8 sec;
44 	u8 min;
45 	u8 hour;
46 	u8 week;
47 	u8 day;
48 	u8 month;
49 	u8 year;
50 };
51 
52 struct __packed nct6694_rtc_alarm {
53 	u8 sec;
54 	u8 min;
55 	u8 hour;
56 	u8 alarm_en;
57 	u8 alarm_pend;
58 };
59 
60 struct __packed nct6694_rtc_status {
61 	u8 irq_en;
62 	u8 irq_pend;
63 };
64 
65 union __packed nct6694_rtc_msg {
66 	struct nct6694_rtc_time time;
67 	struct nct6694_rtc_alarm alarm;
68 	struct nct6694_rtc_status sts;
69 };
70 
71 struct nct6694_rtc_data {
72 	struct nct6694 *nct6694;
73 	struct rtc_device *rtc;
74 	union nct6694_rtc_msg *msg;
75 	int irq;
76 };
77 
78 static int nct6694_rtc_read_time(struct device *dev, struct rtc_time *tm)
79 {
80 	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
81 	struct nct6694_rtc_time *time = &data->msg->time;
82 	static const struct nct6694_cmd_header cmd_hd = {
83 		.mod = NCT6694_RTC_MOD,
84 		.cmd = NCT6694_RTC_TIME,
85 		.sel = NCT6694_RTC_TIME_SEL,
86 		.len = cpu_to_le16(sizeof(*time))
87 	};
88 	int ret;
89 
90 	ret = nct6694_read_msg(data->nct6694, &cmd_hd, time);
91 	if (ret)
92 		return ret;
93 
94 	tm->tm_sec = bcd2bin(time->sec);		/* tm_sec expect 0 ~ 59 */
95 	tm->tm_min = bcd2bin(time->min);		/* tm_min expect 0 ~ 59 */
96 	tm->tm_hour = bcd2bin(time->hour);		/* tm_hour expect 0 ~ 23 */
97 	tm->tm_wday = bcd2bin(time->week) - 1;		/* tm_wday expect 0 ~ 6 */
98 	tm->tm_mday = bcd2bin(time->day);		/* tm_mday expect 1 ~ 31 */
99 	tm->tm_mon = bcd2bin(time->month) - 1;		/* tm_month expect 0 ~ 11 */
100 	tm->tm_year = bcd2bin(time->year) + 100;	/* tm_year expect since 1900 */
101 
102 	return ret;
103 }
104 
105 static int nct6694_rtc_set_time(struct device *dev, struct rtc_time *tm)
106 {
107 	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
108 	struct nct6694_rtc_time *time = &data->msg->time;
109 	static const struct nct6694_cmd_header cmd_hd = {
110 		.mod = NCT6694_RTC_MOD,
111 		.cmd = NCT6694_RTC_TIME,
112 		.sel = NCT6694_RTC_TIME_SEL,
113 		.len = cpu_to_le16(sizeof(*time))
114 	};
115 
116 	time->sec = bin2bcd(tm->tm_sec);
117 	time->min = bin2bcd(tm->tm_min);
118 	time->hour = bin2bcd(tm->tm_hour);
119 	time->week = bin2bcd(tm->tm_wday + 1);
120 	time->day = bin2bcd(tm->tm_mday);
121 	time->month = bin2bcd(tm->tm_mon + 1);
122 	time->year = bin2bcd(tm->tm_year - 100);
123 
124 	return nct6694_write_msg(data->nct6694, &cmd_hd, time);
125 }
126 
127 static int nct6694_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
128 {
129 	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
130 	struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
131 	static const struct nct6694_cmd_header cmd_hd = {
132 		.mod = NCT6694_RTC_MOD,
133 		.cmd = NCT6694_RTC_ALARM,
134 		.sel = NCT6694_RTC_ALARM_SEL,
135 		.len = cpu_to_le16(sizeof(*alarm))
136 	};
137 	int ret;
138 
139 	ret = nct6694_read_msg(data->nct6694, &cmd_hd, alarm);
140 	if (ret)
141 		return ret;
142 
143 	alrm->time.tm_sec = bcd2bin(alarm->sec);
144 	alrm->time.tm_min = bcd2bin(alarm->min);
145 	alrm->time.tm_hour = bcd2bin(alarm->hour);
146 	alrm->enabled = alarm->alarm_en;
147 	alrm->pending = alarm->alarm_pend;
148 
149 	return ret;
150 }
151 
152 static int nct6694_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
153 {
154 	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
155 	struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
156 	static const struct nct6694_cmd_header cmd_hd = {
157 		.mod = NCT6694_RTC_MOD,
158 		.cmd = NCT6694_RTC_ALARM,
159 		.sel = NCT6694_RTC_ALARM_SEL,
160 		.len = cpu_to_le16(sizeof(*alarm))
161 	};
162 
163 	alarm->sec = bin2bcd(alrm->time.tm_sec);
164 	alarm->min = bin2bcd(alrm->time.tm_min);
165 	alarm->hour = bin2bcd(alrm->time.tm_hour);
166 	alarm->alarm_en = alrm->enabled ? NCT6694_RTC_IRQ_EN : 0;
167 	alarm->alarm_pend = 0;
168 
169 	return nct6694_write_msg(data->nct6694, &cmd_hd, alarm);
170 }
171 
172 static int nct6694_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
173 {
174 	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
175 	struct nct6694_rtc_status *sts = &data->msg->sts;
176 	static const struct nct6694_cmd_header cmd_hd = {
177 		.mod = NCT6694_RTC_MOD,
178 		.cmd = NCT6694_RTC_STATUS,
179 		.sel = NCT6694_RTC_STATUS_SEL,
180 		.len = cpu_to_le16(sizeof(*sts))
181 	};
182 
183 	if (enabled)
184 		sts->irq_en |= NCT6694_RTC_IRQ_EN;
185 	else
186 		sts->irq_en &= ~NCT6694_RTC_IRQ_EN;
187 
188 	sts->irq_pend = 0;
189 
190 	return nct6694_write_msg(data->nct6694, &cmd_hd, sts);
191 }
192 
193 static const struct rtc_class_ops nct6694_rtc_ops = {
194 	.read_time = nct6694_rtc_read_time,
195 	.set_time = nct6694_rtc_set_time,
196 	.read_alarm = nct6694_rtc_read_alarm,
197 	.set_alarm = nct6694_rtc_set_alarm,
198 	.alarm_irq_enable = nct6694_rtc_alarm_irq_enable,
199 };
200 
201 static irqreturn_t nct6694_irq(int irq, void *dev_id)
202 {
203 	struct nct6694_rtc_data *data = dev_id;
204 	struct nct6694_rtc_status *sts = &data->msg->sts;
205 	static const struct nct6694_cmd_header cmd_hd = {
206 		.mod = NCT6694_RTC_MOD,
207 		.cmd = NCT6694_RTC_STATUS,
208 		.sel = NCT6694_RTC_STATUS_SEL,
209 		.len = cpu_to_le16(sizeof(*sts))
210 	};
211 	int ret;
212 
213 	rtc_lock(data->rtc);
214 
215 	sts->irq_en = NCT6694_RTC_IRQ_EN;
216 	sts->irq_pend = NCT6694_RTC_IRQ_STS;
217 	ret = nct6694_write_msg(data->nct6694, &cmd_hd, sts);
218 	if (ret) {
219 		rtc_unlock(data->rtc);
220 		return IRQ_NONE;
221 	}
222 
223 	rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF);
224 
225 	rtc_unlock(data->rtc);
226 
227 	return IRQ_HANDLED;
228 }
229 
230 static void nct6694_irq_dispose_mapping(void *d)
231 {
232 	struct nct6694_rtc_data *data = d;
233 
234 	irq_dispose_mapping(data->irq);
235 }
236 
237 static int nct6694_rtc_probe(struct platform_device *pdev)
238 {
239 	struct nct6694_rtc_data *data;
240 	struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent);
241 	int ret;
242 
243 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
244 	if (!data)
245 		return -ENOMEM;
246 
247 	data->msg = devm_kzalloc(&pdev->dev, sizeof(union nct6694_rtc_msg),
248 				 GFP_KERNEL);
249 	if (!data->msg)
250 		return -ENOMEM;
251 
252 	data->irq = irq_create_mapping(nct6694->domain, NCT6694_IRQ_RTC);
253 	if (!data->irq)
254 		return -EINVAL;
255 
256 	ret = devm_add_action_or_reset(&pdev->dev, nct6694_irq_dispose_mapping,
257 				       data);
258 	if (ret)
259 		return ret;
260 
261 	ret = devm_device_init_wakeup(&pdev->dev);
262 	if (ret)
263 		return dev_err_probe(&pdev->dev, ret, "Failed to init wakeup\n");
264 
265 	data->rtc = devm_rtc_allocate_device(&pdev->dev);
266 	if (IS_ERR(data->rtc))
267 		return PTR_ERR(data->rtc);
268 
269 	data->nct6694 = nct6694;
270 	data->rtc->ops = &nct6694_rtc_ops;
271 	data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
272 	data->rtc->range_max = RTC_TIMESTAMP_END_2099;
273 
274 	platform_set_drvdata(pdev, data);
275 
276 	ret = devm_request_threaded_irq(&pdev->dev, data->irq, NULL,
277 					nct6694_irq, IRQF_ONESHOT,
278 					"rtc-nct6694", data);
279 	if (ret < 0)
280 		return dev_err_probe(&pdev->dev, ret, "Failed to request irq\n");
281 
282 	return devm_rtc_register_device(data->rtc);
283 }
284 
285 static struct platform_driver nct6694_rtc_driver = {
286 	.driver = {
287 		.name	= "nct6694-rtc",
288 	},
289 	.probe		= nct6694_rtc_probe,
290 };
291 
292 module_platform_driver(nct6694_rtc_driver);
293 
294 MODULE_DESCRIPTION("USB-RTC driver for NCT6694");
295 MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
296 MODULE_LICENSE("GPL");
297 MODULE_ALIAS("platform:nct6694-rtc");
298