]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/rtc/rtc-ds1307.c
[ARM] 4915/1: AT91: Update defconfigs (Part 2)
[linux-2.6-omap-h63xx.git] / drivers / rtc / rtc-ds1307.c
index db6f3f0d8982e685b7e48cc78e2f2db6040c4742..f389a28720d2da4302c05a1ef56e2fc5530272a7 100644 (file)
@@ -89,6 +89,7 @@ enum ds_type {
 
 struct ds1307 {
        u8                      reg_addr;
+       bool                    has_nvram;
        u8                      regs[8];
        enum ds_type            type;
        struct i2c_msg          msg[2];
@@ -242,6 +243,87 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
        .set_time       = ds1307_set_time,
 };
 
+/*----------------------------------------------------------------------*/
+
+#define NVRAM_SIZE     56
+
+static ssize_t
+ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct i2c_client       *client;
+       struct ds1307           *ds1307;
+       struct i2c_msg          msg[2];
+       int                     result;
+
+       client = kobj_to_i2c_client(kobj);
+       ds1307 = i2c_get_clientdata(client);
+
+       if (unlikely(off >= NVRAM_SIZE))
+               return 0;
+       if ((off + count) > NVRAM_SIZE)
+               count = NVRAM_SIZE - off;
+       if (unlikely(!count))
+               return count;
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 1;
+       msg[0].buf = buf;
+
+       buf[0] = 8 + off;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = count;
+       msg[1].buf = buf;
+
+       result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2);
+       if (result != 2) {
+               dev_err(&client->dev, "%s error %d\n", "nvram read", result);
+               return -EIO;
+       }
+       return count;
+}
+
+static ssize_t
+ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct i2c_client       *client;
+       u8                      buffer[NVRAM_SIZE + 1];
+       int                     ret;
+
+       client = kobj_to_i2c_client(kobj);
+
+       if (unlikely(off >= NVRAM_SIZE))
+               return -EFBIG;
+       if ((off + count) > NVRAM_SIZE)
+               count = NVRAM_SIZE - off;
+       if (unlikely(!count))
+               return count;
+
+       buffer[0] = 8 + off;
+       memcpy(buffer + 1, buf, count);
+
+       ret = i2c_master_send(client, buffer, count + 1);
+       return (ret < 0) ? ret : (ret - 1);
+}
+
+static struct bin_attribute nvram = {
+       .attr = {
+               .name   = "nvram",
+               .mode   = S_IRUGO | S_IWUSR,
+               .owner  = THIS_MODULE,
+       },
+
+       .read   = ds1307_nvram_read,
+       .write  = ds1307_nvram_write,
+       .size   = NVRAM_SIZE,
+};
+
+/*----------------------------------------------------------------------*/
+
 static struct i2c_driver ds1307_driver;
 
 static int __devinit ds1307_probe(struct i2c_client *client)
@@ -330,11 +412,6 @@ read_rtc:
         */
        tmp = ds1307->regs[DS1307_REG_SECS];
        switch (ds1307->type) {
-       case ds_1340:
-               /* FIXME read register with DS1340_BIT_OSF, use that to
-                * trigger the "set time" warning (*after* restarting the
-                * oscillator!) instead of this weaker ds1307/m41t00 test.
-                */
        case ds_1307:
        case m41t00:
                /* clock halted?  turn it on, so clock can tick. */
@@ -358,6 +435,24 @@ read_rtc:
                        goto read_rtc;
                }
                break;
+       case ds_1340:
+               /* clock halted?  turn it on, so clock can tick. */
+               if (tmp & DS1340_BIT_nEOSC)
+                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+               tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
+               if (tmp < 0) {
+                       pr_debug("read error %d\n", tmp);
+                       err = -EIO;
+                       goto exit_free;
+               }
+
+               /* oscillator fault?  clear flag, and warn */
+               if (tmp & DS1340_BIT_OSF) {
+                       i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
+                       dev_warn(&client->dev, "SET TIME!\n");
+               }
+               break;
        case ds_1337:
        case ds_1339:
                break;
@@ -413,6 +508,14 @@ read_rtc:
                goto exit_free;
        }
 
+       if (chip->nvram56) {
+               err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
+               if (err == 0) {
+                       ds1307->has_nvram = true;
+                       dev_info(&client->dev, "56 bytes nvram\n");
+               }
+       }
+
        return 0;
 
 exit_bad:
@@ -432,6 +535,9 @@ static int __devexit ds1307_remove(struct i2c_client *client)
 {
        struct ds1307   *ds1307 = i2c_get_clientdata(client);
 
+       if (ds1307->has_nvram)
+               sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+
        rtc_device_unregister(ds1307->rtc);
        kfree(ds1307);
        return 0;