From d4653bf946a5856a17342cd47c47d10b16b1cc22 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:29 +0200 Subject: i2c/eeprom: Only probe buses with DDC or SPD class The eeprom driver shouldn't probe i2c buses which don't want to be probed. Signed-off-by: Jean Delvare --- drivers/i2c/chips/eeprom.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 7dee001e5133..213a9f98decc 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -159,6 +159,8 @@ static struct bin_attribute eeprom_attr = { static int eeprom_attach_adapter(struct i2c_adapter *adapter) { + if (!(adapter->class & (I2C_CLASS_DDC | I2C_CLASS_SPD))) + return 0; return i2c_probe(adapter, &addr_data, eeprom_detect); } @@ -169,6 +171,12 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) struct eeprom_data *data; int err = 0; + /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all + addresses 0x50-0x57, but we only care about 0x50. So decline + attaching to addresses >= 0x51 on DDC buses */ + if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51) + goto exit; + /* There are three ways we can read the EEPROM data: (1) I2C block reads (faster, but unsupported by most adapters) (2) Consecutive byte reads (100% overhead) -- cgit v1.2.1 From 1b4dff9cd37d430bc76112396e92bb3552f37ccd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:29 +0200 Subject: i2c/eeprom: Fall back to SMBus read word transactions When I2C block reads are not supported by the underlying adapter, use SMBus read word transactions instead of consecutive byte reads. Reasons for this change are: * The consecutive byte read approach is not safe on multi-master buses. * While consecutive byte reads have less overhead if you only count the bytes on the bus, it takes more than twice as many transactions as with SMBus read word transactions, and each transaction has a cost: taking and releasing the adapter mutex, and for polling drivers, waiting for the transaction to complete. This change yields a significant performance boost at HZ=250 with EEPROMs on an Intel 82801 bus (basically twice as fast.) SMBus read word transactions are widely supported so I don't expect compatibility issues. Signed-off-by: Jean Delvare --- drivers/i2c/chips/eeprom.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 213a9f98decc..9a81252a7218 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -78,7 +78,7 @@ static struct i2c_driver eeprom_driver = { static void eeprom_update_client(struct i2c_client *client, u8 slice) { struct eeprom_data *data = i2c_get_clientdata(client); - int i, j; + int i; mutex_lock(&data->update_lock); @@ -93,15 +93,12 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) != 32) goto exit; } else { - if (i2c_smbus_write_byte(client, slice << 5)) { - dev_dbg(&client->dev, "eeprom read start has failed!\n"); - goto exit; - } - for (i = slice << 5; i < (slice + 1) << 5; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) + for (i = slice << 5; i < (slice + 1) << 5; i += 2) { + int word = i2c_smbus_read_word_data(client, i); + if (word < 0) goto exit; - data->data[i] = (u8) j; + data->data[i] = word & 0xff; + data->data[i + 1] = word >> 8; } } data->last_updated[slice] = jiffies; @@ -177,14 +174,15 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51) goto exit; - /* There are three ways we can read the EEPROM data: + /* There are four ways we can read the EEPROM data: (1) I2C block reads (faster, but unsupported by most adapters) - (2) Consecutive byte reads (100% overhead) - (3) Regular byte data reads (200% overhead) - The third method is not implemented by this driver because all - known adapters support at least the second. */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA - | I2C_FUNC_SMBUS_BYTE)) + (2) Word reads (128% overhead) + (3) Consecutive byte reads (88% overhead, unsafe) + (4) Regular byte data reads (265% overhead) + The third and fourth methods are not implemented by this driver + because all known adapters support one of the first two. */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) goto exit; if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { @@ -212,13 +210,14 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) /* Detect the Vaio nature of EEPROMs. We use the "PCG-" or "VGN-" prefix as the signature. */ - if (address == 0x57) { + if (address == 0x57 + && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { char name[4]; name[0] = i2c_smbus_read_byte_data(new_client, 0x80); - name[1] = i2c_smbus_read_byte(new_client); - name[2] = i2c_smbus_read_byte(new_client); - name[3] = i2c_smbus_read_byte(new_client); + name[1] = i2c_smbus_read_byte_data(new_client, 0x81); + name[2] = i2c_smbus_read_byte_data(new_client, 0x82); + name[3] = i2c_smbus_read_byte_data(new_client, 0x83); if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { dev_info(&new_client->dev, "Vaio EEPROM detected, " -- cgit v1.2.1 From 8a56ce1033073657572bd993595a56498baa4800 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 14 Jul 2008 22:38:31 +0200 Subject: i2c: Deprecate the legacy gpio drivers The legacy pcf8574 and pcf8575 drivers should be avoided on systems using the new gpiolib code, and generally deprecated in the same way the legacy pca9539 driver is deprecated. Also, correct the pca9539 deprecation to match the current name of the preferred driver: pca953x, supporting several more chips. Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- drivers/i2c/chips/Kconfig | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 2da2edfa68ec..6326468d5f0b 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -26,8 +26,8 @@ config SENSORS_EEPROM will be called eeprom. config SENSORS_PCF8574 - tristate "Philips PCF8574 and PCF8574A" - depends on EXPERIMENTAL + tristate "Philips PCF8574 and PCF8574A (DEPRECATED)" + depends on EXPERIMENTAL && GPIO_PCF857X = "n" default n help If you say yes here you get support for Philips PCF8574 and @@ -36,12 +36,16 @@ config SENSORS_PCF8574 This driver can also be built as a module. If so, the module will be called pcf8574. + This driver is deprecated and will be dropped soon. Use + drivers/gpio/pcf857x.c instead. + These devices are hard to detect and rarely found on mainstream hardware. If unsure, say N. config PCF8575 - tristate "Philips PCF8575" + tristate "Philips PCF8575 (DEPRECATED)" default n + depends on GPIO_PCF857X = "n" help If you say yes here you get support for Philips PCF8575 chip. This chip is a 16-bit I/O expander for the I2C bus. Several other @@ -50,12 +54,15 @@ config PCF8575 This driver can also be built as a module. If so, the module will be called pcf8575. + This driver is deprecated and will be dropped soon. Use + drivers/gpio/pcf857x.c instead. + This device is hard to detect and is rarely found on mainstream hardware. If unsure, say N. config SENSORS_PCA9539 tristate "Philips PCA9539 16-bit I/O port (DEPRECATED)" - depends on EXPERIMENTAL && GPIO_PCA9539 = "n" + depends on EXPERIMENTAL && GPIO_PCA953X = "n" help If you say yes here you get support for the Philips PCA9539 16-bit I/O port. @@ -64,7 +71,7 @@ config SENSORS_PCA9539 will be called pca9539. This driver is deprecated and will be dropped soon. Use - drivers/gpio/pca9539.c instead. + drivers/gpio/pca953x.c instead. config SENSORS_PCF8591 tristate "Philips PCF8591" -- cgit v1.2.1 From 954a99307f256f1badd751a2e128c09af235c317 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:34 +0200 Subject: i2c: Drop stray references to lm_sensors Signed-off-by: Jean Delvare --- drivers/i2c/chips/eeprom.c | 8 +------- drivers/i2c/chips/pcf8574.c | 2 -- drivers/i2c/chips/pcf8591.c | 2 -- 3 files changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 9a81252a7218..e22ec3b3aedf 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -1,15 +1,9 @@ /* - eeprom.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring Copyright (C) 1998, 1999 Frodo Looijaard and Philip Edelbrock Copyright (C) 2003 Greg Kroah-Hartman Copyright (C) 2003 IBM Corp. - - 2004-01-16 Jean Delvare - Divide the eeprom in 32-byte (arbitrary) slices. This significantly - speeds sensors up, as well as various scripts using the eeprom - module. + Copyright (C) 2004 Jean Delvare This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index e5b31329b56e..ad2f7901a8c9 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -1,6 +1,4 @@ /* - pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring Copyright (c) 2000 Frodo Looijaard , Philip Edelbrock , Dan Eaton diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 66c7c3bb9429..d3a24524817a 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -1,6 +1,4 @@ /* - pcf8591.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring Copyright (C) 2001-2004 Aurelien Jarno Ported to Linux 2.6 by Aurelien Jarno with the help of Jean Delvare -- cgit v1.2.1 From 2b7a5056a0a7ff17d5d2004c29c852a92a6bd632 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 14 Jul 2008 22:38:35 +0200 Subject: i2c: New-style EEPROM driver using device IDs Add a new-style driver for most I2C EEPROMs, giving sysfs read/write access to their data. Tested with various chips and clock rates. Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- drivers/i2c/chips/Kconfig | 26 ++ drivers/i2c/chips/Makefile | 1 + drivers/i2c/chips/at24.c | 583 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 610 insertions(+) create mode 100644 drivers/i2c/chips/at24.c (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 6326468d5f0b..50e0a4653741 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -14,6 +14,32 @@ config DS1682 This driver can also be built as a module. If so, the module will be called ds1682. +config AT24 + tristate "EEPROMs from most vendors" + depends on SYSFS && EXPERIMENTAL + help + Enable this driver to get read/write support to most I2C EEPROMs, + after you configure the driver to know about each EEPROM on + your target board. Use these generic chip names, instead of + vendor-specific ones like at24c64 or 24lc02: + + 24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08, + 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024 + + Unless you like data loss puzzles, always be sure that any chip + you configure as a 24c32 (32 kbit) or larger is NOT really a + 24c16 (16 kbit) or smaller, and vice versa. Marking the chip + as read-only won't help recover from this. Also, if your chip + has any software write-protect mechanism you may want to review the + code to make sure this driver won't turn it on by accident. + + If you use this with an SMBus adapter instead of an I2C adapter, + full functionality is not available. Only smaller devices are + supported (24c16 and below, max 4 kByte). + + This driver can also be built as a module. If so, the module + will be called at24. + config SENSORS_EEPROM tristate "EEPROM reader" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index e47aca0ca5ae..39e3e69ed125 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -10,6 +10,7 @@ # obj-$(CONFIG_DS1682) += ds1682.o +obj-$(CONFIG_AT24) += at24.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o diff --git a/drivers/i2c/chips/at24.c b/drivers/i2c/chips/at24.c new file mode 100644 index 000000000000..e764c94f3e3d --- /dev/null +++ b/drivers/i2c/chips/at24.c @@ -0,0 +1,583 @@ +/* + * at24.c - handle most I2C EEPROMs + * + * Copyright (C) 2005-2007 David Brownell + * Copyright (C) 2008 Wolfram Sang, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * I2C EEPROMs from most vendors are inexpensive and mostly interchangeable. + * Differences between different vendor product lines (like Atmel AT24C or + * MicroChip 24LC, etc) won't much matter for typical read/write access. + * There are also I2C RAM chips, likewise interchangeable. One example + * would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes). + * + * However, misconfiguration can lose data. "Set 16-bit memory address" + * to a part with 8-bit addressing will overwrite data. Writing with too + * big a page size also loses data. And it's not safe to assume that the + * conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC + * uses 0x51, for just one example. + * + * Accordingly, explicit board-specific configuration data should be used + * in almost all cases. (One partial exception is an SMBus used to access + * "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.) + * + * So this driver uses "new style" I2C driver binding, expecting to be + * told what devices exist. That may be in arch/X/mach-Y/board-Z.c or + * similar kernel-resident tables; or, configuration data coming from + * a bootloader. + * + * Other than binding model, current differences from "eeprom" driver are + * that this one handles write access and isn't restricted to 24c02 devices. + * It also handles larger devices (32 kbit and up) with two-byte addresses, + * which won't work on pure SMBus systems. + */ + +struct at24_data { + struct at24_platform_data chip; + bool use_smbus; + + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + struct bin_attribute bin; + + u8 *writebuf; + unsigned write_max; + unsigned num_addresses; + + /* + * Some chips tie up multiple I2C addresses; dummy devices reserve + * them for us, and we'll use them with SMBus calls. + */ + struct i2c_client *client[]; +}; + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +static unsigned io_limit = 128; +module_param(io_limit, uint, 0); +MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)"); + +/* + * Specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned write_timeout = 25; +module_param(write_timeout, uint, 0); +MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)"); + +#define AT24_SIZE_BYTELEN 5 +#define AT24_SIZE_FLAGS 8 + +#define AT24_BITMASK(x) (BIT(x) - 1) + +/* create non-zero magic value for given eeprom parameters */ +#define AT24_DEVICE_MAGIC(_len, _flags) \ + ((1 << AT24_SIZE_FLAGS | (_flags)) \ + << AT24_SIZE_BYTELEN | ilog2(_len)) + +static const struct i2c_device_id at24_ids[] = { + /* needs 8 addresses as A0-A2 are ignored */ + { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) }, + /* old variants can't be handled with this generic entry! */ + { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) }, + { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) }, + /* spd is a 24c02 in memory DIMMs */ + { "spd", AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, + { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, + /* 24rf08 quirk is handled at i2c-core */ + { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, + { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, + { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) }, + { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) }, + { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) }, + { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) }, + { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) }, + { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) }, + { "at24", 0 }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(i2c, at24_ids); + +/*-------------------------------------------------------------------------*/ + +/* + * This routine supports chips which consume multiple I2C addresses. It + * computes the addressing information to be used for a given r/w request. + * Assumes that sanity checks for offset happened at sysfs-layer. + */ +static struct i2c_client *at24_translate_offset(struct at24_data *at24, + unsigned *offset) +{ + unsigned i; + + if (at24->chip.flags & AT24_FLAG_ADDR16) { + i = *offset >> 16; + *offset &= 0xffff; + } else { + i = *offset >> 8; + *offset &= 0xff; + } + + return at24->client[i]; +} + +static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, + unsigned offset, size_t count) +{ + struct i2c_msg msg[2]; + u8 msgbuf[2]; + struct i2c_client *client; + int status, i; + + memset(msg, 0, sizeof(msg)); + + /* + * REVISIT some multi-address chips don't rollover page reads to + * the next slave address, so we may need to truncate the count. + * Those chips might need another quirk flag. + * + * If the real hardware used four adjacent 24c02 chips and that + * were misconfigured as one 24c08, that would be a similar effect: + * one "eeprom" file not four, but larger reads would fail when + * they crossed certain pages. + */ + + /* + * Slave address and byte offset derive from the offset. Always + * set the byte address; on a multi-master board, another master + * may have changed the chip's "current" address pointer. + */ + client = at24_translate_offset(at24, &offset); + + if (count > io_limit) + count = io_limit; + + /* Smaller eeproms can work given some SMBus extension calls */ + if (at24->use_smbus) { + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + status = i2c_smbus_read_i2c_block_data(client, offset, + count, buf); + dev_dbg(&client->dev, "smbus read %zd@%d --> %d\n", + count, offset, status); + return (status < 0) ? -EIO : status; + } + + /* + * When we have a better choice than SMBus calls, use a combined + * I2C message. Write address; then read up to io_limit data bytes. + * Note that read page rollover helps us here (unlike writes). + * msgbuf is u8 and will cast to our needs. + */ + i = 0; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msgbuf[i++] = offset >> 8; + msgbuf[i++] = offset; + + msg[0].addr = client->addr; + msg[0].buf = msgbuf; + msg[0].len = i; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + + status = i2c_transfer(client->adapter, msg, 2); + dev_dbg(&client->dev, "i2c read %zd@%d --> %d\n", + count, offset, status); + + if (status == 2) + return count; + else if (status >= 0) + return -EIO; + else + return status; +} + +static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct at24_data *at24; + ssize_t retval = 0; + + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + if (unlikely(!count)) + return count; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + ssize_t status; + + status = at24_eeprom_read(at24, buf, off, count); + if (status <= 0) { + if (retval == 0) + retval = status; + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&at24->lock); + + return retval; +} + + +/* + * 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. + * + * We only use page mode writes; the alternative is sloooow. This routine + * writes at most one page. + */ +static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf, + unsigned offset, size_t count) +{ + struct i2c_client *client; + struct i2c_msg msg; + ssize_t status; + unsigned long timeout, write_time; + unsigned next_page; + + /* Get corresponding I2C address and adjust offset */ + client = at24_translate_offset(at24, &offset); + + /* write_max is at most a page */ + if (count > at24->write_max) + count = at24->write_max; + + /* Never roll over backwards, to the start of this page */ + next_page = roundup(offset + 1, at24->chip.page_size); + if (offset + count > next_page) + count = next_page - offset; + + /* If we'll use I2C calls for I/O, set up the message */ + if (!at24->use_smbus) { + int i = 0; + + msg.addr = client->addr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = at24->writebuf; + if (at24->chip.flags & AT24_FLAG_ADDR16) + msg.buf[i++] = offset >> 8; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + } + + /* + * Writes fail if the previous one didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + if (at24->use_smbus) { + status = i2c_smbus_write_i2c_block_data(client, + offset, count, buf); + if (status == 0) + status = count; + } else { + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + } + dev_dbg(&client->dev, "write %zd@%d --> %zd (%ld)\n", + count, offset, status, jiffies); + + if (status == count) + return count; + + /* REVISIT: at HZ=100, this is sloooow */ + msleep(1); + } while (time_before(write_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct at24_data *at24; + ssize_t retval = 0; + + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + if (unlikely(!count)) + return count; + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&at24->lock); + + while (count) { + ssize_t status; + + status = at24_eeprom_write(at24, buf, off, count); + if (status <= 0) { + if (retval == 0) + retval = status; + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&at24->lock); + + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct at24_platform_data chip; + bool writable; + bool use_smbus = false; + struct at24_data *at24; + int err; + unsigned i, num_addresses; + kernel_ulong_t magic; + + if (client->dev.platform_data) { + chip = *(struct at24_platform_data *)client->dev.platform_data; + } else { + if (!id->driver_data) { + err = -ENODEV; + goto err_out; + } + magic = id->driver_data; + chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN)); + magic >>= AT24_SIZE_BYTELEN; + chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS); + /* + * This is slow, but we can't know all eeproms, so we better + * play safe. Specifying custom eeprom-types via platform_data + * is recommended anyhow. + */ + chip.page_size = 1; + } + + if (!is_power_of_2(chip.byte_len)) + dev_warn(&client->dev, + "byte_len looks suspicious (no power of 2)!\n"); + if (!is_power_of_2(chip.page_size)) + dev_warn(&client->dev, + "page_size looks suspicious (no power of 2)!\n"); + + /* Use I2C operations unless we're stuck with SMBus extensions. */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + if (chip.flags & AT24_FLAG_ADDR16) { + err = -EPFNOSUPPORT; + goto err_out; + } + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + err = -EPFNOSUPPORT; + goto err_out; + } + use_smbus = true; + } + + if (chip.flags & AT24_FLAG_TAKE8ADDR) + num_addresses = 8; + else + num_addresses = DIV_ROUND_UP(chip.byte_len, + (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256); + + at24 = kzalloc(sizeof(struct at24_data) + + num_addresses * sizeof(struct i2c_client *), GFP_KERNEL); + if (!at24) { + err = -ENOMEM; + goto err_out; + } + + mutex_init(&at24->lock); + at24->use_smbus = use_smbus; + at24->chip = chip; + at24->num_addresses = num_addresses; + + /* + * Export the EEPROM bytes through sysfs, since that's convenient. + * By default, only root should see the data (maybe passwords etc) + */ + at24->bin.attr.name = "eeprom"; + at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR; + at24->bin.attr.owner = THIS_MODULE; + at24->bin.read = at24_bin_read; + at24->bin.size = chip.byte_len; + + writable = !(chip.flags & AT24_FLAG_READONLY); + if (writable) { + if (!use_smbus || i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + + unsigned write_max = chip.page_size; + + at24->bin.write = at24_bin_write; + at24->bin.attr.mode |= S_IWUSR; + + if (write_max > io_limit) + write_max = io_limit; + if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) + write_max = I2C_SMBUS_BLOCK_MAX; + at24->write_max = write_max; + + /* buffer (data + address at the beginning) */ + at24->writebuf = kmalloc(write_max + 2, GFP_KERNEL); + if (!at24->writebuf) { + err = -ENOMEM; + goto err_struct; + } + } else { + dev_warn(&client->dev, + "cannot write due to controller restrictions."); + } + } + + at24->client[0] = client; + + /* use dummy devices for multiple-address chips */ + for (i = 1; i < num_addresses; i++) { + at24->client[i] = i2c_new_dummy(client->adapter, + client->addr + i); + if (!at24->client[i]) { + dev_err(&client->dev, "address 0x%02x unavailable\n", + client->addr + i); + err = -EADDRINUSE; + goto err_clients; + } + } + + err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin); + if (err) + goto err_clients; + + i2c_set_clientdata(client, at24); + + dev_info(&client->dev, "%Zd byte %s EEPROM %s\n", + at24->bin.size, client->name, + writable ? "(writable)" : "(read-only)"); + dev_dbg(&client->dev, + "page_size %d, num_addresses %d, write_max %d%s\n", + chip.page_size, num_addresses, + at24->write_max, + use_smbus ? ", use_smbus" : ""); + + return 0; + +err_clients: + for (i = 1; i < num_addresses; i++) + if (at24->client[i]) + i2c_unregister_device(at24->client[i]); + + kfree(at24->writebuf); +err_struct: + kfree(at24); +err_out: + dev_dbg(&client->dev, "probe error %d\n", err); + return err; +} + +static int __devexit at24_remove(struct i2c_client *client) +{ + struct at24_data *at24; + int i; + + at24 = i2c_get_clientdata(client); + sysfs_remove_bin_file(&client->dev.kobj, &at24->bin); + + for (i = 1; i < at24->num_addresses; i++) + i2c_unregister_device(at24->client[i]); + + kfree(at24->writebuf); + kfree(at24); + i2c_set_clientdata(client, NULL); + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct i2c_driver at24_driver = { + .driver = { + .name = "at24", + .owner = THIS_MODULE, + }, + .probe = at24_probe, + .remove = __devexit_p(at24_remove), + .id_table = at24_ids, +}; + +static int __init at24_init(void) +{ + io_limit = rounddown_pow_of_two(io_limit); + return i2c_add_driver(&at24_driver); +} +module_init(at24_init); + +static void __exit at24_exit(void) +{ + i2c_del_driver(&at24_driver); +} +module_exit(at24_exit); + +MODULE_DESCRIPTION("Driver for most I2C EEPROMs"); +MODULE_AUTHOR("David Brownell and Wolfram Sang"); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From f741f673298b03b92d46e30b0b6fd0e960423665 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Jul 2008 22:38:36 +0200 Subject: i2c: Clean up old chip drivers Clean up old i2c chip drivers: * Name the i2c_client "client" instead of "new_client". * Drop useless initializations to 0. Signed-off-by: Jean Delvare --- drivers/i2c/chips/eeprom.c | 32 +++++++++++++++----------------- drivers/i2c/chips/max6875.c | 4 +--- drivers/i2c/chips/pca9539.c | 25 ++++++++++++------------- drivers/i2c/chips/pcf8574.c | 23 +++++++++++------------ drivers/i2c/chips/pcf8591.c | 31 +++++++++++++++---------------- 5 files changed, 54 insertions(+), 61 deletions(-) (limited to 'drivers/i2c/chips') diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index e22ec3b3aedf..373ea8d8fe8f 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -158,7 +158,7 @@ static int eeprom_attach_adapter(struct i2c_adapter *adapter) /* This function is called by i2c_probe */ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct eeprom_data *data; int err = 0; @@ -184,22 +184,20 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; + client = &data->client; memset(data->data, 0xff, EEPROM_SIZE); - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &eeprom_driver; - new_client->flags = 0; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &eeprom_driver; /* Fill in the remaining client fields */ - strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, "eeprom", I2C_NAME_SIZE); mutex_init(&data->update_lock); data->nature = UNKNOWN; /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_kfree; /* Detect the Vaio nature of EEPROMs. @@ -208,27 +206,27 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { char name[4]; - name[0] = i2c_smbus_read_byte_data(new_client, 0x80); - name[1] = i2c_smbus_read_byte_data(new_client, 0x81); - name[2] = i2c_smbus_read_byte_data(new_client, 0x82); - name[3] = i2c_smbus_read_byte_data(new_client, 0x83); + name[0] = i2c_smbus_read_byte_data(client, 0x80); + name[1] = i2c_smbus_read_byte_data(client, 0x81); + name[2] = i2c_smbus_read_byte_data(client, 0x82); + name[3] = i2c_smbus_read_byte_data(client, 0x83); if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { - dev_info(&new_client->dev, "Vaio EEPROM detected, " + dev_info(&client->dev, "Vaio EEPROM detected, " "enabling privacy protection\n"); data->nature = VAIO; } } /* create the sysfs eeprom file */ - err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); + err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); if (err) goto exit_detach; return 0; exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_kfree: kfree(data); exit: diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index cf507b3f60f3..5a0285d8b6f9 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -170,7 +170,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *real_client; struct i2c_client *fake_client; struct max6875_data *data; - int err = 0; + int err; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_BYTE)) @@ -195,7 +195,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) real_client->addr = address; real_client->adapter = adapter; real_client->driver = &max6875_driver; - real_client->flags = 0; strlcpy(real_client->name, "max6875", I2C_NAME_SIZE); mutex_init(&data->update_lock); @@ -204,7 +203,6 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind) fake_client->addr = address | 1; fake_client->adapter = adapter; fake_client->driver = &max6875_driver; - fake_client->flags = 0; strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE); if ((err = i2c_attach_client(real_client)) != 0) diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c index f43c4e79b55e..58ab7f26be26 100644 --- a/drivers/i2c/chips/pca9539.c +++ b/drivers/i2c/chips/pca9539.c @@ -113,7 +113,7 @@ static int pca9539_attach_adapter(struct i2c_adapter *adapter) /* This function is called by i2c_probe */ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct pca9539_data *data; int err = 0; @@ -127,29 +127,28 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &pca9539_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &pca9539_driver; if (kind < 0) { /* Detection: the pca9539 only has 8 registers (0-7). A read of 7 should succeed, but a read of 8 should fail. */ - if ((i2c_smbus_read_byte_data(new_client, 7) < 0) || - (i2c_smbus_read_byte_data(new_client, 8) >= 0)) + if ((i2c_smbus_read_byte_data(client, 7) < 0) || + (i2c_smbus_read_byte_data(client, 8) >= 0)) goto exit_kfree; } - strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE); + strlcpy(client->name, "pca9539", I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_kfree; /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, + err = sysfs_create_group(&client->dev.kobj, &pca9539_defattr_group); if (err) goto exit_detach; @@ -157,7 +156,7 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_kfree: kfree(data); exit: diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index ad2f7901a8c9..1b3db2b3ada9 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -127,7 +127,7 @@ static int pcf8574_attach_adapter(struct i2c_adapter *adapter) /* This function is called by i2c_probe */ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct pcf8574_data *data; int err = 0; const char *client_name = ""; @@ -142,12 +142,11 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &pcf8574_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &pcf8574_driver; /* Now, we would do the remaining detection. But the PCF8574 is plainly impossible to detect! Stupid chip. */ @@ -166,23 +165,23 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) client_name = "pcf8574"; /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + strlcpy(client->name, client_name, I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_free; /* Initialize the PCF8574 chip */ - pcf8574_init_client(new_client); + pcf8574_init_client(client); /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group); + err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group); if (err) goto exit_detach; return 0; exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index d3a24524817a..db735379f22f 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -188,7 +188,7 @@ static int pcf8591_attach_adapter(struct i2c_adapter *adapter) /* This function is called by i2c_probe */ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct pcf8591_data *data; int err = 0; @@ -203,12 +203,11 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &pcf8591_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &pcf8591_driver; /* Now, we would do the remaining detection. But the PCF8591 is plainly impossible to detect! Stupid chip. */ @@ -219,31 +218,31 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, "pcf8591", I2C_NAME_SIZE); + strlcpy(client->name, "pcf8591", I2C_NAME_SIZE); mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto exit_kfree; /* Initialize the PCF8591 chip */ - pcf8591_init_client(new_client); + pcf8591_init_client(client); /* Register sysfs hooks */ - err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group); + err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); if (err) goto exit_detach; /* Register input2 if not in "two differential inputs" mode */ if (input_mode != 3) { - if ((err = device_create_file(&new_client->dev, + if ((err = device_create_file(&client->dev, &dev_attr_in2_input))) goto exit_sysfs_remove; } /* Register input3 only in "four single ended inputs" mode */ if (input_mode == 0) { - if ((err = device_create_file(&new_client->dev, + if ((err = device_create_file(&client->dev, &dev_attr_in3_input))) goto exit_sysfs_remove; } @@ -251,10 +250,10 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_sysfs_remove: - sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt); - sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group); + sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); + sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_kfree: kfree(data); exit: -- cgit v1.2.1