xref: /freebsd-src/sys/dev/iicbus/rtc/rv3032.c (revision 1d6a6a524409662992ca96bc91ae69b2a2a5ff35)
1*1d6a6a52SEmmanuel Vadot /*-
2*1d6a6a52SEmmanuel Vadot  * SPDX-License-Identifier: BSD-2-Clause
3*1d6a6a52SEmmanuel Vadot  *
4*1d6a6a52SEmmanuel Vadot  * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG
5*1d6a6a52SEmmanuel Vadot  *
6*1d6a6a52SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
7*1d6a6a52SEmmanuel Vadot  * modification, are permitted provided that the following conditions
8*1d6a6a52SEmmanuel Vadot  * are met:
9*1d6a6a52SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
10*1d6a6a52SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
11*1d6a6a52SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
12*1d6a6a52SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
13*1d6a6a52SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
14*1d6a6a52SEmmanuel Vadot  *
15*1d6a6a52SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*1d6a6a52SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*1d6a6a52SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*1d6a6a52SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*1d6a6a52SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*1d6a6a52SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*1d6a6a52SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*1d6a6a52SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*1d6a6a52SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*1d6a6a52SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*1d6a6a52SEmmanuel Vadot  * SUCH DAMAGE.
26*1d6a6a52SEmmanuel Vadot  */
27*1d6a6a52SEmmanuel Vadot 
28*1d6a6a52SEmmanuel Vadot #include <sys/cdefs.h>
29*1d6a6a52SEmmanuel Vadot #include "opt_platform.h"
30*1d6a6a52SEmmanuel Vadot 
31*1d6a6a52SEmmanuel Vadot #include <sys/param.h>
32*1d6a6a52SEmmanuel Vadot #include <sys/systm.h>
33*1d6a6a52SEmmanuel Vadot #include <sys/bus.h>
34*1d6a6a52SEmmanuel Vadot #include <sys/clock.h>
35*1d6a6a52SEmmanuel Vadot #include <sys/kernel.h>
36*1d6a6a52SEmmanuel Vadot #include <sys/lock.h>
37*1d6a6a52SEmmanuel Vadot #include <sys/module.h>
38*1d6a6a52SEmmanuel Vadot #include <sys/sysctl.h>
39*1d6a6a52SEmmanuel Vadot 
40*1d6a6a52SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
41*1d6a6a52SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
42*1d6a6a52SEmmanuel Vadot 
43*1d6a6a52SEmmanuel Vadot #include <dev/iicbus/iiconf.h>
44*1d6a6a52SEmmanuel Vadot #include <dev/iicbus/iicbus.h>
45*1d6a6a52SEmmanuel Vadot 
46*1d6a6a52SEmmanuel Vadot #include "clock_if.h"
47*1d6a6a52SEmmanuel Vadot #include "iicbus_if.h"
48*1d6a6a52SEmmanuel Vadot 
49*1d6a6a52SEmmanuel Vadot /* Date registers */
50*1d6a6a52SEmmanuel Vadot #define	RV3032_SECS_100TH	0x00
51*1d6a6a52SEmmanuel Vadot #define	RV3032_SECS		0x01
52*1d6a6a52SEmmanuel Vadot #define	RV3032_MINS		0x02
53*1d6a6a52SEmmanuel Vadot #define	RV3032_HOURS		0x03
54*1d6a6a52SEmmanuel Vadot #define	RV3032_WEEKDAY		0x04
55*1d6a6a52SEmmanuel Vadot #define	RV3032_DATE		0x05
56*1d6a6a52SEmmanuel Vadot #define	RV3032_MONTH		0x06
57*1d6a6a52SEmmanuel Vadot #define	RV3032_YEAR		0x07
58*1d6a6a52SEmmanuel Vadot 
59*1d6a6a52SEmmanuel Vadot /* Alarm registers */
60*1d6a6a52SEmmanuel Vadot #define	RV3032_ALARM_MINUTES	0x08
61*1d6a6a52SEmmanuel Vadot #define	RV3032_ALARM_HOURS	0x09
62*1d6a6a52SEmmanuel Vadot #define	RV3032_ALARM_DATE	0x0A
63*1d6a6a52SEmmanuel Vadot 
64*1d6a6a52SEmmanuel Vadot /* Periodic countdown timer registers */
65*1d6a6a52SEmmanuel Vadot #define	RV3032_TIMER_VALUE0	0x0B
66*1d6a6a52SEmmanuel Vadot #define	RV3032_TIMER_VALUE1	0x0C
67*1d6a6a52SEmmanuel Vadot 
68*1d6a6a52SEmmanuel Vadot /* Status register */
69*1d6a6a52SEmmanuel Vadot #define	RV3032_STATUS		0x0D
70*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_VLF	(1 << 0)	/* Voltage Low Flag */
71*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_PORF	(1 << 1)	/* Power On Reset Flag */
72*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_EVF	(1 << 2)	/* External eVent Flag */
73*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_AF	(1 << 3)	/* Alarm Flag */
74*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_TF	(1 << 4)	/* periodic countdown Timer Flag */
75*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_UF	(1 << 5)	/* periodic time Update Flag */
76*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_TLF 	(1 << 6)	/* Temperature Low Flag */
77*1d6a6a52SEmmanuel Vadot #define	 RV3032_STATUS_THF	(1 << 7)	/* Temperature High Flag */
78*1d6a6a52SEmmanuel Vadot 
79*1d6a6a52SEmmanuel Vadot /* Temperature registers */
80*1d6a6a52SEmmanuel Vadot #define	RV3032_TEMP_LSB		0x0E
81*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_BSF	(1 << 0)
82*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_CLKF	(1 << 1)
83*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_EEBUSY	(1 << 2)
84*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_EEF	(1 << 3)
85*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_MASK	(0xF0)
86*1d6a6a52SEmmanuel Vadot #define	 RV3032_TEMP_LSB_SHIFT	4
87*1d6a6a52SEmmanuel Vadot 
88*1d6a6a52SEmmanuel Vadot #define	RV3032_TEMP_MSB		0x0F
89*1d6a6a52SEmmanuel Vadot 
90*1d6a6a52SEmmanuel Vadot #define	TEMP_DIV		16
91*1d6a6a52SEmmanuel Vadot #define	TEMP_C_TO_K		273
92*1d6a6a52SEmmanuel Vadot 
93*1d6a6a52SEmmanuel Vadot /* Control registers */
94*1d6a6a52SEmmanuel Vadot #define	RV3032_CTRL1		0x10
95*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_MASK	0x3	/* Timer clock frequency */
96*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_SHIFT	0
97*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_4096	0
98*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_64	1
99*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_1	2
100*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TD_1_60	3
101*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_EERD	(1 << 2)	/* EEPROM memory refresh disable bit */
102*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_TE	(1 << 3)	/* Periodic countdown timer enable bit */
103*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_USEL	(1 << 4)	/* Update interrupt select bit */
104*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL1_GP0	(1 << 5)	/* General Purpose bit 0 */
105*1d6a6a52SEmmanuel Vadot 
106*1d6a6a52SEmmanuel Vadot #define	RV3032_CTRL2		0x11
107*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_STOP	(1 << 0)	/* Stop bit */
108*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_GP1	(1 << 1)	/* General Purpose bit 1 */
109*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_EIE	(1 << 2)	/* External event interrupt enable bit */
110*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_AIE	(1 << 3)	/* Alarm interrupt enable bit */
111*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_TIE	(1 << 4)	/* Periodic countdown timer interrupt enable bit */
112*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_UIE	(1 << 5)	/* Periodic time update interrupt enable bit */
113*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL2_CLKIE	(1 << 6)	/* Interrupt Controlled Clock Output Enable bit */
114*1d6a6a52SEmmanuel Vadot #define	RV3032_CTRL3		0x12
115*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL3_TLIE	(1 << 0)	/* Temperature Low Interrupt Enable bit */
116*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL3_THIE	(1 << 1)	/* Temperature High Interrupt Enable bit */
117*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL3_TLE	(1 << 2)	/* Temperature Low Enable bit */
118*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL3_THE	(1 << 3)	/* Temperature High Enable bit */
119*1d6a6a52SEmmanuel Vadot #define	 RV3032_CTRL3_BSIE	(1 << 4)	/* Backup Switchover Interrupt Enable bit */
120*1d6a6a52SEmmanuel Vadot 
121*1d6a6a52SEmmanuel Vadot /* EEPROM registers */
122*1d6a6a52SEmmanuel Vadot #define	RV3032_EEPROM_ADDRESS		0x3D
123*1d6a6a52SEmmanuel Vadot #define	RV3032_EEPROM_DATA		0x3E
124*1d6a6a52SEmmanuel Vadot #define	RV3032_EEPROM_COMMAND		0x3F
125*1d6a6a52SEmmanuel Vadot #define RV3032_EEPROM_CMD_UPDATE	0x11
126*1d6a6a52SEmmanuel Vadot #define RV3032_EEPROM_CMD_REFRESH	0x12
127*1d6a6a52SEmmanuel Vadot #define RV3032_EEPROM_CMD_WRITE_ONE	0x21
128*1d6a6a52SEmmanuel Vadot #define RV3032_EEPROM_CMD_READ_ONE	0x22
129*1d6a6a52SEmmanuel Vadot 
130*1d6a6a52SEmmanuel Vadot /* PMU register */
131*1d6a6a52SEmmanuel Vadot #define	RV3032_EEPROM_PMU	0xC0
132*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_MASK	0x3
133*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_SHIFT	0
134*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_OFF	0
135*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_175V	1
136*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_30V	2
137*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCM_45V	3
138*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_MASK	0x3
139*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_SHIFT	2
140*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_06K	0
141*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_2K	1
142*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_7K	2
143*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_TCR_12K	3
144*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_MASK	0x3
145*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_SHIFT	4
146*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_OFF	0
147*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_DSM	1
148*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_LSM	2
149*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_BSM_OFF2	3
150*1d6a6a52SEmmanuel Vadot #define	 RV3032_PMU_NCLKE	(1 << 6)
151*1d6a6a52SEmmanuel Vadot 
152*1d6a6a52SEmmanuel Vadot struct rv3032_softc {
153*1d6a6a52SEmmanuel Vadot 	device_t		dev;
154*1d6a6a52SEmmanuel Vadot 	device_t		busdev;
155*1d6a6a52SEmmanuel Vadot 	struct intr_config_hook	init_hook;
156*1d6a6a52SEmmanuel Vadot };
157*1d6a6a52SEmmanuel Vadot 
158*1d6a6a52SEmmanuel Vadot struct rv3032_timeregs {
159*1d6a6a52SEmmanuel Vadot 	uint8_t	secs;
160*1d6a6a52SEmmanuel Vadot 	uint8_t	mins;
161*1d6a6a52SEmmanuel Vadot 	uint8_t	hours;
162*1d6a6a52SEmmanuel Vadot 	uint8_t	weekday;
163*1d6a6a52SEmmanuel Vadot 	uint8_t	date;
164*1d6a6a52SEmmanuel Vadot 	uint8_t	month;
165*1d6a6a52SEmmanuel Vadot 	uint8_t	year;
166*1d6a6a52SEmmanuel Vadot };
167*1d6a6a52SEmmanuel Vadot 
168*1d6a6a52SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
169*1d6a6a52SEmmanuel Vadot 	{"microcrystal,rv3032",	1},
170*1d6a6a52SEmmanuel Vadot 	{NULL,			0},
171*1d6a6a52SEmmanuel Vadot };
172*1d6a6a52SEmmanuel Vadot 
173*1d6a6a52SEmmanuel Vadot static int
rv3032_update_register(struct rv3032_softc * sc,uint8_t reg,uint8_t value,uint8_t mask)174*1d6a6a52SEmmanuel Vadot rv3032_update_register(struct rv3032_softc *sc, uint8_t reg, uint8_t value, uint8_t mask)
175*1d6a6a52SEmmanuel Vadot {
176*1d6a6a52SEmmanuel Vadot 	int rv;
177*1d6a6a52SEmmanuel Vadot 	uint8_t data;
178*1d6a6a52SEmmanuel Vadot 
179*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_readfrom(sc->dev, reg, &data, 1, IIC_WAIT)) != 0)
180*1d6a6a52SEmmanuel Vadot 		return (rv);
181*1d6a6a52SEmmanuel Vadot 	data &= mask;
182*1d6a6a52SEmmanuel Vadot 	data |= value;
183*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_writeto(sc->dev, reg, &data, 1, IIC_WAIT)) != 0)
184*1d6a6a52SEmmanuel Vadot 		return (rv);
185*1d6a6a52SEmmanuel Vadot 	return (0);
186*1d6a6a52SEmmanuel Vadot }
187*1d6a6a52SEmmanuel Vadot 
188*1d6a6a52SEmmanuel Vadot static int
rv3032_eeprom_wait(struct rv3032_softc * sc)189*1d6a6a52SEmmanuel Vadot rv3032_eeprom_wait(struct rv3032_softc *sc)
190*1d6a6a52SEmmanuel Vadot {
191*1d6a6a52SEmmanuel Vadot 	int rv, timeout;
192*1d6a6a52SEmmanuel Vadot 	uint8_t data;
193*1d6a6a52SEmmanuel Vadot 
194*1d6a6a52SEmmanuel Vadot 	for (timeout = 1000; timeout > 0; timeout--) {
195*1d6a6a52SEmmanuel Vadot 		if ((rv = iicdev_readfrom(sc->dev, RV3032_TEMP_LSB, &data, sizeof(data), IIC_WAIT)) != 0)
196*1d6a6a52SEmmanuel Vadot 		return (rv);
197*1d6a6a52SEmmanuel Vadot 		if ((data & RV3032_TEMP_LSB_EEBUSY) == 0) {
198*1d6a6a52SEmmanuel Vadot 			break;
199*1d6a6a52SEmmanuel Vadot 		}
200*1d6a6a52SEmmanuel Vadot 	}
201*1d6a6a52SEmmanuel Vadot 	if (timeout == 0) {
202*1d6a6a52SEmmanuel Vadot 		device_printf(sc->dev, "Timeout updating the eeprom\n");
203*1d6a6a52SEmmanuel Vadot 		return (ETIMEDOUT);
204*1d6a6a52SEmmanuel Vadot 	}
205*1d6a6a52SEmmanuel Vadot 	/* Wait 1ms before allowing another eeprom access */
206*1d6a6a52SEmmanuel Vadot 	DELAY(1000);
207*1d6a6a52SEmmanuel Vadot 
208*1d6a6a52SEmmanuel Vadot 	return (0);
209*1d6a6a52SEmmanuel Vadot }
210*1d6a6a52SEmmanuel Vadot 
211*1d6a6a52SEmmanuel Vadot static int
rv3032_eeprom_disable(struct rv3032_softc * sc)212*1d6a6a52SEmmanuel Vadot rv3032_eeprom_disable(struct rv3032_softc *sc)
213*1d6a6a52SEmmanuel Vadot {
214*1d6a6a52SEmmanuel Vadot 	int rv;
215*1d6a6a52SEmmanuel Vadot 
216*1d6a6a52SEmmanuel Vadot 	if ((rv = rv3032_update_register(sc, RV3032_CTRL1, RV3032_CTRL1_EERD, ~RV3032_CTRL1_EERD)) != 0)
217*1d6a6a52SEmmanuel Vadot 		return (rv);
218*1d6a6a52SEmmanuel Vadot 	/* Wait 1ms before checking EBUSY */
219*1d6a6a52SEmmanuel Vadot 	DELAY(1000);
220*1d6a6a52SEmmanuel Vadot 	return (rv3032_eeprom_wait(sc));
221*1d6a6a52SEmmanuel Vadot }
222*1d6a6a52SEmmanuel Vadot 
223*1d6a6a52SEmmanuel Vadot static int
rv3032_eeprom_update(struct rv3032_softc * sc)224*1d6a6a52SEmmanuel Vadot rv3032_eeprom_update(struct rv3032_softc *sc)
225*1d6a6a52SEmmanuel Vadot {
226*1d6a6a52SEmmanuel Vadot 	int rv;
227*1d6a6a52SEmmanuel Vadot 	uint8_t data;
228*1d6a6a52SEmmanuel Vadot 
229*1d6a6a52SEmmanuel Vadot 	data = RV3032_EEPROM_CMD_UPDATE;
230*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_writeto(sc->dev, RV3032_EEPROM_COMMAND, &data, sizeof(data), IIC_WAIT)) != 0)
231*1d6a6a52SEmmanuel Vadot 		return (rv);
232*1d6a6a52SEmmanuel Vadot 	/* Wait 1ms before checking EBUSY */
233*1d6a6a52SEmmanuel Vadot 	DELAY(1000);
234*1d6a6a52SEmmanuel Vadot 	return (rv3032_eeprom_wait(sc));
235*1d6a6a52SEmmanuel Vadot }
236*1d6a6a52SEmmanuel Vadot 
237*1d6a6a52SEmmanuel Vadot static int
rv3032_eeprom_enable(struct rv3032_softc * sc)238*1d6a6a52SEmmanuel Vadot rv3032_eeprom_enable(struct rv3032_softc *sc)
239*1d6a6a52SEmmanuel Vadot {
240*1d6a6a52SEmmanuel Vadot 	int rv;
241*1d6a6a52SEmmanuel Vadot 
242*1d6a6a52SEmmanuel Vadot 	/* Restore eeprom refresh */
243*1d6a6a52SEmmanuel Vadot 	if ((rv = rv3032_update_register(sc, RV3032_CTRL1, 0, ~RV3032_CTRL1_EERD)) != 0)
244*1d6a6a52SEmmanuel Vadot 		return (rv);
245*1d6a6a52SEmmanuel Vadot 	DELAY(1000);
246*1d6a6a52SEmmanuel Vadot 
247*1d6a6a52SEmmanuel Vadot 	return (0);
248*1d6a6a52SEmmanuel Vadot }
249*1d6a6a52SEmmanuel Vadot 
250*1d6a6a52SEmmanuel Vadot static int
rv3032_update_cfg(struct rv3032_softc * sc)251*1d6a6a52SEmmanuel Vadot rv3032_update_cfg(struct rv3032_softc *sc)
252*1d6a6a52SEmmanuel Vadot {
253*1d6a6a52SEmmanuel Vadot 	int rv;
254*1d6a6a52SEmmanuel Vadot 
255*1d6a6a52SEmmanuel Vadot 	if ((rv = rv3032_eeprom_disable(sc)) != 0)
256*1d6a6a52SEmmanuel Vadot 		return (rv);
257*1d6a6a52SEmmanuel Vadot 
258*1d6a6a52SEmmanuel Vadot 	/* Save configuration in eeprom and re-enable it */
259*1d6a6a52SEmmanuel Vadot 	if ((rv = rv3032_eeprom_update(sc)) != 0)
260*1d6a6a52SEmmanuel Vadot 		return (rv);
261*1d6a6a52SEmmanuel Vadot 	return (rv3032_eeprom_enable(sc));
262*1d6a6a52SEmmanuel Vadot }
263*1d6a6a52SEmmanuel Vadot 
264*1d6a6a52SEmmanuel Vadot static int
rv3032_temp_read(struct rv3032_softc * sc,int * temp)265*1d6a6a52SEmmanuel Vadot rv3032_temp_read(struct rv3032_softc *sc, int *temp)
266*1d6a6a52SEmmanuel Vadot {
267*1d6a6a52SEmmanuel Vadot 	int rv, temp2;
268*1d6a6a52SEmmanuel Vadot 	uint8_t data[2];
269*1d6a6a52SEmmanuel Vadot 
270*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_readfrom(sc->dev, RV3032_TEMP_LSB, &data, sizeof(data), IIC_WAIT)) != 0)
271*1d6a6a52SEmmanuel Vadot 		return (rv);
272*1d6a6a52SEmmanuel Vadot 
273*1d6a6a52SEmmanuel Vadot 	/* Wait for temp to be stable */
274*1d6a6a52SEmmanuel Vadot 	*temp = (((data[0] & RV3032_TEMP_LSB_MASK) >> RV3032_TEMP_LSB_SHIFT) |
275*1d6a6a52SEmmanuel Vadot 	    (data[1] << RV3032_TEMP_LSB_SHIFT));
276*1d6a6a52SEmmanuel Vadot 	do {
277*1d6a6a52SEmmanuel Vadot 		temp2 = *temp;
278*1d6a6a52SEmmanuel Vadot 		*temp = (((data[0] & RV3032_TEMP_LSB_MASK) >> RV3032_TEMP_LSB_SHIFT) |
279*1d6a6a52SEmmanuel Vadot 		    (data[1] << RV3032_TEMP_LSB_SHIFT));
280*1d6a6a52SEmmanuel Vadot 	} while (temp2 != *temp);
281*1d6a6a52SEmmanuel Vadot 	*temp = (*temp / TEMP_DIV) + TEMP_C_TO_K;
282*1d6a6a52SEmmanuel Vadot 	return (0);
283*1d6a6a52SEmmanuel Vadot }
284*1d6a6a52SEmmanuel Vadot 
285*1d6a6a52SEmmanuel Vadot static int
rv3032_temp_sysctl(SYSCTL_HANDLER_ARGS)286*1d6a6a52SEmmanuel Vadot rv3032_temp_sysctl(SYSCTL_HANDLER_ARGS)
287*1d6a6a52SEmmanuel Vadot {
288*1d6a6a52SEmmanuel Vadot 	int error, temp;
289*1d6a6a52SEmmanuel Vadot 	struct rv3032_softc *sc;
290*1d6a6a52SEmmanuel Vadot 
291*1d6a6a52SEmmanuel Vadot 	sc = (struct rv3032_softc *)arg1;
292*1d6a6a52SEmmanuel Vadot 	if (rv3032_temp_read(sc, &temp) != 0)
293*1d6a6a52SEmmanuel Vadot 		return (EIO);
294*1d6a6a52SEmmanuel Vadot 	error = sysctl_handle_int(oidp, &temp, 0, req);
295*1d6a6a52SEmmanuel Vadot 
296*1d6a6a52SEmmanuel Vadot 	return (error);
297*1d6a6a52SEmmanuel Vadot }
298*1d6a6a52SEmmanuel Vadot 
299*1d6a6a52SEmmanuel Vadot static void
rv3032_init(void * arg)300*1d6a6a52SEmmanuel Vadot rv3032_init(void *arg)
301*1d6a6a52SEmmanuel Vadot {
302*1d6a6a52SEmmanuel Vadot 	struct rv3032_softc	*sc;
303*1d6a6a52SEmmanuel Vadot 	struct sysctl_ctx_list *ctx;
304*1d6a6a52SEmmanuel Vadot 	struct sysctl_oid *tree_node;
305*1d6a6a52SEmmanuel Vadot 	struct sysctl_oid_list *tree;
306*1d6a6a52SEmmanuel Vadot 	int rv;
307*1d6a6a52SEmmanuel Vadot 
308*1d6a6a52SEmmanuel Vadot 	sc = (struct rv3032_softc*)arg;
309*1d6a6a52SEmmanuel Vadot 	config_intrhook_disestablish(&sc->init_hook);
310*1d6a6a52SEmmanuel Vadot 
311*1d6a6a52SEmmanuel Vadot 	/* Set direct switching mode */
312*1d6a6a52SEmmanuel Vadot 	rv3032_update_register(sc,
313*1d6a6a52SEmmanuel Vadot 	    RV3032_EEPROM_PMU,
314*1d6a6a52SEmmanuel Vadot 	    RV3032_PMU_BSM_DSM << RV3032_PMU_BSM_SHIFT,
315*1d6a6a52SEmmanuel Vadot 	    RV3032_PMU_BSM_MASK);
316*1d6a6a52SEmmanuel Vadot 	if ((rv = rv3032_update_cfg(sc)) != 0) {
317*1d6a6a52SEmmanuel Vadot 		device_printf(sc->dev, "Cannot set to DSM mode (%d)\n", rv);
318*1d6a6a52SEmmanuel Vadot 		return;
319*1d6a6a52SEmmanuel Vadot 	}
320*1d6a6a52SEmmanuel Vadot 
321*1d6a6a52SEmmanuel Vadot 	/* Register as clock source */
322*1d6a6a52SEmmanuel Vadot 	clock_register_flags(sc->dev, 1000000, CLOCKF_SETTIME_NO_ADJ);
323*1d6a6a52SEmmanuel Vadot 	clock_schedule(sc->dev, 1);
324*1d6a6a52SEmmanuel Vadot 
325*1d6a6a52SEmmanuel Vadot 	ctx = device_get_sysctl_ctx(sc->dev);
326*1d6a6a52SEmmanuel Vadot 	tree_node = device_get_sysctl_tree(sc->dev);
327*1d6a6a52SEmmanuel Vadot 	tree = SYSCTL_CHILDREN(tree_node);
328*1d6a6a52SEmmanuel Vadot 	SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "temperature",
329*1d6a6a52SEmmanuel Vadot 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
330*1d6a6a52SEmmanuel Vadot 	    rv3032_temp_sysctl, "IK0", "Current temperature");
331*1d6a6a52SEmmanuel Vadot 	return;
332*1d6a6a52SEmmanuel Vadot }
333*1d6a6a52SEmmanuel Vadot 
334*1d6a6a52SEmmanuel Vadot static int
rv3032_probe(device_t dev)335*1d6a6a52SEmmanuel Vadot rv3032_probe(device_t dev)
336*1d6a6a52SEmmanuel Vadot {
337*1d6a6a52SEmmanuel Vadot 
338*1d6a6a52SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
339*1d6a6a52SEmmanuel Vadot 		return (ENXIO);
340*1d6a6a52SEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
341*1d6a6a52SEmmanuel Vadot 		device_set_desc(dev, "Microcrystal RV3032");
342*1d6a6a52SEmmanuel Vadot 		return (BUS_PROBE_DEFAULT);
343*1d6a6a52SEmmanuel Vadot 	}
344*1d6a6a52SEmmanuel Vadot 	return (ENXIO);
345*1d6a6a52SEmmanuel Vadot }
346*1d6a6a52SEmmanuel Vadot 
347*1d6a6a52SEmmanuel Vadot static int
rv3032_attach(device_t dev)348*1d6a6a52SEmmanuel Vadot rv3032_attach(device_t dev)
349*1d6a6a52SEmmanuel Vadot {
350*1d6a6a52SEmmanuel Vadot 	struct rv3032_softc	*sc;
351*1d6a6a52SEmmanuel Vadot 
352*1d6a6a52SEmmanuel Vadot 	sc = device_get_softc(dev);
353*1d6a6a52SEmmanuel Vadot 	sc->dev = dev;
354*1d6a6a52SEmmanuel Vadot 	sc->busdev = device_get_parent(sc->dev);
355*1d6a6a52SEmmanuel Vadot 
356*1d6a6a52SEmmanuel Vadot 	sc->init_hook.ich_func = rv3032_init;
357*1d6a6a52SEmmanuel Vadot 	sc->init_hook.ich_arg = sc;
358*1d6a6a52SEmmanuel Vadot 	if (config_intrhook_establish(&sc->init_hook) != 0)
359*1d6a6a52SEmmanuel Vadot 		return (ENOMEM);
360*1d6a6a52SEmmanuel Vadot 
361*1d6a6a52SEmmanuel Vadot 	return (0);
362*1d6a6a52SEmmanuel Vadot }
363*1d6a6a52SEmmanuel Vadot 
364*1d6a6a52SEmmanuel Vadot static int
rv3032_detach(device_t dev)365*1d6a6a52SEmmanuel Vadot rv3032_detach(device_t dev)
366*1d6a6a52SEmmanuel Vadot {
367*1d6a6a52SEmmanuel Vadot 
368*1d6a6a52SEmmanuel Vadot 	clock_unregister(dev);
369*1d6a6a52SEmmanuel Vadot 	return (0);
370*1d6a6a52SEmmanuel Vadot }
371*1d6a6a52SEmmanuel Vadot 
372*1d6a6a52SEmmanuel Vadot static int
rv3032_gettime(device_t dev,struct timespec * ts)373*1d6a6a52SEmmanuel Vadot rv3032_gettime(device_t dev, struct timespec *ts)
374*1d6a6a52SEmmanuel Vadot {
375*1d6a6a52SEmmanuel Vadot 	struct rv3032_softc *sc;
376*1d6a6a52SEmmanuel Vadot 	struct rv3032_timeregs time_regs;
377*1d6a6a52SEmmanuel Vadot 	struct clocktime ct;
378*1d6a6a52SEmmanuel Vadot 	uint8_t status;
379*1d6a6a52SEmmanuel Vadot 	int rv;
380*1d6a6a52SEmmanuel Vadot 
381*1d6a6a52SEmmanuel Vadot 	sc = device_get_softc(dev);
382*1d6a6a52SEmmanuel Vadot 
383*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_readfrom(sc->dev, RV3032_STATUS, &status, sizeof(status), IIC_WAIT)) != 0)
384*1d6a6a52SEmmanuel Vadot 		return (rv);
385*1d6a6a52SEmmanuel Vadot 	if (status & (RV3032_STATUS_PORF | RV3032_STATUS_VLF))
386*1d6a6a52SEmmanuel Vadot 		return (EINVAL);
387*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_readfrom(sc->dev, RV3032_SECS, &time_regs, sizeof(time_regs), IIC_WAIT)) != 0)
388*1d6a6a52SEmmanuel Vadot 		return (rv);
389*1d6a6a52SEmmanuel Vadot 
390*1d6a6a52SEmmanuel Vadot 	bzero(&ct, sizeof(ct));
391*1d6a6a52SEmmanuel Vadot 	ct.sec = FROMBCD(time_regs.secs & 0x7f);
392*1d6a6a52SEmmanuel Vadot 	ct.min = FROMBCD(time_regs.mins & 0x7f);
393*1d6a6a52SEmmanuel Vadot 	ct.hour = FROMBCD(time_regs.hours & 0x3f);
394*1d6a6a52SEmmanuel Vadot 	ct.day = FROMBCD(time_regs.date & 0x3f);
395*1d6a6a52SEmmanuel Vadot 	ct.mon = FROMBCD(time_regs.month & 0x1f) - 1;
396*1d6a6a52SEmmanuel Vadot 	ct.year = FROMBCD(time_regs.year) + 2000;
397*1d6a6a52SEmmanuel Vadot 
398*1d6a6a52SEmmanuel Vadot 	return (clock_ct_to_ts(&ct, ts));
399*1d6a6a52SEmmanuel Vadot }
400*1d6a6a52SEmmanuel Vadot 
401*1d6a6a52SEmmanuel Vadot static int
rv3032_settime(device_t dev,struct timespec * ts)402*1d6a6a52SEmmanuel Vadot rv3032_settime(device_t dev, struct timespec *ts)
403*1d6a6a52SEmmanuel Vadot {
404*1d6a6a52SEmmanuel Vadot 	struct rv3032_softc *sc;
405*1d6a6a52SEmmanuel Vadot 	struct rv3032_timeregs time_regs;
406*1d6a6a52SEmmanuel Vadot 	struct clocktime ct;
407*1d6a6a52SEmmanuel Vadot 	uint8_t status;
408*1d6a6a52SEmmanuel Vadot 	int rv;
409*1d6a6a52SEmmanuel Vadot 
410*1d6a6a52SEmmanuel Vadot 	sc = device_get_softc(dev);
411*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_readfrom(sc->dev, RV3032_STATUS, &status, sizeof(status), IIC_WAIT)) != 0)
412*1d6a6a52SEmmanuel Vadot 		return (rv);
413*1d6a6a52SEmmanuel Vadot 
414*1d6a6a52SEmmanuel Vadot 	clock_ts_to_ct(ts, &ct);
415*1d6a6a52SEmmanuel Vadot 
416*1d6a6a52SEmmanuel Vadot 	time_regs.secs = TOBCD(ct.sec);
417*1d6a6a52SEmmanuel Vadot 	time_regs.mins = TOBCD(ct.min);
418*1d6a6a52SEmmanuel Vadot 	time_regs.hours = TOBCD(ct.hour);
419*1d6a6a52SEmmanuel Vadot 	time_regs.date = TOBCD(ct.day);
420*1d6a6a52SEmmanuel Vadot 	time_regs.month = TOBCD(ct.mon + 1);
421*1d6a6a52SEmmanuel Vadot 	time_regs.year = TOBCD(ct.year - 2000);
422*1d6a6a52SEmmanuel Vadot 
423*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_writeto(sc->dev, RV3032_SECS, &time_regs, sizeof(time_regs), IIC_WAIT)) != 0)
424*1d6a6a52SEmmanuel Vadot 		return (rv);
425*1d6a6a52SEmmanuel Vadot 
426*1d6a6a52SEmmanuel Vadot 	/* Force a power on reset event so rv3032 reload the registers */
427*1d6a6a52SEmmanuel Vadot 	status &= ~(RV3032_STATUS_PORF | RV3032_STATUS_VLF);
428*1d6a6a52SEmmanuel Vadot 	if ((rv = iicdev_writeto(sc->dev, RV3032_STATUS, &status, sizeof(status), IIC_WAIT)) != 0)
429*1d6a6a52SEmmanuel Vadot 		return (rv);
430*1d6a6a52SEmmanuel Vadot 	return (0);
431*1d6a6a52SEmmanuel Vadot }
432*1d6a6a52SEmmanuel Vadot 
433*1d6a6a52SEmmanuel Vadot static device_method_t rv3032_methods[] = {
434*1d6a6a52SEmmanuel Vadot         /* device_if methods */
435*1d6a6a52SEmmanuel Vadot 	DEVMETHOD(device_probe,		rv3032_probe),
436*1d6a6a52SEmmanuel Vadot 	DEVMETHOD(device_attach,	rv3032_attach),
437*1d6a6a52SEmmanuel Vadot 	DEVMETHOD(device_detach,	rv3032_detach),
438*1d6a6a52SEmmanuel Vadot 
439*1d6a6a52SEmmanuel Vadot         /* clock_if methods */
440*1d6a6a52SEmmanuel Vadot 	DEVMETHOD(clock_gettime,	rv3032_gettime),
441*1d6a6a52SEmmanuel Vadot 	DEVMETHOD(clock_settime,	rv3032_settime),
442*1d6a6a52SEmmanuel Vadot 
443*1d6a6a52SEmmanuel Vadot 	DEVMETHOD_END,
444*1d6a6a52SEmmanuel Vadot };
445*1d6a6a52SEmmanuel Vadot 
446*1d6a6a52SEmmanuel Vadot static driver_t rv3032_driver = {
447*1d6a6a52SEmmanuel Vadot 	"rv3032",
448*1d6a6a52SEmmanuel Vadot 	rv3032_methods,
449*1d6a6a52SEmmanuel Vadot 	sizeof(struct rv3032_softc),
450*1d6a6a52SEmmanuel Vadot };
451*1d6a6a52SEmmanuel Vadot 
452*1d6a6a52SEmmanuel Vadot DRIVER_MODULE(rv3032, iicbus, rv3032_driver, NULL, NULL);
453*1d6a6a52SEmmanuel Vadot MODULE_VERSION(rv3032, 1);
454*1d6a6a52SEmmanuel Vadot MODULE_DEPEND(rv3032, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
455*1d6a6a52SEmmanuel Vadot IICBUS_FDT_PNP_INFO(compat_data);
456