]> 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 5306a1a5b873a54cb0937eb569e16057dbe83698..f389a28720d2da4302c05a1ef56e2fc5530272a7 100644 (file)
  * This is currently a simple no-alarms driver.  If your board has the
  * alarm irq wired up on a ds1337 or ds1339, and you want to use that,
  * then look at the rtc-rs5c372 driver for code to steal...
- *
- * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
- * (Much better would be board-specific tables of I2C devices, along with
- * the platform_data drivers would use to sort such issues out.)
  */
 enum ds_type {
-       unknown = 0,
        ds_1307,
        ds_1337,
        ds_1338,
@@ -43,11 +38,6 @@ enum ds_type {
        // rs5c372 too?  different address...
 };
 
-static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
-
 
 /* RTC registers don't differ much, except for the century flag */
 #define DS1307_REG_SECS                0x00    /* 00-59 */
@@ -55,6 +45,8 @@ I2C_CLIENT_INSMOD;
 #      define DS1340_BIT_nEOSC         0x80
 #define DS1307_REG_MIN         0x01    /* 00-59 */
 #define DS1307_REG_HOUR                0x02    /* 00-23, or 1-12{am,pm} */
+#      define DS1307_BIT_12HR          0x40    /* in REG_HOUR */
+#      define DS1307_BIT_PM            0x20    /* in REG_HOUR */
 #      define DS1340_BIT_CENTURY_EN    0x80    /* in REG_HOUR */
 #      define DS1340_BIT_CENTURY       0x40    /* in REG_HOUR */
 #define DS1307_REG_WDAY                0x03    /* 01-07 */
@@ -97,6 +89,7 @@ I2C_CLIENT_INSMOD;
 
 struct ds1307 {
        u8                      reg_addr;
+       bool                    has_nvram;
        u8                      regs[8];
        enum ds_type            type;
        struct i2c_msg          msg[2];
@@ -250,41 +243,110 @@ 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_detect(struct i2c_adapter *adapter, int address, int kind)
+static int __devinit ds1307_probe(struct i2c_client *client)
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
-       struct i2c_client       *client;
        int                     tmp;
        const struct chip_desc  *chip;
+       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
 
-       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
+       chip = find_chip(client->name);
+       if (!chip) {
+               dev_err(&client->dev, "unknown chip type '%s'\n",
+                               client->name);
+               return -ENODEV;
        }
 
-       /* REVISIT:  pending driver model conversion, set up "client"
-        * ourselves, and use a hack to determine the RTC type (instead
-        * of reading the client->name we're given)
-        */
-       client = &ds1307->dev;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &ds1307_driver;
-
-       /* HACK: "force" implies "needs ds1337-style-oscillator setup", and
-        * that's the only kind of chip setup we'll know about.  Until the
-        * driver model conversion, here's where to add any board-specific
-        * code to say what kind of chip is present...
-        */
-       if (kind >= 0)
-               chip = find_chip("ds1337");
-       else
-               chip = find_chip("ds1307");
-       strlcpy(client->name, chip->name, I2C_NAME_SIZE);
+       if (!i2c_check_functionality(adapter,
+                       I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return -EIO;
+
+       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+               return -ENOMEM;
 
        ds1307->client = client;
        i2c_set_clientdata(client, ds1307);
@@ -350,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. */
@@ -372,100 +429,127 @@ read_rtc:
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
                        i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
-                                       ds1307->regs[DS1337_REG_CONTROL]
+                                       ds1307->regs[DS1307_REG_CONTROL]
                                        & ~DS1338_BIT_OSF);
                        dev_warn(&client->dev, "SET TIME!\n");
                        goto read_rtc;
                }
                break;
-       default:
+       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;
        }
 
        tmp = ds1307->regs[DS1307_REG_SECS];
        tmp = BCD2BIN(tmp & 0x7f);
        if (tmp > 60)
-               goto exit_free;
+               goto exit_bad;
        tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
        if (tmp > 60)
-               goto exit_free;
+               goto exit_bad;
 
        tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
        if (tmp == 0 || tmp > 31)
-               goto exit_free;
+               goto exit_bad;
 
        tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
        if (tmp == 0 || tmp > 12)
-               goto exit_free;
+               goto exit_bad;
 
-       /* force into in 24 hour mode (most chips) or
-        * disable century bit (ds1340)
-        *
-        * REVISIT forcing 24 hour mode can prevent multi-master
-        * configs from sharing this RTC ... don't do this.
-        * The clock needs to be reset after changing it, too...
-        */
        tmp = ds1307->regs[DS1307_REG_HOUR];
-       if (tmp & (1 << 6)) {
-               if (tmp & (1 << 5))
-                       tmp = BCD2BIN(tmp & 0x1f) + 12;
-               else
-                       tmp = BCD2BIN(tmp);
+       switch (ds1307->type) {
+       case ds_1340:
+       case m41t00:
+               /* NOTE: ignores century bits; fix before deploying
+                * systems that will run through year 2100.
+                */
+               break;
+       default:
+               if (!(tmp & DS1307_BIT_12HR))
+                       break;
+
+               /* Be sure we're in 24 hour mode.  Multi-master systems
+                * take note...
+                */
+               tmp = BCD2BIN(tmp & 0x1f);
+               if (tmp == 12)
+                       tmp = 0;
+               if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
+                       tmp += 12;
                i2c_smbus_write_byte_data(client,
                                DS1307_REG_HOUR,
                                BIN2BCD(tmp));
        }
 
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(client)))
-               goto exit_free;
-
        ds1307->rtc = rtc_device_register(client->name, &client->dev,
                                &ds13xx_rtc_ops, THIS_MODULE);
        if (IS_ERR(ds1307->rtc)) {
                err = PTR_ERR(ds1307->rtc);
                dev_err(&client->dev,
                        "unable to register the class device\n");
-               goto exit_detach;
+               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_detach:
-       i2c_detach_client(client);
+exit_bad:
+       dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+                       "bogus register",
+                       ds1307->regs[0], ds1307->regs[1],
+                       ds1307->regs[2], ds1307->regs[3],
+                       ds1307->regs[4], ds1307->regs[5],
+                       ds1307->regs[6]);
+
 exit_free:
        kfree(ds1307);
-exit:
        return err;
 }
 
-static int __devinit
-ds1307_attach_adapter(struct i2c_adapter *adapter)
+static int __devexit ds1307_remove(struct i2c_client *client)
 {
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return 0;
-       return i2c_probe(adapter, &addr_data, ds1307_detect);
-}
-
-static int __devexit ds1307_detach_client(struct i2c_client *client)
-{
-       int             err;
        struct ds1307   *ds1307 = i2c_get_clientdata(client);
 
+       if (ds1307->has_nvram)
+               sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+
        rtc_device_unregister(ds1307->rtc);
-       if ((err = i2c_detach_client(client)))
-               return err;
        kfree(ds1307);
        return 0;
 }
 
 static struct i2c_driver ds1307_driver = {
        .driver = {
-               .name   = "ds1307",
+               .name   = "rtc-ds1307",
                .owner  = THIS_MODULE,
        },
-       .attach_adapter = ds1307_attach_adapter,
-       .detach_client  = __devexit_p(ds1307_detach_client),
+       .probe          = ds1307_probe,
+       .remove         = __devexit_p(ds1307_remove),
 };
 
 static int __init ds1307_init(void)