.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> |
---|
5 | 6 | * Copyright (C) 2006 Tower Technologies |
---|
6 | 7 | * Copyright (C) 2008 Paul Mundt |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/i2c.h> |
---|
.. | .. |
---|
52 | 49 | # define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */ |
---|
53 | 50 | #define RS5C_REG_CTRL2 15 |
---|
54 | 51 | # define RS5C372_CTRL2_24 (1 << 5) |
---|
55 | | -# define R2025_CTRL2_XST (1 << 5) |
---|
56 | | -# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2025S/D */ |
---|
| 52 | +# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2x2x */ |
---|
| 53 | +# define R2x2x_CTRL2_VDET (1 << 6) /* only if R2x2x */ |
---|
| 54 | +# define R2x2x_CTRL2_XSTP (1 << 5) /* only if R2x2x */ |
---|
| 55 | +# define R2x2x_CTRL2_PON (1 << 4) /* only if R2x2x */ |
---|
57 | 56 | # define RS5C_CTRL2_CTFG (1 << 2) |
---|
58 | 57 | # define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */ |
---|
59 | 58 | # define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */ |
---|
.. | .. |
---|
212 | 211 | struct i2c_client *client = to_i2c_client(dev); |
---|
213 | 212 | struct rs5c372 *rs5c = i2c_get_clientdata(client); |
---|
214 | 213 | int status = rs5c_get_regs(rs5c); |
---|
| 214 | + unsigned char ctrl2 = rs5c->regs[RS5C_REG_CTRL2]; |
---|
215 | 215 | |
---|
216 | 216 | if (status < 0) |
---|
217 | 217 | return status; |
---|
| 218 | + |
---|
| 219 | + switch (rs5c->type) { |
---|
| 220 | + case rtc_r2025sd: |
---|
| 221 | + case rtc_r2221tl: |
---|
| 222 | + if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) || |
---|
| 223 | + (rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) { |
---|
| 224 | + dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n"); |
---|
| 225 | + return -EINVAL; |
---|
| 226 | + } |
---|
| 227 | + break; |
---|
| 228 | + default: |
---|
| 229 | + if (ctrl2 & RS5C_CTRL2_XSTP) { |
---|
| 230 | + dev_warn(&client->dev, "rtc oscillator interruption detected. Please reset the rtc clock.\n"); |
---|
| 231 | + return -EINVAL; |
---|
| 232 | + } |
---|
| 233 | + } |
---|
218 | 234 | |
---|
219 | 235 | tm->tm_sec = bcd2bin(rs5c->regs[RS5C372_REG_SECS] & 0x7f); |
---|
220 | 236 | tm->tm_min = bcd2bin(rs5c->regs[RS5C372_REG_MINS] & 0x7f); |
---|
.. | .. |
---|
243 | 259 | struct i2c_client *client = to_i2c_client(dev); |
---|
244 | 260 | struct rs5c372 *rs5c = i2c_get_clientdata(client); |
---|
245 | 261 | unsigned char buf[7]; |
---|
| 262 | + unsigned char ctrl2; |
---|
246 | 263 | int addr; |
---|
247 | 264 | |
---|
248 | 265 | dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " |
---|
.. | .. |
---|
261 | 278 | buf[6] = bin2bcd(tm->tm_year - 100); |
---|
262 | 279 | |
---|
263 | 280 | if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) { |
---|
264 | | - dev_err(&client->dev, "%s: write error\n", __func__); |
---|
| 281 | + dev_dbg(&client->dev, "%s: write error in line %i\n", |
---|
| 282 | + __func__, __LINE__); |
---|
| 283 | + return -EIO; |
---|
| 284 | + } |
---|
| 285 | + |
---|
| 286 | + addr = RS5C_ADDR(RS5C_REG_CTRL2); |
---|
| 287 | + ctrl2 = i2c_smbus_read_byte_data(client, addr); |
---|
| 288 | + |
---|
| 289 | + /* clear rtc warning bits */ |
---|
| 290 | + switch (rs5c->type) { |
---|
| 291 | + case rtc_r2025sd: |
---|
| 292 | + case rtc_r2221tl: |
---|
| 293 | + ctrl2 &= ~(R2x2x_CTRL2_VDET | R2x2x_CTRL2_PON); |
---|
| 294 | + if (rs5c->type == rtc_r2025sd) |
---|
| 295 | + ctrl2 |= R2x2x_CTRL2_XSTP; |
---|
| 296 | + else |
---|
| 297 | + ctrl2 &= ~R2x2x_CTRL2_XSTP; |
---|
| 298 | + break; |
---|
| 299 | + default: |
---|
| 300 | + ctrl2 &= ~RS5C_CTRL2_XSTP; |
---|
| 301 | + break; |
---|
| 302 | + } |
---|
| 303 | + |
---|
| 304 | + if (i2c_smbus_write_byte_data(client, addr, ctrl2) < 0) { |
---|
| 305 | + dev_dbg(&client->dev, "%s: write error in line %i\n", |
---|
| 306 | + __func__, __LINE__); |
---|
265 | 307 | return -EIO; |
---|
266 | 308 | } |
---|
267 | 309 | |
---|
.. | .. |
---|
519 | 561 | unsigned char buf[2]; |
---|
520 | 562 | int addr, i, ret = 0; |
---|
521 | 563 | |
---|
522 | | - if (rs5c372->type == rtc_r2025sd) { |
---|
523 | | - if (rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST) |
---|
524 | | - return ret; |
---|
525 | | - rs5c372->regs[RS5C_REG_CTRL2] |= R2025_CTRL2_XST; |
---|
526 | | - } else { |
---|
527 | | - if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP)) |
---|
528 | | - return ret; |
---|
529 | | - rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP; |
---|
530 | | - } |
---|
531 | | - |
---|
532 | 564 | addr = RS5C_ADDR(RS5C_REG_CTRL1); |
---|
533 | 565 | buf[0] = rs5c372->regs[RS5C_REG_CTRL1]; |
---|
534 | 566 | buf[1] = rs5c372->regs[RS5C_REG_CTRL2]; |
---|
535 | 567 | |
---|
| 568 | + switch (rs5c372->type) { |
---|
| 569 | + case rtc_r2025sd: |
---|
| 570 | + if (buf[1] & R2x2x_CTRL2_XSTP) |
---|
| 571 | + return ret; |
---|
| 572 | + break; |
---|
| 573 | + case rtc_r2221tl: |
---|
| 574 | + if (!(buf[1] & R2x2x_CTRL2_XSTP)) |
---|
| 575 | + return ret; |
---|
| 576 | + break; |
---|
| 577 | + default: |
---|
| 578 | + if (!(buf[1] & RS5C_CTRL2_XSTP)) |
---|
| 579 | + return ret; |
---|
| 580 | + break; |
---|
| 581 | + } |
---|
| 582 | + |
---|
536 | 583 | /* use 24hr mode */ |
---|
537 | 584 | switch (rs5c372->type) { |
---|
538 | 585 | case rtc_rs5c372a: |
---|