* [PATCH] rtc-ds1307: True SMBus compatibility
@ 2009-01-05 17:41 Ed Swierk
2009-01-06 22:48 ` David Brownell
[not found] ` <1231177261.13443.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
0 siblings, 2 replies; 15+ messages in thread
From: Ed Swierk @ 2009-01-05 17:41 UTC (permalink / raw)
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell,
Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Andrew Morton, BAR
[-- Attachment #1: Type: text/plain, Size: 635 bytes --]
[Resent to correct linux-i2c address]
Following up to Sebastien Barre's recent patch, here I go one step
further, replacing i2c block transfers with SMBus byte transfers.
Sticking to pure SMBus makes the driver work on our board, which has an
nVidia SMBus controller driving a DS1339; nforce2 controllers
unfortunately don't support any flavor of i2c block transfer.
Reading or writing registers repeatedly until they stick is rather
nauseating but I'm aiming for correctness if not elegance. I would
appreciate any suggestions for improvement.
Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org>
[-- Attachment #2: rtc-ds1307-pure-smbus-compatibility.patch --]
[-- Type: text/x-patch, Size: 5414 bytes --]
Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c
===================================================================
--- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c
+++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c
@@ -132,6 +132,64 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id);
/*----------------------------------------------------------------------*/
+static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command,
+ u8 length, u8 *values)
+{
+ s32 i, data;
+ for (i = 0; i < length; i++) {
+ data = i2c_smbus_read_byte_data(client, command + i);
+ if (data < 0)
+ return data;
+ *(values + i) = data;
+ }
+ return i;
+}
+
+static s32 ds1307_read_block_data(struct i2c_client *client, u8 command,
+ u8 length, u8 *values)
+{
+ u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+ s32 ret;
+ pr_debug("ds1307_read_block_data (length=%d)\n", length);
+ ret = ds1307_read_block_data_once(client, command, length, values);
+ if (ret < 0)
+ return ret;
+ do {
+ s32 ret;
+ memcpy(oldvalues, values, length);
+ ret = ds1307_read_block_data_once(client, command, length, values);
+ if (ret < 0)
+ return ret;
+ } while (memcmp(oldvalues, values, length));
+ return length;
+}
+
+static s32 ds1307_write_block_data(struct i2c_client *client, u8 command,
+ u8 length, const u8 *values)
+{
+ u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+ s32 ret;
+ pr_debug("ds1307_write_block_data (length=%d)\n", length);
+ ret = ds1307_read_block_data_once(client, command, length, currvalues);
+ if (ret < 0)
+ return ret;
+ do {
+ s32 i, ret;
+ for (i = 0; i < length; i++) {
+ ret = i2c_smbus_write_byte_data(client, command + i,
+ *(values + i));
+ if (ret < 0)
+ return ret;
+ }
+ ret = ds1307_read_block_data_once(client, command, length, currvalues);
+ if (ret < 0)
+ return ret;
+ } while (memcmp(currvalues, values, length));
+ return length;
+}
+
+/*----------------------------------------------------------------------*/
+
/*
* The IRQ logic includes a "real" handler running in IRQ context just
* long enough to schedule this workqueue entry. We need a task context
@@ -202,7 +266,7 @@ static int ds1307_get_time(struct device
int tmp;
/* read the RTC date and time registers all at once */
- tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+ tmp = ds1307_read_block_data(ds1307->client,
DS1307_REG_SECS, 7, ds1307->regs);
if (tmp != 7) {
dev_err(dev, "%s error %d\n", "read", tmp);
@@ -279,7 +343,7 @@ static int ds1307_set_time(struct device
"write", buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6]);
- result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf);
+ result = ds1307_write_block_data(ds1307->client, 0, 7, buf);
if (result < 0) {
dev_err(dev, "%s error %d\n", "write", result);
return result;
@@ -297,7 +361,7 @@ static int ds1307_read_alarm(struct devi
return -EINVAL;
/* read all ALARM1, ALARM2, and status registers at once */
- ret = i2c_smbus_read_i2c_block_data(client,
+ ret = ds1307_read_block_data(client,
DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
if (ret != 9) {
dev_err(dev, "%s error %d\n", "alarm read", ret);
@@ -356,7 +420,7 @@ static int ds1307_set_alarm(struct devic
t->enabled, t->pending);
/* read current status of both alarms and the chip */
- ret = i2c_smbus_read_i2c_block_data(client,
+ ret = ds1307_read_block_data(client,
DS1339_REG_ALARM1_SECS, 9, buf);
if (ret != 9) {
dev_err(dev, "%s error %d\n", "alarm write", ret);
@@ -391,7 +455,7 @@ static int ds1307_set_alarm(struct devic
}
buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
- ret = i2c_smbus_write_i2c_block_data(client,
+ ret = ds1307_write_block_data(client,
DS1339_REG_ALARM1_SECS, 9, buf);
if (ret < 0) {
dev_err(dev, "can't set alarm time\n");
@@ -479,7 +543,7 @@ ds1307_nvram_read(struct kobject *kobj,
if (unlikely(!count))
return count;
- result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf);
+ result = ds1307_read_block_data(client, 8 + off, count, buf);
if (result < 0)
dev_err(&client->dev, "%s error %d\n", "nvram read", result);
return result;
@@ -501,7 +565,7 @@ ds1307_nvram_write(struct kobject *kobj,
if (unlikely(!count))
return count;
- result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf);
+ result = ds1307_write_block_data(client, 8 + off, count, buf);
if (result < 0) {
dev_err(&client->dev, "%s error %d\n", "nvram write", result);
return result;
@@ -537,8 +601,7 @@ static int __devinit ds1307_probe(struct
unsigned char *buf;
if (!i2c_check_functionality(adapter,
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK))
+ I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
@@ -558,7 +621,7 @@ static int __devinit ds1307_probe(struct
want_irq = true;
}
/* get registers that the "rtc" read below won't read... */
- tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+ tmp = ds1307_read_block_data(ds1307->client,
DS1337_REG_CONTROL, 2, buf);
if (tmp != 2) {
pr_debug("read error %d\n", tmp);
@@ -596,7 +659,7 @@ static int __devinit ds1307_probe(struct
read_rtc:
/* read RTC registers */
- tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf);
+ tmp = ds1307_read_block_data(ds1307->client, 0, 8, buf);
if (tmp != 8) {
pr_debug("read error %d\n", tmp);
err = -EIO;
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH] rtc-ds1307: True SMBus compatibility 2009-01-05 17:41 [PATCH] rtc-ds1307: True SMBus compatibility Ed Swierk @ 2009-01-06 22:48 ` David Brownell [not found] ` <1231177261.13443.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 1 sibling, 0 replies; 15+ messages in thread From: David Brownell @ 2009-01-06 22:48 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c, Alessandro Zummo, linux-kernel, Andrew Morton, BARRE Sebastien On Monday 05 January 2009, Ed Swierk wrote: > Reading or writing registers repeatedly until they stick is rather > nauseating but I'm aiming for correctness if not elegance. I would > appreciate any suggestions for improvement. Can i2c_smbus_read_i2c_block_data()/i2c_ smbus_write_i2c_block_data() work better -- without nauseating anyone? Faking atomic writes doesn't seem "correct" to me. Minimally there is the case of an alarm misfiring. - Dave ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <1231177261.13443.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <1231177261.13443.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2009-01-07 13:24 ` Jean Delvare [not found] ` <20090107142426.4be04d4d-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Jean Delvare @ 2009-01-07 13:24 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien Hi Ed, On Mon, 05 Jan 2009 09:41:01 -0800, Ed Swierk wrote: > [Resent to correct linux-i2c address] > > Following up to Sebastien Barre's recent patch, here I go one step > further, replacing i2c block transfers with SMBus byte transfers. Please, no. Adding a compatibility quirk may be acceptable, but forcing everyone to use it instead of the more efficient original code is not fair. > Sticking to pure SMBus makes the driver work on our board, which has an > nVidia SMBus controller driving a DS1339; nforce2 controllers > unfortunately don't support any flavor of i2c block transfer. Are you certain the nForce2 controllers can't do it? The i2c-nforce2 driver doesn't implement it, but this doesn't mean the hardware can't do it. I don't have any datasheet for these chips, but I know their SMBus implementation is very similar to those of the AMD 8111, and i2c-amd8111 has support for I2C block reads and writes. I think it would be worth giving it a try, by copying the i2c-amd8111 implementation into the i2c-nforce2 driver and seeing if it happens to just work. If it works, that would be more elegant than your proposed hack to the rtc-ds1307 driver. > Reading or writing registers repeatedly until they stick is rather > nauseating but I'm aiming for correctness if not elegance. I would > appreciate any suggestions for improvement. See above. -- Jean Delvare ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <20090107142426.4be04d4d-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <20090107142426.4be04d4d-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2009-01-07 15:22 ` Ed Swierk [not found] ` <9ae48b020901070722l77bebc6boc8fa2fd0bcc8da28-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Ed Swierk @ 2009-01-07 15:22 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien On Wed, Jan 7, 2009 at 5:24 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > Are you certain the nForce2 controllers can't do it? The i2c-nforce2 > driver doesn't implement it, but this doesn't mean the hardware can't > do it. I don't have any datasheet for these chips, but I know their > SMBus implementation is very similar to those of the AMD 8111, and > i2c-amd8111 has support for I2C block reads and writes. I think it > would be worth giving it a try, by copying the i2c-amd8111 > implementation into the i2c-nforce2 driver and seeing if it happens to > just work. If it works, that would be more elegant than your proposed > hack to the rtc-ds1307 driver. I checked the datasheet and also tried every possible SMBus command value to try to discover any supported commands that the i2c-nforce2 driver happens not to use, to no avail. The nVidia SMBus is pure SMBus. I could change the ds1307 driver to check whether the controller supports i2c block commands and fall back to emulation only if they are not available. Would that address your concerns? --Ed ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <9ae48b020901070722l77bebc6boc8fa2fd0bcc8da28-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <9ae48b020901070722l77bebc6boc8fa2fd0bcc8da28-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2009-01-07 15:27 ` Jean Delvare [not found] ` <20090107162709.755982c0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Jean Delvare @ 2009-01-07 15:27 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien Hi Ed, On Wed, 7 Jan 2009 07:22:12 -0800, Ed Swierk wrote: > On Wed, Jan 7, 2009 at 5:24 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > > Are you certain the nForce2 controllers can't do it? The i2c-nforce2 > > driver doesn't implement it, but this doesn't mean the hardware can't > > do it. I don't have any datasheet for these chips, but I know their > > SMBus implementation is very similar to those of the AMD 8111, and > > i2c-amd8111 has support for I2C block reads and writes. I think it > > would be worth giving it a try, by copying the i2c-amd8111 > > implementation into the i2c-nforce2 driver and seeing if it happens to > > just work. If it works, that would be more elegant than your proposed > > hack to the rtc-ds1307 driver. > > I checked the datasheet and also tried every possible SMBus command > value to try to discover any supported commands that the i2c-nforce2 > driver happens not to use, to no avail. The nVidia SMBus is pure > SMBus. Did you try 0x4a (as i2c-amd8111 is using)? So, you have the datasheet... Is this something you would be allowed to share with me? > I could change the ds1307 driver to check whether the controller > supports i2c block commands and fall back to emulation only if they > are not available. Would that address your concerns? Yes, that would. Same thing the eeprom or lm93 drivers are doing, to only name a few of them. Should be fairly easy. -- Jean Delvare ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <20090107162709.755982c0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <20090107162709.755982c0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2009-01-07 15:43 ` Ed Swierk [not found] ` <9ae48b020901070743x1a5eaf72k5314cd969dc580ef-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2009-01-19 23:59 ` Ed Swierk 1 sibling, 1 reply; 15+ messages in thread From: Ed Swierk @ 2009-01-07 15:43 UTC (permalink / raw) To: Jean Delvare Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien On Wed, Jan 7, 2009 at 7:27 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > Did you try 0x4a (as i2c-amd8111 is using)? Yes, it returns an error, as do all the other unsupported commands. > So, you have the datasheet... Is this something you would be allowed to > share with me? Unfortunately not; we acquired it under an NDA. >> I could change the ds1307 driver to check whether the controller >> supports i2c block commands and fall back to emulation only if they >> are not available. Would that address your concerns? > > Yes, that would. Same thing the eeprom or lm93 drivers are doing, to > only name a few of them. Should be fairly easy. OK, will do. --Ed ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <9ae48b020901070743x1a5eaf72k5314cd969dc580ef-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <9ae48b020901070743x1a5eaf72k5314cd969dc580ef-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2009-01-07 15:49 ` Jean Delvare 0 siblings, 0 replies; 15+ messages in thread From: Jean Delvare @ 2009-01-07 15:49 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien On Wed, 7 Jan 2009 07:43:18 -0800, Ed Swierk wrote: > On Wed, Jan 7, 2009 at 7:27 AM, Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> wrote: > > Did you try 0x4a (as i2c-amd8111 is using)? > > Yes, it returns an error, as do all the other unsupported commands. Oh well. > > So, you have the datasheet... Is this something you would be allowed to > > share with me? > > Unfortunately not; we acquired it under an NDA. I expected that :( By any chance, the datasheet doesn't explain why SMBus block transactions of size 32 lock the chip, nor how to work around it? > >> I could change the ds1307 driver to check whether the controller > >> supports i2c block commands and fall back to emulation only if they > >> are not available. Would that address your concerns? > > > > Yes, that would. Same thing the eeprom or lm93 drivers are doing, to > > only name a few of them. Should be fairly easy. > > OK, will do. OK. BTW, designing a system with an SMBus master which is so clearly inappropriate for the I2C chips that are connected to it wasn't exactly smart to start with. Whoever did this should be told to think twice about it next time. -- Jean Delvare ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <20090107162709.755982c0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 2009-01-07 15:43 ` Ed Swierk @ 2009-01-19 23:59 ` Ed Swierk [not found] ` <1232409577.25123.11.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 1 sibling, 1 reply; 15+ messages in thread From: Ed Swierk @ 2009-01-19 23:59 UTC (permalink / raw) To: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew [-- Attachment #1: Type: text/plain, Size: 371 bytes --] Here is an updated patch for rtc-ds1307 that allows the driver to work with SMBus controllers like nforce2 that do not support i2c block transfers. The driver now checks the capabilities of the controller and emulates the block transfers with SMBus byte transfers only if necessary. Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> [-- Attachment #2: rtc-ds1307-pure-smbus-compatibility.patch --] [-- Type: text/x-patch, Size: 6614 bytes --] Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c =================================================================== --- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c +++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c @@ -94,6 +94,10 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; + s32 (*read_block_data)(struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(struct i2c_client *client, u8 command, + u8 length, const u8 *values); }; struct chip_desc { @@ -132,6 +136,61 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + *(values + i) = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + pr_debug("ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + s32 ret; + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + pr_debug("ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + *(values + i)); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +261,7 @@ static int ds1307_get_time(struct device int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +338,7 @@ static int ds1307_set_time(struct device "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +356,7 @@ static int ds1307_read_alarm(struct devi return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +415,7 @@ static int ds1307_set_alarm(struct devic t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +450,7 @@ static int ds1307_set_alarm(struct devic } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307->write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +538,7 @@ ds1307_nvram_read(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -490,9 +549,11 @@ ds1307_nvram_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct i2c_client *client; + struct ds1307 *ds1307; int result; client = kobj_to_i2c_client(kobj); + ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -501,7 +562,7 @@ ds1307_nvram_write(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -536,9 +597,8 @@ static int __devinit ds1307_probe(struct int want_irq = false; unsigned char *buf; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -548,6 +608,14 @@ static int __devinit ds1307_probe(struct i2c_set_clientdata(client, ds1307); ds1307->type = id->driver_data; buf = ds1307->regs; + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + ds1307->read_block_data = i2c_smbus_read_i2c_block_data; + ds1307->write_block_data = i2c_smbus_write_i2c_block_data; + } + else { + ds1307->read_block_data = ds1307_read_block_data; + ds1307->write_block_data = ds1307_write_block_data; + } switch (ds1307->type) { case ds_1337: @@ -558,7 +626,7 @@ static int __devinit ds1307_probe(struct want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -596,7 +664,7 @@ static int __devinit ds1307_probe(struct read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <1232409577.25123.11.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <1232409577.25123.11.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2009-01-20 10:43 ` Jean Delvare [not found] ` <20090120114304.3b956189-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Jean Delvare @ 2009-01-20 10:43 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien Hi Ed, On Mon, 19 Jan 2009 15:59:37 -0800, Ed Swierk wrote: > Here is an updated patch for rtc-ds1307 that allows the driver to work > with SMBus controllers like nforce2 that do not support i2c block > transfers. The driver now checks the capabilities of the controller and > emulates the block transfers with SMBus byte transfers only if > necessary. > > Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> Patch looks reasonable, with just minor objections: > Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c > =================================================================== > --- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c > +++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c > @@ -94,6 +94,10 @@ struct ds1307 { > struct i2c_client *client; > struct rtc_device *rtc; > struct work_struct work; > + s32 (*read_block_data)(struct i2c_client *client, u8 command, > + u8 length, u8 *values); > + s32 (*write_block_data)(struct i2c_client *client, u8 command, > + u8 length, const u8 *values); > }; > > struct chip_desc { > @@ -132,6 +136,61 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); > > /*----------------------------------------------------------------------*/ > > +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, > + u8 length, u8 *values) > +{ > + s32 i, data; > + for (i = 0; i < length; i++) { > + data = i2c_smbus_read_byte_data(client, command + i); > + if (data < 0) > + return data; > + *(values + i) = data; > + } > + return i; > +} > + > +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, > + u8 length, u8 *values) > +{ > + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; > + s32 ret; > + pr_debug("ds1307_read_block_data (length=%d)\n", length); Please use dev_dbg(&client->dev, ...). > + ret = ds1307_read_block_data_once(client, command, length, values); > + if (ret < 0) > + return ret; > + do { > + s32 ret; Redeclaring a variable that already exists? > + memcpy(oldvalues, values, length); > + ret = ds1307_read_block_data_once(client, command, length, values); > + if (ret < 0) > + return ret; > + } while (memcmp(oldvalues, values, length)); What guarantee do you have that you'll ever leave this loop? > + return length; > +} > + > +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, > + u8 length, const u8 *values) > +{ > + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; > + pr_debug("ds1307_write_block_data (length=%d)\n", length); dev_dbg > + do { > + s32 i, ret; > + for (i = 0; i < length; i++) { > + ret = i2c_smbus_write_byte_data(client, command + i, > + *(values + i)); > + if (ret < 0) > + return ret; > + } > + ret = ds1307_read_block_data_once(client, command, length, > + currvalues); > + if (ret < 0) > + return ret; > + } while (memcmp(currvalues, values, length)); Same question as above, what if you get stuck in the loop? > + return length; > +} > + > +/*----------------------------------------------------------------------*/ > + > /* All the rest is fine. -- Jean Delvare ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <20090120114304.3b956189-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <20090120114304.3b956189-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org> @ 2009-01-26 6:33 ` Ed Swierk [not found] ` <1232951630.1329.4.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 0 siblings, 1 reply; 15+ messages in thread From: Ed Swierk @ 2009-01-26 6:33 UTC (permalink / raw) To: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew [-- Attachment #1: Type: text/plain, Size: 385 bytes --] Here's another attempt at a patch for rtc-ds1307 that allows the driver to work with SMBus controllers like nforce2 that do not support i2c block transfers. The byte-oriented compatibility routines now give up after 10 unsuccessful attempts to read or write a block of registers without conflict. Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> [-- Attachment #2: rtc-ds1307-pure-smbus-compatibility.patch --] [-- Type: text/x-patch, Size: 6957 bytes --] Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c =================================================================== --- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c +++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c @@ -94,6 +94,10 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; + s32 (*read_block_data)(struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(struct i2c_client *client, u8 command, + u8 length, const u8 *values); }; struct chip_desc { @@ -132,6 +136,75 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +#define BLOCK_DATA_MAX_TRIES 10 + +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + values[i] = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + int tries = 0; + dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_read_block_data failed\n"); + return -EIO; + } + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, + values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + int tries = 0; + dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_write_block_data failed\n"); + return -EIO; + } + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + values[i]); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +275,7 @@ static int ds1307_get_time(struct device int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +352,7 @@ static int ds1307_set_time(struct device "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +370,7 @@ static int ds1307_read_alarm(struct devi return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +429,7 @@ static int ds1307_set_alarm(struct devic t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +464,7 @@ static int ds1307_set_alarm(struct devic } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307->write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +552,7 @@ ds1307_nvram_read(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -490,9 +563,11 @@ ds1307_nvram_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct i2c_client *client; + struct ds1307 *ds1307; int result; client = kobj_to_i2c_client(kobj); + ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -501,7 +576,7 @@ ds1307_nvram_write(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -536,9 +611,8 @@ static int __devinit ds1307_probe(struct int want_irq = false; unsigned char *buf; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -548,6 +622,13 @@ static int __devinit ds1307_probe(struct i2c_set_clientdata(client, ds1307); ds1307->type = id->driver_data; buf = ds1307->regs; + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + ds1307->read_block_data = i2c_smbus_read_i2c_block_data; + ds1307->write_block_data = i2c_smbus_write_i2c_block_data; + } else { + ds1307->read_block_data = ds1307_read_block_data; + ds1307->write_block_data = ds1307_write_block_data; + } switch (ds1307->type) { case ds_1337: @@ -558,7 +639,7 @@ static int __devinit ds1307_probe(struct want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -596,7 +677,7 @@ static int __devinit ds1307_probe(struct read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <1232951630.1329.4.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <1232951630.1329.4.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> @ 2009-01-26 9:37 ` Jean Delvare 2009-01-26 21:06 ` David Brownell 1 sibling, 0 replies; 15+ messages in thread From: Jean Delvare @ 2009-01-26 9:37 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien On Sun, 25 Jan 2009 22:33:50 -0800, Ed Swierk wrote: > Here's another attempt at a patch for rtc-ds1307 that allows the driver > to work with SMBus controllers like nforce2 that do not support i2c > block transfers. The byte-oriented compatibility routines now give up > after 10 unsuccessful attempts to read or write a block of registers > without conflict. > > Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> Looks alright to me this time. Acked-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org> -- Jean Delvare ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <1232951630.1329.4.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org> 2009-01-26 9:37 ` Jean Delvare @ 2009-01-26 21:06 ` David Brownell [not found] ` <200901261306.21059.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> 1 sibling, 1 reply; 15+ messages in thread From: David Brownell @ 2009-01-26 21:06 UTC (permalink / raw) To: Ed Swierk Cc: Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, BARRE Sebastien On Sunday 25 January 2009, Ed Swierk wrote: > Here's another attempt at a patch for rtc-ds1307 that allows the driver > to work with SMBus controllers like nforce2 that do not support i2c > block transfers. The byte-oriented compatibility routines now give up > after 10 unsuccessful attempts to read or write a block of registers > without conflict. > > Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> Well, other than the *conceptual* ugliness of this (which we seem to be stuck with, courtesy the board designer) ... I have two patch format issues: - Always put a line of whitespace after variable declarations. - Include text like the above as part of the patch, even if you're stuck with a mailer that mangles non-attached text. You're using Evolution, which is mentioned in the Documentation/email-clients.txt file as having a way (albeit awkward) to send normal patch email. Given those changes: Acked-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> Thanks. - Dave ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <200901261306.21059.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <200901261306.21059.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org> @ 2009-01-26 21:54 ` Ed Swierk 0 siblings, 0 replies; 15+ messages in thread From: Ed Swierk @ 2009-01-26 21:54 UTC (permalink / raw) To: David Brownell, Jean Delvare, linux-i2c-u79uwXL29TY76Z2rM5mHXA, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew On Mon, 2009-01-26 at 13:06 -0800, David Brownell wrote: > I have two patch format issues: > > - Always put a line of whitespace after variable > declarations. > > - Include text like the above as part of the patch, > even if you're stuck with a mailer that mangles > non-attached text. > > You're using Evolution, which is mentioned in the > Documentation/email-clients.txt file as having a > way (albeit awkward) to send normal patch email. > > Given those changes: > > Acked-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> > > Thanks. Thanks for the feedback. Here you go: 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-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c =================================================================== --- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c +++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c @@ -94,6 +94,10 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; + s32 (*read_block_data)(struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(struct i2c_client *client, u8 command, + u8 length, const u8 *values); }; struct chip_desc { @@ -132,6 +136,79 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +#define BLOCK_DATA_MAX_TRIES 10 + +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + values[i] = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_read_block_data failed\n"); + return -EIO; + } + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, + values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_write_block_data failed\n"); + return -EIO; + } + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + values[i]); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +279,7 @@ static int ds1307_get_time(struct device int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +356,7 @@ static int ds1307_set_time(struct device "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +374,7 @@ static int ds1307_read_alarm(struct devi return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +433,7 @@ static int ds1307_set_alarm(struct devic t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +468,7 @@ static int ds1307_set_alarm(struct devic } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307->write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +556,7 @@ ds1307_nvram_read(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -490,9 +567,11 @@ ds1307_nvram_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct i2c_client *client; + struct ds1307 *ds1307; int result; client = kobj_to_i2c_client(kobj); + ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -501,7 +580,7 @@ ds1307_nvram_write(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -536,9 +615,8 @@ static int __devinit ds1307_probe(struct int want_irq = false; unsigned char *buf; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -548,6 +626,13 @@ static int __devinit ds1307_probe(struct i2c_set_clientdata(client, ds1307); ds1307->type = id->driver_data; buf = ds1307->regs; + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + ds1307->read_block_data = i2c_smbus_read_i2c_block_data; + ds1307->write_block_data = i2c_smbus_write_i2c_block_data; + } else { + ds1307->read_block_data = ds1307_read_block_data; + ds1307->write_block_data = ds1307_write_block_data; + } switch (ds1307->type) { case ds_1337: @@ -558,7 +643,7 @@ static int __devinit ds1307_probe(struct want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -596,7 +681,7 @@ static int __devinit ds1307_probe(struct read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <1231176979.13443.19.camel@localhost.localdomain>]
[parent not found: <C1C62166118DFA4A8BBA01A2411F0D171224AECDC1@PRI-MBX-101.dom1.vinci-energies.net>]
[parent not found: <C1C62166118DFA4A8BBA01A2411F0D171224AECDC1-iGzfJtNnmHkUlixSki3fykIJAyBIbWHDnAJcWxkt5PDR7s880joybQ@public.gmane.org>]
* Re: [PATCH] rtc-ds1307: True SMBus compatibility [not found] ` <C1C62166118DFA4A8BBA01A2411F0D171224AECDC1-iGzfJtNnmHkUlixSki3fykIJAyBIbWHDnAJcWxkt5PDR7s880joybQ@public.gmane.org> @ 2009-01-06 22:13 ` Ed Swierk 2009-01-07 14:22 ` BARRE Sebastien 0 siblings, 1 reply; 15+ messages in thread From: Ed Swierk @ 2009-01-06 22:13 UTC (permalink / raw) To: BARRE Sebastien Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, David Brownell, Alessandro Zummo, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Andrew Morton [-- Attachment #1: Type: text/plain, Size: 562 bytes --] On Tue, Jan 6, 2009 at 5:35 AM, BARRE Sebastien <sbarre-6lXSvc0s5hDQT0dZR+AlfA@public.gmane.org> wrote: > I've read your patch quicly, I will test it on my board as soon as possible. Thanks. > You can delete the next 3 lines, they are not useful: > >> + ret = ds1307_read_block_data_once(client, command, length, currvalues); >> + if (ret < 0) >> + return ret; Oops! Here is an updated patch with these lines removed, and a minor formatting fix. Signed-off-by: Ed Swierk <eswierk-BGArkANP9klv6pq1l3V1OdBPR1lH4CV8@public.gmane.org> --Ed [-- Attachment #2: rtc-ds1307-pure-smbus-compatibility.patch --] [-- Type: text/x-patch, Size: 5319 bytes --] Index: linux-2.6.27.4/drivers/rtc/rtc-ds1307.c =================================================================== --- linux-2.6.27.4.orig/drivers/rtc/rtc-ds1307.c +++ linux-2.6.27.4/drivers/rtc/rtc-ds1307.c @@ -132,6 +132,62 @@ MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + *(values + i) = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + pr_debug("ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + s32 ret; + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + pr_debug("ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + *(values + i)); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +258,7 @@ static int ds1307_get_time(struct device int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307_read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +335,7 @@ static int ds1307_set_time(struct device "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307_write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +353,7 @@ static int ds1307_read_alarm(struct devi return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307_read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +412,7 @@ static int ds1307_set_alarm(struct devic t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307_read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +447,7 @@ static int ds1307_set_alarm(struct devic } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307_write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +535,7 @@ ds1307_nvram_read(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307_read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -501,7 +557,7 @@ ds1307_nvram_write(struct kobject *kobj, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307_write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -537,8 +593,7 @@ static int __devinit ds1307_probe(struct unsigned char *buf; if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -558,7 +613,7 @@ static int __devinit ds1307_probe(struct want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307_read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -596,7 +651,7 @@ static int __devinit ds1307_probe(struct read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307_read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; ^ permalink raw reply [flat|nested] 15+ messages in thread
* RE: [PATCH] rtc-ds1307: True SMBus compatibility 2009-01-06 22:13 ` Ed Swierk @ 2009-01-07 14:22 ` BARRE Sebastien 0 siblings, 0 replies; 15+ messages in thread From: BARRE Sebastien @ 2009-01-07 14:22 UTC (permalink / raw) To: Ed Swierk Cc: linux-i2c@vger.kernel.org, David Brownell, Alessandro Zummo, linux-kernel@vger.kernel.org, Andrew Morton, Jean Delvare > -----Original Message----- > From: Ed Swierk [mailto:eswierk@aristanetworks.com] > Sent: Tuesday, January 06, 2009 11:14 PM > To: BARRE Sebastien > Cc: linux-i2c@vger.kernel.org; David Brownell; Alessandro Zummo; linux- > kernel@vger.kernel.org; Andrew Morton > Subject: Re: [PATCH] rtc-ds1307: True SMBus compatibility > > On Tue, Jan 6, 2009 at 5:35 AM, BARRE Sebastien <sbarre@sdelcc.com> wrote: > > I've read your patch quicly, I will test it on my board as soon as > possible. > > Thanks. > > > You can delete the next 3 lines, they are not useful: > > > >> + ret = ds1307_read_block_data_once(client, command, length, > currvalues); > >> + if (ret < 0) > >> + return ret; > > Oops! Here is an updated patch with these lines removed, and a minor > formatting fix. > > Signed-off-by: Ed Swierk <eswierk@aristanetworks.com> > > --Ed I've tested the patch on my geode LX board with a DS1307 device. It works well for me. However I think writing the clock one byte at a time could cause strange behavior when using alarms on device like ds1337. Tested-by: Sébastien Barré <sbarre@sdelcc.com> -- Sébastien Barré Bureau d'étude - Développement SDEL Contrôle Commande D2A - Rue Nungesser et Coli 44860 Saint Aignan de Grand Lieu FRANCE Tél : +33(0)2 40 84 50 88 Fax : +33(0)2 40 84 51 10 ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2009-01-26 21:54 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-05 17:41 [PATCH] rtc-ds1307: True SMBus compatibility Ed Swierk
2009-01-06 22:48 ` David Brownell
[not found] ` <1231177261.13443.20.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2009-01-07 13:24 ` Jean Delvare
[not found] ` <20090107142426.4be04d4d-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-01-07 15:22 ` Ed Swierk
[not found] ` <9ae48b020901070722l77bebc6boc8fa2fd0bcc8da28-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-01-07 15:27 ` Jean Delvare
[not found] ` <20090107162709.755982c0-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-01-07 15:43 ` Ed Swierk
[not found] ` <9ae48b020901070743x1a5eaf72k5314cd969dc580ef-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-01-07 15:49 ` Jean Delvare
2009-01-19 23:59 ` Ed Swierk
[not found] ` <1232409577.25123.11.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2009-01-20 10:43 ` Jean Delvare
[not found] ` <20090120114304.3b956189-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-01-26 6:33 ` Ed Swierk
[not found] ` <1232951630.1329.4.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2009-01-26 9:37 ` Jean Delvare
2009-01-26 21:06 ` David Brownell
[not found] ` <200901261306.21059.david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org>
2009-01-26 21:54 ` Ed Swierk
[not found] <1231176979.13443.19.camel@localhost.localdomain>
[not found] ` <C1C62166118DFA4A8BBA01A2411F0D171224AECDC1@PRI-MBX-101.dom1.vinci-energies.net>
[not found] ` <C1C62166118DFA4A8BBA01A2411F0D171224AECDC1-iGzfJtNnmHkUlixSki3fykIJAyBIbWHDnAJcWxkt5PDR7s880joybQ@public.gmane.org>
2009-01-06 22:13 ` Ed Swierk
2009-01-07 14:22 ` BARRE Sebastien
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox