Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  i2c: Document the message size limit
  i2c-algo-pca: Drop duplicate variable
  i2c: Hook up runtime PM support
  i2c-parport-light: Add SMBus alert support
  i2c-parport: Add SMBus alert support
  i2c: Separate Kconfig option for i2c-smbus
  i2c: Add SMBus alert support
  i2c-parport: Give powered devices some time to settle
  i2c-tiny-usb: Fix a comment on bus frequency
  i2c-i801: Add Intel Cougar Point device IDs
  i2c: Make PCI device ids constant
This commit is contained in:
Linus Torvalds 2010-03-03 07:34:47 -08:00
commit a03696e912
33 changed files with 537 additions and 38 deletions

View File

@ -15,7 +15,8 @@ Supported adapters:
* Intel 82801I (ICH9)
* Intel EP80579 (Tolapai)
* Intel 82801JI (ICH10)
* Intel PCH
* Intel 3400/5 Series (PCH)
* Intel Cougar Point (PCH)
Datasheets: Publicly available at the Intel website
Authors:

View File

@ -29,6 +29,9 @@ can be easily added when needed.
Earlier kernels defaulted to type=0 (Philips). But now, if the type
parameter is missing, the driver will simply fail to initialize.
SMBus alert support is available on adapters which have this line properly
connected to the parallel port's interrupt pin.
Building your own adapter
-------------------------

View File

@ -9,3 +9,14 @@ parport handling is not an option. The drawback is a reduced portability
and the impossibility to daisy-chain other parallel port devices.
Please see i2c-parport for documentation.
Module parameters:
* type: type of adapter (see i2c-parport or modinfo)
* base: base I/O address
Default is 0x378 which is fairly common for parallel ports, at least on PC.
* irq: optional IRQ
This must be passed if you want SMBus alert support, assuming your adapter
actually supports this.

View File

@ -185,6 +185,22 @@ the protocol. All ARP communications use slave address 0x61 and
require PEC checksums.
SMBus Alert
===========
SMBus Alert was introduced in Revision 1.0 of the specification.
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 implemented the following way in the Linux kernel:
* I2C bus drivers which support SMBus alert should call
i2c_setup_smbus_alert() to setup SMBus alert support.
* I2C drivers for devices which can trigger SMBus alerts should implement
the optional alert() callback.
I2C Block Transactions
======================

View File

@ -318,8 +318,9 @@ Plain I2C communication
These routines read and write some bytes from/to a client. The client
contains the i2c address, so you do not have to include it. The second
parameter contains the bytes to read/write, the third the number of bytes
to read/write (must be less than the length of the buffer.) Returned is
the actual number of bytes read/written.
to read/write (must be less than the length of the buffer, also should be
less than 64k since msg.len is u16.) Returned is the actual number of bytes
read/written.
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num);

View File

@ -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

View File

@ -4,6 +4,7 @@
obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.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/

View File

@ -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
*/

View File

@ -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.
@ -580,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.
@ -603,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.

View File

@ -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) },
{ },
};

View File

@ -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) },
{},
};

View File

@ -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, }
};

View File

@ -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),

View File

@ -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, }
};

View File

@ -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, }
};

View File

@ -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
@ -561,7 +562,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) },
@ -578,6 +579,7 @@ static 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:

View File

@ -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, }
};

View File

@ -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) },

View File

@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@ -27,10 +27,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-smbus.h>
#include <asm/io.h>
#include "i2c-parport.h"
@ -43,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)
@ -119,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;
@ -127,18 +143,39 @@ 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);
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...) */
@ -205,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;

View File

@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@ -27,9 +27,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/parport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-smbus.h>
#include "i2c-parport.h"
/* ----- Device list ------------------------------------------------------ */
@ -38,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;
};
@ -143,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;
@ -154,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;
@ -185,14 +203,29 @@ 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");
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;
@ -213,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...) */

View File

@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.h I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
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 */
{

View File

@ -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, }
};

View File

@ -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) },

View File

@ -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, }
};

View File

@ -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, }

View File

@ -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, }
};

View File

@ -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);
@ -137,7 +139,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 */

View File

@ -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, }
};

View File

@ -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),

View File

@ -34,6 +34,7 @@
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#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 = {
@ -1133,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.
*/
@ -1160,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.
*/

263
drivers/i2c/i2c-smbus.c Normal file
View File

@ -0,0 +1,263 @@
/*
* i2c-smbus.c - SMBus extensions to the I2C protocol
*
* Copyright (C) 2008 David Brownell
* Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
*
* 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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
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 <khali@linux-fr.org>");
MODULE_DESCRIPTION("SMBus protocol extensions support");
MODULE_LICENSE("GPL");

50
include/linux/i2c-smbus.h Normal file
View File

@ -0,0 +1,50 @@
/*
* i2c-smbus.h - SMBus extensions to the I2C protocol
*
* Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
*
* 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.
*/
#ifndef _LINUX_I2C_SMBUS_H
#define _LINUX_I2C_SMBUS_H
#include <linux/i2c.h>
/**
* i2c_smbus_alert_setup - platform data for the smbus_alert i2c client
* @alert_edge_triggered: whether the alert interrupt is edge (1) or level (0)
* triggered
* @irq: IRQ number, if the smbus_alert driver should take care of interrupt
* handling
*
* If irq is not specified, the smbus_alert driver doesn't take care of
* interrupt handling. In that case it is up to the I2C bus driver to either
* handle the interrupts or to poll for alerts.
*
* If irq is specified then it it crucial that alert_edge_triggered is
* properly set.
*/
struct i2c_smbus_alert_setup {
unsigned int alert_edge_triggered:1;
int irq;
};
struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
struct i2c_smbus_alert_setup *setup);
int i2c_handle_smbus_alert(struct i2c_client *ara);
#endif /* _LINUX_I2C_SMBUS_H */

View File

@ -53,6 +53,7 @@ struct i2c_board_info;
* on a bus (or read from them). Apart from two basic transfer functions to
* transmit one message at a time, a more complex version can be used to
* transmit an arbitrary number of messages without interruption.
* @count must be be less than 64k since msg.len is u16.
*/
extern int i2c_master_send(struct i2c_client *client, const char *buf,
int count);
@ -152,6 +153,13 @@ struct i2c_driver {
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
/* Alert callback, for example for the SMBus alert protocol.
* The format and meaning of the data value depends on the protocol.
* For the SMBus alert protocol, there is a single bit of data passed
* as the alert response's low bit ("event flag").
*/
void (*alert)(struct i2c_client *, unsigned int data);
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/