diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 182 |
1 files changed, 94 insertions, 88 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 62b0763b7b9a..cd188ab72f79 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -20,7 +20,8 @@ -/* We can't determine type by probing, but if we expect pre-Linux code +/* + * We can't determine type by probing, but if we expect pre-Linux code * to have set the chip up as a clock (turning on the oscillator and * setting the date and time), Linux can ignore the non-clock features. * That's a natural job for a factory or repair bench. @@ -36,7 +37,8 @@ enum ds_type { m41t00, mcp7941x, rx_8025, - // rs5c372 too? different address... + last_ds_type /* always last */ + /* rs5c372 too? different address... */ }; @@ -58,7 +60,8 @@ enum ds_type { # define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */ #define DS1307_REG_YEAR 0x06 /* 00-99 */ -/* Other registers (control, status, alarms, trickle charge, NVRAM, etc) +/* + * Other registers (control, status, alarms, trickle charge, NVRAM, etc) * start at 7, and they differ a LOT. Only control and status matter for * basic RTC date and time functionality; be careful using them. */ @@ -102,6 +105,8 @@ enum ds_type { struct ds1307 { u8 offset; /* register's offset */ u8 regs[11]; + u16 nvram_offset; + struct bin_attribute *nvram; enum ds_type type; unsigned long flags; #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ @@ -116,34 +121,35 @@ struct ds1307 { }; struct chip_desc { - unsigned nvram56:1; unsigned alarm:1; + u16 nvram_offset; + u16 nvram_size; }; -static const struct chip_desc chips[] = { -[ds_1307] = { - .nvram56 = 1, -}, -[ds_1337] = { - .alarm = 1, -}, -[ds_1338] = { - .nvram56 = 1, -}, -[ds_1339] = { - .alarm = 1, -}, -[ds_1340] = { -}, -[ds_3231] = { - .alarm = 1, -}, -[m41t00] = { -}, -[mcp7941x] = { -}, -[rx_8025] = { -}, }; +static const struct chip_desc chips[last_ds_type] = { + [ds_1307] = { + .nvram_offset = 8, + .nvram_size = 56, + }, + [ds_1337] = { + .alarm = 1, + }, + [ds_1338] = { + .nvram_offset = 8, + .nvram_size = 56, + }, + [ds_1339] = { + .alarm = 1, + }, + [ds_3231] = { + .alarm = 1, + }, + [mcp7941x] = { + /* this is battery backed SRAM */ + .nvram_offset = 0x20, + .nvram_size = 0x40, + }, +}; static const struct i2c_device_id ds1307_id[] = { { "ds1307", ds_1307 }, @@ -372,6 +378,11 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) | DS1340_BIT_CENTURY; break; case mcp7941x: + /* + * these bits were cleared when preparing the date/time + * values and need to be set again before writing the + * buffer out to the device. + */ buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST; buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN; break; @@ -417,7 +428,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) ds1307->regs[6], ds1307->regs[7], ds1307->regs[8]); - /* report alarm time (ALARM1); assume 24 hour and day-of-month modes, + /* + * report alarm time (ALARM1); assume 24 hour and day-of-month modes, * and that all four fields are checked matches */ t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f); @@ -445,7 +457,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); unsigned char *buf = ds1307->regs; u8 control, status; @@ -541,8 +553,6 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { /*----------------------------------------------------------------------*/ -#define NVRAM_SIZE 56 - static ssize_t ds1307_nvram_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, @@ -555,14 +565,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= NVRAM_SIZE)) + if (unlikely(off >= ds1307->nvram->size)) return 0; - if ((off + count) > NVRAM_SIZE) - count = NVRAM_SIZE - off; + if ((off + count) > ds1307->nvram->size) + count = ds1307->nvram->size - off; if (unlikely(!count)) return count; - result = ds1307->read_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, ds1307->nvram_offset + off, + count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -580,14 +591,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= NVRAM_SIZE)) + if (unlikely(off >= ds1307->nvram->size)) return -EFBIG; - if ((off + count) > NVRAM_SIZE) - count = NVRAM_SIZE - off; + if ((off + count) > ds1307->nvram->size) + count = ds1307->nvram->size - off; if (unlikely(!count)) return count; - result = ds1307->write_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, ds1307->nvram_offset + off, + count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -595,21 +607,8 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, return count; } -static struct bin_attribute nvram = { - .attr = { - .name = "nvram", - .mode = S_IRUGO | S_IWUSR, - }, - - .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, const struct i2c_device_id *id) { @@ -630,7 +629,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; - if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) + ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL); + if (!ds1307) return -ENOMEM; i2c_set_clientdata(client, ds1307); @@ -652,11 +652,6 @@ static int __devinit ds1307_probe(struct i2c_client *client, case ds_1337: case ds_1339: case ds_3231: - /* has IRQ? */ - if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, ds1307_work); - want_irq = true; - } /* get registers that the "rtc" read below won't read... */ tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); @@ -670,14 +665,19 @@ static int __devinit ds1307_probe(struct i2c_client *client, if (ds1307->regs[0] & DS1337_BIT_nEOSC) ds1307->regs[0] &= ~DS1337_BIT_nEOSC; - /* Using IRQ? Disable the square wave and both alarms. + /* + * Using IRQ? Disable the square wave and both alarms. * For some variants, be sure alarms can trigger when we're * running on Vbackup (BBSQI/BBSQW) */ - if (want_irq) { + if (ds1307->client->irq > 0 && chip->alarm) { + INIT_WORK(&ds1307->work, ds1307_work); + ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); + + want_irq = true; } i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, @@ -772,7 +772,8 @@ read_rtc: goto exit_free; } - /* minimal sanity checking; some chips (like DS1340) don't + /* + * minimal sanity checking; some chips (like DS1340) don't * specify the extra bits as must-be-zero, but there are * still a few values that are clearly out-of-range. */ @@ -836,11 +837,7 @@ read_rtc: } break; - case rx_8025: - case ds_1337: - case ds_1339: - case ds_1388: - case ds_3231: + default: break; } @@ -848,7 +845,8 @@ read_rtc: switch (ds1307->type) { case ds_1340: case m41t00: - /* NOTE: ignores century bits; fix before deploying + /* + * NOTE: ignores century bits; fix before deploying * systems that will run through year 2100. */ break; @@ -858,7 +856,8 @@ read_rtc: if (!(tmp & DS1307_BIT_12HR)) break; - /* Be sure we're in 24 hour mode. Multi-master systems + /* + * Be sure we're in 24 hour mode. Multi-master systems * take note... */ tmp = bcd2bin(tmp & 0x1f); @@ -894,16 +893,31 @@ read_rtc: dev_dbg(&client->dev, "got IRQ %d\n", client->irq); } - if (chip->nvram56) { - err = sysfs_create_bin_file(&client->dev.kobj, &nvram); - if (err == 0) { - set_bit(HAS_NVRAM, &ds1307->flags); - dev_info(&client->dev, "56 bytes nvram\n"); + if (chip->nvram_size) { + ds1307->nvram = kzalloc(sizeof(struct bin_attribute), + GFP_KERNEL); + if (!ds1307->nvram) { + err = -ENOMEM; + goto exit_nvram; + } + ds1307->nvram->attr.name = "nvram"; + ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; + ds1307->nvram->read = ds1307_nvram_read, + ds1307->nvram->write = ds1307_nvram_write, + ds1307->nvram->size = chip->nvram_size; + ds1307->nvram_offset = chip->nvram_offset; + err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); + if (err) { + kfree(ds1307->nvram); + goto exit_nvram; } + set_bit(HAS_NVRAM, &ds1307->flags); + dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size); } return 0; +exit_nvram: exit_irq: rtc_device_unregister(ds1307->rtc); exit_free: @@ -913,15 +927,17 @@ exit_free: static int __devexit ds1307_remove(struct i2c_client *client) { - struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct ds1307 *ds1307 = i2c_get_clientdata(client); if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) { free_irq(client->irq, client); cancel_work_sync(&ds1307->work); } - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) - sysfs_remove_bin_file(&client->dev.kobj, &nvram); + if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) { + sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); + kfree(ds1307->nvram); + } rtc_device_unregister(ds1307->rtc); kfree(ds1307); @@ -938,17 +954,7 @@ static struct i2c_driver ds1307_driver = { .id_table = ds1307_id, }; -static int __init ds1307_init(void) -{ - return i2c_add_driver(&ds1307_driver); -} -module_init(ds1307_init); - -static void __exit ds1307_exit(void) -{ - i2c_del_driver(&ds1307_driver); -} -module_exit(ds1307_exit); +module_i2c_driver(ds1307_driver); MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips"); MODULE_LICENSE("GPL"); |