diff options
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 970a236b147a..a65621c42170 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 2005 James Chapman (ds1337 core) | 4 | * Copyright (C) 2005 James Chapman (ds1337 core) |
5 | * Copyright (C) 2006 David Brownell | 5 | * Copyright (C) 2006 David Brownell |
6 | * Copyright (C) 2009 Matthias Fuchs (rx8025 support) | 6 | * Copyright (C) 2009 Matthias Fuchs (rx8025 support) |
7 | * Copyright (C) 2012 Bertrand Achard (nvram access fixes) | ||
7 | * | 8 | * |
8 | * This program is free software; you can redistribute it and/or modify | 9 | * 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 | * it under the terms of the GNU General Public License version 2 as |
@@ -196,7 +197,7 @@ static s32 ds1307_read_block_data_once(const struct i2c_client *client, | |||
196 | static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, | 197 | static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, |
197 | u8 length, u8 *values) | 198 | u8 length, u8 *values) |
198 | { | 199 | { |
199 | u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; | 200 | u8 oldvalues[255]; |
200 | s32 ret; | 201 | s32 ret; |
201 | int tries = 0; | 202 | int tries = 0; |
202 | 203 | ||
@@ -222,7 +223,7 @@ static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, | |||
222 | static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, | 223 | static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, |
223 | u8 length, const u8 *values) | 224 | u8 length, const u8 *values) |
224 | { | 225 | { |
225 | u8 currvalues[I2C_SMBUS_BLOCK_MAX]; | 226 | u8 currvalues[255]; |
226 | int tries = 0; | 227 | int tries = 0; |
227 | 228 | ||
228 | dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); | 229 | dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); |
@@ -250,6 +251,57 @@ static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, | |||
250 | 251 | ||
251 | /*----------------------------------------------------------------------*/ | 252 | /*----------------------------------------------------------------------*/ |
252 | 253 | ||
254 | /* These RTC devices are not designed to be connected to a SMbus adapter. | ||
255 | SMbus limits block operations length to 32 bytes, whereas it's not | ||
256 | limited on I2C buses. As a result, accesses may exceed 32 bytes; | ||
257 | in that case, split them into smaller blocks */ | ||
258 | |||
259 | static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client, | ||
260 | u8 command, u8 length, const u8 *values) | ||
261 | { | ||
262 | u8 suboffset = 0; | ||
263 | |||
264 | if (length <= I2C_SMBUS_BLOCK_MAX) | ||
265 | return i2c_smbus_write_i2c_block_data(client, | ||
266 | command, length, values); | ||
267 | |||
268 | while (suboffset < length) { | ||
269 | s32 retval = i2c_smbus_write_i2c_block_data(client, | ||
270 | command + suboffset, | ||
271 | min(I2C_SMBUS_BLOCK_MAX, length - suboffset), | ||
272 | values + suboffset); | ||
273 | if (retval < 0) | ||
274 | return retval; | ||
275 | |||
276 | suboffset += I2C_SMBUS_BLOCK_MAX; | ||
277 | } | ||
278 | return length; | ||
279 | } | ||
280 | |||
281 | static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, | ||
282 | u8 command, u8 length, u8 *values) | ||
283 | { | ||
284 | u8 suboffset = 0; | ||
285 | |||
286 | if (length <= I2C_SMBUS_BLOCK_MAX) | ||
287 | return i2c_smbus_read_i2c_block_data(client, | ||
288 | command, length, values); | ||
289 | |||
290 | while (suboffset < length) { | ||
291 | s32 retval = i2c_smbus_read_i2c_block_data(client, | ||
292 | command + suboffset, | ||
293 | min(I2C_SMBUS_BLOCK_MAX, length - suboffset), | ||
294 | values + suboffset); | ||
295 | if (retval < 0) | ||
296 | return retval; | ||
297 | |||
298 | suboffset += I2C_SMBUS_BLOCK_MAX; | ||
299 | } | ||
300 | return length; | ||
301 | } | ||
302 | |||
303 | /*----------------------------------------------------------------------*/ | ||
304 | |||
253 | /* | 305 | /* |
254 | * The IRQ logic includes a "real" handler running in IRQ context just | 306 | * The IRQ logic includes a "real" handler running in IRQ context just |
255 | * long enough to schedule this workqueue entry. We need a task context | 307 | * long enough to schedule this workqueue entry. We need a task context |
@@ -646,8 +698,8 @@ static int ds1307_probe(struct i2c_client *client, | |||
646 | 698 | ||
647 | buf = ds1307->regs; | 699 | buf = ds1307->regs; |
648 | if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { | 700 | if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { |
649 | ds1307->read_block_data = i2c_smbus_read_i2c_block_data; | 701 | ds1307->read_block_data = ds1307_native_smbus_read_block_data; |
650 | ds1307->write_block_data = i2c_smbus_write_i2c_block_data; | 702 | ds1307->write_block_data = ds1307_native_smbus_write_block_data; |
651 | } else { | 703 | } else { |
652 | ds1307->read_block_data = ds1307_read_block_data; | 704 | ds1307->read_block_data = ds1307_read_block_data; |
653 | ds1307->write_block_data = ds1307_write_block_data; | 705 | ds1307->write_block_data = ds1307_write_block_data; |