From 69735698312f6f5e47001cf62dc678f591b6a6de Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:08:57 +0100 Subject: i2c-ali1563: Improve the status messages Improve the status messages printed by the i2c-ali1563 driver. Signed-off-by: Jean Delvare Cc: Rudolf Marek diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 8e1e3f8..3b0e79b 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -328,7 +328,6 @@ static int __devinit ali1563_setup(struct pci_dev * dev) u16 ctrl; pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - printk("ali1563: SMBus control = %04x\n",ctrl); /* Check if device is even enabled first */ if (!(ctrl & ALI1563_SMB_IOEN)) { @@ -353,9 +352,11 @@ static int __devinit ali1563_setup(struct pci_dev * dev) } if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, ali1563_pci_driver.name)) { - dev_warn(&dev->dev,"Could not allocate I/O space"); + dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n", + ali1563_smba); goto Err; } + dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba); return 0; Err: @@ -384,13 +385,18 @@ static int __devinit ali1563_probe(struct pci_dev * dev, int error; if ((error = ali1563_setup(dev))) - return error; + goto exit; ali1563_adapter.dev.parent = &dev->dev; sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x", ali1563_smba); if ((error = i2c_add_adapter(&ali1563_adapter))) - ali1563_shutdown(dev); - printk("%s: Returning %d\n",__FUNCTION__,error); + goto exit_shutdown; + return 0; + +exit_shutdown: + ali1563_shutdown(dev); +exit: + dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error); return error; } -- cgit v0.10.2 From 849be516c57501ec4729bde51babc25a7b073b65 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:08:57 +0100 Subject: i2c-ali1563: Fix device initialization The i2c-ali1563 initialization looks quite broken to me: * If the I/O space isn't enabled, we forcibly set 3 bits in the PCI configuration space instead of just the one enabling the I/O space. * After that we pretend to check if the write worked, but we don't actually read the new value from the register. * It's probably not a good idea to enable the I/O space if no base address has been set. So I propose the following changes to that part of the driver: * Merge ali1563_enable() into ali1563_setup(). * Check the base address before the I/O space enabled bit. Signed-off-by: Jean Delvare Acked-by: Rudolf Marek diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 3b0e79b..55ebbef 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -314,35 +314,12 @@ static u32 ali1563_func(struct i2c_adapter * a) } -static void ali1563_enable(struct pci_dev * dev) -{ - u16 ctrl; - - pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - ctrl |= 0x7; - pci_write_config_word(dev,ALI1563_SMBBA,ctrl); -} - static int __devinit ali1563_setup(struct pci_dev * dev) { u16 ctrl; pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); - /* Check if device is even enabled first */ - if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_warn(&dev->dev,"I/O space not enabled, trying manually\n"); - ali1563_enable(dev); - } - if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_warn(&dev->dev,"I/O space still not enabled, giving up\n"); - goto Err; - } - if (!(ctrl & ALI1563_SMB_HOSTEN)) { - dev_warn(&dev->dev,"Host Controller not enabled\n"); - goto Err; - } - /* SMB I/O Base in high 12 bits and must be aligned with the * size of the I/O space. */ ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); @@ -350,6 +327,24 @@ static int __devinit ali1563_setup(struct pci_dev * dev) dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); goto Err; } + + /* Check if device is enabled */ + if (!(ctrl & ALI1563_SMB_HOSTEN)) { + dev_warn(&dev->dev, "Host Controller not enabled\n"); + goto Err; + } + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_warn(&dev->dev, "I/O space not enabled, trying manually\n"); + pci_write_config_word(dev, ALI1563_SMBBA, + ctrl | ALI1563_SMB_IOEN); + pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); + if (!(ctrl & ALI1563_SMB_IOEN)) { + dev_err(&dev->dev, "I/O space still not enabled, " + "giving up\n"); + goto Err; + } + } + if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE, ali1563_pci_driver.name)) { dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n", -- cgit v0.10.2 From bbeaeef73a0b0a5c43ad2657b61857167d914a55 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Feb 2007 22:08:58 +0100 Subject: i2c/vt8231: Remove superfluous initialization Remove a superfluous initialization from the vt8231 hwmon driver; the i2c core does this, and the source field will be vanishing soon. Signed-off-by: David Brownell Signed-off-by: Jean Delvare diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 93f93d4..a6a4aa0 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -727,7 +727,6 @@ int vt8231_detect(struct i2c_adapter *adapter) client->addr = isa_address; client->adapter = adapter; client->driver = &vt8231_driver; - client->dev.parent = &adapter->dev; /* Fill in the remaining client fields and put into the global list */ strlcpy(client->name, "vt8231", I2C_NAME_SIZE); -- cgit v0.10.2 From 4ef0ce90df3763e277b5307fb580ff1cdaaad7b2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:08:58 +0100 Subject: i2c-nforce2: Drop unused reference to pci_dev Signed-off-by: Jean Delvare Cc: Hans-Frieder Vogt diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ad37c10..69d0730 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -57,7 +57,6 @@ MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver"); struct nforce2_smbus { - struct pci_dev *dev; struct i2c_adapter adapter; int base; int size; @@ -230,7 +229,6 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK; smbus->size = 64; } - smbus->dev = dev; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", -- cgit v0.10.2 From 4e6697fcc194db8b45559a9863947c6cbfeea363 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:08:59 +0100 Subject: i2c-piix4: Add support for the ATI SB600 Add support for the ATI SB600 SMBus controller. Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4 index 9214763..7cbe43f 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 IXP southbridges IXP200, IXP300, IXP400 + * ATI IXP200, IXP300, IXP400 and SB600 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 9367c4c..f2894de 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -183,6 +183,7 @@ config I2C_PIIX4 ATI IXP200 ATI IXP300 ATI IXP400 + ATI SB600 Serverworks OSB4 Serverworks CSB5 Serverworks CSB6 diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 30c7a1b..07546c2 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -23,6 +23,7 @@ Supports: Intel PIIX4, 440MX Serverworks OSB4, CSB5, CSB6, HT-1000 + ATI IXP200, IXP300, IXP400, SB600 SMSC Victory66 Note: we assume there can only be one device, with one SMBus interface. @@ -396,6 +397,8 @@ static struct pci_device_id piix4_ids[] = { .driver_data = 0 }, { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_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 8fb9c3e..182a96f 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -369,6 +369,7 @@ #define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a #define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380 #define PCI_DEVICE_ID_ATI_IXP600_SRAID 0x4381 +#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385 #define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c #define PCI_VENDOR_ID_VLSI 0x1004 -- cgit v0.10.2 From 3f9a4790a3818af1228c7fb4286afd66f3201fd0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 13 Feb 2007 22:08:59 +0100 Subject: i2c: Fix typo in SMBus Write Word Data description Write data, don't read it. Signed-off-by: Mike Frysinger Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 09f5e5c..8a653c6 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -97,7 +97,7 @@ SMBus Write Word Data ===================== This is the opposite operation of the Read Word Data command. 16 bits -of data is read from a device, from a designated register that is +of data is written to a device, to the designated register that is specified through the Comm byte. S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P -- cgit v0.10.2 From fcdd96ecaf04fb4f229ac1a64fe77fda890dffd5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:08:59 +0100 Subject: i2c-i801: Spelling fix Signed-off-by: Jean Delvare diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ae625b8..de5e23a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -123,7 +123,7 @@ static int i801_transaction(void) dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&I801_dev->dev, "Successfull!\n"); + dev_dbg(&I801_dev->dev, "Successful!\n"); } } -- cgit v0.10.2 From 099ab118b6b194ad43865f62776a0d36d4b1c7d2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:00 +0100 Subject: i2c-i801: Document the SMBus unhiding quirk This is a frequently asked question so it deserves a paragraph in the driver documentation. Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 3db69a0..c34f0db 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -48,14 +48,9 @@ following: The SMBus controller is function 3 in device 1f. Class 0c05 is SMBus Serial Controller. -If you do NOT see the 24x3 device at function 3, and you can't figure out -any way in the BIOS to enable it, - The ICH chips are quite similar to Intel's PIIX4 chip, at least in the SMBus controller. -See the file i2c-piix4 for some additional information. - Process Call Support -------------------- @@ -74,6 +69,61 @@ SMBus 2.0 Support The 82801DB (ICH4) and later chips support several SMBus 2.0 features. + +Hidden ICH SMBus +---------------- + +If your system has an Intel ICH south bridge, but you do NOT see the +SMBus device at 00:1f.3 in lspci, and you can't figure out any way in the +BIOS to enable it, it means it has been hidden by the BIOS code. Asus is +well known for first doing this on their P4B motherboard, and many other +boards after that. Some vendor machines are affected as well. + +The first thing to try is the "i2c_ec" ACPI driver. It could be that the +SMBus was hidden on purpose because it'll be driven by ACPI. If the +i2c_ec driver works for you, just forget about the i2c-i801 driver and +don't try to unhide the ICH SMBus. Even if i2c_ec doesn't work, you +better make sure that the SMBus isn't used by the ACPI code. Try loading +the "fan" and "thermal" drivers, and check in /proc/acpi/fan and +/proc/acpi/thermal_zone. If you find anything there, it's likely that +the ACPI is accessing the SMBus and it's safer not to unhide it. Only +once you are certain that ACPI isn't using the SMBus, you can attempt +to unhide it. + +In order to unhide the SMBus, we need to change the value of a PCI +register before the kernel enumerates the PCI devices. This is done in +drivers/pci/quirks.c, where all affected boards must be listed (see +function asus_hides_smbus_hostbridge.) If the SMBus device is missing, +and you think there's something interesting on the SMBus (e.g. a +hardware monitoring chip), you need to add your board to the list. + +The motherboard is identified using the subvendor and subdevice IDs of the +host bridge PCI device. Get yours with "lspci -n -v -s 00:00.0": + +00:00.0 Class 0600: 8086:2570 (rev 02) + Subsystem: 1043:80f2 + Flags: bus master, fast devsel, latency 0 + Memory at fc000000 (32-bit, prefetchable) [size=32M] + Capabilities: [e4] #09 [2106] + Capabilities: [a0] AGP version 3.0 + +Here the host bridge ID is 2570 (82865G/PE/P), the subvendor ID is 1043 +(Asus) and the subdevice ID is 80f2 (P4P800-X). You can find the symbolic +names for the bridge ID and the subvendor ID in include/linux/pci_ids.h, +and then add a case for your subdevice ID at the right place in +drivers/pci/quirks.c. Then please give it very good testing, to make sure +that the unhidden SMBus doesn't conflict with e.g. ACPI. + +If it works, proves useful (i.e. there are usable chips on the SMBus) +and seems safe, please submit a patch for inclusion into the kernel. + +Note: There's a useful script in lm_sensors 2.10.2 and later, named +unhide_ICH_SMBus (in prog/hotplug), which uses the fakephp driver to +temporarily unhide the SMBus without having to patch and recompile your +kernel. It's very convenient if you just want to check if there's +anything interesting on your hidden ICH SMBus. + + ********************** The lm_sensors project gratefully acknowledges the support of Texas Instruments in the initial development of this driver. -- cgit v0.10.2 From b8d6f45b32f6fe72bf7304183275e99332544ce1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:00 +0100 Subject: i2c: completion header cleanups i2c-core and i2c-isa use completions without including . Fix it. i2c-powermac includes but doesn't use any completion. Fix it. Signed-off-by: Jean Delvare Acked-by: Benjamin Herrenschmidt Cc: David Brownell diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 8ed59a2..5f33bc9 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -39,6 +39,7 @@ #include #include #include +#include static u32 isa_func(struct i2c_adapter *adapter); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 648d555..1425d224 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b05378a3..60f6eb1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -32,6 +32,7 @@ #include #include #include +#include #include -- cgit v0.10.2 From f37dd80ac2a67e4e4e921f99d34a1ceeb2488abb Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 13 Feb 2007 22:09:00 +0100 Subject: i2c: Add driver suspend/resume/shutdown support Driver model updates for the I2C core: - Add new suspend(), resume(), and shutdown() methods. Use them in the standard driver model style; document them. - Minor doc updates to highlight zero-initialized fields in drivers, and the driver model accessors for "clientdata". If any i2c drivers were previously using the old suspend/resume calls in "struct driver", they were getting warning messages ... and will now no longer work. Other than that, this patch changes no behaviors; and it lets I2C drivers use conventional PM and shutdown support. Signed-off-by: David Brownell Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index f03c2a0..ca272b2 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -129,6 +129,12 @@ Technical changes: structure, those name member should be initialized to a driver name string. i2c_driver itself has no name member anymore. +* [Driver model] Instead of shutdown or reboot notifiers, provide a + shutdown() method in your driver. + +* [Power management] Use the driver model suspend() and resume() + callbacks instead of the obsolete pm_register() calls. + Coding policy: * [Copyright] Use (C), not (c), for copyright. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 3a057c8..fbcff96 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -21,20 +21,26 @@ The driver structure Usually, you will implement a single driver structure, and instantiate all clients from it. Remember, a driver structure contains general access -routines, a client structure specific information like the actual I2C -address. +routines, and should be zero-initialized except for fields with data you +provide. A client structure holds device-specific information like the +driver model device node, and its I2C address. static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, - .attach_adapter = &foo_attach_adapter, - .detach_client = &foo_detach_client, - .command = &foo_command /* may be NULL */ + .attach_adapter = foo_attach_adapter, + .detach_client = foo_detach_client, + .shutdown = foo_shutdown, /* optional */ + .suspend = foo_suspend, /* optional */ + .resume = foo_resume, /* optional */ + .command = foo_command, /* optional */ } -The name field must match the driver name, including the case. It must not -contain spaces, and may be up to 31 characters long. +The name field is the driver name, and must not contain spaces. It +should match the module name (if the driver can be compiled as a module), +although you can use MODULE_ALIAS (passing "foo" in this example) to add +another name for the module. All other fields are for call-back functions which will be explained below. @@ -43,11 +49,18 @@ below. Extra client data ================= -The client structure has a special `data' field that can point to any -structure at all. You can use this to keep client-specific data. You +Each client structure has a special `data' field that can point to any +structure at all. You should use this to keep device-specific data, +especially in drivers that handle multiple I2C or SMBUS devices. You do not always need this, but especially for `sensors' drivers, it can be very useful. + /* store the value */ + void i2c_set_clientdata(struct i2c_client *client, void *data); + + /* retrieve the value */ + void *i2c_get_clientdata(struct i2c_client *client); + An example structure is below. struct foo_data { @@ -493,6 +506,33 @@ by `__init_data'. Hose functions and structures can be removed after kernel booting (or module loading) is completed. +Power Management +================ + +If your I2C device needs special handling when entering a system low +power state -- like putting a transceiver into a low power mode, or +activating a system wakeup mechanism -- do that in the suspend() method. +The resume() method should reverse what the suspend() method does. + +These are standard driver model calls, and they work just like they +would for any other driver stack. The calls can sleep, and can use +I2C messaging to the device being suspended or resumed (since their +parent I2C adapter is active when these calls are issued, and IRQs +are still enabled). + + +System Shutdown +=============== + +If your I2C device needs special handling when the system shuts down +or reboots (including kexec) -- like turning something off -- use a +shutdown() method. + +Again, this is a standard driver model call, working just like it +would for any other driver stack: the calls can sleep, and can use +I2C messaging. + + Command function ================ diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 60f6eb1..9653f7f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -41,49 +41,72 @@ static LIST_HEAD(drivers); static DEFINE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); + +/* ------------------------------------------------------------------------- */ + /* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { return 1; } -static int i2c_bus_suspend(struct device * dev, pm_message_t state) +static int i2c_device_probe(struct device *dev) { - int rc = 0; + return -ENODEV; +} - if (dev->driver && dev->driver->suspend) - rc = dev->driver->suspend(dev, state); - return rc; +static int i2c_device_remove(struct device *dev) +{ + return 0; } -static int i2c_bus_resume(struct device * dev) +static void i2c_device_shutdown(struct device *dev) { - int rc = 0; - - if (dev->driver && dev->driver->resume) - rc = dev->driver->resume(dev); - return rc; + struct i2c_driver *driver; + + if (!dev->driver) + return; + driver = to_i2c_driver(dev->driver); + if (driver->shutdown) + driver->shutdown(to_i2c_client(dev)); } -static int i2c_device_probe(struct device *dev) +static int i2c_device_suspend(struct device * dev, pm_message_t mesg) { - return -ENODEV; + struct i2c_driver *driver; + + if (!dev->driver) + return 0; + driver = to_i2c_driver(dev->driver); + if (!driver->suspend) + return 0; + return driver->suspend(to_i2c_client(dev), mesg); } -static int i2c_device_remove(struct device *dev) +static int i2c_device_resume(struct device * dev) { - return 0; + struct i2c_driver *driver; + + if (!dev->driver) + return 0; + driver = to_i2c_driver(dev->driver); + if (!driver->resume) + return 0; + return driver->resume(to_i2c_client(dev)); } struct bus_type i2c_bus_type = { - .name = "i2c", - .match = i2c_device_match, - .probe = i2c_device_probe, - .remove = i2c_device_remove, - .suspend = i2c_bus_suspend, - .resume = i2c_bus_resume, + .name = "i2c", + .match = i2c_device_match, + .probe = i2c_device_probe, + .remove = i2c_device_remove, + .shutdown = i2c_device_shutdown, + .suspend = i2c_device_suspend, + .resume = i2c_device_resume, }; +/* ------------------------------------------------------------------------- */ + void i2c_adapter_dev_release(struct device *dev) { struct i2c_adapter *adap = dev_to_i2c_adapter(dev); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 71e50d3..9428092 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -125,7 +125,12 @@ struct i2c_driver { * it must be freed here. */ int (*detach_client)(struct i2c_client *); - + + /* driver model interfaces that don't relate to enumeration */ + void (*shutdown)(struct i2c_client *); + int (*suspend)(struct i2c_client *, pm_message_t mesg); + int (*resume)(struct i2c_client *); + /* a ioctl like command that can be used to perform specific functions * with the device. */ -- cgit v0.10.2 From a394ae15427f215b43fca21f3c9370b0e63ba252 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:01 +0100 Subject: i2c: Update the list of bus IDs * The Voodoo3 has no SMBus, it has two bit-banged busses which already have an ID assigned (I2C_HW_B_VOO). * The i2c-ipmi bus driver was a non-sense, it'll never be ported to Linux 2.6. Signed-off-by: Jean Delvare Acked-by: Yani Ioannou diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 6e7ec4c..b65c1c9 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -232,7 +232,6 @@ #define I2C_HW_SMBUS_PIIX4 0x040000 #define I2C_HW_SMBUS_ALI15X3 0x040001 #define I2C_HW_SMBUS_VIA2 0x040002 -#define I2C_HW_SMBUS_VOODOO3 0x040003 #define I2C_HW_SMBUS_I801 0x040004 #define I2C_HW_SMBUS_AMD756 0x040005 #define I2C_HW_SMBUS_SIS5595 0x040006 @@ -252,9 +251,6 @@ /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x050000 -/* --- IPMI pseudo-adapter */ -#define I2C_HW_IPMI 0x0b0000 - /* --- IPMB adapter */ #define I2C_HW_IPMB 0x0c0000 -- cgit v0.10.2 From 9ace555d7d87c55ceab6999be444c9a17e0e79b4 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Feb 2007 22:09:01 +0100 Subject: i2c: Add IDs to adapters IDs have been defined but not used by most of the I2C adapters. By having a unique ID, clients can check for correct connection during probe. Signed-off-by: Stephen Hemminger Signed-off-by: Jean Delvare diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index e75d339..0b0a87b 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -475,6 +475,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI1535, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 55ebbef..6b68074 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -370,6 +370,7 @@ static const struct i2c_algorithm ali1563_algorithm = { static struct i2c_adapter ali1563_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI1563, .class = I2C_CLASS_HWMON, .algo = &ali1563_algorithm, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 3f11b6e..c537441 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -470,6 +470,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_ALI15X3, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 2d21afd..91fbc0e 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -301,6 +301,7 @@ static const struct i2c_algorithm smbus_algorithm = { struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_AMD756, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 0fbc718..21f8a82 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -351,6 +351,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, I2C_NAME_SIZE, "SMBus2 AMD8111 adapter at %04x", smbus->base); + smbus->adapter.id = I2C_HW_SMBUS_AMD8111; smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index de5e23a..8c3569a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -442,6 +442,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_I801, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c index 10c98bc..42e8d94 100644 --- a/drivers/i2c/busses/i2c-i810.c +++ b/drivers/i2c/busses/i2c-i810.c @@ -171,6 +171,7 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = { static struct i2c_adapter i810_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_I810, .name = "I810/I815 I2C Adapter", .algo_data = &i810_i2c_bit_data, }; @@ -186,6 +187,7 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = { static struct i2c_adapter i810_ddc_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_I810, .name = "I810/I815 DDC Adapter", .algo_data = &i810_ddc_bit_data, }; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 69d0730..6535551 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -236,6 +236,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, return -1; } smbus->adapter.owner = THIS_MODULE; + smbus->adapter.id = I2C_HW_SMBUS_NFORCE2; smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 07546c2..03d0aee 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -384,6 +384,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_PIIX4, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c index 844b4ff..b7fb65c 100644 --- a/drivers/i2c/busses/i2c-savage4.c +++ b/drivers/i2c/busses/i2c-savage4.c @@ -145,6 +145,7 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = { static struct i2c_adapter savage4_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_SAVAGE, .name = "I2C Savage4 adapter", .algo_data = &sav_i2c_bit_data, }; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 38bbfd8..d333bab 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -365,6 +365,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS5595, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index dec0baf..172bacf 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -457,6 +457,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS630, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 7fd07fb..869a635 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -249,6 +249,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_SIS96X, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 15d7e00..bbcc621 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -86,6 +86,7 @@ static struct i2c_algo_bit_data bit_data = { static struct i2c_adapter vt586b_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VIA, .class = I2C_CLASS_HWMON, .name = "VIA i2c", .algo_data = &bit_data, diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index efc6bbf..43a081f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -306,6 +306,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_SMBUS_VIA2, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index b0377b8..88a3447 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -165,6 +165,7 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VOO, .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, @@ -181,6 +182,7 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = { static struct i2c_adapter voodoo3_ddc_adapter = { .owner = THIS_MODULE, + .id = I2C_HW_B_VOO, .class = I2C_CLASS_DDC, .name = "DDC Voodoo3/Banshee adapter", .algo_data = &voo_ddc_bit_data, diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c index 6cd96e4..c3022a0 100644 --- a/drivers/i2c/busses/scx200_i2c.c +++ b/drivers/i2c/busses/scx200_i2c.c @@ -81,6 +81,7 @@ static struct i2c_algo_bit_data scx200_i2c_data = { static struct i2c_adapter scx200_i2c_ops = { .owner = THIS_MODULE, + .id = I2C_HW_B_SCX200, .algo_data = &scx200_i2c_data, .name = "NatSemi SCx200 I2C", }; diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index b65c1c9..9c21dc7 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -247,6 +247,7 @@ #define I2C_HW_SMBUS_OV519 0x040010 /* OV519 USB 1.1 webcam IC */ #define I2C_HW_SMBUS_OVFX2 0x040011 /* Cypress/OmniVision FX2 webcam */ #define I2C_HW_SMBUS_CAFE 0x040012 /* Marvell 88ALP01 "CAFE" cam */ +#define I2C_HW_SMBUS_ALI1563 0x040013 /* --- ISA pseudo-adapter */ #define I2C_HW_ISA 0x050000 -- cgit v0.10.2 From ab6a6ed271c757b429ddc68f5b93a41f9592ab8b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:02 +0100 Subject: i2c-viapro: Add support for the VIA CX700 south bridge We do not have any documentation for the CX700, but it was reported to work fine. Thanks to Claas Langbehn for testing. Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro index 2568034..775f489 100644 --- a/Documentation/i2c/busses/i2c-viapro +++ b/Documentation/i2c/busses/i2c-viapro @@ -13,6 +13,9 @@ Supported adapters: * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251 Datasheet: available on request and under NDA from VIA + * VIA Technologies, Inc. CX700 + Datasheet: available on request and under NDA from VIA + Authors: Kyösti Mälkki , Mark D. Studebaker , @@ -44,6 +47,7 @@ Your lspci -n listing must show one of these : device 1106:3227 (VT8237R) device 1106:3337 (VT8237A) device 1106:3287 (VT8251) + device 1106:8324 (CX700) If none of these show up, you should look in the BIOS for settings like enable ACPI / SMBus or even USB. @@ -51,3 +55,6 @@ enable ACPI / SMBus or even USB. Except for the oldest chips (VT82C596A/B, VT82C686A and most probably VT8231), this driver supports I2C block transactions. Such transactions are mainly useful to read from and write to EEPROMs. + +The CX700 additionally appears to support SMBus PEC, although this driver +doesn't implement it yet. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f2894de..25d52e0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -500,11 +500,11 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA 82C596/82C686/82xx" + tristate "VIA VT82C596/82C686/82xx and CX700" depends on I2C && PCI help If you say yes to this option, support will be included for the VIA - 82C596/82C686/82xx I2C interfaces. Specifically, the following + VT82C596 and later SMBus interface. Specifically, the following chipsets are supported: VT82C596A/B VT82C686A/B @@ -513,6 +513,7 @@ config I2C_VIAPRO VT8235 VT8237R/A VT8251 + CX700 This driver can also be built as a module. If so, the module will be called i2c-viapro. diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 43a081f..03c5fc8 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -4,7 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard , Philip Edelbrock , Kyösti Mälkki , Mark D. Studebaker - Copyright (C) 2005 Jean Delvare + Copyright (C) 2005 - 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 @@ -36,6 +36,7 @@ VT8237R 0x3227 yes VT8237A 0x3337 yes VT8251 0x3287 yes + CX700 0x8324 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -384,6 +385,7 @@ found: dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); switch (pdev->device) { + case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -443,6 +445,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700), + .driver_data = SMBBA3 }, { 0, } }; -- cgit v0.10.2 From 55249cf750e4d9be19c7f8afd502c9ca42de8858 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Tue, 13 Feb 2007 22:09:02 +0100 Subject: i2c-parport: Add support for One For All remote JP1 interface This simple patch adds support to i2c-parport for the One For All remote JP1 parallel port interfaces which can be found detailed at: http://www.hifi-remote.com/jp1/hardware.shtml These allow access to the internal configuration EEPROM on various remote controls and there are a variety of Windows tools that make use of this hardware. I have tested this patch with the "simple" parallel port device and a One For All URC-7562 and confirmed that the data read using the eeprom i2c driver matches that returned by the Windows "IR" JP1 tool. Signed-off-by: Jonathan McDowell Signed-off-by: Jean Delvare diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index 77b995d..dceaba1 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -19,6 +19,7 @@ It currently supports the following devices: * (type=4) Analog Devices ADM1032 evaluation board * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 * (type=6) Barco LPT->DVI (K5800236) adapter + * (type=7) One For All JP1 parallel port adapter These devices use different pinout configurations, so you have to tell the driver what you have, using the type module parameter. There is no @@ -157,3 +158,17 @@ many more, using /dev/velleman. http://home.wanadoo.nl/hihihi/libk8005.htm http://struyve.mine.nu:8080/index.php?block=k8000 http://sourceforge.net/projects/libk8005/ + + +One For All JP1 parallel port adapter +------------------------------------- + +The JP1 project revolves around a set of remote controls which expose +the I2C bus their internal configuration EEPROM lives on via a 6 pin +jumper in the battery compartment. More details can be found at: + +http://www.hifi-remote.com/jp1/ + +Details of the simple parallel port hardware can be found at: + +http://www.hifi-remote.com/jp1/hardware.shtml diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index 9ddd816..ed69d84 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -88,6 +88,13 @@ static struct adapter_parm adapter_parm[] = { .getscl = { 0x40, STAT, 0 }, .init = { 0xfc, DATA, 0 }, }, + /* type 7: One For All JP1 parallel port adapter */ + { + .setsda = { 0x01, DATA, 0 }, + .setscl = { 0x02, DATA, 0 }, + .getsda = { 0x80, STAT, 1 }, + .init = { 0x04, DATA, 1 }, + }, }; static int type = -1; @@ -101,4 +108,5 @@ MODULE_PARM_DESC(type, " 4 = ADM1032 evaluation board\n" " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" " 6 = Barco LPT->DVI (K5800236) adapter\n" + " 7 = One For All JP1 parallel port adapter\n" ); -- cgit v0.10.2 From 88b9e750e974febd9128fc622109c526a9d22c10 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:02 +0100 Subject: i2c-amd8111: Proposed cleanups Proposed cleanups to the i2c-amd8111 SMBus driver: * Fold long lines. * Add an explicit mask when writing the low byte of a word. * Use I2C_SMBUS_BLOCK_MAX instead of hardcoding 32. * Discard extra blank lines. * Use boolean not instead of bitwise not for bit tests, it's clearer. * Return -EBUSY rather than -1 on I/O resource conflict. * Fix a race on device registration, initialization should be done before the bus is registered. Signed-off-by: Jean Delvare diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 21f8a82..14ad991 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -76,7 +76,8 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus) udelay(1); if (!timeout) { - dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n"); + dev_warn(&smbus->dev->dev, + "Timeout while waiting for IBF to clear\n"); return -1; } @@ -91,14 +92,16 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus) udelay(1); if (!timeout) { - dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n"); + dev_warn(&smbus->dev->dev, + "Timeout while waiting for OBF to set\n"); return -1; } return 0; } -static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data) +static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, + unsigned char *data) { if (amd_ec_wait_write(smbus)) return -1; @@ -115,7 +118,8 @@ static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, return 0; } -static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data) +static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, + unsigned char data) { if (amd_ec_wait_write(smbus)) return -1; @@ -175,18 +179,19 @@ static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, #define AMD_SMB_PRTCL_PEC 0x80 -static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags, - char read_write, u8 command, int size, union i2c_smbus_data * data) +static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, + unsigned short flags, char read_write, u8 command, int size, + union i2c_smbus_data * data) { struct amd_smbus *smbus = adap->algo_data; unsigned char protocol, len, pec, temp[2]; int i; - protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE; + protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ + : AMD_SMB_PRTCL_WRITE; pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0; switch (size) { - case I2C_SMBUS_QUICK: protocol |= AMD_SMB_PRTCL_QUICK; read_write = I2C_SMBUS_WRITE; @@ -208,8 +213,10 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl case I2C_SMBUS_WORD_DATA: amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { - amd_ec_write(smbus, AMD_SMB_DATA, data->word); - amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); + amd_ec_write(smbus, AMD_SMB_DATA, + data->word & 0xff); + amd_ec_write(smbus, AMD_SMB_DATA + 1, + data->word >> 8); } protocol |= AMD_SMB_PRTCL_WORD_DATA | pec; break; @@ -217,27 +224,31 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl case I2C_SMBUS_BLOCK_DATA: amd_ec_write(smbus, AMD_SMB_CMD, command); if (read_write == I2C_SMBUS_WRITE) { - len = min_t(u8, data->block[0], 32); + len = min_t(u8, data->block[0], + I2C_SMBUS_BLOCK_MAX); amd_ec_write(smbus, AMD_SMB_BCNT, len); for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); } protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec; break; case I2C_SMBUS_I2C_BLOCK_DATA: - len = min_t(u8, data->block[0], 32); + len = min_t(u8, data->block[0], + I2C_SMBUS_BLOCK_MAX); amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); if (read_write == I2C_SMBUS_WRITE) for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA; break; case I2C_SMBUS_PROC_CALL: amd_ec_write(smbus, AMD_SMB_CMD, command); - amd_ec_write(smbus, AMD_SMB_DATA, data->word); + amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff); amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8); protocol = AMD_SMB_PRTCL_PROC_CALL | pec; read_write = I2C_SMBUS_READ; @@ -248,7 +259,8 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl amd_ec_write(smbus, AMD_SMB_CMD, command); amd_ec_write(smbus, AMD_SMB_BCNT, len); for (i = 0; i < len; i++) - amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]); + amd_ec_write(smbus, AMD_SMB_DATA + i, + data->block[i + 1]); protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec; read_write = I2C_SMBUS_READ; break; @@ -280,7 +292,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl return 0; switch (size) { - case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: amd_ec_read(smbus, AMD_SMB_DATA, &data->byte); @@ -296,10 +307,11 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: amd_ec_read(smbus, AMD_SMB_BCNT, &len); - len = min_t(u8, len, 32); + len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < len; i++) - amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1); + amd_ec_read(smbus, AMD_SMB_DATA + i, + data->block + i + 1); data->block[0] = len; break; } @@ -310,7 +322,8 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl static u32 amd8111_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC; @@ -329,12 +342,13 @@ static struct pci_device_id amd8111_ids[] = { MODULE_DEVICE_TABLE (pci, amd8111_ids); -static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int __devinit amd8111_probe(struct pci_dev *dev, + const struct pci_device_id *id) { struct amd_smbus *smbus; - int error = -ENODEV; + int error; - if (~pci_resource_flags(dev, 0) & IORESOURCE_IO) + if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) return -ENODEV; smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL); @@ -345,8 +359,10 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ smbus->base = pci_resource_start(dev, 0); smbus->size = pci_resource_len(dev, 0); - if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) + if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) { + error = -EBUSY; goto out_kfree; + } smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, I2C_NAME_SIZE, @@ -359,11 +375,11 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ /* set up the driverfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; + pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); error = i2c_add_adapter(&smbus->adapter); if (error) goto out_release_region; - pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0); pci_set_drvdata(dev, smbus); return 0; @@ -371,10 +387,9 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_ release_region(smbus->base, smbus->size); out_kfree: kfree(smbus); - return -1; + return error; } - static void __devexit amd8111_remove(struct pci_dev *dev) { struct amd_smbus *smbus = pci_get_drvdata(dev); @@ -396,7 +411,6 @@ static int __init i2c_amd8111_init(void) return pci_register_driver(&amd8111_driver); } - static void __exit i2c_amd8111_exit(void) { pci_unregister_driver(&amd8111_driver); -- cgit v0.10.2 From beb58aa39e6e5a52875defe12c7697b0bfa95d4c Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Tue, 13 Feb 2007 22:09:03 +0100 Subject: i2c: PA Semi SMBus driver New driver for the PA Semi SMBus interfaces. Signed-off-by: Olof Johansson Signed-off-by: Jean Delvare diff --git a/MAINTAINERS b/MAINTAINERS index f85c603..93a338d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2523,6 +2523,12 @@ M: olof@lixom.net L: netdev@vger.kernel.org S: Maintained +PA SEMI SMBUS DRIVER +P: Olof Johansson +M: olof@lixom.net +L: i2c@lm-sensors.org +S: Maintained + PARALLEL PORT SUPPORT P: Phil Blundell M: philb@gnu.org diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 25d52e0..4d44a2d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -342,6 +342,13 @@ config I2C_PARPORT_LIGHT This support is also available as a module. If so, the module will be called i2c-parport-light. +config I2C_PASEMI + tristate "PA Semi SMBus interface" +# depends on PPC_PASEMI && I2C && PCI + depends on I2C && PCI + help + Supports the PA Semi PWRficient on-chip SMBus interfaces. + config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" depends on I2C && PCI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37196c1..03505aa 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o +obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c new file mode 100644 index 0000000..f54fb5d --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * SMBus host driver for PA Semi PWRficient + * + * 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. + * + * 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 + +static struct pci_driver pasemi_smb_driver; + +struct pasemi_smbus { + struct pci_dev *dev; + struct i2c_adapter adapter; + unsigned long base; + int size; +}; + +/* Register offsets */ +#define REG_MTXFIFO 0x00 +#define REG_MRXFIFO 0x04 +#define REG_SMSTA 0x14 +#define REG_CTL 0x1c + +/* Register defs */ +#define MTXFIFO_READ 0x00000400 +#define MTXFIFO_STOP 0x00000200 +#define MTXFIFO_START 0x00000100 +#define MTXFIFO_DATA_M 0x000000ff + +#define MRXFIFO_EMPTY 0x00000100 +#define MRXFIFO_DATA_M 0x000000ff + +#define SMSTA_XEN 0x08000000 + +#define CTL_MRR 0x00000400 +#define CTL_MTR 0x00000200 +#define CTL_CLK_M 0x000000ff + +#define CLK_100K_DIV 84 +#define CLK_400K_DIV 21 + +static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val) +{ + dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n", + smbus->base + reg, val); + outl(val, smbus->base + reg); +} + +static inline int reg_read(struct pasemi_smbus *smbus, int reg) +{ + int ret; + ret = inl(smbus->base + reg); + dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n", + smbus->base + reg, ret); + return ret; +} + +#define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg)) +#define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO) + +static void pasemi_smb_clear(struct pasemi_smbus *smbus) +{ + unsigned int status; + + status = reg_read(smbus, REG_SMSTA); + reg_write(smbus, REG_SMSTA, status); +} + +static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus) +{ + int timeout = 10; + unsigned int status; + + status = reg_read(smbus, REG_SMSTA); + + while (!(status & SMSTA_XEN) && timeout--) { + msleep(1); + status = reg_read(smbus, REG_SMSTA); + } + + if (timeout < 0) { + dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status); + reg_write(smbus, REG_SMSTA, status); + return -ETIME; + } + + /* Clear XEN */ + reg_write(smbus, REG_SMSTA, SMSTA_XEN); + + return 0; +} + +static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, + struct i2c_msg *msg, int stop) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + int read, i, err; + u32 rd; + + read = msg->flags & I2C_M_RD ? 1 : 0; + + TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read); + + if (read) { + TXFIFO_WR(smbus, msg->len | MTXFIFO_READ | + (stop ? MTXFIFO_STOP : 0)); + + err = pasemi_smb_waitready(smbus); + if (err) + goto reset_out; + + for (i = 0; i < msg->len; i++) { + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + msg->buf[i] = rd & MRXFIFO_DATA_M; + } + } else { + for (i = 0; i < msg->len - 1; i++) + TXFIFO_WR(smbus, msg->buf[i]); + + TXFIFO_WR(smbus, msg->buf[msg->len] | + (stop ? MTXFIFO_STOP : 0)); + } + + return 0; + + reset_out: + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + return err; +} + +static int pasemi_i2c_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + int ret, i; + + pasemi_smb_clear(smbus); + + ret = 0; + + for (i = 0; i < num && !ret; i++) + ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1))); + + return ret ? ret : num; +} + +static int pasemi_smb_xfer(struct i2c_adapter *adapter, + u16 addr, unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + struct pasemi_smbus *smbus = adapter->algo_data; + unsigned int rd; + int read_flag, err; + int len = 0, i; + + /* All our ops take 8-bit shifted addresses */ + addr <<= 1; + read_flag = read_write == I2C_SMBUS_READ; + + pasemi_smb_clear(smbus); + + switch (size) { + case I2C_SMBUS_QUICK: + TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START | + MTXFIFO_STOP); + break; + case I2C_SMBUS_BYTE: + TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START); + if (read_write) + TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ); + else + TXFIFO_WR(smbus, MTXFIFO_STOP | command); + break; + case I2C_SMBUS_BYTE_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP); + } else { + TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte); + } + break; + case I2C_SMBUS_WORD_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP); + } else { + TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8)); + } + break; + case I2C_SMBUS_BLOCK_DATA: + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + if (read_write) { + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 1 | MTXFIFO_READ); + rd = RXFIFO_RD(smbus); + len = min_t(u8, (rd & MRXFIFO_DATA_M), + I2C_SMBUS_BLOCK_MAX); + TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ | + MTXFIFO_STOP); + } else { + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); + TXFIFO_WR(smbus, len); + for (i = 1; i < len; i++) + TXFIFO_WR(smbus, data->block[i]); + TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP); + } + break; + case I2C_SMBUS_PROC_CALL: + read_write = I2C_SMBUS_READ; + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M); + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START); + TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ); + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1); + read_write = I2C_SMBUS_READ; + TXFIFO_WR(smbus, addr | MTXFIFO_START); + TXFIFO_WR(smbus, command); + TXFIFO_WR(smbus, len); + for (i = 1; i <= len; i++) + TXFIFO_WR(smbus, data->block[i]); + TXFIFO_WR(smbus, addr | I2C_SMBUS_READ); + TXFIFO_WR(smbus, MTXFIFO_READ | 1); + rd = RXFIFO_RD(smbus); + len = min_t(u8, (rd & MRXFIFO_DATA_M), + I2C_SMBUS_BLOCK_MAX - len); + TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ | MTXFIFO_STOP); + break; + + default: + dev_warn(&adapter->dev, "Unsupported transaction %d\n", size); + return -EINVAL; + } + + err = pasemi_smb_waitready(smbus); + if (err) + goto reset_out; + + if (read_write == I2C_SMBUS_WRITE) + return 0; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->byte = rd & MRXFIFO_DATA_M; + break; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->word = rd & MRXFIFO_DATA_M; + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->word |= (rd & MRXFIFO_DATA_M) << 8; + break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + data->block[0] = len; + for (i = 1; i <= len; i ++) { + rd = RXFIFO_RD(smbus); + if (rd & MRXFIFO_EMPTY) { + err = -ENODATA; + goto reset_out; + } + data->block[i] = rd & MRXFIFO_DATA_M; + } + break; + } + + return 0; + + reset_out: + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + return err; +} + +static u32 pasemi_smb_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C; +} + +static const struct i2c_algorithm smbus_algorithm = { + .master_xfer = pasemi_i2c_xfer, + .smbus_xfer = pasemi_smb_xfer, + .functionality = pasemi_smb_func, +}; + +static int __devinit pasemi_smb_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pasemi_smbus *smbus; + int error; + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) + return -ENODEV; + + smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL); + if (!smbus) + return -ENOMEM; + + smbus->dev = dev; + smbus->base = pci_resource_start(dev, 0); + smbus->size = pci_resource_len(dev, 0); + + if (!request_region(smbus->base, smbus->size, + pasemi_smb_driver.name)) { + error = -EBUSY; + goto out_kfree; + } + + smbus->adapter.owner = THIS_MODULE; + snprintf(smbus->adapter.name, I2C_NAME_SIZE, + "PA Semi SMBus adapter at 0x%lx", smbus->base); + smbus->adapter.class = I2C_CLASS_HWMON; + smbus->adapter.algo = &smbus_algorithm; + smbus->adapter.algo_data = smbus; + + /* set up the driverfs linkage to our parent device */ + smbus->adapter.dev.parent = &dev->dev; + + reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | + (CLK_100K_DIV & CTL_CLK_M))); + + error = i2c_add_adapter(&smbus->adapter); + if (error) + goto out_release_region; + + pci_set_drvdata(dev, smbus); + + return 0; + + out_release_region: + release_region(smbus->base, smbus->size); + out_kfree: + kfree(smbus); + return error; +} + +static void __devexit pasemi_smb_remove(struct pci_dev *dev) +{ + struct pasemi_smbus *smbus = pci_get_drvdata(dev); + + i2c_del_adapter(&smbus->adapter); + release_region(smbus->base, smbus->size); + kfree(smbus); +} + +static struct pci_device_id pasemi_smb_ids[] = { + { PCI_DEVICE(0x1959, 0xa003) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, pasemi_smb_ids); + +static struct pci_driver pasemi_smb_driver = { + .name = "i2c-pasemi", + .id_table = pasemi_smb_ids, + .probe = pasemi_smb_probe, + .remove = __devexit_p(pasemi_smb_remove), +}; + +static int __init pasemi_smb_init(void) +{ + return pci_register_driver(&pasemi_smb_driver); +} + +static void __exit pasemi_smb_exit(void) +{ + pci_unregister_driver(&pasemi_smb_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR ("Olof Johansson "); +MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); + +module_init(pasemi_smb_init); +module_exit(pasemi_smb_exit); -- cgit v0.10.2 From 12a917f69d1468c91d646dbad8408dd0d39d6207 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:03 +0100 Subject: i2c: Declare more i2c_adapter parent devices Declare the parent device of i2c_adapter devices each time we can easily do so. It makes the i2c_adapter appear at the right place in the device tree, rather than as a platform device. Signed-off-by: Jean Delvare Cc: David Brownell Cc: Len Brown Cc: Jordan Crouse Cc: Jody McIntyre Cc: Stefan Richter Cc: v4l-dvb-maintainer@linuxtv.org Cc: Petr Vandrovec diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 8338be0..bb54b6c 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -340,6 +340,7 @@ static int acpi_ec_hc_add(struct acpi_device *device) smbus->adapter.owner = THIS_MODULE; smbus->adapter.algo = &acpi_ec_smbus_algorithm; smbus->adapter.algo_data = smbus; + smbus->adapter.dev.parent = &device->dev; if (i2c_add_adapter(&smbus->adapter)) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index 08e9157..e5e96c8 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -184,12 +184,14 @@ static int __init amd756_s4882_init(void) s4882_algo[0].smbus_xfer = amd756_access_virt0; s4882_adapter[0] = amd756_smbus; s4882_adapter[0].algo = s4882_algo; + s4882_adapter[0].dev.parent = amd756_smbus.dev.parent; for (i = 1; i < 5; i++) { s4882_algo[i] = *(amd756_smbus.algo); s4882_adapter[i] = amd756_smbus; sprintf(s4882_adapter[i].name, "SMBus 8111 adapter (CPU%d)", i-1); s4882_adapter[i].algo = s4882_algo+i; + s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; } s4882_algo[1].smbus_xfer = amd756_access_virt1; s4882_algo[2].smbus_xfer = amd756_access_virt2; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 1898e99..8b14d14 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -727,6 +727,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ /* Register it with i2c layer */ adap = &dev->adap; + adap->dev.parent = &ocp->dev; strcpy(adap->name, "IBM IIC"); i2c_set_adapdata(adap, dev); adap->id = I2C_HW_OCP; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 4901736..a3283b9 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -520,6 +520,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) rc = -ENXIO; goto exit_unmap_regs; } + drv_data->adapter.dev.parent = &pd->dev; drv_data->adapter.id = I2C_HW_MV64XXX; drv_data->adapter.algo = &mv64xxx_i2c_algo; drv_data->adapter.owner = THIS_MODULE; diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 714bae7..0b082c5 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -428,7 +428,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface) } static __init struct scx200_acb_iface *scx200_create_iface(const char *text, - int index) + struct device *dev, int index) { struct scx200_acb_iface *iface; struct i2c_adapter *adapter; @@ -446,6 +446,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; adapter->class = I2C_CLASS_HWMON; + adapter->dev.parent = dev; mutex_init(&iface->mutex); @@ -486,7 +487,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev, struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, 0); + iface = scx200_create_iface(text, &pdev->dev, 0); if (iface == NULL) return -ENOMEM; @@ -524,7 +525,7 @@ static int __init scx200_create_isa(const char *text, unsigned long base, struct scx200_acb_iface *iface; int rc; - iface = scx200_create_iface(text, index); + iface = scx200_create_iface(text, NULL, index); if (iface == NULL) return -ENOMEM; diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index fbb7f14..0742bef 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -1434,6 +1434,7 @@ static int __devinit add_card(struct pci_dev *dev, i2c_adapter_data = bit_data; i2c_ad->algo_data = &i2c_adapter_data; i2c_adapter_data.data = lynx; + i2c_ad->dev.parent = &dev->dev; PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d", reg_read(lynx, SERIAL_EEPROM_CONTROL)); diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index e0bd2d8..5347a40 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -190,6 +190,7 @@ int flexcop_i2c_init(struct flexcop_device *fc) fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL; fc->i2c_adap.algo = &flexcop_algo; fc->i2c_adap.algo_data = NULL; + fc->i2c_adap.dev.parent = fc->dev; if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0) return ret; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 55ba020..70df31b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -27,6 +27,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) #endif d->i2c_adap.algo = d->props.i2c_algo; d->i2c_adap.algo_data = NULL; + d->i2c_adap.dev.parent = &d->udev->dev; i2c_set_adapdata(&d->i2c_adap, d); diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 60820de..b60cdc9 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1690,6 +1690,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i #endif ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; + ttusb->i2c_adap.dev.parent = &udev->dev; result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index fb1410c..4dae892 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -549,6 +549,7 @@ static int cafe_smbus_setup(struct cafe_camera *cam) adap->client_unregister = cafe_smbus_detach; adap->algo = &cafe_smbus_algo; strcpy(adap->name, "cafe_ccic"); + adap->dev.parent = &cam->pdev->dev; i2c_set_adapdata(adap, cam); ret = i2c_add_adapter(adap); if (ret) diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index f9bb41d..62a7cfc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -977,6 +977,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo)); strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name)); + hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev; hdw->i2c_adap.algo = &hdw->i2c_algo; hdw->i2c_adap.algo_data = hdw; hdw->i2c_pend_mask = 0; diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 858252c..a242b76 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -258,6 +258,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), " #%d", usbvision->vdev->minor & 0x1f); PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); + usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; i2c_set_adapdata(&usbvision->i2c_adap, usbvision); i2c_set_clientdata(&usbvision->i2c_client, usbvision); diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 6e64af2..8f31613 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -1573,6 +1573,7 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam) memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter)); strcpy(cam->i2c_adapter.name, "w9968cf"); + cam->i2c_adapter.dev.parent = &cam->usbdev->dev; i2c_set_adapdata(&cam->i2c_adapter, cam); DBG(6, "Registering I2C adapter with kernel...") diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 4d1eb2f..73162a3 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -843,6 +843,7 @@ zoran_register_i2c (struct zoran *zr) sizeof(I2C_NAME(&zr->i2c_adapter)) - 1); i2c_set_adapdata(&zr->i2c_adapter, zr); zr->i2c_adapter.algo_data = &zr->i2c_algo; + zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; return i2c_bit_add_bus(&zr->i2c_adapter); } diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index f64c4a0..5ec718a 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -115,6 +115,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, minfo->fbcon.node); i2c_set_adapdata(&b->adapter, b); b->adapter.algo_data = &b->bac; + b->adapter.dev.parent = &ACCESS_FBINFO(pcidev)->dev; b->bac = matrox_i2c_algo_template; b->bac.data = b; err = i2c_bit_add_bus(&b->adapter); -- cgit v0.10.2 From fe2c8d51af96ef7b8ec0bfd70ec62bbe32c0696e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:04 +0100 Subject: i2c: Remove the warning on missing adapter device Now that the i2c_adapter migration plan changed and we are going to keep i2c_adapter.dev, it's no longer that urgent to add a proper device to all i2c_adapter drivers. Thus is seems resonable to degrade the warning asking authors to migrate their driver to a debug message. Signed-off-by: Jean Delvare diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9653f7f..21fe140 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -217,9 +217,8 @@ int i2c_add_adapter(struct i2c_adapter *adap) */ if (adap->dev.parent == NULL) { adap->dev.parent = &platform_bus; - printk(KERN_WARNING "**WARNING** I2C adapter driver [%s] " - "forgot to specify physical device; fix it!\n", - adap->name); + pr_debug("I2C adapter driver [%s] forgot to specify " + "physical device\n", adap->name); } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); adap->dev.driver = &i2c_adapter_driver; -- cgit v0.10.2 From 5dd3ffae0afe355738eca14da1b47284bdae6240 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Feb 2007 22:09:04 +0100 Subject: i2c: Stop using i2c_adapter.class_dev Stop using i2c_adapter.class_dev, as it is going to be removed soon. Luckily, there are only 4 RTC drivers affected. Signed-off-by: Jean Delvare Cc: Alessandro Zummo diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 205fa28..dfef163 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 038118b..0242d80 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -279,7 +279,7 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) int err = 0; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index e7851e3..09bbe575 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -499,7 +499,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) struct rs5c372 *rs5c372; struct rtc_time tm; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 019ae25..513d1a6 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -506,7 +506,7 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *client; struct rtc_device *rtc; - dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__); + dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { err = -ENODEV; -- cgit v0.10.2