diff options
Diffstat (limited to 'drivers/i2c')
64 files changed, 1264 insertions, 527 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 525c7345fa0b..7f0b83219744 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -15,7 +15,8 @@ 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. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. * ------------------------------------------------------------------------- */ /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki @@ -103,9 +104,15 @@ static int sclhi(struct i2c_algo_bit_data *adap) * chips may hold it low ("clock stretching") while they * are processing data internally. */ - if (time_after(jiffies, start + adap->timeout)) + if (time_after(jiffies, start + adap->timeout)) { + /* Test one last time, as we may have been preempted + * between last check and timeout test. + */ + if (getscl(adap)) + break; return -ETIMEDOUT; - cond_resched(); + } + cpu_relax(); } #ifdef DEBUG if (jiffies != start && i2c_debug >= 3) @@ -610,10 +617,11 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ -static const struct i2c_algorithm i2c_bit_algo = { +const struct i2c_algorithm i2c_bit_algo = { .master_xfer = bit_xfer, .functionality = bit_func, }; +EXPORT_SYMBOL(i2c_bit_algo); /* * registering functions to load algorithms at runtime diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index beb9ffe2564b..73133b1063f0 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -15,7 +15,8 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. */ #include <linux/kernel.h> diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 5eebf562ff31..5c2379522aa9 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -16,7 +16,8 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. * * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h index 5263a9eeb8d7..1ec703ee788d 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.h +++ b/drivers/i2c/algos/i2c-algo-pcf.h @@ -16,7 +16,8 @@ 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. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* -------------------------------------------------------------------- */ /* With some changes from Frodo Looijaard <frodol@dds.nl> */ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a3afac4be734..d2c5095deeac 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -103,6 +103,7 @@ config I2C_I801 Patsburg (PCH) DH89xxCC (PCH) Panther Point (PCH) + Lynx Point (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -299,11 +300,11 @@ config I2C_AT91 unless your system can cope with those limitations. config I2C_AU1550 - tristate "Au1550/Au1200 SMBus interface" + tristate "Au1550/Au1200/Au1300 SMBus interface" depends on MIPS_ALCHEMY help If you say yes to this option, support will be included for the - Au1550 and Au1200 SMBus interface. + Au1550/Au1200/Au1300 SMBus interface. This driver can also be built as a module. If so, the module will be called i2c-au1550. @@ -369,6 +370,21 @@ config I2C_DESIGNWARE_PCI This driver can also be built as a module. If so, the module will be called i2c-designware-pci. +config I2C_EG20T + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" + depends on PCI + help + This driver is for PCH(Platform controller Hub) I2C of EG20T which + is an IOH(Input/Output Hub) for x86 embedded processor. + This driver can access PCH I2C bus device. + + This driver also can be used for LAPIS Semiconductor IOH(Input/ + Output Hub), ML7213, ML7223 and ML7831. + ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is + for MP(Media Phone) use and ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. + config I2C_GPIO tristate "GPIO-based bitbanging I2C" depends on GENERIC_GPIO @@ -630,6 +646,16 @@ config I2C_SIMTEC This driver can also be built as a module. If so, the module will be called i2c-simtec. +config I2C_SIRF + tristate "CSR SiRFprimaII I2C interface" + depends on ARCH_PRIMA2 + help + If you say yes to this option, support will be included for the + CSR SiRFprimaII I2C interface. + + This driver can also be built as a module. If so, the module + will be called i2c-sirf. + config I2C_STU300 tristate "ST Microelectronics DDC I2C interface" depends on MACH_U300 @@ -681,20 +707,15 @@ config I2C_XILINX This driver can also be built as a module. If so, the module will be called xilinx_i2c. -config I2C_EG20T - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)" - depends on PCI +config I2C_XLR + tristate "XLR I2C support" + depends on CPU_XLR help - This driver is for PCH(Platform controller Hub) I2C of EG20T which - is an IOH(Input/Output Hub) for x86 embedded processor. - This driver can access PCH I2C bus device. + This driver enables support for the on-chip I2C interface of + the Netlogic XLR/XLS MIPS processors. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver can also be built as a module. If so, the module + will be called i2c-xlr. comment "External I2C/SMBus adapter drivers" diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index fba6da60aa0e..569567b0d027 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o +obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o @@ -63,12 +64,13 @@ obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o +obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o -obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o +obj-$(CONFIG_I2C_XLR) += i2c-xlr.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 86796488ef4f..ed9f48d566db 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -19,7 +19,6 @@ #include <mach/hardware.h> #include <asm/hardware/ioc.h> -#include <asm/system.h> #define FORCE_ONES 0xdc #define SCL 0x02 diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b6807db7b36f..e66d248fc126 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -132,7 +132,8 @@ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ static struct pci_driver ali1535_driver; -static unsigned short ali1535_smba; +static unsigned long ali1535_smba; +static unsigned short ali1535_offset; /* Detect whether a ALI1535 can be found, and initialize it, where necessary. Note the differences between kernels with the old PCI BIOS interface and @@ -140,7 +141,7 @@ static unsigned short ali1535_smba; defined to make the transition easier. */ static int __devinit ali1535_setup(struct pci_dev *dev) { - int retval = -ENODEV; + int retval; unsigned char temp; /* Check the following things: @@ -149,15 +150,28 @@ static int __devinit ali1535_setup(struct pci_dev *dev) - We can use the addresses */ + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "ALI1535_smb can't enable device\n"); + goto exit; + } + /* Determine the address of the SMBus area */ - pci_read_config_word(dev, SMBBA, &ali1535_smba); - ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); - if (ali1535_smba == 0) { + pci_read_config_word(dev, SMBBA, &ali1535_offset); + dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset); + ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); + if (ali1535_offset == 0) { dev_warn(&dev->dev, "ALI1535_smb region uninitialized - upgrade BIOS?\n"); + retval = -ENODEV; goto exit; } + if (pci_resource_flags(dev, 0) & IORESOURCE_IO) + ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset; + else + ali1535_smba = ali1535_offset; + retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name); if (retval) @@ -165,8 +179,9 @@ static int __devinit ali1535_setup(struct pci_dev *dev) if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name)) { - dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", + dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n", ali1535_smba); + retval = -EBUSY; goto exit; } @@ -174,6 +189,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBCFG, &temp); if ((temp & ALI1535_SMBIO_EN) == 0) { dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -181,6 +197,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -196,14 +213,13 @@ static int __devinit ali1535_setup(struct pci_dev *dev) */ pci_read_config_byte(dev, SMBREV, &temp); dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); - dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba); + dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba); - retval = 0; -exit: - return retval; + return 0; exit_free: release_region(ali1535_smba, ALI1535_SMB_IOSIZE); +exit: return retval; } @@ -498,7 +514,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ ali1535_adapter.dev.parent = &dev->dev; snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), - "SMBus ALI1535 adapter at %04x", ali1535_smba); + "SMBus ALI1535 adapter at %04x", ali1535_offset); return i2c_add_adapter(&ali1535_adapter); } diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index a409cfcf0629..47ae0091e027 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev) ali1563_shutdown(dev); } -static const struct pci_device_id ali1563_id_table[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 83e8a60cdc86..087ea9caa74d 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id ali15x3_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 03bcd07c4697..eb778bf15c18 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -308,7 +308,7 @@ static const char* chipname[] = { "nVidia nForce", "AMD8111", }; -static const struct pci_device_id amd756_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 6b6a6b1d7025..e5ac53b99b04 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -415,7 +415,7 @@ static const struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id amd8111_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 305c07504f7e..1679deef9c89 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -295,9 +295,6 @@ static int at91_i2c_resume(struct platform_device *pdev) #define at91_i2c_resume NULL #endif -/* work with "modprobe at91_i2c" from hotplugging or coldplugging */ -MODULE_ALIAS("platform:at91_i2c"); - static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), @@ -309,19 +306,9 @@ static struct platform_driver at91_i2c_driver = { }, }; -static int __init at91_i2c_init(void) -{ - return platform_driver_register(&at91_i2c_driver); -} - -static void __exit at91_i2c_exit(void) -{ - platform_driver_unregister(&at91_i2c_driver); -} - -module_init(at91_i2c_init); -module_exit(at91_i2c_exit); +module_platform_driver(at91_i2c_driver); MODULE_AUTHOR("Rick Bronson"); MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index f314d7f433d3..582d616db346 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -426,20 +426,9 @@ static struct platform_driver au1xpsc_smbus_driver = { .remove = __devexit_p(i2c_au1550_remove), }; -static int __init i2c_au1550_init(void) -{ - return platform_driver_register(&au1xpsc_smbus_driver); -} - -static void __exit i2c_au1550_exit(void) -{ - platform_driver_unregister(&au1xpsc_smbus_driver); -} +module_platform_driver(au1xpsc_smbus_driver); MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:au1xpsc_smbus"); - -module_init (i2c_au1550_init); -module_exit (i2c_au1550_exit); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b1d9cd28d8da..c1e1096ba069 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -724,18 +724,7 @@ static struct platform_driver cpm_i2c_driver = { }, }; -static int __init cpm_i2c_init(void) -{ - return platform_driver_register(&cpm_i2c_driver); -} - -static void __exit cpm_i2c_exit(void) -{ - platform_driver_unregister(&cpm_i2c_driver); -} - -module_init(cpm_i2c_init); -module_exit(cpm_i2c_exit); +module_platform_driver(cpm_i2c_driver); MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 9e89e7313d62..00e8f213f56e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -182,7 +182,6 @@ static int i2c_dw_pci_resume(struct device *dev) pci_restore_state(pdev); i2c_dw_init(i2c); - i2c_dw_enable(i2c); return 0; } @@ -349,7 +348,7 @@ static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("i2c_designware-pci"); -DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { +static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 5244c4724df7..4ba589ab8614 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -214,7 +214,7 @@ static int __init dw_i2c_init_driver(void) { return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); } -module_init(dw_i2c_init_driver); +subsys_initcall(dw_i2c_init_driver); static void __exit dw_i2c_exit_driver(void) { diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 18936ac9d51c..f086131cb1c7 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * 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 @@ -136,7 +136,8 @@ /* Set the number of I2C instance max Intel EG20T PCH : 1ch -OKI SEMICONDUCTOR ML7213 IOH : 2ch +LAPIS Semiconductor ML7213 IOH : 2ch +LAPIS Semiconductor ML7831 IOH : 1ch */ #define PCH_I2C_MAX_DEV 2 @@ -180,15 +181,17 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ static wait_queue_head_t pch_event; static DEFINE_MUTEX(pch_mutex); -/* Definition for ML7213 by OKI SEMICONDUCTOR */ +/* Definition for ML7213 by LAPIS Semiconductor */ #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_I2C 0x802D #define PCI_DEVICE_ID_ML7223_I2C 0x8010 +#define PCI_DEVICE_ID_ML7831_I2C 0x8817 -static struct pci_device_id __devinitdata pch_pcidev_id[] = { +static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, }, {0,} }; @@ -243,7 +246,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) if (pch_clk > PCH_MAX_CLK) pch_clk = 62500; - pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8; + pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8); /* Set transfer speed in I2CBC */ iowrite32(pch_i2cbc, p + PCH_I2CBC); @@ -268,30 +271,36 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2) /** * pch_i2c_wait_for_bus_idle() - check the status of bus. * @adap: Pointer to struct i2c_algo_pch_data. - * @timeout: waiting time counter (us). + * @timeout: waiting time counter (ms). */ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, s32 timeout) { void __iomem *p = adap->pch_base_address; - ktime_t ns_val; + int schedule = 0; + unsigned long end = jiffies + msecs_to_jiffies(timeout); + + while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) { + if (time_after(jiffies, end)) { + pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); + pch_err(adap, "%s: Timeout Error.return%d\n", + __func__, -ETIME); + pch_i2c_init(adap); - if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) - return 0; + return -ETIME; + } - /* MAX timeout value is timeout*1000*1000nsec */ - ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); - do { - msleep(20); - if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) - return 0; - } while (ktime_lt(ktime_get(), ns_val)); + if (!schedule) + /* Retry after some usecs */ + udelay(5); + else + /* Wait a bit more without consuming CPU */ + usleep_range(20, 1000); - pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); - pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); - pch_i2c_init(adap); + schedule = 1; + } - return -ETIME; + return 0; } /** @@ -775,8 +784,6 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *pmsg; u32 i = 0; u32 status; - u32 msglen; - u32 subaddrlen; s32 ret; struct i2c_algo_pch_data *adap = i2c_adap->algo_data; @@ -801,12 +808,6 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, status = pmsg->flags; pch_dbg(adap, "After invoking I2C_MODE_SEL :flag= 0x%x\n", status); - /* calculate sub address length and message length */ - /* these are applicable only for buffer mode */ - subaddrlen = pmsg->buf[0]; - /* calculate actual message length excluding - * the sub address fields */ - msglen = (pmsg->len) - (subaddrlen + 1); if ((status & (I2C_M_RD)) != false) { ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num), @@ -918,7 +919,9 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_adap->dev.parent = &pdev->dev; pch_i2c_init(&adap_info->pch_data[i]); - ret = i2c_add_adapter(pch_adap); + + pch_adap->nr = i; + ret = i2c_add_numbered_adapter(pch_adap); if (ret) { pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); goto err_add_adapter; @@ -1058,8 +1061,8 @@ static void __exit pch_pci_exit(void) } module_exit(pch_pci_exit); -MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver"); +MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C"); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.okisemi.com>"); +MODULE_AUTHOR("Tomoya MORINAGA. <tomoya-linux@dsn.lapis-semi.com>"); module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); module_param(pch_clk, int, (S_IRUSR | S_IWUSR)); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index a651779d9ff7..c0330a41db03 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -14,8 +14,15 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_device.h> - -#include <asm/gpio.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/of_i2c.h> + +struct i2c_gpio_private_data { + struct i2c_adapter adap; + struct i2c_algo_bit_data bit_data; + struct i2c_gpio_platform_data pdata; +}; /* Toggle SDA by changing the direction of the pin */ static void i2c_gpio_setsda_dir(void *data, int state) @@ -78,24 +85,62 @@ static int i2c_gpio_getscl(void *data) return gpio_get_value(pdata->scl_pin); } +static int __devinit of_i2c_gpio_probe(struct device_node *np, + struct i2c_gpio_platform_data *pdata) +{ + u32 reg; + + if (of_gpio_count(np) < 2) + return -ENODEV; + + pdata->sda_pin = of_get_gpio(np, 0); + pdata->scl_pin = of_get_gpio(np, 1); + + if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) { + pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n", + np->full_name, pdata->sda_pin, pdata->scl_pin); + return -ENODEV; + } + + of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); + + if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) + pdata->timeout = msecs_to_jiffies(reg); + + pdata->sda_is_open_drain = + of_property_read_bool(np, "i2c-gpio,sda-open-drain"); + pdata->scl_is_open_drain = + of_property_read_bool(np, "i2c-gpio,scl-open-drain"); + pdata->scl_is_output_only = + of_property_read_bool(np, "i2c-gpio,scl-output-only"); + + return 0; +} + static int __devinit i2c_gpio_probe(struct platform_device *pdev) { + struct i2c_gpio_private_data *priv; 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; + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + adap = &priv->adap; + bit_data = &priv->bit_data; + pdata = &priv->pdata; + + if (pdev->dev.of_node) { + ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata); + if (ret) + return ret; + } else { + if (!pdev->dev.platform_data) + return -ENXIO; + memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); + } ret = gpio_request(pdata->sda_pin, "sda"); if (ret) @@ -143,6 +188,7 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; /* * If "dev->id" is negative we consider it as zero. @@ -154,7 +200,9 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev) if (ret) goto err_add_bus; - platform_set_drvdata(pdev, adap); + of_i2c_register_devices(adap); + + platform_set_drvdata(pdev, priv); dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", pdata->sda_pin, pdata->scl_pin, @@ -168,34 +216,40 @@ err_add_bus: 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 __devexit i2c_gpio_remove(struct platform_device *pdev) { + struct i2c_gpio_private_data *priv; struct i2c_gpio_platform_data *pdata; struct i2c_adapter *adap; - adap = platform_get_drvdata(pdev); - pdata = pdev->dev.platform_data; + priv = platform_get_drvdata(pdev); + adap = &priv->adap; + pdata = &priv->pdata; i2c_del_adapter(adap); gpio_free(pdata->scl_pin); gpio_free(pdata->sda_pin); - kfree(adap->algo_data); - kfree(adap); return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id i2c_gpio_dt_ids[] = { + { .compatible = "i2c-gpio", }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); +#endif + static struct platform_driver i2c_gpio_driver = { .driver = { .name = "i2c-gpio", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(i2c_gpio_dt_ids), }, .probe = i2c_gpio_probe, .remove = __devexit_p(i2c_gpio_remove), diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 63bb1cc2a042..19515df61021 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -52,7 +52,7 @@ struct highlander_i2c_dev { size_t buf_len; }; -static int iic_force_poll, iic_force_normal; +static bool iic_force_poll, iic_force_normal; static int iic_timeout = 1000, iic_read_delay; static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev) @@ -468,18 +468,7 @@ static struct platform_driver highlander_i2c_driver = { .remove = __devexit_p(highlander_i2c_remove), }; -static int __init highlander_i2c_init(void) -{ - return platform_driver_register(&highlander_i2c_driver); -} - -static void __exit highlander_i2c_exit(void) -{ - platform_driver_unregister(&highlander_i2c_driver); -} - -module_init(highlander_i2c_init); -module_exit(highlander_i2c_exit); +module_platform_driver(highlander_i2c_driver); MODULE_AUTHOR("Paul Mundt"); MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter"); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 9ff1695d8458..c527de17db4f 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = { .algo_data = &hydra_bit_data, }; -static const struct pci_device_id hydra_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ab26840d0c70..ae2945a5e007 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -2,7 +2,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2007 - 2012 Jean Delvare <khali@linux-fr.org> Copyright (C) 2010 Intel Corporation, David Woodhouse <dwmw2@infradead.org> @@ -51,6 +51,7 @@ Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes DH89xxCC (PCH) 0x2330 32 hard yes yes yes Panther Point (PCH) 0x1e22 32 hard yes yes yes + Lynx Point (PCH) 0x8c22 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -105,7 +106,7 @@ #define SMBHSTCNT_KILL 2 /* Other settings */ -#define MAX_TIMEOUT 100 +#define MAX_RETRIES 400 #define ENABLE_INT9 0 /* set to 0x01 to enable - untested */ /* I801 command constants */ @@ -145,6 +146,7 @@ #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 struct i801_priv { struct i2c_adapter adapter; @@ -215,7 +217,7 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout) dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv)); - msleep(1); + usleep_range(1000, 2000); outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv)); @@ -272,11 +274,11 @@ static int i801_transaction(struct i801_priv *priv, int xact) /* We will always wait for a fraction of a second! */ do { - msleep(1); + usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); - } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); + } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES)); - result = i801_check_post(priv, status, timeout > MAX_TIMEOUT); + result = i801_check_post(priv, status, timeout > MAX_RETRIES); if (result < 0) return result; @@ -291,12 +293,12 @@ static void i801_wait_hwpec(struct i801_priv *priv) int status; do { - msleep(1); + usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); } while ((!(status & SMBHSTSTS_INTR)) - && (timeout++ < MAX_TIMEOUT)); + && (timeout++ < MAX_RETRIES)); - if (timeout > MAX_TIMEOUT) + if (timeout > MAX_RETRIES) dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n"); outb_p(status, SMBHSTSTS(priv)); @@ -380,12 +382,12 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, /* We will always wait for a fraction of a second! */ timeout = 0; do { - msleep(1); + usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); } while ((!(status & SMBHSTSTS_BYTE_DONE)) - && (timeout++ < MAX_TIMEOUT)); + && (timeout++ < MAX_RETRIES)); - result = i801_check_post(priv, status, timeout > MAX_TIMEOUT); + result = i801_check_post(priv, status, timeout > MAX_RETRIES); if (result < 0) return result; @@ -609,7 +611,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; -static const struct pci_device_id i801_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(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) }, @@ -633,6 +635,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 3c110fbc409b..806e225f3de7 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -51,11 +51,11 @@ MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_LICENSE("GPL"); -static int iic_force_poll; +static bool iic_force_poll; module_param(iic_force_poll, bool, 0); MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); -static int iic_force_fast; +static bool iic_force_fast; module_param(iic_force_fast, bool, 0); MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)"); @@ -815,15 +815,4 @@ static struct platform_driver ibm_iic_driver = { .remove = __devexit_p(iic_remove), }; -static int __init iic_init(void) -{ - return platform_driver_register(&ibm_iic_driver); -} - -static void __exit iic_exit(void) -{ - platform_driver_unregister(&ibm_iic_driver); -} - -module_init(iic_init); -module_exit(iic_exit); +module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 58832e578fff..dfb84b7ee550 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -149,11 +149,6 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) break; if (!for_busy && !(temp & I2SR_IBB)) break; - if (signal_pending(current)) { - dev_dbg(&i2c_imx->adapter.dev, - "<%s> I2C Interrupted\n", __func__); - return -EINTR; - } if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C bus is busy\n", __func__); @@ -196,7 +191,7 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); - clk_enable(i2c_imx->clk); + clk_prepare_enable(i2c_imx->clk); writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR); /* Enable I2C controller */ writeb(0, i2c_imx->base + IMX_I2C_I2SR); @@ -245,7 +240,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) /* Disable I2C controller */ writeb(0, i2c_imx->base + IMX_I2C_I2CR); - clk_disable(i2c_imx->clk); + clk_disable_unprepare(i2c_imx->clk); } static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index e828ac85cfa7..365bad5b890b 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1093,7 +1093,7 @@ static void __devexit intel_mid_i2c_remove(struct pci_dev *dev) pci_release_region(dev, 0); } -static struct pci_device_id intel_mid_i2c_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), 0 }, { PCI_VDEVICE(INTEL, 0x0803), 1 }, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index f09c9319a2ba..93f147a96b62 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -523,21 +523,7 @@ static struct platform_driver iop3xx_i2c_driver = { }, }; -static int __init -i2c_iop3xx_init (void) -{ - return platform_driver_register(&iop3xx_i2c_driver); -} - -static void __exit -i2c_iop3xx_exit (void) -{ - platform_driver_unregister(&iop3xx_i2c_driver); - return; -} - -module_init (i2c_iop3xx_init); -module_exit (i2c_iop3xx_exit); +module_platform_driver(iop3xx_i2c_driver); MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>"); MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 0682f8f277b0..f90a6057508d 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -47,7 +47,7 @@ #define SMBBLKDAT (0x20 + sch_smba) /* Other settings */ -#define MAX_TIMEOUT 500 +#define MAX_RETRIES 5000 /* I2C constants */ #define SCH_QUICK 0x00 @@ -68,7 +68,7 @@ static int sch_transaction(void) { int temp; int result = 0; - int timeout = 0; + int retries = 0; dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), @@ -100,12 +100,12 @@ static int sch_transaction(void) outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); do { - msleep(1); + usleep_range(100, 200); temp = inb(SMBHSTSTS) & 0x0f; - } while ((temp & 0x08) && (timeout++ < MAX_TIMEOUT)); + } while ((temp & 0x08) && (retries++ < MAX_RETRIES)); /* If the SMBus is still busy, we give up */ - if (timeout > MAX_TIMEOUT) { + if (retries > MAX_RETRIES) { dev_err(&sch_adapter.dev, "SMBus Timeout!\n"); result = -ETIMEDOUT; } @@ -306,20 +306,9 @@ static struct platform_driver smbus_sch_driver = { .remove = __devexit_p(smbus_sch_remove), }; -static int __init i2c_sch_init(void) -{ - return platform_driver_register(&smbus_sch_driver); -} - -static void __exit i2c_sch_exit(void) -{ - platform_driver_unregister(&smbus_sch_driver); -} +module_platform_driver(smbus_sch_driver); MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>"); MODULE_DESCRIPTION("Intel SCH SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_sch_init); -module_exit(i2c_sch_exit); MODULE_ALIAS("platform:isch_smbus"); diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index c01e9519f6c1..5d263f9014d6 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -148,18 +148,7 @@ static struct platform_driver ixp2000_i2c_driver = { }, }; -static int __init ixp2000_i2c_init(void) -{ - return platform_driver_register(&ixp2000_i2c_driver); -} - -static void __exit ixp2000_i2c_exit(void) -{ - platform_driver_unregister(&ixp2000_i2c_driver); -} - -module_init(ixp2000_i2c_init); -module_exit(ixp2000_i2c_exit); +module_platform_driver(ixp2000_i2c_driver); MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 107397a606b4..206caacd30d7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -454,7 +454,7 @@ static int mpc_write(struct mpc_i2c *i2c, int target, } static int mpc_read(struct mpc_i2c *i2c, int target, - u8 *data, int length, int restart) + u8 *data, int length, int restart, bool recv_len) { unsigned timeout = i2c->adap.timeout; int i, result; @@ -470,7 +470,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target, return result; if (length) { - if (length == 1) + if (length == 1 && !recv_len) writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); else writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA); @@ -479,17 +479,46 @@ static int mpc_read(struct mpc_i2c *i2c, int target, } for (i = 0; i < length; i++) { + u8 byte; + result = i2c_wait(i2c, timeout, 0); if (result < 0) return result; - /* Generate txack on next to last byte */ - if (i == length - 2) - writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK); - /* Do not generate stop on last byte */ - if (i == length - 1) - writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX); - data[i] = readb(i2c->base + MPC_I2C_DR); + /* + * For block reads, we have to know the total length (1st byte) + * before we can determine if we are done. + */ + if (i || !recv_len) { + /* Generate txack on next to last byte */ + if (i == length - 2) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA + | CCR_TXAK); + /* Do not generate stop on last byte */ + if (i == length - 1) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA + | CCR_MTX); + } + + byte = readb(i2c->base + MPC_I2C_DR); + + /* + * Adjust length if first received byte is length. + * The length is 1 length byte plus actually data length + */ + if (i == 0 && recv_len) { + if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + length += byte; + /* + * For block reads, generate txack here if data length + * is 1 byte (total length is 2 bytes). + */ + if (length == 2) + writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA + | CCR_TXAK); + } + data[i] = byte; } return length; @@ -532,12 +561,17 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) "Doing %s %d bytes to 0x%02x - %d of %d messages\n", pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num); - if (pmsg->flags & I2C_M_RD) - ret = - mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); - else + if (pmsg->flags & I2C_M_RD) { + bool recv_len = pmsg->flags & I2C_M_RECV_LEN; + + ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i, + recv_len); + if (recv_len && ret > 0) + pmsg->len = ret; + } else { ret = mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i); + } } mpc_i2c_stop(i2c); return (ret < 0) ? ret : num; @@ -545,7 +579,8 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) static u32 mpc_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL; } static const struct i2c_algorithm mpc_algo = { @@ -715,18 +750,7 @@ static struct platform_driver mpc_i2c_driver = { }, }; -static int __init fsl_i2c_init(void) -{ - return platform_driver_register(&mpc_i2c_driver); -} - -static void __exit fsl_i2c_exit(void) -{ - platform_driver_unregister(&mpc_i2c_driver); -} - -module_init(fsl_i2c_init); -module_exit(fsl_i2c_exit); +module_platform_driver(mpc_i2c_driver); MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and " diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a9941c65f226..4f44a33017b0 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -611,20 +611,7 @@ static struct platform_driver mv64xxx_i2c_driver = { }, }; -static int __init -mv64xxx_i2c_init(void) -{ - return platform_driver_register(&mv64xxx_i2c_driver); -} - -static void __exit -mv64xxx_i2c_exit(void) -{ - platform_driver_unregister(&mv64xxx_i2c_driver); -} - -module_init(mv64xxx_i2c_init); -module_exit(mv64xxx_i2c_exit); +module_platform_driver(mv64xxx_i2c_driver); MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 7e78f7c87857..3d471d56bf15 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -72,6 +72,7 @@ #define MXS_I2C_QUEUESTAT (0x70) #define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000 +#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F #define MXS_I2C_QUEUECMD (0x80) @@ -219,14 +220,14 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int ret; int flags; - init_completion(&i2c->cmd_complete); - dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); if (msg->len == 0) return -EINVAL; + init_completion(&i2c->cmd_complete); + flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; if (msg->flags & I2C_M_RD) @@ -286,6 +287,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) { struct mxs_i2c_dev *i2c = dev_id; u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK; + bool is_last_cmd; if (!stat) return IRQ_NONE; @@ -300,9 +302,14 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) else i2c->cmd_err = 0; - complete(&i2c->cmd_complete); + is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & + MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; + + if (is_last_cmd || i2c->cmd_err) + complete(&i2c->cmd_complete); writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); + return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ff1e127dfea8..43a96a123920 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -309,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id nforce2_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(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) }, @@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, error = acpi_check_region(smbus->base, smbus->size, nforce2_driver.name); if (error) - return -1; + return error; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1b46a9d9f907..18068dee48f1 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -394,9 +394,6 @@ static struct of_device_id ocores_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, ocores_i2c_match); -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:ocores-i2c"); - static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), @@ -409,19 +406,9 @@ static struct platform_driver ocores_i2c_driver = { }, }; -static int __init ocores_i2c_init(void) -{ - return platform_driver_register(&ocores_i2c_driver); -} - -static void __exit ocores_i2c_exit(void) -{ - platform_driver_unregister(&ocores_i2c_driver); -} - -module_init(ocores_i2c_init); -module_exit(ocores_i2c_exit); +module_platform_driver(ocores_i2c_driver); MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 56dbe54e8811..ee139a598814 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -629,24 +629,10 @@ static struct platform_driver octeon_i2c_driver = { }, }; -static int __init octeon_i2c_init(void) -{ - int rv; - - rv = platform_driver_register(&octeon_i2c_driver); - return rv; -} - -static void __exit octeon_i2c_exit(void) -{ - platform_driver_unregister(&octeon_i2c_driver); -} +module_platform_driver(octeon_i2c_driver); MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:" DRV_NAME); - -module_init(octeon_i2c_init); -module_exit(octeon_i2c_exit); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fa23faa20f0e..801df6000e9b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -37,6 +37,9 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> @@ -182,7 +185,9 @@ struct omap_i2c_dev { u32 latency; /* maximum mpu wkup latency */ void (*set_mpu_wkup_lat)(struct device *dev, long latency); - u32 speed; /* Speed of bus in Khz */ + u32 speed; /* Speed of bus in kHz */ + u32 dtrev; /* extra revision from DT */ + u32 flags; u16 cmd_err; u8 *buf; u8 *regs; @@ -235,7 +240,7 @@ static const u8 reg_map_ip_v2[] = { [OMAP_I2C_BUF_REG] = 0x94, [OMAP_I2C_CNT_REG] = 0x98, [OMAP_I2C_DATA_REG] = 0x9c, - [OMAP_I2C_SYSC_REG] = 0x20, + [OMAP_I2C_SYSC_REG] = 0x10, [OMAP_I2C_CON_REG] = 0xa4, [OMAP_I2C_OA_REG] = 0xa8, [OMAP_I2C_SA_REG] = 0xac, @@ -266,11 +271,7 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) static void omap_i2c_unidle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; - - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); @@ -291,13 +292,10 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) static void omap_i2c_idle(struct omap_i2c_dev *dev) { - struct omap_i2c_bus_platform_data *pdata; u16 iv; - pdata = dev->dev->platform_data; - dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); else omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); @@ -320,9 +318,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long timeout; unsigned long internal_clk = 0; struct clk *fclk; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ @@ -373,7 +368,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) } omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { + if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420 @@ -397,7 +392,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { + if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -406,7 +401,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * The filter is iclk (fclk for HS) period. */ if (dev->speed > 400 || - pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) + dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) internal_clk = 19200; else if (dev->speed > 100) internal_clk = 9600; @@ -475,7 +470,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) dev->errata = 0; - if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) + if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; /* Enable interrupts */ @@ -484,7 +479,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); - if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { dev->pscstate = psc; dev->scllstate = scll; dev->sclhstate = sclh; @@ -804,9 +799,6 @@ omap_i2c_isr(int this_irq, void *dev_id) u16 bits; u16 stat, w; int err, count = 0; - struct omap_i2c_bus_platform_data *pdata; - - pdata = dev->dev->platform_data; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; @@ -830,11 +822,9 @@ complete: ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - if (stat & OMAP_I2C_STAT_NACK) { + if (stat & OMAP_I2C_STAT_NACK) err |= OMAP_I2C_STAT_NACK; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, - OMAP_I2C_CON_STP); - } + if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; @@ -875,7 +865,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { *dev->buf++ = w >> 8; @@ -918,7 +908,7 @@ complete: * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (pdata->flags & + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { if (dev->buf_len) { w |= *dev->buf++ << 8; @@ -965,6 +955,32 @@ static const struct i2c_algorithm omap_i2c_algo = { .functionality = omap_i2c_func, }; +#ifdef CONFIG_OF +static struct omap_i2c_bus_platform_data omap3_pdata = { + .rev = OMAP_I2C_IP_VERSION_1, + .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 | + OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | + OMAP_I2C_FLAG_BUS_SHIFT_2, +}; + +static struct omap_i2c_bus_platform_data omap4_pdata = { + .rev = OMAP_I2C_IP_VERSION_2, +}; + +static const struct of_device_id omap_i2c_of_match[] = { + { + .compatible = "ti,omap4-i2c", + .data = &omap4_pdata, + }, + { + .compatible = "ti,omap3-i2c", + .data = &omap3_pdata, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, omap_i2c_of_match); +#endif + static int __devinit omap_i2c_probe(struct platform_device *pdev) { @@ -972,9 +988,10 @@ omap_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct resource *mem, *irq, *ioarea; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; + const struct of_device_id *match; irq_handler_t isr; int r; - u32 speed = 0; /* NOTE: driver uses the static register mapping */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1001,15 +1018,24 @@ omap_i2c_probe(struct platform_device *pdev) goto err_release_region; } - if (pdata != NULL) { - speed = pdata->clkrate; + match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); + if (match) { + u32 freq = 100000; /* default to 100000 Hz */ + + pdata = match->data; + dev->dtrev = pdata->rev; + dev->flags = pdata->flags; + + of_property_read_u32(node, "clock-frequency", &freq); + /* convert DT freq value in Hz into kHz for speed */ + dev->speed = freq / 1000; + } else if (pdata != NULL) { + dev->speed = pdata->clkrate; + dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; - } else { - speed = 100; /* Default speed */ - dev->set_mpu_wkup_lat = NULL; + dev->dtrev = pdata->rev; } - dev->speed = speed; dev->dev = &pdev->dev; dev->irq = irq->start; dev->base = ioremap(mem->start, resource_size(mem)); @@ -1020,9 +1046,9 @@ omap_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; + dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - if (pdata->rev == OMAP_I2C_IP_VERSION_2) + if (dev->dtrev == OMAP_I2C_IP_VERSION_2) dev->regs = (u8 *)reg_map_ip_v2; else dev->regs = (u8 *)reg_map_ip_v1; @@ -1035,7 +1061,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->rev <= OMAP_I2C_REV_ON_3430) dev->errata |= I2C_OMAP3_1P153; - if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) { + if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; /* Set up the fifo size - Get total size */ @@ -1058,7 +1084,7 @@ omap_i2c_probe(struct platform_device *pdev) /* calculate wakeup latency constraint for MPU */ if (dev->set_mpu_wkup_lat != NULL) dev->latency = (1000000 * dev->fifo_size) / - (1000 * speed / 8); + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ @@ -1074,7 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, - pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed); + dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); pm_runtime_put(dev->dev); @@ -1085,6 +1111,7 @@ omap_i2c_probe(struct platform_device *pdev) strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; @@ -1094,6 +1121,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(adap); + return 0; err_free_irq: @@ -1166,6 +1195,7 @@ static struct platform_driver omap_i2c_driver = { .name = "omap_i2c", .owner = THIS_MODULE, .pm = OMAP_I2C_PM_OPS, + .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 837b8c1aa02a..eaaea73209c5 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -401,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static const struct pci_device_id pasemi_smb_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index ace67995d7de..2adbf1a8fdea 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -286,20 +286,8 @@ static struct platform_driver i2c_pca_pf_driver = { }, }; -static int __init i2c_pca_pf_init(void) -{ - return platform_driver_register(&i2c_pca_pf_driver); -} - -static void __exit i2c_pca_pf_exit(void) -{ - platform_driver_unregister(&i2c_pca_pf_driver); -} +module_platform_driver(i2c_pca_pf_driver); MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_pca_pf_init); -module_exit(i2c_pca_pf_exit); - diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d14ac2e3c41..c14d48dd601a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id piix4_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 127051b06921..07b7447ecbc9 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -627,9 +627,6 @@ static struct i2c_adapter pmcmsptwi_adapter = { .name = DRV_NAME, }; -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:" DRV_NAME); - static struct platform_driver pmcmsptwi_driver = { .probe = pmcmsptwi_probe, .remove = __devexit_p(pmcmsptwi_remove), @@ -639,18 +636,8 @@ static struct platform_driver pmcmsptwi_driver = { }, }; -static int __init pmcmsptwi_init(void) -{ - return platform_driver_register(&pmcmsptwi_driver); -} - -static void __exit pmcmsptwi_exit(void) -{ - platform_driver_unregister(&pmcmsptwi_driver); -} +module_platform_driver(pmcmsptwi_driver); MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver"); MODULE_LICENSE("GPL"); - -module_init(pmcmsptwi_init); -module_exit(pmcmsptwi_exit); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index b289ec99eeba..7b397c6f607e 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -312,10 +312,6 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) return rc; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c-powermac"); - static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, .remove = __devexit_p(i2c_powermac_remove), @@ -325,17 +321,6 @@ static struct platform_driver i2c_powermac_driver = { }, }; -static int __init i2c_powermac_init(void) -{ - platform_driver_register(&i2c_powermac_driver); - return 0; -} +module_platform_driver(i2c_powermac_driver); - -static void __exit i2c_powermac_cleanup(void) -{ - platform_driver_unregister(&i2c_powermac_driver); -} - -module_init(i2c_powermac_init); -module_exit(i2c_powermac_cleanup); +MODULE_ALIAS("platform:i2c-powermac"); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 632e088760a3..a05817980556 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -150,7 +150,7 @@ static void __devexit ce4100_i2c_remove(struct pci_dev *dev) kfree(sds); } -static struct pci_device_id ce4100_i2c_devices[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { }, }; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index d60364650990..f6733267fa9c 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -29,6 +29,8 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/i2c-pxa.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_i2c.h> #include <linux/platform_device.h> #include <linux/err.h> @@ -1044,23 +1046,60 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -static int i2c_pxa_probe(struct platform_device *dev) +static struct of_device_id i2c_pxa_dt_ids[] = { + { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, + { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, + { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); + +static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, + enum pxa_i2c_types *i2c_types) { - struct pxa_i2c *i2c; - struct resource *res; - struct i2c_pxa_platform_data *plat = dev->dev.platform_data; - const struct platform_device_id *id = platform_get_device_id(dev); - enum pxa_i2c_types i2c_type = id->driver_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(i2c_pxa_dt_ids, &pdev->dev); int ret; - int irq; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - irq = platform_get_irq(dev, 0); - if (res == NULL || irq < 0) - return -ENODEV; + if (!of_id) + return 1; + ret = of_alias_get_id(np, "i2c"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + pdev->id = ret; + if (of_get_property(np, "mrvl,i2c-polling", NULL)) + i2c->use_pio = 1; + if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) + i2c->fast_mode = 1; + *i2c_types = (u32)(of_id->data); + return 0; +} - if (!request_mem_region(res->start, resource_size(res), res->name)) - return -ENOMEM; +static int i2c_pxa_probe_pdata(struct platform_device *pdev, + struct pxa_i2c *i2c, + enum pxa_i2c_types *i2c_types) +{ + struct i2c_pxa_platform_data *plat = pdev->dev.platform_data; + const struct platform_device_id *id = platform_get_device_id(pdev); + + *i2c_types = id->driver_data; + if (plat) { + i2c->use_pio = plat->use_pio; + i2c->fast_mode = plat->fast_mode; + } + return 0; +} + +static int i2c_pxa_probe(struct platform_device *dev) +{ + struct i2c_pxa_platform_data *plat = dev->dev.platform_data; + enum pxa_i2c_types i2c_type; + struct pxa_i2c *i2c; + struct resource *res = NULL; + int ret, irq; i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); if (!i2c) { @@ -1068,6 +1107,24 @@ static int i2c_pxa_probe(struct platform_device *dev) goto emalloc; } + ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type); + if (ret > 0) + ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type); + if (ret < 0) + goto eclk; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + irq = platform_get_irq(dev, 0); + if (res == NULL || irq < 0) { + ret = -ENODEV; + goto eclk; + } + + if (!request_mem_region(res->start, resource_size(res), res->name)) { + ret = -ENOMEM; + goto eclk; + } + i2c->adap.owner = THIS_MODULE; i2c->adap.retries = 5; @@ -1109,21 +1166,16 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->slave_addr = I2C_PXA_SLAVE_ADDR; -#ifdef CONFIG_I2C_PXA_SLAVE if (plat) { +#ifdef CONFIG_I2C_PXA_SLAVE i2c->slave_addr = plat->slave_addr; i2c->slave = plat->slave; - } #endif - - clk_enable(i2c->clk); - - if (plat) { i2c->adap.class = plat->class; - i2c->use_pio = plat->use_pio; - i2c->fast_mode = plat->fast_mode; } + clk_enable(i2c->clk); + if (i2c->use_pio) { i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { @@ -1234,6 +1286,7 @@ static struct platform_driver i2c_pxa_driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, .pm = I2C_PXA_DEV_PM_OPS, + .of_match_table = i2c_pxa_dt_ids, }, .id_table = i2c_pxa_id_table, }; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4c1718081685..737f7218a32c 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -31,6 +31,7 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/slab.h> @@ -564,6 +565,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, int retry; int ret; + pm_runtime_get_sync(&adap->dev); clk_enable(i2c->clk); for (retry = 0; retry < adap->retries; retry++) { @@ -572,6 +574,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, if (ret != -EAGAIN) { clk_disable(i2c->clk); + pm_runtime_put_sync(&adap->dev); return ret; } @@ -581,6 +584,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, } clk_disable(i2c->clk); + pm_runtime_put_sync(&adap->dev); return -EREMOTEIO; } @@ -890,7 +894,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) } } - i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); + i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL); if (!i2c) { dev_err(&pdev->dev, "no memory for state\n"); return -ENOMEM; @@ -1013,6 +1017,9 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) of_i2c_register_devices(&i2c->adap); platform_set_drvdata(pdev, i2c); + pm_runtime_enable(&pdev->dev); + pm_runtime_enable(&i2c->adap.dev); + dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); clk_disable(i2c->clk); return 0; @@ -1035,7 +1042,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) clk_put(i2c->clk); err_noclk: - kfree(i2c); return ret; } @@ -1048,6 +1054,9 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + pm_runtime_disable(&i2c->adap.dev); + pm_runtime_disable(&pdev->dev); + s3c24xx_i2c_deregister_cpufreq(i2c); i2c_del_adapter(&i2c->adap); @@ -1061,7 +1070,6 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) release_resource(i2c->ioarea); s3c24xx_i2c_dt_gpio_free(i2c); kfree(i2c->ioarea); - kfree(i2c); return 0; } diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index a67132b2e092..c0c9dffbdb12 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -560,18 +560,7 @@ static struct platform_driver sh7760_i2c_drv = { .remove = __devexit_p(sh7760_i2c_remove), }; -static int __init sh7760_i2c_init(void) -{ - return platform_driver_register(&sh7760_i2c_drv); -} - -static void __exit sh7760_i2c_exit(void) -{ - platform_driver_unregister(&sh7760_i2c_drv); -} - -module_init(sh7760_i2c_init); -module_exit(sh7760_i2c_exit); +module_platform_driver(sh7760_i2c_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 2fc08fbf67a2..4fc87e7c94c9 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -156,12 +156,8 @@ static int simtec_i2c_remove(struct platform_device *dev) return 0; } - /* device driver */ -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:simtec-i2c"); - static struct platform_driver simtec_i2c_driver = { .driver = { .name = "simtec-i2c", @@ -171,19 +167,9 @@ static struct platform_driver simtec_i2c_driver = { .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_platform_driver(simtec_i2c_driver); MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:simtec-i2c"); diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c new file mode 100644 index 000000000000..5574a47792fb --- /dev/null +++ b/drivers/i2c/busses/i2c-sirf.c @@ -0,0 +1,459 @@ +/* + * I2C bus driver for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> + +#define SIRFSOC_I2C_CLK_CTRL 0x00 +#define SIRFSOC_I2C_STATUS 0x0C +#define SIRFSOC_I2C_CTRL 0x10 +#define SIRFSOC_I2C_IO_CTRL 0x14 +#define SIRFSOC_I2C_SDA_DELAY 0x18 +#define SIRFSOC_I2C_CMD_START 0x1C +#define SIRFSOC_I2C_CMD_BUF 0x30 +#define SIRFSOC_I2C_DATA_BUF 0x80 + +#define SIRFSOC_I2C_CMD_BUF_MAX 16 +#define SIRFSOC_I2C_DATA_BUF_MAX 16 + +#define SIRFSOC_I2C_CMD(x) (SIRFSOC_I2C_CMD_BUF + (x)*0x04) +#define SIRFSOC_I2C_DATA_MASK(x) (0xFF<<(((x)&3)*8)) +#define SIRFSOC_I2C_DATA_SHIFT(x) (((x)&3)*8) + +#define SIRFSOC_I2C_DIV_MASK (0xFFFF) + +/* I2C status flags */ +#define SIRFSOC_I2C_STAT_BUSY BIT(0) +#define SIRFSOC_I2C_STAT_TIP BIT(1) +#define SIRFSOC_I2C_STAT_NACK BIT(2) +#define SIRFSOC_I2C_STAT_TR_INT BIT(4) +#define SIRFSOC_I2C_STAT_STOP BIT(6) +#define SIRFSOC_I2C_STAT_CMD_DONE BIT(8) +#define SIRFSOC_I2C_STAT_ERR BIT(9) +#define SIRFSOC_I2C_CMD_INDEX (0x1F<<16) + +/* I2C control flags */ +#define SIRFSOC_I2C_RESET BIT(0) +#define SIRFSOC_I2C_CORE_EN BIT(1) +#define SIRFSOC_I2C_MASTER_MODE BIT(2) +#define SIRFSOC_I2C_CMD_DONE_EN BIT(11) +#define SIRFSOC_I2C_ERR_INT_EN BIT(12) + +#define SIRFSOC_I2C_SDA_DELAY_MASK (0xFF) +#define SIRFSOC_I2C_SCLF_FILTER (3<<8) + +#define SIRFSOC_I2C_START_CMD BIT(0) + +#define SIRFSOC_I2C_CMD_RP(x) ((x)&0x7) +#define SIRFSOC_I2C_NACK BIT(3) +#define SIRFSOC_I2C_WRITE BIT(4) +#define SIRFSOC_I2C_READ BIT(5) +#define SIRFSOC_I2C_STOP BIT(6) +#define SIRFSOC_I2C_START BIT(7) + +#define SIRFSOC_I2C_DEFAULT_SPEED 100000 + +struct sirfsoc_i2c { + void __iomem *base; + struct clk *clk; + u32 cmd_ptr; /* Current position in CMD buffer */ + u8 *buf; /* Buffer passed by user */ + u32 msg_len; /* Message length */ + u32 finished_len; /* number of bytes read/written */ + u32 read_cmd_len; /* number of read cmd sent */ + int msg_read; /* 1 indicates a read message */ + int err_status; /* 1 indicates an error on bus */ + + u32 sda_delay; /* For suspend/resume */ + u32 clk_div; + int last; /* Last message in transfer, STOP cmd can be sent */ + + struct completion done; /* indicates completion of message transfer */ + struct i2c_adapter adapter; +}; + +static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic) +{ + u32 data = 0; + int i; + + for (i = 0; i < siic->read_cmd_len; i++) { + if (!(i & 0x3)) + data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i); + siic->buf[siic->finished_len++] = + (u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >> + SIRFSOC_I2C_DATA_SHIFT(i)); + } +} + +static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic) +{ + u32 regval; + int i = 0; + + if (siic->msg_read) { + while (((siic->finished_len + i) < siic->msg_len) + && (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) { + regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0); + if (((siic->finished_len + i) == + (siic->msg_len - 1)) && siic->last) + regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK; + writel(regval, + siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); + i++; + } + + siic->read_cmd_len = i; + } else { + while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1) + && (siic->finished_len < siic->msg_len)) { + regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0); + if ((siic->finished_len == (siic->msg_len - 1)) + && siic->last) + regval |= SIRFSOC_I2C_STOP; + writel(regval, + siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); + writel(siic->buf[siic->finished_len++], + siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); + } + } + siic->cmd_ptr = 0; + + /* Trigger the transfer */ + writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START); +} + +static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id) +{ + struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id; + u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS); + + if (i2c_stat & SIRFSOC_I2C_STAT_ERR) { + /* Error conditions */ + siic->err_status = 1; + writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS); + + if (i2c_stat & SIRFSOC_I2C_STAT_NACK) + dev_err(&siic->adapter.dev, "ACK not received\n"); + else + dev_err(&siic->adapter.dev, "I2C error\n"); + + complete(&siic->done); + } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) { + /* CMD buffer execution complete */ + if (siic->msg_read) + i2c_sirfsoc_read_data(siic); + if (siic->finished_len == siic->msg_len) + complete(&siic->done); + else /* Fill a new CMD buffer for left data */ + i2c_sirfsoc_queue_cmd(siic); + + writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS); + } + + return IRQ_HANDLED; +} + +static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic, + struct i2c_msg *msg) +{ + unsigned char addr; + u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE; + + /* no data and last message -> add STOP */ + if (siic->last && (msg->len == 0)) + regval |= SIRFSOC_I2C_STOP; + + writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); + + addr = msg->addr << 1; /* Generate address */ + if (msg->flags & I2C_M_RD) + addr |= 1; + + writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++)); +} + +static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg) +{ + u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL); + /* timeout waiting for the xfer to finish or fail */ + int timeout = msecs_to_jiffies((msg->len + 1) * 50); + int ret = 0; + + i2c_sirfsoc_set_address(siic, msg); + + writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN, + siic->base + SIRFSOC_I2C_CTRL); + i2c_sirfsoc_queue_cmd(siic); + + if (wait_for_completion_timeout(&siic->done, timeout) == 0) { + siic->err_status = 1; + dev_err(&siic->adapter.dev, "Transfer timeout\n"); + } + + writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN), + siic->base + SIRFSOC_I2C_CTRL); + writel(0, siic->base + SIRFSOC_I2C_CMD_START); + + if (siic->err_status) { + writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, + siic->base + SIRFSOC_I2C_CTRL); + while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) + cpu_relax(); + + ret = -EIO; + } + + return ret; +} + +static u32 i2c_sirfsoc_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct sirfsoc_i2c *siic = adap->algo_data; + int i, ret; + + clk_enable(siic->clk); + + for (i = 0; i < num; i++) { + siic->buf = msgs[i].buf; + siic->msg_len = msgs[i].len; + siic->msg_read = !!(msgs[i].flags & I2C_M_RD); + siic->err_status = 0; + siic->cmd_ptr = 0; + siic->finished_len = 0; + siic->last = (i == (num - 1)); + + ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]); + if (ret) { + clk_disable(siic->clk); + return ret; + } + } + + clk_disable(siic->clk); + return num; +} + +/* I2C algorithms associated with this master controller driver */ +static const struct i2c_algorithm i2c_sirfsoc_algo = { + .master_xfer = i2c_sirfsoc_xfer, + .functionality = i2c_sirfsoc_func, +}; + +static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev) +{ + struct sirfsoc_i2c *siic; + struct i2c_adapter *adap; + struct resource *mem_res; + struct clk *clk; + int bitrate; + int ctrl_speed; + int irq; + + int err; + u32 regval; + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + err = PTR_ERR(clk); + dev_err(&pdev->dev, "Clock get failed\n"); + goto err_get_clk; + } + + err = clk_prepare(clk); + if (err) { + dev_err(&pdev->dev, "Clock prepare failed\n"); + goto err_clk_prep; + } + + err = clk_enable(clk); + if (err) { + dev_err(&pdev->dev, "Clock enable failed\n"); + goto err_clk_en; + } + + ctrl_speed = clk_get_rate(clk); + + siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL); + if (!siic) { + dev_err(&pdev->dev, "Can't allocate driver data\n"); + err = -ENOMEM; + goto out; + } + adap = &siic->adapter; + adap->class = I2C_CLASS_HWMON; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem_res == NULL) { + dev_err(&pdev->dev, "Unable to get MEM resource\n"); + err = -EINVAL; + goto out; + } + + siic->base = devm_request_and_ioremap(&pdev->dev, mem_res); + if (siic->base == NULL) { + dev_err(&pdev->dev, "IO remap failed!\n"); + err = -ENOMEM; + goto out; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + err = irq; + goto out; + } + err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0, + dev_name(&pdev->dev), siic); + if (err) + goto out; + + adap->algo = &i2c_sirfsoc_algo; + adap->algo_data = siic; + + adap->dev.parent = &pdev->dev; + adap->nr = pdev->id; + + strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name)); + + platform_set_drvdata(pdev, adap); + init_completion(&siic->done); + + /* Controller Initalisation */ + + writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); + while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) + cpu_relax(); + writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, + siic->base + SIRFSOC_I2C_CTRL); + + siic->clk = clk; + + err = of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &bitrate); + if (err < 0) + bitrate = SIRFSOC_I2C_DEFAULT_SPEED; + + if (bitrate < 100000) + regval = + (2 * ctrl_speed) / (2 * bitrate * 11); + else + regval = ctrl_speed / (bitrate * 5); + + writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL); + if (regval > 0xFF) + writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY); + else + writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY); + + err = i2c_add_numbered_adapter(adap); + if (err < 0) { + dev_err(&pdev->dev, "Can't add new i2c adapter\n"); + goto out; + } + + clk_disable(clk); + + dev_info(&pdev->dev, " I2C adapter ready to operate\n"); + + return 0; + +out: + clk_disable(clk); +err_clk_en: + clk_unprepare(clk); +err_clk_prep: + clk_put(clk); +err_get_clk: + return err; +} + +static int __devexit i2c_sirfsoc_remove(struct platform_device *pdev) +{ + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + struct sirfsoc_i2c *siic = adapter->algo_data; + + writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); + i2c_del_adapter(adapter); + clk_unprepare(siic->clk); + clk_put(siic->clk); + return 0; +} + +#ifdef CONFIG_PM +static int i2c_sirfsoc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + struct sirfsoc_i2c *siic = adapter->algo_data; + + clk_enable(siic->clk); + siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY); + siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL); + clk_disable(siic->clk); + return 0; +} + +static int i2c_sirfsoc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct i2c_adapter *adapter = platform_get_drvdata(pdev); + struct sirfsoc_i2c *siic = adapter->algo_data; + + clk_enable(siic->clk); + writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); + writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE, + siic->base + SIRFSOC_I2C_CTRL); + writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL); + writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY); + clk_disable(siic->clk); + return 0; +} + +static const struct dev_pm_ops i2c_sirfsoc_pm_ops = { + .suspend = i2c_sirfsoc_suspend, + .resume = i2c_sirfsoc_resume, +}; +#endif + +static const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = { + { .compatible = "sirf,prima2-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match); + +static struct platform_driver i2c_sirfsoc_driver = { + .driver = { + .name = "sirfsoc_i2c", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &i2c_sirfsoc_pm_ops, +#endif + .of_match_table = sirfsoc_i2c_of_match, + }, + .probe = i2c_sirfsoc_probe, + .remove = __devexit_p(i2c_sirfsoc_remove), +}; +module_platform_driver(i2c_sirfsoc_driver); + +MODULE_DESCRIPTION("SiRF SoC I2C master controller driver"); +MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, " + "Xiangzhen Ye <Xiangzhen.Ye@csr.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 437586611d4a..87e5126d449c 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) u16 a; u8 val; int *i; - int retval = -ENODEV; + int retval; /* Look for imposters */ for (i = blacklist; *i != 0; i++) { @@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) error: release_region(sis5595_base + SMB_INDEX, 2); - return retval; + return -ENODEV; } static int sis5595_transaction(struct i2c_adapter *adap) @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis5595_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e6f539e26f65..15cf78f65ce0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -93,8 +93,8 @@ static struct pci_driver sis630_driver; /* insmod parameters */ -static int high_clock; -static int force; +static bool high_clock; +static bool force; module_param(high_clock, bool, 0); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); module_param(force, bool, 0); @@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) { unsigned char b; struct pci_dev *dummy = NULL; - int retval = -ENODEV, i; + int retval, i; /* check for supported SiS devices */ for (i=0; supported[i] > 0 ; i++) { @@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) */ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n"); + retval = -ENODEV; goto exit; } /* if ACPI already enabled , do nothing */ if (!(b & 0x80) && pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) { dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n"); + retval = -ENODEV; goto exit; } /* Determine the ACPI base address */ if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n"); + retval = -ENODEV; goto exit; } @@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); + retval = -EBUSY; goto exit; } @@ -468,7 +472,7 @@ static struct i2c_adapter sis630_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis630_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 86837f0c4cb9..cc5d149413f7 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis96x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 6381604696d3..e978635e60f0 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -457,7 +457,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, int ret; tegra_i2c_flush_fifos(i2c_dev); - i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS); if (msg->len == 0) return -EINVAL; @@ -755,7 +754,7 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, - .remove = tegra_i2c_remove, + .remove = __devexit_p(tegra_i2c_remove), #ifdef CONFIG_PM .suspend = tegra_i2c_suspend, .resume = tegra_i2c_resume, diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 60556012312f..f585aead50cc 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> +#include <linux/of_i2c.h> #define I2C_CONTROL 0x00 #define I2C_CONTROLS 0x00 @@ -99,6 +100,7 @@ static int i2c_versatile_probe(struct platform_device *dev) strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name)); i2c->adap.algo_data = &i2c->algo; i2c->adap.dev.parent = &dev->dev; + i2c->adap.dev.of_node = dev->dev.of_node; i2c->algo = i2c_versatile_algo; i2c->algo.data = i2c; @@ -111,6 +113,7 @@ static int i2c_versatile_probe(struct platform_device *dev) ret = i2c_bit_add_bus(&i2c->adap); if (ret >= 0) { platform_set_drvdata(dev, i2c); + of_i2c_register_devices(&i2c->adap); return 0; } @@ -133,12 +136,19 @@ static int i2c_versatile_remove(struct platform_device *dev) return 0; } +static const struct of_device_id i2c_versatile_match[] = { + { .compatible = "arm,versatile-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_versatile_match); + static struct platform_driver i2c_versatile_driver = { .probe = i2c_versatile_probe, .remove = i2c_versatile_remove, .driver = { .name = "versatile-i2c", .owner = THIS_MODULE, + .of_match_table = i2c_versatile_match, }, }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 7799fe5bda88..713d31ade26b 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = { }; -static const struct pci_device_id vt586b_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0b012f1f8ac5..333011c83d52 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -91,7 +91,7 @@ static unsigned short SMBHSTCFG = 0xD2; /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); @@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned char temp; - int error = -ENODEV; + int error; /* Determine the address of the SMBus areas */ if (force_addr) { @@ -390,6 +390,7 @@ found: dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " "controller not enabled! - upgrade BIOS or " "use force=1\n"); + error = -ENODEV; goto release_region; } } @@ -422,9 +423,11 @@ found: "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); - if (i2c_add_adapter(&vt596_adapter)) { + error = i2c_add_adapter(&vt596_adapter); + if (error) { pci_dev_put(vt596_pdev); vt596_pdev = NULL; + goto release_region; } /* Always return failure here. This is to allow other drivers to bind @@ -438,7 +441,7 @@ release_region: return error; } -static const struct pci_device_id vt596_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(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), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index ac083a28ae08..2bded7647ef2 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -795,10 +795,6 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev) return 0; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:"DRIVER_NAME); - static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, .remove = __devexit_p(xiic_i2c_remove), @@ -808,19 +804,9 @@ static struct platform_driver xiic_i2c_driver = { }, }; -static int __init xiic_i2c_init(void) -{ - return platform_driver_register(&xiic_i2c_driver); -} - -static void __exit xiic_i2c_exit(void) -{ - platform_driver_unregister(&xiic_i2c_driver); -} - -module_init(xiic_i2c_init); -module_exit(xiic_i2c_exit); +module_platform_driver(xiic_i2c_driver); MODULE_AUTHOR("info@mocean-labs.com"); MODULE_DESCRIPTION("Xilinx I2C bus driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c new file mode 100644 index 000000000000..96d3fabd8883 --- /dev/null +++ b/drivers/i2c/busses/i2c-xlr.c @@ -0,0 +1,278 @@ +/* + * Copyright 2011, Netlogic Microsystems Inc. + * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +/* XLR I2C REGISTERS */ +#define XLR_I2C_CFG 0x00 +#define XLR_I2C_CLKDIV 0x01 +#define XLR_I2C_DEVADDR 0x02 +#define XLR_I2C_ADDR 0x03 +#define XLR_I2C_DATAOUT 0x04 +#define XLR_I2C_DATAIN 0x05 +#define XLR_I2C_STATUS 0x06 +#define XLR_I2C_STARTXFR 0x07 +#define XLR_I2C_BYTECNT 0x08 +#define XLR_I2C_HDSTATIM 0x09 + +/* XLR I2C REGISTERS FLAGS */ +#define XLR_I2C_BUS_BUSY 0x01 +#define XLR_I2C_SDOEMPTY 0x02 +#define XLR_I2C_RXRDY 0x04 +#define XLR_I2C_ACK_ERR 0x08 +#define XLR_I2C_ARB_STARTERR 0x30 + +/* Register Values */ +#define XLR_I2C_CFG_ADDR 0xF8 +#define XLR_I2C_CFG_NOADDR 0xFA +#define XLR_I2C_STARTXFR_ND 0x02 /* No Data */ +#define XLR_I2C_STARTXFR_RD 0x01 /* Read */ +#define XLR_I2C_STARTXFR_WR 0x00 /* Write */ + +#define XLR_I2C_TIMEOUT 10 /* timeout per byte in msec */ + +/* + * On XLR/XLS, we need to use __raw_ IO to read the I2C registers + * because they are in the big-endian MMIO area on the SoC. + * + * The readl/writel implementation on XLR/XLS byteswaps, because + * those are for its little-endian PCI space (see arch/mips/Kconfig). + */ +static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val) +{ + __raw_writel(val, base + reg); +} + +static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg) +{ + return __raw_readl(base + reg); +} + +struct xlr_i2c_private { + struct i2c_adapter adap; + u32 __iomem *iobase; +}; + +static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, + u8 *buf, u16 addr) +{ + struct i2c_adapter *adap = &priv->adap; + unsigned long timeout, stoptime, checktime; + u32 i2c_status; + int pos, timedout; + u8 offset, byte; + + offset = buf[0]; + xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); + xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); + xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR); + xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); + + timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); + stoptime = jiffies + timeout; + timedout = 0; + pos = 1; +retry: + if (len == 1) { + xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, + XLR_I2C_STARTXFR_ND); + } else { + xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]); + xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, + XLR_I2C_STARTXFR_WR); + } + + while (!timedout) { + checktime = jiffies; + i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); + + if (i2c_status & XLR_I2C_SDOEMPTY) { + pos++; + /* need to do a empty dataout after the last byte */ + byte = (pos < len) ? buf[pos] : 0; + xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte); + + /* reset timeout on successful xmit */ + stoptime = jiffies + timeout; + } + timedout = time_after(checktime, stoptime); + + if (i2c_status & XLR_I2C_ARB_STARTERR) { + if (timedout) + break; + goto retry; + } + + if (i2c_status & XLR_I2C_ACK_ERR) + return -EIO; + + if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len) + return 0; + } + dev_err(&adap->dev, "I2C transmit timeout\n"); + return -ETIMEDOUT; +} + +static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) +{ + struct i2c_adapter *adap = &priv->adap; + u32 i2c_status; + unsigned long timeout, stoptime, checktime; + int nbytes, timedout; + u8 byte; + + xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR); + xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len); + xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); + + timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); + stoptime = jiffies + timeout; + timedout = 0; + nbytes = 0; +retry: + xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD); + + while (!timedout) { + checktime = jiffies; + i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); + if (i2c_status & XLR_I2C_RXRDY) { + if (nbytes > len) + return -EIO; /* should not happen */ + + /* we need to do a dummy datain when nbytes == len */ + byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); + if (nbytes < len) + buf[nbytes] = byte; + nbytes++; + + /* reset timeout on successful read */ + stoptime = jiffies + timeout; + } + + timedout = time_after(checktime, stoptime); + if (i2c_status & XLR_I2C_ARB_STARTERR) { + if (timedout) + break; + goto retry; + } + + if (i2c_status & XLR_I2C_ACK_ERR) + return -EIO; + + if ((i2c_status & XLR_I2C_BUS_BUSY) == 0) + return 0; + } + + dev_err(&adap->dev, "I2C receive timeout\n"); + return -ETIMEDOUT; +} + +static int xlr_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct i2c_msg *msg; + int i; + int ret = 0; + struct xlr_i2c_private *priv = i2c_get_adapdata(adap); + + for (i = 0; ret == 0 && i < num; i++) { + msg = &msgs[i]; + if (msg->flags & I2C_M_RD) + ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0], + msg->addr); + else + ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0], + msg->addr); + } + + return (ret != 0) ? ret : num; +} + +static u32 xlr_func(struct i2c_adapter *adap) +{ + /* Emulate SMBUS over I2C */ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; +} + +static struct i2c_algorithm xlr_i2c_algo = { + .master_xfer = xlr_i2c_xfer, + .functionality = xlr_func, +}; + +static int __devinit xlr_i2c_probe(struct platform_device *pdev) +{ + struct xlr_i2c_private *priv; + struct resource *res; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->iobase = devm_request_and_ioremap(&pdev->dev, res); + if (!priv->iobase) { + dev_err(&pdev->dev, "devm_request_and_ioremap failed\n"); + return -EBUSY; + } + + priv->adap.dev.parent = &pdev->dev; + priv->adap.owner = THIS_MODULE; + priv->adap.algo_data = priv; + priv->adap.algo = &xlr_i2c_algo; + priv->adap.nr = pdev->id; + priv->adap.class = I2C_CLASS_HWMON; + snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); + + i2c_set_adapdata(&priv->adap, priv); + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret < 0) { + dev_err(&priv->adap.dev, "Failed to add i2c bus.\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + dev_info(&priv->adap.dev, "Added I2C Bus.\n"); + return 0; +} + +static int __devexit xlr_i2c_remove(struct platform_device *pdev) +{ + struct xlr_i2c_private *priv; + + priv = platform_get_drvdata(pdev); + i2c_del_adapter(&priv->adap); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver xlr_i2c_driver = { + .probe = xlr_i2c_probe, + .remove = __devexit_p(xlr_i2c_remove), + .driver = { + .name = "xlr-i2cbus", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(xlr_i2c_driver); + +MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>"); +MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:xlr-i2cbus"); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 91e349c884c5..2eacb7784d56 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -559,7 +559,7 @@ static struct platform_driver scx200_pci_driver = { .remove = __devexit_p(scx200_remove), }; -static const struct pci_device_id scx200_isa[] __initconst = { +static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, { 0, } diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 10274ffb66d7..f24cc64e2e8c 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -13,7 +13,8 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. */ #include <linux/kernel.h> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 1e5606185b4f..feb7dc359186 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -14,7 +14,8 @@ 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. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>. @@ -1386,8 +1387,10 @@ int i2c_master_send(const struct i2c_client *client, const char *buf, int count) ret = i2c_transfer(adap, &msg, 1); - /* If everything went ok (i.e. 1 msg transmitted), return #bytes - transmitted, else error code. */ + /* + * If everything went ok (i.e. 1 msg transmitted), return #bytes + * transmitted, else error code. + */ return (ret == 1) ? count : ret; } EXPORT_SYMBOL(i2c_master_send); @@ -1414,8 +1417,10 @@ int i2c_master_recv(const struct i2c_client *client, char *buf, int count) ret = i2c_transfer(adap, &msg, 1); - /* If everything went ok (i.e. 1 msg transmitted), return #bytes - transmitted, else error code. */ + /* + * If everything went ok (i.e. 1 msg received), return #bytes received, + * else error code. + */ return (ret == 1) ? count : ret; } EXPORT_SYMBOL(i2c_master_recv); diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 9f9c57ff6708..18a8fd21d2c2 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -13,7 +13,8 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. */ #include <linux/rwsem.h> diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 57a45ce84b2d..45048323b75e 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -17,7 +17,8 @@ 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. + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. */ /* Note that this is a complete rewrite of Simon Vogl's i2c-dev module. @@ -251,15 +252,10 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; - rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); - if (!rdwr_pa) - return -ENOMEM; - - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { - kfree(rdwr_pa); - return -EFAULT; - } + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f61ccc1e5ea3..9836d08f7a77 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -16,7 +16,8 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA. */ #include <linux/kernel.h> diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c index 7b6ce624cd6e..e5fa695eb0fa 100644 --- a/drivers/i2c/muxes/gpio-i2cmux.c +++ b/drivers/i2c/muxes/gpio-i2cmux.c @@ -165,18 +165,7 @@ static struct platform_driver gpiomux_driver = { }, }; -static int __init gpiomux_init(void) -{ - return platform_driver_register(&gpiomux_driver); -} - -static void __exit gpiomux_exit(void) -{ - platform_driver_unregister(&gpiomux_driver); -} - -module_init(gpiomux_init); -module_exit(gpiomux_exit); +module_platform_driver(gpiomux_driver); MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver"); MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>"); diff --git a/drivers/i2c/muxes/pca9541.c b/drivers/i2c/muxes/pca9541.c index ed699c5aa79d..e0df9b6c66b3 100644 --- a/drivers/i2c/muxes/pca9541.c +++ b/drivers/i2c/muxes/pca9541.c @@ -393,18 +393,7 @@ static struct i2c_driver pca9541_driver = { .id_table = pca9541_id, }; -static int __init pca9541_init(void) -{ - return i2c_add_driver(&pca9541_driver); -} - -static void __exit pca9541_exit(void) -{ - i2c_del_driver(&pca9541_driver); -} - -module_init(pca9541_init); -module_exit(pca9541_exit); +module_i2c_driver(pca9541_driver); MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>"); MODULE_DESCRIPTION("PCA9541 I2C master selector driver"); diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 6f8953664636..0e37ef27aa12 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -284,18 +284,7 @@ static struct i2c_driver pca954x_driver = { .id_table = pca954x_id, }; -static int __init pca954x_init(void) -{ - return i2c_add_driver(&pca954x_driver); -} - -static void __exit pca954x_exit(void) -{ - i2c_del_driver(&pca954x_driver); -} - -module_init(pca954x_init); -module_exit(pca954x_exit); +module_i2c_driver(pca954x_driver); MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); MODULE_DESCRIPTION("PCA954x I2C mux/switch driver"); |