mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
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
This commit is contained in:
commit
429966b8f6
2 changed files with 103 additions and 66 deletions
|
@ -674,7 +674,14 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
|
||||
err = 0;
|
||||
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) {
|
||||
err |= OMAP_I2C_STAT_NACK;
|
||||
|
@ -687,6 +694,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
}
|
||||
if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
|
||||
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);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -774,7 +784,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
|
|||
* memory to the I2C interface.
|
||||
*/
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
if (dev->rev <= OMAP_I2C_REV_ON_3430) {
|
||||
while (!(stat & OMAP_I2C_STAT_XUDF)) {
|
||||
if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
|
||||
omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
|
||||
|
|
|
@ -117,7 +117,8 @@ enum stu300_error {
|
|||
STU300_ERROR_NONE = 0,
|
||||
STU300_ERROR_ACKNOWLEDGE_FAILURE,
|
||||
STU300_ERROR_BUS_ERROR,
|
||||
STU300_ERROR_ARBITRATION_LOST
|
||||
STU300_ERROR_ARBITRATION_LOST,
|
||||
STU300_ERROR_UNKNOWN
|
||||
};
|
||||
|
||||
/* timeout waiting for the controller to respond */
|
||||
|
@ -127,7 +128,7 @@ enum stu300_error {
|
|||
* The number of address send athemps tried before giving up.
|
||||
* 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*/
|
||||
static unsigned int scl_frequency = 100000;
|
||||
|
@ -149,6 +150,7 @@ module_param(scl_frequency, uint, 0644);
|
|||
* @msg_index: index of current message
|
||||
* @msg_len: length of current message
|
||||
*/
|
||||
|
||||
struct stu300_dev {
|
||||
struct platform_device *pdev;
|
||||
struct i2c_adapter adapter;
|
||||
|
@ -188,6 +190,27 @@ static inline u32 stu300_r8(void __iomem *address)
|
|||
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
|
||||
* response to a command. The events represent states in
|
||||
|
@ -196,9 +219,10 @@ static inline u32 stu300_r8(void __iomem *address)
|
|||
* documentation and can only be treated as abstract state
|
||||
* machine states.
|
||||
*
|
||||
* @ret 0 = event has not occurred, any other value means
|
||||
* the event occurred.
|
||||
* @ret 0 = event has not occurred or unknown error, any
|
||||
* other value means the correct event occurred or an error.
|
||||
*/
|
||||
|
||||
static int stu300_event_occurred(struct stu300_dev *dev,
|
||||
enum stu300_event mr_event) {
|
||||
u32 status1;
|
||||
|
@ -206,11 +230,28 @@ static int stu300_event_occurred(struct stu300_dev *dev,
|
|||
|
||||
/* What event happened? */
|
||||
status1 = stu300_r8(dev->virtbase + I2C_SR1);
|
||||
|
||||
if (!(status1 & I2C_SR1_EVF_IND))
|
||||
/* No event at all */
|
||||
return 0;
|
||||
|
||||
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) {
|
||||
case STU300_EVENT_1:
|
||||
if (status1 & I2C_SR1_ADSL_IND)
|
||||
|
@ -221,10 +262,6 @@ static int stu300_event_occurred(struct stu300_dev *dev,
|
|||
case STU300_EVENT_7:
|
||||
case STU300_EVENT_8:
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -240,8 +277,6 @@ static int stu300_event_occurred(struct stu300_dev *dev,
|
|||
case STU300_EVENT_6:
|
||||
if (status2 & I2C_SR2_ENDAD_IND) {
|
||||
/* First check for any errors */
|
||||
if (status2 & I2C_SR2_AF_IND)
|
||||
dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -252,8 +287,15 @@ static int stu300_event_occurred(struct stu300_dev *dev,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (status2 & I2C_SR2_ARLO_IND)
|
||||
dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
|
||||
/* If we get here, we're on thin ice.
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
@ -262,21 +304,20 @@ static irqreturn_t stu300_irh(int irq, void *data)
|
|||
struct stu300_dev *dev = data;
|
||||
int res;
|
||||
|
||||
/* Just make sure that the block is clocked */
|
||||
clk_enable(dev->clk);
|
||||
|
||||
/* See if this was what we were waiting for */
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
clk_disable(dev->clk);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -308,7 +349,6 @@ static int stu300_start_and_await_event(struct stu300_dev *dev,
|
|||
stu300_wr8(cr_value, dev->virtbase + I2C_CR);
|
||||
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
|
||||
STU300_TIMEOUT);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
"wait_for_completion_interruptible_timeout() "
|
||||
|
@ -342,7 +382,6 @@ static int stu300_await_event(struct stu300_dev *dev,
|
|||
enum stu300_event mr_event)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (unlikely(irqs_disabled())) {
|
||||
/* TODO: implement polling for this case if need be. */
|
||||
|
@ -354,36 +393,18 @@ static int stu300_await_event(struct stu300_dev *dev,
|
|||
/* Is it already here? */
|
||||
spin_lock_irq(&dev->cmd_issue_lock);
|
||||
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;
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
|
||||
/* Turn on the I2C interrupt for current operation */
|
||||
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? */
|
||||
if (unlikely(stu300_event_occurred(dev, mr_event))) {
|
||||
/* 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;
|
||||
}
|
||||
stu300_irq_enable(dev);
|
||||
|
||||
/* Unlock the command block and wait for the event to occur */
|
||||
spin_unlock_irq(&dev->cmd_issue_lock);
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
|
||||
STU300_TIMEOUT);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
"wait_for_completion_interruptible_timeout()"
|
||||
|
@ -401,7 +422,6 @@ static int stu300_await_event(struct stu300_dev *dev,
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
exit_await_check_err:
|
||||
if (dev->cmd_err != STU300_ERROR_NONE) {
|
||||
if (mr_event != STU300_EVENT_6) {
|
||||
dev_err(&dev->pdev->dev, "controller "
|
||||
|
@ -469,6 +489,7 @@ static const struct stu300_clkset stu300_clktable[] = {
|
|||
{ 100000000, 0xFFU },
|
||||
};
|
||||
|
||||
|
||||
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)
|
||||
/* Fast Mode I2C */
|
||||
val = ((clkrate/dev->speed)-9)/3;
|
||||
val = ((clkrate/dev->speed) - 9)/3 + 1;
|
||||
else
|
||||
/* Standard Mode I2C */
|
||||
val = ((clkrate/dev->speed)-7)/2;
|
||||
val = ((clkrate/dev->speed) - 7)/2 + 1;
|
||||
|
||||
/* According to spec the divider must be > 2 */
|
||||
if (val < 0x002) {
|
||||
|
@ -557,6 +578,7 @@ static int stu300_init_hw(struct stu300_dev *dev)
|
|||
*/
|
||||
clkrate = clk_get_rate(dev->clk);
|
||||
ret = stu300_set_clk(dev, clkrate);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
|
@ -641,7 +663,6 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,
|
|||
int attempts = 0;
|
||||
struct stu300_dev *dev = i2c_get_adapdata(adap);
|
||||
|
||||
|
||||
clk_enable(dev->clk);
|
||||
|
||||
/* Remove this if (0) to trace each and every message. */
|
||||
|
@ -723,6 +744,7 @@ static int stu300_xfer_msg(struct i2c_adapter *adap,
|
|||
goto exit_disable;
|
||||
}
|
||||
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
/* READ: we read the actual bytes one at a time */
|
||||
for (i = 0; i < msg->len; i++) {
|
||||
|
@ -804,8 +826,10 @@ static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
{
|
||||
int ret = -1;
|
||||
int i;
|
||||
|
||||
struct stu300_dev *dev = i2c_get_adapdata(adap);
|
||||
dev->msg_len = num;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/*
|
||||
* 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,
|
|||
dev->msg_index = i;
|
||||
|
||||
ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
|
||||
|
||||
if (ret != 0) {
|
||||
num = ret;
|
||||
break;
|
||||
|
@ -845,6 +870,7 @@ stu300_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int bus_nr;
|
||||
int ret = 0;
|
||||
char clk_name[] = "I2C0";
|
||||
|
||||
dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
|
@ -854,7 +880,8 @@ stu300_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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)) {
|
||||
ret = PTR_ERR(dev->clk);
|
||||
dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
|
||||
|
|
Loading…
Reference in a new issue