Skip to content

Commit

Permalink
Merge branch 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "A set of driver bugfixes for the I2C subsystem"

* 'i2c/for-current-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: uniphier-f: fix violation of tLOW requirement for Fast-mode
  i2c: uniphier: fix violation of tLOW requirement for Fast-mode
  i2c: uniphier-f: fill TX-FIFO only in IRQ handler for repeated START
  i2c: uniphier-f: fix timeout error after reading 8 bytes
  i2c: scmi: Fix probe error on devices with an empty SMB0001 ACPI device node
  i2c: axxia: properly handle master timeout
  i2c: rcar: check bus state before reinitializing
  i2c: nvidia-gpu: limit reads also for combined messages
  i2c: nvidia-gpu: adhere to I2C fault codes
  • Loading branch information
Linus Torvalds committed Dec 7, 2018
2 parents c431b42 + ece27a3 commit 52f842c
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 30 deletions.
40 changes: 29 additions & 11 deletions drivers/i2c/busses/i2c-axxia.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@
MST_STATUS_ND)
#define MST_STATUS_ERR (MST_STATUS_NAK | \
MST_STATUS_AL | \
MST_STATUS_IP | \
MST_STATUS_TSS)
MST_STATUS_IP)
#define MST_TX_BYTES_XFRD 0x50
#define MST_RX_BYTES_XFRD 0x54
#define SCL_HIGH_PERIOD 0x80
Expand Down Expand Up @@ -241,7 +240,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
*/
if (c <= 0 || c > I2C_SMBUS_BLOCK_MAX) {
idev->msg_err = -EPROTO;
i2c_int_disable(idev, ~0);
i2c_int_disable(idev, ~MST_STATUS_TSS);
complete(&idev->msg_complete);
break;
}
Expand Down Expand Up @@ -299,14 +298,19 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)

if (status & MST_STATUS_SCC) {
/* Stop completed */
i2c_int_disable(idev, ~0);
i2c_int_disable(idev, ~MST_STATUS_TSS);
complete(&idev->msg_complete);
} else if (status & MST_STATUS_SNS) {
/* Transfer done */
i2c_int_disable(idev, ~0);
i2c_int_disable(idev, ~MST_STATUS_TSS);
if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
axxia_i2c_empty_rx_fifo(idev);
complete(&idev->msg_complete);
} else if (status & MST_STATUS_TSS) {
/* Transfer timeout */
idev->msg_err = -ETIMEDOUT;
i2c_int_disable(idev, ~MST_STATUS_TSS);
complete(&idev->msg_complete);
} else if (unlikely(status & MST_STATUS_ERR)) {
/* Transfer error */
i2c_int_disable(idev, ~0);
Expand Down Expand Up @@ -339,10 +343,10 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
u32 rx_xfer, tx_xfer;
u32 addr_1, addr_2;
unsigned long time_left;
unsigned int wt_value;

idev->msg = msg;
idev->msg_xfrd = 0;
idev->msg_err = 0;
reinit_completion(&idev->msg_complete);

if (i2c_m_ten(msg)) {
Expand Down Expand Up @@ -383,9 +387,18 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
else if (axxia_i2c_fill_tx_fifo(idev) != 0)
int_mask |= MST_STATUS_TFL;

wt_value = WT_VALUE(readl(idev->base + WAIT_TIMER_CONTROL));
/* Disable wait timer temporarly */
writel(wt_value, idev->base + WAIT_TIMER_CONTROL);
/* Check if timeout error happened */
if (idev->msg_err)
goto out;

/* Start manual mode */
writel(CMD_MANUAL, idev->base + MST_COMMAND);

writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL);

i2c_int_enable(idev, int_mask);

time_left = wait_for_completion_timeout(&idev->msg_complete,
Expand All @@ -396,21 +409,23 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
dev_warn(idev->dev, "busy after xfer\n");

if (time_left == 0)
if (time_left == 0) {
idev->msg_err = -ETIMEDOUT;

if (idev->msg_err == -ETIMEDOUT)
i2c_recover_bus(&idev->adapter);
axxia_i2c_init(idev);
}

if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
out:
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO &&
idev->msg_err != -ETIMEDOUT)
axxia_i2c_init(idev);

return idev->msg_err;
}

static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
{
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC | MST_STATUS_TSS;
unsigned long time_left;

reinit_completion(&idev->msg_complete);
Expand All @@ -437,6 +452,9 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
int i;
int ret = 0;

idev->msg_err = 0;
i2c_int_enable(idev, MST_STATUS_TSS);

for (i = 0; ret == 0 && i < num; ++i)
ret = axxia_i2c_xfer_msg(idev, &msgs[i]);

Expand Down
7 changes: 4 additions & 3 deletions drivers/i2c/busses/i2c-nvidia-gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,17 @@ static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)

if (time_is_before_jiffies(target)) {
dev_err(i2cd->dev, "i2c timeout error %x\n", val);
return -ETIME;
return -ETIMEDOUT;
}

val = readl(i2cd->regs + I2C_MST_CNTL);
switch (val & I2C_MST_CNTL_STATUS) {
case I2C_MST_CNTL_STATUS_OKAY:
return 0;
case I2C_MST_CNTL_STATUS_NO_ACK:
return -EIO;
return -ENXIO;
case I2C_MST_CNTL_STATUS_TIMEOUT:
return -ETIME;
return -ETIMEDOUT;
default:
return 0;
}
Expand Down Expand Up @@ -218,6 +218,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,

static const struct i2c_adapter_quirks gpu_i2c_quirks = {
.max_read_len = 4,
.max_comb_2nd_msg_len = 4,
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
};

Expand Down
9 changes: 5 additions & 4 deletions drivers/i2c/busses/i2c-rcar.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,

pm_runtime_get_sync(dev);

