• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * TI LP8788 MFD - rtc driver
4  *
5  * Copyright 2012 Texas Instruments
6  *
7  * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
8  */
9 
10 #include <linux/err.h>
11 #include <linux/irqdomain.h>
12 #include <linux/mfd/lp8788.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/rtc.h>
16 #include <linux/slab.h>
17 
18 /* register address */
19 #define LP8788_INTEN_3			0x05
20 #define LP8788_RTC_UNLOCK		0x64
21 #define LP8788_RTC_SEC			0x70
22 #define LP8788_ALM1_SEC			0x77
23 #define LP8788_ALM1_EN			0x7D
24 #define LP8788_ALM2_SEC			0x7E
25 #define LP8788_ALM2_EN			0x84
26 
27 /* mask/shift bits */
28 #define LP8788_INT_RTC_ALM1_M		BIT(1)	/* Addr 05h */
29 #define LP8788_INT_RTC_ALM1_S		1
30 #define LP8788_INT_RTC_ALM2_M		BIT(2)	/* Addr 05h */
31 #define LP8788_INT_RTC_ALM2_S		2
32 #define LP8788_ALM_EN_M			BIT(7)	/* Addr 7Dh or 84h */
33 #define LP8788_ALM_EN_S			7
34 
35 #define DEFAULT_ALARM_SEL		LP8788_ALARM_1
36 #define LP8788_MONTH_OFFSET		1
37 #define LP8788_BASE_YEAR		2000
38 #define MAX_WDAY_BITS			7
39 #define LP8788_WDAY_SET			1
40 #define RTC_UNLOCK			0x1
41 #define RTC_LATCH			0x2
42 #define ALARM_IRQ_FLAG			(RTC_IRQF | RTC_AF)
43 
44 enum lp8788_time {
45 	LPTIME_SEC,
46 	LPTIME_MIN,
47 	LPTIME_HOUR,
48 	LPTIME_MDAY,
49 	LPTIME_MON,
50 	LPTIME_YEAR,
51 	LPTIME_WDAY,
52 	LPTIME_MAX,
53 };
54 
55 struct lp8788_rtc {
56 	struct lp8788 *lp;
57 	struct rtc_device *rdev;
58 	enum lp8788_alarm_sel alarm;
59 	int irq;
60 };
61 
62 static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = {
63 	LP8788_ALM1_SEC,
64 	LP8788_ALM2_SEC,
65 };
66 
67 static const u8 addr_alarm_en[LP8788_ALARM_MAX] = {
68 	LP8788_ALM1_EN,
69 	LP8788_ALM2_EN,
70 };
71 
72 static const u8 mask_alarm_en[LP8788_ALARM_MAX] = {
73 	LP8788_INT_RTC_ALM1_M,
74 	LP8788_INT_RTC_ALM2_M,
75 };
76 
77 static const u8 shift_alarm_en[LP8788_ALARM_MAX] = {
78 	LP8788_INT_RTC_ALM1_S,
79 	LP8788_INT_RTC_ALM2_S,
80 };
81 
_to_tm_wday(u8 lp8788_wday)82 static int _to_tm_wday(u8 lp8788_wday)
83 {
84 	int i;
85 
86 	if (lp8788_wday == 0)
87 		return 0;
88 
89 	/* lookup defined weekday from read register value */
90 	for (i = 0; i < MAX_WDAY_BITS; i++) {
91 		if ((lp8788_wday >> i) == LP8788_WDAY_SET)
92 			break;
93 	}
94 
95 	return i + 1;
96 }
97 
_to_lp8788_wday(int tm_wday)98 static inline int _to_lp8788_wday(int tm_wday)
99 {
100 	return LP8788_WDAY_SET << (tm_wday - 1);
101 }
102 
lp8788_rtc_unlock(struct lp8788 * lp)103 static void lp8788_rtc_unlock(struct lp8788 *lp)
104 {
105 	lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK);
106 	lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH);
107 }
108 
lp8788_rtc_read_time(struct device * dev,struct rtc_time * tm)109 static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm)
110 {
111 	struct lp8788_rtc *rtc = dev_get_drvdata(dev);
112 	struct lp8788 *lp = rtc->lp;
113 	u8 data[LPTIME_MAX];
114 	int ret;
115 
116 	lp8788_rtc_unlock(lp);
117 
118 	ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data,	LPTIME_MAX);
119 	if (ret)
120 		return ret;
121 
122 	tm->tm_sec  = data[LPTIME_SEC];
123 	tm->tm_min  = data[LPTIME_MIN];
124 	tm->tm_hour = data[LPTIME_HOUR];
125 	tm->tm_mday = data[LPTIME_MDAY];
126 	tm->tm_mon  = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
127 	tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
128 	tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
129 
130 	return 0;
131 }
132 
lp8788_rtc_set_time(struct device * dev,struct rtc_time * tm)133 static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm)
134 {
135 	struct lp8788_rtc *rtc = dev_get_drvdata(dev);
136 	struct lp8788 *lp = rtc->lp;
137 	u8 data[LPTIME_MAX - 1];
138 	int ret, i, year;
139 
140 	year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
141 	if (year < 0) {
142 		dev_err(lp->dev, "invalid year: %d\n", year);
143 		return -EINVAL;
144 	}
145 
146 	/* because rtc weekday is a readonly register, do not update */
147 	data[LPTIME_SEC]  = tm->tm_sec;
148 	data[LPTIME_MIN]  = tm->tm_min;
149 	data[LPTIME_HOUR] = tm->tm_hour;
150 	data[LPTIME_MDAY] = tm->tm_mday;
151 	data[LPTIME_MON]  = tm->tm_mon + LP8788_MONTH_OFFSET;
152 	data[LPTIME_YEAR] = year;
153 
154 	for (i = 0; i < ARRAY_SIZE(data); i++) {
155 		ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]);
156 		if (ret)
157 			return ret;
158 	}
159 
160 	return 0;
161 }
162 
lp8788_read_alarm(struct device * dev,struct rtc_wkalrm * alarm)163 static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
164 {
165 	struct lp8788_rtc *rtc = dev_get_drvdata(dev);
166 	struct lp8788 *lp = rtc->lp;
167 	struct rtc_time *tm = &alarm->time;
168 	u8 addr, data[LPTIME_MAX];
169 	int ret;
170 
171 	addr = addr_alarm_sec[rtc->alarm];
172 	ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX);
173 	if (ret)
174 		return ret;
175 
176 	tm->tm_sec  = data[LPTIME_SEC];
177 	tm->tm_min  = data[LPTIME_MIN];
178 	tm->tm_hour = data[LPTIME_HOUR];
179 	tm->tm_mday = data[LPTIME_MDAY];
180 	tm->tm_mon  = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
181 	tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
182 	tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
183 	alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M;
184 
185 	return 0;
186 }
187 
lp8788_set_alarm(struct device * dev,struct rtc_wkalrm * alarm)188 static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
189 {
190 	struct lp8788_rtc *rtc = dev_get_drvdata(dev);
191 	struct lp8788 *lp = rtc->lp;
192 	struct rtc_time *tm = &alarm->time;
193 	u8 addr, data[LPTIME_MAX];
194 	int ret, i, year;
195 
196 	year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
197 	if (year < 0) {
198 		dev_err(lp->dev, "invalid year: %d\n", year);
199 		return -EINVAL;
200 	}
201 
202 	data[LPTIME_SEC]  = tm->tm_sec;
203 	data[LPTIME_MIN]  = tm->tm_min;
204 	data[LPTIME_HOUR] = tm->tm_hour;
205 	data[LPTIME_MDAY] = tm->tm_mday;
206 	data[LPTIME_MON]  = tm->tm_mon + LP8788_MONTH_OFFSET;
207 	data[LPTIME_YEAR] = year;
208 	data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday);
209 
210 	for (i = 0; i < ARRAY_SIZE(data); i++) {
211 		addr = addr_alarm_sec[rtc->alarm] + i;
212 		ret = lp8788_write_byte(lp, addr, data[i]);
213 		if (ret)
214 			return ret;
215 	}
216 
217 	alarm->enabled = 1;
218 	addr = addr_alarm_en[rtc->alarm];
219 
220 	return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M,
221 				alarm->enabled << LP8788_ALM_EN_S);
222 }
223 
lp8788_alarm_irq_enable(struct device * dev,unsigned int enable)224 static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable)
225 {
226 	struct lp8788_rtc *rtc = dev_get_drvdata(dev);
227 	struct lp8788 *lp = rtc->lp;
228 	u8 mask, shift;
229 
230 	if (!rtc->irq)
231 		return -EIO;
232 
233 	mask = mask_alarm_en[rtc->alarm];
234 	shift = shift_alarm_en[rtc->alarm];
235 
236 	return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift);
237 }
238 
239 static const struct rtc_class_ops lp8788_rtc_ops = {
240 	.read_time = lp8788_rtc_read_time,
241 	.set_time = lp8788_rtc_set_time,
242 	.read_alarm = lp8788_read_alarm,
243 	.set_alarm = lp8788_set_alarm,
244 	.alarm_irq_enable = lp8788_alarm_irq_enable,
245 };
246 
lp8788_alarm_irq_handler(int irq,void * ptr)247 static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr)
248 {
249 	struct lp8788_rtc *rtc = ptr;
250 
251 	rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG);
252 	return IRQ_HANDLED;
253 }
254 
lp8788_alarm_irq_register(struct platform_device * pdev,struct lp8788_rtc * rtc)255 static int lp8788_alarm_irq_register(struct platform_device *pdev,
256 				struct lp8788_rtc *rtc)
257 {
258 	struct resource *r;
259 	struct lp8788 *lp = rtc->lp;
260 	struct irq_domain *irqdm = lp->irqdm;
261 	int irq;
262 
263 	rtc->irq = 0;
264 
265 	/* even the alarm IRQ number is not specified, rtc time should work */
266 	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ);
267 	if (!r)
268 		return 0;
269 
270 	if (rtc->alarm == LP8788_ALARM_1)
271 		irq = r->start;
272 	else
273 		irq = r->end;
274 
275 	rtc->irq = irq_create_mapping(irqdm, irq);
276 
277 	return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
278 				lp8788_alarm_irq_handler,
279 				0, LP8788_ALM_IRQ, rtc);
280 }
281 
lp8788_rtc_probe(struct platform_device * pdev)282 static int lp8788_rtc_probe(struct platform_device *pdev)
283 {
284 	struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
285 	struct lp8788_rtc *rtc;
286 	struct device *dev = &pdev->dev;
287 
288 	rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL);
289 	if (!rtc)
290 		return -ENOMEM;
291 
292 	rtc->lp = lp;
293 	rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL;
294 	platform_set_drvdata(pdev, rtc);
295 
296 	device_init_wakeup(dev, 1);
297 
298 	rtc->rdev = devm_rtc_device_register(dev, "lp8788_rtc",
299 					&lp8788_rtc_ops, THIS_MODULE);
300 	if (IS_ERR(rtc->rdev)) {
301 		dev_err(dev, "can not register rtc device\n");
302 		return PTR_ERR(rtc->rdev);
303 	}
304 
305 	if (lp8788_alarm_irq_register(pdev, rtc))
306 		dev_warn(lp->dev, "no rtc irq handler\n");
307 
308 	return 0;
309 }
310 
311 static struct platform_driver lp8788_rtc_driver = {
312 	.probe = lp8788_rtc_probe,
313 	.driver = {
314 		.name = LP8788_DEV_RTC,
315 	},
316 };
317 module_platform_driver(lp8788_rtc_driver);
318 
319 MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver");
320 MODULE_AUTHOR("Milo Kim");
321 MODULE_LICENSE("GPL");
322 MODULE_ALIAS("platform:lp8788-rtc");
323