From 4111ecd2178dbc262bf384c5e472de346d593341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20N=C3=A9meth?= Date: Tue, 2 Mar 2010 12:23:37 +0100 Subject: i2c: Make PCI device ids constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The id_table field of the struct pci_driver is constant in so it is worth to make initialization data also constant. The semantic match that finds this kind of pattern is as follows: (http://coccinelle.lip6.fr/) // @r@ disable decl_init,const_decl_init; identifier I1, I2, x; @@ struct I1 { ... const struct I2 *x; ... }; @s@ identifier r.I1, y; identifier r.x, E; @@ struct I1 y = { .x = E, }; @c@ identifier r.I2; identifier s.E; @@ const struct I2 E[] = ... ; @depends on !c@ identifier r.I2; identifier s.E; @@ + const struct I2 E[] = ...; // Signed-off-by: Márton Németh Cc: Julia Lawall Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-ali1535.c | 2 +- drivers/i2c/busses/i2c-ali1563.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 2 +- drivers/i2c/busses/i2c-amd756.c | 2 +- drivers/i2c/busses/i2c-amd8111.c | 2 +- drivers/i2c/busses/i2c-hydra.c | 2 +- drivers/i2c/busses/i2c-i801.c | 2 +- drivers/i2c/busses/i2c-isch.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-pasemi.c | 2 +- drivers/i2c/busses/i2c-piix4.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 2 +- drivers/i2c/busses/i2c-sis630.c | 2 +- drivers/i2c/busses/i2c-sis96x.c | 2 +- drivers/i2c/busses/i2c-tiny-usb.c | 2 +- drivers/i2c/busses/i2c-via.c | 2 +- drivers/i2c/busses/i2c-viapro.c | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 8de7d7b87bb0..bd8f1e4d9e6c 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -480,7 +480,7 @@ static struct i2c_adapter ali1535_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id ali1535_ids[] = { +static const struct pci_device_id ali1535_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { }, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 4687af40dd50..a409cfcf0629 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev) ali1563_shutdown(dev); } -static struct pci_device_id __devinitdata ali1563_id_table[] = { +static const struct pci_device_id ali1563_id_table[] __devinitconst = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index e7e3205f1286..659f63f5e4af 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id ali15x3_ids[] = { +static const struct pci_device_id ali15x3_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 8f0b90ef8c76..c5a9fa488e7f 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -308,7 +308,7 @@ static const char* chipname[] = { "nVidia nForce", "AMD8111", }; -static struct pci_device_id amd756_ids[] = { +static const struct pci_device_id amd756_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 5b4ad86ca166..d0dc970d7370 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -351,7 +351,7 @@ static const struct i2c_algorithm smbus_algorithm = { }; -static struct pci_device_id amd8111_ids[] = { +static const struct pci_device_id amd8111_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index bec9b845dd16..c767295ad1fb 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = { .algo_data = &hydra_bit_data, }; -static struct pci_device_id hydra_ids[] = { +static const struct pci_device_id hydra_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index df6ab553f975..cefe80c0f44c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -561,7 +561,7 @@ static struct i2c_adapter i801_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id i801_ids[] = { +static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index dba6eb053e2f..69c22f79f231 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -256,7 +256,7 @@ static struct i2c_adapter sch_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id sch_ids[] = { +static const struct pci_device_id sch_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ec11d1c4e77b..4a700587ef18 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -308,7 +308,7 @@ static struct i2c_algorithm smbus_algorithm = { }; -static struct pci_device_id nforce2_ids[] = { +static const struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index adf0fbb902f0..0d20ff46a518 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -400,7 +400,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static struct pci_device_id pasemi_smb_ids[] = { +static const struct pci_device_id pasemi_smb_ids[] = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index e56e4b6823ca..ee9da6fcf69a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id piix4_ids[] = { +static const struct pci_device_id piix4_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 844569f7d8b7..55a71370c79b 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id sis5595_ids[] __devinitdata = { +static const struct pci_device_id sis5595_ids[] __devinitconst = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 68cff7af7013..2309c7f1bde2 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -468,7 +468,7 @@ static struct i2c_adapter sis630_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id sis630_ids[] __devinitdata = { +static const struct pci_device_id sis630_ids[] __devinitconst = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 1649963b00dc..d43d8f8943dd 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = { .algo = &smbus_algorithm, }; -static struct pci_device_id sis96x_ids[] = { +static const struct pci_device_id sis96x_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index e29b6d5ba8ef..41adb390e49c 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -137,7 +137,7 @@ static const struct i2c_algorithm usb_algorithm = { * Future Technology Devices International Ltd., later a pair was * bought from EZPrototypes */ -static struct usb_device_id i2c_tiny_usb_table [] = { +static const struct usb_device_id i2c_tiny_usb_table[] = { { USB_DEVICE(0x0403, 0xc631) }, /* FTDI */ { USB_DEVICE(0x1c40, 0x0534) }, /* EZPrototypes */ { } /* Terminating entry */ diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 8b24f192103a..de78283bddbe 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = { }; -static struct pci_device_id vt586b_ids[] __devinitdata = { +static const struct pci_device_id vt586b_ids[] __devinitconst = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index a84a909e1234..d57292e5dae0 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -444,7 +444,7 @@ release_region: return error; } -static struct pci_device_id vt596_ids[] = { +static const struct pci_device_id vt596_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), -- cgit v1.2.3 From 393764340beb595c1ad7dd2d2243c2b6551aaa71 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Tue, 2 Mar 2010 12:23:39 +0100 Subject: i2c-i801: Add Intel Cougar Point device IDs Add the Intel Cougar Point (PCH) SMBus controller device IDs. Signed-off-by: Seth Heasley Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 5 +++-- drivers/i2c/busses/i2c-i801.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 737f05200b1d..7c382f9d81c3 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -77,7 +77,7 @@ config I2C_AMD8111 will be called i2c-amd8111. config I2C_I801 - tristate "Intel 82801 (ICH)" + tristate "Intel 82801 (ICH/PCH)" depends on PCI help If you say yes to this option, support will be included for the Intel @@ -97,7 +97,8 @@ config I2C_I801 ICH9 Tolapai ICH10 - PCH + 3400/5 Series (PCH) + Cougar Point (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index cefe80c0f44c..9da5b05cdb52 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -41,7 +41,8 @@ Tolapai 0x5032 32 hard yes yes yes ICH10 0x3a30 32 hard yes yes yes ICH10 0x3a60 32 hard yes yes yes - PCH 0x3b30 32 hard yes yes yes + 3400/5 Series (PCH) 0x3b30 32 hard yes yes yes + Cougar Point (PCH) 0x1c22 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -578,6 +579,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) }, { 0, } }; @@ -707,6 +709,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ICH10_4: case PCI_DEVICE_ID_INTEL_ICH10_5: case PCI_DEVICE_ID_INTEL_PCH_SMBUS: + case PCI_DEVICE_ID_INTEL_CPT_SMBUS: i801_features |= FEATURE_I2C_BLOCK_READ; /* fall through */ case PCI_DEVICE_ID_INTEL_82801DB_3: -- cgit v1.2.3 From c05d490234b7cf1715d9568d2041d9bc598a0b45 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:40 +0100 Subject: i2c-tiny-usb: Fix a comment on bus frequency The description of the delay parameter is incomplete, it suggests that there is a direct relation between the delay value and the bus frequency. In fact, due to additional delays in the i2c bitbanging code, the i2c clock is always much slower. Signed-off-by: Jean Delvare Cc: Till Harbaum --- drivers/i2c/busses/i2c-tiny-usb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index 41adb390e49c..b5b1bbf37d3c 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -31,11 +31,13 @@ #define CMD_I2C_IO_BEGIN (1<<0) #define CMD_I2C_IO_END (1<<1) -/* i2c bit delay, default is 10us -> 100kHz */ +/* i2c bit delay, default is 10us -> 100kHz max + (in practice, due to additional delays in the i2c bitbanging + code this results in a i2c clock of about 50kHz) */ static unsigned short delay = 10; module_param(delay, ushort, 0); -MODULE_PARM_DESC(delay, "bit delay in microseconds, " - "e.g. 10 for 100kHz (default is 100kHz)"); +MODULE_PARM_DESC(delay, "bit delay in microseconds " + "(default is 10us for 100kHz max)"); static int usb_read(struct i2c_adapter *adapter, int cmd, int value, int index, void *data, int len); -- cgit v1.2.3 From 6d376fcc28d98f7f8f652755ae4dca1ff7240563 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:41 +0100 Subject: i2c-parport: Give powered devices some time to settle When the i2c-parport adapter is reponsible for powering devices, it would seem reasonable to give them some time to settle before trying to access them. Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-parport-light.c | 6 +++++- drivers/i2c/busses/i2c-parport.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 322c5691e38e..5383f64c5372 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -127,8 +128,11 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev) parport_setsda(NULL, 1); parport_setscl(NULL, 1); /* Other init if needed (power on...) */ - if (adapter_parm[type].init.val) + if (adapter_parm[type].init.val) { line_set(1, &adapter_parm[type].init); + /* Give powered devices some time to settle */ + msleep(100); + } parport_adapter.dev.parent = &pdev->dev; err = i2c_bit_add_bus(&parport_adapter); diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0d8998610c74..056af1820993 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -185,8 +186,11 @@ static void i2c_parport_attach (struct parport *port) parport_setsda(port, 1); parport_setscl(port, 1); /* Other init if needed (power on...) */ - if (adapter_parm[type].init.val) + if (adapter_parm[type].init.val) { line_set(port, 1, &adapter_parm[type].init); + /* Give powered devices some time to settle */ + msleep(100); + } if (i2c_bit_add_bus(&adapter->adapter) < 0) { printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); -- cgit v1.2.3 From b5527a7766f0505dc72efe3cefe5e9dea826f611 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:42 +0100 Subject: i2c: Add SMBus alert support SMBus alert support. The SMBus alert protocol allows several SMBus slave devices to share a single interrupt pin on the SMBus master, while still allowing the master to know which slave triggered the interrupt. This is based on preliminary work by David Brownell. The key difference between David's implementation and mine is that his was part of i2c-core, while mine is split into a separate, standalone module named i2c-smbus. The i2c-smbus module is meant to include support for all SMBus extensions to the I2C protocol in the future. The benefit of this approach is a zero cost for I2C bus segments which do not need SMBus alert support. Where David's implementation increased the size of struct i2c_adapter by 7% (40 bytes on i386), mine doesn't touch it. Where David's implementation added over 150 lines of code to i2c-core (+10%), mine doesn't touch it. The only change that touches all the users of the i2c subsystem is a new callback in struct i2c_driver (common to both implementations.) I seem to remember Trent was worried about the footprint of David'd implementation, hopefully mine addresses the issue. Signed-off-by: Jean Delvare Acked-by: Jonathan Cameron Cc: David Brownell Cc: Trent Piepho --- drivers/i2c/Makefile | 2 +- drivers/i2c/i2c-smbus.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/i2c-smbus.c (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index ba26e6cbe74e..7111c93bd3e6 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o -obj-$(CONFIG_I2C) += i2c-core.o +obj-$(CONFIG_I2C) += i2c-core.o i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-y += busses/ chips/ algos/ diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c new file mode 100644 index 000000000000..421278221243 --- /dev/null +++ b/drivers/i2c/i2c-smbus.c @@ -0,0 +1,263 @@ +/* + * i2c-smbus.c - SMBus extensions to the I2C protocol + * + * Copyright (C) 2008 David Brownell + * Copyright (C) 2010 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct i2c_smbus_alert { + unsigned int alert_edge_triggered:1; + int irq; + struct work_struct alert; + struct i2c_client *ara; /* Alert response address */ +}; + +struct alert_data { + unsigned short addr; + u8 flag:1; +}; + +/* If this is the alerting device, notify its driver */ +static int smbus_do_alert(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct alert_data *data = addrp; + + if (!client || client->addr != data->addr) + return 0; + if (client->flags & I2C_CLIENT_TEN) + return 0; + + /* + * Drivers should either disable alerts, or provide at least + * a minimal handler. Lock so client->driver won't change. + */ + down(&dev->sem); + if (client->driver) { + if (client->driver->alert) + client->driver->alert(client, data->flag); + else + dev_warn(&client->dev, "no driver alert()!\n"); + } else + dev_dbg(&client->dev, "alert with no driver\n"); + up(&dev->sem); + + /* Stop iterating after we find the device */ + return -EBUSY; +} + +/* + * The alert IRQ handler needs to hand work off to a task which can issue + * SMBus calls, because those sleeping calls can't be made in IRQ context. + */ +static void smbus_alert(struct work_struct *work) +{ + struct i2c_smbus_alert *alert; + struct i2c_client *ara; + unsigned short prev_addr = 0; /* Not a valid address */ + + alert = container_of(work, struct i2c_smbus_alert, alert); + ara = alert->ara; + + for (;;) { + s32 status; + struct alert_data data; + + /* + * Devices with pending alerts reply in address order, low + * to high, because of slave transmit arbitration. After + * responding, an SMBus device stops asserting SMBALERT#. + * + * Note that SMBus 2.0 reserves 10-bit addresess for future + * use. We neither handle them, nor try to use PEC here. + */ + status = i2c_smbus_read_byte(ara); + if (status < 0) + break; + + data.flag = status & 1; + data.addr = status >> 1; + + if (data.addr == prev_addr) { + dev_warn(&ara->dev, "Duplicate SMBALERT# from dev " + "0x%02x, skipping\n", data.addr); + break; + } + dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n", + data.addr, data.flag); + + /* Notify driver for the device which issued the alert */ + device_for_each_child(&ara->adapter->dev, &data, + smbus_do_alert); + prev_addr = data.addr; + } + + /* We handled all alerts; re-enable level-triggered IRQs */ + if (!alert->alert_edge_triggered) + enable_irq(alert->irq); +} + +static irqreturn_t smbalert_irq(int irq, void *d) +{ + struct i2c_smbus_alert *alert = d; + + /* Disable level-triggered IRQs until we handle them */ + if (!alert->alert_edge_triggered) + disable_irq_nosync(irq); + + schedule_work(&alert->alert); + return IRQ_HANDLED; +} + +/* Setup SMBALERT# infrastructure */ +static int smbalert_probe(struct i2c_client *ara, + const struct i2c_device_id *id) +{ + struct i2c_smbus_alert_setup *setup = ara->dev.platform_data; + struct i2c_smbus_alert *alert; + struct i2c_adapter *adapter = ara->adapter; + int res; + + alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL); + if (!alert) + return -ENOMEM; + + alert->alert_edge_triggered = setup->alert_edge_triggered; + alert->irq = setup->irq; + INIT_WORK(&alert->alert, smbus_alert); + alert->ara = ara; + + if (setup->irq > 0) { + res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, + 0, "smbus_alert", alert); + if (res) { + kfree(alert); + return res; + } + } + + i2c_set_clientdata(ara, alert); + dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", + setup->alert_edge_triggered ? "edge" : "level"); + + return 0; +} + +/* IRQ resource is managed so it is freed automatically */ +static int smbalert_remove(struct i2c_client *ara) +{ + struct i2c_smbus_alert *alert = i2c_get_clientdata(ara); + + cancel_work_sync(&alert->alert); + + i2c_set_clientdata(ara, NULL); + kfree(alert); + return 0; +} + +static const struct i2c_device_id smbalert_ids[] = { + { "smbus_alert", 0 }, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, smbalert_ids); + +static struct i2c_driver smbalert_driver = { + .driver = { + .name = "smbus_alert", + }, + .probe = smbalert_probe, + .remove = smbalert_remove, + .id_table = smbalert_ids, +}; + +/** + * i2c_setup_smbus_alert - Setup SMBus alert support + * @adapter: the target adapter + * @setup: setup data for the SMBus alert handler + * Context: can sleep + * + * Setup handling of the SMBus alert protocol on a given I2C bus segment. + * + * Handling can be done either through our IRQ handler, or by the + * adapter (from its handler, periodic polling, or whatever). + * + * NOTE that if we manage the IRQ, we *MUST* know if it's level or + * edge triggered in order to hand it to the workqueue correctly. + * If triggering the alert seems to wedge the system, you probably + * should have said it's level triggered. + * + * This returns the ara client, which should be saved for later use with + * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL + * to indicate an error. + */ +struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, + struct i2c_smbus_alert_setup *setup) +{ + struct i2c_board_info ara_board_info = { + I2C_BOARD_INFO("smbus_alert", 0x0c), + .platform_data = setup, + }; + + return i2c_new_device(adapter, &ara_board_info); +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); + +/** + * i2c_handle_smbus_alert - Handle an SMBus alert + * @ara: the ARA client on the relevant adapter + * Context: can't sleep + * + * Helper function to be called from an I2C bus driver's interrupt + * handler. It will schedule the alert work, in turn calling the + * corresponding I2C device driver's alert function. + * + * It is assumed that ara is a valid i2c client previously returned by + * i2c_setup_smbus_alert(). + */ +int i2c_handle_smbus_alert(struct i2c_client *ara) +{ + struct i2c_smbus_alert *alert = i2c_get_clientdata(ara); + + return schedule_work(&alert->alert); +} +EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); + +static int __init i2c_smbus_init(void) +{ + return i2c_add_driver(&smbalert_driver); +} + +static void __exit i2c_smbus_exit(void) +{ + i2c_del_driver(&smbalert_driver); +} + +module_init(i2c_smbus_init); +module_exit(i2c_smbus_exit); + +MODULE_AUTHOR("Jean Delvare "); +MODULE_DESCRIPTION("SMBus protocol extensions support"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e2ca307439fb9df922c3e8891289a2ac05812fb7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:43 +0100 Subject: i2c: Separate Kconfig option for i2c-smbus Having a separate Kconfig option for i2c-smbus makes it possible to build that support as a module even when i2c-core itself is built-in. Bus drivers which implement SMBus alert should select this option, so in most cases this option is hidden and the user doesn't have to care about it. Signed-off-by: Jean Delvare Cc: David Brownell Cc: Trent Piepho --- drivers/i2c/Kconfig | 10 ++++++++++ drivers/i2c/Makefile | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 8d8a00e5a30e..02ce9cff5fcf 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -61,6 +61,16 @@ config I2C_HELPER_AUTO In doubt, say Y. +config I2C_SMBUS + tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO + help + Say Y here if you want support for SMBus extensions to the I2C + specification. At the moment, the only supported extension is + the SMBus alert protocol. + + This support is also available as a module. If so, the module + will be called i2c-smbus. + source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig source drivers/i2c/chips/Kconfig diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 7111c93bd3e6..acd0250c16a0 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,7 +3,8 @@ # obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o -obj-$(CONFIG_I2C) += i2c-core.o i2c-smbus.o +obj-$(CONFIG_I2C) += i2c-core.o +obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-y += busses/ chips/ algos/ -- cgit v1.2.3 From 35859254483bce479024781885bc02d860552995 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:44 +0100 Subject: i2c-parport: Add SMBus alert support Add support for the SMBus alert mechanism to the i2c-parport driver. The ADM1032 evaluation board at least is properly wired for this. Signed-off-by: Jean Delvare Cc: David Brownell Cc: Trent Piepho --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-parport.c | 37 +++++++++++++++++++++++++++++++++++-- drivers/i2c/busses/i2c-parport.h | 4 +++- 3 files changed, 39 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7c382f9d81c3..4d65546ede44 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -581,6 +581,7 @@ config I2C_PARPORT tristate "Parallel port adapter" depends on PARPORT select I2C_ALGOBIT + select I2C_SMBUS help This supports parallel port I2C adapters such as the ones made by Philips or Velleman, Analog Devices evaluation boards, and more. diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 056af1820993..220fca7f23a6 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2007 Jean Delvare + Copyright (C) 2003-2010 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -31,6 +31,7 @@ #include #include #include +#include #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -39,6 +40,8 @@ struct i2c_par { struct pardevice *pdev; struct i2c_adapter adapter; struct i2c_algo_bit_data algo_data; + struct i2c_smbus_alert_setup alert_data; + struct i2c_client *ara; struct i2c_par *next; }; @@ -144,6 +147,19 @@ static struct i2c_algo_bit_data parport_algo_data = { /* ----- I2c and parallel port call-back functions and structures --------- */ +void i2c_parport_irq(void *data) +{ + struct i2c_par *adapter = data; + struct i2c_client *ara = adapter->ara; + + if (ara) { + dev_dbg(&ara->dev, "SMBus alert received\n"); + i2c_handle_smbus_alert(ara); + } else + dev_dbg(&adapter->adapter.dev, + "SMBus alert received but no ARA client!\n"); +} + static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; @@ -155,8 +171,9 @@ static void i2c_parport_attach (struct parport *port) } pr_debug("i2c-parport: attaching to %s\n", port->name); + parport_disable_irq(port); adapter->pdev = parport_register_device(port, "i2c-parport", - NULL, NULL, NULL, PARPORT_FLAG_EXCL, NULL); + NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter); if (!adapter->pdev) { printk(KERN_ERR "i2c-parport: Unable to register with parport\n"); goto ERROR0; @@ -197,6 +214,18 @@ static void i2c_parport_attach (struct parport *port) goto ERROR1; } + /* Setup SMBus alert if supported */ + if (adapter_parm[type].smbus_alert) { + adapter->alert_data.alert_edge_triggered = 1; + adapter->ara = i2c_setup_smbus_alert(&adapter->adapter, + &adapter->alert_data); + if (adapter->ara) + parport_enable_irq(port); + else + printk(KERN_WARNING "i2c-parport: Failed to register " + "ARA client\n"); + } + /* Add the new adapter to the list */ adapter->next = adapter_list; adapter_list = adapter; @@ -217,6 +246,10 @@ static void i2c_parport_detach (struct parport *port) for (prev = NULL, adapter = adapter_list; adapter; prev = adapter, adapter = adapter->next) { if (adapter->pdev->port == port) { + if (adapter->ara) { + parport_disable_irq(port); + i2c_unregister_device(adapter->ara); + } i2c_del_adapter(&adapter->adapter); /* Un-init if needed (power off...) */ diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index ed69d846cb95..a9f66816546c 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.h I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2004 Jean Delvare + Copyright (C) 2003-2010 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 @@ -38,6 +38,7 @@ struct adapter_parm { struct lineop getsda; struct lineop getscl; struct lineop init; + unsigned int smbus_alert:1; }; static struct adapter_parm adapter_parm[] = { @@ -73,6 +74,7 @@ static struct adapter_parm adapter_parm[] = { .setscl = { 0x01, DATA, 1 }, .getsda = { 0x10, STAT, 1 }, .init = { 0xf0, DATA, 0 }, + .smbus_alert = 1, }, /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */ { -- cgit v1.2.3 From 927ab2f80745ec26f1e83e6ca15a5b29e134c8e5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:45 +0100 Subject: i2c-parport-light: Add SMBus alert support Add support for the SMBus alert mechanism to the i2c-parport-light driver. The ADM1032 evaluation board at least is properly wired for this. Signed-off-by: Jean Delvare Cc: David Brownell Cc: Trent Piepho --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-parport-light.c | 42 +++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4d65546ede44..4cc3807bd31c 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -605,6 +605,7 @@ config I2C_PARPORT config I2C_PARPORT_LIGHT tristate "Parallel port adapter (light)" select I2C_ALGOBIT + select I2C_SMBUS help This supports parallel port I2C adapters such as the ones made by Philips or Velleman, Analog Devices evaluation boards, and more. diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 5383f64c5372..5f41ec0f72d2 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport-light.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2007 Jean Delvare + Copyright (C) 2003-2010 Jean Delvare Based on older i2c-velleman.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "i2c-parport.h" @@ -44,6 +45,10 @@ static u16 base; module_param(base, ushort, 0); MODULE_PARM_DESC(base, "Base I/O address"); +static int irq; +module_param(irq, int, 0); +MODULE_PARM_DESC(irq, "IRQ (optional)"); + /* ----- Low-level parallel port access ----------------------------------- */ static inline void port_write(unsigned char p, unsigned char d) @@ -120,6 +125,16 @@ static struct i2c_adapter parport_adapter = { .name = "Parallel port adapter (light)", }; +/* SMBus alert support */ +static struct i2c_smbus_alert_setup alert_data = { + .alert_edge_triggered = 1, +}; +static struct i2c_client *ara; +static struct lineop parport_ctrl_irq = { + .val = (1 << 4), + .port = CTRL, +}; + static int __devinit i2c_parport_probe(struct platform_device *pdev) { int err; @@ -136,13 +151,31 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev) parport_adapter.dev.parent = &pdev->dev; err = i2c_bit_add_bus(&parport_adapter); - if (err) + if (err) { dev_err(&pdev->dev, "Unable to register with I2C\n"); - return err; + return err; + } + + /* Setup SMBus alert if supported */ + if (adapter_parm[type].smbus_alert && irq) { + alert_data.irq = irq; + ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data); + if (ara) + line_set(1, &parport_ctrl_irq); + else + dev_warn(&pdev->dev, "Failed to register ARA client\n"); + } + + return 0; } static int __devexit i2c_parport_remove(struct platform_device *pdev) { + if (ara) { + line_set(0, &parport_ctrl_irq); + i2c_unregister_device(ara); + ara = NULL; + } i2c_del_adapter(&parport_adapter); /* Un-init if needed (power off...) */ @@ -209,6 +242,9 @@ static int __init i2c_parport_init(void) if (!request_region(base, 3, DRVNAME)) return -EBUSY; + if (irq != 0) + pr_info(DRVNAME ": using irq %d\n", irq); + if (!adapter_parm[type].getscl.val) parport_algo_data.getscl = NULL; -- cgit v1.2.3 From 6de468ae2df0ee6fbee668d946811638b57361f6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Mar 2010 12:23:46 +0100 Subject: i2c: Hook up runtime PM support Allow I2C drivers to make use of the runtime PM framework by adding bus implementations of the runtime PM operations. These simply immediately suspend when the device is idle. The runtime PM framework provides drivers with off the shelf refcounts for enables and sysfs control for managing runtime suspend from userspace so is useful even without meaningful input from the bus. Signed-off-by: Mark Brown Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 10be7b5fbe97..4131698008b9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "i2c-core.h" @@ -184,6 +185,52 @@ static int i2c_device_pm_resume(struct device *dev) #define i2c_device_pm_resume NULL #endif +#ifdef CONFIG_PM_RUNTIME +static int i2c_device_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm; + + if (!dev->driver) + return 0; + pm = dev->driver->pm; + if (!pm || !pm->runtime_suspend) + return 0; + return pm->runtime_suspend(dev); +} + +static int i2c_device_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm; + + if (!dev->driver) + return 0; + pm = dev->driver->pm; + if (!pm || !pm->runtime_resume) + return 0; + return pm->runtime_resume(dev); +} + +static int i2c_device_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = NULL; + int ret; + + if (dev->driver) + pm = dev->driver->pm; + if (pm && pm->runtime_idle) { + ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + return pm_runtime_suspend(dev); +} +#else +#define i2c_device_runtime_suspend NULL +#define i2c_device_runtime_resume NULL +#define i2c_device_runtime_idle NULL +#endif + static int i2c_device_suspend(struct device *dev, pm_message_t mesg) { struct i2c_client *client = i2c_verify_client(dev); @@ -251,6 +298,9 @@ static const struct attribute_group *i2c_dev_attr_groups[] = { static const struct dev_pm_ops i2c_device_pm_ops = { .suspend = i2c_device_pm_suspend, .resume = i2c_device_pm_resume, + .runtime_suspend = i2c_device_runtime_suspend, + .runtime_resume = i2c_device_runtime_resume, + .runtime_idle = i2c_device_runtime_idle, }; struct bus_type i2c_bus_type = { -- cgit v1.2.3 From eec74a257f0a695688ba44c0f6c1e92dc81459be Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 2 Mar 2010 12:23:47 +0100 Subject: i2c-algo-pca: Drop duplicate variable Thanks to -Wshadow. Signed-off-by: Jean Delvare Reviewed-by: Wolfram Sang --- drivers/i2c/algos/i2c-algo-pca.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 78d42aae0089..dcdaf8e675bf 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -453,8 +453,6 @@ static int pca_init(struct i2c_adapter *adap) */ int raise_fall_time; - struct i2c_algo_pca_data *pca_data = adap->algo_data; - /* Ignore the reset function from the module, * we can use the parallel bus reset */ -- cgit v1.2.3 From 0c43ea544c1086fbbed5a6c99ea58eb64674ea8f Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Tue, 2 Mar 2010 12:23:49 +0100 Subject: i2c: Document the message size limit i2c_master_send & i2c_master_recv do not support more than 64 kb transfer, since msg.len is u16. Signed-off-by: Zhangfei Gao Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 4131698008b9..3202a86f420e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1183,7 +1183,7 @@ EXPORT_SYMBOL(i2c_transfer); * i2c_master_send - issue a single I2C message in master transmit mode * @client: Handle to slave device * @buf: Data that will be written to the slave - * @count: How many bytes to write + * @count: How many bytes to write, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes written. */ @@ -1210,7 +1210,7 @@ EXPORT_SYMBOL(i2c_master_send); * i2c_master_recv - issue a single I2C message in master receive mode * @client: Handle to slave device * @buf: Where to store data read from slave - * @count: How many bytes to read + * @count: How many bytes to read, must be less than 64k since msg.len is u16 * * Returns negative errno, or else the number of bytes read. */ -- cgit v1.2.3