1e9034789SMichal Meloun /*-
2e9034789SMichal Meloun  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3e9034789SMichal Meloun  *
4e9034789SMichal Meloun  * Copyright 2020 Michal Meloun <mmel@FreeBSD.org>
5e9034789SMichal Meloun  *
6e9034789SMichal Meloun  * Redistribution and use in source and binary forms, with or without
7e9034789SMichal Meloun  * modification, are permitted provided that the following conditions
8e9034789SMichal Meloun  * are met:
9e9034789SMichal Meloun  * 1. Redistributions of source code must retain the above copyright
10e9034789SMichal Meloun  *    notice, this list of conditions and the following disclaimer.
11e9034789SMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
12e9034789SMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
13e9034789SMichal Meloun  *    documentation and/or other materials provided with the distribution.
14e9034789SMichal Meloun  *
15e9034789SMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e9034789SMichal Meloun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e9034789SMichal Meloun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e9034789SMichal Meloun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e9034789SMichal Meloun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e9034789SMichal Meloun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e9034789SMichal Meloun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e9034789SMichal Meloun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e9034789SMichal Meloun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e9034789SMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e9034789SMichal Meloun  * SUCH DAMAGE.
26e9034789SMichal Meloun  */
27e9034789SMichal Meloun 
28e9034789SMichal Meloun #include <sys/cdefs.h>
29e9034789SMichal Meloun __FBSDID("$FreeBSD$");
30e9034789SMichal Meloun 
31e9034789SMichal Meloun #include <sys/param.h>
32e9034789SMichal Meloun #include <sys/systm.h>
33e9034789SMichal Meloun #include <sys/bus.h>
34e9034789SMichal Meloun #include <sys/clock.h>
35e9034789SMichal Meloun #include <sys/kernel.h>
36e9034789SMichal Meloun #include <sys/module.h>
37e9034789SMichal Meloun #include <sys/rman.h>
38e9034789SMichal Meloun #include <sys/sx.h>
39e9034789SMichal Meloun 
40e9034789SMichal Meloun #include <dev/iicbus/iiconf.h>
41e9034789SMichal Meloun #include <dev/iicbus/iicbus.h>
42e9034789SMichal Meloun #include <dev/ofw/ofw_bus.h>
43a534b50eSMichal Meloun #include <dev/ofw/ofw_bus_subr.h>
44e9034789SMichal Meloun 
45e9034789SMichal Meloun #include "clock_if.h"
46a534b50eSMichal Meloun #include "ofw_iicbus_if.h"
47e9034789SMichal Meloun #include "max77620.h"
48a534b50eSMichal Meloun 
49e9034789SMichal Meloun #define	MAX77620_RTC_INT	0x00
50e9034789SMichal Meloun #define	MAX77620_RTC_INTM	0x01
51e9034789SMichal Meloun #define	MAX77620_RTC_CONTROLM	0x02
52e9034789SMichal Meloun #define	MAX77620_RTC_CONTROL	0x03
53e9034789SMichal Meloun #define  RTC_CONTROL_MODE_24		(1 << 1)
54e9034789SMichal Meloun #define  RTC_CONTROL_BCD_EN		(1 << 0)
55e9034789SMichal Meloun 
56e9034789SMichal Meloun #define	MAX77620_RTC_UPDATE0	0x04
57e9034789SMichal Meloun #define	 RTC_UPDATE0_RTC_RBUDR		(1 << 4)
58e9034789SMichal Meloun #define	 RTC_UPDATE0_RTC_UDR		(1 << 0)
59e9034789SMichal Meloun 
60e9034789SMichal Meloun #define	MAX77620_WTSR_SMPL_CNTL	0x06
61e9034789SMichal Meloun #define	MAX77620_RTC_SEC	0x07
62e9034789SMichal Meloun #define	MAX77620_RTC_MIN	0x08
63e9034789SMichal Meloun #define	MAX77620_RTC_HOUR	0x09
64e9034789SMichal Meloun #define	MAX77620_RTC_WEEKDAY	0x0A
65e9034789SMichal Meloun #define	MAX77620_RTC_MONTH	0x0B
66e9034789SMichal Meloun #define	MAX77620_RTC_YEAR	0x0C
67e9034789SMichal Meloun #define	MAX77620_RTC_DATE	0x0D
68e9034789SMichal Meloun #define	MAX77620_ALARM1_SEC	0x0E
69e9034789SMichal Meloun #define	MAX77620_ALARM1_MIN	0x0F
70e9034789SMichal Meloun #define	MAX77620_ALARM1_HOUR	0x10
71e9034789SMichal Meloun #define	MAX77620_ALARM1_WEEKDAY	0x11
72e9034789SMichal Meloun #define	MAX77620_ALARM1_MONTH	0x12
73e9034789SMichal Meloun #define	MAX77620_ALARM1_YEAR	0x13
74e9034789SMichal Meloun #define	MAX77620_ALARM1_DATE	0x14
75e9034789SMichal Meloun #define	MAX77620_ALARM2_SEC	0x15
76e9034789SMichal Meloun #define	MAX77620_ALARM2_MIN	0x16
77e9034789SMichal Meloun #define	MAX77620_ALARM2_HOUR	0x17
78e9034789SMichal Meloun #define	MAX77620_ALARM2_WEEKDAY	0x18
79e9034789SMichal Meloun #define	MAX77620_ALARM2_MONTH	0x19
80e9034789SMichal Meloun #define	MAX77620_ALARM2_YEAR	0x1A
81e9034789SMichal Meloun #define	MAX77620_ALARM2_DATE	0x1B
82e9034789SMichal Meloun 
83e9034789SMichal Meloun #define	MAX77620_RTC_START_YEAR	2000
84e9034789SMichal Meloun #define MAX77620_RTC_I2C_ADDR	0x68
85e9034789SMichal Meloun 
86e9034789SMichal Meloun #define	LOCK(_sc)		sx_xlock(&(_sc)->lock)
87e9034789SMichal Meloun #define	UNLOCK(_sc)		sx_xunlock(&(_sc)->lock)
88e9034789SMichal Meloun #define	LOCK_INIT(_sc)		sx_init(&(_sc)->lock, "max77620_rtc")
89e9034789SMichal Meloun #define	LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->lock);
90e9034789SMichal Meloun 
91e9034789SMichal Meloun struct max77620_rtc_softc {
92e9034789SMichal Meloun 	device_t			dev;
93e9034789SMichal Meloun 	struct sx			lock;
94e9034789SMichal Meloun 	int				bus_addr;
95e9034789SMichal Meloun };
96e9034789SMichal Meloun 
97a534b50eSMichal Meloun char max77620_rtc_compat[] = "maxim,max77620_rtc";
98a534b50eSMichal Meloun 
99e9034789SMichal Meloun /*
100e9034789SMichal Meloun  * Raw register access function.
101e9034789SMichal Meloun  */
102e9034789SMichal Meloun static int
103e9034789SMichal Meloun max77620_rtc_read(struct max77620_rtc_softc *sc, uint8_t reg, uint8_t *val)
104e9034789SMichal Meloun {
105e9034789SMichal Meloun 	uint8_t addr;
106e9034789SMichal Meloun 	int rv;
107e9034789SMichal Meloun 	struct iic_msg msgs[2] = {
108e9034789SMichal Meloun 		{0, IIC_M_WR, 1, &addr},
109e9034789SMichal Meloun 		{0, IIC_M_RD, 1, val},
110e9034789SMichal Meloun 	};
111e9034789SMichal Meloun 
112e9034789SMichal Meloun 	msgs[0].slave = sc->bus_addr;
113e9034789SMichal Meloun 	msgs[1].slave = sc->bus_addr;
114e9034789SMichal Meloun 	addr = reg;
115e9034789SMichal Meloun 
116e9034789SMichal Meloun 	rv = iicbus_transfer(sc->dev, msgs, 2);
117e9034789SMichal Meloun 	if (rv != 0) {
118e9034789SMichal Meloun 		device_printf(sc->dev,
119e9034789SMichal Meloun 		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
120e9034789SMichal Meloun 		return (EIO);
121e9034789SMichal Meloun 	}
122e9034789SMichal Meloun 
123e9034789SMichal Meloun 	return (0);
124e9034789SMichal Meloun }
125e9034789SMichal Meloun 
126e9034789SMichal Meloun static int
127e9034789SMichal Meloun max77620_rtc_read_buf(struct max77620_rtc_softc *sc, uint8_t reg,
128e9034789SMichal Meloun     uint8_t *buf, size_t size)
129e9034789SMichal Meloun {
130e9034789SMichal Meloun 	uint8_t addr;
131e9034789SMichal Meloun 	int rv;
132e9034789SMichal Meloun 	struct iic_msg msgs[2] = {
133e9034789SMichal Meloun 		{0, IIC_M_WR, 1, &addr},
134e9034789SMichal Meloun 		{0, IIC_M_RD, size, buf},
135e9034789SMichal Meloun 	};
136e9034789SMichal Meloun 
137e9034789SMichal Meloun 	msgs[0].slave = sc->bus_addr;
138e9034789SMichal Meloun 	msgs[1].slave = sc->bus_addr;
139e9034789SMichal Meloun 	addr = reg;
140e9034789SMichal Meloun 
141e9034789SMichal Meloun 	rv = iicbus_transfer(sc->dev, msgs, 2);
142e9034789SMichal Meloun 	if (rv != 0) {
143e9034789SMichal Meloun 		device_printf(sc->dev,
144e9034789SMichal Meloun 		    "Error when reading reg 0x%02X, rv: %d\n", reg,  rv);
145e9034789SMichal Meloun 		return (EIO);
146e9034789SMichal Meloun 	}
147e9034789SMichal Meloun 
148e9034789SMichal Meloun 	return (0);
149e9034789SMichal Meloun }
150e9034789SMichal Meloun 
151e9034789SMichal Meloun static int
152e9034789SMichal Meloun max77620_rtc_write(struct max77620_rtc_softc *sc, uint8_t reg, uint8_t val)
153e9034789SMichal Meloun {
154e9034789SMichal Meloun 	uint8_t data[2];
155e9034789SMichal Meloun 	int rv;
156e9034789SMichal Meloun 
157e9034789SMichal Meloun 	struct iic_msg msgs[1] = {
158e9034789SMichal Meloun 		{0, IIC_M_WR, 2, data},
159e9034789SMichal Meloun 	};
160e9034789SMichal Meloun 
161e9034789SMichal Meloun 	msgs[0].slave = sc->bus_addr;
162e9034789SMichal Meloun 	data[0] = reg;
163e9034789SMichal Meloun 	data[1] = val;
164e9034789SMichal Meloun 
165e9034789SMichal Meloun 	rv = iicbus_transfer(sc->dev, msgs, 1);
166e9034789SMichal Meloun 	if (rv != 0) {
167e9034789SMichal Meloun 		device_printf(sc->dev,
168e9034789SMichal Meloun 		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
169e9034789SMichal Meloun 		return (EIO);
170e9034789SMichal Meloun 	}
171e9034789SMichal Meloun 	return (0);
172e9034789SMichal Meloun }
173e9034789SMichal Meloun 
174e9034789SMichal Meloun static int
175e9034789SMichal Meloun max77620_rtc_write_buf(struct max77620_rtc_softc *sc, uint8_t reg, uint8_t *buf,
176e9034789SMichal Meloun     size_t size)
177e9034789SMichal Meloun {
178e9034789SMichal Meloun 	uint8_t data[1];
179e9034789SMichal Meloun 	int rv;
180e9034789SMichal Meloun 	struct iic_msg msgs[2] = {
181e9034789SMichal Meloun 		{0, IIC_M_WR, 1, data},
182e9034789SMichal Meloun 		{0, IIC_M_WR | IIC_M_NOSTART, size, buf},
183e9034789SMichal Meloun 	};
184e9034789SMichal Meloun 
185e9034789SMichal Meloun 	msgs[0].slave = sc->bus_addr;
186e9034789SMichal Meloun 	msgs[1].slave = sc->bus_addr;
187e9034789SMichal Meloun 	data[0] = reg;
188e9034789SMichal Meloun 
189e9034789SMichal Meloun 	rv = iicbus_transfer(sc->dev, msgs, 2);
190e9034789SMichal Meloun 	if (rv != 0) {
191e9034789SMichal Meloun 		device_printf(sc->dev,
192e9034789SMichal Meloun 		    "Error when writing reg 0x%02X, rv: %d\n", reg, rv);
193e9034789SMichal Meloun 		return (EIO);
194e9034789SMichal Meloun 	}
195e9034789SMichal Meloun 	return (0);
196e9034789SMichal Meloun }
197e9034789SMichal Meloun 
198e9034789SMichal Meloun static int
199e9034789SMichal Meloun max77620_rtc_modify(struct max77620_rtc_softc *sc, uint8_t reg, uint8_t clear,
200e9034789SMichal Meloun     uint8_t set)
201e9034789SMichal Meloun {
202e9034789SMichal Meloun 	uint8_t val;
203e9034789SMichal Meloun 	int rv;
204e9034789SMichal Meloun 
205e9034789SMichal Meloun 	rv = max77620_rtc_read(sc, reg, &val);
206e9034789SMichal Meloun 	if (rv != 0)
207e9034789SMichal Meloun 		return (rv);
208e9034789SMichal Meloun 
209e9034789SMichal Meloun 	val &= ~clear;
210e9034789SMichal Meloun 	val |= set;
211e9034789SMichal Meloun 
212e9034789SMichal Meloun 	rv = max77620_rtc_write(sc, reg, val);
213e9034789SMichal Meloun 	if (rv != 0)
214e9034789SMichal Meloun 		return (rv);
215e9034789SMichal Meloun 
216e9034789SMichal Meloun 	return (0);
217e9034789SMichal Meloun }
218e9034789SMichal Meloun 
219e9034789SMichal Meloun static int
220e9034789SMichal Meloun max77620_rtc_update(struct max77620_rtc_softc *sc, bool for_read)
221e9034789SMichal Meloun {
222e9034789SMichal Meloun 	uint8_t reg;
223e9034789SMichal Meloun 	int rv;
224e9034789SMichal Meloun 
225e9034789SMichal Meloun 	reg = for_read ? RTC_UPDATE0_RTC_RBUDR: RTC_UPDATE0_RTC_UDR;
226e9034789SMichal Meloun 	rv = max77620_rtc_modify(sc, MAX77620_RTC_UPDATE0, reg, reg);
227e9034789SMichal Meloun 	if (rv != 0)
228e9034789SMichal Meloun 		return (rv);
229e9034789SMichal Meloun 
230e9034789SMichal Meloun 	DELAY(16000);
231e9034789SMichal Meloun 	return (rv);
232e9034789SMichal Meloun }
233e9034789SMichal Meloun 
234e9034789SMichal Meloun static int
235e9034789SMichal Meloun max77620_rtc_gettime(device_t dev, struct timespec *ts)
236e9034789SMichal Meloun {
237e9034789SMichal Meloun 	struct max77620_rtc_softc *sc;
238e9034789SMichal Meloun 	struct clocktime ct;
239e9034789SMichal Meloun 	uint8_t buf[7];
240e9034789SMichal Meloun 	int rv;
241e9034789SMichal Meloun 
242e9034789SMichal Meloun 	sc = device_get_softc(dev);
243e9034789SMichal Meloun 
244e9034789SMichal Meloun 	LOCK(sc);
245e9034789SMichal Meloun 	rv = max77620_rtc_update(sc, true);
246e9034789SMichal Meloun 	if (rv != 0) {
247e9034789SMichal Meloun 		UNLOCK(sc);
248e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to strobe RTC data\n");
249e9034789SMichal Meloun 		return (rv);
250e9034789SMichal Meloun 	}
251e9034789SMichal Meloun 
252e9034789SMichal Meloun 	rv = max77620_rtc_read_buf(sc, MAX77620_RTC_SEC, buf, nitems(buf));
253e9034789SMichal Meloun 	UNLOCK(sc);
254e9034789SMichal Meloun 	if (rv != 0) {
255e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to read RTC data\n");
256e9034789SMichal Meloun 		return (rv);
257e9034789SMichal Meloun 	}
258e9034789SMichal Meloun 	ct.nsec = 0;
259e9034789SMichal Meloun 	ct.sec  = bcd2bin(buf[0] & 0x7F);
260e9034789SMichal Meloun 	ct.min  = bcd2bin(buf[1] & 0x7F);
261e9034789SMichal Meloun 	ct.hour = bcd2bin(buf[2] & 0x3F);
262e9034789SMichal Meloun 	ct.dow  = ffs(buf[3] & 07);
263e9034789SMichal Meloun 	ct.mon  = bcd2bin(buf[4] & 0x1F);
264e9034789SMichal Meloun 	ct.year = bcd2bin(buf[5] & 0x7F) + MAX77620_RTC_START_YEAR;
265e9034789SMichal Meloun 	ct.day  = bcd2bin(buf[6] & 0x3F);
266e9034789SMichal Meloun 
267e9034789SMichal Meloun 	return (clock_ct_to_ts(&ct, ts));
268e9034789SMichal Meloun }
269e9034789SMichal Meloun 
270e9034789SMichal Meloun static int
271e9034789SMichal Meloun max77620_rtc_settime(device_t dev, struct timespec *ts)
272e9034789SMichal Meloun {
273e9034789SMichal Meloun 	struct max77620_rtc_softc *sc;
274e9034789SMichal Meloun 	struct clocktime ct;
275e9034789SMichal Meloun 	uint8_t buf[7];
276e9034789SMichal Meloun 	int rv;
277e9034789SMichal Meloun 
278e9034789SMichal Meloun 	sc = device_get_softc(dev);
279e9034789SMichal Meloun 	clock_ts_to_ct(ts, &ct);
280e9034789SMichal Meloun 
281e9034789SMichal Meloun 	if (ct.year < MAX77620_RTC_START_YEAR)
282e9034789SMichal Meloun 		return (EINVAL);
283e9034789SMichal Meloun 
284e9034789SMichal Meloun 	buf[0] = bin2bcd(ct.sec);
285e9034789SMichal Meloun 	buf[1] = bin2bcd(ct.min);
286e9034789SMichal Meloun 	buf[2] = bin2bcd(ct.hour);
287e9034789SMichal Meloun 	buf[3] = 1 << ct.dow;
288e9034789SMichal Meloun 	buf[4] = bin2bcd(ct.mon);
289e9034789SMichal Meloun 	buf[5] = bin2bcd(ct.year - MAX77620_RTC_START_YEAR);
290e9034789SMichal Meloun 	buf[6] = bin2bcd(ct.day);
291e9034789SMichal Meloun 
292e9034789SMichal Meloun 	LOCK(sc);
293e9034789SMichal Meloun 	rv = max77620_rtc_write_buf(sc, MAX77620_RTC_SEC, buf, nitems(buf));
294e9034789SMichal Meloun 	if (rv != 0) {
295e9034789SMichal Meloun 		UNLOCK(sc);
296e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to write RTC data\n");
297e9034789SMichal Meloun 		return (rv);
298e9034789SMichal Meloun 	}
299e9034789SMichal Meloun 	rv = max77620_rtc_update(sc, false);
300e9034789SMichal Meloun 	UNLOCK(sc);
301e9034789SMichal Meloun 	if (rv != 0) {
302e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to update RTC data\n");
303e9034789SMichal Meloun 		return (rv);
304e9034789SMichal Meloun 	}
305e9034789SMichal Meloun 
306e9034789SMichal Meloun 	return (0);
307e9034789SMichal Meloun }
308e9034789SMichal Meloun 
309e9034789SMichal Meloun static int
310e9034789SMichal Meloun max77620_rtc_probe(device_t dev)
311e9034789SMichal Meloun {
312a534b50eSMichal Meloun 	const char *compat;
313e9034789SMichal Meloun 
314a534b50eSMichal Meloun 	/*
315a534b50eSMichal Meloun 	 * TODO:
316a534b50eSMichal Meloun 	 * ofw_bus_is_compatible() should use compat string from devinfo cache
317a534b50eSMichal Meloun 	 * maximum size of OFW property should be defined in public header
318a534b50eSMichal Meloun 	 */
319a534b50eSMichal Meloun 	if ((compat = ofw_bus_get_compat(dev)) == NULL)
320e9034789SMichal Meloun 		return (ENXIO);
321a534b50eSMichal Meloun 	if (strncasecmp(compat, max77620_rtc_compat, 255) != 0)
322e9034789SMichal Meloun 		return (ENXIO);
323e9034789SMichal Meloun 
324e9034789SMichal Meloun 	device_set_desc(dev, "MAX77620 RTC");
325e9034789SMichal Meloun 	return (BUS_PROBE_DEFAULT);
326e9034789SMichal Meloun }
327e9034789SMichal Meloun 
328e9034789SMichal Meloun static int
329e9034789SMichal Meloun max77620_rtc_attach(device_t dev)
330e9034789SMichal Meloun {
331e9034789SMichal Meloun 	struct max77620_rtc_softc *sc;
332e9034789SMichal Meloun 	uint8_t reg;
333e9034789SMichal Meloun 	int rv;
334e9034789SMichal Meloun 
335e9034789SMichal Meloun 	sc = device_get_softc(dev);
336e9034789SMichal Meloun 	sc->dev = dev;
337e9034789SMichal Meloun 	sc->bus_addr = iicbus_get_addr(dev);
338e9034789SMichal Meloun 
339e9034789SMichal Meloun 	LOCK_INIT(sc);
340e9034789SMichal Meloun 
341e9034789SMichal Meloun 	reg = RTC_CONTROL_MODE_24 | RTC_CONTROL_BCD_EN;
342e9034789SMichal Meloun 	rv = max77620_rtc_modify(sc, MAX77620_RTC_CONTROLM, reg, reg);
343e9034789SMichal Meloun 	if (rv != 0) {
344e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to configure RTC\n");
345e9034789SMichal Meloun 		goto fail;
346e9034789SMichal Meloun 	}
347e9034789SMichal Meloun 
348e9034789SMichal Meloun 	rv = max77620_rtc_modify(sc, MAX77620_RTC_CONTROL, reg, reg);
349e9034789SMichal Meloun 	if (rv != 0) {
350e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to configure RTC\n");
351e9034789SMichal Meloun 		goto fail;
352e9034789SMichal Meloun 	}
353e9034789SMichal Meloun 	rv = max77620_rtc_update(sc, false);
354e9034789SMichal Meloun 	if (rv != 0) {
355e9034789SMichal Meloun 		device_printf(sc->dev, "Failed to update RTC data\n");
356e9034789SMichal Meloun 		return (rv);
357e9034789SMichal Meloun 	}
358e9034789SMichal Meloun 
359e9034789SMichal Meloun 	clock_register(sc->dev, 1000000);
360e9034789SMichal Meloun 
361e9034789SMichal Meloun 	return (bus_generic_attach(dev));
362e9034789SMichal Meloun 
363e9034789SMichal Meloun fail:
364e9034789SMichal Meloun 	LOCK_DESTROY(sc);
365e9034789SMichal Meloun 	return (rv);
366e9034789SMichal Meloun }
367e9034789SMichal Meloun 
368e9034789SMichal Meloun static int
369e9034789SMichal Meloun max77620_rtc_detach(device_t dev)
370e9034789SMichal Meloun {
371e9034789SMichal Meloun 	struct max77620_softc *sc;
372e9034789SMichal Meloun 
373e9034789SMichal Meloun 	sc = device_get_softc(dev);
374e9034789SMichal Meloun 	LOCK_DESTROY(sc);
375e9034789SMichal Meloun 
376e9034789SMichal Meloun 	return (bus_generic_detach(dev));
377e9034789SMichal Meloun }
378e9034789SMichal Meloun 
379a534b50eSMichal Meloun /*
380a534b50eSMichal Meloun  * The secondary address of MAX77620 (RTC function) is not in DT,
381a534b50eSMichal Meloun  * add it manualy as subdevice
382a534b50eSMichal Meloun  */
383e9034789SMichal Meloun int
384e9034789SMichal Meloun max77620_rtc_create(struct max77620_softc *sc, phandle_t node)
385e9034789SMichal Meloun {
386e9034789SMichal Meloun 	device_t parent, child;
387a534b50eSMichal Meloun 	int rv;
388e9034789SMichal Meloun 
389e9034789SMichal Meloun 	parent = device_get_parent(sc->dev);
390a534b50eSMichal Meloun 
391e9034789SMichal Meloun 	child = BUS_ADD_CHILD(parent, 0, NULL, -1);
392a534b50eSMichal Meloun 	if (child == NULL)	{
393a534b50eSMichal Meloun 		device_printf(sc->dev, "Cannot create MAX77620 RTC device.\n");
394e9034789SMichal Meloun 		return (ENXIO);
395e9034789SMichal Meloun 	}
396a534b50eSMichal Meloun 
397a534b50eSMichal Meloun 	rv = OFW_IICBUS_SET_DEVINFO(parent, child, -1, "rtc@68",
398a534b50eSMichal Meloun 	     max77620_rtc_compat, MAX77620_RTC_I2C_ADDR << 1);
399a534b50eSMichal Meloun 	if (rv != 0)	{
400a534b50eSMichal Meloun 		device_printf(sc->dev, "Cannot setup MAX77620 RTC device.\n");
401e9034789SMichal Meloun 		return (ENXIO);
402e9034789SMichal Meloun 	}
403a534b50eSMichal Meloun 
404e9034789SMichal Meloun 	return (0);
405e9034789SMichal Meloun }
406e9034789SMichal Meloun 
407e9034789SMichal Meloun static device_method_t max77620_rtc_methods[] = {
408e9034789SMichal Meloun 	/* Device interface */
409e9034789SMichal Meloun 	DEVMETHOD(device_probe,		max77620_rtc_probe),
410e9034789SMichal Meloun 	DEVMETHOD(device_attach,	max77620_rtc_attach),
411e9034789SMichal Meloun 	DEVMETHOD(device_detach,	max77620_rtc_detach),
412e9034789SMichal Meloun 
413e9034789SMichal Meloun 	/* RTC interface */
414e9034789SMichal Meloun 	DEVMETHOD(clock_gettime,	max77620_rtc_gettime),
415e9034789SMichal Meloun 	DEVMETHOD(clock_settime,	max77620_rtc_settime),
416e9034789SMichal Meloun 
417e9034789SMichal Meloun 	DEVMETHOD_END
418e9034789SMichal Meloun };
419e9034789SMichal Meloun 
420e9034789SMichal Meloun static DEFINE_CLASS_0(rtc, max77620_rtc_driver, max77620_rtc_methods,
421e9034789SMichal Meloun     sizeof(struct max77620_rtc_softc));
422289f133bSJohn Baldwin EARLY_DRIVER_MODULE(max77620rtc_, iicbus, max77620_rtc_driver, NULL, NULL, 74);
423