diff options
Diffstat (limited to 'drivers/i2c')
26 files changed, 470 insertions, 291 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 30f06e956bf..5f13c62e64b 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -7,7 +7,7 @@ menuconfig I2C depends on HAS_IOMEM select RT_MUTEXES ---help--- - I2C (pronounce: I-square-C) is a slow serial bus protocol used in + I2C (pronounce: I-squared-C) is a slow serial bus protocol used in many micro controller applications and developed by Philips. SMBus, or System Management Bus is a subset of the I2C protocol. More information is contained in the directory <file:Documentation/i2c/>, diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 326652f673f..646068e5100 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -79,6 +79,7 @@ config I2C_AMD8111 config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI + select CHECK_SIGNATURE if X86 && DMI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -101,6 +102,7 @@ config I2C_I801 6 Series (PCH) Patsburg (PCH) DH89xxCC (PCH) + Panther Point (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -671,15 +673,19 @@ config I2C_XILINX will be called xilinx_i2c. config I2C_EG20T - tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH" + tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)" 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 supports the ML7213, a companion chip for the - Atom E6xx series and compatible with the Intel EG20T PCH. + 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. comment "External I2C/SMBus adapter drivers" diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index dd364171f9c..b6807db7b36 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -1,23 +1,23 @@ /* - Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>, - Philip Edelbrock <phil@netroedge.com>, - Mark D. Studebaker <mdsxyz123@yahoo.com>, - Dan Eaton <dan.eaton@rocketlogix.com> and - Stephen Rousset<stephen.rousset@rocketlogix.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>, + * Philip Edelbrock <phil@netroedge.com>, + * Mark D. Studebaker <mdsxyz123@yahoo.com>, + * Dan Eaton <dan.eaton@rocketlogix.com> and + * Stephen Rousset <stephen.rousset@rocketlogix.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -254,8 +254,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) { /* do a clear-on-write */ outb_p(0xFF, SMBHSTSTS); - if ((temp = inb_p(SMBHSTSTS)) & - (ALI1535_STS_ERR | ALI1535_STS_BUSY)) { + temp = inb_p(SMBHSTSTS); + if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) { /* This is probably going to be correctable only by a * power reset as one of the bits now appears to be * stuck */ @@ -267,9 +267,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) } } else { /* check and clear done bit */ - if (temp & ALI1535_STS_DONE) { + if (temp & ALI1535_STS_DONE) outb_p(temp, SMBHSTSTS); - } } /* start the transaction by writing anything to the start register */ @@ -278,7 +277,7 @@ static int ali1535_transaction(struct i2c_adapter *adap) /* We will always wait for a fraction of a second! */ timeout = 0; do { - msleep(1); + usleep_range(1000, 2000); temp = inb_p(SMBHSTSTS); } while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE)) && (timeout++ < MAX_TIMEOUT)); @@ -325,12 +324,12 @@ static int ali1535_transaction(struct i2c_adapter *adap) /* take consequent actions for error conditions */ if (!(temp & ALI1535_STS_DONE)) { /* issue "kill" to reset host controller */ - outb_p(ALI1535_KILL,SMBHSTTYP); - outb_p(0xFF,SMBHSTSTS); + outb_p(ALI1535_KILL, SMBHSTTYP); + outb_p(0xFF, SMBHSTSTS); } else if (temp & ALI1535_STS_ERR) { /* issue "timeout" to reset all devices on bus */ - outb_p(ALI1535_T_OUT,SMBHSTTYP); - outb_p(0xFF,SMBHSTSTS); + outb_p(ALI1535_T_OUT, SMBHSTTYP); + outb_p(0xFF, SMBHSTSTS); } return result; @@ -351,7 +350,7 @@ static s32 ali1535_access(struct i2c_adapter *adap, u16 addr, for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE); timeout++) { - msleep(1); + usleep_range(1000, 2000); temp = inb_p(SMBHSTSTS); } if (timeout >= MAX_TIMEOUT) @@ -480,12 +479,12 @@ static struct i2c_adapter ali1535_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id ali1535_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { }, }; -MODULE_DEVICE_TABLE (pci, ali1535_ids); +MODULE_DEVICE_TABLE(pci, ali1535_ids); static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) { diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 52b545a795f..cbc98aea5b0 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -193,7 +193,13 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, return; } if (twi_int_status & MCOMP) { - if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if ((read_MASTER_CTL(iface) & MEN) == 0 && + (iface->cur_mode == TWI_I2C_MODE_REPEAT || + iface->cur_mode == TWI_I2C_MODE_COMBINED)) { + iface->result = -1; + write_INT_MASK(iface, 0); + write_MASTER_CTL(iface, 0); + } else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { if (iface->readNum == 0) { /* set the read number to 1 and ask for manual * stop in block combine mode diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 3a20961bef1..b1d9cd28d8d 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -662,11 +662,8 @@ static int __devinit cpm_i2c_probe(struct platform_device *ofdev) /* register new adapter to i2c module... */ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); - if (data && len == 4) { - cpm->adap.nr = *data; - result = i2c_add_numbered_adapter(&cpm->adap); - } else - result = i2c_add_adapter(&cpm->adap); + cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; + result = i2c_add_numbered_adapter(&cpm->adap); if (result < 0) { dev_err(&ofdev->dev, "Unable to register with I2C\n"); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 878a12026af..ce1a32b71e4 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex); /* Definition for ML7213 by OKI SEMICONDUCTOR */ #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_I2C 0x802D +#define PCI_DEVICE_ID_ML7223_I2C 0x8010 static struct pci_device_id __devinitdata 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, }, {0,} }; @@ -671,32 +673,33 @@ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, /* transfer not completed */ adap->pch_i2c_xfer_in_progress = true; - pmsg = &msgs[0]; - pmsg->flags |= adap->pch_buff_mode_en; - 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)) { - pch_dbg(adap, "invoking pch_i2c_readbytes\n"); - ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num), - (i == 0)); - } else { - pch_dbg(adap, "invoking pch_i2c_writebytes\n"); - ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num), - (i == 0)); + for (i = 0; i < num && ret >= 0; i++) { + pmsg = &msgs[i]; + pmsg->flags |= adap->pch_buff_mode_en; + 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), + (i == 0)); + } else { + ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num), + (i == 0)); + } } adap->pch_i2c_xfer_in_progress = false; /* transfer completed */ mutex_unlock(&pch_mutex); - return ret; + return (ret < 0) ? ret : num; } /** diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index d9aa9a649e3..a651779d9ff 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -219,7 +219,7 @@ static void __exit i2c_gpio_exit(void) } module_exit(i2c_gpio_exit); -MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:i2c-gpio"); diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 3df1bc80f37..3876a2478bd 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -227,7 +227,7 @@ static int highlander_i2c_read(struct highlander_i2c_dev *dev) /* * The R0P7780LC0011RL FPGA needs a significant delay between - * data read cycles, otherwise the transciever gets confused and + * data read cycles, otherwise the transceiver gets confused and * garbage is returned when the read is subsequently aborted. * * It is not sufficient to wait for BBSY. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 72c0415f6f9..ab26840d0c7 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -50,6 +50,7 @@ Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes 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 Features supported by this driver: Software PEC no @@ -134,10 +135,16 @@ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_INTR) +/* Older devices have their ID defined in <linux/pci_ids.h> */ +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#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 struct i801_priv { struct i2c_adapter adapter; @@ -153,6 +160,8 @@ static struct pci_driver i801_driver; #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) #define FEATURE_I2C_BLOCK_READ (1 << 3) +/* Not really a feature, but it's convenient to handle it as such */ +#define FEATURE_IDF (1 << 15) static const char *i801_feature_names[] = { "SMBus PEC", @@ -623,12 +632,13 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, { 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) }, { 0, } }; MODULE_DEVICE_TABLE(pci, i801_ids); -#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE +#if defined CONFIG_X86 && defined CONFIG_DMI static unsigned char apanel_addr; /* Scan the system ROM for the signature "FJKEYINF" */ @@ -658,11 +668,7 @@ static void __init input_apanel_init(void) } iounmap(bios); } -#else -static void __init input_apanel_init(void) {} -#endif -#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE struct dmi_onboard_device_info { const char *name; u8 type; @@ -728,7 +734,30 @@ static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm, dmi_check_onboard_device(type, name, adap); } } -#endif + +/* Register optional slaves */ +static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) +{ + /* Only register slaves on main SMBus channel */ + if (priv->features & FEATURE_IDF) + return; + + if (apanel_addr) { + struct i2c_board_info info; + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = apanel_addr; + strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); + i2c_new_device(&priv->adapter, &info); + } + + if (dmi_name_in_vendors("FUJITSU")) + dmi_walk(dmi_check_onboard_devices, &priv->adapter); +} +#else +static void __init input_apanel_init(void) {} +static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {} +#endif /* CONFIG_X86 && CONFIG_DMI */ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -748,6 +777,11 @@ static int __devinit i801_probe(struct pci_dev *dev, priv->pci_dev = dev; switch (dev->device) { + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: + priv->features |= FEATURE_IDF; + /* fall through */ default: priv->features |= FEATURE_I2C_BLOCK_READ; /* fall through */ @@ -833,21 +867,7 @@ static int __devinit i801_probe(struct pci_dev *dev, goto exit_release; } - /* Register optional slaves */ -#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE - if (apanel_addr) { - struct i2c_board_info info; - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = apanel_addr; - strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); - i2c_new_device(&priv->adapter, &info); - } -#endif -#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE - if (dmi_name_in_vendors("FUJITSU")) - dmi_walk(dmi_check_onboard_devices, &priv->adapter); -#endif + i801_probe_optional_slaves(priv); pci_set_drvdata(dev, priv); return 0; @@ -907,7 +927,8 @@ static struct pci_driver i801_driver = { static int __init i2c_i801_init(void) { - input_apanel_init(); + if (dmi_name_in_vendors("FUJITSU")) + input_apanel_init(); return pci_register_driver(&i801_driver); } diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 75b984c519a..107397a606b 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -560,15 +560,18 @@ static struct i2c_adapter mpc_ops = { .timeout = HZ, }; +static const struct of_device_id mpc_i2c_of_match[]; static int __devinit fsl_i2c_probe(struct platform_device *op) { + const struct of_device_id *match; struct mpc_i2c *i2c; const u32 *prop; u32 clock = MPC_I2C_CLOCK_LEGACY; int result = 0; int plen; - if (!op->dev.of_match) + match = of_match_device(mpc_i2c_of_match, &op->dev); + if (!match) return -EINVAL; i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); @@ -605,8 +608,8 @@ static int __devinit fsl_i2c_probe(struct platform_device *op) clock = *prop; } - if (op->dev.of_match->data) { - struct mpc_i2c_data *data = op->dev.of_match->data; + if (match->data) { + struct mpc_i2c_data *data = match->data; data->setup(op->dev.of_node, i2c, clock, data->prescaler); } else { /* Backwards compatibility */ diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index e10e5cf3751..0c731ca69f1 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -15,13 +15,14 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/delay.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> #include <plat/i2c.h> @@ -103,9 +104,6 @@ /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 -/* per-transfer delay, required for the hardware to stabilize */ -#define I2C_DELAY 150 - enum i2c_status { I2C_NOP, I2C_ON_GOING, @@ -120,9 +118,6 @@ enum i2c_operation { I2C_READ = 0x01 }; -/* controller response timeout in ms */ -#define I2C_TIMEOUT_MS 2000 - /** * struct i2c_nmk_client - client specific data * @slave_adr: 7-bit slave address @@ -151,6 +146,7 @@ struct i2c_nmk_client { * @stop: stop condition * @xfer_complete: acknowledge completion for a I2C message * @result: controller propogated result + * @busy: Busy doing transfer */ struct nmk_i2c_dev { struct platform_device *pdev; @@ -163,6 +159,8 @@ struct nmk_i2c_dev { int stop; struct completion xfer_complete; int result; + struct regulator *regulator; + bool busy; }; /* controller's abort causes */ @@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR); for (i = 0; i < LOOP_ATTEMPTS; i++) { - timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS); + timeout = jiffies + dev->adap.timeout; while (!time_after(jiffies, timeout)) { if ((readl(dev->virtbase + I2C_CR) & @@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev) { int stat; - clk_enable(dev->clk); - stat = flush_i2c_fifo(dev); if (stat) - return stat; + goto exit; /* disable the controller */ i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE); @@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev) dev->cli.operation = I2C_NO_OPERATION; - clk_disable(dev->clk); - - udelay(I2C_DELAY); - return 0; +exit: + return stat; } /* enable peripheral, master mode operation */ @@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); + &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controller has timedout, re-init the h/w */ - dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); - (void) init_hw(dev); + /* Controller timed out */ + dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n", + dev->cli.slave_adr); status = -ETIMEDOUT; } return status; } +static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) +{ + int count; + + for (count = (no_bytes - 2); + (count > 0) && + (dev->cli.count != 0); + count--) { + /* write to the Tx FIFO */ + writeb(*dev->cli.buffer, + dev->virtbase + I2C_TFR); + dev->cli.buffer++; + dev->cli.count--; + dev->cli.xfer_bytes++; + } + +} + /** * write_i2c() - Write data to I2C client. * @dev: private data of I2C Driver @@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev) init_completion(&dev->xfer_complete); /* enable interrupts by settings the masks */ - irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR | - I2C_IT_MAL | I2C_IT_BERR); + irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR); + + /* Fill the TX FIFO with transmit data */ + fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD); + + if (dev->cli.count != 0) + irq_mask |= I2C_IT_TXFNE; /* * check if we want to transfer a single or multiple bytes, if so @@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) dev->virtbase + I2C_IMSCR); timeout = wait_for_completion_interruptible_timeout( - &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); + &dev->xfer_complete, dev->adap.timeout); if (timeout < 0) { dev_err(&dev->pdev->dev, @@ -498,9 +515,9 @@ static int write_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controller has timedout, re-init the h/w */ - dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); - (void) init_hw(dev); + /* Controller timed out */ + dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n", + dev->cli.slave_adr); status = -ETIMEDOUT; } @@ -508,6 +525,51 @@ static int write_i2c(struct nmk_i2c_dev *dev) } /** + * nmk_i2c_xfer_one() - transmit a single I2C message + * @dev: device with a message encoded into it + * @flags: message flags + */ +static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) +{ + int status; + + if (flags & I2C_M_RD) { + /* read operation */ + dev->cli.operation = I2C_READ; + status = read_i2c(dev); + } else { + /* write operation */ + dev->cli.operation = I2C_WRITE; + status = write_i2c(dev); + } + + if (status || (dev->result)) { + u32 i2c_sr; + u32 cause; + + i2c_sr = readl(dev->virtbase + I2C_SR); + /* + * Check if the controller I2C operation status + * is set to ABORT(11b). + */ + if (((i2c_sr >> 2) & 0x3) == 0x3) { + /* get the abort cause */ + cause = (i2c_sr >> 4) & 0x7; + dev_err(&dev->pdev->dev, "%s\n", cause + >= ARRAY_SIZE(abort_causes) ? + "unknown reason" : + abort_causes[cause]); + } + + (void) init_hw(dev); + + status = status ? status : dev->result; + } + + return status; +} + +/** * nmk_i2c_xfer() - I2C transfer function used by kernel framework * @i2c_adap: Adapter pointer to the controller * @msgs: Pointer to data to be written. @@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, { int status; int i; - u32 cause; struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); + int j; + + dev->busy = true; + + if (dev->regulator) + regulator_enable(dev->regulator); + pm_runtime_get_sync(&dev->pdev->dev); + + clk_enable(dev->clk); status = init_hw(dev); if (status) - return status; + goto out; - clk_enable(dev->clk); + /* Attempt three times to send the message queue */ + for (j = 0; j < 3; j++) { + /* setup the i2c controller */ + setup_i2c_controller(dev); - /* setup the i2c controller */ - setup_i2c_controller(dev); + for (i = 0; i < num_msgs; i++) { + if (unlikely(msgs[i].flags & I2C_M_TEN)) { + dev_err(&dev->pdev->dev, "10 bit addressing" + "not supported\n"); - for (i = 0; i < num_msgs; i++) { - if (unlikely(msgs[i].flags & I2C_M_TEN)) { - dev_err(&dev->pdev->dev, "10 bit addressing" - "not supported\n"); - return -EINVAL; - } - dev->cli.slave_adr = msgs[i].addr; - dev->cli.buffer = msgs[i].buf; - dev->cli.count = msgs[i].len; - dev->stop = (i < (num_msgs - 1)) ? 0 : 1; - dev->result = 0; - - if (msgs[i].flags & I2C_M_RD) { - /* it is a read operation */ - dev->cli.operation = I2C_READ; - status = read_i2c(dev); - } else { - /* write operation */ - dev->cli.operation = I2C_WRITE; - status = write_i2c(dev); - } - if (status || (dev->result)) { - /* get the abort cause */ - cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7; - dev_err(&dev->pdev->dev, "error during I2C" - "message xfer: %d\n", cause); - dev_err(&dev->pdev->dev, "%s\n", - cause >= ARRAY_SIZE(abort_causes) - ? "unknown reason" : abort_causes[cause]); - clk_disable(dev->clk); - return status; + status = -EINVAL; + goto out; + } + dev->cli.slave_adr = msgs[i].addr; + dev->cli.buffer = msgs[i].buf; + dev->cli.count = msgs[i].len; + dev->stop = (i < (num_msgs - 1)) ? 0 : 1; + dev->result = 0; + + status = nmk_i2c_xfer_one(dev, msgs[i].flags); + if (status != 0) + break; } - udelay(I2C_DELAY); + if (status == 0) + break; } + +out: clk_disable(dev->clk); + pm_runtime_put_sync(&dev->pdev->dev); + if (dev->regulator) + regulator_disable(dev->regulator); + + dev->busy = false; /* return the no. messages processed */ if (status) @@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) */ disable_interrupts(dev, I2C_IT_TXFNE); } else { - for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2); - (count > 0) && - (dev->cli.count != 0); - count--) { - /* write to the Tx FIFO */ - writeb(*dev->cli.buffer, - dev->virtbase + I2C_TFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; - } + fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft)); /* * if done, close the transfer by disabling the * corresponding TXFNE interrupt @@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) } } - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD); - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS); - - disable_interrupts(dev, - (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF - | I2C_IT_TXFOVR | I2C_IT_RXFNF - | I2C_IT_RXFF | I2C_IT_RXFE)); + disable_all_interrupts(dev); + clear_all_interrupts(dev); if (dev->cli.count) { - dev->result = -1; + dev->result = -EIO; dev_err(&dev->pdev->dev, "%lu bytes still remain to be" "xfered\n", dev->cli.count); (void) init_hw(dev); @@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) /* Master Arbitration lost interrupt */ case I2C_IT_MAL: - dev->result = -1; + dev->result = -EIO; (void) init_hw(dev); i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL); @@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * during the transaction. */ case I2C_IT_BERR: - dev->result = -1; + dev->result = -EIO; /* get the status */ if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT) (void) init_hw(dev); @@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * the Tx FIFO is full. */ case I2C_IT_TXFOVR: - dev->result = -1; + dev->result = -EIO; (void) init_hw(dev); dev_err(&dev->pdev->dev, "Tx Fifo Over run\n"); @@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) return IRQ_HANDLED; } + +#ifdef CONFIG_PM +static int nmk_i2c_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev); + + if (nmk_i2c->busy) + return -EBUSY; + + return 0; +} + +static int nmk_i2c_resume(struct device *dev) +{ + return 0; +} +#else +#define nmk_i2c_suspend NULL +#define nmk_i2c_resume NULL +#endif + +/* + * We use noirq so that we suspend late and resume before the wakeup interrupt + * to ensure that we do the !pm_runtime_suspended() check in resume before + * there has been a regular pm runtime resume (via pm_runtime_get_sync()). + */ +static const struct dev_pm_ops nmk_i2c_pm = { + .suspend_noirq = nmk_i2c_suspend, + .resume_noirq = nmk_i2c_resume, +}; + static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; @@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_no_mem; } - + dev->busy = false; dev->pdev = pdev; platform_set_drvdata(pdev, dev); @@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) goto err_irq; } + dev->regulator = regulator_get(&pdev->dev, "v-i2c"); + if (IS_ERR(dev->regulator)) { + dev_warn(&pdev->dev, "could not get i2c regulator\n"); + dev->regulator = NULL; + } + + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) { dev_err(&pdev->dev, "could not get i2c clock\n"); @@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; + adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) : + msecs_to_jiffies(20000); snprintf(adap->name, sizeof(adap->name), "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); @@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, dev); - ret = init_hw(dev); - if (ret != 0) { - dev_err(&pdev->dev, "error in initializing i2c hardware\n"); - goto err_init_hw; - } - dev_info(&pdev->dev, "initialize %s on virtual " "base %p\n", adap->name, dev->virtbase); @@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) return 0; - err_init_hw: err_add_adap: clk_put(dev->clk); err_no_clk: + if (dev->regulator) + regulator_put(dev->regulator); + pm_runtime_disable(&pdev->dev); free_irq(dev->irq, dev); err_irq: iounmap(dev->virtbase); @@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) if (res) release_mem_region(res->start, resource_size(res)); clk_put(dev->clk); + if (dev->regulator) + regulator_put(dev->regulator); + pm_runtime_disable(&pdev->dev); platform_set_drvdata(pdev, NULL); kfree(dev); @@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, + .pm = &nmk_i2c_pm, }, .probe = nmk_i2c_probe, .remove = __devexit_p(nmk_i2c_remove), diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index fee1a261386..1b46a9d9f90 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -49,7 +49,6 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> @@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return -EIO; } - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (pdata) { i2c->regstep = pdata->regstep; i2c->clock_khz = pdata->clock_khz; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 58a58c7eaa1..1a766cf74f6 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -204,7 +204,7 @@ struct omap_i2c_dev { u16 errata; }; -const static u8 reg_map[] = { +static const u8 reg_map[] = { [OMAP_I2C_REV_REG] = 0x00, [OMAP_I2C_IE_REG] = 0x01, [OMAP_I2C_STAT_REG] = 0x02, @@ -225,7 +225,7 @@ const static u8 reg_map[] = { [OMAP_I2C_BUFSTAT_REG] = 0x10, }; -const static u8 omap4_reg_map[] = { +static const u8 omap4_reg_map[] = { [OMAP_I2C_REV_REG] = 0x04, [OMAP_I2C_IE_REG] = 0x2c, [OMAP_I2C_STAT_REG] = 0x28, diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index fc5fbd1012c..4b95f7a63a3 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -2,13 +2,13 @@ * i2c-parport-light.c I2C bus over parallel port * * ------------------------------------------------------------------------ * Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> - + Based on older i2c-velleman.c driver Copyright (C) 1995-2000 Simon G. Vogl With some changes from: Frodo Looijaard <frodol@dds.nl> Kyösti Mälkki <kmalkki@cc.hut.fi> - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -114,7 +114,7 @@ static struct i2c_algo_bit_data parport_algo_data = { .getscl = parport_getscl, .udelay = 50, .timeout = HZ, -}; +}; /* ----- Driver registration ---------------------------------------------- */ @@ -132,7 +132,7 @@ static struct i2c_smbus_alert_setup alert_data = { static struct i2c_client *ara; static struct lineop parport_ctrl_irq = { .val = (1 << 4), - .port = CTRL, + .port = PORT_CTRL, }; static int __devinit i2c_parport_probe(struct platform_device *pdev) @@ -245,7 +245,7 @@ static int __init i2c_parport_init(void) if (irq != 0) pr_info(DRVNAME ": using irq %d\n", irq); - if (!adapter_parm[type].getscl.val) + if (!adapter_parm[type].getscl.val) parport_algo_data.getscl = NULL; /* Sets global pdev as a side effect */ diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0eb1515541e..24565687ac9 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,14 +1,14 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> - + Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org> + Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl With some changes from: Frodo Looijaard <frodol@dds.nl> Kyösti Mälkki <kmalkki@cc.hut.fi> - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -33,6 +33,8 @@ #include <linux/i2c-algo-bit.h> #include <linux/i2c-smbus.h> #include <linux/slab.h> +#include <linux/list.h> +#include <linux/mutex.h> #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -43,10 +45,11 @@ struct i2c_par { struct i2c_algo_bit_data algo_data; struct i2c_smbus_alert_setup alert_data; struct i2c_client *ara; - struct i2c_par *next; + struct list_head node; }; -static struct i2c_par *adapter_list; +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(adapter_list_lock); /* ----- Low-level parallel port access ----------------------------------- */ @@ -75,13 +78,13 @@ static unsigned char port_read_control(struct parport *p) return parport_read_control(p); } -static void (*port_write[])(struct parport *, unsigned char) = { +static void (* const port_write[])(struct parport *, unsigned char) = { port_write_data, NULL, port_write_control, }; -static unsigned char (*port_read[])(struct parport *) = { +static unsigned char (* const port_read[])(struct parport *) = { port_read_data, port_read_status, port_read_control, @@ -144,7 +147,7 @@ static const struct i2c_algo_bit_data parport_algo_data = { .getscl = parport_getscl, .udelay = 10, /* ~50 kbps */ .timeout = HZ, -}; +}; /* ----- I2c and parallel port call-back functions and structures --------- */ @@ -161,10 +164,10 @@ void i2c_parport_irq(void *data) "SMBus alert received but no ARA client!\n"); } -static void i2c_parport_attach (struct parport *port) +static void i2c_parport_attach(struct parport *port) { struct i2c_par *adapter; - + adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL); if (adapter == NULL) { printk(KERN_ERR "i2c-parport: Failed to kzalloc\n"); @@ -177,7 +180,7 @@ static void i2c_parport_attach (struct parport *port) NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter); if (!adapter->pdev) { printk(KERN_ERR "i2c-parport: Unable to register with parport\n"); - goto ERROR0; + goto err_free; } /* Fill the rest of the structure */ @@ -197,7 +200,7 @@ static void i2c_parport_attach (struct parport *port) if (parport_claim_or_block(adapter->pdev) < 0) { printk(KERN_ERR "i2c-parport: Could not claim parallel port\n"); - goto ERROR1; + goto err_unregister; } /* Reset hardware to a sane state (SCL and SDA high) */ @@ -212,7 +215,7 @@ static void i2c_parport_attach (struct parport *port) if (i2c_bit_add_bus(&adapter->adapter) < 0) { printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); - goto ERROR1; + goto err_unregister; } /* Setup SMBus alert if supported */ @@ -228,24 +231,25 @@ static void i2c_parport_attach (struct parport *port) } /* Add the new adapter to the list */ - adapter->next = adapter_list; - adapter_list = adapter; - return; + mutex_lock(&adapter_list_lock); + list_add_tail(&adapter->node, &adapter_list); + mutex_unlock(&adapter_list_lock); + return; -ERROR1: + err_unregister: parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); -ERROR0: + err_free: kfree(adapter); } -static void i2c_parport_detach (struct parport *port) +static void i2c_parport_detach(struct parport *port) { - struct i2c_par *adapter, *prev; + struct i2c_par *adapter, *_n; /* Walk the list */ - for (prev = NULL, adapter = adapter_list; adapter; - prev = adapter, adapter = adapter->next) { + mutex_lock(&adapter_list_lock); + list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) { parport_disable_irq(port); @@ -256,17 +260,14 @@ static void i2c_parport_detach (struct parport *port) /* Un-init if needed (power off...) */ if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); - + parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); - if (prev) - prev->next = adapter->next; - else - adapter_list = adapter->next; + list_del(&adapter->node); kfree(adapter); - return; } } + mutex_unlock(&adapter_list_lock); } static struct parport_driver i2c_parport_driver = { diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index a9f66816546..3fe652302ea 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -2,7 +2,7 @@ * i2c-parport.h I2C bus over parallel port * * ------------------------------------------------------------------------ * Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org> - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -18,13 +18,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * ------------------------------------------------------------------------ */ -#ifdef DATA -#undef DATA -#endif - -#define DATA 0 -#define STAT 1 -#define CTRL 2 +#define PORT_DATA 0 +#define PORT_STAT 1 +#define PORT_CTRL 2 struct lineop { u8 val; @@ -41,61 +37,61 @@ struct adapter_parm { unsigned int smbus_alert:1; }; -static struct adapter_parm adapter_parm[] = { +static const struct adapter_parm adapter_parm[] = { /* type 0: Philips adapter */ { - .setsda = { 0x80, DATA, 1 }, - .setscl = { 0x08, CTRL, 0 }, - .getsda = { 0x80, STAT, 0 }, - .getscl = { 0x08, STAT, 0 }, + .setsda = { 0x80, PORT_DATA, 1 }, + .setscl = { 0x08, PORT_CTRL, 0 }, + .getsda = { 0x80, PORT_STAT, 0 }, + .getscl = { 0x08, PORT_STAT, 0 }, }, /* type 1: home brew teletext adapter */ { - .setsda = { 0x02, DATA, 0 }, - .setscl = { 0x01, DATA, 0 }, - .getsda = { 0x80, STAT, 1 }, + .setsda = { 0x02, PORT_DATA, 0 }, + .setscl = { 0x01, PORT_DATA, 0 }, + .getsda = { 0x80, PORT_STAT, 1 }, }, /* type 2: Velleman K8000 adapter */ { - .setsda = { 0x02, CTRL, 1 }, - .setscl = { 0x08, CTRL, 1 }, - .getsda = { 0x10, STAT, 0 }, + .setsda = { 0x02, PORT_CTRL, 1 }, + .setscl = { 0x08, PORT_CTRL, 1 }, + .getsda = { 0x10, PORT_STAT, 0 }, }, /* type 3: ELV adapter */ { - .setsda = { 0x02, DATA, 1 }, - .setscl = { 0x01, DATA, 1 }, - .getsda = { 0x40, STAT, 1 }, - .getscl = { 0x08, STAT, 1 }, + .setsda = { 0x02, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x40, PORT_STAT, 1 }, + .getscl = { 0x08, PORT_STAT, 1 }, }, /* type 4: ADM1032 evaluation board */ { - .setsda = { 0x02, DATA, 1 }, - .setscl = { 0x01, DATA, 1 }, - .getsda = { 0x10, STAT, 1 }, - .init = { 0xf0, DATA, 0 }, + .setsda = { 0x02, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x10, PORT_STAT, 1 }, + .init = { 0xf0, PORT_DATA, 0 }, .smbus_alert = 1, }, /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */ { - .setsda = { 0x02, DATA, 1 }, - .setscl = { 0x01, DATA, 1 }, - .getsda = { 0x10, STAT, 1 }, + .setsda = { 0x02, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x10, PORT_STAT, 1 }, }, /* type 6: Barco LPT->DVI (K5800236) adapter */ { - .setsda = { 0x02, DATA, 1 }, - .setscl = { 0x01, DATA, 1 }, - .getsda = { 0x20, STAT, 0 }, - .getscl = { 0x40, STAT, 0 }, - .init = { 0xfc, DATA, 0 }, + .setsda = { 0x02, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x20, PORT_STAT, 0 }, + .getscl = { 0x40, PORT_STAT, 0 }, + .init = { 0xfc, PORT_DATA, 0 }, }, /* type 7: One For All JP1 parallel port adapter */ { - .setsda = { 0x01, DATA, 0 }, - .setscl = { 0x02, DATA, 0 }, - .getsda = { 0x80, STAT, 1 }, - .init = { 0x04, DATA, 1 }, + .setsda = { 0x01, PORT_DATA, 0 }, + .setscl = { 0x02, PORT_DATA, 0 }, + .getsda = { 0x80, PORT_STAT, 1 }, + .init = { 0x04, PORT_DATA, 1 }, }, }; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a97e3fec814..04be9f82e14 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)&alg_data; + timer->data = (unsigned long)alg_data; add_timer(timer); } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index f59224a5c76..d6036465099 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1079,7 +1079,7 @@ static int i2c_pxa_probe(struct platform_device *dev) * The reason to do so is to avoid sysfs names that only make * sense when there are multiple adapters. */ - i2c->adap.nr = dev->id != -1 ? dev->id : 0; + i2c->adap.nr = dev->id; snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u", i2c->adap.nr); @@ -1142,10 +1142,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - if (i2c_type == REGS_CE4100) - ret = i2c_add_adapter(&i2c->adap); - else - ret = i2c_add_numbered_adapter(&i2c->adap); + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); goto eadapt; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6c00c107ebf..f84a63c6dd9 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -248,12 +248,12 @@ static inline int is_msgend(struct s3c24xx_i2c *i2c) return i2c->msg_ptr >= i2c->msg->len; } -/* i2s_s3c_irq_nextbyte +/* i2c_s3c_irq_nextbyte * * process an interrupt and work out what to do */ -static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) +static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) { unsigned long tmp; unsigned char byte; @@ -264,7 +264,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) case STATE_IDLE: dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__); goto out; - break; case STATE_STOP: dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__); @@ -444,7 +443,7 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id) /* pretty much this leaves us with the fact that we've * transmitted or received whatever byte we last sent */ - i2s_s3c_irq_nextbyte(i2c, status); + i2c_s3c_irq_nextbyte(i2c, status); out: return IRQ_HANDLED; diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c index cb5d01e279c..c64ba736f48 100644 --- a/drivers/i2c/busses/i2c-s6000.c +++ b/drivers/i2c/busses/i2c-s6000.c @@ -341,10 +341,7 @@ static int __devinit s6i2c_probe(struct platform_device *dev) i2c_wr16(iface, S6_I2C_TXTL, 0); platform_set_drvdata(dev, iface); - if (bus_num < 0) - rc = i2c_add_adapter(p_adap); - else - rc = i2c_add_numbered_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc) goto err_irq_free; return 0; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2707f5e1715..f633a53b6db 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -32,6 +32,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/i2c/i2c-sh_mobile.h> /* Transmit operation: */ /* */ @@ -117,7 +118,7 @@ struct sh_mobile_i2c_data { struct device *dev; void __iomem *reg; struct i2c_adapter adap; - + unsigned long bus_speed; struct clk *clk; u_int8_t icic; u_int8_t iccl; @@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) * We also round off the result. */ num = i2c_clk * 5; - denom = NORMAL_SPEED * 9; + denom = pd->bus_speed * 9; tmp = num * 10 / denom; if (tmp % 10 >= 5) pd->iccl = (u_int8_t)((num/denom) + 1); @@ -574,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) static int sh_mobile_i2c_probe(struct platform_device *dev) { + struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data; struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - char clk_name[8]; int size; int ret; @@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return -ENOMEM; } - snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); - pd->clk = clk_get(&dev->dev, clk_name); + pd->clk = clk_get(&dev->dev, NULL); if (IS_ERR(pd->clk)) { - dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name); + dev_err(&dev->dev, "cannot get clock\n"); ret = PTR_ERR(pd->clk); goto err; } @@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } + /* Use platformd data bus speed or NORMAL_SPEED */ + pd->bus_speed = NORMAL_SPEED; + if (pdata && pdata->bus_speed) + pd->bus_speed = pdata->bus_speed; + /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. */ @@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_all; } + dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n", + adap->nr, pd->bus_speed); return 0; err_all: @@ -729,3 +736,4 @@ module_exit(sh_mobile_i2c_adap_exit); MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); MODULE_AUTHOR("Magnus Damm"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:i2c-sh_mobile"); diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index dd39c1eb03e..26c352a0929 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -234,7 +234,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) if (taos->state != TAOS_STATE_IDLE) { err = -ENODEV; - dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, " + dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, " "pos=%d)\n", taos->state, taos->pos); goto exit_close; } @@ -255,7 +255,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) msecs_to_jiffies(250)); if (taos->state != TAOS_STATE_IDLE) { err = -ENODEV; - dev_err(&adapter->dev, "Echo off failed " + dev_err(&serio->dev, "TAOS EVM echo off failed " "(state=%d)\n", taos->state); goto exit_close; } @@ -263,7 +263,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) err = i2c_add_adapter(adapter); if (err) goto exit_close; - dev_dbg(&serio->dev, "Connected to TAOS EVM\n"); + dev_info(&serio->dev, "Connected to TAOS EVM\n"); taos->client = taos_instantiate_device(adapter); return 0; @@ -288,7 +288,7 @@ static void taos_disconnect(struct serio *serio) serio_set_drvdata(serio, NULL); kfree(taos); - dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n"); + dev_info(&serio->dev, "Disconnected from TAOS EVM\n"); } static struct serio_device_id taos_serio_ids[] = { diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b4ab39b741e..2440b741197 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/i2c-tegra.h> +#include <linux/of_i2c.h> #include <asm/unaligned.h> @@ -35,11 +36,15 @@ #define BYTES_PER_FIFO_WORD 4 #define I2C_CNFG 0x000 +#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 #define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_NEW_MASTER_FSM (1<<11) +#define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 +#define I2C_SL_CNFG_NACK (1<<1) #define I2C_SL_CNFG_NEWSL (1<<2) #define I2C_SL_ADDR1 0x02c +#define I2C_SL_ADDR2 0x030 #define I2C_TX_FIFO 0x050 #define I2C_RX_FIFO 0x054 #define I2C_PACKET_TRANSFER_STATUS 0x058 @@ -77,6 +82,7 @@ #define I2C_ERR_NONE 0x00 #define I2C_ERR_NO_ACK 0x01 #define I2C_ERR_ARBITRATION_LOST 0x02 +#define I2C_ERR_UNKNOWN_INTERRUPT 0x04 #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 #define PACKET_HEADER0_PACKET_ID_SHIFT 16 @@ -121,6 +127,7 @@ struct tegra_i2c_dev { void __iomem *base; int cont_id; int irq; + bool irq_disabled; int is_dvc; struct completion msg_complete; int msg_err; @@ -325,11 +332,21 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (i2c_dev->is_dvc) tegra_dvc_init(i2c_dev); - val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN; + val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | + (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); + if (!i2c_dev->is_dvc) { + u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); + sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; + i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); + i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); + i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); + + } + val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); @@ -338,6 +355,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) err = -ETIMEDOUT; clk_disable(i2c_dev->clk); + + if (i2c_dev->irq_disabled) { + i2c_dev->irq_disabled = 0; + enable_irq(i2c_dev->irq); + } + return err; } @@ -350,8 +373,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) status = i2c_readl(i2c_dev, I2C_INT_STATUS); if (status == 0) { - dev_warn(i2c_dev->dev, "interrupt with no status\n"); - return IRQ_NONE; + dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", + i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), + i2c_readl(i2c_dev, I2C_STATUS), + i2c_readl(i2c_dev, I2C_CNFG)); + i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT; + + if (!i2c_dev->irq_disabled) { + disable_irq_nosync(i2c_dev->irq); + i2c_dev->irq_disabled = 1; + } + + complete(&i2c_dev->msg_complete); + goto err; } if (unlikely(status & status_err)) { @@ -391,6 +425,8 @@ err: I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | I2C_INT_RX_FIFO_DATA_REQ); i2c_writel(i2c_dev, status, I2C_INT_STATUS); + if (i2c_dev->is_dvc) + dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); return IRQ_HANDLED; } @@ -424,12 +460,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT; packet_header |= I2C_HEADER_IE_ENABLE; + if (!stop) + packet_header |= I2C_HEADER_REPEAT_START; if (msg->flags & I2C_M_TEN) packet_header |= I2C_HEADER_10BIT_ADDR; if (msg->flags & I2C_M_IGNORE_NAK) packet_header |= I2C_HEADER_CONT_ON_NAK; - if (msg->flags & I2C_M_NOSTART) - packet_header |= I2C_HEADER_REPEAT_START; if (msg->flags & I2C_M_RD) packet_header |= I2C_HEADER_READ; i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); @@ -511,6 +547,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) struct resource *iomem; struct clk *clk; struct clk *i2c_clk; + const unsigned int *prop; void *base; int irq; int ret = 0; @@ -568,7 +605,17 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->irq = irq; i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; - i2c_dev->bus_clk_rate = pdata ? pdata->bus_clk_rate : 100000; + + i2c_dev->bus_clk_rate = 100000; /* default clock rate */ + if (pdata) { + i2c_dev->bus_clk_rate = pdata->bus_clk_rate; + + } else if (i2c_dev->dev->of_node) { /* if there is a device tree node ... */ + prop = of_get_property(i2c_dev->dev->of_node, + "clock-frequency", NULL); + if (prop) + i2c_dev->bus_clk_rate = be32_to_cpup(prop); + } if (pdev->id == 3) i2c_dev->is_dvc = 1; @@ -598,6 +645,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; + i2c_dev->adapter.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c_dev->adapter); if (ret) { @@ -605,6 +653,8 @@ static int tegra_i2c_probe(struct platform_device *pdev) goto err_free_irq; } + of_i2c_register_devices(&i2c_dev->adapter); + return 0; err_free_irq: free_irq(i2c_dev->irq, i2c_dev); diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index e9d5ff4d149..4bb68f35caf 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -34,7 +34,6 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/wait.h> @@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev) if (irq < 0) goto resource_missing; - pdata = mfd_get_data(pdev); + pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data; if (!pdata) return -EINVAL; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9a58994ff7e..131079a3e29 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -925,6 +925,9 @@ EXPORT_SYMBOL(i2c_add_adapter); * or otherwise built in to the system's mainboard, and where i2c_board_info * is used to properly configure I2C devices. * + * If the requested bus number is set to -1, then this function will behave + * identically to i2c_add_adapter, and will dynamically assign a bus number. + * * If no devices have pre-been declared for this bus, then be sure to * register the adapter before any dynamically allocated ones. Otherwise * the required bus ID may not be available. @@ -940,6 +943,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adap) int id; int status; + if (adap->nr == -1) /* -1 means dynamically assign bus id */ + return i2c_add_adapter(adap); if (adap->nr & ~MAX_ID_MASK) return -EINVAL; diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 54e1ce73534..6f895366463 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -201,10 +201,11 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - /* Read the mux register at addr to verify - * that the mux is in fact present. + /* Write the mux register at addr to verify + * that the mux is in fact present. This also + * initializes the mux to disconnected state. */ - if (i2c_smbus_read_byte(client) < 0) { + if (i2c_smbus_write_byte(client, 0) < 0) { dev_warn(&client->dev, "probe failed\n"); goto exit_free; } |