Commit 4a7df24d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus/2640/i2c' of git://git.fluff.org/bjdooks/linux

* 'for-linus/2640/i2c' of git://git.fluff.org/bjdooks/linux: (21 commits)
  mach-ux500: set proper I2C platform data from MOP500s
  i2c-nomadik: break out single messsage transmission
  i2c-nomadik: reset the hw after status check
  i2c-nomadik: remove the unnecessary delay
  i2c-nomadik: change the TX and RX threshold
  i2c-nomadik: add code to retry on timeout failure
  i2c-nomadik: use pm_runtime API
  i2c-nomadik: print abort cause only on abort tag
  i2c-nomadik: correct adapter timeout initialization
  i2c-nomadik: remove the redundant error message
  i2c-nomadik: corrrect returned error numbers
  i2c-nomadik: fix speed enumerator
  i2c-nomadik: make i2c timeout specific per i2c bus
  i2c-nomadik: add regulator support
  i2c: i2c-sh_mobile bus speed platform data V2
  i2c: i2c-sh_mobile clock string removal
  i2c-eg20t: Support new device ML7223 IOH
  i2c: tegra: Add de-bounce cycles.
  i2c: tegra: fix repeated start handling
  i2c: tegra: recover from spurious interrupt storm
  ...
parents 37d8cb54 5bdfdfee
...@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = { ...@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
}, },
}; };
#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ #define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm) \
static struct nmk_i2c_controller u8500_i2c##id##_data = { \ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
/* \ /* \
* slave data setup time, which is \ * slave data setup time, which is \
...@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \ ...@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
.rft = _rft, \ .rft = _rft, \
/* std. mode operation */ \ /* std. mode operation */ \
.clk_freq = clk, \ .clk_freq = clk, \
/* Slave response timeout(ms) */\
.timeout = t_out, \
.sm = _sm, \ .sm = _sm, \
} }
/* /*
* The board uses 4 i2c controllers, initialize all of * The board uses 4 i2c controllers, initialize all of
* them with slave data setup time of 250 ns, * them with slave data setup time of 250 ns,
* Tx & Rx FIFO threshold values as 1 and standard * Tx & Rx FIFO threshold values as 8 and standard
* mode of operation * mode of operation
*/ */
U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(2, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(3, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
static void __init mop500_i2c_init(void) static void __init mop500_i2c_init(void)
{ {
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
enum i2c_freq_mode { enum i2c_freq_mode {
I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */ I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */
I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */ I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */
I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */
I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */
I2C_FREQ_MODE_HIGH_SPEED /* up to 3.4 Mb/s */
}; };
/** /**
...@@ -24,6 +24,7 @@ enum i2c_freq_mode { ...@@ -24,6 +24,7 @@ enum i2c_freq_mode {
* to the values of 14, 6, 2 for a 48 MHz i2c clk * to the values of 14, 6, 2 for a 48 MHz i2c clk
* @tft: Tx FIFO Threshold in bytes * @tft: Tx FIFO Threshold in bytes
* @rft: Rx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes
* @timeout Slave response timeout(ms)
* @sm: speed mode * @sm: speed mode
*/ */
struct nmk_i2c_controller { struct nmk_i2c_controller {
...@@ -31,6 +32,7 @@ struct nmk_i2c_controller { ...@@ -31,6 +32,7 @@ struct nmk_i2c_controller {
unsigned short slsu; unsigned short slsu;
unsigned char tft; unsigned char tft;
unsigned char rft; unsigned char rft;
int timeout;
enum i2c_freq_mode sm; enum i2c_freq_mode sm;
}; };
......
...@@ -673,15 +673,19 @@ config I2C_XILINX ...@@ -673,15 +673,19 @@ config I2C_XILINX
will be called xilinx_i2c. will be called xilinx_i2c.
config I2C_EG20T config I2C_EG20T
tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH" tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
depends on PCI depends on PCI
help help
This driver is for PCH(Platform controller Hub) I2C of EG20T which This driver is for PCH(Platform controller Hub) I2C of EG20T which
is an IOH(Input/Output Hub) for x86 embedded processor. is an IOH(Input/Output Hub) for x86 embedded processor.
This driver can access PCH I2C bus device. This driver can access PCH I2C bus device.
This driver also supports the ML7213, a companion chip for the This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
Atom E6xx series and compatible with the Intel EG20T PCH. 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" comment "External I2C/SMBus adapter drivers"
......
...@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex); ...@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
/* Definition for ML7213 by OKI SEMICONDUCTOR */ /* Definition for ML7213 by OKI SEMICONDUCTOR */
#define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_VENDOR_ID_ROHM 0x10DB
#define PCI_DEVICE_ID_ML7213_I2C 0x802D #define PCI_DEVICE_ID_ML7213_I2C 0x802D
#define PCI_DEVICE_ID_ML7223_I2C 0x8010
static struct pci_device_id __devinitdata pch_pcidev_id[] = { static struct pci_device_id __devinitdata pch_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
{0,} {0,}
}; };
......
This diff is collapsed.
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c/i2c-sh_mobile.h>
/* Transmit operation: */ /* Transmit operation: */
/* */ /* */
...@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data { ...@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
struct device *dev; struct device *dev;
void __iomem *reg; void __iomem *reg;
struct i2c_adapter adap; struct i2c_adapter adap;
unsigned long bus_speed;
struct clk *clk; struct clk *clk;
u_int8_t icic; u_int8_t icic;
u_int8_t iccl; u_int8_t iccl;
...@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) ...@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
* We also round off the result. * We also round off the result.
*/ */
num = i2c_clk * 5; num = i2c_clk * 5;
denom = NORMAL_SPEED * 9; denom = pd->bus_speed * 9;
tmp = num * 10 / denom; tmp = num * 10 / denom;
if (tmp % 10 >= 5) if (tmp % 10 >= 5)
pd->iccl = (u_int8_t)((num/denom) + 1); 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) ...@@ -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) 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 sh_mobile_i2c_data *pd;
struct i2c_adapter *adap; struct i2c_adapter *adap;
struct resource *res; struct resource *res;
char clk_name[8];
int size; int size;
int ret; int ret;
...@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return -ENOMEM; return -ENOMEM;
} }
snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); pd->clk = clk_get(&dev->dev, NULL);
pd->clk = clk_get(&dev->dev, clk_name);
if (IS_ERR(pd->clk)) { 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); ret = PTR_ERR(pd->clk);
goto err; goto err;
} }
...@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
goto err_irq; 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 /* The IIC blocks on SH-Mobile ARM processors
* come with two new bits in ICIC. * come with two new bits in ICIC.
*/ */
...@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ...@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
goto err_all; goto err_all;
} }
dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
adap->nr, pd->bus_speed);
return 0; return 0;
err_all: err_all:
......
...@@ -35,8 +35,10 @@ ...@@ -35,8 +35,10 @@
#define BYTES_PER_FIFO_WORD 4 #define BYTES_PER_FIFO_WORD 4
#define I2C_CNFG 0x000 #define I2C_CNFG 0x000
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_CNFG_PACKET_MODE_EN (1<<10) #define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_FSM (1<<11) #define I2C_CNFG_NEW_MASTER_FSM (1<<11)
#define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020 #define I2C_SL_CNFG 0x020
#define I2C_SL_CNFG_NEWSL (1<<2) #define I2C_SL_CNFG_NEWSL (1<<2)
#define I2C_SL_ADDR1 0x02c #define I2C_SL_ADDR1 0x02c
...@@ -77,6 +79,7 @@ ...@@ -77,6 +79,7 @@
#define I2C_ERR_NONE 0x00 #define I2C_ERR_NONE 0x00
#define I2C_ERR_NO_ACK 0x01 #define I2C_ERR_NO_ACK 0x01
#define I2C_ERR_ARBITRATION_LOST 0x02 #define I2C_ERR_ARBITRATION_LOST 0x02
#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
#define PACKET_HEADER0_PACKET_ID_SHIFT 16 #define PACKET_HEADER0_PACKET_ID_SHIFT 16
...@@ -121,6 +124,7 @@ struct tegra_i2c_dev { ...@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
void __iomem *base; void __iomem *base;
int cont_id; int cont_id;
int irq; int irq;
bool irq_disabled;
int is_dvc; int is_dvc;
struct completion msg_complete; struct completion msg_complete;
int msg_err; int msg_err;
...@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) ...@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->is_dvc) if (i2c_dev->is_dvc)
tegra_dvc_init(i2c_dev); 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, val, I2C_CNFG);
i2c_writel(i2c_dev, 0, I2C_INT_MASK); i2c_writel(i2c_dev, 0, I2C_INT_MASK);
clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8); 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 | val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
...@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) ...@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
err = -ETIMEDOUT; err = -ETIMEDOUT;
clk_disable(i2c_dev->clk); clk_disable(i2c_dev->clk);
if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0;
enable_irq(i2c_dev->irq);
}
return err; return err;
} }
...@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) ...@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
status = i2c_readl(i2c_dev, I2C_INT_STATUS); status = i2c_readl(i2c_dev, I2C_INT_STATUS);
if (status == 0) { if (status == 0) {
dev_warn(i2c_dev->dev, "interrupt with no status\n"); dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
return IRQ_NONE; 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)) { if (unlikely(status & status_err)) {
...@@ -391,6 +418,8 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) ...@@ -391,6 +418,8 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
I2C_INT_RX_FIFO_DATA_REQ); I2C_INT_RX_FIFO_DATA_REQ);
i2c_writel(i2c_dev, status, I2C_INT_STATUS); 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; return IRQ_HANDLED;
} }
...@@ -424,12 +453,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, ...@@ -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 = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
packet_header |= I2C_HEADER_IE_ENABLE; packet_header |= I2C_HEADER_IE_ENABLE;
if (!stop)
packet_header |= I2C_HEADER_REPEAT_START;
if (msg->flags & I2C_M_TEN) if (msg->flags & I2C_M_TEN)
packet_header |= I2C_HEADER_10BIT_ADDR; packet_header |= I2C_HEADER_10BIT_ADDR;
if (msg->flags & I2C_M_IGNORE_NAK) if (msg->flags & I2C_M_IGNORE_NAK)
packet_header |= I2C_HEADER_CONT_ON_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) if (msg->flags & I2C_M_RD)
packet_header |= I2C_HEADER_READ; packet_header |= I2C_HEADER_READ;
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
......
#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__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment