diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-bfin-twi.c | 59 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ibm_iic.c | 6 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 5 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 39 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 22 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 48 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh7760.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-viapro.c | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-voodoo3.c | 1 | ||||
-rw-r--r-- | drivers/i2c/chips/Kconfig | 15 | ||||
-rw-r--r-- | drivers/i2c/chips/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/chips/max6875.c | 246 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 43 |
14 files changed, 156 insertions, 343 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index f1c6ca7e285..0d04d3ebfc2 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -211,7 +211,7 @@ config I2C_VIA will be called i2c-via. config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" + tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" depends on PCI help If you say yes to this option, support will be included for the VIA @@ -225,8 +225,8 @@ config I2C_VIAPRO VT8237R/A/S VT8251 CX700 - VX800 - VX820 + VX800/VX820 + VX855/VX875 This driver can also be built as a module. If so, the module will be called i2c-viapro. @@ -298,7 +298,7 @@ config I2C_BLACKFIN_TWI config I2C_BLACKFIN_TWI_CLK_KHZ int "Blackfin TWI I2C clock (kHz)" depends on I2C_BLACKFIN_TWI - range 10 400 + range 21 400 default 50 help The unit of the TWI clock is kHz. diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index fc548b3d002..26d8987e69b 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -104,9 +104,14 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) write_MASTER_CTL(iface, read_MASTER_CTL(iface) | STOP); else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); + } SSYNC(); /* Clear status */ write_INT_STAT(iface, XMTSERV); @@ -134,9 +139,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) read_MASTER_CTL(iface) | STOP); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg+1 < iface->msg_num) { - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | RSTART); + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | RSTART | MDIR); + else + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | RSTART) & ~MDIR); SSYNC(); } /* Clear interrupt source */ @@ -196,8 +205,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MEN | MDIR); SSYNC(); } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && iface->cur_msg+1 < iface->msg_num) { @@ -222,18 +229,19 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) } if (iface->pmsg[iface->cur_msg].len <= 255) - write_MASTER_CTL(iface, - iface->pmsg[iface->cur_msg].len << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) & + (~(0xff << 6))) | + (iface->pmsg[iface->cur_msg].len << 6)); else { - write_MASTER_CTL(iface, 0xff << 6); + write_MASTER_CTL(iface, + (read_MASTER_CTL(iface) | + (0xff << 6))); iface->manual_stop = 1; } /* remove restart bit and enable master receive */ write_MASTER_CTL(iface, read_MASTER_CTL(iface) & ~RSTART); - write_MASTER_CTL(iface, read_MASTER_CTL(iface) | - MEN | ((iface->read_write == I2C_SMBUS_READ) ? - MDIR : 0)); SSYNC(); } else { iface->result = 1; @@ -441,6 +449,16 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, } iface->transPtr = data->block; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0]; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->block[1]; + break; default: return -1; } @@ -564,7 +582,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | - I2C_FUNC_I2C; + I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; } static struct i2c_algorithm bfin_twi_algorithm = { @@ -614,6 +632,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) struct i2c_adapter *p_adap; struct resource *res; int rc; + unsigned int clkhilow; iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); if (!iface) { @@ -675,10 +694,14 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) /* Set TWI internal clock as 10MHz */ write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + /* + * We will not end up with a CLKDIV=0 because no one will specify + * 20kHz SCL or less in Kconfig now. (5 * 1024 / 20 = 0x100) + */ + clkhilow = 5 * 1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ; + /* Set Twi interface clock as specified */ - write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) - & 0xFF)); + write_CLKDIV(iface, (clkhilow << 8) | clkhilow); /* Enable TWI */ write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 8b92a4666e0..e4476743f20 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -756,12 +756,12 @@ static int __devinit iic_probe(struct of_device *ofdev, goto error_cleanup; } - /* Now register all the child nodes */ - of_register_i2c_devices(adap, np); - dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); + /* Now register all the child nodes */ + of_register_i2c_devices(adap, np); + return 0; error_cleanup: diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index e5193bf7548..3542c6ba98f 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -216,6 +216,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) struct ocores_i2c_platform_data *pdata; struct resource *res, *res2; int ret; + int i; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -271,6 +272,10 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) goto add_adapter_failed; } + /* add in known devices to the bus */ + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + return 0; add_adapter_failed: diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ece0125a1ee..c73475dd0fb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -333,8 +333,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) if (cpu_is_omap2430() || cpu_is_omap34xx()) { - /* HSI2C controller internal clk rate should be 19.2 Mhz */ - internal_clk = 19200; + /* + * HSI2C controller internal clk rate should be 19.2 Mhz for + * HS and for all modes on 2430. On 34xx we can use lower rate + * to get longer filter period for better noise suppression. + * The filter is iclk (fclk for HS) period. + */ + if (dev->speed > 400 || cpu_is_omap_2430()) + internal_clk = 19200; + else if (dev->speed > 100) + internal_clk = 9600; + else + internal_clk = 4000; fclk_rate = clk_get_rate(dev->fclk) / 1000; /* Compute prescaler divisor */ @@ -343,17 +353,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* If configured for High Speed */ if (dev->speed > 400) { + unsigned long scl; + /* For first phase of HS mode */ - fsscll = internal_clk / (400 * 2) - 6; - fssclh = internal_clk / (400 * 2) - 6; + scl = internal_clk / 400; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - hsscll = fclk_rate / (dev->speed * 2) - 6; - hssclh = fclk_rate / (dev->speed * 2) - 6; + scl = fclk_rate / dev->speed; + hsscll = scl - (scl / 3) - 7; + hssclh = (scl / 3) - 5; + } else if (dev->speed > 100) { + unsigned long scl; + + /* Fast mode */ + scl = internal_clk / dev->speed; + fsscll = scl - (scl / 3) - 7; + fssclh = (scl / 3) - 5; } else { - /* To handle F/S modes */ - fsscll = internal_clk / (dev->speed * 2) - 6; - fssclh = internal_clk / (dev->speed * 2) - 6; + /* Standard mode */ + fsscll = internal_clk / (dev->speed * 2) - 7; + fssclh = internal_clk / (dev->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index acc7143d965..035a6c7e59d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,10 +34,24 @@ #include <linux/err.h> #include <linux/clk.h> -#include <mach/hardware.h> #include <asm/irq.h> #include <asm/io.h> -#include <mach/i2c.h> +#include <plat/i2c.h> + +/* + * I2C register offsets will be shifted 0 or 1 bit left, depending on + * different SoCs + */ +#define REG_SHIFT_0 (0 << 0) +#define REG_SHIFT_1 (1 << 0) +#define REG_SHIFT(d) ((d) & 0x1) + +static const struct platform_device_id i2c_pxa_id_table[] = { + { "pxa2xx-i2c", REG_SHIFT_1 }, + { "pxa3xx-pwri2c", REG_SHIFT_0 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); /* * I2C registers and bit definitions @@ -985,6 +999,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct pxa_i2c *i2c; struct resource *res; struct i2c_pxa_platform_data *plat = dev->dev.platform_data; + struct platform_device_id *id = platform_get_device_id(dev); int ret; int irq; @@ -1028,7 +1043,7 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = -EIO; goto eremap; } - i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1; + i2c->reg_shift = REG_SHIFT(id->driver_data); i2c->iobase = res->start; i2c->iosize = res_len(res); @@ -1150,6 +1165,7 @@ static struct platform_driver i2c_pxa_driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, }, + .id_table = i2c_pxa_id_table, }; static int __init i2c_adap_pxa_init(void) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 1691ef0f1ee..079a312d36f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -51,6 +51,11 @@ enum s3c24xx_i2c_state { STATE_STOP }; +enum s3c24xx_i2c_type { + TYPE_S3C2410, + TYPE_S3C2440, +}; + struct s3c24xx_i2c { spinlock_t lock; wait_queue_head_t wait; @@ -88,8 +93,10 @@ struct s3c24xx_i2c { static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) { struct platform_device *pdev = to_platform_device(i2c->dev); + enum s3c24xx_i2c_type type; - return !strcmp(pdev->name, "s3c2440-i2c"); + type = platform_get_device_id(pdev)->driver_data; + return type == TYPE_S3C2440; } /* s3c24xx_i2c_master_complete @@ -969,52 +976,41 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) /* device driver for platform bus bits */ -static struct platform_driver s3c2410_i2c_driver = { - .probe = s3c24xx_i2c_probe, - .remove = s3c24xx_i2c_remove, - .suspend_late = s3c24xx_i2c_suspend_late, - .resume = s3c24xx_i2c_resume, - .driver = { - .owner = THIS_MODULE, - .name = "s3c2410-i2c", - }, +static struct platform_device_id s3c24xx_driver_ids[] = { + { + .name = "s3c2410-i2c", + .driver_data = TYPE_S3C2410, + }, { + .name = "s3c2440-i2c", + .driver_data = TYPE_S3C2440, + }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static struct platform_driver s3c2440_i2c_driver = { +static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, .suspend_late = s3c24xx_i2c_suspend_late, .resume = s3c24xx_i2c_resume, + .id_table = s3c24xx_driver_ids, .driver = { .owner = THIS_MODULE, - .name = "s3c2440-i2c", + .name = "s3c-i2c", }, }; static int __init i2c_adap_s3c_init(void) { - int ret; - - ret = platform_driver_register(&s3c2410_i2c_driver); - if (ret == 0) { - ret = platform_driver_register(&s3c2440_i2c_driver); - if (ret) - platform_driver_unregister(&s3c2410_i2c_driver); - } - - return ret; + return platform_driver_register(&s3c24xx_i2c_driver); } subsys_initcall(i2c_adap_s3c_init); static void __exit i2c_adap_s3c_exit(void) { - platform_driver_unregister(&s3c2410_i2c_driver); - platform_driver_unregister(&s3c2440_i2c_driver); + platform_driver_unregister(&s3c24xx_i2c_driver); } module_exit(i2c_adap_s3c_exit); MODULE_DESCRIPTION("S3C24XX I2C Bus driver"); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-i2c"); -MODULE_ALIAS("platform:s3c2440-i2c"); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index baa28b73ae4..b9680f50f54 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -396,7 +396,7 @@ static int __devinit calc_CCR(unsigned long scl_hz) signed char cdf, cdfm; int scgd, scgdm, scgds; - mclk = clk_get(NULL, "module_clk"); + mclk = clk_get(NULL, "peripheral_clk"); if (IS_ERR(mclk)) { return PTR_ERR(mclk); } else { diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f724b05..54d810a4d00 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -37,6 +37,7 @@ VT8251 0x3287 yes CX700 0x8324 yes VX800/VX820 0x8353 yes + VX855/VX875 0x8409 yes Note: we assume there can only be one device, with one SMBus interface. */ @@ -404,6 +405,7 @@ found: switch (pdev->device) { case PCI_DEVICE_ID_VIA_CX700: case PCI_DEVICE_ID_VIA_VX800: + case PCI_DEVICE_ID_VIA_VX855: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: @@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), + .driver_data = SMBBA3 }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474acc0dd..7663d57833a 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c @@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { static struct i2c_adapter voodoo3_i2c_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, .name = "I2C Voodoo3/Banshee adapter", .algo_data = &voo_i2c_bit_data, }; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81eb0ae..02d746c9c47 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -64,21 +64,6 @@ config SENSORS_PCA9539 This driver is deprecated and will be dropped soon. Use drivers/gpio/pca953x.c instead. -config SENSORS_MAX6875 - tristate "Maxim MAX6875 Power supply supervisor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Maxim MAX6875 - EEPROM-programmable, quad power-supply sequencer/supervisor. - - This provides an interface to program the EEPROM and reset the chip. - - This driver also supports the Maxim MAX6874 hex power-supply - sequencer/supervisor if found at a compatible address. - - This driver can also be built as a module. If so, the module - will be called max6875. - config SENSORS_TSL2550 tristate "Taos TSL2550 ambient light sensor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a37603718..f4680d16ee3 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -11,7 +11,6 @@ # obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_SENSORS_MAX6875) += max6875.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o obj-$(CONFIG_PCF8575) += pcf8575.o diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c deleted file mode 100644 index 033d9d81ec8..00000000000 --- a/drivers/i2c/chips/max6875.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - max6875.c - driver for MAX6874/MAX6875 - - Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> - - Based on i2c/chips/eeprom.c - - The MAX6875 has a bank of registers and two banks of EEPROM. - Address ranges are defined as follows: - * 0x0000 - 0x0046 = configuration registers - * 0x8000 - 0x8046 = configuration EEPROM - * 0x8100 - 0x82FF = user EEPROM - - This driver makes the user EEPROM available for read. - - The registers & config EEPROM should be accessed via i2c-dev. - - The MAX6875 ignores the lowest address bit, so each chip responds to - two addresses - 0x50/0x51 and 0x52/0x53. - - Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read - address, so this driver is destructive if loaded for the wrong EEPROM chip. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. -*/ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -/* Do not scan - the MAX6875 access method will write to some EEPROM chips */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -/* Insmod parameters */ -I2C_CLIENT_INSMOD_1(max6875); - -/* The MAX6875 can only read/write 16 bytes at a time */ -#define SLICE_SIZE 16 -#define SLICE_BITS 4 - -/* USER EEPROM is at addresses 0x8100 - 0x82FF */ -#define USER_EEPROM_BASE 0x8100 -#define USER_EEPROM_SIZE 0x0200 -#define USER_EEPROM_SLICES 32 - -/* MAX6875 commands */ -#define MAX6875_CMD_BLK_READ 0x84 - -/* Each client has this additional data */ -struct max6875_data { - struct i2c_client *fake_client; - struct mutex update_lock; - - u32 valid; - u8 data[USER_EEPROM_SIZE]; - unsigned long last_updated[USER_EEPROM_SLICES]; -}; - -static void max6875_update_slice(struct i2c_client *client, int slice) -{ - struct max6875_data *data = i2c_get_clientdata(client); - int i, j, addr; - u8 *buf; - - if (slice >= USER_EEPROM_SLICES) - return; - - mutex_lock(&data->update_lock); - - buf = &data->data[slice << SLICE_BITS]; - - if (!(data->valid & (1 << slice)) || - time_after(jiffies, data->last_updated[slice])) { - - dev_dbg(&client->dev, "Starting update of slice %u\n", slice); - - data->valid &= ~(1 << slice); - - addr = USER_EEPROM_BASE + (slice << SLICE_BITS); - - /* select the eeprom address */ - if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { - dev_err(&client->dev, "address set failed\n"); - goto exit_up; - } - - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - if (i2c_smbus_read_i2c_block_data(client, - MAX6875_CMD_BLK_READ, - SLICE_SIZE, - buf) != SLICE_SIZE) { - goto exit_up; - } - } else { - for (i = 0; i < SLICE_SIZE; i++) { - j = i2c_smbus_read_byte(client); - if (j < 0) { - goto exit_up; - } - buf[i] = j; - } - } - data->last_updated[slice] = jiffies; - data->valid |= (1 << slice); - } -exit_up: - mutex_unlock(&data->update_lock); -} - -static ssize_t max6875_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = kobj_to_i2c_client(kobj); - struct max6875_data *data = i2c_get_clientdata(client); - int slice, max_slice; - - if (off > USER_EEPROM_SIZE) - return 0; - - if (off + count > USER_EEPROM_SIZE) - count = USER_EEPROM_SIZE - off; - - /* refresh slices which contain requested bytes */ - max_slice = (off + count - 1) >> SLICE_BITS; - for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) - max6875_update_slice(client, slice); - - memcpy(buf, &data->data[off], count); - - return count; -} - -static struct bin_attribute user_eeprom_attr = { - .attr = { - .name = "eeprom", - .mode = S_IRUGO, - }, - .size = USER_EEPROM_SIZE, - .read = max6875_read, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int max6875_detect(struct i2c_client *client, int kind, - struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA - | I2C_FUNC_SMBUS_READ_BYTE)) - return -ENODEV; - - /* Only check even addresses */ - if (client->addr & 1) - return -ENODEV; - - strlcpy(info->type, "max6875", I2C_NAME_SIZE); - - return 0; -} - -static int max6875_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct max6875_data *data; - int err; - - if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) - return -ENOMEM; - - /* A fake client is created on the odd address */ - data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); - if (!data->fake_client) { - err = -ENOMEM; - goto exit_kfree; - } - - /* Init real i2c_client */ - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - - err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); - if (err) - goto exit_remove_fake; - - return 0; - -exit_remove_fake: - i2c_unregister_device(data->fake_client); -exit_kfree: - kfree(data); - return err; -} - -static int max6875_remove(struct i2c_client *client) -{ - struct max6875_data *data = i2c_get_clientdata(client); - - i2c_unregister_device(data->fake_client); - - sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); - kfree(data); - - return 0; -} - -static const struct i2c_device_id max6875_id[] = { - { "max6875", 0 }, - { } -}; - -static struct i2c_driver max6875_driver = { - .driver = { - .name = "max6875", - }, - .probe = max6875_probe, - .remove = max6875_remove, - .id_table = max6875_id, - - .detect = max6875_detect, - .address_data = &addr_data, -}; - -static int __init max6875_init(void) -{ - return i2c_add_driver(&max6875_driver); -} - -static void __exit max6875_exit(void) -{ - i2c_del_driver(&max6875_driver); -} - - -MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); -MODULE_DESCRIPTION("MAX6875 driver"); -MODULE_LICENSE("GPL"); - -module_init(max6875_init); -module_exit(max6875_exit); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919d1c..5ed622ee65c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,7 +29,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/idr.h> -#include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/completion.h> #include <linux/hardirq.h> @@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) mutex_lock(&core_lock); - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; @@ -1022,7 +1011,8 @@ module_exit(i2c_exit); */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1060,7 +1050,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) mutex_lock_nested(&adap->bus_lock, adap->level); } - ret = adap->algo->master_xfer(adap,msgs,num); + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } mutex_unlock(&adap->bus_lock); return ret; @@ -1509,7 +1507,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; @@ -1995,14 +1993,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, |