]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/rtc/rtc-ds1307.c
V4L/DVB (9079): gspca: Return error code from stream start functions.
[linux-2.6-omap-h63xx.git] / drivers / rtc / rtc-ds1307.c
index cc5032b6f42ac45c9aba4f0ff896b17585a6c813..bbf97e65202a24327b57beafbba98d6daca738a2 100644 (file)
  * setting the date and time), Linux can ignore the non-clock features.
  * That's a natural job for a factory or repair bench.
  *
- * 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.)
+ * 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...
  */
 enum ds_type {
-       unknown = 0,
-       ds_1307,                /* or ds1338, ... */
-       ds_1337,                /* or ds1339, ... */
-       ds_1340,                /* or st m41t00, ... */
+       ds_1307,
+       ds_1337,
+       ds_1338,
+       ds_1339,
+       ds_1340,
+       m41t00,
        // 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 */
 #      define DS1307_BIT_CH            0x80
+#      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 */
@@ -56,11 +56,12 @@ I2C_CLIENT_INSMOD;
 #define DS1307_REG_YEAR                0x06    /* 00-99 */
 
 /* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
- * start at 7, and they differ a lot. Only control and status matter for RTC;
- * be careful using them.
+ * start at 7, and they differ a LOT. Only control and status matter for
+ * basic RTC date and time functionality; be careful using them.
  */
-#define DS1307_REG_CONTROL     0x07
+#define DS1307_REG_CONTROL     0x07            /* or ds1338 */
 #      define DS1307_BIT_OUT           0x80
+#      define DS1338_BIT_OSF           0x20
 #      define DS1307_BIT_SQWE          0x10
 #      define DS1307_BIT_RS1           0x02
 #      define DS1307_BIT_RS0           0x01
@@ -71,6 +72,13 @@ I2C_CLIENT_INSMOD;
 #      define DS1337_BIT_INTCN         0x04
 #      define DS1337_BIT_A2IE          0x02
 #      define DS1337_BIT_A1IE          0x01
+#define DS1340_REG_CONTROL     0x07
+#      define DS1340_BIT_OUT           0x80
+#      define DS1340_BIT_FT            0x40
+#      define DS1340_BIT_CALIB_SIGN    0x20
+#      define DS1340_M_CALIBRATION     0x1f
+#define DS1340_REG_FLAG                0x09
+#      define DS1340_BIT_OSF           0x80
 #define DS1337_REG_STATUS      0x0f
 #      define DS1337_BIT_OSF           0x80
 #      define DS1337_BIT_A2I           0x02
@@ -81,24 +89,60 @@ I2C_CLIENT_INSMOD;
 
 struct ds1307 {
        u8                      reg_addr;
+       bool                    has_nvram;
        u8                      regs[8];
        enum ds_type            type;
        struct i2c_msg          msg[2];
-       struct i2c_client       client;
+       struct i2c_client       *client;
+       struct i2c_client       dev;
        struct rtc_device       *rtc;
 };
 
+struct chip_desc {
+       unsigned                nvram56:1;
+       unsigned                alarm:1;
+};
+
+static const struct chip_desc chips[] = {
+[ds_1307] = {
+       .nvram56        = 1,
+},
+[ds_1337] = {
+       .alarm          = 1,
+},
+[ds_1338] = {
+       .nvram56        = 1,
+},
+[ds_1339] = {
+       .alarm          = 1,
+},
+[ds_1340] = {
+},
+[m41t00] = {
+}, };
+
+static const struct i2c_device_id ds1307_id[] = {
+       { "ds1307", ds_1307 },
+       { "ds1337", ds_1337 },
+       { "ds1338", ds_1338 },
+       { "ds1339", ds_1339 },
+       { "ds1340", ds_1340 },
+       { "m41t00", m41t00 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
        int             tmp;
 
-       /* read the RTC registers all at once */
+       /* read the RTC date and time registers all at once */
        ds1307->msg[1].flags = I2C_M_RD;
        ds1307->msg[1].len = 7;
 
-       tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+       tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
+                       ds1307->msg, 2);
        if (tmp != 2) {
                dev_err(dev, "%s error %d\n", "read", tmp);
                return -EIO;
@@ -129,7 +173,8 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
                t->tm_hour, t->tm_mday,
                t->tm_mon, t->tm_year, t->tm_wday);
 
-       return 0;
+       /* initial clock setting can be undefined */
+       return rtc_valid_tm(t);
 }
 
 static int ds1307_set_time(struct device *dev, struct rtc_time *t)
@@ -141,9 +186,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
 
        dev_dbg(dev, "%s secs=%d, mins=%d, "
                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
-               "write", dt->tm_sec, dt->tm_min,
-               dt->tm_hour, dt->tm_mday,
-               dt->tm_mon, dt->tm_year, dt->tm_wday);
+               "write", t->tm_sec, t->tm_min,
+               t->tm_hour, t->tm_mday,
+               t->tm_mon, t->tm_year, t->tm_wday);
 
        *buf++ = 0;             /* first register addr */
        buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
@@ -157,11 +202,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
        tmp = t->tm_year - 100;
        buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
 
-       if (ds1307->type == ds_1337)
+       switch (ds1307->type) {
+       case ds_1337:
+       case ds_1339:
                buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
-       else if (ds1307->type == ds_1340)
+               break;
+       case ds_1340:
                buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
                                | DS1340_BIT_CENTURY;
+               break;
+       default:
+               break;
+       }
 
        ds1307->msg[1].flags = 0;
        ds1307->msg[1].len = 8;
@@ -170,7 +222,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                "write", buf[0], buf[1], buf[2], buf[3],
                buf[4], buf[5], buf[6]);
 
