Commit 429966b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c-fixes-rc6' of git://aeryn.fluff.org.uk/bjdooks/linux

* 'i2c-fixes-rc6' of git://aeryn.fluff.org.uk/bjdooks/linux:
  i2c-stu300: I2C STU300 stability updates
  i2c-omap: Enable workaround for Errata 1.153 based on
  i2c-omap: ACK pending [R/X]DR and [R/X]RDY interrupts
  i2c-omap: Fix I2C status ACK
parents a1d12511 c37faafa
...@@ -674,7 +674,14 @@ omap_i2c_isr(int this_irq, void *dev_id) ...@@ -674,7 +674,14 @@ omap_i2c_isr(int this_irq, void *dev_id)
err = 0; err = 0;
complete: complete:
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); /*
* Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
* acked after the data operation is complete.
* Ref: TRM SWPU114Q Figure 18-31
*/
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
if (stat & OMAP_I2C_STAT_NACK) { if (stat & OMAP_I2C_STAT_NACK) {
err |= OMAP_I2C_STAT_NACK; err |= OMAP_I2C_STAT_NACK;
...@@ -687,6 +694,9 @@ omap_i2c_isr(int this_irq, void *dev_id) ...@@ -687,6 +694,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
} }
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
OMAP_I2C_STAT_AL)) { OMAP_I2C_STAT_AL)) {
omap_i2c_ack_stat(dev, stat &
(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
omap_i2c_complete_cmd(dev, err); omap_i2c_complete_cmd(dev, err);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -774,7 +784,7 @@ omap_i2c_isr(int this_irq, void *dev_id) ...@@ -774,7 +784,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
* memory to the I2C interface. * memory to the I2C interface.
*/ */
if (cpu_is_omap34xx()) { if (dev->rev <= OMAP_I2C_REV_ON_3430) {
while (!(stat & OMAP_I2C_STAT_XUDF)) { while (!(stat & OMAP_I2C_STAT_XUDF)) {
if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
......
...@@ -117,7 +117,8 @@ enum stu300_error { ...@@ -117,7 +117,8 @@ enum stu300_error {
STU300_ERROR_NONE = 0, STU300_ERROR_NONE = 0,
STU300_ERROR_ACKNOWLEDGE_FAILURE, STU300_ERROR_ACKNOWLEDGE_FAILURE,
STU300_ERROR_BUS_ERROR, STU300_ERROR_BUS_ERROR,
STU300_ERROR_ARBITRATION_LOST STU300_ERROR_ARBITRATION_LOST,
STU300_ERROR_UNKNOWN
}; };
/* timeout waiting for the controller to respond */ /* timeout waiting for the controller to respond */
...@@ -127,7 +128,7 @@ enum stu300_error { ...@@ -127,7 +128,7 @@ enum stu300_error {
* The number of address send athemps tried before giving up. * The number of address send athemps tried before giving up.
* If the first one failes it seems like 5 to 8 attempts are required. * If the first one failes it seems like 5 to 8 attempts are required.
*/ */
#define NUM_ADDR_RESEND_ATTEMPTS 10 #define NUM_ADDR_RESEND_ATTEMPTS 12
/* I2C clock speed, in Hz 0-400kHz*/ /* I2C clock speed, in Hz 0-400kHz*/
static unsigned int scl_frequency = 100000; static unsigned int scl_frequency = 100000;
...@@ -149,6 +150,7 @@ module_param(scl_frequency, uint, 0644); ...@@ -149,6 +150,7 @@ module_param(scl_frequency, uint, 0644);
* @msg_index: index of current message * @msg_index: index of current message
* @msg_len: length of current message * @msg_len: length of current message
*/ */
struct stu300_dev { struct stu300_dev {
struct platform_device *pdev; struct platform_device *pdev;
struct i2c_adapter adapter; struct i2c_adapter adapter;
...@@ -188,6 +190,27 @@ static inline u32 stu300_r8(void __iomem *address) ...@@ -188,6 +190,27 @@ static inline u32 stu300_r8(void __iomem *address)
return readl(address) & 0x000000FFU; return readl(address) & 0x000000FFU;
} }
static void stu300_irq_enable(struct stu300_dev *dev)
{
u32 val;
val = stu300_r8(dev->virtbase + I2C_CR);
val |= I2C_CR_INTERRUPT_ENABLE;
/* Twice paranoia (possible HW glitch) */
stu300_wr8(val, dev->virtbase + I2C_CR);
stu300_wr8(val, dev->virtbase + I2C_CR);
}
static void stu300_irq_disable(struct stu300_dev *dev)
{
u32 val;
val = stu300_r8(dev->virtbase + I2C_CR);
val &= ~I2C_CR_INTERRUPT_ENABLE;
/* Twice paranoia (possible HW glitch) */
stu300_wr8(val, dev->virtbase + I2C_CR);
stu300_wr8(val, dev->virtbase + I2C_CR);
}
/* /*
* Tells whether a certain event or events occurred in * Tells whether a certain event or events occurred in
* response to a command. The events represent states in * response to a command. The events represent states in
...@@ -196,9 +219,10 @@ static inline u32 stu300_r8(void __iomem *address) ...@@ -196,9 +219,10 @@ static inline u32 stu300_r8(void __iomem *address)
* documentation and can only be treated as abstract state * documentation and can only be treated as abstract state
* machine states. * machine states.
* *
* @ret 0 = event has not occurred, any other value means * @ret 0 = event has not occurred or unknown error, any
* the event occurred. * other value means the correct event occurred or an error.
*/ */
static int stu300_event_occurred(struct stu300_dev *dev, static int stu300_event_occurred(struct stu300_dev *dev,
enum stu300_event mr_event) { enum stu300_event mr_event) {
u32 status1; u32 status1;
...@@ -206,11 +230,28 @@ static int stu300_event_occurred(struct stu300_dev *dev, ...@@ -206,11 +230,28 @@ static int stu300_event_occurred(struct stu300_dev *dev,
/* What event happened? */ /* What event happened? */
status1 = stu300_r8(dev->virtbase + I2C_SR1); status1 = stu300_r8(dev->virtbase + I2C_SR1);
if (!(status1 & I2C_SR1_EVF_IND)) if (!(status1 & I2C_SR1_EVF_IND))
/* No event at all */ /* No event at all */
return 0; return 0;
status2 = stu300_r8(dev->virtbase + I2C_SR2); status2 = stu300_r8(dev->virtbase + I2C_SR2);
/* Block any multiple interrupts */
stu300_irq_disable(dev);
/* Check for errors first */
if (status2 & I2C_SR2_AF_IND) {
dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
return 1;
} else if (status2 & I2C_SR2_BERR_IND) {
dev->cmd_err = STU300_ERROR_BUS_ERROR;
return 1;
} else if (status2 & I2C_SR2_ARLO_IND) {
dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
return 1;
}
switch (mr_event) { switch (mr_event) {
case STU300_EVENT_1: case STU300_EVENT_1:
if (status1 & I2C_SR1_ADSL_IND) if (status1 & I2C_SR1_ADSL_IND)
...@@ -221,10 +262,6 @@ static int stu300_event_occurred(struct stu300_dev *dev, ...@@ -221,10 +262,6 @@ static int stu300_event_occurred(struct stu300_dev *dev,
case STU300_EVENT_7: case STU300_EVENT_7:
case STU300_EVENT_8: case STU300_EVENT_8:
if (status1 & I2C_SR1_BTF_IND) { if (status1 & I2C_SR1_BTF_IND) {
if (status2 & I2C_SR2_AF_IND)
dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
else if (status2 & I2C_SR2_BERR_IND)
dev->cmd_err = STU300_ERROR_BUS_ERROR;
return 1; return 1;
} }
break; break;
...@@ -240,8 +277,6 @@ static int stu300_event_occurred(struct stu300_dev *dev, ...@@ -240,8 +277,6 @@ static int stu300_event_occurred(struct stu300_dev *dev,
case STU300_EVENT_6: case STU300_EVENT_6:
if (status2 & I2C_SR2_ENDAD_IND) { if (status2 & I2C_SR2_ENDAD_IND) {
/* First check for any errors */ /* First check for any errors */
if (status2 & I2C_SR2_AF_IND)
dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
return 1; return 1;
} }
break; break;
...@@ -252,8 +287,15 @@ static int stu300_event_occurred(struct stu300_dev *dev, ...@@ -252,8 +287,15 @@ static int stu300_event_occurred(struct stu300_dev *dev,
default: default:
break; break;
} }
if (status2 & I2C_SR2_ARLO_IND) /* If we get here, we're on thin ice.
dev->cmd_err = STU300_ERROR_ARBITRATION_LOST; * Here we are in a status where we have
* gotten a response that does not match
* what we requested.
*/
dev->cmd_err = STU300_ERROR_UNKNOWN;
dev_err(&dev->pdev->dev,
"Unhandled interrupt! %d sr1: 0x%x sr2: 0x%x\n",
mr_event, status1, status2);
return 0; return 0;
} }
...@@ -262,21 +304,20 @@ static irqreturn_t stu300_irh(int irq, void *data) ...@@ -262,21 +304,20 @@ static irqreturn_t stu300_irh(int irq, void *data)
struct stu300_dev *dev = data; struct stu300_dev *dev = data;
int res; int res;
/* Just make sure that the block is clocked */
clk_enable(dev->clk);
/* See if this was what we were waiting for */ /* See if this was what we were waiting for */
spin_lock(&dev->cmd_issue_lock); spin_lock(&dev->cmd_issue_lock);
if (dev->cmd_event != STU300_EVENT_NONE) {
res = stu300_event_occurred(dev, dev->cmd_event);
if (res || dev->cmd_err != STU300_ERROR_NONE) {
u32 val;
res = stu300_event_occurred(dev, dev->cmd_event);
if (res || dev->cmd_err != STU300_ERROR_NONE)
complete(&dev->cmd_complete); complete(&dev->cmd_complete);
/* Block any multiple interrupts */
val = stu300_r8(dev->virtbase + I2C_CR);
val &= ~I2C_CR_INTERRUPT_ENABLE;
stu300_wr8(val, dev->virtbase + I2C_CR);
}
}
spin_unlock(&dev->cmd_issue_lock); spin_unlock(&dev->cmd_issue_lock);
clk_disable(dev->clk);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -308,7 +349,6 @@ static int stu300_start_and_await_event(struct stu300_dev *dev, ...@@ -308,7 +349,6 @@ static int stu300_start_and_await_event(struct stu300_dev *dev,
stu300_wr8(cr_value, dev->virtbase + I2C_CR); stu300_wr8(cr_value, dev->virtbase + I2C_CR);
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
STU300_TIMEOUT); STU300_TIMEOUT);
if (ret < 0) { if (ret < 0) {
dev_err(&dev->pdev->dev, dev_err(&dev->pdev->dev,
"wait_for_completion_interruptible_timeout() " "wait_for_completion_interruptible_timeout() "
...@@ -342,7 +382,6 @@ static int stu300_await_event(struct stu300_dev *dev, ...@@ -342,7 +382,6 @@ static int stu300_await_event(struct stu300_dev *dev,
enum stu300_event mr_event) enum stu300_event mr_event)
{ {
int ret; int ret;
u32 val;
if (unlikely(irqs_disabled())) { if (unlikely(irqs_disabled())) {
/* TODO: implement polling for this case if need be. */ /* TODO: implement polling for this case if need be. */
...@@ -354,36 +393,18 @@ static int stu300_await_event(struct stu300_dev *dev, ...@@ -354,36 +393,18 @@ static int stu300_await_event(struct stu300_dev *dev,
/* Is it already here? */ /* Is it already here? */
spin_lock_irq(&dev->cmd_issue_lock); spin_lock_irq(&dev->cmd_issue_lock);
dev->cmd_err = STU300_ERROR_NONE; dev->cmd_err = STU300_ERROR_NONE;
if (stu300_event_occurred(dev, mr_event)) {
spin_unlock_irq(&dev->cmd_issue_lock);
goto exit_await_check_err;
}
init_completion(&dev->cmd_complete);
dev->cmd_err = STU300_ERROR_NONE;
dev->cmd_event = mr_event; dev->cmd_event = mr_event;
/* Turn on the I2C interrupt for current operation */ init_completion(&dev->cmd_complete);
val = stu300_r8(dev->virtbase + I2C_CR);
val |= I2C_CR_INTERRUPT_ENABLE;
stu300_wr8(val, dev->virtbase + I2C_CR);
/* Twice paranoia (possible HW glitch) */
stu300_wr8(val, dev->virtbase + I2C_CR);
/* Check again: is it already here? */ /* Turn on the I2C interrupt for current operation */
if (unlikely(stu300_event_occurred(dev, mr_event))) { stu300_irq_enable(dev);
/* Disable IRQ again. */
val &= ~I2C_CR_INTERRUPT_ENABLE;
stu300_wr8(val, dev->virtbase + I2C_CR);
spin_unlock_irq(&dev->cmd_issue_lock);
goto exit_await_check_err;
}
/* Unlock the command block and wait for the event to occur */ /* Unlock the command block and wait for the event to occur */
spin_unlock_irq(&dev->cmd_issue_lock); spin_unlock_irq(&dev->cmd_issue_lock);
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
STU300_TIMEOUT); STU300_TIMEOUT);
if (ret < 0) { if (ret < 0) {
dev_err(&dev->pdev->dev, dev_err(&dev->pdev->dev,
"wait_for_completion_interruptible_timeout()" "wait_for_completion_interruptible_timeout()"
...@@ -401,7 +422,6 @@ static int stu300_await_event(struct stu300_dev *dev, ...@@ -401,7 +422,6 @@ static int stu300_await_event(struct stu300_dev *dev,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
exit_await_check_err:
if (dev->cmd_err != STU300_ERROR_NONE) { if (dev->cmd_err != STU300_ERROR_NONE) {
if (mr_event != STU300_EVENT_6) { if (mr_event != STU300_EVENT_6) {
dev_err(&dev->pdev->dev, "controller " dev_err(&dev->pdev->dev, "controller "
...@@ -469,6 +489,7 @@ static const struct stu300_clkset stu300_clktable[] = { ...@@ -469,6 +489,7 @@ static const struct stu300_clkset stu300_clktable[] = {
{ 100000000, 0xFFU }, { 100000000, 0xFFU },
}; };
static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
{ {
...@@ -494,10 +515,10 @@ static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) ...@@ -494,10 +515,10 @@ static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
if (dev->speed > 100000) if (dev->speed > 100000)
/* Fast Mode I2C */ /* Fast Mode I2C */
val = ((clkrate/dev->speed)-9)/3; val = ((clkrate/dev->speed) - 9)/3 + 1;
else else
/* Standard Mode I2C */ /* Standard Mode I2C */
val = ((clkrate/dev->speed)-7)/2; val = ((clkrate/dev->speed) - 7)/2 + 1;
/* According to spec the divider must be > 2 */ /* According to spec the divider must be > 2 */
if (val < 0x002) { if (val < 0x002) {
...@@ -557,6 +578,7 @@ static int stu300_init_hw(struct stu300_dev *dev) ...@@ -557,6 +578,7 @@ static int stu300_init_hw(struct stu300_dev *dev)
*/ */
clkrate = clk_get_rate(dev->clk); clkrate = clk_get_rate(dev->clk);
ret = stu300_set_clk(dev, clkrate); ret = stu300_set_clk(dev, clkrate);
if (ret) if (ret)
return ret; return ret;
/* /*
...@@ -641,7 +663,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap, ...@@ -641,7 +663,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,
int attempts = 0; int attempts = 0;
struct stu300_dev *dev = i2c_get_adapdata(adap); struct stu300_dev *dev = i2c_get_adapdata(adap);
clk_enable(dev->clk); clk_enable(dev->clk);
/* Remove this if (0) to trace each and every message. */ /* Remove this if (0) to trace each and every message. */
...@@ -723,6 +744,7 @@ static int stu300_xfer_msg(struct i2c_adapter *adap, ...@@ -723,6 +744,7 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,
goto exit_disable; goto exit_disable;
} }
if (msg->flags & I2C_M_RD) { if (msg->flags & I2C_M_RD) {
/* READ: we read the actual bytes one at a time */ /* READ: we read the actual bytes one at a time */
for (i = 0; i < msg->len; i++) { for (i = 0; i < msg->len; i++) {
...@@ -804,8 +826,10 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -804,8 +826,10 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
{ {
int ret = -1; int ret = -1;
int i; int i;
struct stu300_dev *dev = i2c_get_adapdata(adap); struct stu300_dev *dev = i2c_get_adapdata(adap);
dev->msg_len = num; dev->msg_len = num;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
/* /*
* Another driver appears to send stop for each message, * Another driver appears to send stop for each message,
...@@ -817,6 +841,7 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ...@@ -817,6 +841,7 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
dev->msg_index = i; dev->msg_index = i;
ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1))); ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
if (ret != 0) { if (ret != 0) {
num = ret; num = ret;
break; break;
...@@ -845,6 +870,7 @@ stu300_probe(struct platform_device *pdev) ...@@ -845,6 +870,7 @@ stu300_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
int bus_nr; int bus_nr;
int ret = 0; int ret = 0;
char clk_name[] = "I2C0";
dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL); dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
if (!dev) { if (!dev) {
...@@ -854,7 +880,8 @@ stu300_probe(struct platform_device *pdev) ...@@ -854,7 +880,8 @@ stu300_probe(struct platform_device *pdev)
} }
bus_nr = pdev->id; bus_nr = pdev->id;
dev->clk = clk_get(&pdev->dev, NULL); clk_name[3] += (char)bus_nr;
dev->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(dev->clk)) { if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk); ret = PTR_ERR(dev->clk);
dev_err(&pdev->dev, "could not retrieve i2c bus clock\n"); dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
......
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