Blame view
drivers/rtc/rtc-rs5c372.c
17.6 KB
7520b94de [PATCH] RTC subsy... |
1 |
/* |
37fc5e2c4 rtc: rtc-rs5c372:... |
2 |
* An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs |
7520b94de [PATCH] RTC subsy... |
3 4 5 |
* * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> * Copyright (C) 2006 Tower Technologies |
0053dc0d1 rtc: rtc-rs5c372:... |
6 |
* Copyright (C) 2008 Paul Mundt |
7520b94de [PATCH] RTC subsy... |
7 8 9 10 11 12 13 14 15 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/i2c.h> #include <linux/rtc.h> #include <linux/bcd.h> |
5a0e3ad6a include cleanup: ... |
16 |
#include <linux/slab.h> |
2113852b2 rtc: Add module.h... |
17 |
#include <linux/module.h> |
ff764b88e rtc: rs5c372: Add... |
18 |
#include <linux/of_device.h> |
7520b94de [PATCH] RTC subsy... |
19 |
|
cb26b572d [PATCH] Update th... |
20 21 22 23 24 25 |
/* * Ricoh has a family of I2C based RTCs, which differ only slightly from * each other. Differences center on pinout (e.g. how many interrupts, * output clock, etc) and how the control registers are used. The '372 * is significant only because that's the one this driver first supported. */ |
7520b94de [PATCH] RTC subsy... |
26 27 28 29 30 31 32 33 |
#define RS5C372_REG_SECS 0 #define RS5C372_REG_MINS 1 #define RS5C372_REG_HOURS 2 #define RS5C372_REG_WDAY 3 #define RS5C372_REG_DAY 4 #define RS5C372_REG_MONTH 5 #define RS5C372_REG_YEAR 6 #define RS5C372_REG_TRIM 7 |
cb26b572d [PATCH] Update th... |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# define RS5C372_TRIM_XSL 0x80 # define RS5C372_TRIM_MASK 0x7F #define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */ #define RS5C_REG_ALARM_A_HOURS 9 #define RS5C_REG_ALARM_A_WDAY 10 #define RS5C_REG_ALARM_B_MIN 11 /* or ALARM_D */ #define RS5C_REG_ALARM_B_HOURS 12 #define RS5C_REG_ALARM_B_WDAY 13 /* (ALARM_B only) */ #define RS5C_REG_CTRL1 14 # define RS5C_CTRL1_AALE (1 << 7) /* or WALE */ # define RS5C_CTRL1_BALE (1 << 6) /* or DALE */ # define RV5C387_CTRL1_24 (1 << 5) # define RS5C372A_CTRL1_SL1 (1 << 5) # define RS5C_CTRL1_CT_MASK (7 << 0) # define RS5C_CTRL1_CT0 (0 << 0) /* no periodic irq */ # define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */ #define RS5C_REG_CTRL2 15 # define RS5C372_CTRL2_24 (1 << 5) |
37fc5e2c4 rtc: rtc-rs5c372:... |
55 56 |
# define R2025_CTRL2_XST (1 << 5) # define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2025S/D */ |
cb26b572d [PATCH] Update th... |
57 58 59 60 61 62 63 64 65 66 67 |
# define RS5C_CTRL2_CTFG (1 << 2) # define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */ # define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */ /* to read (style 1) or write registers starting at R */ #define RS5C_ADDR(R) (((R) << 4) | 0) enum rtc_type { rtc_undef = 0, |
37fc5e2c4 rtc: rtc-rs5c372:... |
68 |
rtc_r2025sd, |
550fcb8f7 drivers/rtc/rtc-r... |
69 |
rtc_r2221tl, |
cb26b572d [PATCH] Update th... |
70 71 72 73 74 |
rtc_rs5c372a, rtc_rs5c372b, rtc_rv5c386, rtc_rv5c387a, }; |
7520b94de [PATCH] RTC subsy... |
75 |
|
3760f7367 i2c: Convert most... |
76 |
static const struct i2c_device_id rs5c372_id[] = { |
37fc5e2c4 rtc: rtc-rs5c372:... |
77 |
{ "r2025sd", rtc_r2025sd }, |
550fcb8f7 drivers/rtc/rtc-r... |
78 |
{ "r2221tl", rtc_r2221tl }, |
3760f7367 i2c: Convert most... |
79 80 81 82 83 84 85 |
{ "rs5c372a", rtc_rs5c372a }, { "rs5c372b", rtc_rs5c372b }, { "rv5c386", rtc_rv5c386 }, { "rv5c387a", rtc_rv5c387a }, { } }; MODULE_DEVICE_TABLE(i2c, rs5c372_id); |
ff764b88e rtc: rs5c372: Add... |
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
static const struct of_device_id rs5c372_of_match[] = { { .compatible = "ricoh,r2025sd", .data = (void *)rtc_r2025sd }, { .compatible = "ricoh,r2221tl", .data = (void *)rtc_r2221tl }, { .compatible = "ricoh,rs5c372a", .data = (void *)rtc_rs5c372a }, { .compatible = "ricoh,rs5c372b", .data = (void *)rtc_rs5c372b }, { .compatible = "ricoh,rv5c386", .data = (void *)rtc_rv5c386 }, { .compatible = "ricoh,rv5c387a", .data = (void *)rtc_rv5c387a }, { } }; MODULE_DEVICE_TABLE(of, rs5c372_of_match); |
cb26b572d [PATCH] Update th... |
114 115 116 117 118 119 120 121 122 123 124 |
/* REVISIT: this assumes that: * - we're in the 21st century, so it's safe to ignore the century * bit for rv5c38[67] (REG_MONTH bit 7); * - we should use ALARM_A not ALARM_B (may be wrong on some boards) */ struct rs5c372 { struct i2c_client *client; struct rtc_device *rtc; enum rtc_type type; unsigned time24:1; unsigned has_irq:1; |
0053dc0d1 rtc: rtc-rs5c372:... |
125 |
unsigned smbus:1; |
cb26b572d [PATCH] Update th... |
126 127 |
char buf[17]; char *regs; |
cb26b572d [PATCH] Update th... |
128 |
}; |
7520b94de [PATCH] RTC subsy... |
129 |
|
cb26b572d [PATCH] Update th... |
130 131 132 133 |
static int rs5c_get_regs(struct rs5c372 *rs5c) { struct i2c_client *client = rs5c->client; struct i2c_msg msgs[] = { |
a606757ff drivers/rtc/rtc-r... |
134 135 136 137 138 139 |
{ .addr = client->addr, .flags = I2C_M_RD, .len = sizeof(rs5c->buf), .buf = rs5c->buf }, |
cb26b572d [PATCH] Update th... |
140 141 142 143 144 145 146 147 |
}; /* This implements the third reading method from the datasheet, using * an internal address that's reset after each transaction (by STOP) * to 0x0f ... so we read extra registers, and skip the first one. * * The first method doesn't work with the iop3xx adapter driver, on at * least 80219 chips; this works around that bug. |
0053dc0d1 rtc: rtc-rs5c372:... |
148 149 150 151 |
* * The third method on the other hand doesn't work for the SMBus-only * configurations, so we use the the first method there, stripping off * the extra register in the process. |
cb26b572d [PATCH] Update th... |
152 |
*/ |
0053dc0d1 rtc: rtc-rs5c372:... |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
if (rs5c->smbus) { int addr = RS5C_ADDR(RS5C372_REG_SECS); int size = sizeof(rs5c->buf) - 1; if (i2c_smbus_read_i2c_block_data(client, addr, size, rs5c->buf + 1) != size) { dev_warn(&client->dev, "can't read registers "); return -EIO; } } else { if ((i2c_transfer(client->adapter, msgs, 1)) != 1) { dev_warn(&client->dev, "can't read registers "); return -EIO; } |
cb26b572d [PATCH] Update th... |
169 |
} |
7520b94de [PATCH] RTC subsy... |
170 |
|
cb26b572d [PATCH] Update th... |
171 |
dev_dbg(&client->dev, |
b513e522c drivers/rtc/rtc-r... |
172 173 174 175 176 177 |
"%3ph (%02x) %3ph (%02x), %3ph, %3ph; %02x %02x ", rs5c->regs + 0, rs5c->regs[3], rs5c->regs + 4, rs5c->regs[7], rs5c->regs + 8, rs5c->regs + 11, rs5c->regs[14], rs5c->regs[15]); |
7520b94de [PATCH] RTC subsy... |
178 |
|
cb26b572d [PATCH] Update th... |
179 180 |
return 0; } |
c6f24f99c [PATCH] rtc-rs5c3... |
181 |
|
cb26b572d [PATCH] Update th... |
182 183 184 |
static unsigned rs5c_reg2hr(struct rs5c372 *rs5c, unsigned reg) { unsigned hour; |
7520b94de [PATCH] RTC subsy... |
185 |
|
cb26b572d [PATCH] Update th... |
186 |
if (rs5c->time24) |
fe20ba70a drivers/rtc/: use... |
187 |
return bcd2bin(reg & 0x3f); |
cb26b572d [PATCH] Update th... |
188 |
|
fe20ba70a drivers/rtc/: use... |
189 |
hour = bcd2bin(reg & 0x1f); |
cb26b572d [PATCH] Update th... |
190 191 192 193 194 195 196 197 |
if (hour == 12) hour = 0; if (reg & 0x20) hour += 12; return hour; } static unsigned rs5c_hr2reg(struct rs5c372 *rs5c, unsigned hour) |
7520b94de [PATCH] RTC subsy... |
198 |
{ |
cb26b572d [PATCH] Update th... |
199 |
if (rs5c->time24) |
fe20ba70a drivers/rtc/: use... |
200 |
return bin2bcd(hour); |
cb26b572d [PATCH] Update th... |
201 202 |
if (hour > 12) |
fe20ba70a drivers/rtc/: use... |
203 |
return 0x20 | bin2bcd(hour - 12); |
cb26b572d [PATCH] Update th... |
204 |
if (hour == 12) |
fe20ba70a drivers/rtc/: use... |
205 |
return 0x20 | bin2bcd(12); |
cb26b572d [PATCH] Update th... |
206 |
if (hour == 0) |
fe20ba70a drivers/rtc/: use... |
207 208 |
return bin2bcd(12); return bin2bcd(hour); |
cb26b572d [PATCH] Update th... |
209 |
} |
7520b94de [PATCH] RTC subsy... |
210 |
|
cb26b572d [PATCH] Update th... |
211 212 213 214 |
static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) { struct rs5c372 *rs5c = i2c_get_clientdata(client); int status = rs5c_get_regs(rs5c); |
c6f24f99c [PATCH] rtc-rs5c3... |
215 |
|
cb26b572d [PATCH] Update th... |
216 217 |
if (status < 0) return status; |
7520b94de [PATCH] RTC subsy... |
218 |
|
fe20ba70a drivers/rtc/: use... |
219 220 |
tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f); tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f); |
cb26b572d [PATCH] Update th... |
221 |
tm->tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C372_REG_HOURS]); |
7520b94de [PATCH] RTC subsy... |
222 |
|
fe20ba70a drivers/rtc/: use... |
223 224 |
tm->tm_wday = bcd2bin(rs5c->regs[RS5C372_REG_WDAY] & 0x07); tm->tm_mday = bcd2bin(rs5c->regs[RS5C372_REG_DAY] & 0x3f); |
7520b94de [PATCH] RTC subsy... |
225 226 |
/* tm->tm_mon is zero-based */ |
fe20ba70a drivers/rtc/: use... |
227 |
tm->tm_mon = bcd2bin(rs5c->regs[RS5C372_REG_MONTH] & 0x1f) - 1; |
7520b94de [PATCH] RTC subsy... |
228 229 |
/* year is 1900 + tm->tm_year */ |
fe20ba70a drivers/rtc/: use... |
230 |
tm->tm_year = bcd2bin(rs5c->regs[RS5C372_REG_YEAR]) + 100; |
7520b94de [PATCH] RTC subsy... |
231 232 233 234 |
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d ", |
2a4e2b878 rtc: replace rema... |
235 |
__func__, |
7520b94de [PATCH] RTC subsy... |
236 237 |
tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); |
cb26b572d [PATCH] Update th... |
238 239 |
/* rtc might need initialization */ return rtc_valid_tm(tm); |
7520b94de [PATCH] RTC subsy... |
240 241 242 243 |
} static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) { |
cb26b572d [PATCH] Update th... |
244 |
struct rs5c372 *rs5c = i2c_get_clientdata(client); |
118364948 rtc: rs5c372: fix... |
245 |
unsigned char buf[7]; |
0053dc0d1 rtc: rtc-rs5c372:... |
246 |
int addr; |
7520b94de [PATCH] RTC subsy... |
247 |
|
cb26b572d [PATCH] Update th... |
248 |
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " |
7520b94de [PATCH] RTC subsy... |
249 250 |
"mday=%d, mon=%d, year=%d, wday=%d ", |
2a4e2b878 rtc: replace rema... |
251 |
__func__, |
cb26b572d [PATCH] Update th... |
252 |
tm->tm_sec, tm->tm_min, tm->tm_hour, |
7520b94de [PATCH] RTC subsy... |
253 |
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); |
0053dc0d1 rtc: rtc-rs5c372:... |
254 |
addr = RS5C_ADDR(RS5C372_REG_SECS); |
fe20ba70a drivers/rtc/: use... |
255 256 |
buf[0] = bin2bcd(tm->tm_sec); buf[1] = bin2bcd(tm->tm_min); |
0053dc0d1 rtc: rtc-rs5c372:... |
257 |
buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour); |
fe20ba70a drivers/rtc/: use... |
258 259 260 261 |
buf[3] = bin2bcd(tm->tm_wday); buf[4] = bin2bcd(tm->tm_mday); buf[5] = bin2bcd(tm->tm_mon + 1); buf[6] = bin2bcd(tm->tm_year - 100); |
7520b94de [PATCH] RTC subsy... |
262 |
|
0053dc0d1 rtc: rtc-rs5c372:... |
263 |
if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) { |
2a4e2b878 rtc: replace rema... |
264 265 |
dev_err(&client->dev, "%s: write error ", __func__); |
7520b94de [PATCH] RTC subsy... |
266 267 268 269 270 |
return -EIO; } return 0; } |
6fca3fc51 rtc: Use IS_ENABL... |
271 |
#if IS_ENABLED(CONFIG_RTC_INTF_PROC) |
cb26b572d [PATCH] Update th... |
272 273 |
#define NEED_TRIM #endif |
6fca3fc51 rtc: Use IS_ENABL... |
274 |
#if IS_ENABLED(CONFIG_RTC_INTF_SYSFS) |
cb26b572d [PATCH] Update th... |
275 276 277 278 |
#define NEED_TRIM #endif #ifdef NEED_TRIM |
7520b94de [PATCH] RTC subsy... |
279 280 |
static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) { |
c6f24f99c [PATCH] rtc-rs5c3... |
281 |
struct rs5c372 *rs5c372 = i2c_get_clientdata(client); |
cb26b572d [PATCH] Update th... |
282 |
u8 tmp = rs5c372->regs[RS5C372_REG_TRIM]; |
7520b94de [PATCH] RTC subsy... |
283 |
|
7520b94de [PATCH] RTC subsy... |
284 |
if (osc) |
c6f24f99c [PATCH] rtc-rs5c3... |
285 |
*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; |
7520b94de [PATCH] RTC subsy... |
286 |
|
17ad78e59 [PATCH] drivers/r... |
287 |
if (trim) { |
2a4e2b878 rtc: replace rema... |
288 289 |
dev_dbg(&client->dev, "%s: raw trim=%x ", __func__, tmp); |
cb26b572d [PATCH] Update th... |
290 291 292 293 294 295 296 297 298 299 300 301 302 |
tmp &= RS5C372_TRIM_MASK; if (tmp & 0x3e) { int t = tmp & 0x3f; if (tmp & 0x40) t = (~t | (s8)0xc0) + 1; else t = t - 1; tmp = t * 2; } else tmp = 0; *trim = tmp; |
17ad78e59 [PATCH] drivers/r... |
303 |
} |
7520b94de [PATCH] RTC subsy... |
304 305 306 |
return 0; } |
cb26b572d [PATCH] Update th... |
307 |
#endif |
7520b94de [PATCH] RTC subsy... |
308 309 310 311 312 313 314 315 316 317 |
static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) { return rs5c372_get_datetime(to_i2c_client(dev), tm); } static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) { return rs5c372_set_datetime(to_i2c_client(dev), tm); } |
cb26b572d [PATCH] Update th... |
318 |
|
16380c153 RTC: Convert rtc ... |
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); unsigned char buf; int status, addr; buf = rs5c->regs[RS5C_REG_CTRL1]; if (!rs5c->has_irq) return -EINVAL; status = rs5c_get_regs(rs5c); if (status < 0) return status; addr = RS5C_ADDR(RS5C_REG_CTRL1); if (enabled) buf |= RS5C_CTRL1_AALE; else buf &= ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf) < 0) { |
0c6516ea4 rtc: rtc-rs5c372:... |
342 343 |
dev_warn(dev, "can't update alarm "); |
16380c153 RTC: Convert rtc ... |
344 345 346 347 348 349 |
status = -EIO; } else rs5c->regs[RS5C_REG_CTRL1] = buf; return status; } |
cb26b572d [PATCH] Update th... |
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
/* NOTE: Since RTC_WKALM_{RD,SET} were originally defined for EFI, * which only exposes a polled programming interface; and since * these calls map directly to those EFI requests; we don't demand * we have an IRQ for this chip when we go through this API. * * The older x86_pc derived RTC_ALM_{READ,SET} calls require irqs * though, managed through RTC_AIE_{ON,OFF} requests. */ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); int status; status = rs5c_get_regs(rs5c); if (status < 0) return status; /* report alarm time */ t->time.tm_sec = 0; |
fe20ba70a drivers/rtc/: use... |
371 |
t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); |
cb26b572d [PATCH] Update th... |
372 |
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); |
cb26b572d [PATCH] Update th... |
373 374 375 376 377 378 379 380 381 382 383 384 |
/* ... and status */ t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); t->pending = !!(rs5c->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_AAFG); return 0; } static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); |
0053dc0d1 rtc: rtc-rs5c372:... |
385 386 |
int status, addr, i; unsigned char buf[3]; |
cb26b572d [PATCH] Update th... |
387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
/* only handle up to 24 hours in the future, like RTC_ALM_SET */ if (t->time.tm_mday != -1 || t->time.tm_mon != -1 || t->time.tm_year != -1) return -EINVAL; /* REVISIT: round up tm_sec */ /* if needed, disable irq (clears pending status) */ status = rs5c_get_regs(rs5c); if (status < 0) return status; if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) { |
0053dc0d1 rtc: rtc-rs5c372:... |
401 402 403 |
addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) { |
0c6516ea4 rtc: rtc-rs5c372:... |
404 405 |
dev_dbg(dev, "can't disable alarm "); |
cb26b572d [PATCH] Update th... |
406 407 |
return -EIO; } |
0053dc0d1 rtc: rtc-rs5c372:... |
408 |
rs5c->regs[RS5C_REG_CTRL1] = buf[0]; |
cb26b572d [PATCH] Update th... |
409 410 411 |
} /* set alarm */ |
fe20ba70a drivers/rtc/: use... |
412 |
buf[0] = bin2bcd(t->time.tm_min); |
0053dc0d1 rtc: rtc-rs5c372:... |
413 414 415 416 417 418 |
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); buf[2] = 0x7f; /* any/all days */ for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) { |
0c6516ea4 rtc: rtc-rs5c372:... |
419 420 |
dev_dbg(dev, "can't set alarm time "); |
0053dc0d1 rtc: rtc-rs5c372:... |
421 422 |
return -EIO; } |
cb26b572d [PATCH] Update th... |
423 424 425 426 |
} /* ... and maybe enable its irq */ if (t->enabled) { |
0053dc0d1 rtc: rtc-rs5c372:... |
427 428 429 |
addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) |
0c6516ea4 rtc: rtc-rs5c372:... |
430 431 |
dev_warn(dev, "can't enable alarm "); |
0053dc0d1 rtc: rtc-rs5c372:... |
432 |
rs5c->regs[RS5C_REG_CTRL1] = buf[0]; |
cb26b572d [PATCH] Update th... |
433 434 435 436 |
} return 0; } |
6fca3fc51 rtc: Use IS_ENABL... |
437 |
#if IS_ENABLED(CONFIG_RTC_INTF_PROC) |
cb26b572d [PATCH] Update th... |
438 |
|
7520b94de [PATCH] RTC subsy... |
439 440 441 |
static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) { int err, osc, trim; |
adfb43412 [PATCH] RTC subsy... |
442 443 |
err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); if (err == 0) { |
cb26b572d [PATCH] Update th... |
444 445 446 447 448 |
seq_printf(seq, "crystal\t\t: %d.%03d KHz ", osc / 1000, osc % 1000); seq_printf(seq, "trim\t\t: %d ", trim); |
7520b94de [PATCH] RTC subsy... |
449 450 451 452 |
} return 0; } |
cb26b572d [PATCH] Update th... |
453 454 455 |
#else #define rs5c372_rtc_proc NULL #endif |
ff8371ac9 [PATCH] constify ... |
456 |
static const struct rtc_class_ops rs5c372_rtc_ops = { |
7520b94de [PATCH] RTC subsy... |
457 458 459 |
.proc = rs5c372_rtc_proc, .read_time = rs5c372_rtc_read_time, .set_time = rs5c372_rtc_set_time, |
cb26b572d [PATCH] Update th... |
460 461 |
.read_alarm = rs5c_read_alarm, .set_alarm = rs5c_set_alarm, |
16380c153 RTC: Convert rtc ... |
462 |
.alarm_irq_enable = rs5c_rtc_alarm_irq_enable, |
7520b94de [PATCH] RTC subsy... |
463 |
}; |
6fca3fc51 rtc: Use IS_ENABL... |
464 |
#if IS_ENABLED(CONFIG_RTC_INTF_SYSFS) |
cb26b572d [PATCH] Update th... |
465 |
|
7520b94de [PATCH] RTC subsy... |
466 467 468 |
static ssize_t rs5c372_sysfs_show_trim(struct device *dev, struct device_attribute *attr, char *buf) { |
828960724 [PATCH] RTC subsy... |
469 |
int err, trim; |
7520b94de [PATCH] RTC subsy... |
470 |
|
828960724 [PATCH] RTC subsy... |
471 472 473 |
err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim); if (err) return err; |
7520b94de [PATCH] RTC subsy... |
474 |
|
cb26b572d [PATCH] Update th... |
475 476 |
return sprintf(buf, "%d ", trim); |
7520b94de [PATCH] RTC subsy... |
477 478 479 480 481 482 |
} static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); static ssize_t rs5c372_sysfs_show_osc(struct device *dev, struct device_attribute *attr, char *buf) { |
828960724 [PATCH] RTC subsy... |
483 |
int err, osc; |
7520b94de [PATCH] RTC subsy... |
484 |
|
828960724 [PATCH] RTC subsy... |
485 486 487 |
err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL); if (err) return err; |
7520b94de [PATCH] RTC subsy... |
488 |
|
828960724 [PATCH] RTC subsy... |
489 490 |
return sprintf(buf, "%d.%03d KHz ", osc / 1000, osc % 1000); |
7520b94de [PATCH] RTC subsy... |
491 492 |
} static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); |
cb26b572d [PATCH] Update th... |
493 |
static int rs5c_sysfs_register(struct device *dev) |
7520b94de [PATCH] RTC subsy... |
494 |
{ |
cb26b572d [PATCH] Update th... |
495 496 497 498 499 500 501 502 503 504 505 |
int err; err = device_create_file(dev, &dev_attr_trim); if (err) return err; err = device_create_file(dev, &dev_attr_osc); if (err) device_remove_file(dev, &dev_attr_trim); return err; } |
d815461c7 rtc-rs5c372 becom... |
506 507 508 509 510 |
static void rs5c_sysfs_unregister(struct device *dev) { device_remove_file(dev, &dev_attr_trim); device_remove_file(dev, &dev_attr_osc); } |
cb26b572d [PATCH] Update th... |
511 512 513 514 |
#else static int rs5c_sysfs_register(struct device *dev) { return 0; |
7520b94de [PATCH] RTC subsy... |
515 |
} |
d815461c7 rtc-rs5c372 becom... |
516 517 518 519 520 |
static void rs5c_sysfs_unregister(struct device *dev) { /* nothing */ } |
cb26b572d [PATCH] Update th... |
521 522 523 |
#endif /* SYSFS */ static struct i2c_driver rs5c372_driver; |
7520b94de [PATCH] RTC subsy... |
524 |
|
0053dc0d1 rtc: rtc-rs5c372:... |
525 526 527 528 |
static int rs5c_oscillator_setup(struct rs5c372 *rs5c372) { unsigned char buf[2]; int addr, i, ret = 0; |
37fc5e2c4 rtc: rtc-rs5c372:... |
529 |
if (rs5c372->type == rtc_r2025sd) { |
a9dbe5589 rtc: rs5c372: r20... |
530 |
if (rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST) |
37fc5e2c4 rtc: rtc-rs5c372:... |
531 |
return ret; |
a9dbe5589 rtc: rs5c372: r20... |
532 |
rs5c372->regs[RS5C_REG_CTRL2] |= R2025_CTRL2_XST; |
37fc5e2c4 rtc: rtc-rs5c372:... |
533 534 535 536 537 |
} else { if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP)) return ret; rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP; } |
0053dc0d1 rtc: rtc-rs5c372:... |
538 539 540 541 542 543 544 545 546 547 548 549 |
addr = RS5C_ADDR(RS5C_REG_CTRL1); buf[0] = rs5c372->regs[RS5C_REG_CTRL1]; buf[1] = rs5c372->regs[RS5C_REG_CTRL2]; /* use 24hr mode */ switch (rs5c372->type) { case rtc_rs5c372a: case rtc_rs5c372b: buf[1] |= RS5C372_CTRL2_24; rs5c372->time24 = 1; break; |
37fc5e2c4 rtc: rtc-rs5c372:... |
550 |
case rtc_r2025sd: |
550fcb8f7 drivers/rtc/rtc-r... |
551 |
case rtc_r2221tl: |
0053dc0d1 rtc: rtc-rs5c372:... |
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
case rtc_rv5c386: case rtc_rv5c387a: buf[0] |= RV5C387_CTRL1_24; rs5c372->time24 = 1; break; default: /* impossible */ break; } for (i = 0; i < sizeof(buf); i++) { addr = RS5C_ADDR(RS5C_REG_CTRL1 + i); ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]); if (unlikely(ret < 0)) return ret; } rs5c372->regs[RS5C_REG_CTRL1] = buf[0]; rs5c372->regs[RS5C_REG_CTRL2] = buf[1]; return 0; } |
d2653e927 i2c: Add support ... |
574 575 |
static int rs5c372_probe(struct i2c_client *client, const struct i2c_device_id *id) |
7520b94de [PATCH] RTC subsy... |
576 577 |
{ int err = 0; |
0053dc0d1 rtc: rtc-rs5c372:... |
578 |
int smbus_mode = 0; |
c6f24f99c [PATCH] rtc-rs5c3... |
579 |
struct rs5c372 *rs5c372; |
cb26b572d [PATCH] Update th... |
580 |
struct rtc_time tm; |
7520b94de [PATCH] RTC subsy... |
581 |
|
2a4e2b878 rtc: replace rema... |
582 583 |
dev_dbg(&client->dev, "%s ", __func__); |
7520b94de [PATCH] RTC subsy... |
584 |
|
0053dc0d1 rtc: rtc-rs5c372:... |
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { /* * If we don't have any master mode adapter, try breaking * it down in to the barest of capabilities. */ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) smbus_mode = 1; else { /* Still no good, give up */ err = -ENODEV; goto exit; } |
7520b94de [PATCH] RTC subsy... |
600 |
} |
b8a4b4e2f rtc: rtc-rs5c372:... |
601 602 603 |
rs5c372 = devm_kzalloc(&client->dev, sizeof(struct rs5c372), GFP_KERNEL); if (!rs5c372) { |
7520b94de [PATCH] RTC subsy... |
604 605 606 |
err = -ENOMEM; goto exit; } |
cb26b572d [PATCH] Update th... |
607 |
|
cb26b572d [PATCH] Update th... |
608 |
rs5c372->client = client; |
c6f24f99c [PATCH] rtc-rs5c3... |
609 |
i2c_set_clientdata(client, rs5c372); |
ff764b88e rtc: rs5c372: Add... |
610 611 612 613 614 |
if (client->dev.of_node) rs5c372->type = (enum rtc_type) of_device_get_match_data(&client->dev); else rs5c372->type = id->driver_data; |
c6f24f99c [PATCH] rtc-rs5c3... |
615 |
|
e2bfe3424 rtc: rtc-rs5c372:... |
616 617 |
/* we read registers 0x0f then 0x00-0x0f; skip the first one */ rs5c372->regs = &rs5c372->buf[1]; |
0053dc0d1 rtc: rtc-rs5c372:... |
618 |
rs5c372->smbus = smbus_mode; |
e2bfe3424 rtc: rtc-rs5c372:... |
619 |
|
cb26b572d [PATCH] Update th... |
620 621 |
err = rs5c_get_regs(rs5c372); if (err < 0) |
b8a4b4e2f rtc: rtc-rs5c372:... |
622 |
goto exit; |
cb26b572d [PATCH] Update th... |
623 |
|
cb26b572d [PATCH] Update th... |
624 625 626 627 628 629 630 631 632 633 |
/* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { case rtc_rs5c372a: case rtc_rs5c372b: /* alarm uses ALARM_A; and nINTRA on 372a, nINTR on 372b. * so does periodic irq, except some 327a modes. */ if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24) rs5c372->time24 = 1; break; |
37fc5e2c4 rtc: rtc-rs5c372:... |
634 |
case rtc_r2025sd: |
550fcb8f7 drivers/rtc/rtc-r... |
635 |
case rtc_r2221tl: |
cb26b572d [PATCH] Update th... |
636 637 638 639 640 641 642 643 644 645 646 |
case rtc_rv5c386: case rtc_rv5c387a: if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24) rs5c372->time24 = 1; /* alarm uses ALARM_W; and nINTRB for alarm and periodic * irq, on both 386 and 387 */ break; default: dev_err(&client->dev, "unknown RTC type "); |
b8a4b4e2f rtc: rtc-rs5c372:... |
647 |
goto exit; |
cb26b572d [PATCH] Update th... |
648 649 650 651 |
} /* if the oscillator lost power and no other software (like * the bootloader) set it up, do it here. |
37fc5e2c4 rtc: rtc-rs5c372:... |
652 653 654 |
* * The R2025S/D does this a little differently than the other * parts, so we special case that.. |
cb26b572d [PATCH] Update th... |
655 |
*/ |
0053dc0d1 rtc: rtc-rs5c372:... |
656 657 658 659 |
err = rs5c_oscillator_setup(rs5c372); if (unlikely(err < 0)) { dev_err(&client->dev, "setup error "); |
b8a4b4e2f rtc: rtc-rs5c372:... |
660 |
goto exit; |
cb26b572d [PATCH] Update th... |
661 662 663 664 665 |
} if (rs5c372_get_datetime(client, &tm) < 0) dev_warn(&client->dev, "clock needs to be set "); |
fa5691131 rtc: remove usele... |
666 667 |
dev_info(&client->dev, "%s found, %s ", |
cb26b572d [PATCH] Update th... |
668 |
({ char *s; switch (rs5c372->type) { |
37fc5e2c4 rtc: rtc-rs5c372:... |
669 |
case rtc_r2025sd: s = "r2025sd"; break; |
550fcb8f7 drivers/rtc/rtc-r... |
670 |
case rtc_r2221tl: s = "r2221tl"; break; |
cb26b572d [PATCH] Update th... |
671 672 673 674 675 676 677 678 |
case rtc_rs5c372a: s = "rs5c372a"; break; case rtc_rs5c372b: s = "rs5c372b"; break; case rtc_rv5c386: s = "rv5c386"; break; case rtc_rv5c387a: s = "rv5c387a"; break; default: s = "chip"; break; }; s;}), rs5c372->time24 ? "24hr" : "am/pm" ); |
d815461c7 rtc-rs5c372 becom... |
679 |
/* REVISIT use client->irq to register alarm irq ... */ |
b8a4b4e2f rtc: rtc-rs5c372:... |
680 681 682 |
rs5c372->rtc = devm_rtc_device_register(&client->dev, rs5c372_driver.driver.name, &rs5c372_rtc_ops, THIS_MODULE); |
7520b94de [PATCH] RTC subsy... |
683 |
|
c6f24f99c [PATCH] rtc-rs5c3... |
684 685 |
if (IS_ERR(rs5c372->rtc)) { err = PTR_ERR(rs5c372->rtc); |
b8a4b4e2f rtc: rtc-rs5c372:... |
686 |
goto exit; |
7520b94de [PATCH] RTC subsy... |
687 |
} |
cb26b572d [PATCH] Update th... |
688 |
err = rs5c_sysfs_register(&client->dev); |
c6f24f99c [PATCH] rtc-rs5c3... |
689 |
if (err) |
b8a4b4e2f rtc: rtc-rs5c372:... |
690 |
goto exit; |
7520b94de [PATCH] RTC subsy... |
691 692 |
return 0; |
7520b94de [PATCH] RTC subsy... |
693 694 695 |
exit: return err; } |
d815461c7 rtc-rs5c372 becom... |
696 |
static int rs5c372_remove(struct i2c_client *client) |
cb26b572d [PATCH] Update th... |
697 |
{ |
d815461c7 rtc-rs5c372 becom... |
698 |
rs5c_sysfs_unregister(&client->dev); |
7520b94de [PATCH] RTC subsy... |
699 700 |
return 0; } |
cb26b572d [PATCH] Update th... |
701 702 703 |
static struct i2c_driver rs5c372_driver = { .driver = { .name = "rtc-rs5c372", |
ff764b88e rtc: rs5c372: Add... |
704 |
.of_match_table = of_match_ptr(rs5c372_of_match), |
cb26b572d [PATCH] Update th... |
705 |
}, |
d815461c7 rtc-rs5c372 becom... |
706 707 |
.probe = rs5c372_probe, .remove = rs5c372_remove, |
3760f7367 i2c: Convert most... |
708 |
.id_table = rs5c372_id, |
cb26b572d [PATCH] Update th... |
709 |
}; |
0abc92011 rtc: convert rtc ... |
710 |
module_i2c_driver(rs5c372_driver); |
7520b94de [PATCH] RTC subsy... |
711 712 713 |
MODULE_AUTHOR( "Pavel Mironchik <pmironchik@optifacio.net>, " |
0053dc0d1 rtc: rtc-rs5c372:... |
714 715 |
"Alessandro Zummo <a.zummo@towertech.it>, " "Paul Mundt <lethal@linux-sh.org>"); |
7520b94de [PATCH] RTC subsy... |
716 717 |
MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); MODULE_LICENSE("GPL"); |