From d64f73be1b59b9556de0a8fbd4f1a003c6a45a5c Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 12 Jul 2007 14:12:28 +0200 Subject: i2c: Add kernel documentation Generate I2C kerneldoc; fix various glitches and add "context" sections to that documentation. Most I2C and SMBus functions still have no kerneldoc. Let me suggest providing kerneldoc for all the i2c_smbus_*() functions as a small and mostly self-contained project for anyone so inclined. :) Signed-off-by: David Brownell Signed-off-by: Jean Delvare --- Documentation/DocBook/kernel-api.tmpl | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 8c5698a8c2e..46bcff2849b 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -643,6 +643,60 @@ X!Idrivers/video/console/fonts.c !Edrivers/spi/spi.c + + I<superscript>2</superscript>C and SMBus Subsystem + + + I2C (or without fancy typography, "I2C") + is an acronym for the "Inter-IC" bus, a simple bus protocol which is + widely used where low data rate communications suffice. + Since it's also a licensed trademark, some vendors use another + name (such as "Two-Wire Interface", TWI) for the same bus. + I2C only needs two signals (SCL for clock, SDA for data), conserving + board real estate and minimizing signal quality issues. + Most I2C devices use seven bit addresses, and bus speeds of up + to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet + found wide use. + I2C is a multi-master bus; open drain signaling is used to + arbitrate between masters, as well as to handshake and to + synchronize clocks from slower clients. + + + + The Linux I2C programming interfaces support only the master + side of bus interactions, not the slave side. + The programming interface is structured around two kinds of driver, + and two kinds of device. + An I2C "Adapter Driver" abstracts the controller hardware; it binds + to a physical device (perhaps a PCI device or platform_device) and + exposes a struct i2c_adapter representing + each I2C bus segment it manages. + On each I2C bus segment will be I2C devices represented by a + struct i2c_client. Those devices will + be bound to a struct i2c_driver, + which should follow the standard Linux driver model. + (At this writing, a legacy model is more widely used.) + There are functions to perform various I2C protocol operations; at + this writing all such functions are usable only from task context. + + + + The System Management Bus (SMBus) is a sibling protocol. Most SMBus + systems are also I2C conformant. The electrical constraints are + tighter for SMBus, and it standardizes particular protocol messages + and idioms. Controllers that support I2C can also support most + SMBus operations, but SMBus controllers don't support all the protocol + options that an I2C controller will. + There are functions to perform various SMBus protocol operations, + either using I2C primitives or by issuing SMBus commands to + i2c_adapter devices which don't support those I2C operations. + + +!Iinclude/linux/i2c.h +!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info +!Edrivers/i2c/i2c-core.c + + splice API ) @@ -654,4 +708,5 @@ X!Idrivers/video/console/fonts.c !Ffs/splice.c + -- cgit v1.2.3-70-g09d2 From 890e037509f5b3f967b16ea0ea525c7c75b213ae Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2007 14:12:28 +0200 Subject: i2c: Delete outdated x1205 driver documentation The x1205 driver moved to the RTC subsystem and was significantly modified since then, so just delete the outdated documentation. Signed-off-by: Jean Delvare Cc: Alessandro Zummo --- Documentation/i2c/chips/x1205 | 38 -------------------------------------- drivers/rtc/rtc-x1205.c | 5 ++++- 2 files changed, 4 insertions(+), 39 deletions(-) delete mode 100644 Documentation/i2c/chips/x1205 (limited to 'Documentation') diff --git a/Documentation/i2c/chips/x1205 b/Documentation/i2c/chips/x1205 deleted file mode 100644 index 09407c991fe..00000000000 --- a/Documentation/i2c/chips/x1205 +++ /dev/null @@ -1,38 +0,0 @@ -Kernel driver x1205 -=================== - -Supported chips: - * Xicor X1205 RTC - Prefix: 'x1205' - Addresses scanned: none - Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html - -Authors: - Karen Spearel , - Alessandro Zummo - -Description ------------ - -This module aims to provide complete access to the Xicor X1205 RTC. -Recently Xicor has merged with Intersil, but the chip is -still sold under the Xicor brand. - -This chip is located at address 0x6f and uses a 2-byte register addressing. -Two bytes need to be written to read a single register, while most -other chips just require one and take the second one as the data -to be written. To prevent corrupting unknown chips, the user must -explicitely set the probe parameter. - -example: - -modprobe x1205 probe=0,0x6f - -The module supports one more option, hctosys, which is used to set the -software clock from the x1205. On systems where the x1205 is the -only hardware rtc, this parameter could be used to achieve a correct -date/time earlier in the system boot sequence. - -example: - -modprobe x1205 probe=0,0x6f hctosys=1 diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 513d1a611aa..b3fae357ca4 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -9,6 +9,9 @@ * * based on a lot of other RTC drivers. * + * Information and datasheet: + * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -26,7 +29,7 @@ * Two bytes need to be written to read a single register, * while most other chips just require one and take the second * one as the data to be written. To prevent corrupting - * unknown chips, the user must explicitely set the probe parameter. + * unknown chips, the user must explicitly set the probe parameter. */ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; -- cgit v1.2.3-70-g09d2 From ba7fbb723f50ab2607989a282af655fb0fab0492 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2007 14:12:29 +0200 Subject: i2c: Deprecate legacy RTC drivers We have a new RTC subsystem with better drivers. Legacy driver status: * ds1337: The DS1337 and DS1339 are now supported by the rtc-ds1307 driver, so it looks to me like we could even delete the ds1337 driver right away. * ds1374: Will soon be replaced with Scott Wood's rtc-ds1374 driver. * m41t00: The M41T00 is supported by the rtc-ds1307 driver. For the M41T81 and M41T85, the rtc-m41t80 driver written by Atsushi Nemoto should work. Signed-off-by: Jean Delvare Cc: Alessandro Zummo Acked-by: Mark A. Greer Acked-by: James Chapman Cc: Randy Vinson --- Documentation/feature-removal-schedule.txt | 7 +++++++ drivers/i2c/chips/Kconfig | 15 ++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3a159dac04f..281458b47d7 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -330,3 +330,10 @@ Who: Tejun Heo --------------------------- +What: Legacy RTC drivers (under drivers/i2c/chips) +When: November 2007 +Why: Obsolete. We have a RTC subsystem with better drivers. +Who: Jean Delvare + +--------------------------- + diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index ea085a006ea..8113ce201e4 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -5,7 +5,7 @@ menu "Miscellaneous I2C Chip support" config SENSORS_DS1337 - tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" + tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)" depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor @@ -14,8 +14,11 @@ config SENSORS_DS1337 This driver can also be built as a module. If so, the module will be called ds1337. + This driver is deprecated and will be dropped soon. Use + rtc-ds1307 instead. + config SENSORS_DS1374 - tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" + tristate "Dallas DS1374 Real Time Clock (DEPRECATED)" depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor @@ -24,6 +27,9 @@ config SENSORS_DS1374 This driver can also be built as a module. If so, the module will be called ds1374. + This driver is deprecated and will be dropped soon. Use + rtc-ds1374 instead. + config SENSORS_EEPROM tristate "EEPROM reader" depends on EXPERIMENTAL @@ -101,7 +107,7 @@ config TPS65010 will be called tps65010. config SENSORS_M41T00 - tristate "ST M41T00 RTC chip" + tristate "ST M41T00 RTC chip (DEPRECATED)" depends on PPC32 help If you say yes here you get support for the ST M41T00 RTC chip. @@ -109,6 +115,9 @@ config SENSORS_M41T00 This driver can also be built as a module. If so, the module will be called m41t00. + This driver is deprecated and will be dropped soon. Use + rtc-ds1307 or rtc-m41t80 instead. + config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" depends on EXPERIMENTAL -- cgit v1.2.3-70-g09d2 From 4b2643d7d9bdcd776749e17f73c168ddf02e93cb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2007 14:12:29 +0200 Subject: i2c: Fix the i2c_smbus_read_i2c_block_data() prototype Let the drivers specify how many bytes they want to read with i2c_smbus_read_i2c_block_data(). So far, the block count was hard-coded to I2C_SMBUS_BLOCK_MAX (32), which did not make much sense. Many driver authors complained about this before, and I believe it's about time to fix it. Right now, authors have to do technically stupid things, such as individual byte reads or full-fledged I2C messaging, to work around the problem. We do not want to encourage that. I even found that some bus drivers (e.g. i2c-amd8111) already implemented I2C block read the "right" way, that is, they didn't follow the old, broken standard. The fact that it was never noticed before just shows how little i2c_smbus_read_i2c_block_data() was used, which isn't that surprising given how broken its prototype was so far. There are some obvious compatiblity considerations: * This changes the i2c_smbus_read_i2c_block_data() prototype. Users outside the kernel tree will notice at compilation time, and will have to update their code. * User-space has access to i2c_smbus_xfer() directly using i2c-dev, so the changed expectations would affect tools such as i2cdump. In order to preserve binary compatibility, we give I2C_SMBUS_I2C_BLOCK_DATA a new numeric value, and define I2C_SMBUS_I2C_BLOCK_BROKEN with the old numeric value. When i2c-dev receives a transaction with the old value, it can convert it to the new format on the fly. Signed-off-by: Jean Delvare --- Documentation/i2c/chips/max6875 | 2 +- Documentation/i2c/writing-clients | 2 +- drivers/i2c/busses/i2c-powermac.c | 3 +-- drivers/i2c/busses/i2c-viapro.c | 2 +- drivers/i2c/busses/scx200_acb.c | 2 -- drivers/i2c/chips/eeprom.c | 6 ++++-- drivers/i2c/chips/max6875.c | 1 + drivers/i2c/i2c-core.c | 12 +++++++----- drivers/i2c/i2c-dev.c | 9 +++++++++ drivers/macintosh/windfarm_smu_sat.c | 28 ++++------------------------ include/linux/i2c.h | 5 +++-- 11 files changed, 32 insertions(+), 40 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875 index 96fec562a8e..a0cd8af2f40 100644 --- a/Documentation/i2c/chips/max6875 +++ b/Documentation/i2c/chips/max6875 @@ -99,7 +99,7 @@ And then read the data or - count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer); + count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer); The block read should read 16 bytes. 0x84 is the block read command. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 3d8d36b0ad1..2c170032bf3 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -571,7 +571,7 @@ SMBus communication u8 command, u8 length, u8 *values); extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, - u8 command, u8 *values); + u8 command, u8 length, u8 *values); These ones were removed in Linux 2.6.10 because they had no users, but could be added back later if needed: diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 1425d2245c8..0ab4f2627c2 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -121,8 +121,7 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, if (rc) goto bail; rc = pmac_i2c_xfer(bus, addrdir, 1, command, - read ? data->block : &data->block[1], - data->block[0]); + &data->block[1], data->block[0]); break; default: diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 7a2bc06304f..a0f7e4a303b 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -235,7 +235,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, if (!(vt596_features & FEATURE_I2CBLOCK)) goto exit_unsupported; if (read_write == I2C_SMBUS_READ) - outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); + outb_p(data->block[0], SMBHSTDAT0); /* Fall through */ case I2C_SMBUS_BLOCK_DATA: outb_p(command, SMBHSTCMD); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index dc64f8b6b24..e6c4a2b762e 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -310,8 +310,6 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter, break; case I2C_SMBUS_I2C_BLOCK_DATA: - if (rw == I2C_SMBUS_READ) - data->block[0] = I2C_SMBUS_BLOCK_MAX; /* For now */ len = data->block[0]; if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) return -EINVAL; diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index bfce13c8f1f..48f857ae874 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -88,8 +88,10 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX) - if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX) + for (i = slice << 5; i < (slice + 1) << 5; i += 32) + if (i2c_smbus_read_i2c_block_data(client, i, + 32, data->data + i) + != 32) goto exit; } else { if (i2c_smbus_write_byte(client, slice << 5)) { diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 76645c14297..e9e9e5171b5 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -106,6 +106,7 @@ static void max6875_update_slice(struct i2c_client *client, int slice) I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { if (i2c_smbus_read_i2c_block_data(client, MAX6875_CMD_BLK_READ, + SLICE_SIZE, buf) != SLICE_SIZE) { goto exit_up; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index cccfa867824..6971a62397d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1344,10 +1344,14 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, EXPORT_SYMBOL(i2c_smbus_write_block_data); /* Returns the number of read bytes */ -s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) +s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) { union i2c_smbus_data data; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + data.block[0] = length; if (i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_READ,command, I2C_SMBUS_I2C_BLOCK_DATA,&data)) @@ -1468,7 +1472,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - msg[1].len = I2C_SMBUS_BLOCK_MAX; + msg[1].len = data->block[0]; } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { @@ -1524,9 +1528,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; case I2C_SMBUS_I2C_BLOCK_DATA: - /* fixed at 32 for now */ - data->block[0] = I2C_SMBUS_BLOCK_MAX; - for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) + for (i = 0; i < data->block[0]; i++) data->block[i+1] = msgbuf1[i]; break; case I2C_SMBUS_BLOCK_DATA: diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index e7a70971059..64eee9551b2 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -283,6 +283,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, (data_arg.size != I2C_SMBUS_WORD_DATA) && (data_arg.size != I2C_SMBUS_PROC_CALL) && (data_arg.size != I2C_SMBUS_BLOCK_DATA) && + (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { dev_dbg(&client->adapter->dev, @@ -329,10 +330,18 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file, if ((data_arg.size == I2C_SMBUS_PROC_CALL) || (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || + (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || (data_arg.read_write == I2C_SMBUS_WRITE)) { if (copy_from_user(&temp, data_arg.data, datasize)) return -EFAULT; } + if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { + /* Convert old I2C block commands to the new + convention. This preserves binary compatibility. */ + data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; + if (data_arg.read_write == I2C_SMBUS_READ) + temp.block[0] = I2C_SMBUS_BLOCK_MAX; + } res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, data_arg.read_write, data_arg.command,data_arg.size,&temp); diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 1043b39aa12..351982bcec1 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c @@ -67,26 +67,6 @@ static struct i2c_driver wf_sat_driver = { .detach_client = wf_sat_detach, }; -/* - * XXX i2c_smbus_read_i2c_block_data doesn't pass the requested - * length down to the low-level driver, so we use this, which - * works well enough with the SMU i2c driver code... - */ -static int sat_read_block(struct i2c_client *client, u8 command, - u8 *values, int len) -{ - union i2c_smbus_data data; - int err; - - data.block[0] = len; - err = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA, - &data); - if (!err) - memcpy(values, data.block, len); - return err; -} - struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, unsigned int *size) { @@ -124,8 +104,8 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, return NULL; for (i = 0; i < len; i += 4) { - err = sat_read_block(&sat->i2c, 0xa, data, 4); - if (err) { + err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data); + if (err < 0) { printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", err); goto fail; @@ -157,8 +137,8 @@ static int wf_sat_read_cache(struct wf_sat *sat) { int err; - err = sat_read_block(&sat->i2c, 0x3f, sat->cache, 16); - if (err) + err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache); + if (err < 0) return err; sat->last_read = jiffies; #ifdef LOTSA_DEBUG diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 44f2ecf47d9..2eaba21b9b1 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -90,7 +90,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, const u8 *values); /* Returns the number of read bytes */ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, - u8 command, u8 *values); + u8 command, u8 length, u8 *values); extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, u8 command, u8 length, const u8 *values); @@ -524,8 +524,9 @@ union i2c_smbus_data { #define I2C_SMBUS_WORD_DATA 3 #define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_BLOCK_DATA 5 -#define I2C_SMBUS_I2C_BLOCK_DATA 6 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 /* ----- commands for the ioctl like i2c_command call: -- cgit v1.2.3-70-g09d2 From c29c22218b99dad95f7cd0281415a854aeee805c Mon Sep 17 00:00:00 2001 From: Henry Su Date: Thu, 12 Jul 2007 14:12:29 +0200 Subject: i2c-piix4: Add support for the ATI SB700 Add the SMBus device ID for ATI SB700. Signed-off-by: Henry Su Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-piix4 | 2 +- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-piix4.c | 4 +++- include/linux/pci_ids.h | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index 7cbe43fa270..fa0c786a8bf 100644 --- a/Documentation/i2c/busses/i2c-piix4 +++ b/Documentation/i2c/busses/i2c-piix4 @@ -6,7 +6,7 @@ Supported adapters: Datasheet: Publicly available at the Intel website * ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges Datasheet: Only available via NDA from ServerWorks - * ATI IXP200, IXP300, IXP400 and SB600 southbridges + * ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges Datasheet: Not publicly available * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge Datasheet: Publicly available at the SMSC website http://www.smsc.com diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 838dc1c19d6..165c1266fff 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -207,6 +207,7 @@ config I2C_PIIX4 ATI IXP300 ATI IXP400 ATI SB600 + ATI SB700 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 5a52bf5e3fb..debc76cd216 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -23,7 +23,7 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000 - ATI IXP200, IXP300, IXP400, SB600 + ATI IXP200, IXP300, IXP400, SB600, SB700 SMSC Victory66 Note: we assume there can only be one device, with one SMBus interface. @@ -399,6 +399,8 @@ static struct pci_device_id piix4_ids[] = { .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS), .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS), + .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 75c4d4d0689..8300001e907 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -371,6 +371,7 @@ #define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385 #define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c #define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 +#define PCI_DEVICE_ID_ATI_IXP700_SMBUS 0x4395 #define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c #define PCI_VENDOR_ID_VLSI 0x1004 -- cgit v1.2.3-70-g09d2 From 7edcb9abb594a8f3b4ca756e03d01c870aeae127 Mon Sep 17 00:00:00 2001 From: Oleg Ryjkov Date: Thu, 12 Jul 2007 14:12:31 +0200 Subject: i2c-i801: Use the internal 32-byte buffer on ICH4+ Add an ability to utilize the internal SRAM buffer on ICH4 and newer host controllers to speed up execution of block operations. I've split the code so that it is more clear which block transaction is performed. First of all the host controller's type is identified. isich4 is set when we think that the controller has the internal buffer. Then, before every block transaction, if isich4 is set, we attempt to enable the E32B bit in SMBAUXCTL register. Signed-off-by: Oleg Ryjkov Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-i801 | 4 +- drivers/i2c/busses/i2c-i801.c | 151 +++++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 53 deletions(-) (limited to 'Documentation') diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index c34f0db78a3..fe6406f2f9a 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -5,8 +5,8 @@ Supported adapters: '810' and '810E' chipsets) * Intel 82801BA (ICH2 - part of the '815E' chipset) * Intel 82801CA/CAM (ICH3) - * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported) - * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported) + * Intel 82801DB (ICH4) (HW PEC supported) + * Intel 82801EB/ER (ICH5) (HW PEC supported) * Intel 6300ESB * Intel 82801FB/FR/FW/FRW (ICH6) * Intel 82801G (ICH7) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index d5e12a4f01b..8f5c686123b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -26,8 +26,8 @@ 82801AB 2423 82801BA 2443 82801CA/CAM 2483 - 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) - 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) + 82801DB 24C3 (HW PEC supported) + 82801EB 24D3 (HW PEC supported) 6300ESB 25A4 ICH6 266A ICH7 27DA @@ -114,7 +114,7 @@ static struct pci_driver i801_driver; static struct pci_dev *I801_dev; static int isich4; -static int i801_transaction(void) +static int i801_transaction(int xact) { int temp; int result = 0; @@ -139,7 +139,9 @@ static int i801_transaction(void) } } - outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); + /* the current contents of SMBHSTCNT can be overwritten, since PEC, + * INTREN, SMBSCMD are passed in xact */ + outb_p(xact | I801_START, SMBHSTCNT); /* We will always wait for a fraction of a second! */ do { @@ -207,44 +209,52 @@ static void i801_wait_hwpec(void) outb_p(temp, SMBHSTSTS); } -/* All-inclusive block transaction function */ -static int i801_block_transaction(union i2c_smbus_data *data, char read_write, - int command, int hwpec) +static int i801_block_transaction_by_block(union i2c_smbus_data *data, + char read_write, int hwpec) +{ + int i, len; + + inb_p(SMBHSTCNT); /* reset the data buffer index */ + + /* Use 32-byte buffer to process this transaction */ + if (read_write == I2C_SMBUS_WRITE) { + len = data->block[0]; + outb_p(len, SMBHSTDAT0); + for (i = 0; i < len; i++) + outb_p(data->block[i+1], SMBBLKDAT); + } + + if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 | + I801_PEC_EN * hwpec)) + return -1; + + if (read_write == I2C_SMBUS_READ) { + len = inb_p(SMBHSTDAT0); + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -1; + + data->block[0] = len; + for (i = 0; i < len; i++) + data->block[i + 1] = inb_p(SMBBLKDAT); + } + return 0; +} + +static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, + char read_write, int hwpec) { int i, len; int smbcmd; int temp; int result = 0; int timeout; - unsigned char hostc, errmask; + unsigned char errmask; - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(I801_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else { - dev_err(&I801_dev->dev, - "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); - return -1; - } - } + len = data->block[0]; if (read_write == I2C_SMBUS_WRITE) { - len = data->block[0]; - if (len < 1) - len = 1; - if (len > 32) - len = 32; outb_p(len, SMBHSTDAT0); outb_p(data->block[1], SMBBLKDAT); - } else { - len = 32; /* max for reads */ - } - - if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) { - /* set 32 byte buffer */ } for (i = 1; i <= len; i++) { @@ -277,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) { dev_err(&I801_dev->dev, "Reset failed! (%02x)\n", temp); - result = -1; - goto END; + return -1; } - if (i != 1) { + if (i != 1) /* if die in middle of block transaction, fail */ - result = -1; - goto END; - } + return -1; } if (i == 1) @@ -326,10 +333,8 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, if (i == 1 && read_write == I2C_SMBUS_READ) { len = inb_p(SMBHSTDAT0); - if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { - result = -1; - goto END; - } + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) + return -1; data->block[0] = len; } @@ -352,14 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); if (result < 0) - goto END; + return result; } + return result; +} - if (hwpec) +static int i801_set_block_buffer_mode(void) +{ + outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL); + if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0) + return -1; + return 0; +} + +/* Block transaction function */ +static int i801_block_transaction(union i2c_smbus_data *data, char read_write, + int command, int hwpec) +{ + int result = 0; + unsigned char hostc; + + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(I801_dev, SMBHSTCFG, + hostc | SMBHSTCFG_I2C_EN); + } else { + dev_err(&I801_dev->dev, + "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + return -1; + } + } + + if (read_write == I2C_SMBUS_WRITE) { + if (data->block[0] < 1) + data->block[0] = 1; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + } else { + data->block[0] = 32; /* max for reads */ + } + + if (isich4 && i801_set_block_buffer_mode() == 0 ) + result = i801_block_transaction_by_block(data, read_write, + hwpec); + else + result = i801_block_transaction_byte_by_byte(data, read_write, + hwpec); + + if (result == 0 && hwpec) i801_wait_hwpec(); - result = 0; -END: if (command == I2C_SMBUS_I2C_BLOCK_DATA) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); @@ -431,15 +480,15 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, if(block) ret = i801_block_transaction(data, read_write, size, hwpec); - else { - outb_p(xact | ENABLE_INT9, SMBHSTCNT); - ret = i801_transaction(); - } + else + ret = i801_transaction(xact | ENABLE_INT9); /* Some BIOSes don't like it when PEC is enabled at reboot or resume - time, so we forcibly disable it after every transaction. */ + time, so we forcibly disable it after every transaction. Turn off + E32B for the same reason. */ if (hwpec) - outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); + outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), + SMBAUXCTL); if(block) return ret; -- cgit v1.2.3-70-g09d2 From b9cdad74883a797952de52464d118d685cafc05a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2007 14:12:31 +0200 Subject: i2c: New bus driver for the TAOS evaluation modules This is a new I2C bus driver for the TAOS evaluation modules. Developped and tested on the TAOS TSL2550 EVM. Signed-off-by: Jean Delvare --- Documentation/i2c/busses/i2c-taos-evm | 46 +++++ drivers/i2c/busses/Kconfig | 16 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-taos-evm.c | 330 ++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 5 files changed, 394 insertions(+) create mode 100644 Documentation/i2c/busses/i2c-taos-evm create mode 100644 drivers/i2c/busses/i2c-taos-evm.c (limited to 'Documentation') diff --git a/Documentation/i2c/busses/i2c-taos-evm b/Documentation/i2c/busses/i2c-taos-evm new file mode 100644 index 00000000000..9146e33be6d --- /dev/null +++ b/Documentation/i2c/busses/i2c-taos-evm @@ -0,0 +1,46 @@ +Kernel driver i2c-taos-evm + +Author: Jean Delvare + +This is a driver for the evaluation modules for TAOS I2C/SMBus chips. +The modules include an SMBus master with limited capabilities, which can +be controlled over the serial port. Virtually all evaluation modules +are supported, but a few lines of code need to be added for each new +module to instantiate the right I2C chip on the bus. Obviously, a driver +for the chip in question is also needed. + +Currently supported devices are: + +* TAOS TSL2550 EVM + +For addtional information on TAOS products, please see + http://www.taosinc.com/ + + +Using this driver +----------------- + +In order to use this driver, you'll need the serport driver, and the +inputattach tool, which is part of the input-utils package. The following +commands will tell the kernel that you have a TAOS EVM on the first +serial port: + +# modprobe serport +# inputattach --taos-evm /dev/ttyS0 + + +Technical details +----------------- + +Only 4 SMBus transaction types are supported by the TAOS evaluation +modules: +* Receive Byte +* Send Byte +* Read Byte +* Write Byte + +The communication protocol is text-based and pretty simple. It is +described in a PDF document on the CD which comes with the evaluation +module. The communication is rather slow, because the serial port has +to operate at 1200 bps. However, I don't think this is a big concern in +practice, as these modules are meant for evaluation and testing only. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 165c1266fff..c093b070015 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -513,6 +513,22 @@ config I2C_SIS96X This driver can also be built as a module. If so, the module will be called i2c-sis96x. +config I2C_TAOS_EVM + tristate "TAOS evaluation module" + depends on EXPERIMENTAL + select SERIO + select SERIO_SERPORT + default n + help + This supports TAOS evaluation modules on serial port. In order to + use this driver, you will need the inputattach tool, which is part + of the input-utils package. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called i2c-taos-evm. + config I2C_STUB tristate "I2C/SMBus Test Stub" depends on EXPERIMENTAL && m diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 14d1432f698..a49c0a386ae 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o +obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c new file mode 100644 index 00000000000..1b0cfd5472f --- /dev/null +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -0,0 +1,330 @@ +/* + * Driver for the TAOS evaluation modules + * These devices include an I2C master which can be controlled over the + * serial port. + * + * Copyright (C) 2007 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 + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAOS_BUFFER_SIZE 63 + +#define TAOS_STATE_INIT 0 +#define TAOS_STATE_IDLE 1 +#define TAOS_STATE_SEND 2 +#define TAOS_STATE_RECV 3 + +#define TAOS_CMD_RESET 0x12 + +static DECLARE_WAIT_QUEUE_HEAD(wq); + +struct taos_data { + struct i2c_adapter adapter; + struct i2c_client *client; + int state; + u8 addr; /* last used address */ + unsigned char buffer[TAOS_BUFFER_SIZE]; + unsigned int pos; /* position inside the buffer */ +}; + +/* TAOS TSL2550 EVM */ +static struct i2c_board_info tsl2550_info = { + I2C_BOARD_INFO("tsl2550", 0x39), + .type = "tsl2550", +}; + +/* Instantiate i2c devices based on the adapter name */ +static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter) +{ + if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) { + dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n", + tsl2550_info.driver_name, tsl2550_info.addr); + return i2c_new_device(adapter, &tsl2550_info); + } + + return NULL; +} + +static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + struct serio *serio = adapter->algo_data; + struct taos_data *taos = serio_get_drvdata(serio); + char *p; + + /* Encode our transaction. "@" is for the device address, "$" for the + SMBus command and "#" for the data. */ + p = taos->buffer; + + /* The device remembers the last used address, no need to send it + again if it's the same */ + if (addr != taos->addr) + p += sprintf(p, "@%02X", addr); + + switch (size) { + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) + sprintf(p, "$#%02X", command); + else + sprintf(p, "$"); + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_WRITE) + sprintf(p, "$%02X#%02X", command, data->byte); + else + sprintf(p, "$%02X", command); + break; + default: + dev_dbg(&adapter->dev, "Unsupported transaction size %d\n", + size); + return -EINVAL; + } + + /* Send the transaction to the TAOS EVM */ + dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer); + taos->pos = 0; + taos->state = TAOS_STATE_SEND; + serio_write(serio, taos->buffer[0]); + wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE, + msecs_to_jiffies(250)); + if (taos->state != TAOS_STATE_IDLE) { + dev_err(&adapter->dev, "Transaction failed " + "(state=%d, pos=%d)\n", taos->state, taos->pos); + taos->addr = 0; + return -EIO; + } + taos->addr = addr; + + /* Start the transaction and read the answer */ + taos->pos = 0; + taos->state = TAOS_STATE_RECV; + serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<'); + wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE, + msecs_to_jiffies(150)); + if (taos->state != TAOS_STATE_IDLE + || taos->pos != 6) { + dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n", + taos->pos); + return -EIO; + } + dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer); + + /* Interpret the returned string */ + p = taos->buffer + 2; + p[3] = '\0'; + if (!strcmp(p, "NAK")) + return -ENODEV; + + if (read_write == I2C_SMBUS_WRITE) { + if (!strcmp(p, "ACK")) + return 0; + } else { + if (p[0] == 'x') { + data->byte = simple_strtol(p + 1, NULL, 16); + return 0; + } + } + + return -EIO; +} + +static u32 taos_smbus_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA; +} + +static const struct i2c_algorithm taos_algorithm = { + .smbus_xfer = taos_smbus_xfer, + .functionality = taos_smbus_func, +}; + +static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data, + unsigned int flags) +{ + struct taos_data *taos = serio_get_drvdata(serio); + + switch (taos->state) { + case TAOS_STATE_INIT: + taos->buffer[taos->pos++] = data; + if (data == ':' + || taos->pos == TAOS_BUFFER_SIZE - 1) { + taos->buffer[taos->pos] = '\0'; + taos->state = TAOS_STATE_IDLE; + wake_up_interruptible(&wq); + } + break; + case TAOS_STATE_SEND: + if (taos->buffer[++taos->pos]) + serio_write(serio, taos->buffer[taos->pos]); + else { + taos->state = TAOS_STATE_IDLE; + wake_up_interruptible(&wq); + } + break; + case TAOS_STATE_RECV: + taos->buffer[taos->pos++] = data; + if (data == ']') { + taos->buffer[taos->pos] = '\0'; + taos->state = TAOS_STATE_IDLE; + wake_up_interruptible(&wq); + } + break; + } + + return IRQ_HANDLED; +} + +/* Extract the adapter name from the buffer received after reset. + The buffer is modified and a pointer inside the buffer is returned. */ +static char *taos_adapter_name(char *buffer) +{ + char *start, *end; + + start = strstr(buffer, "TAOS "); + if (!start) + return NULL; + + end = strchr(start, '\r'); + if (!end) + return NULL; + *end = '\0'; + + return start; +} + +static int taos_connect(struct serio *serio, struct serio_driver *drv) +{ + struct taos_data *taos; + struct i2c_adapter *adapter; + char *name; + int err; + + taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL); + if (!taos) { + err = -ENOMEM; + goto exit; + } + taos->state = TAOS_STATE_INIT; + serio_set_drvdata(serio, taos); + + err = serio_open(serio, drv); + if (err) + goto exit_kfree; + + adapter = &taos->adapter; + adapter->owner = THIS_MODULE; + adapter->algo = &taos_algorithm; + adapter->algo_data = serio; + adapter->dev.parent = &serio->dev; + + /* Reset the TAOS evaluation module to identify it */ + serio_write(serio, TAOS_CMD_RESET); + wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE, + msecs_to_jiffies(2000)); + + if (taos->state != TAOS_STATE_IDLE) { + err = -ENODEV; + dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, " + "pos=%d)\n", taos->state, taos->pos); + goto exit_close; + } + + name = taos_adapter_name(taos->buffer); + if (!name) { + err = -ENODEV; + dev_err(&serio->dev, "TAOS EVM identification failed\n"); + goto exit_close; + } + strlcpy(adapter->name, name, sizeof(adapter->name)); + + err = i2c_add_adapter(adapter); + if (err) + goto exit_close; + dev_dbg(&serio->dev, "Connected to TAOS EVM\n"); + + taos->client = taos_instantiate_device(adapter); + return 0; + + exit_close: + serio_close(serio); + exit_kfree: + serio_set_drvdata(serio, NULL); + kfree(taos); + exit: + return err; +} + +static void taos_disconnect(struct serio *serio) +{ + struct taos_data *taos = serio_get_drvdata(serio); + + if (taos->client) + i2c_unregister_device(taos->client); + i2c_del_adapter(&taos->adapter); + serio_close(serio); + serio_set_drvdata(serio, NULL); + kfree(taos); + + dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n"); +} + +static struct serio_device_id taos_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TAOSEVM, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; +MODULE_DEVICE_TABLE(serio, taos_serio_ids); + +static struct serio_driver taos_drv = { + .driver = { + .name = "taos-evm", + }, + .description = "TAOS evaluation module driver", + .id_table = taos_serio_ids, + .connect = taos_connect, + .disconnect = taos_disconnect, + .interrupt = taos_interrupt, +}; + +static int __init taos_init(void) +{ + return serio_register_driver(&taos_drv); +} + +static void __exit taos_exit(void) +{ + serio_unregister_driver(&taos_drv); +} + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("TAOS evaluation module driver"); +MODULE_LICENSE("GPL"); + +module_init(taos_init); +module_exit(taos_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 1ebf0455e22..d9377ce9ffd 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -209,5 +209,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_PENMOUNT 0x31 #define SERIO_TOUCHRIGHT 0x32 #define SERIO_TOUCHWIN 0x33 +#define SERIO_TAOSEVM 0x34 #endif -- cgit v1.2.3-70-g09d2 From 0a85e9a271a754e352af8a8b625025017fd97449 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jul 2007 14:12:32 +0200 Subject: i2c-rpx: Remove This driver has been broken forever. It depends on i2c-algo-8xx which has never been in the mainline kernel. Signed-off-by: Jean Delvare --- Documentation/i2c/summary | 2 - drivers/i2c/algos/Kconfig | 4 -- drivers/i2c/busses/Kconfig | 5 --- drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-rpx.c | 101 ------------------------------------------- 5 files changed, 113 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-rpx.c (limited to 'Documentation') diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary index aea60bf7e8f..003c7319b8c 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary @@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers Algorithm drivers ----------------- -i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT) i2c-algo-bit: A bit-banging algorithm i2c-algo-pcf: A PCF 8584 style algorithm i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT) @@ -81,6 +80,5 @@ i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatch i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit) i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT) i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit) -i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT) i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit) diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 58899078810..014dfa575be 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -34,10 +34,6 @@ config I2C_ALGOPCA This support is also available as a module. If so, the module will be called i2c-algo-pca. -config I2C_ALGO8XX - tristate "MPC8xx CPM I2C interface" - depends on 8xx - config I2C_ALGO_SGI tristate "I2C SGI interfaces" depends on SGI_IP22 || SGI_IP32 || X86_VISWS diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c477dcfad4e..fcde9bab5b9 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -391,11 +391,6 @@ config I2C_PROSAVAGE This support is also available as a module. If so, the module will be called i2c-prosavage. -config I2C_RPXLITE - tristate "Embedded Planet RPX Lite/Classic support" - depends on RPXLITE || RPXCLASSIC - select I2C_ALGO8XX - config I2C_S3C2410 tristate "S3C2410 I2C Driver" depends on ARCH_S3C2410 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index d7bbb90056a..a6db4e38bda 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o -obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c deleted file mode 100644 index 8764df06f51..00000000000 --- a/drivers/i2c/busses/i2c-rpx.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Embedded Planet RPX Lite MPC8xx CPM I2C interface. - * Copyright (c) 1999 Dan Malek (dmalek@jlc.net). - * - * moved into proper i2c interface; - * Brad Parker (brad@heeltoe.com) - * - * RPX lite specific parts of the i2c interface - * Update: There actually isn't anything RPXLite-specific about this module. - * This should work for most any 8xx board. The console messages have been - * changed to eliminate RPXLite references. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -static void -rpx_iic_init(struct i2c_algo_8xx_data *data) -{ - volatile cpm8xx_t *cp; - volatile immap_t *immap; - - cp = cpmp; /* Get pointer to Communication Processor */ - immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ - - data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; - - /* Check for and use a microcode relocation patch. - */ - if ((data->reloc = data->iip->iic_rpbase)) - data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase]; - - data->i2c = (i2c8xx_t *)&(immap->im_i2c); - data->cp = cp; - - /* Initialize Port B IIC pins. - */ - cp->cp_pbpar |= 0x00000030; - cp->cp_pbdir |= 0x00000030; - cp->cp_pbodr |= 0x00000030; - - /* Allocate space for two transmit and two receive buffer - * descriptors in the DP ram. - */ - data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8); - - /* ptr to i2c area */ - data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c); -} - -static int rpx_install_isr(int irq, void (*func)(void *), void *data) -{ - /* install interrupt handler */ - cpm_install_handler(irq, func, data); - - return 0; -} - -static struct i2c_algo_8xx_data rpx_data = { - .setisr = rpx_install_isr -}; - -static struct i2c_adapter rpx_ops = { - .owner = THIS_MODULE, - .name = "m8xx", - .id = I2C_HW_MPC8XX_EPON, - .algo_data = &rpx_data, -}; - -int __init i2c_rpx_init(void) -{ - printk(KERN_INFO "i2c-rpx: i2c MPC8xx driver\n"); - - /* reset hardware to sane state */ - rpx_iic_init(&rpx_data); - - if (i2c_8xx_add_bus(&rpx_ops) < 0) { - printk(KERN_ERR "i2c-rpx: Unable to register with I2C\n"); - return -ENODEV; - } - - return 0; -} - -void __exit i2c_rpx_exit(void) -{ - i2c_8xx_del_bus(&rpx_ops); -} - -MODULE_AUTHOR("Dan Malek "); -MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards"); - -module_init(i2c_rpx_init); -module_exit(i2c_rpx_exit); -- cgit v1.2.3-70-g09d2