Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kevin Hilman and committed by
Linus Torvalds
7274ec8b 06c421ee

+58 -13
+54 -13
drivers/misc/eeprom/at24.c
··· 53 53 54 54 struct at24_data { 55 55 struct at24_platform_data chip; 56 + struct memory_accessor macc; 56 57 bool use_smbus; 57 58 58 59 /* ··· 226 225 return status; 227 226 } 228 227 229 - static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, 228 + static ssize_t at24_read(struct at24_data *at24, 230 229 char *buf, loff_t off, size_t count) 231 230 { 232 - struct at24_data *at24; 233 231 ssize_t retval = 0; 234 - 235 - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); 236 232 237 233 if (unlikely(!count)) 238 234 return count; ··· 260 262 return retval; 261 263 } 262 264 265 + static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, 266 + char *buf, loff_t off, size_t count) 267 + { 268 + struct at24_data *at24; 263 269 264 - /* 265 - * REVISIT: export at24_bin{read,write}() to let other kernel code use 266 - * eeprom data. For example, it might hold a board's Ethernet address, or 267 - * board-specific calibration data generated on the manufacturing floor. 268 - */ 270 + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); 271 + return at24_read(at24, buf, off, count); 272 + } 269 273 270 274 271 275 /* ··· 347 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 351 char *buf, loff_t off, size_t count) 352 352 { 353 - struct at24_data *at24; 354 353 ssize_t retval = 0; 355 - 356 - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); 357 354 358 355 if (unlikely(!count)) 359 356 return count; ··· 379 382 mutex_unlock(&at24->lock); 380 383 381 384 return retval; 385 + } 386 + 387 + static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, 388 + char *buf, loff_t off, size_t count) 389 + { 390 + struct at24_data *at24; 391 + 392 + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); 393 + return at24_write(at24, buf, off, count); 394 + } 395 + 396 + /*-------------------------------------------------------------------------*/ 397 + 398 + /* 399 + * This lets other kernel code access the eeprom data. For example, it 400 + * might hold a board's Ethernet address, or board-specific calibration 401 + * data generated on the manufacturing floor. 402 + */ 403 + 404 + static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf, 405 + off_t offset, size_t count) 406 + { 407 + struct at24_data *at24 = container_of(macc, struct at24_data, macc); 408 + 409 + return at24_read(at24, buf, offset, count); 410 + } 411 + 412 + static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf, 413 + off_t offset, size_t count) 414 + { 415 + struct at24_data *at24 = container_of(macc, struct at24_data, macc); 416 + 417 + return at24_write(at24, buf, offset, count); 382 418 } 383 419 384 420 /*-------------------------------------------------------------------------*/ ··· 443 413 * is recommended anyhow. 444 414 */ 445 415 chip.page_size = 1; 416 + 417 + chip.setup = NULL; 418 + chip.context = NULL; 446 419 } 447 420 448 421 if (!is_power_of_2(chip.byte_len)) ··· 496 463 at24->bin.read = at24_bin_read; 497 464 at24->bin.size = chip.byte_len; 498 465 466 + at24->macc.read = at24_macc_read; 467 + 499 468 writable = !(chip.flags & AT24_FLAG_READONLY); 500 469 if (writable) { 501 470 if (!use_smbus || i2c_check_functionality(client->adapter, 502 471 I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { 503 472 504 473 unsigned write_max = chip.page_size; 474 + 475 + at24->macc.write = at24_macc_write; 505 476 506 477 at24->bin.write = at24_bin_write; 507 478 at24->bin.attr.mode |= S_IWUSR; ··· 556 519 chip.page_size, num_addresses, 557 520 at24->write_max, 558 521 use_smbus ? ", use_smbus" : ""); 522 + 523 + /* export data to kernel code */ 524 + if (chip.setup) 525 + chip.setup(&at24->macc, chip.context); 559 526 560 527 return 0; 561 528
+4
include/linux/i2c/at24.h
··· 2 2 #define _LINUX_AT24_H 3 3 4 4 #include <linux/types.h> 5 + #include <linux/memory.h> 5 6 6 7 /* 7 8 * As seen through Linux I2C, differences between the most common types of I2C ··· 24 23 #define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ 25 24 #define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ 26 25 #define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ 26 + 27 + void (*setup)(struct memory_accessor *, void *context); 28 + void *context; 27 29 }; 28 30 29 31 #endif /* _LINUX_AT24_H */