提交 4a7df24d 编写于 作者: L 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
  ...
...@@ -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,}
}; };
......
...@@ -15,13 +15,14 @@ ...@@ -15,13 +15,14 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <plat/i2c.h> #include <plat/i2c.h>
...@@ -103,9 +104,6 @@ ...@@ -103,9 +104,6 @@
/* maximum threshold value */ /* maximum threshold value */
#define MAX_I2C_FIFO_THRESHOLD 15 #define MAX_I2C_FIFO_THRESHOLD 15
/* per-transfer delay, required for the hardware to stabilize */
#define I2C_DELAY 150
enum i2c_status { enum i2c_status {
I2C_NOP, I2C_NOP,
I2C_ON_GOING, I2C_ON_GOING,
...@@ -120,9 +118,6 @@ enum i2c_operation { ...@@ -120,9 +118,6 @@ enum i2c_operation {
I2C_READ = 0x01 I2C_READ = 0x01
}; };
/* controller response timeout in ms */
#define I2C_TIMEOUT_MS 2000
/** /**
* struct i2c_nmk_client - client specific data * struct i2c_nmk_client - client specific data
* @slave_adr: 7-bit slave address * @slave_adr: 7-bit slave address
...@@ -151,6 +146,7 @@ struct i2c_nmk_client { ...@@ -151,6 +146,7 @@ struct i2c_nmk_client {
* @stop: stop condition * @stop: stop condition
* @xfer_complete: acknowledge completion for a I2C message * @xfer_complete: acknowledge completion for a I2C message
* @result: controller propogated result * @result: controller propogated result
* @busy: Busy doing transfer
*/ */
struct nmk_i2c_dev { struct nmk_i2c_dev {
struct platform_device *pdev; struct platform_device *pdev;
...@@ -163,6 +159,8 @@ struct nmk_i2c_dev { ...@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
int stop; int stop;
struct completion xfer_complete; struct completion xfer_complete;
int result; int result;
struct regulator *regulator;
bool busy;
}; };
/* controller's abort causes */ /* controller's abort causes */
...@@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) ...@@ -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); writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
for (i = 0; i < LOOP_ATTEMPTS; i++) { 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)) { while (!time_after(jiffies, timeout)) {
if ((readl(dev->virtbase + I2C_CR) & if ((readl(dev->virtbase + I2C_CR) &
...@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev) ...@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
{ {
int stat; int stat;
clk_enable(dev->clk);
stat = flush_i2c_fifo(dev); stat = flush_i2c_fifo(dev);
if (stat) if (stat)
return stat; goto exit;
/* disable the controller */ /* disable the controller */
i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE); i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
...@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev) ...@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
dev->cli.operation = I2C_NO_OPERATION; dev->cli.operation = I2C_NO_OPERATION;
clk_disable(dev->clk); exit:
return stat;
udelay(I2C_DELAY);
return 0;
} }
/* enable peripheral, master mode operation */ /* enable peripheral, master mode operation */
...@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) ...@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
dev->virtbase + I2C_IMSCR); dev->virtbase + I2C_IMSCR);
timeout = wait_for_completion_interruptible_timeout( timeout = wait_for_completion_interruptible_timeout(
&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); &dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) { if (timeout < 0) {
dev_err(&dev->pdev->dev, dev_err(&dev->pdev->dev,
...@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev) ...@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
} }
if (timeout == 0) { if (timeout == 0) {
/* controller has timedout, re-init the h/w */ /* Controller timed out */
dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
(void) init_hw(dev); dev->cli.slave_adr);
status = -ETIMEDOUT; status = -ETIMEDOUT;
} }
return status; 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. * write_i2c() - Write data to I2C client.
* @dev: private data of I2C Driver * @dev: private data of I2C Driver
...@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev) ...@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
init_completion(&dev->xfer_complete); init_completion(&dev->xfer_complete);
/* enable interrupts by settings the masks */ /* enable interrupts by settings the masks */
irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR | irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
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 * 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) ...@@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
dev->virtbase + I2C_IMSCR); dev->virtbase + I2C_IMSCR);
timeout = wait_for_completion_interruptible_timeout( timeout = wait_for_completion_interruptible_timeout(
&dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS)); &dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) { if (timeout < 0) {
dev_err(&dev->pdev->dev, dev_err(&dev->pdev->dev,
...@@ -498,15 +515,60 @@ static int write_i2c(struct nmk_i2c_dev *dev) ...@@ -498,15 +515,60 @@ static int write_i2c(struct nmk_i2c_dev *dev)
} }
if (timeout == 0) { if (timeout == 0) {
/* controller has timedout, re-init the h/w */ /* Controller timed out */
dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
(void) init_hw(dev); dev->cli.slave_adr);
status = -ETIMEDOUT; status = -ETIMEDOUT;
} }
return status; return status;
} }
/**
* 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 * nmk_i2c_xfer() - I2C transfer function used by kernel framework
* @i2c_adap: Adapter pointer to the controller * @i2c_adap: Adapter pointer to the controller
...@@ -559,15 +621,23 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -559,15 +621,23 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
{ {
int status; int status;
int i; int i;
u32 cause;
struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
int j;
status = init_hw(dev); dev->busy = true;
if (status)
return status; if (dev->regulator)
regulator_enable(dev->regulator);
pm_runtime_get_sync(&dev->pdev->dev);
clk_enable(dev->clk); clk_enable(dev->clk);
status = init_hw(dev);
if (status)
goto out;
/* Attempt three times to send the message queue */
for (j = 0; j < 3; j++) {
/* setup the i2c controller */ /* setup the i2c controller */
setup_i2c_controller(dev); setup_i2c_controller(dev);
...@@ -575,7 +645,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -575,7 +645,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
if (unlikely(msgs[i].flags & I2C_M_TEN)) { if (unlikely(msgs[i].flags & I2C_M_TEN)) {
dev_err(&dev->pdev->dev, "10 bit addressing" dev_err(&dev->pdev->dev, "10 bit addressing"
"not supported\n"); "not supported\n");
return -EINVAL;
status = -EINVAL;
goto out;
} }
dev->cli.slave_adr = msgs[i].addr; dev->cli.slave_adr = msgs[i].addr;
dev->cli.buffer = msgs[i].buf; dev->cli.buffer = msgs[i].buf;
...@@ -583,29 +655,21 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -583,29 +655,21 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
dev->stop = (i < (num_msgs - 1)) ? 0 : 1; dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
dev->result = 0; dev->result = 0;
if (msgs[i].flags & I2C_M_RD) { status = nmk_i2c_xfer_one(dev, msgs[i].flags);
/* it is a read operation */ if (status != 0)
dev->cli.operation = I2C_READ; break;
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;
} }
udelay(I2C_DELAY); if (status == 0)
break;
} }
out:
clk_disable(dev->clk); 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 */ /* return the no. messages processed */
if (status) if (status)
...@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
*/ */
disable_interrupts(dev, I2C_IT_TXFNE); disable_interrupts(dev, I2C_IT_TXFNE);
} else { } else {
for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2); fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
(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++;
}
/* /*
* if done, close the transfer by disabling the * if done, close the transfer by disabling the
* corresponding TXFNE interrupt * corresponding TXFNE interrupt
...@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
} }
} }
i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD); disable_all_interrupts(dev);
i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS); clear_all_interrupts(dev);
disable_interrupts(dev,
(I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
| I2C_IT_TXFOVR | I2C_IT_RXFNF
| I2C_IT_RXFF | I2C_IT_RXFE));
if (dev->cli.count) { if (dev->cli.count) {
dev->result = -1; dev->result = -EIO;
dev_err(&dev->pdev->dev, "%lu bytes still remain to be" dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
"xfered\n", dev->cli.count); "xfered\n", dev->cli.count);
(void) init_hw(dev); (void) init_hw(dev);
...@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
/* Master Arbitration lost interrupt */ /* Master Arbitration lost interrupt */
case I2C_IT_MAL: case I2C_IT_MAL:
dev->result = -1; dev->result = -EIO;
(void) init_hw(dev); (void) init_hw(dev);
i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL); i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
...@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
* during the transaction. * during the transaction.
*/ */
case I2C_IT_BERR: case I2C_IT_BERR:
dev->result = -1; dev->result = -EIO;
/* get the status */ /* get the status */
if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT) if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
(void) init_hw(dev); (void) init_hw(dev);
...@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
* the Tx FIFO is full. * the Tx FIFO is full.
*/ */
case I2C_IT_TXFOVR: case I2C_IT_TXFOVR:
dev->result = -1; dev->result = -EIO;
(void) init_hw(dev); (void) init_hw(dev);
dev_err(&dev->pdev->dev, "Tx Fifo Over run\n"); dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
...@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) ...@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
return IRQ_HANDLED; 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) static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
...@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
ret = -ENOMEM; ret = -ENOMEM;
goto err_no_mem; goto err_no_mem;
} }
dev->busy = false;
dev->pdev = pdev; dev->pdev = pdev;
platform_set_drvdata(pdev, dev); platform_set_drvdata(pdev, dev);
...@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
goto err_irq; 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); dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) { if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "could not get i2c clock\n"); dev_err(&pdev->dev, "could not get i2c clock\n");
...@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
adap->owner = THIS_MODULE; adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &nmk_i2c_algo; adap->algo = &nmk_i2c_algo;
adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
msecs_to_jiffies(20000);
snprintf(adap->name, sizeof(adap->name), snprintf(adap->name, sizeof(adap->name),
"Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start); "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) ...@@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, dev); 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 " dev_info(&pdev->dev, "initialize %s on virtual "
"base %p\n", adap->name, dev->virtbase); "base %p\n", adap->name, dev->virtbase);
...@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) ...@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
return 0; return 0;
err_init_hw:
err_add_adap: err_add_adap:
clk_put(dev->clk); clk_put(dev->clk);
err_no_clk: err_no_clk:
if (dev->regulator)
regulator_put(dev->regulator);
pm_runtime_disable(&pdev->dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
err_irq: err_irq:
iounmap(dev->virtbase); iounmap(dev->virtbase);
...@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev) ...@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
if (res) if (res)
release_mem_region(res->start, resource_size(res)); release_mem_region(res->start, resource_size(res));
clk_put(dev->clk); clk_put(dev->clk);
if (dev->regulator)
regulator_put(dev->regulator);
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
kfree(dev); kfree(dev);
...@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = { ...@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DRIVER_NAME, .name = DRIVER_NAME,
.pm = &nmk_i2c_pm,
}, },
.probe = nmk_i2c_probe, .probe = nmk_i2c_probe,
.remove = __devexit_p(nmk_i2c_remove), .remove = __devexit_p(nmk_i2c_remove),
......
...@@ -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% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册