Subject: [PATCH 2/3] I2C: at24: add kernel interface for reading/writing EEPROM Date: Monday 25 August 2008 From: Kevin Hilman To: davinci-linux-open-source@linux.davincidsp.com This patch adds an interface by which other kernel code can read/write detected EEPROM. 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 at24_iface and calls the setup callback. The platform code can then use the read/write functions in the at24_iface struct for reading and writing the EEPROM. Original idea, review and updates by David Brownell Signed-off-by: Kevin Hilman --- drivers/i2c/chips/at24.c | 42 +++++++++++++++++++++++++++++++++++------- include/linux/i2c/at24.h | 10 ++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) --- a/drivers/i2c/chips/at24.c +++ b/drivers/i2c/chips/at24.c @@ -53,6 +53,7 @@ struct at24_data { struct at24_platform_data chip; + struct at24_iface iface; bool use_smbus; /* @@ -264,13 +265,6 @@ static ssize_t at24_bin_read(struct kobj /* - * REVISIT: export at24_bin{read,write}() to let other kernel code use - * eeprom data. For example, it might hold a board's Ethernet address, or - * board-specific calibration data generated on the manufacturing floor. - */ - - -/* * Note that if the hardware write-protect pin is pulled high, the whole * chip is normally write protected. But there are plenty of product * variants here, including OTP fuses and partial chip protect. @@ -386,6 +380,30 @@ static ssize_t at24_bin_write(struct kob /*-------------------------------------------------------------------------*/ +/* + * This lets other kernel code access the eeprom data. For example, it + * might hold a board's Ethernet address, or board-specific calibration + * data generated on the manufacturing floor. + */ + +static ssize_t at24_iface_read(struct at24_iface *iface, char *buf, + off_t offset, size_t count) +{ + struct at24_data *at24 = container_of(iface, struct at24_data, iface); + + return at24_eeprom_read(at24, buf, offset, count); +} + +static ssize_t at24_iface_write(struct at24_iface *iface, char *buf, + off_t offset, size_t count) +{ + struct at24_data *at24 = container_of(iface, struct at24_data, iface); + + return at24_eeprom_write(at24, buf, offset, count); +} + +/*-------------------------------------------------------------------------*/ + static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct at24_platform_data chip; @@ -413,6 +431,9 @@ static int at24_probe(struct i2c_client * is recommended anyhow. */ chip.page_size = 1; + + chip.setup = NULL; + chip.context = NULL; } if (!is_power_of_2(chip.byte_len)) @@ -449,6 +470,9 @@ static int at24_probe(struct i2c_client goto err_out; } + at24->iface.read = at24_iface_read; + at24->iface.write = at24_iface_write; + mutex_init(&at24->lock); at24->use_smbus = use_smbus; at24->chip = chip; @@ -520,6 +544,10 @@ static int at24_probe(struct i2c_client at24->write_max, use_smbus ? ", use_smbus" : ""); + /* export data to kernel code */ + if (chip.setup) + chip.setup(&at24->iface, chip.context); + return 0; err_clients: --- a/include/linux/i2c/at24.h +++ b/include/linux/i2c/at24.h @@ -15,6 +15,13 @@ * is bigger than what the chip actually supports! */ +struct at24_iface { + ssize_t (*read)(struct at24_iface *, char *buf, off_t offset, + size_t count); + ssize_t (*write)(struct at24_iface *, char *buf, off_t offset, + size_t count); +}; + struct at24_platform_data { u32 byte_len; /* size (sum of all addr) */ u16 page_size; /* for writes */ @@ -23,6 +30,9 @@ struct at24_platform_data { #define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */ #define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */ #define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */ + + int (*setup)(struct at24_iface *, void *context); + void *context; }; #endif /* _LINUX_AT24_H */