xref: /openbsd/sys/dev/fdt/dapmic.c (revision 0701a158)
1 /*	$OpenBSD: dapmic.c,v 1.4 2022/10/12 13:39:50 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/task.h>
23 #include <sys/proc.h>
24 #include <sys/signalvar.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_regulator.h>
28 #include <dev/ofw/fdt.h>
29 
30 #include <dev/i2c/i2cvar.h>
31 
32 #include <dev/clock_subr.h>
33 
34 #include <machine/fdt.h>
35 
36 extern void (*cpuresetfn)(void);
37 extern void (*powerdownfn)(void);
38 
39 /* Registers */
40 #define FAULT_LOG		0x05
41 #define EVENT_A			0x06
42 #define  EVENT_A_EVENTS_D		(1 << 7)
43 #define  EVENT_A_EVENTS_C		(1 << 6)
44 #define  EVENT_A_EVENTS_B		(1 << 5)
45 #define  EVENT_A_E_nONKEY		(1 << 0)
46 #define EVENT_B			0x07
47 #define EVENT_C			0x08
48 #define EVENT_D			0x09
49 #define IRQ_MASK_A		0x0a
50 #define  IRQ_MASK_A_M_RESERVED		((1 << 7) | (1 << 6) | (1 << 5))
51 #define  IRQ_MASK_A_M_SEQ_RDY		(1 << 4)
52 #define  IRQ_MASK_A_M_ADC_RDY		(1 << 3)
53 #define  IRQ_MASK_A_M_TICK		(1 << 2)
54 #define  IRQ_MASK_A_M_ALARM		(1 << 1)
55 #define  IRQ_MASK_A_M_nONKEY		(1 << 0)
56 #define IRQ_MASK_B		0x0b
57 #define IRQ_MASK_C		0x0c
58 #define IRQ_MASK_D		0x0d
59 #define CONTROL_F		0x13
60 #define  CONTROL_F_WAKE_UP		(1 << 2)
61 #define  CONTROL_F_SHUTDOWN		(1 << 1)
62 #define COUNT_S			0x40
63 #define  COUNT_S_COUNT_SEC		0x3f
64 #define COUNT_MI		0x41
65 #define  COUNT_MI_COUNT_MIN		0x3f
66 #define COUNT_H			0x42
67 #define  COUNT_H_COUNT_HOUR		0x1f
68 #define COUNT_D			0x43
69 #define  COUNT_D_COUNT_DAY		0x1f
70 #define COUNT_MO		0x44
71 #define  COUNT_MO_COUNT_MONTH		0x0f
72 #define COUNT_Y			0x45
73 #define  COUNT_Y_MONITOR		(1 << 6)
74 #define  COUNT_Y_COUNT_YEAR		0x3f
75 #define ALARM_MO		0x4a
76 #define  ALARM_MO_TICK_WAKE		(1 << 5)
77 #define  ALARM_MO_TICK_TYPE		(1 << 4)
78 #define ALARM_Y			0x4b
79 #define  ALARM_Y_TICK_ON		(1 << 7)
80 
81 #ifdef DAPMIC_DEBUG
82 # define DPRINTF(args) do { printf args; } while (0)
83 #else
84 # define DPRINTF(args) do {} while (0)
85 #endif
86 
87 struct dapmic_softc {
88 	struct device sc_dev;
89 	i2c_tag_t sc_tag;
90 	i2c_addr_t sc_addr;
91 
92 	int (*sc_ih)(void *);
93 	struct task sc_task;
94 
95 	struct todr_chip_handle sc_todr;
96 };
97 
98 int	dapmic_match(struct device *, void *, void *);
99 void	dapmic_attach(struct device *, struct device *, void *);
100 
101 const struct cfattach dapmic_ca = {
102 	sizeof(struct dapmic_softc), dapmic_match, dapmic_attach
103 };
104 
105 struct cfdriver dapmic_cd = {
106 	NULL, "dapmic", DV_DULL
107 };
108 
109 uint8_t	dapmic_reg_read(struct dapmic_softc *, int);
110 void	dapmic_reg_write(struct dapmic_softc *, int, uint8_t);
111 int	dapmic_clock_read(struct dapmic_softc *, struct clock_ymdhms *);
112 int	dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *);
113 int	dapmic_gettime(struct todr_chip_handle *, struct timeval *);
114 int	dapmic_settime(struct todr_chip_handle *, struct timeval *);
115 void	dapmic_reset_irq_mask(struct dapmic_softc *);
116 void	dapmic_reset(void);
117 void	dapmic_powerdown(void);
118 int	dapmic_intr(void *);
119 void	dapmic_shutdown_task(void *);
120 
121 int
dapmic_match(struct device * parent,void * match,void * aux)122 dapmic_match(struct device *parent, void *match, void *aux)
123 {
124 	struct i2c_attach_args *ia = aux;
125 
126 	return (strcmp(ia->ia_name, "dlg,da9063") == 0);
127 }
128 
129 void
dapmic_attach(struct device * parent,struct device * self,void * aux)130 dapmic_attach(struct device *parent, struct device *self, void *aux)
131 {
132 	struct dapmic_softc *sc = (struct dapmic_softc *)self;
133 	struct i2c_attach_args *ia = aux;
134 	int node = *(int *)ia->ia_cookie;
135 
136 	sc->sc_tag = ia->ia_tag;
137 	sc->sc_addr = ia->ia_addr;
138 
139 	sc->sc_todr.cookie = sc;
140 	sc->sc_todr.todr_gettime = dapmic_gettime;
141 	sc->sc_todr.todr_settime = dapmic_settime;
142 	sc->sc_todr.todr_quality = 0;
143 	todr_attach(&sc->sc_todr);
144 
145 	if (cpuresetfn == NULL)
146 		cpuresetfn = dapmic_reset;
147 	if (powerdownfn == NULL)
148 		powerdownfn = dapmic_powerdown;
149 
150 	task_set(&sc->sc_task, dapmic_shutdown_task, sc);
151 
152 	/* Mask away events we don't care about */
153 	dapmic_reg_write(sc, IRQ_MASK_A,
154 	    0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY));
155 	dapmic_reg_write(sc, IRQ_MASK_B, 0xff);
156 	dapmic_reg_write(sc, IRQ_MASK_C, 0xff);
157 	dapmic_reg_write(sc, IRQ_MASK_D, 0xff);
158 
159 	/* Clear past faults and events. */
160 	dapmic_reg_write(sc, FAULT_LOG, dapmic_reg_read(sc, FAULT_LOG));
161 	dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A));
162 	dapmic_reg_write(sc, EVENT_B, dapmic_reg_read(sc, EVENT_B));
163 	dapmic_reg_write(sc, EVENT_C, dapmic_reg_read(sc, EVENT_C));
164 	dapmic_reg_write(sc, EVENT_D, dapmic_reg_read(sc, EVENT_D));
165 
166 	if (node != 0) {
167                 sc->sc_ih = fdt_intr_establish_idx(node, 0, IPL_CLOCK,
168 		    dapmic_intr, sc, sc->sc_dev.dv_xname);
169                 if (sc->sc_ih == NULL)
170                         printf(", can't establish interrupt");
171         }
172 
173 	printf("\n");
174 }
175 
176 uint8_t
dapmic_reg_read(struct dapmic_softc * sc,int reg)177 dapmic_reg_read(struct dapmic_softc *sc, int reg)
178 {
179 	uint8_t cmd = reg;
180 	uint8_t val;
181 	int error;
182 
183 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
184 	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
185 	    &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL);
186 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
187 
188 	if (error) {
189 		printf("%s: can't read register 0x%02x\n",
190 		    sc->sc_dev.dv_xname, reg);
191 		val = 0xff;
192 	}
193 
194 	return val;
195 }
196 
197 void
dapmic_reg_write(struct dapmic_softc * sc,int reg,uint8_t val)198 dapmic_reg_write(struct dapmic_softc *sc, int reg, uint8_t val)
199 {
200 	uint8_t cmd = reg;
201 	int error;
202 
203 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
204 	error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
205 	    &cmd, sizeof cmd, &val, sizeof val, I2C_F_POLL);
206 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
207 
208 	if (error) {
209 		printf("%s: can't write register 0x%02x\n",
210 		    sc->sc_dev.dv_xname, reg);
211 	}
212 }
213 
214 int
dapmic_clock_read(struct dapmic_softc * sc,struct clock_ymdhms * dt)215 dapmic_clock_read(struct dapmic_softc *sc, struct clock_ymdhms *dt)
216 {
217 	uint8_t regs[6];
218 	uint8_t cmd = COUNT_S;
219 	int error;
220 
221 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
222 	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
223 	    &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL);
224 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
225 
226 	if (error)
227 		return error;
228 
229 	dt->dt_sec = (regs[0] & COUNT_S_COUNT_SEC);
230 	dt->dt_min = (regs[1] & COUNT_MI_COUNT_MIN);
231 	dt->dt_hour = (regs[2] & COUNT_H_COUNT_HOUR);
232 	dt->dt_day = (regs[3] & COUNT_D_COUNT_DAY);
233 	dt->dt_mon = (regs[4] & COUNT_MO_COUNT_MONTH);
234 	dt->dt_year = (regs[5] & COUNT_Y_COUNT_YEAR) + 2000;
235 
236 	/* Consider the time to be invalid if the MONITOR bit isn't set. */
237 	if ((regs[5] & COUNT_Y_MONITOR) == 0)
238 		return EINVAL;
239 
240 	return 0;
241 }
242 
243 int
dapmic_clock_write(struct dapmic_softc * sc,struct clock_ymdhms * dt)244 dapmic_clock_write(struct dapmic_softc *sc, struct clock_ymdhms *dt)
245 {
246 	uint8_t regs[6];
247 	uint8_t cmd = COUNT_S;
248 	int error;
249 
250 	regs[0] = dt->dt_sec;
251 	regs[1] = dt->dt_min;
252 	regs[2] = dt->dt_hour;
253 	regs[3] = dt->dt_day;
254 	regs[4] = dt->dt_mon;
255 	regs[5] = (dt->dt_year - 2000) | COUNT_Y_MONITOR;
256 
257 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
258 	error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
259 	    &cmd, sizeof(cmd), regs, sizeof(regs), I2C_F_POLL);
260 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
261 
262 	if (error)
263 		return error;
264 
265 	return 0;
266 }
267 
268 int
dapmic_gettime(struct todr_chip_handle * handle,struct timeval * tv)269 dapmic_gettime(struct todr_chip_handle *handle, struct timeval *tv)
270 {
271 	struct dapmic_softc *sc = handle->cookie;
272 	struct clock_ymdhms dt;
273 	int error;
274 
275 	error = dapmic_clock_read(sc, &dt);
276 	if (error)
277 		return error;
278 
279 	if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 ||
280 	    dt.dt_day > 31 || dt.dt_day == 0 ||
281 	    dt.dt_mon > 12 || dt.dt_mon == 0 ||
282 	    dt.dt_year < POSIX_BASE_YEAR)
283 		return EINVAL;
284 
285 	tv->tv_sec = clock_ymdhms_to_secs(&dt);
286 	tv->tv_usec = 0;
287 	return 0;
288 }
289 
290 int
dapmic_settime(struct todr_chip_handle * handle,struct timeval * tv)291 dapmic_settime(struct todr_chip_handle *handle, struct timeval *tv)
292 {
293 	struct dapmic_softc *sc = handle->cookie;
294 	struct clock_ymdhms dt;
295 
296 	clock_secs_to_ymdhms(tv->tv_sec, &dt);
297 
298 	return dapmic_clock_write(sc, &dt);
299 }
300 
301 void
dapmic_reset_irq_mask(struct dapmic_softc * sc)302 dapmic_reset_irq_mask(struct dapmic_softc *sc)
303 {
304 	dapmic_reg_write(sc, IRQ_MASK_A, 0);
305 	dapmic_reg_write(sc, IRQ_MASK_B, 0);
306 	dapmic_reg_write(sc, IRQ_MASK_C, 0);
307 	dapmic_reg_write(sc, IRQ_MASK_D, 0);
308 }
309 
310 void
dapmic_reset(void)311 dapmic_reset(void)
312 {
313 	struct dapmic_softc *sc = dapmic_cd.cd_devs[0];
314 	uint8_t reg;
315 
316 	/* Re-enable irqs and the associated wake-up events. */
317 	dapmic_reset_irq_mask(sc);
318 
319 	/* Enable tick alarm wakeup with a one second interval. */
320 	reg = dapmic_reg_read(sc, ALARM_MO);
321 	reg &= ~ALARM_MO_TICK_TYPE;
322 	reg |= ALARM_MO_TICK_WAKE;
323 	dapmic_reg_write(sc, ALARM_MO, reg);
324 
325 	/* Enable tick function. */
326 	reg = dapmic_reg_read(sc, ALARM_Y);
327 	reg |= ALARM_Y_TICK_ON;
328 	dapmic_reg_write(sc, ALARM_Y, reg);
329 
330 	/* Clear events such that we wake up again. */
331 	dapmic_reg_write(sc, EVENT_A, dapmic_reg_read(sc, EVENT_A));
332 	dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN);
333 }
334 
335 void
dapmic_powerdown(void)336 dapmic_powerdown(void)
337 {
338 	struct dapmic_softc *sc = dapmic_cd.cd_devs[0];
339 	uint8_t reg;
340 
341 	/* Re-enable irqs and the associated wake-up events. */
342 	dapmic_reset_irq_mask(sc);
343 
344 	/* Disable tick function such that it doesn't wake us up. */
345 	reg = dapmic_reg_read(sc, ALARM_Y);
346 	reg &= ~ALARM_Y_TICK_ON;
347 	dapmic_reg_write(sc, ALARM_Y, reg);
348 
349 	dapmic_reg_write(sc, CONTROL_F, CONTROL_F_SHUTDOWN);
350 }
351 
352 void
dapmic_shutdown_task(void * arg)353 dapmic_shutdown_task(void *arg)
354 {
355 	extern int allowpowerdown;
356 
357 	if (allowpowerdown == 1) {
358 		allowpowerdown = 0;
359 		prsignal(initprocess, SIGUSR2);
360 	}
361 }
362 
363 int
dapmic_intr(void * arg)364 dapmic_intr(void *arg)
365 {
366 	struct dapmic_softc *sc = arg;
367 	uint8_t event_a, event_b, event_c, event_d, fault;
368 
369 	event_b = event_c = event_d = 0;
370 
371 	event_a = dapmic_reg_read(sc, EVENT_A);
372 	DPRINTF(("%s: %s: event_a %#02.2hhx", sc->sc_dev.dv_xname, __func__,
373 	    event_a));
374 
375 	/* Acknowledge all events. */
376 	if (event_a & EVENT_A_EVENTS_B) {
377 		event_b = dapmic_reg_read(sc, EVENT_B);
378 		DPRINTF((", event_b %#02.2hhx", event_b));
379 		if (event_b != 0)
380 			dapmic_reg_write(sc, EVENT_B, event_b);
381 	}
382 	if (event_a & EVENT_A_EVENTS_C) {
383 		event_c = dapmic_reg_read(sc, EVENT_C);
384 		DPRINTF((", event_c %#02.2hhx", event_c));
385 		if (event_c != 0)
386 			dapmic_reg_write(sc, EVENT_C, event_c);
387 	}
388 	if (event_a & EVENT_A_EVENTS_D) {
389 		event_d = dapmic_reg_read(sc, EVENT_D);
390 		DPRINTF((", event_d %#02.2hhx", event_d));
391 		if (event_d != 0)
392 			dapmic_reg_write(sc, EVENT_D, event_d);
393 	}
394 	event_a &= ~(EVENT_A_EVENTS_B|EVENT_A_EVENTS_C|EVENT_A_EVENTS_D);
395 	if (event_a != 0)
396 		dapmic_reg_write(sc, EVENT_A, event_a);
397 
398 	DPRINTF(("\n"));
399 
400 	fault = dapmic_reg_read(sc, FAULT_LOG);
401 	if (fault != 0) {
402 		static int warned;
403 		if (!warned) {
404 			warned = 1;
405 			printf("%s: FAULT_LOG %#02.2hhx\n", sc->sc_dev.dv_xname,
406 			    fault);
407 		}
408 		/*
409 		 * Don't blindly acknowledge the fault log bits, else we may
410 		 * prevent legit behavior like a forced poweroff with a long
411 		 * power button press.
412 		 */
413 	}
414 
415 	if (event_a & EVENT_A_E_nONKEY)
416 		task_add(systq, &sc->sc_task);
417 
418 	if (event_a | event_b | event_c | event_d)
419 		return 1;
420 
421 	return 0;
422 }
423