diff options
| author | Kevin Hilman <khilman@deeprootsystems.com> | 2009-04-02 19:56:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-02 22:04:50 -0400 |
| commit | 7274ec8bd71e99018642f474528ea7de4bb3ae25 (patch) | |
| tree | 3c2e719f696292afa0717f7111d174bdfc073f27 | |
| parent | 06c421ee0d5af95c8c6749ca0ba620cd5010707f (diff) | |
memory_accessor: implement the new memory_accessor interface for I2C EEPROM
In the case of at24, the platform code registers a 'setup' callback with
the at24_platform_data. When the at24 driver detects an EEPROM, it fills
out the read and write functions of the memory_accessor and calls the
setup callback passing the memory_accessor struct. The platform code can
then use the read/write functions in the memory_accessor struct for
reading and writing the EEPROM.
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/misc/eeprom/at24.c | 67 | ||||
| -rw-r--r-- | include/linux/i2c/at24.h | 4 |
2 files changed, 58 insertions, 13 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index d4775528abc6..d184dfab9631 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | 53 | ||
| 54 | struct at24_data { | 54 | struct at24_data { |
| 55 | struct at24_platform_data chip; | 55 | struct at24_platform_data chip; |
| 56 | struct memory_accessor macc; | ||
| 56 | bool use_smbus; | 57 | bool use_smbus; |
| 57 | 58 | ||
| 58 | /* | 59 | /* |
| @@ -225,14 +226,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, | |||
| 225 | return status; | 226 | return status; |
| 226 | } | 227 | } |
| 227 | 228 | ||
| 228 | static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | 229 | static ssize_t at24_read(struct at24_data *at24, |
| 229 | char *buf, loff_t off, size_t count) | 230 | char *buf, loff_t off, size_t count) |
| 230 | { | 231 | { |
| 231 | struct at24_data *at24; | ||
| 232 | ssize_t retval = 0; | 232 | ssize_t retval = 0; |
| 233 | 233 | ||
| 234 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
| 235 | |||
| 236 | if (unlikely(!count)) | 234 | if (unlikely(!count)) |
| 237 | return count; | 235 | return count; |
| 238 | 236 | ||
| @@ -262,12 +260,14 @@ static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | |||
| 262 | return retval; | 260 | return retval; |
| 263 | } | 261 | } |
| 264 | 262 | ||
| 263 | static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | ||
| 264 | char *buf, loff_t off, size_t count) | ||
| 265 | { | ||
| 266 | struct at24_data *at24; | ||
| 265 | 267 | ||
| 266 | /* | 268 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); |
| 267 | * REVISIT: export at24_bin{read,write}() to let other kernel code use | 269 | return at24_read(at24, buf, off, count); |
| 268 | * eeprom data. For example, it might hold a board's Ethernet address, or | 270 | } |
| 269 | * board-specific calibration data generated on the manufacturing floor. | ||
| 270 | */ | ||
| 271 | 271 | ||
| 272 | 272 | ||
| 273 | /* | 273 | /* |
| @@ -347,14 +347,11 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf, | |||
| 347 | return -ETIMEDOUT; | 347 | return -ETIMEDOUT; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | 350 | static ssize_t at24_write(struct at24_data *at24, |
| 351 | char *buf, loff_t off, size_t count) | 351 | char *buf, loff_t off, size_t count) |
| 352 | { | 352 | { |
| 353 | struct at24_data *at24; | ||
| 354 | ssize_t retval = 0; | 353 | ssize_t retval = 0; |
| 355 | 354 | ||
| 356 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
| 357 | |||
| 358 | if (unlikely(!count)) | 355 | if (unlikely(!count)) |
| 359 | return count; | 356 | return count; |
| 360 | 357 | ||
| @@ -384,6 +381,39 @@ static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | |||
| 384 | return retval; | 381 | return retval; |
| 385 | } | 382 | } |
| 386 | 383 | ||
| 384 | static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | ||
| 385 | char *buf, loff_t off, size_t count) | ||
| 386 | { | ||
| 387 | struct at24_data *at24; | ||
| 388 | |||
| 389 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
| 390 | return at24_write(at24, buf, off, count); | ||
| 391 | } | ||
| 392 | |||
| 393 | /*-------------------------------------------------------------------------*/ | ||
| 394 | |||
| 395 | /* | ||
| 396 | * This lets other kernel code access the eeprom data. For example, it | ||
| 397 | * might hold a board's Ethernet address, or board-specific calibration | ||
| 398 | * data generated on the manufacturing floor. | ||
| 399 | */ | ||
| 400 | |||
| 401 | static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf, | ||
| 402 | off_t offset, size_t count) | ||
| 403 | { | ||
| 404 | struct at24_data *at24 = container_of(macc, struct at24_data, macc); | ||
| 405 | |||
| 406 | return at24_read(at24, buf, offset, count); | ||
| 407 | } | ||
| 408 | |||
| 409 | static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf, | ||
| 410 | off_t offset, size_t count) | ||
| 411 | { | ||
| 412 | struct at24_data *at24 = container_of(macc, struct at24_data, macc); | ||
| 413 | |||
| 414 | return at24_write(at24, buf, offset, count); | ||
| 415 | } | ||
| 416 | |||
| 387 | /*-------------------------------------------------------------------------*/ | 417 | /*-------------------------------------------------------------------------*/ |
| 388 | 418 | ||
| 389 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | 419 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| @@ -413,6 +443,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 413 | * is recommended anyhow. | 443 | * is recommended anyhow. |
| 414 | */ | 444 | */ |
| 415 | chip.page_size = 1; | 445 | chip.page_size = 1; |
| 446 | |||
| 447 | chip.setup = NULL; | ||
| 448 | chip.context = NULL; | ||
| 416 | } | 449 | } |
| 417 | 450 | ||
| 418 | if (!is_power_of_2(chip.byte_len)) | 451 | if (!is_power_of_2(chip.byte_len)) |
| @@ -463,6 +496,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 463 | at24->bin.read = at24_bin_read; | 496 | at24->bin.read = at24_bin_read; |
| 464 | at24->bin.size = chip.byte_len; | 497 | at24->bin.size = chip.byte_len; |
| 465 | 498 | ||
| 499 | at24->macc.read = at24_macc_read; | ||
| 500 | |||
| 466 | writable = !(chip.flags & AT24_FLAG_READONLY); | 501 | writable = !(chip.flags & AT24_FLAG_READONLY); |
| 467 | if (writable) { | 502 | if (writable) { |
| 468 | if (!use_smbus || i2c_check_functionality(client->adapter, | 503 | if (!use_smbus || i2c_check_functionality(client->adapter, |
| @@ -470,6 +505,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 470 | 505 | ||
| 471 | unsigned write_max = chip.page_size; | 506 | unsigned write_max = chip.page_size; |
| 472 | 507 | ||
| 508 | at24->macc.write = at24_macc_write; | ||
| 509 | |||
| 473 | at24->bin.write = at24_bin_write; | 510 | at24->bin.write = at24_bin_write; |
| 474 | at24->bin.attr.mode |= S_IWUSR; | 511 | at24->bin.attr.mode |= S_IWUSR; |
| 475 | 512 | ||
| @@ -520,6 +557,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
| 520 | at24->write_max, | 557 | at24->write_max, |
| 521 | use_smbus ? ", use_smbus" : ""); | 558 | use_smbus ? ", use_smbus" : ""); |
| 522 | 559 | ||
| 560 | /* export data to kernel code */ | ||
| 561 | if (chip.setup) | ||
| 562 | chip.setup(&at24->macc, chip.context); | ||
| 563 | |||
| 523 | return 0; | 564 | return 0; |
| 524 | 565 | ||
| 525 | err_clients: | 566 | err_clients: |
diff --git a/include/linux/i2c/at24.h b/include/linux/i2c/at24.h index f6edd522a929..8ace93024d60 100644 --- a/include/linux/i2c/at24.h +++ b/include/linux/i2c/at24.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define _LINUX_AT24_H | 2 | #define _LINUX_AT24_H |
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <linux/memory.h> | ||
| 5 | 6 | ||
| 6 | /* | 7 | /* |
| 7 | * As seen through Linux I2C, differences between the most common types of I2C | 8 | * As seen through Linux I2C, differences between the most common types of I2C |
| @@ -23,6 +24,9 @@ struct at24_platform_data { | |||
| 23 | #define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ | 24 | #define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ |
| 24 | #define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ | 25 | #define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ |
| 25 | #define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ | 26 | #define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ |
| 27 | |||
| 28 | void (*setup)(struct memory_accessor *, void *context); | ||
| 29 | void *context; | ||
| 26 | }; | 30 | }; |
| 27 | 31 | ||
| 28 | #endif /* _LINUX_AT24_H */ | 32 | #endif /* _LINUX_AT24_H */ |
