diff options
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r-- | drivers/i2c/busses/Kconfig | 12 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-eg20t.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 60 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 276 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-parport-light.c | 10 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-parport.c | 30 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-parport.h | 74 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 20 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 39 |
9 files changed, 336 insertions, 187 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 326652f673f7..646068e5100b 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-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 878a12026af2..8abfa4a03ce1 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,} }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 455e909bc768..ab26840d0c70 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 @@ -141,6 +142,7 @@ #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 @@ -158,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", @@ -628,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" */ @@ -663,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; @@ -733,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) @@ -753,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 */ @@ -838,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; @@ -912,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-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index e10e5cf3751a..0c731ca69f15 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-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index fc5fbd1012c9..4b95f7a63a3b 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 2dbba163b102..24565687ac9b 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -2,13 +2,13 @@ * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * 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 @@ -78,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, @@ -147,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 --------- */ @@ -164,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"); @@ -180,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 */ @@ -200,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) */ @@ -215,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 */ @@ -234,16 +234,16 @@ static void i2c_parport_attach (struct parport *port) mutex_lock(&adapter_list_lock); list_add_tail(&adapter->node, &adapter_list); mutex_unlock(&adapter_list_lock); - return; + 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, *_n; @@ -260,7 +260,7 @@ 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); list_del(&adapter->node); diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index a9f66816546c..3fe652302ea7 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-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2707f5e17158..f633a53b6dbe 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-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b4ab39b741eb..4d9319665e32 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -35,8 +35,10 @@ #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_NEWSL (1<<2) #define I2C_SL_ADDR1 0x02c @@ -77,6 +79,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 +124,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 +329,17 @@ 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); + i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG); + } + 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 +348,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 +366,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 +418,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 +453,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); |