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