diff options
author | Austin Boyle <Austin.Boyle@aviatnet.com> | 2012-03-23 18:02:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 19:58:40 -0400 |
commit | 9eab0a788d2d6e513f43b7c0e5bb9d60446233cb (patch) | |
tree | 74b0e4386fbfd3b0ca58596bdb0616e57244a58d | |
parent | 40ce972d59fcfd4979e5de04456122447b40c1cf (diff) |
rtc: ds1307: generalise ram size and offset
Generalise NVRAM to support RAM with other size and offset, such as the
64 bytes of SRAM on the mcp7941x.
[rdunlap@xenotime.net: fix printk format warning]
Signed-off-by: Austin Boyle <Austin.Boyle@aviatnet.com>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Cc: David Anders <danders.dev@gmail.com>
Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 78 |
1 files changed, 47 insertions, 31 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 84ab971978cf..cd188ab72f79 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
@@ -105,6 +105,8 @@ enum ds_type { | |||
105 | struct ds1307 { | 105 | struct ds1307 { |
106 | u8 offset; /* register's offset */ | 106 | u8 offset; /* register's offset */ |
107 | u8 regs[11]; | 107 | u8 regs[11]; |
108 | u16 nvram_offset; | ||
109 | struct bin_attribute *nvram; | ||
108 | enum ds_type type; | 110 | enum ds_type type; |
109 | unsigned long flags; | 111 | unsigned long flags; |
110 | #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ | 112 | #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ |
@@ -119,19 +121,22 @@ struct ds1307 { | |||
119 | }; | 121 | }; |
120 | 122 | ||
121 | struct chip_desc { | 123 | struct chip_desc { |
122 | unsigned nvram56:1; | ||
123 | unsigned alarm:1; | 124 | unsigned alarm:1; |
125 | u16 nvram_offset; | ||
126 | u16 nvram_size; | ||
124 | }; | 127 | }; |
125 | 128 | ||
126 | static const struct chip_desc chips[last_ds_type] = { | 129 | static const struct chip_desc chips[last_ds_type] = { |
127 | [ds_1307] = { | 130 | [ds_1307] = { |
128 | .nvram56 = 1, | 131 | .nvram_offset = 8, |
132 | .nvram_size = 56, | ||
129 | }, | 133 | }, |
130 | [ds_1337] = { | 134 | [ds_1337] = { |
131 | .alarm = 1, | 135 | .alarm = 1, |
132 | }, | 136 | }, |
133 | [ds_1338] = { | 137 | [ds_1338] = { |
134 | .nvram56 = 1, | 138 | .nvram_offset = 8, |
139 | .nvram_size = 56, | ||
135 | }, | 140 | }, |
136 | [ds_1339] = { | 141 | [ds_1339] = { |
137 | .alarm = 1, | 142 | .alarm = 1, |
@@ -139,6 +144,11 @@ static const struct chip_desc chips[last_ds_type] = { | |||
139 | [ds_3231] = { | 144 | [ds_3231] = { |
140 | .alarm = 1, | 145 | .alarm = 1, |
141 | }, | 146 | }, |
147 | [mcp7941x] = { | ||
148 | /* this is battery backed SRAM */ | ||
149 | .nvram_offset = 0x20, | ||
150 | .nvram_size = 0x40, | ||
151 | }, | ||
142 | }; | 152 | }; |
143 | 153 | ||
144 | static const struct i2c_device_id ds1307_id[] = { | 154 | static const struct i2c_device_id ds1307_id[] = { |
@@ -543,8 +553,6 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { | |||
543 | 553 | ||
544 | /*----------------------------------------------------------------------*/ | 554 | /*----------------------------------------------------------------------*/ |
545 | 555 | ||
546 | #define NVRAM_SIZE 56 | ||
547 | |||
548 | static ssize_t | 556 | static ssize_t |
549 | ds1307_nvram_read(struct file *filp, struct kobject *kobj, | 557 | ds1307_nvram_read(struct file *filp, struct kobject *kobj, |
550 | struct bin_attribute *attr, | 558 | struct bin_attribute *attr, |
@@ -557,14 +565,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj, | |||
557 | client = kobj_to_i2c_client(kobj); | 565 | client = kobj_to_i2c_client(kobj); |
558 | ds1307 = i2c_get_clientdata(client); | 566 | ds1307 = i2c_get_clientdata(client); |
559 | 567 | ||
560 | if (unlikely(off >= NVRAM_SIZE)) | 568 | if (unlikely(off >= ds1307->nvram->size)) |
561 | return 0; | 569 | return 0; |
562 | if ((off + count) > NVRAM_SIZE) | 570 | if ((off + count) > ds1307->nvram->size) |
563 | count = NVRAM_SIZE - off; | 571 | count = ds1307->nvram->size - off; |
564 | if (unlikely(!count)) | 572 | if (unlikely(!count)) |
565 | return count; | 573 | return count; |
566 | 574 | ||
567 | result = ds1307->read_block_data(client, 8 + off, count, buf); | 575 | result = ds1307->read_block_data(client, ds1307->nvram_offset + off, |
576 | count, buf); | ||
568 | if (result < 0) | 577 | if (result < 0) |
569 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); | 578 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); |
570 | return result; | 579 | return result; |
@@ -582,14 +591,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, | |||
582 | client = kobj_to_i2c_client(kobj); | 591 | client = kobj_to_i2c_client(kobj); |
583 | ds1307 = i2c_get_clientdata(client); | 592 | ds1307 = i2c_get_clientdata(client); |
584 | 593 | ||
585 | if (unlikely(off >= NVRAM_SIZE)) | 594 | if (unlikely(off >= ds1307->nvram->size)) |
586 | return -EFBIG; | 595 | return -EFBIG; |
587 | if ((off + count) > NVRAM_SIZE) | 596 | if ((off + count) > ds1307->nvram->size) |
588 | count = NVRAM_SIZE - off; | 597 | count = ds1307->nvram->size - off; |
589 | if (unlikely(!count)) | 598 | if (unlikely(!count)) |
590 | return count; | 599 | return count; |
591 | 600 | ||
592 | result = ds1307->write_block_data(client, 8 + off, count, buf); | 601 | result = ds1307->write_block_data(client, ds1307->nvram_offset + off, |
602 | count, buf); | ||
593 | if (result < 0) { | 603 | if (result < 0) { |
594 | dev_err(&client->dev, "%s error %d\n", "nvram write", result); | 604 | dev_err(&client->dev, "%s error %d\n", "nvram write", result); |
595 | return result; | 605 | return result; |
@@ -597,17 +607,6 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, | |||
597 | return count; | 607 | return count; |
598 | } | 608 | } |
599 | 609 | ||
600 | static struct bin_attribute nvram = { | ||
601 | .attr = { | ||
602 | .name = "nvram", | ||
603 | .mode = S_IRUGO | S_IWUSR, | ||
604 | }, | ||
605 | |||
606 | .read = ds1307_nvram_read, | ||
607 | .write = ds1307_nvram_write, | ||
608 | .size = NVRAM_SIZE, | ||
609 | }; | ||
610 | |||
611 | /*----------------------------------------------------------------------*/ | 610 | /*----------------------------------------------------------------------*/ |
612 | 611 | ||
613 | static int __devinit ds1307_probe(struct i2c_client *client, | 612 | static int __devinit ds1307_probe(struct i2c_client *client, |
@@ -894,16 +893,31 @@ read_rtc: | |||
894 | dev_dbg(&client->dev, "got IRQ %d\n", client->irq); | 893 | dev_dbg(&client->dev, "got IRQ %d\n", client->irq); |
895 | } | 894 | } |
896 | 895 | ||
897 | if (chip->nvram56) { | 896 | if (chip->nvram_size) { |
898 | err = sysfs_create_bin_file(&client->dev.kobj, &nvram); | 897 | ds1307->nvram = kzalloc(sizeof(struct bin_attribute), |
899 | if (err == 0) { | 898 | GFP_KERNEL); |
900 | set_bit(HAS_NVRAM, &ds1307->flags); | 899 | if (!ds1307->nvram) { |
901 | dev_info(&client->dev, "56 bytes nvram\n"); | 900 | err = -ENOMEM; |
901 | goto exit_nvram; | ||
902 | } | ||
903 | ds1307->nvram->attr.name = "nvram"; | ||
904 | ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; | ||
905 | ds1307->nvram->read = ds1307_nvram_read, | ||
906 | ds1307->nvram->write = ds1307_nvram_write, | ||
907 | ds1307->nvram->size = chip->nvram_size; | ||
908 | ds1307->nvram_offset = chip->nvram_offset; | ||
909 | err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); | ||
910 | if (err) { | ||
911 | kfree(ds1307->nvram); | ||
912 | goto exit_nvram; | ||
902 | } | 913 | } |
914 | set_bit(HAS_NVRAM, &ds1307->flags); | ||
915 | dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size); | ||
903 | } | 916 | } |
904 | 917 | ||
905 | return 0; | 918 | return 0; |
906 | 919 | ||
920 | exit_nvram: | ||
907 | exit_irq: | 921 | exit_irq: |
908 | rtc_device_unregister(ds1307->rtc); | 922 | rtc_device_unregister(ds1307->rtc); |
909 | exit_free: | 923 | exit_free: |
@@ -920,8 +934,10 @@ static int __devexit ds1307_remove(struct i2c_client *client) | |||
920 | cancel_work_sync(&ds1307->work); | 934 | cancel_work_sync(&ds1307->work); |
921 | } | 935 | } |
922 | 936 | ||
923 | if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) | 937 | if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) { |
924 | sysfs_remove_bin_file(&client->dev.kobj, &nvram); | 938 | sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); |
939 | kfree(ds1307->nvram); | ||
940 | } | ||
925 | 941 | ||
926 | rtc_device_unregister(ds1307->rtc); | 942 | rtc_device_unregister(ds1307->rtc); |
927 | kfree(ds1307); | 943 | kfree(ds1307); |