summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig151
-rw-r--r--drivers/i2c/busses/Makefile4
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-at91.c1
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c644
-rw-r--r--drivers/i2c/busses/i2c-elektor.c51
-rw-r--r--drivers/i2c/busses/i2c-gpio.c215
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-isa.c43
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c2
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c1
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c2
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c6
-rw-r--r--drivers/i2c/busses/i2c-omap.c3
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c144
-rw-r--r--drivers/i2c/busses/i2c-parport.c25
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c2
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c36
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c15
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c96
-rw-r--r--drivers/i2c/busses/i2c-simtec.c186
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c277
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c3
29 files changed, 1718 insertions, 205 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ece31d2c6c6..838dc1c19d6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -3,11 +3,10 @@
#
menu "I2C Hardware Bus support"
- depends on I2C
config I2C_ALI1535
tristate "ALI 1535"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
@@ -19,7 +18,7 @@ config I2C_ALI1535
config I2C_ALI1563
tristate "ALI 1563"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
@@ -31,7 +30,7 @@ config I2C_ALI1563
config I2C_ALI15X3
tristate "ALI 15x3"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
@@ -41,7 +40,7 @@ config I2C_ALI15X3
config I2C_AMD756
tristate "AMD 756/766/768/8111 and nVidia nForce"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the AMD
756/766/768 mainboard I2C interfaces. The driver also includes
@@ -66,7 +65,7 @@ config I2C_AMD756_S4882
config I2C_AMD8111
tristate "AMD 8111"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
@@ -76,14 +75,14 @@ config I2C_AMD8111
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on I2C && ARCH_AT91 && EXPERIMENTAL
+ depends on ARCH_AT91 && EXPERIMENTAL
help
This supports the use of the I2C interface on Atmel AT91
processors.
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
- depends on I2C && (SOC_AU1550 || SOC_AU1200)
+ depends on SOC_AU1550 || SOC_AU1200
help
If you say yes to this option, support will be included for the
Au1550 and Au1200 SMBus interface.
@@ -91,9 +90,25 @@ config I2C_AU1550
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
+config I2C_BLACKFIN_TWI
+ tristate "Blackfin TWI I2C support"
+ depends on BF534 || BF536 || BF537
+ help
+ This is the TWI I2C device driver for Blackfin 534/536/537.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+ int "Blackfin TWI I2C clock (kHz)"
+ depends on I2C_BLACKFIN_TWI
+ range 10 400
+ default 50
+ help
+ The unit of the TWI clock is kHz.
+
config I2C_ELEKTOR
tristate "Elektor ISA card"
- depends on I2C && ISA && BROKEN_ON_SMP
+ depends on ISA && BROKEN_ON_SMP
select I2C_ALGOPCF
help
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
@@ -102,9 +117,17 @@ config I2C_ELEKTOR
This support is also available as a module. If so, the module
will be called i2c-elektor.
+config I2C_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GENERIC_GPIO
+ select I2C_ALGOBIT
+ help
+ This is a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+
config I2C_HYDRA
tristate "CHRP Apple Hydra Mac I/O I2C interface"
- depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL
+ depends on PCI && PPC_CHRP && EXPERIMENTAL
select I2C_ALGOBIT
help
This supports the use of the I2C interface in the Apple Hydra Mac
@@ -116,7 +139,7 @@ config I2C_HYDRA
config I2C_I801
tristate "Intel 82801 (ICH)"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
@@ -139,7 +162,7 @@ config I2C_I801
config I2C_I810
tristate "Intel 810/815"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the Intel
@@ -156,7 +179,7 @@ config I2C_I810
config I2C_PXA
tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
- depends on I2C && EXPERIMENTAL && ARCH_PXA
+ depends on EXPERIMENTAL && ARCH_PXA
help
If you have devices in the PXA I2C bus, say yes to this option.
This driver can also be built as a module. If so, the module
@@ -172,7 +195,7 @@ config I2C_PXA_SLAVE
config I2C_PIIX4
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Intel
PIIX4 family of mainboard I2C interfaces. Specifically, the following
@@ -195,7 +218,7 @@ config I2C_PIIX4
config I2C_IBM_IIC
tristate "IBM PPC 4xx on-chip I2C interface"
- depends on IBM_OCP && I2C
+ depends on IBM_OCP
help
Say Y here if you want to use IIC peripheral found on
embedded IBM PPC 4xx based systems.
@@ -205,7 +228,7 @@ config I2C_IBM_IIC
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
- depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
help
Say Y here if you want to use the IIC bus controller on
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
@@ -215,11 +238,10 @@ config I2C_IOP3XX
config I2C_ISA
tristate
- depends on I2C
config I2C_IXP4XX
- tristate "IXP4xx GPIO-Based I2C Interface"
- depends on I2C && ARCH_IXP4XX
+ tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP4XX
select I2C_ALGOBIT
help
Say Y here if you have an Intel IXP4xx(420,421,422,425) based
@@ -228,9 +250,12 @@ config I2C_IXP4XX
This support is also available as a module. If so, the module
will be called i2c-ixp4xx.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
config I2C_IXP2000
- tristate "IXP2000 GPIO-Based I2C Interface"
- depends on I2C && ARCH_IXP2000
+ tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP2000
select I2C_ALGOBIT
help
Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based
@@ -239,9 +264,12 @@ config I2C_IXP2000
This support is also available as a module. If so, the module
will be called i2c-ixp2000.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
config I2C_POWERMAC
tristate "Powermac I2C interface"
- depends on I2C && PPC_PMAC
+ depends on PPC_PMAC
default y
help
This exposes the various PowerMac i2c interfaces to the linux i2c
@@ -253,7 +281,7 @@ config I2C_POWERMAC
config I2C_MPC
tristate "MPC107/824x/85xx/52xx/86xx"
- depends on I2C && PPC32
+ depends on PPC32
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -265,7 +293,7 @@ config I2C_MPC
config I2C_NFORCE2
tristate "Nvidia nForce2, nForce3 and nForce4"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Nvidia
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
@@ -275,7 +303,7 @@ config I2C_NFORCE2
config I2C_OCORES
tristate "OpenCores I2C Controller"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes to this option, support will be included for the
OpenCores I2C controller. For details see
@@ -286,7 +314,7 @@ config I2C_OCORES
config I2C_OMAP
tristate "OMAP I2C adapter"
- depends on I2C && ARCH_OMAP
+ depends on ARCH_OMAP
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes to this option, support will be included for the
@@ -296,7 +324,7 @@ config I2C_OMAP
config I2C_PARPORT
tristate "Parallel port adapter"
- depends on I2C && PARPORT
+ depends on PARPORT
select I2C_ALGOBIT
help
This supports parallel port I2C adapters such as the ones made by
@@ -320,7 +348,6 @@ config I2C_PARPORT
config I2C_PARPORT_LIGHT
tristate "Parallel port adapter (light)"
- depends on I2C
select I2C_ALGOBIT
help
This supports parallel port I2C adapters such as the ones made by
@@ -344,13 +371,13 @@ config I2C_PARPORT_LIGHT
config I2C_PASEMI
tristate "PA Semi SMBus interface"
- depends on PPC_PASEMI && I2C && PCI
+ depends on PPC_PASEMI && PCI
help
Supports the PA Semi PWRficient on-chip SMBus interfaces.
config I2C_PROSAVAGE
tristate "S3/VIA (Pro)Savage"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -365,19 +392,19 @@ config I2C_PROSAVAGE
config I2C_RPXLITE
tristate "Embedded Planet RPX Lite/Classic support"
- depends on (RPXLITE || RPXCLASSIC) && I2C
+ depends on RPXLITE || RPXCLASSIC
select I2C_ALGO8XX
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
- depends on I2C && ARCH_S3C2410
+ depends on ARCH_S3C2410
help
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
config I2C_SAVAGE4
tristate "S3 Savage 4"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -388,13 +415,25 @@ config I2C_SAVAGE4
config I2C_SIBYTE
tristate "SiByte SMBus interface"
- depends on SIBYTE_SB1xxx_SOC && I2C
+ depends on SIBYTE_SB1xxx_SOC
help
Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+config I2C_SIMTEC
+ tristate "Simtec Generic I2C interface"
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be inclyded for
+ the Simtec Generic I2C interface. This driver is for the
+ simple I2C bus used on newer Simtec products for general
+ I2C, such as DDC on the Simtec BBD2016A.
+
+ This driver can also be build as a module. If so, the module
+ will be called i2c-simtec.
+
config SCx200_I2C
- tristate "NatSemi SCx200 I2C using GPIO pins"
- depends on SCx200_GPIO && I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+ depends on SCx200_GPIO
select I2C_ALGOBIT
help
Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
@@ -404,6 +443,9 @@ config SCx200_I2C
This support is also available as a module. If so, the module
will be called scx200_i2c.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ (or scx200_acb) instead.
+
config SCx200_I2C_SCL
int "GPIO pin used for SCL"
depends on SCx200_I2C
@@ -422,7 +464,7 @@ config SCx200_I2C_SDA
config SCx200_ACB
tristate "Geode ACCESS.bus support"
- depends on X86_32 && I2C && PCI
+ depends on X86_32 && PCI
help
Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
SC1100 processors and the CS5535 and CS5536 Geode companion devices.
@@ -434,7 +476,7 @@ config SCx200_ACB
config I2C_SIS5595
tristate "SiS 5595"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
SiS5595 SMBus (a subset of I2C) interface.
@@ -444,7 +486,7 @@ config I2C_SIS5595
config I2C_SIS630
tristate "SiS 630/730"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
SiS630 and SiS730 SMBus (a subset of I2C) interface.
@@ -454,7 +496,7 @@ config I2C_SIS630
config I2C_SIS96X
tristate "SiS 96x"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the SiS
96x SMBus (a subset of I2C) interfaces. Specifically, the following
@@ -472,7 +514,7 @@ config I2C_SIS96X
config I2C_STUB
tristate "I2C/SMBus Test Stub"
- depends on I2C && EXPERIMENTAL && 'm'
+ depends on EXPERIMENTAL && m
default 'n'
help
This module may be useful to developers of SMBus client drivers,
@@ -483,9 +525,20 @@ config I2C_STUB
If you don't know what to do here, definitely say N.
+config I2C_TINY_USB
+ tristate "I2C-Tiny-USB"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for the
+ i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+ http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-tiny-usb.
+
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
- depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
+ depends on ARCH_VERSATILE || ARCH_REALVIEW
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
@@ -496,7 +549,7 @@ config I2C_VERSATILE
config I2C_ACORN
bool "Acorn IOC/IOMD I2C bus support"
- depends on I2C && ARCH_ACORN
+ depends on ARCH_ACORN
default y
select I2C_ALGOBIT
help
@@ -506,7 +559,7 @@ config I2C_ACORN
config I2C_VIA
tristate "VIA 82C586B"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the VIA
@@ -517,7 +570,7 @@ config I2C_VIA
config I2C_VIAPRO
tristate "VIA VT82C596/82C686/82xx and CX700"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the VIA
VT82C596 and later SMBus interface. Specifically, the following
@@ -536,7 +589,7 @@ config I2C_VIAPRO
config I2C_VOODOO3
tristate "Voodoo 3"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -547,7 +600,7 @@ config I2C_VOODOO3
config I2C_PCA_ISA
tristate "PCA9564 on an ISA bus"
- depends on I2C
+ depends on ISA
select I2C_ALGOPCA
default n
help
@@ -564,7 +617,7 @@ config I2C_PCA_ISA
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
- depends on I2C && MV64X60 && EXPERIMENTAL
+ depends on MV64X60 && EXPERIMENTAL
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -574,7 +627,7 @@ config I2C_MV64XXX
config I2C_PNX
tristate "I2C bus support for Philips PNX targets"
- depends on ARCH_PNX4008 && I2C
+ depends on ARCH_PNX4008
help
This driver supports the Philips IP3204 I2C IP block master and/or
slave controller
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 290b5401835..14d1432f698 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_I810) += i2c-i810.o
@@ -37,10 +39,12 @@ obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 1e277ba5a9f..f14372ac2fc 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
/* set up the sysfs linkage to our parent device */
ali1535_adapter.dev.parent = &dev->dev;
- snprintf(ali1535_adapter.name, I2C_NAME_SIZE,
+ snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
"SMBus ALI1535 adapter at %04x", ali1535_smba);
return i2c_add_adapter(&ali1535_adapter);
}
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index e47fe01bf42..93bf87d7096 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_
/* set up the sysfs linkage to our parent device */
ali15x3_adapter.dev.parent = &dev->dev;
- snprintf(ali15x3_adapter.name, I2C_NAME_SIZE,
+ snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
return i2c_add_adapter(&ali15x3_adapter);
}
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 0c70f829334..c9fca7b4926 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
}
smbus->adapter.owner = THIS_MODULE;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"SMBus2 AMD8111 adapter at %04x", smbus->base);
smbus->adapter.id = I2C_HW_SMBUS_AMD8111;
smbus->adapter.class = I2C_CLASS_HWMON;
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 67f91bdda08..f35156c5892 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -17,7 +17,6 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/i2c.h>
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 00000000000..6311039dfe6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,644 @@
+/*
+ * drivers/i2c/busses/i2c-bfin-twi.c
+ *
+ * Description: Driver for Blackfin Two Wire Interface
+ *
+ * Author: sonicz <sonic.zhang@analog.com>
+ *
+ * Copyright (c) 2005-2007 Analog Devices, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+#define POLL_TIMEOUT (2 * HZ)
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD 0x01
+#define TWI_I2C_MODE_STANDARDSUB 0x02
+#define TWI_I2C_MODE_COMBINED 0x04
+
+struct bfin_twi_iface {
+ struct mutex twi_lock;
+ int irq;
+ spinlock_t lock;
+ char read_write;
+ u8 command;
+ u8 *transPtr;
+ int readNum;
+ int writeNum;
+ int cur_mode;
+ int manual_stop;
+ int result;
+ int timeout_count;
+ struct timer_list timeout_timer;
+ struct i2c_adapter adap;
+ struct completion complete;
+};
+
+static struct bfin_twi_iface twi_iface;
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
+{
+ unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
+ unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
+
+ if (twi_int_status & XMTSERV) {
+ /* Transmit next data */
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ iface->writeNum--;
+ }
+ /* start receive immediately after complete sending in
+ * combine mode.
+ */
+ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | MDIR | RSTART);
+ } else if (iface->manual_stop)
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | STOP);
+ SSYNC();
+ /* Clear status */
+ bfin_write_TWI_INT_STAT(XMTSERV);
+ SSYNC();
+ }
+ if (twi_int_status & RCVSERV) {
+ if (iface->readNum > 0) {
+ /* Receive next data */
+ *(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ /* Change combine mode into sub mode after
+ * read first data.
+ */
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ /* Get read number from first byte in block
+ * combine mode.
+ */
+ if (iface->readNum == 1 && iface->manual_stop)
+ iface->readNum = *iface->transPtr + 1;
+ }
+ iface->transPtr++;
+ iface->readNum--;
+ } else if (iface->manual_stop) {
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | STOP);
+ SSYNC();
+ }
+ /* Clear interrupt source */
+ bfin_write_TWI_INT_STAT(RCVSERV);
+ SSYNC();
+ }
+ if (twi_int_status & MERR) {
+ bfin_write_TWI_INT_STAT(MERR);
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_STAT(0x3e);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ iface->result = -1;
+ /* if both err and complete int stats are set, return proper
+ * results.
+ */
+ if (twi_int_status & MCOMP) {
+ bfin_write_TWI_INT_STAT(MCOMP);
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ /* If it is a quick transfer, only address bug no data,
+ * not an err, return 1.
+ */
+ if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
+ iface->result = 1;
+ /* If address not acknowledged return -1,
+ * else return 0.
+ */
+ else if (!(mast_stat & ANAK))
+ iface->result = 0;
+ }
+ complete(&iface->complete);
+ return;
+ }
+ if (twi_int_status & MCOMP) {
+ bfin_write_TWI_INT_STAT(MCOMP);
+ SSYNC();
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ if (iface->readNum == 0) {
+ /* set the read number to 1 and ask for manual
+ * stop in block combine mode
+ */
+ iface->readNum = 1;
+ iface->manual_stop = 1;
+ bfin_write_TWI_MASTER_CTL(
+ bfin_read_TWI_MASTER_CTL()
+ | (0xff << 6));
+ } else {
+ /* set the readd number in other
+ * combine mode.
+ */
+ bfin_write_TWI_MASTER_CTL(
+ (bfin_read_TWI_MASTER_CTL() &
+ (~(0xff << 6))) |
+ ( iface->readNum << 6));
+ }
+ /* remove restart bit and enable master receive */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
+ ~RSTART);
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
+ MEN | MDIR);
+ SSYNC();
+ } else {
+ iface->result = 1;
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ complete(&iface->complete);
+ }
+ }
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+ struct bfin_twi_iface *iface = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ del_timer(&iface->timeout_timer);
+ bfin_twi_handle_interrupt(iface);
+ spin_unlock_irqrestore(&iface->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void bfin_twi_timeout(unsigned long data)
+{
+ struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ bfin_twi_handle_interrupt(iface);
+ if (iface->result == 0) {
+ iface->timeout_count--;
+ if (iface->timeout_count > 0) {
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+ } else {
+ iface->result = -1;
+ complete(&iface->complete);
+ }
+ }
+ spin_unlock_irqrestore(&iface->lock, flags);
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i, ret;
+ int rc = 0;
+
+ if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ return -ENXIO;
+
+ mutex_lock(&iface->twi_lock);
+
+ while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ mutex_unlock(&iface->twi_lock);
+ yield();
+ mutex_lock(&iface->twi_lock);
+ }
+
+ ret = 0;
+ for (i = 0; rc >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
+ "not supported !\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ iface->manual_stop = 0;
+ iface->transPtr = pmsg->buf;
+ iface->writeNum = iface->readNum = pmsg->len;
+ iface->result = 0;
+ iface->timeout_count = 10;
+ /* Set Transmit device address */
+ bfin_write_TWI_MASTER_ADDR(pmsg->addr);
+
+ /* FIFO Initiation. Data in FIFO should be
+ * discarded before start a new operation.
+ */
+ bfin_write_TWI_FIFO_CTL(0x3);
+ SSYNC();
+ bfin_write_TWI_FIFO_CTL(0);
+ SSYNC();
+
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
+ }
+ }
+
+ /* clear int stat */
+ bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+ /* Interrupt mask . Enable XMT, RCV interrupt */
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ)?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (pmsg->len > 0 && pmsg->len <= 255)
+ bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
+ else if (pmsg->len > 255) {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ } else
+ break;
+
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ SSYNC();
+
+ wait_for_completion(&iface->complete);
+
+ rc = iface->result;
+ if (rc == 1)
+ ret++;
+ else if (rc == -1)
+ break;
+ }
+
+ /* Release mutex */
+ mutex_unlock(&iface->twi_lock);
+
+ return ret;
+}
+
+/*
+ * SMBus type transfer entrypoint
+ */
+
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ int rc = 0;
+
+ if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ return -ENXIO;
+
+ mutex_lock(&iface->twi_lock);
+
+ while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ mutex_unlock(&iface->twi_lock);
+ yield();
+ mutex_lock(&iface->twi_lock);
+ }
+
+ iface->writeNum = 0;
+ iface->readNum = 0;
+
+ /* Prepare datas & select mode */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ iface->transPtr = NULL;
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (data == NULL)
+ iface->transPtr = NULL;
+ else {
+ if (read_write == I2C_SMBUS_READ)
+ iface->readNum = 1;
+ else
+ iface->writeNum = 1;
+ iface->transPtr = &data->byte;
+ }
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ iface->writeNum = 2;
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 0;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0] + 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = data->block;
+ break;
+ default:
+ return -1;
+ }
+
+ iface->result = 0;
+ iface->manual_stop = 0;
+ iface->read_write = read_write;
+ iface->command = command;
+ iface->timeout_count = 10;
+
+ /* FIFO Initiation. Data in FIFO should be discarded before
+ * start a new operation.
+ */
+ bfin_write_TWI_FIFO_CTL(0x3);
+ SSYNC();
+ bfin_write_TWI_FIFO_CTL(0);
+
+ /* clear int stat */
+ bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+ /* Set Transmit device address */
+ bfin_write_TWI_MASTER_ADDR(addr);
+ SSYNC();
+
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+
+ switch (iface->cur_mode) {
+ case TWI_I2C_MODE_STANDARDSUB:
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (iface->writeNum + 1 <= 255)
+ bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ else {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ }
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ case TWI_I2C_MODE_COMBINED:
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (iface->writeNum > 0)
+ bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ else
+ bfin_write_TWI_MASTER_CTL(0x1 << 6);
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ default:
+ bfin_write_TWI_MASTER_CTL(0);
+ if (size != I2C_SMBUS_QUICK) {
+ /* Don't access xmit data register when this is a
+ * read operation.
+ */
+ if (iface->read_write != I2C_SMBUS_READ) {
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ if (iface->writeNum <= 255)
+ bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
+ else {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ }
+ iface->writeNum--;
+ } else {
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_MASTER_CTL(1 << 6);
+ }
+ } else {
+ if (iface->readNum > 0 && iface->readNum <= 255)
+ bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
+ else if (iface->readNum > 255) {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ } else {
+ del_timer(&iface->timeout_timer);
+ break;
+ }
+ }
+ }
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ break;
+ }
+ SSYNC();
+
+ wait_for_completion(&iface->complete);
+
+ rc = (iface->result >= 0) ? 0 : -1;
+
+ /* Release mutex */
+ mutex_unlock(&iface->twi_lock);
+
+ return rc;
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(struct i2c_adapter *adap)
+{
+ 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_I2C;
+}
+
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+ .master_xfer = bfin_twi_master_xfer,
+ .smbus_xfer = bfin_twi_smbus_xfer,
+ .functionality = bfin_twi_functionality,
+};
+
+
+static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
+{
+/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+ /* Disable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+ SSYNC();
+
+ return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *dev)
+{
+/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+ /* Enable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ SSYNC();
+
+ return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *dev)
+{
+ struct bfin_twi_iface *iface = &twi_iface;
+ struct i2c_adapter *p_adap;
+ int rc;
+
+ mutex_init(&(iface->twi_lock));
+ spin_lock_init(&(iface->lock));
+ init_completion(&(iface->complete));
+ iface->irq = IRQ_TWI;
+
+ init_timer(&(iface->timeout_timer));
+ iface->timeout_timer.function = bfin_twi_timeout;
+ iface->timeout_timer.data = (unsigned long)iface;
+
+ p_adap = &iface->adap;
+ p_adap->id = I2C_HW_BLACKFIN;
+ strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+ p_adap->algo = &bfin_twi_algorithm;
+ p_adap->algo_data = iface;
+ p_adap->class = I2C_CLASS_ALL;
+ p_adap->dev.parent = &dev->dev;
+
+ rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ IRQF_DISABLED, dev->name, iface);
+ if (rc) {
+ dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
+ iface->irq);
+ return -ENODEV;
+ }
+
+ /* Set TWI internal clock as 10MHz */
+ bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+
+ /* Set Twi interface clock as specified */
+ bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+ << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+ & 0xFF));
+
+ /* Enable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ SSYNC();
+
+ rc = i2c_add_adapter(p_adap);
+ if (rc < 0)
+ free_irq(iface->irq, iface);
+ else
+ platform_set_drvdata(dev, iface);
+
+ return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&(iface->adap));
+ free_irq(iface->irq, iface);
+
+ return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+ .probe = i2c_bfin_twi_probe,
+ .remove = i2c_bfin_twi_remove,
+ .suspend = i2c_bfin_twi_suspend,
+ .resume = i2c_bfin_twi_resume,
+ .driver = {
+ .name = "i2c-bfin-twi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+ pr_info("I2C: Blackfin I2C TWI driver\n");
+
+ return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+ platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 83496746481..804f0a551c0 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -35,6 +35,7 @@
#include <linux/pci.h>
#include <linux/wait.h>
+#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pcf.h>
@@ -207,7 +208,7 @@ static struct i2c_adapter pcf_isa_ops = {
.name = "i2c-elektor",
};
-static int __init i2c_pcfisa_init(void)
+static int __devinit elektor_match(struct device *dev, unsigned int id)
{
#ifdef __alpha__
/* check to see we have memory mapped PCF8584 connected to the
@@ -222,9 +223,8 @@ static int __init i2c_pcfisa_init(void)
/* yeap, we've found cypress, let's check config */
if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
- pr_debug("%s: found cy82c693, config "
- "register 0x47 = 0x%02x\n",
- pcf_isa_ops.name, config);
+ dev_dbg(dev, "found cy82c693, config "
+ "register 0x47 = 0x%02x\n", config);
/* UP2000 board has this register set to 0xe1,
but the most significant bit as seems can be
@@ -244,9 +244,9 @@ static int __init i2c_pcfisa_init(void)
8.25 MHz (PCI/4) clock
(this can be read from cypress) */
clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
- pr_info("%s: found API UP2000 like "
- "board, will probe PCF8584 "
- "later\n", pcf_isa_ops.name);
+ dev_info(dev, "found API UP2000 like "
+ "board, will probe PCF8584 "
+ "later\n");
}
}
pci_dev_put(cy693_dev);
@@ -256,22 +256,27 @@ static int __init i2c_pcfisa_init(void)
/* sanity checks for mmapped I/O */
if (mmapped && base < 0xc8000) {
- printk(KERN_ERR "%s: incorrect base address (%#x) specified "
- "for mmapped I/O\n", pcf_isa_ops.name, base);
- return -ENODEV;
+ dev_err(dev, "incorrect base address (%#x) specified "
+ "for mmapped I/O\n", base);
+ return 0;
}
if (base == 0) {
base = DEFAULT_BASE;
}
+ return 1;
+}
+static int __devinit elektor_probe(struct device *dev, unsigned int id)
+{
init_waitqueue_head(&pcf_wait);
if (pcf_isa_init())
return -ENODEV;
+ pcf_isa_ops.dev.parent = dev;
if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
goto fail;
- dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base);
+ dev_info(dev, "found device at %#x\n", base);
return 0;
@@ -291,7 +296,7 @@ static int __init i2c_pcfisa_init(void)
return -ENODEV;
}
-static void i2c_pcfisa_exit(void)
+static int __devexit elektor_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pcf_isa_ops);
@@ -307,6 +312,28 @@ static void i2c_pcfisa_exit(void)
iounmap(base_iomem);
release_mem_region(base, 2);
}
+
+ return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+ .match = elektor_match,
+ .probe = elektor_probe,
+ .remove = __devexit_p(elektor_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-elektor",
+ },
+};
+
+static int __init i2c_pcfisa_init(void)
+{
+ return isa_register_driver(&i2c_elektor_driver, 1);
+}
+
+static void __exit i2c_pcfisa_exit(void)
+{
+ isa_unregister_driver(&i2c_elektor_driver);
}
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 00000000000..a7dd54654a9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,215 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->sda_pin);
+ else
+ gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->scl_pin);
+ else
+ gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->scl_pin, state);
+}
+
+int i2c_gpio_getsda(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->sda_pin);
+}
+
+int i2c_gpio_getscl(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->scl_pin);
+}
+
+static int __init i2c_gpio_probe(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_algo_bit_data *bit_data;
+ struct i2c_adapter *adap;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENXIO;
+
+ ret = -ENOMEM;
+ adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!adap)
+ goto err_alloc_adap;
+ bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
+ if (!bit_data)
+ goto err_alloc_bit_data;
+
+ ret = gpio_request(pdata->sda_pin, "sda");
+ if (ret)
+ goto err_request_sda;
+ ret = gpio_request(pdata->scl_pin, "scl");
+ if (ret)
+ goto err_request_scl;
+
+ if (pdata->sda_is_open_drain) {
+ gpio_direction_output(pdata->sda_pin, 1);
+ bit_data->setsda = i2c_gpio_setsda_val;
+ } else {
+ gpio_direction_input(pdata->sda_pin);
+ bit_data->setsda = i2c_gpio_setsda_dir;
+ }
+
+ if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+ gpio_direction_output(pdata->scl_pin, 1);
+ bit_data->setscl = i2c_gpio_setscl_val;
+ } else {
+ gpio_direction_input(pdata->scl_pin);
+ bit_data->setscl = i2c_gpio_setscl_dir;
+ }
+
+ if (!pdata->scl_is_output_only)
+ bit_data->getscl = i2c_gpio_getscl;
+ bit_data->getsda = i2c_gpio_getsda;
+
+ if (pdata->udelay)
+ bit_data->udelay = pdata->udelay;
+ else if (pdata->scl_is_output_only)
+ bit_data->udelay = 50; /* 10 kHz */
+ else
+ bit_data->udelay = 5; /* 100 kHz */
+
+ if (pdata->timeout)
+ bit_data->timeout = pdata->timeout;
+ else
+ bit_data->timeout = HZ / 10; /* 100 ms */
+
+ bit_data->data = pdata;
+
+ adap->owner = THIS_MODULE;
+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+ adap->algo_data = bit_data;
+ adap->dev.parent = &pdev->dev;
+
+ ret = i2c_bit_add_bus(adap);
+ if (ret)
+ goto err_add_bus;
+
+ platform_set_drvdata(pdev, adap);
+
+ dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+ pdata->sda_pin, pdata->scl_pin,
+ pdata->scl_is_output_only
+ ? ", no clock stretching" : "");
+
+ return 0;
+
+err_add_bus:
+ gpio_free(pdata->scl_pin);
+err_request_scl:
+ gpio_free(pdata->sda_pin);
+err_request_sda:
+ kfree(bit_data);
+err_alloc_bit_data:
+ kfree(adap);
+err_alloc_adap:
+ return ret;
+}
+
+static int __exit i2c_gpio_remove(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_adapter *adap;
+
+ adap = platform_get_drvdata(pdev);
+ pdata = pdev->dev.platform_data;
+
+ i2c_del_adapter(adap);
+ gpio_free(pdata->scl_pin);
+ gpio_free(pdata->sda_pin);
+ kfree(adap->algo_data);
+ kfree(adap);
+
+ return 0;
+}
+
+static struct platform_driver i2c_gpio_driver = {
+ .driver = {
+ .name = "i2c-gpio",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+ int ret;
+
+ ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe);
+ if (ret)
+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+ return ret;
+}
+module_init(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+ platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index a320e7d82c1..611b57192c9 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -527,7 +527,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
/* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
- snprintf(i801_adapter.name, I2C_NAME_SIZE,
+ snprintf(i801_adapter.name, sizeof(i801_adapter.name),
"SMBus I801 adapter at %04lx", i801_smba);
err = i2c_add_adapter(&i801_adapter);
if (err) {
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 5f33bc9c1e0..b0e1370075d 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -41,6 +41,10 @@
#include <linux/platform_device.h>
#include <linux/completion.h>
+/* Exported by i2c-core for i2c-isa only */
+extern void i2c_adapter_dev_release(struct device *dev);
+extern struct class i2c_adapter_class;
+
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
@@ -64,16 +68,6 @@ static u32 isa_func(struct i2c_adapter *adapter)
}
-/* Copied from i2c-core */
-static ssize_t show_adapter_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
- return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
-
-
/* We implement an interface which resembles i2c_{add,del}_driver,
but for i2c-isa drivers. We don't have to remember and handle lists
of drivers and adapters so this is much more simple, of course. */
@@ -139,41 +133,18 @@ static int __init i2c_isa_init(void)
isa_adapter.nr = ANY_I2C_ISA_BUS;
isa_adapter.dev.parent = &platform_bus;
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
- isa_adapter.dev.driver = &i2c_adapter_driver;
isa_adapter.dev.release = &i2c_adapter_dev_release;
+ isa_adapter.dev.class = &i2c_adapter_class;
err = device_register(&isa_adapter.dev);
if (err) {
printk(KERN_ERR "i2c-isa: Failed to register device\n");
goto exit;
}
- err = device_create_file(&isa_adapter.dev, &dev_attr_name);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to create name file\n");
- goto exit_unregister;
- }
-
- /* Add this adapter to the i2c_adapter class */
- memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
- isa_adapter.class_dev.dev = &isa_adapter.dev;
- isa_adapter.class_dev.class = &i2c_adapter_class;
- strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
- BUS_ID_SIZE);
- err = class_device_register(&isa_adapter.class_dev);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to register class device\n");
- goto exit_remove_name;
- }
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
-exit_remove_name:
- device_remove_file(&isa_adapter.dev, &dev_attr_name);
-exit_unregister:
- init_completion(&isa_adapter.dev_released); /* Needed? */
- device_unregister(&isa_adapter.dev);
- wait_for_completion(&isa_adapter.dev_released);
exit:
return err;
}
@@ -201,15 +172,11 @@ static void __exit i2c_isa_exit(void)
/* Clean up the sysfs representation */
dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
init_completion(&isa_adapter.dev_released);
- init_completion(&isa_adapter.class_dev_released);
- class_device_unregister(&isa_adapter.class_dev);
- device_remove_file(&isa_adapter.dev, &dev_attr_name);
device_unregister(&isa_adapter.dev);
/* Wait for sysfs to drop all references */
dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
wait_for_completion(&isa_adapter.dev_released);
- wait_for_completion(&isa_adapter.class_dev_released);
dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
}
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index efa3ecc5522..6352121a282 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
drv_data->adapter.id = I2C_HW_B_IXP2000,
strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
drv_data->adapter.algo_data = &drv_data->algo_data,
drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 08e89b83984..069ed7f3b39 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
drv_data->adapter.id = I2C_HW_B_IXP4XX;
drv_data->adapter.class = I2C_CLASS_HWMON;
strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
drv_data->adapter.algo_data = &drv_data->algo_data;
drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index ee65aa1be13..c6b6898592b 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/platform_device.h>
#include <asm/io.h>
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a3283b907eb..a55b3335d1b 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
}
strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 1514ec5b77f..3cd0d63e7b5 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -33,6 +33,8 @@
nForce4 MCP-04 0034
nForce4 MCP51 0264
nForce4 MCP55 0368
+ nForce MCP61 03EB
+ nForce MCP65 0446
This driver supports the 2 SMBuses that are included in the MCP of the
nForce2/3/4/5xx chipsets.
@@ -200,6 +202,8 @@ static struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
{ 0 }
};
@@ -240,7 +244,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
smbus->adapter.dev.parent = &dev->dev;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"SMBus nForce2 adapter at %04x", smbus->base);
error = i2c_add_adapter(&smbus->adapter);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index bcd8367cede..e471e3bfdc1 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -605,7 +605,8 @@ omap_i2c_probe(struct platform_device *pdev)
adap->dev.parent = &pdev->dev;
/* i2c device drivers may be active on return from add_adapter() */
- r = i2c_add_adapter(adap);
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
if (r) {
dev_err(dev->dev, "failure adding adapter\n");
goto err_free_irq;
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 4bc42810b9a..49a95e2887b 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
- * i2c-parport.c I2C bus over parallel port *
+ * i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -34,6 +35,9 @@
#include "i2c-parport.h"
#define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
static u16 base;
module_param(base, ushort, 0);
@@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
.timeout = HZ,
};
-/* ----- I2c structure ---------------------------------------------------- */
+/* ----- Driver registration ---------------------------------------------- */
static struct i2c_adapter parport_adapter = {
.owner = THIS_MODULE,
@@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapter = {
.name = "Parallel port adapter (light)",
};
-/* ----- Module loading, unloading and information ------------------------ */
+static int __devinit i2c_parport_probe(struct platform_device *pdev)
+{
+ int err;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
+ return -EBUSY;
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(NULL, 1);
+ parport_setscl(NULL, 1);
+ /* Other init if needed (power on...) */
+ if (adapter_parm[type].init.val)
+ line_set(1, &adapter_parm[type].init);
+
+ parport_adapter.dev.parent = &pdev->dev;
+ err = i2c_bit_add_bus(&parport_adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to register with I2C\n");
+ goto exit_region;
+ }
+ return 0;
+
+exit_region:
+ release_region(res->start, res->end - res->start + 1);
+ return err;
+}
+
+static int __devexit i2c_parport_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ i2c_del_adapter(&parport_adapter);
+
+ /* Un-init if needed (power off...) */
+ if (adapter_parm[type].init.val)
+ line_set(0, &adapter_parm[type].init);
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, res->end - res->start + 1);
+ return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = i2c_parport_probe,
+ .remove = __devexit_p(i2c_parport_remove),
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + 2,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, -1);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
static int __init i2c_parport_init(void)
{
+ int err;
+
if (type < 0) {
- printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
+ printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
return -ENODEV;
}
if (type >= ARRAY_SIZE(adapter_parm)) {
- printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+ printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
return -ENODEV;
}
if (base == 0) {
- printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE);
+ pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
base = DEFAULT_BASE;
}
- if (!request_region(base, 3, "i2c-parport"))
- return -ENODEV;
-
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
- /* Reset hardware to a sane state (SCL and SDA high) */
- parport_setsda(NULL, 1);
- parport_setscl(NULL, 1);
- /* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
- line_set(1, &adapter_parm[type].init);
+ /* Sets global pdev as a side effect */
+ err = i2c_parport_device_add(base);
+ if (err)
+ goto exit;
- if (i2c_bit_add_bus(&parport_adapter) < 0) {
- printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
- release_region(base, 3);
- return -ENODEV;
- }
+ err = platform_driver_register(&i2c_parport_driver);
+ if (err)
+ goto exit_device;
return 0;
+
+exit_device:
+ platform_device_unregister(pdev);
+exit:
+ return err;
}
static void __exit i2c_parport_exit(void)
{
- /* Un-init if needed (power off...) */
- if (adapter_parm[type].init.val)
- line_set(0, &adapter_parm[type].init);
-
- i2c_del_adapter(&parport_adapter);
- release_region(base, 3);
+ platform_driver_unregister(&i2c_parport_driver);
+ platform_device_unregister(pdev);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 66696a40c7b..8c953707253 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -137,19 +137,12 @@ static struct i2c_algo_bit_data parport_algo_data = {
.setscl = parport_setscl,
.getsda = parport_getsda,
.getscl = parport_getscl,
- .udelay = 60,
+ .udelay = 10, /* ~50 kbps */
.timeout = HZ,
};
/* ----- I2c and parallel port call-back functions and structures --------- */
-static struct i2c_adapter parport_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_HWMON,
- .id = I2C_HW_B_LP,
- .name = "Parallel port adapter",
-};
-
static void i2c_parport_attach (struct parport *port)
{
struct i2c_par *adapter;
@@ -169,10 +162,17 @@ static void i2c_parport_attach (struct parport *port)
}
/* Fill the rest of the structure */
- adapter->adapter = parport_adapter;
+ adapter->adapter.owner = THIS_MODULE;
+ adapter->adapter.class = I2C_CLASS_HWMON;
+ adapter->adapter.id = I2C_HW_B_LP;
+ strlcpy(adapter->adapter.name, "Parallel port adapter",
+ sizeof(adapter->adapter.name));
adapter->algo_data = parport_algo_data;
- if (!adapter_parm[type].getscl.val)
+ /* Slow down if we can't sense SCL */
+ if (!adapter_parm[type].getscl.val) {
adapter->algo_data.getscl = NULL;
+ adapter->algo_data.udelay = 50; /* ~10 kbps */
+ }
adapter->algo_data.data = port;
adapter->adapter.algo_data = &adapter->algo_data;
@@ -214,11 +214,12 @@ 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) {
+ i2c_del_adapter(&adapter->adapter);
+
/* Un-init if needed (power off...) */
if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
- i2c_del_adapter(&adapter->adapter);
parport_unregister_device(adapter->pdev);
if (prev)
prev->next = adapter->next;
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index bf89eeef74e..58e32714afb 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
}
smbus->adapter.owner = THIS_MODULE;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"PA Semi SMBus adapter at 0x%lx", smbus->base);
smbus->adapter.class = I2C_CLASS_HWMON;
smbus->adapter.algo = &smbus_algorithm;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index cc6536a19ec..5161aaf9341 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -25,9 +25,9 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/wait.h>
+#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pca.h>
@@ -119,27 +119,26 @@ static struct i2c_adapter pca_isa_ops = {
.name = "PCA9564 ISA Adapter",
};
-static int __init pca_isa_init(void)
+static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
{
-
init_waitqueue_head(&pca_wait);
- printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq);
+ dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
- printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base);
+ dev_err(dev, "I/O address %#08lx is in use\n", base);
goto out;
}
if (irq > -1) {
if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
- printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq);
+ dev_err(dev, "Request irq%d failed\n", irq);
goto out_region;
}
}
if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
- printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n");
+ dev_err(dev, "Failed to add i2c bus\n");
goto out_irq;
}
@@ -154,7 +153,7 @@ static int __init pca_isa_init(void)
return -ENODEV;
}
-static void pca_isa_exit(void)
+static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pca_isa_ops);
@@ -163,6 +162,27 @@ static void pca_isa_exit(void)
free_irq(irq, &pca_isa_ops);
}
release_region(base, IO_SIZE);
+
+ return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+ .probe = pca_isa_probe,
+ .remove = __devexit_p(pca_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-pca-isa",
+ }
+};
+
+static int __init pca_isa_init(void)
+{
+ return isa_register_driver(&pca_isa_driver, 1);
+}
+
+static void __exit pca_isa_exit(void)
+{
+ isa_unregister_driver(&pca_isa_driver);
}
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 21b18090408..5a52bf5e3fb 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct pci_dev *dev,
/* set up the sysfs linkage to our parent device */
piix4_adapter.dev.parent = &dev->dev;
- snprintf(piix4_adapter.name, I2C_NAME_SIZE,
+ snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
"SMBus PIIX4 adapter at %04x", piix4_smba);
if ((retval = i2c_add_adapter(&piix4_adapter))) {
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 14e83d0aac8..c059b27fa88 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -539,6 +539,18 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
writel(icr | ICR_START | ICR_TB, _ICR(i2c));
}
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /*
+ * Clear the STOP and ACK flags
+ */
+ icr = readl(_ICR(i2c));
+ icr &= ~(ICR_STOP | ICR_ACKNAK);
+ writel(icr, _IRC(i2c));
+}
+
/*
* We are protected by the adapter bus mutex.
*/
@@ -581,6 +593,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
* The rest of the processing occurs in the interrupt handler.
*/
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+ i2c_pxa_stop_message(i2c);
/*
* We place the return code in i2c->msg_idx.
@@ -825,7 +838,7 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
};
static struct pxa_i2c i2c_pxa = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(i2c_pxa.lock),
.adap = {
.owner = THIS_MODULE,
.algo = &i2c_pxa_algorithm,
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 556f244aae7..e68a96f589f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -61,6 +61,8 @@ struct s3c24xx_i2c {
unsigned int msg_idx;
unsigned int msg_ptr;
+ unsigned int tx_setup;
+
enum s3c24xx_i2c_state state;
void __iomem *regs;
@@ -199,8 +201,11 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS);
- // delay a bit and reset iiccon before setting start (per samsung)
- udelay(1);
+ /* delay here to ensure the data byte has gotten onto the bus
+ * before the transaction is started */
+
+ ndelay(i2c->tx_setup);
+
dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
writel(iiccon, i2c->regs + S3C2410_IICCON);
@@ -322,7 +327,15 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
-
+
+ /* delay after writing the byte to allow the
+ * data setup time on the bus, as writing the
+ * data to the register causes the first bit
+ * to appear on SDA, and SCL will change as
+ * soon as the interrupt is acknowledged */
+
+ ndelay(i2c->tx_setup);
+
} else if (!is_lastmsg(i2c)) {
/* we need to go to the next i2c message */
@@ -570,9 +583,10 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
};
static struct s3c24xx_i2c s3c24xx_i2c = {
- .lock = SPIN_LOCK_UNLOCKED,
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
- .adap = {
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
+ .tx_setup = 50,
+ .adap = {
.name = "s3c2410-i2c",
.owner = THIS_MODULE,
.algo = &s3c24xx_i2c_algorithm,
@@ -731,26 +745,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
return 0;
}
-static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
-{
- if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- i2c->clk = NULL;
- }
-
- if (i2c->regs != NULL) {
- iounmap(i2c->regs);
- i2c->regs = NULL;
- }
-
- if (i2c->ioarea != NULL) {
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- i2c->ioarea = NULL;
- }
-}
-
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
@@ -769,7 +763,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = -ENOENT;
- goto out;
+ goto err_noclk;
}
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
@@ -782,7 +776,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
- goto out;
+ goto err_clk;
}
i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
@@ -791,7 +785,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (i2c->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
- goto out;
+ goto err_clk;
}
i2c->regs = ioremap(res->start, (res->end-res->start)+1);
@@ -799,7 +793,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (i2c->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
- goto out;
+ goto err_ioarea;
}
dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
@@ -813,7 +807,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = s3c24xx_i2c_init(i2c);
if (ret != 0)
- goto out;
+ goto err_iomap;
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
@@ -823,7 +817,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IRQ\n");
ret = -ENOENT;
- goto out;
+ goto err_iomap;
}
ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
@@ -831,7 +825,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ\n");
- goto out;
+ goto err_iomap;
}
i2c->irq = res;
@@ -841,17 +835,29 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
- goto out;
+ goto err_irq;
}
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+ return 0;
- out:
- if (ret < 0)
- s3c24xx_i2c_free(i2c);
+ err_irq:
+ free_irq(i2c->irq->start, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ err_noclk:
return ret;
}
@@ -863,11 +869,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
-
- if (i2c != NULL) {
- s3c24xx_i2c_free(i2c);
- platform_set_drvdata(pdev, NULL);
- }
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq->start, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 00000000000..10af8d31e12
--- /dev/null
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * 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
+ *
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+struct simtec_i2c_data {
+ struct resource *ioarea;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA (1<<2)
+#define CMD_SET_SCL (1<<3)
+
+#define STATE_SDA (1<<0)
+#define STATE_SCL (1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd;
+ struct resource *res;
+ int size;
+ int ret;
+
+ pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+ if (pd == NULL) {
+ dev_err(&dev->dev, "cannot allocate private data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&dev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ size = (res->end-res->start)+1;
+
+ pd->ioarea = request_mem_region(res->start, size, dev->name);
+ if (pd->ioarea == NULL) {
+ dev_err(&dev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err;
+ }
+
+ pd->reg = ioremap(res->start, size);
+ if (pd->reg == NULL) {
+ dev_err(&dev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_res;
+ }
+
+ /* setup the private data */
+
+ pd->adap.owner = THIS_MODULE;
+ pd->adap.algo_data = &pd->bit;
+ pd->adap.dev.parent = &dev->dev;
+
+ strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+ pd->bit.data = pd;
+ pd->bit.setsda = simtec_i2c_setsda;
+ pd->bit.setscl = simtec_i2c_setscl;
+ pd->bit.getsda = simtec_i2c_getsda;
+ pd->bit.getscl = simtec_i2c_getscl;
+ pd->bit.timeout = HZ;
+ pd->bit.udelay = 20;
+
+ ret = i2c_bit_add_bus(&pd->adap);
+ if (ret)
+ goto err_all;
+
+ return 0;
+
+ err_all:
+ iounmap(pd->reg);
+
+ err_res:
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+
+ err:
+ kfree(pd);
+ return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+
+ iounmap(pd->reg);
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+ kfree(pd);
+
+ return 0;
+}
+
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+ .driver = {
+ .name = "simtec-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = simtec_i2c_probe,
+ .remove = simtec_i2c_remove,
+};
+
+static int __init i2c_adap_simtec_init(void)
+{
+ return platform_driver_register(&simtec_i2c_driver);
+}
+
+static void __exit i2c_adap_simtec_exit(void)
+{
+ platform_driver_unregister(&simtec_i2c_driver);
+}
+
+module_init(i2c_adap_simtec_init);
+module_exit(i2c_adap_simtec_exit);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 4157b0cd604..dc235bb8e24 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
/* set up the sysfs linkage to our parent device */
sis96x_adapter.dev.parent = &dev->dev;
- snprintf(sis96x_adapter.name, I2C_NAME_SIZE,
+ snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
if ((retval = i2c_add_adapter(&sis96x_adapter))) {
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 00000000000..907999049d5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,277 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+/* include interfaces to usb layer */
+#include <linux/usb.h>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO 0
+#define CMD_GET_FUNC 1
+#define CMD_SET_DELAY 2
+#define CMD_GET_STATUS 3
+
+#define CMD_I2C_IO 4
+#define CMD_I2C_IO_BEGIN (1<<0)
+#define CMD_I2C_IO_END (1<<1)
+
+/* i2c bit delay, default is 10us -> 100kHz */
+static int delay = 10;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds, "
+ "e.g. 10 for 100kHz (default is 100kHz)");
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE 0
+#define STATUS_ADDRESS_ACK 1
+#define STATUS_ADDRESS_NAK 2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ unsigned char status;
+ struct i2c_msg *pmsg;
+ int i;
+
+ dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+ for (i = 0 ; i < num ; i++) {
+ int cmd = CMD_I2C_IO;
+
+ if (i == 0)
+ cmd |= CMD_I2C_IO_BEGIN;
+
+ if (i == num-1)
+ cmd |= CMD_I2C_IO_END;
+
+ pmsg = &msgs[i];
+
+ dev_dbg(&adapter->dev,
+ " %d: %s (flags %d) %d bytes to 0x%02x\n",
+ i, pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->flags, pmsg->len, pmsg->addr);
+
+ /* and directly send the message */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read data */
+ if (usb_read(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure reading data\n");
+ return -EREMOTEIO;
+ }
+ } else {
+ /* write data */
+ if (usb_write(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure writing data\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ /* read status */
+ if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+ dev_err(&adapter->dev, "failure reading status\n");
+ return -EREMOTEIO;
+ }
+
+ dev_dbg(&adapter->dev, " status = %d\n", status);
+ if (status == STATUS_ADDRESS_NAK)
+ return -EREMOTEIO;
+ }
+
+ return i;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+ u32 func;
+
+ /* get functionality from adapter */
+ if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
+ sizeof(func)) {
+ dev_err(&adapter->dev, "failure reading functionality\n");
+ return 0;
+ }
+
+ return func;
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+ .master_xfer = usb_xfer,
+ .functionality = usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/* The usb i2c interface uses a vid/pid pair donated by */
+/* Future Technology Devices International Ltd. */
+static struct usb_device_id i2c_tiny_usb_table [] = {
+ { USB_DEVICE(0x0403, 0xc631) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+ USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, data, len, 2000);
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct i2c_tiny_usb *dev;
+ int retval = -ENOMEM;
+ u16 version;
+
+ dev_dbg(&interface->dev, "probing usb device\n");
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error;
+ }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+ dev_info(&interface->dev,
+ "version %x.%02x found at bus %03d address %03d\n",
+ version >> 8, version & 0xff,
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &usb_algorithm;
+ dev->adapter.algo_data = dev;
+ snprintf(dev->adapter.name, I2C_NAME_SIZE,
+ "i2c-tiny-usb at bus %03d device %03d",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ if (usb_write(&dev->adapter, CMD_SET_DELAY,
+ cpu_to_le16(delay), 0, NULL, 0) != 0) {
+ dev_err(&dev->adapter.dev,
+ "failure setting delay to %dus\n", delay);
+ retval = -EIO;
+ goto error;
+ }
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* and finally attach to i2c layer */
+ i2c_add_adapter(&dev->adapter);
+
+ /* inform user about successful attachment to i2c layer */
+ dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+ return 0;
+
+ error:
+ if (dev)
+ i2c_tiny_usb_free(dev);
+
+ return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+ struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ i2c_tiny_usb_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+ .name = "i2c-tiny-usb",
+ .probe = i2c_tiny_usb_probe,
+ .disconnect = i2c_tiny_usb_disconnect,
+ .id_table = i2c_tiny_usb_table,
+};
+
+static int __init usb_i2c_tiny_usb_init(void)
+{
+ /* register this driver with the USB subsystem */
+ return usb_register(&i2c_tiny_usb_driver);
+}
+
+static void __exit usb_i2c_tiny_usb_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&i2c_tiny_usb_driver);
+}
+
+module_init(usb_i2c_tiny_usb_init);
+module_exit(usb_i2c_tiny_usb_exit);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 03c5fc86854..7a2bc06304f 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -404,7 +404,7 @@ found:
}
vt596_adapter.dev.parent = &pdev->dev;
- snprintf(vt596_adapter.name, I2C_NAME_SIZE,
+ snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
"SMBus Via Pro adapter at %04x", vt596_smba);
vt596_pdev = pci_dev_get(pdev);
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 0b082c5a019..0db56e7bc34 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -441,7 +441,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
adapter = &iface->adapter;
i2c_set_adapdata(adapter, iface);
- snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index);
+ snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
adapter->owner = THIS_MODULE;
adapter->id = I2C_HW_SMBUS_SCX200;
adapter->algo = &scx200_acb_algorithm;
@@ -599,6 +599,7 @@ static __init int scx200_scan_pci(void)
else {
int i;
+ pci_dev_put(pdev);
for (i = 0; i < MAX_DEVICES; ++i) {
if (base[i] == 0)
continue;