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