aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-10-16 01:03:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 14:21:39 -0400
commit0053dc0d13eb14108ebc48619456dd9ff6e25768 (patch)
treeb83bef18caede3cfa357ff771047685a31a50653
parent0f4d3fd8ac76122675de900d67a470306647374b (diff)
rtc: rtc-rs5c372: SMBus conversion/support
rtc-rs5c372 presently depends on I2C master mode transfers, despite the fact that these RTCs frequently find themselves on SMBus-only adapters. Given that the only capabilities that were checked were for I2C_FUNC_I2C, it's assumed that most of the adapters that are currently using this driver are fairly sane, and are able to handle SMBus emulation (though we adjust the default capabilities to check for I2C_FUNC_SMBUS_EMUL anyways, which is the vast majority of them. The adapters that don't have their own ->smbus_xfer() fall back on the ->master_xfer() through the emulated transfer). The special case is iop3xx, which has more than its fair share of hacks within this driver, it remains untested -- though also claims to support emulated SMBus accesses. The corner case there is rs5c_get_regs() which uses access mode #3 for transferring the register state, while we use mode #1 for SMBus. Signed-off-by: Paul Mundt <lethal@linux-sh.org> Acked-by: David Brownell <david-b@pacbell.net> Tested-by: Riku Voipio <riku.voipio@movial.fi> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/rtc-rs5c372.c209
1 files changed, 131 insertions, 78 deletions
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 56caf6b2c3e..c390e335559 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> 4 * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
5 * Copyright (C) 2006 Tower Technologies 5 * Copyright (C) 2006 Tower Technologies
6 * Copyright (C) 2008 Paul Mundt
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
@@ -13,7 +14,7 @@
13#include <linux/rtc.h> 14#include <linux/rtc.h>
14#include <linux/bcd.h> 15#include <linux/bcd.h>
15 16
16#define DRV_VERSION "0.5" 17#define DRV_VERSION "0.6"
17 18
18 19
19/* 20/*
@@ -89,6 +90,7 @@ struct rs5c372 {
89 enum rtc_type type; 90 enum rtc_type type;
90 unsigned time24:1; 91 unsigned time24:1;
91 unsigned has_irq:1; 92 unsigned has_irq:1;
93 unsigned smbus:1;
92 char buf[17]; 94 char buf[17];
93 char *regs; 95 char *regs;
94}; 96};
@@ -106,10 +108,25 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
106 * 108 *
107 * The first method doesn't work with the iop3xx adapter driver, on at 109 * The first method doesn't work with the iop3xx adapter driver, on at
108 * least 80219 chips; this works around that bug. 110 * least 80219 chips; this works around that bug.
111 *
112 * The third method on the other hand doesn't work for the SMBus-only
113 * configurations, so we use the the first method there, stripping off
114 * the extra register in the process.
109 */ 115 */
110 if ((i2c_transfer(client->adapter, msgs, 1)) != 1) { 116 if (rs5c->smbus) {
111 dev_warn(&client->dev, "can't read registers\n"); 117 int addr = RS5C_ADDR(RS5C372_REG_SECS);
112 return -EIO; 118 int size = sizeof(rs5c->buf) - 1;
119
120 if (i2c_smbus_read_i2c_block_data(client, addr, size,
121 rs5c->buf + 1) != size) {
122 dev_warn(&client->dev, "can't read registers\n");
123 return -EIO;
124 }
125 } else {
126 if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
127 dev_warn(&client->dev, "can't read registers\n");
128 return -EIO;
129 }
113 } 130 }
114 131
115 dev_dbg(&client->dev, 132 dev_dbg(&client->dev,
@@ -187,6 +204,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
187{ 204{
188 struct rs5c372 *rs5c = i2c_get_clientdata(client); 205 struct rs5c372 *rs5c = i2c_get_clientdata(client);
189 unsigned char buf[8]; 206 unsigned char buf[8];
207 int addr;
190 208
191 dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " 209 dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
192 "mday=%d, mon=%d, year=%d, wday=%d\n", 210 "mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -194,16 +212,16 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
194 tm->tm_sec, tm->tm_min, tm->tm_hour, 212 tm->tm_sec, tm->tm_min, tm->tm_hour,
195 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 213 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
196 214
197 buf[0] = RS5C_ADDR(RS5C372_REG_SECS); 215 addr = RS5C_ADDR(RS5C372_REG_SECS);
198 buf[1] = BIN2BCD(tm->tm_sec); 216 buf[0] = BIN2BCD(tm->tm_sec);
199 buf[2] = BIN2BCD(tm->tm_min); 217 buf[1] = BIN2BCD(tm->tm_min);
200 buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour); 218 buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
201 buf[4] = BIN2BCD(tm->tm_wday); 219 buf[3] = BIN2BCD(tm->tm_wday);
202 buf[5] = BIN2BCD(tm->tm_mday); 220 buf[4] = BIN2BCD(tm->tm_mday);
203 buf[6] = BIN2BCD(tm->tm_mon + 1); 221 buf[5] = BIN2BCD(tm->tm_mon + 1);
204 buf[7] = BIN2BCD(tm->tm_year - 100); 222 buf[6] = BIN2BCD(tm->tm_year - 100);
205 223
206 if ((i2c_master_send(client, buf, 8)) != 8) { 224 if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
207 dev_err(&client->dev, "%s: write error\n", __func__); 225 dev_err(&client->dev, "%s: write error\n", __func__);
208 return -EIO; 226 return -EIO;
209 } 227 }
@@ -266,16 +284,16 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
266{ 284{
267 struct i2c_client *client = to_i2c_client(dev); 285 struct i2c_client *client = to_i2c_client(dev);
268 struct rs5c372 *rs5c = i2c_get_clientdata(client); 286 struct rs5c372 *rs5c = i2c_get_clientdata(client);
269 unsigned char buf[2]; 287 unsigned char buf;
270 int status; 288 int status, addr;
271 289
272 buf[1] = rs5c->regs[RS5C_REG_CTRL1]; 290 buf = rs5c->regs[RS5C_REG_CTRL1];
273 switch (cmd) { 291 switch (cmd) {
274 case RTC_UIE_OFF: 292 case RTC_UIE_OFF:
275 case RTC_UIE_ON: 293 case RTC_UIE_ON:
276 /* some 327a modes use a different IRQ pin for 1Hz irqs */ 294 /* some 327a modes use a different IRQ pin for 1Hz irqs */
277 if (rs5c->type == rtc_rs5c372a 295 if (rs5c->type == rtc_rs5c372a
278 && (buf[1] & RS5C372A_CTRL1_SL1)) 296 && (buf & RS5C372A_CTRL1_SL1))
279 return -ENOIOCTLCMD; 297 return -ENOIOCTLCMD;
280 case RTC_AIE_OFF: 298 case RTC_AIE_OFF:
281 case RTC_AIE_ON: 299 case RTC_AIE_ON:
@@ -293,28 +311,30 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
293 if (status < 0) 311 if (status < 0)
294 return status; 312 return status;
295 313
296 buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); 314 addr = RS5C_ADDR(RS5C_REG_CTRL1);
297 switch (cmd) { 315 switch (cmd) {
298 case RTC_AIE_OFF: /* alarm off */ 316 case RTC_AIE_OFF: /* alarm off */
299 buf[1] &= ~RS5C_CTRL1_AALE; 317 buf &= ~RS5C_CTRL1_AALE;
300 break; 318 break;
301 case RTC_AIE_ON: /* alarm on */ 319 case RTC_AIE_ON: /* alarm on */
302 buf[1] |= RS5C_CTRL1_AALE; 320 buf |= RS5C_CTRL1_AALE;
303 break; 321 break;
304 case RTC_UIE_OFF: /* update off */ 322 case RTC_UIE_OFF: /* update off */
305 buf[1] &= ~RS5C_CTRL1_CT_MASK; 323 buf &= ~RS5C_CTRL1_CT_MASK;
306 break; 324 break;
307 case RTC_UIE_ON: /* update on */ 325 case RTC_UIE_ON: /* update on */
308 buf[1] &= ~RS5C_CTRL1_CT_MASK; 326 buf &= ~RS5C_CTRL1_CT_MASK;
309 buf[1] |= RS5C_CTRL1_CT4; 327 buf |= RS5C_CTRL1_CT4;
310 break; 328 break;
311 } 329 }
312 if ((i2c_master_send(client, buf, 2)) != 2) { 330
331 if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
313 printk(KERN_WARNING "%s: can't update alarm\n", 332 printk(KERN_WARNING "%s: can't update alarm\n",
314 rs5c->rtc->name); 333 rs5c->rtc->name);
315 status = -EIO; 334 status = -EIO;
316 } else 335 } else
317 rs5c->regs[RS5C_REG_CTRL1] = buf[1]; 336 rs5c->regs[RS5C_REG_CTRL1] = buf;
337
318 return status; 338 return status;
319} 339}
320 340
@@ -364,8 +384,8 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
364{ 384{
365 struct i2c_client *client = to_i2c_client(dev); 385 struct i2c_client *client = to_i2c_client(dev);
366 struct rs5c372 *rs5c = i2c_get_clientdata(client); 386 struct rs5c372 *rs5c = i2c_get_clientdata(client);
367 int status; 387 int status, addr, i;
368 unsigned char buf[4]; 388 unsigned char buf[3];
369 389
370 /* only handle up to 24 hours in the future, like RTC_ALM_SET */ 390 /* only handle up to 24 hours in the future, like RTC_ALM_SET */
371 if (t->time.tm_mday != -1 391 if (t->time.tm_mday != -1
@@ -380,33 +400,36 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
380 if (status < 0) 400 if (status < 0)
381 return status; 401 return status;
382 if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) { 402 if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
383 buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); 403 addr = RS5C_ADDR(RS5C_REG_CTRL1);
384 buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE; 404 buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
385 if (i2c_master_send(client, buf, 2) != 2) { 405 if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
386 pr_debug("%s: can't disable alarm\n", rs5c->rtc->name); 406 pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
387 return -EIO; 407 return -EIO;
388 } 408 }
389 rs5c->regs[RS5C_REG_CTRL1] = buf[1]; 409 rs5c->regs[RS5C_REG_CTRL1] = buf[0];
390 } 410 }
391 411
392 /* set alarm */ 412 /* set alarm */
393 buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN); 413 buf[0] = BIN2BCD(t->time.tm_min);
394 buf[1] = BIN2BCD(t->time.tm_min); 414 buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
395 buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour); 415 buf[2] = 0x7f; /* any/all days */
396 buf[3] = 0x7f; /* any/all days */ 416
397 if ((i2c_master_send(client, buf, 4)) != 4) { 417 for (i = 0; i < sizeof(buf); i++) {
398 pr_debug("%s: can't set alarm time\n", rs5c->rtc->name); 418 addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
399 return -EIO; 419 if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
420 pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
421 return -EIO;
422 }
400 } 423 }
401 424
402 /* ... and maybe enable its irq */ 425 /* ... and maybe enable its irq */
403 if (t->enabled) { 426 if (t->enabled) {
404 buf[0] = RS5C_ADDR(RS5C_REG_CTRL1); 427 addr = RS5C_ADDR(RS5C_REG_CTRL1);
405 buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE; 428 buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
406 if ((i2c_master_send(client, buf, 2)) != 2) 429 if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
407 printk(KERN_WARNING "%s: can't enable alarm\n", 430 printk(KERN_WARNING "%s: can't enable alarm\n",
408 rs5c->rtc->name); 431 rs5c->rtc->name);
409 rs5c->regs[RS5C_REG_CTRL1] = buf[1]; 432 rs5c->regs[RS5C_REG_CTRL1] = buf[0];
410 } 433 }
411 434
412 return 0; 435 return 0;
@@ -503,18 +526,74 @@ static void rs5c_sysfs_unregister(struct device *dev)
503 526
504static struct i2c_driver rs5c372_driver; 527static struct i2c_driver rs5c372_driver;
505 528
529static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
530{
531 unsigned char buf[2];
532 int addr, i, ret = 0;
533
534 if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
535 return ret;
536 rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
537
538 addr = RS5C_ADDR(RS5C_REG_CTRL1);
539 buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
540 buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
541
542 /* use 24hr mode */
543 switch (rs5c372->type) {
544 case rtc_rs5c372a:
545 case rtc_rs5c372b:
546 buf[1] |= RS5C372_CTRL2_24;
547 rs5c372->time24 = 1;
548 break;
549 case rtc_rv5c386:
550 case rtc_rv5c387a:
551 buf[0] |= RV5C387_CTRL1_24;
552 rs5c372->time24 = 1;
553 break;
554 default:
555 /* impossible */
556 break;
557 }
558
559 for (i = 0; i < sizeof(buf); i++) {
560 addr = RS5C_ADDR(RS5C_REG_CTRL1 + i);
561 ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]);
562 if (unlikely(ret < 0))
563 return ret;
564 }
565
566 rs5c372->regs[RS5C_REG_CTRL1] = buf[0];
567 rs5c372->regs[RS5C_REG_CTRL2] = buf[1];
568
569 return 0;
570}
571
506static int rs5c372_probe(struct i2c_client *client, 572static int rs5c372_probe(struct i2c_client *client,
507 const struct i2c_device_id *id) 573 const struct i2c_device_id *id)
508{ 574{
509 int err = 0; 575 int err = 0;
576 int smbus_mode = 0;
510 struct rs5c372 *rs5c372; 577 struct rs5c372 *rs5c372;
511 struct rtc_time tm; 578 struct rtc_time tm;
512 579
513 dev_dbg(&client->dev, "%s\n", __func__); 580 dev_dbg(&client->dev, "%s\n", __func__);
514 581
515 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 582 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
516 err = -ENODEV; 583 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
517 goto exit; 584 /*
585 * If we don't have any master mode adapter, try breaking
586 * it down in to the barest of capabilities.
587 */
588 if (i2c_check_functionality(client->adapter,
589 I2C_FUNC_SMBUS_BYTE_DATA |
590 I2C_FUNC_SMBUS_I2C_BLOCK))
591 smbus_mode = 1;
592 else {
593 /* Still no good, give up */
594 err = -ENODEV;
595 goto exit;
596 }
518 } 597 }
519 598
520 if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) { 599 if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
@@ -528,6 +607,7 @@ static int rs5c372_probe(struct i2c_client *client,
528 607
529 /* we read registers 0x0f then 0x00-0x0f; skip the first one */ 608 /* we read registers 0x0f then 0x00-0x0f; skip the first one */
530 rs5c372->regs = &rs5c372->buf[1]; 609 rs5c372->regs = &rs5c372->buf[1];
610 rs5c372->smbus = smbus_mode;
531 611
532 err = rs5c_get_regs(rs5c372); 612 err = rs5c_get_regs(rs5c372);
533 if (err < 0) 613 if (err < 0)
@@ -559,38 +639,10 @@ static int rs5c372_probe(struct i2c_client *client,
559 /* if the oscillator lost power and no other software (like 639 /* if the oscillator lost power and no other software (like
560 * the bootloader) set it up, do it here. 640 * the bootloader) set it up, do it here.
561 */ 641 */
562 if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) { 642 err = rs5c_oscillator_setup(rs5c372);
563 unsigned char buf[3]; 643 if (unlikely(err < 0)) {
564 644 dev_err(&client->dev, "setup error\n");
565 rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP; 645 goto exit_kfree;
566
567 buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
568 buf[1] = rs5c372->regs[RS5C_REG_CTRL1];
569 buf[2] = rs5c372->regs[RS5C_REG_CTRL2];
570
571 /* use 24hr mode */
572 switch (rs5c372->type) {
573 case rtc_rs5c372a:
574 case rtc_rs5c372b:
575 buf[2] |= RS5C372_CTRL2_24;
576 rs5c372->time24 = 1;
577 break;
578 case rtc_rv5c386:
579 case rtc_rv5c387a:
580 buf[1] |= RV5C387_CTRL1_24;
581 rs5c372->time24 = 1;
582 break;
583 default:
584 /* impossible */
585 break;
586 }
587
588 if ((i2c_master_send(client, buf, 3)) != 3) {
589 dev_err(&client->dev, "setup error\n");
590 goto exit_kfree;
591 }
592 rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
593 rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
594 } 646 }
595 647
596 if (rs5c372_get_datetime(client, &tm) < 0) 648 if (rs5c372_get_datetime(client, &tm) < 0)
@@ -667,7 +719,8 @@ module_exit(rs5c372_exit);
667 719
668MODULE_AUTHOR( 720MODULE_AUTHOR(
669 "Pavel Mironchik <pmironchik@optifacio.net>, " 721 "Pavel Mironchik <pmironchik@optifacio.net>, "
670 "Alessandro Zummo <a.zummo@towertech.it>"); 722 "Alessandro Zummo <a.zummo@towertech.it>, "
723 "Paul Mundt <lethal@linux-sh.org>");
671MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); 724MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
672MODULE_LICENSE("GPL"); 725MODULE_LICENSE("GPL");
673MODULE_VERSION(DRV_VERSION); 726MODULE_VERSION(DRV_VERSION);