aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/rtc-ds1307.c60
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,
196static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command, 197static 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,
222static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command, 223static 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
259static 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
281static 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;