diff options
Diffstat (limited to 'drivers/rtc/rtc-ds1307.c')
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index db6f3f0d8982..bc1c7fe94ad3 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c | |||
| @@ -89,6 +89,7 @@ enum ds_type { | |||
| 89 | 89 | ||
| 90 | struct ds1307 { | 90 | struct ds1307 { |
| 91 | u8 reg_addr; | 91 | u8 reg_addr; |
| 92 | bool has_nvram; | ||
| 92 | u8 regs[8]; | 93 | u8 regs[8]; |
| 93 | enum ds_type type; | 94 | enum ds_type type; |
| 94 | struct i2c_msg msg[2]; | 95 | struct i2c_msg msg[2]; |
| @@ -242,6 +243,87 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { | |||
| 242 | .set_time = ds1307_set_time, | 243 | .set_time = ds1307_set_time, |
| 243 | }; | 244 | }; |
| 244 | 245 | ||
| 246 | /*----------------------------------------------------------------------*/ | ||
| 247 | |||
| 248 | #define NVRAM_SIZE 56 | ||
| 249 | |||
| 250 | static ssize_t | ||
| 251 | ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, | ||
| 252 | char *buf, loff_t off, size_t count) | ||
| 253 | { | ||
| 254 | struct i2c_client *client; | ||
| 255 | struct ds1307 *ds1307; | ||
| 256 | struct i2c_msg msg[2]; | ||
| 257 | int result; | ||
| 258 | |||
| 259 | client = to_i2c_client(container_of(kobj, struct device, kobj)); | ||
| 260 | ds1307 = i2c_get_clientdata(client); | ||
| 261 | |||
| 262 | if (unlikely(off >= NVRAM_SIZE)) | ||
| 263 | return 0; | ||
| 264 | if ((off + count) > NVRAM_SIZE) | ||
| 265 | count = NVRAM_SIZE - off; | ||
| 266 | if (unlikely(!count)) | ||
| 267 | return count; | ||
| 268 | |||
| 269 | msg[0].addr = client->addr; | ||
| 270 | msg[0].flags = 0; | ||
| 271 | msg[0].len = 1; | ||
| 272 | msg[0].buf = buf; | ||
| 273 | |||
| 274 | buf[0] = 8 + off; | ||
| 275 | |||
| 276 | msg[1].addr = client->addr; | ||
| 277 | msg[1].flags = I2C_M_RD; | ||
| 278 | msg[1].len = count; | ||
| 279 | msg[1].buf = buf; | ||
| 280 | |||
| 281 | result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2); | ||
| 282 | if (result != 2) { | ||
| 283 | dev_err(&client->dev, "%s error %d\n", "nvram read", result); | ||
| 284 | return -EIO; | ||
| 285 | } | ||
| 286 | return count; | ||
| 287 | } | ||
| 288 | |||
| 289 | static ssize_t | ||
| 290 | ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, | ||
| 291 | char *buf, loff_t off, size_t count) | ||
| 292 | { | ||
| 293 | struct i2c_client *client; | ||
| 294 | u8 buffer[NVRAM_SIZE + 1]; | ||
| 295 | int ret; | ||
| 296 | |||
| 297 | client = to_i2c_client(container_of(kobj, struct device, kobj)); | ||
| 298 | |||
| 299 | if (unlikely(off >= NVRAM_SIZE)) | ||
| 300 | return -EFBIG; | ||
| 301 | if ((off + count) > NVRAM_SIZE) | ||
| 302 | count = NVRAM_SIZE - off; | ||
| 303 | if (unlikely(!count)) | ||
| 304 | return count; | ||
| 305 | |||
| 306 | buffer[0] = 8 + off; | ||
| 307 | memcpy(buffer + 1, buf, count); | ||
| 308 | |||
| 309 | ret = i2c_master_send(client, buffer, count + 1); | ||
| 310 | return (ret < 0) ? ret : (ret - 1); | ||
| 311 | } | ||
| 312 | |||
| 313 | static struct bin_attribute nvram = { | ||
| 314 | .attr = { | ||
| 315 | .name = "nvram", | ||
| 316 | .mode = S_IRUGO | S_IWUSR, | ||
| 317 | .owner = THIS_MODULE, | ||
| 318 | }, | ||
| 319 | |||
| 320 | .read = ds1307_nvram_read, | ||
| 321 | .write = ds1307_nvram_write, | ||
| 322 | .size = NVRAM_SIZE, | ||
| 323 | }; | ||
| 324 | |||
| 325 | /*----------------------------------------------------------------------*/ | ||
| 326 | |||
| 245 | static struct i2c_driver ds1307_driver; | 327 | static struct i2c_driver ds1307_driver; |
| 246 | 328 | ||
| 247 | static int __devinit ds1307_probe(struct i2c_client *client) | 329 | static int __devinit ds1307_probe(struct i2c_client *client) |
| @@ -413,6 +495,14 @@ read_rtc: | |||
| 413 | goto exit_free; | 495 | goto exit_free; |
| 414 | } | 496 | } |
| 415 | 497 | ||
| 498 | if (chip->nvram56) { | ||
| 499 | err = sysfs_create_bin_file(&client->dev.kobj, &nvram); | ||
| 500 | if (err == 0) { | ||
| 501 | ds1307->has_nvram = true; | ||
| 502 | dev_info(&client->dev, "56 bytes nvram\n"); | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 416 | return 0; | 506 | return 0; |
| 417 | 507 | ||
| 418 | exit_bad: | 508 | exit_bad: |
| @@ -432,6 +522,9 @@ static int __devexit ds1307_remove(struct i2c_client *client) | |||
| 432 | { | 522 | { |
| 433 | struct ds1307 *ds1307 = i2c_get_clientdata(client); | 523 | struct ds1307 *ds1307 = i2c_get_clientdata(client); |
| 434 | 524 | ||
| 525 | if (ds1307->has_nvram) | ||
| 526 | sysfs_remove_bin_file(&client->dev.kobj, &nvram); | ||
| 527 | |||
| 435 | rtc_device_unregister(ds1307->rtc); | 528 | rtc_device_unregister(ds1307->rtc); |
| 436 | kfree(ds1307); | 529 | kfree(ds1307); |
| 437 | return 0; | 530 | return 0; |