/* Check bus state before init otherwise bus busy info will be lost */
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;

/* Gen3 needs a reset before allowing RXDMA once */
if (priv->devtype == I2C_RCAR_GEN3) {
priv->flags |= ID_P_NO_RXDMA;
Expand All @@ -791,10 +796,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,

rcar_i2c_init(priv);

ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;

for (i = 0; i < num; i++)
rcar_i2c_request_dma(priv, msgs + i);

Expand Down
10 changes: 7 additions & 3 deletions drivers/i2c/busses/i2c-scmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
{
struct acpi_smbus_cmi *smbus_cmi;
const struct acpi_device_id *id;
int ret;

smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
if (!smbus_cmi)
Expand All @@ -388,8 +389,10 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);

if (smbus_cmi->cap_info == 0)
if (smbus_cmi->cap_info == 0) {
ret = -ENODEV;
goto err;
}

snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
"SMBus CMI adapter %s",
Expand All @@ -400,7 +403,8 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
smbus_cmi->adapter.dev.parent = &device->dev;

if (i2c_add_adapter(&smbus_cmi->adapter)) {
ret = i2c_add_adapter(&smbus_cmi->adapter);
if (ret) {
dev_err(&device->dev, "Couldn't register adapter!\n");
goto err;
}
Expand All @@ -410,7 +414,7 @@ static int acpi_smbus_cmi_add(struct acpi_device *device)
err:
kfree(smbus_cmi);
device->driver_data = NULL;
return -EIO;
return ret;
}

static int acpi_smbus_cmi_remove(struct acpi_device *device)
Expand Down
49 changes: 41 additions & 8 deletions drivers/i2c/busses/i2c-uniphier-f.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,6 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
"interrupt: enabled_irqs=%04x, irq_status=%04x\n",
priv->enabled_irqs, irq_status);

uniphier_fi2c_clear_irqs(priv, irq_status);

if (irq_status & UNIPHIER_FI2C_INT_STOP)
goto complete;

Expand Down Expand Up @@ -214,7 +212,13 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)

if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
uniphier_fi2c_drain_rxfifo(priv);
if (!priv->len)
/*
* If the number of bytes to read is multiple of the FIFO size
* (msg->len == 8, 16, 24, ...), the INT_RF bit is set a little
* earlier than INT_RB. We wait for INT_RB to confirm the
* completion of the current message.
*/
if (!priv->len && (irq_status & UNIPHIER_FI2C_INT_RB))
goto data_done;

if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
Expand Down Expand Up @@ -253,12 +257,20 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
}

handled:
/*
* This controller makes a pause while any bit of the IRQ status is
* asserted. Clear the asserted bit to kick the controller just before
* exiting the handler.
*/
uniphier_fi2c_clear_irqs(priv, irq_status);

spin_unlock(&priv->lock);

return IRQ_HANDLED;
}

static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr,
bool repeat)
{
priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
uniphier_fi2c_set_irqs(priv);
Expand All @@ -268,8 +280,12 @@ static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
/* set slave address */
writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
priv->membase + UNIPHIER_FI2C_DTTX);
/* first chunk of data */
uniphier_fi2c_fill_txfifo(priv, true);
/*
* First chunk of data. For a repeated START condition, do not write
* data to the TX fifo here to avoid the timing issue.
*/
if (!repeat)
uniphier_fi2c_fill_txfifo(priv, true);
}

static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
Expand Down Expand Up @@ -350,7 +366,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
if (is_read)
uniphier_fi2c_rx_init(priv, msg->addr);
else
uniphier_fi2c_tx_init(priv, msg->addr);
uniphier_fi2c_tx_init(priv, msg->addr, repeat);

dev_dbg(&adap->dev, "start condition\n");
/*
Expand Down Expand Up @@ -502,9 +518,26 @@ static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv)

uniphier_fi2c_reset(priv);

/*
* Standard-mode: tLOW + tHIGH = 10 us
* Fast-mode: tLOW + tHIGH = 2.5 us
*/
writel(cyc, priv->membase + UNIPHIER_FI2C_CYC);
writel(cyc / 2, priv->membase + UNIPHIER_FI2C_LCTL);
/*
* Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us, tBUF = 4.7 us
* Fast-mode: tLOW = 1.3 us, tHIGH = 0.6 us, tBUF = 1.3 us
* "tLow/tHIGH = 5/4" meets both.
*/
writel(cyc * 5 / 9, priv->membase + UNIPHIER_FI2C_LCTL);
/*
* Standard-mode: tHD;STA = 4.0 us, tSU;STA = 4.7 us, tSU;STO = 4.0 us
* Fast-mode: tHD;STA = 0.6 us, tSU;STA = 0.6 us, tSU;STO = 0.6 us
*/
writel(cyc / 2, priv->membase + UNIPHIER_FI2C_SSUT);
/*
* Standard-mode: tSU;DAT = 250 ns
* Fast-mode: tSU;DAT = 100 ns
*/
writel(cyc / 16, priv->membase + UNIPHIER_FI2C_DSUT);

uniphier_fi2c_prepare_operation(priv);
Expand Down
8 changes: 7 additions & 1 deletion drivers/i2c/busses/i2c-uniphier.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,13 @@ static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv)

uniphier_i2c_reset(priv, true);

writel((cyc / 2 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK);
/*
* Bit30-16: clock cycles of tLOW.
* Standard-mode: tLOW = 4.7 us, tHIGH = 4.0 us
* Fast-mode: tLOW = 1.3 us, tHIGH = 0.6 us
* "tLow/tHIGH = 5/4" meets both.
*/
writel((cyc * 5 / 9 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK);

uniphier_i2c_reset(priv, false);
}
Expand Down

0 comments on commit 52f842c

Please sign in to comment.