diff options
author | Ed Swierk <eswierk@aristanetworks.com> | 2009-03-31 18:24:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-01 11:59:25 -0400 |
commit | 30e7b039b1f9a6d5a4e50df5469a4f347ea1aa77 (patch) | |
tree | 901a186c2e97ff83804992ecaf4f9e52be8aadff /drivers/rtc | |
parent | b250c96ea9d7bc0b9ac3ff6e878b254b0b0b6abc (diff) |
rtc-ds1307: true SMBus compatibility
Allow the rtc-ds1307 driver to work with SMBus controllers like nforce2
that do not support i2c block transfers.
Signed-off-by: Ed Swierk <eswierk@aristanetworks.com>
Acked-by: Jean Delvare <khali@linux-fr.org>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: BARRE Sebastien <sbarre@sdelcc.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 109 |
1 files changed, 97 insertions, 12 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 7e5155e88ac7..1c975e6439b3 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -94,6 +94,10 @@ struct ds1307 { | |||
94 | struct i2c_client *client; | 94 | struct i2c_client *client; |
95 | struct rtc_device *rtc; | 95 | struct rtc_device *rtc; |
96 | struct work_struct work; | 96 | struct work_struct work; |
97 | s32 (*read_block_data)(struct i2c_client *client, u8 command, | ||
98 | u8 length, u8 *values); | ||
99 | s32 (*write_block_data)(struct i2c_client *client, u8 command, | ||
100 | u8 length, const u8 *values); | ||
97 | }; | 101 | }; |
98 | 102 | ||
99 | struct chip_desc { | 103 | struct chip_desc { |
@@ -132,6 +136,79 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); | |||
132 | 136 | ||
133 | /*----------------------------------------------------------------------*/ | 137 | /*----------------------------------------------------------------------*/ |
134 | 138 | ||
139 | #define BLOCK_DATA_MAX_TRIES 10 | ||
140 | |||
141 | static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, | ||
142 | u8 length, u8 *values) | ||
143 | { | ||
144 | s32 i, data; | ||
145 | |||
146 | for (i = 0; i < length; i++) { | ||
147 | data = i2c_smbus_read_byte_data(client, command + i); | ||
148 | if (data < 0) | ||
149 | return data; | ||
150 | values[i] = data; | ||
151 | } | ||
152 | return i; | ||
153 | } | ||
154 | |||
155 | static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, | ||
156 | u8 length, u8 *values) | ||
157 | { | ||
158 | u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; | ||
159 | s32 ret; | ||
160 | int tries = 0; | ||
161 | |||
162 | dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); | ||
163 | ret = ds1307_read_block_data_once(client, command, length, values); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | do { | ||
167 | if (++tries > BLOCK_DATA_MAX_TRIES) { | ||
168 | dev_err(&client->dev, | ||
169 | "ds1307_read_block_data failed\n"); | ||
170 | return -EIO; | ||
171 | } | ||
172 | memcpy(oldvalues, values, length); | ||
173 | ret = ds1307_read_block_data_once(client, command, length, | ||
174 | values); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | } while (memcmp(oldvalues, values, length)); | ||
178 | return length; | ||
179 | } | ||
180 | |||
181 | static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, | ||
182 | u8 length, const u8 *values) | ||
183 | { | ||
184 | u8 currvalues[I2C_SMBUS_BLOCK_MAX]; | ||
185 | int tries = 0; | ||
186 | |||
187 | dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); | ||
188 | do { | ||
189 | s32 i, ret; | ||
190 | |||
191 | if (++tries > BLOCK_DATA_MAX_TRIES) { | ||
192 | dev_err(&client->dev, | ||
193 | "ds1307_write_block_data failed\n"); | ||
194 | return -EIO; | ||
195 | } | ||
196 | for (i = 0; i < length; i++) { | ||
197 | ret = i2c_smbus_write_byte_data(client, command + i, | ||
198 | values[i]); | ||
199 | if (ret < 0) | ||
200 | return ret; | ||
201 | } | ||
202 | ret = ds1307_read_block_data_once(client, command, length, | ||
203 | currvalues); | ||
204 | if (ret < 0) | ||
205 | return ret; | ||
206 | } while (memcmp(currvalues, values, length)); | ||
207 | return length; | ||
208 | } | ||
209 | |||
210 | /*----------------------------------------------------------------------*/ | ||
211 | |||
135 | /* | 212 | /* |
136 | * The IRQ logic includes a "real" handler running in IRQ context just | 213 | * The IRQ logic includes a "real" handler running in IRQ context just |
137 | * long enough to schedule this workqueue entry. We need a task context | 214 | * long enough to schedule this workqueue entry. We need a task context |
@@ -202,7 +279,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) | |||
202 | int tmp; | 279 | int tmp; |
203 | 280 | ||
204 | /* read the RTC date and time registers all at once */ | 281 | /* read the RTC date and time registers all at once */ |
205 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, | 282 | tmp = ds1307->read_block_data(ds1307->client, |
206 | DS1307_REG_SECS, 7, ds1307->regs); | 283 | DS1307_REG_SECS, 7, ds1307->regs); |
207 | if (tmp != 7) { | 284 | if (tmp != 7) { |
208 | dev_err(dev, "%s error %d\n", "read", tmp); | 285 | dev_err(dev, "%s error %d\n", "read", tmp); |
@@ -279,7 +356,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | |||
279 | "write", buf[0], buf[1], buf[2], buf[3], | 356 | "write", buf[0], buf[1], buf[2], buf[3], |
280 | buf[4], buf[5], buf[6]); | 357 | buf[4], buf[5], buf[6]); |
281 | 358 | ||
282 | result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); | 359 | result = ds1307->write_block_data(ds1307->client, 0, 7, buf); |
283 | if (result < 0) { | 360 | if (result < 0) { |
284 | dev_err(dev, "%s error %d\n", "write", result); | 361 | dev_err(dev, "%s error %d\n", "write", result); |
285 | return result; | 362 | return result; |
@@ -297,7 +374,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
297 | return -EINVAL; | 374 | return -EINVAL; |
298 | 375 | ||
299 | /* read all ALARM1, ALARM2, and status registers at once */ | 376 | /* read all ALARM1, ALARM2, and status registers at once */ |
300 | ret = i2c_smbus_read_i2c_block_data(client, | 377 | ret = ds1307->read_block_data(client, |
301 | DS1339_REG_ALARM1_SECS, 9, ds1307->regs); | 378 | DS1339_REG_ALARM1_SECS, 9, ds1307->regs); |
302 | if (ret != 9) { | 379 | if (ret != 9) { |
303 | dev_err(dev, "%s error %d\n", "alarm read", ret); | 380 | dev_err(dev, "%s error %d\n", "alarm read", ret); |
@@ -356,7 +433,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
356 | t->enabled, t->pending); | 433 | t->enabled, t->pending); |
357 | 434 | ||
358 | /* read current status of both alarms and the chip */ | 435 | /* read current status of both alarms and the chip */ |
359 | ret = i2c_smbus_read_i2c_block_data(client, | 436 | ret = ds1307->read_block_data(client, |
360 | DS1339_REG_ALARM1_SECS, 9, buf); | 437 | DS1339_REG_ALARM1_SECS, 9, buf); |
361 | if (ret != 9) { | 438 | if (ret != 9) { |
362 | dev_err(dev, "%s error %d\n", "alarm write", ret); | 439 | dev_err(dev, "%s error %d\n", "alarm write", ret); |
@@ -391,7 +468,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
391 | } | 468 | } |
392 | buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); | 469 | buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); |
393 | 470 | ||
394 | ret = i2c_smbus_write_i2c_block_data(client, | 471 | ret = ds1307->write_block_data(client, |
395 | DS1339_REG_ALARM1_SECS, 9, buf); | 472 | DS1339_REG_ALARM1_SECS, 9, buf); |
396 | if (ret < 0) { | 473 | if (ret < 0) { |
397 | dev_err(dev, "can't set alarm time\n"); | 474 | dev_err(dev, "can't set alarm time\n"); |
@@ -479,7 +556,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, | |||
479 | if (unlikely(!count)) | 556 | if (unlikely(!count)) |
480 | return count; | 557 | return count; |
481 | 558 | ||
482 | result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); | 559 | result = ds1307->read_block_data(client, 8 + off, count, buf); |
483 | if (result < 0) | 560 | if (result < 0) |
484 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); | 561 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); |
485 | return result; | 562 | return result; |
@@ -490,9 +567,11 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, | |||
490 | char *buf, loff_t off, size_t count) | 567 | char *buf, loff_t off, size_t count) |
491 | { | 568 | { |
492 | struct i2c_client *client; | 569 | struct i2c_client *client; |
570 | struct ds1307 *ds1307; | ||
493 | int result; | 571 | int result; |
494 | 572 | ||
495 | client = kobj_to_i2c_client(kobj); | 573 | client = kobj_to_i2c_client(kobj); |
574 | ds1307 = i2c_get_clientdata(client); | ||
496 | 575 | ||
497 | if (unlikely(off >= NVRAM_SIZE)) | 576 | if (unlikely(off >= NVRAM_SIZE)) |
498 | return -EFBIG; | 577 | return -EFBIG; |
@@ -501,7 +580,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, | |||
501 | if (unlikely(!count)) | 580 | if (unlikely(!count)) |
502 | return count; | 581 | return count; |
503 | 582 | ||
504 | result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); | 583 | result = ds1307->write_block_data(client, 8 + off, count, buf); |
505 | if (result < 0) { | 584 | if (result < 0) { |
506 | dev_err(&client->dev, "%s error %d\n", "nvram write", result); | 585 | dev_err(&client->dev, "%s error %d\n", "nvram write", result); |
507 | return result; | 586 | return result; |
@@ -535,9 +614,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
535 | int want_irq = false; | 614 | int want_irq = false; |
536 | unsigned char *buf; | 615 | unsigned char *buf; |
537 | 616 | ||
538 | if (!i2c_check_functionality(adapter, | 617 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) |
539 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | | 618 | && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) |
540 | I2C_FUNC_SMBUS_I2C_BLOCK)) | ||
541 | return -EIO; | 619 | return -EIO; |
542 | 620 | ||
543 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) | 621 | if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) |
@@ -547,6 +625,13 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
547 | i2c_set_clientdata(client, ds1307); | 625 | i2c_set_clientdata(client, ds1307); |
548 | ds1307->type = id->driver_data; | 626 | ds1307->type = id->driver_data; |
549 | buf = ds1307->regs; | 627 | buf = ds1307->regs; |
628 | if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { | ||
629 | ds1307->read_block_data = i2c_smbus_read_i2c_block_data; | ||
630 | ds1307->write_block_data = i2c_smbus_write_i2c_block_data; | ||
631 | } else { | ||
632 | ds1307->read_block_data = ds1307_read_block_data; | ||
633 | ds1307->write_block_data = ds1307_write_block_data; | ||
634 | } | ||
550 | 635 | ||
551 | switch (ds1307->type) { | 636 | switch (ds1307->type) { |
552 | case ds_1337: | 637 | case ds_1337: |
@@ -557,7 +642,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
557 | want_irq = true; | 642 | want_irq = true; |
558 | } | 643 | } |
559 | /* get registers that the "rtc" read below won't read... */ | 644 | /* get registers that the "rtc" read below won't read... */ |
560 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, | 645 | tmp = ds1307->read_block_data(ds1307->client, |
561 | DS1337_REG_CONTROL, 2, buf); | 646 | DS1337_REG_CONTROL, 2, buf); |
562 | if (tmp != 2) { | 647 | if (tmp != 2) { |
563 | pr_debug("read error %d\n", tmp); | 648 | pr_debug("read error %d\n", tmp); |
@@ -595,7 +680,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, | |||
595 | 680 | ||
596 | read_rtc: | 681 | read_rtc: |
597 | /* read RTC registers */ | 682 | /* read RTC registers */ |
598 | tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); | 683 | tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); |
599 | if (tmp != 8) { | 684 | if (tmp != 8) { |
600 | pr_debug("read error %d\n", tmp); | 685 | pr_debug("read error %d\n", tmp); |
601 | err = -EIO; | 686 | err = -EIO; |