Skip to content

Commit

Permalink
rtc: ds1307: generalise ram size and offset
Browse files Browse the repository at this point in the history
Generalise NVRAM to support RAM with other size and offset, such as the
64 bytes of SRAM on the mcp7941x.

[[email protected]: fix printk format warning]
Signed-off-by: Austin Boyle <[email protected]>
Signed-off-by: Wolfram Sang <[email protected]>
Signed-off-by: Randy Dunlap <[email protected]>
Cc: David Anders <[email protected]>
Cc: Alessandro Zummo <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
austinmarton authored and torvalds committed Mar 23, 2012
1 parent 40ce972 commit 9eab0a7
Showing 1 changed file with 47 additions and 31 deletions.
78 changes: 47 additions & 31 deletions drivers/rtc/rtc-ds1307.c
Original file line number Diff line number Diff line change
@@ -105,6 +105,8 @@ enum ds_type {
struct ds1307 {
u8 offset; /* register's offset */
u8 regs[11];
u16 nvram_offset;
struct bin_attribute *nvram;
enum ds_type type;
unsigned long flags;
#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
@@ -119,26 +121,34 @@ struct ds1307 {
};

struct chip_desc {
unsigned nvram56:1;
unsigned alarm:1;
u16 nvram_offset;
u16 nvram_size;
};

static const struct chip_desc chips[last_ds_type] = {
[ds_1307] = {
.nvram56 = 1,
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1337] = {
.alarm = 1,
},
[ds_1338] = {
.nvram56 = 1,
.nvram_offset = 8,
.nvram_size = 56,
},
[ds_1339] = {
.alarm = 1,
},
[ds_3231] = {
.alarm = 1,
},
[mcp7941x] = {
/* this is battery backed SRAM */
.nvram_offset = 0x20,
.nvram_size = 0x40,
},
};

static const struct i2c_device_id ds1307_id[] = {
@@ -543,8 +553,6 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {

/*----------------------------------------------------------------------*/

#define NVRAM_SIZE 56

static ssize_t
ds1307_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
@@ -557,14 +565,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);

if (unlikely(off >= NVRAM_SIZE))
if (unlikely(off >= ds1307->nvram->size))
return 0;
if ((off + count) > NVRAM_SIZE)
count = NVRAM_SIZE - off;
if ((off + count) > ds1307->nvram->size)
count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;

result = ds1307->read_block_data(client, 8 + off, count, buf);
result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
count, buf);
if (result < 0)
dev_err(&client->dev, "%s error %d\n", "nvram read", result);
return result;
@@ -582,32 +591,22 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);

if (unlikely(off >= NVRAM_SIZE))
if (unlikely(off >= ds1307->nvram->size))
return -EFBIG;
if ((off + count) > NVRAM_SIZE)
count = NVRAM_SIZE - off;
if ((off + count) > ds1307->nvram->size)
count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;

result = ds1307->write_block_data(client, 8 + off, count, buf);
result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
count, buf);
if (result < 0) {
dev_err(&client->dev, "%s error %d\n", "nvram write", result);
return result;
}
return count;
}

static struct bin_attribute nvram = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
},

.read = ds1307_nvram_read,
.write = ds1307_nvram_write,
.size = NVRAM_SIZE,
};

/*----------------------------------------------------------------------*/

static int __devinit ds1307_probe(struct i2c_client *client,
@@ -894,16 +893,31 @@ static int __devinit ds1307_probe(struct i2c_client *client,
dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
}

if (chip->nvram56) {
err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
if (err == 0) {
set_bit(HAS_NVRAM, &ds1307->flags);
dev_info(&client->dev, "56 bytes nvram\n");
if (chip->nvram_size) {
ds1307->nvram = kzalloc(sizeof(struct bin_attribute),
GFP_KERNEL);
if (!ds1307->nvram) {
err = -ENOMEM;
goto exit_nvram;
}
ds1307->nvram->attr.name = "nvram";
ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
ds1307->nvram->read = ds1307_nvram_read,
ds1307->nvram->write = ds1307_nvram_write,
ds1307->nvram->size = chip->nvram_size;
ds1307->nvram_offset = chip->nvram_offset;
err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
if (err) {
kfree(ds1307->nvram);
goto exit_nvram;
}
set_bit(HAS_NVRAM, &ds1307->flags);
dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);
}

return 0;

exit_nvram:
exit_irq:
rtc_device_unregister(ds1307->rtc);
exit_free:
@@ -920,8 +934,10 @@ static int __devexit ds1307_remove(struct i2c_client *client)
cancel_work_sync(&ds1307->work);
}

if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
sysfs_remove_bin_file(&client->dev.kobj, &nvram);
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) {
sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
kfree(ds1307->nvram);
}

rtc_device_unregister(ds1307->rtc);
kfree(ds1307);

0 comments on commit 9eab0a7

Please sign in to comment.