diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 176 |
1 files changed, 124 insertions, 52 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 3f0f7b8fa81..75e30c6a7d5 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -24,15 +24,22 @@ * setting the date and time), Linux can ignore the non-clock features. * That's a natural job for a factory or repair bench. * + * 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, /* 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... }; @@ -56,11 +63,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_STOP 0x20 # define DS1307_BIT_SQWE 0x10 # define DS1307_BIT_RS1 0x02 # define DS1307_BIT_RS0 0x01 @@ -71,6 +79,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 DS1338_REG_FLAG 0x09 +# define DS1338_BIT_OSF 0x80 #define DS1337_REG_STATUS 0x0f # define DS1337_BIT_OSF 0x80 # define DS1337_BIT_A2I 0x02 @@ -84,21 +99,63 @@ struct ds1307 { 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 { + char name[9]; + unsigned nvram56:1; + unsigned alarm:1; + enum ds_type type; +}; + +static const struct chip_desc chips[] = { { + .name = "ds1307", + .type = ds_1307, + .nvram56 = 1, +}, { + .name = "ds1337", + .type = ds_1337, + .alarm = 1, +}, { + .name = "ds1338", + .type = ds_1338, + .nvram56 = 1, +}, { + .name = "ds1339", + .type = ds_1339, + .alarm = 1, +}, { + .name = "ds1340", + .type = ds_1340, +}, { + .name = "m41t00", + .type = m41t00, +}, }; + +static inline const struct chip_desc *find_chip(const char *s) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(chips); i++) + if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) + return &chips[i]; + return NULL; +} 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 +186,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) @@ -170,7 +228,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; @@ -192,18 +251,34 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) int err = -ENODEV; struct i2c_client *client; int tmp; + const struct chip_desc *chip; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) { err = -ENOMEM; goto exit; } - client = &ds1307->client; + /* 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; - client->flags = 0; + /* 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); + + ds1307->client = client; i2c_set_clientdata(client, ds1307); ds1307->msg[0].addr = client->addr; @@ -216,14 +291,17 @@ 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 = chip->type; + + switch (ds1307->type) { + case ds_1337: + case ds_1339: ds1307->type = ds_1337; ds1307->reg_addr = DS1337_REG_CONTROL; ds1307->msg[1].len = 2; - 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; @@ -236,16 +314,20 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind) /* 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"); +no_osc_start: + printk(KERN_ERR "no %s oscillator code\n", + chip->name); goto exit_free; } - } 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,20 +339,27 @@ 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"); - goto exit_free; + switch (ds1307->type) { + case ds_1307: + case ds_1338: + case m41t00: + if (tmp & DS1307_BIT_CH) { + i2c_smbus_write_byte_data(client, 0, 0); + dev_warn(&client->dev, + "oscillator started; SET TIME!\n"); + goto read_rtc; } - 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; + break; + case ds_1340: + /* FIXME write code to start the oscillator */ + if (tmp & DS1307_BIT_CH) + goto no_osc_start; + break; + default: + break; } + + tmp = ds1307->regs[DS1307_REG_SECS]; tmp = BCD2BIN(tmp & 0x7f); if (tmp > 60) goto exit_free; @@ -288,6 +377,9 @@ read_rtc: /* 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. */ tmp = ds1307->regs[DS1307_REG_HOUR]; if (tmp & (1 << 6)) { @@ -300,26 +392,6 @@ read_rtc: 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); - break; - } - /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(client))) goto exit_free; |