-       result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+       result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
+                       &ds1307->msg[1], 1);
        if (result != 1) {
                dev_err(dev, "%s error %d\n", "write", tmp);
                return -EIO;
@@ -183,27 +236,106 @@ 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,
+                                 const struct i2c_device_id *id)
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
-       struct i2c_client       *client;
        int                     tmp;
+       const struct chip_desc  *chip = &chips[id->driver_data];
+       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
 
-       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       if (!i2c_check_functionality(adapter,
+                       I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+               return -EIO;
 
-       client = &ds1307->client;
-       client->addr = address;
-       client->adapter = adapter;
-       client->driver = &ds1307_driver;
-       client->flags = 0;
+       if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+               return -ENOMEM;
 
+       ds1307->client = client;
        i2c_set_clientdata(client, ds1307);
 
        ds1307->msg[0].addr = client->addr;
@@ -216,14 +348,16 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
        ds1307->msg[1].len = sizeof(ds1307->regs);
        ds1307->msg[1].buf = ds1307->regs;
 
-       /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
-       if (kind >= 0) {
-               ds1307->type = ds_1337;
+       ds1307->type = id->driver_data;
 
+       switch (ds1307->type) {
+       case ds_1337:
+       case ds_1339:
                ds1307->reg_addr = DS1337_REG_CONTROL;
                ds1307->msg[1].len = 2;
 
-               tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+               /* get registers that the "rtc" read below won't read... */
+               tmp = i2c_transfer(adapter, ds1307->msg, 2);
                if (tmp != 2) {
                        pr_debug("read error %d\n", tmp);
                        err = -EIO;
@@ -233,19 +367,26 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
                ds1307->reg_addr = 0;
                ds1307->msg[1].len = sizeof(ds1307->regs);
 
-               /* oscillator is off; need to turn it on */
-               if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
-                               || (ds1307->regs[1] & DS1337_BIT_OSF)) {
-                       printk(KERN_ERR "no ds1337 oscillator code\n");
-                       goto exit_free;
+               /* oscillator off?  turn it on, so clock can tick. */
+               if (ds1307->regs[0] & DS1337_BIT_nEOSC)
+                       i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
+                               ds1307->regs[0] & ~DS1337_BIT_nEOSC);
+
+               /* oscillator fault?  clear flag, and warn */
+               if (ds1307->regs[1] & DS1337_BIT_OSF) {
+                       i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
+                               ds1307->regs[1] & ~DS1337_BIT_OSF);
+                       dev_warn(&client->dev, "SET TIME!\n");
                }
-       } else
-               ds1307->type = ds_1307;
+               break;
+       default:
+               break;
+       }
 
 read_rtc:
        /* read RTC registers */
 
-       tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+       tmp = i2c_transfer(adapter, ds1307->msg, 2);
        if (tmp != 2) {
                pr_debug("read error %d\n", tmp);
                err = -EIO;
@@ -257,72 +398,93 @@ read_rtc:
         * still a few values that are clearly out-of-range.
         */
        tmp = ds1307->regs[DS1307_REG_SECS];
-       if (tmp & DS1307_BIT_CH) {
-               if (ds1307->type && ds1307->type != ds_1307) {
-                       pr_debug("not a ds1307?\n");
+       switch (ds1307->type) {
+       case ds_1307:
+       case m41t00:
+               /* clock halted?  turn it on, so clock can tick. */
+               if (tmp & DS1307_BIT_CH) {
+                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+                       dev_warn(&client->dev, "SET TIME!\n");
+                       goto read_rtc;
+               }
+               break;
+       case ds_1338:
+               /* clock halted?  turn it on, so clock can tick. */
+               if (tmp & DS1307_BIT_CH)
+                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+               /* 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[DS1307_REG_CONTROL]
+                                       & ~DS1338_BIT_OSF);
+                       dev_warn(&client->dev, "SET TIME!\n");
+                       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;
                }
-               ds1307->type = ds_1307;
 
-               /* this partial initialization should work for ds1307,
-                * ds1338, ds1340, st m41t00, and more.
-                */
-               dev_warn(&client->dev, "oscillator started; SET TIME!\n");
-               i2c_smbus_write_byte_data(client, 0, 0);
-               goto read_rtc;
+               /* 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)
-        */
        tmp = ds1307->regs[DS1307_REG_HOUR];
-       if (tmp & (1 << 6)) {
-               if (tmp & (1 << 5))
-                       tmp = BCD2BIN(tmp & 0x1f) + 12;
-               else
-                       tmp = BCD2BIN(tmp);
-               i2c_smbus_write_byte_data(client,
-                               DS1307_REG_HOUR,
-                               BIN2BCD(tmp));
-       }
-
-       /* FIXME chips like 1337 can generate alarm irqs too; those are
-        * worth exposing through the API (especially when the irq is
-        * wakeup-capable).
-        */
-
        switch (ds1307->type) {
-       case unknown:
-               strlcpy(client->name, "unknown", I2C_NAME_SIZE);
-               break;
-       case ds_1307:
-               strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
-               break;
-       case ds_1337:
-               strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
-               break;
        case ds_1340:
-               strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+       case m41t00:
+               /* NOTE: ignores century bits; fix before deploying
+                * systems that will run through year 2100.
+                */
                break;
-       }
+       default:
+               if (!(tmp & DS1307_BIT_12HR))
+                       break;
 
-       /* Tell the I2C layer a new client has arrived */
-       if ((err = i2c_attach_client(client)))
-               goto exit_free;
+               /* 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));
+       }
 
        ds1307->rtc = rtc_device_register(client->name, &client->dev,
                                &ds13xx_rtc_ops, THIS_MODULE);
@@ -330,46 +492,52 @@ read_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)
-{
-       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)
+static int __devexit ds1307_remove(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),
+       .id_table       = ds1307_id,
 };
 
 static int __init ds1307_init(void)