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:
Коммит
a03696e912
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
-------------------------
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
======================
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -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) },
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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...) */
|
||||
|
|
|
@ -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 */
|
||||
{
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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, }
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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");
|
|
@ -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 */
|
|
@ -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.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче