Merge branches 'for-2639/i2c-eg20t', 'for-2639/i2c-shmobile', 'for-2639/i2c-tegra...
authorBen Dooks <ben-linux@fluff.org>
Tue, 24 May 2011 23:25:55 +0000 (00:25 +0100)
committerBen Dooks <ben-linux@fluff.org>
Tue, 24 May 2011 23:25:55 +0000 (00:25 +0100)
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-tegra.c
include/linux/i2c/i2c-sh_mobile.h [new file with mode: 0644]

index 326652f..697ffa8 100644 (file)
@@ -671,15 +671,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"
 
index 878a120..8abfa4a 100644 (file)
@@ -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,}
 };
 
index 81ccd78..f633a53 100644 (file)
@@ -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:
index b4ab39b..4d93196 100644 (file)
 #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);
diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h
new file mode 100644 (file)
index 0000000..beda708
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __I2C_SH_MOBILE_H__
+#define __I2C_SH_MOBILE_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_sh_mobile_platform_data {
+       unsigned long bus_speed;
+};
+
+#endif /* __I2C_SH_MOBILE_H__ */