Commit af6e7de0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "Driver bugfixes for I2C.

  Most of them are for the new mlxbf driver which got more exposure
  after rc1. The sh_mobile patch should already have reached you during
  the merge window, but I accidently dropped it. However, since it fixes
  a problem with rebooting, it is still fine for rc3"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: designware: slave should do WRITE_REQUESTED before WRITE_RECEIVED
  i2c: designware: call i2c_dw_read_clear_intrbits_slave() once
  i2c: mlxbf: I2C_MLXBF should depend on MELLANOX_PLATFORM
  i2c: mlxbf: Update author and maintainer email info
  i2c: mlxbf: Update reference clock frequency
  i2c: mlxbf: Remove unecessary wrapper functions
  i2c: mlxbf: Fix resrticted cast warning of sparse
  i2c: mlxbf: Add CONFIG_ACPI to guard ACPI function call
  i2c: sh_mobile: implement atomic transfers
  i2c: mediatek: move dma reset before i2c reset
parents 4b1d362d 3b5f7f10
...@@ -11163,7 +11163,7 @@ F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt ...@@ -11163,7 +11163,7 @@ F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
F: drivers/input/touchscreen/melfas_mip4.c F: drivers/input/touchscreen/melfas_mip4.c
MELLANOX BLUEFIELD I2C DRIVER MELLANOX BLUEFIELD I2C DRIVER
M: Khalil Blaiech <kblaiech@mellanox.com> M: Khalil Blaiech <kblaiech@nvidia.com>
L: linux-i2c@vger.kernel.org L: linux-i2c@vger.kernel.org
S: Supported S: Supported
F: drivers/i2c/busses/i2c-mlxbf.c F: drivers/i2c/busses/i2c-mlxbf.c
......
...@@ -733,7 +733,7 @@ config I2C_LPC2K ...@@ -733,7 +733,7 @@ config I2C_LPC2K
config I2C_MLXBF config I2C_MLXBF
tristate "Mellanox BlueField I2C controller" tristate "Mellanox BlueField I2C controller"
depends on ARM64 depends on MELLANOX_PLATFORM && ARM64
help help
Enabling this option will add I2C SMBus support for Mellanox BlueField Enabling this option will add I2C SMBus support for Mellanox BlueField
system. system.
......
...@@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
u32 raw_stat, stat, enabled, tmp; u32 raw_stat, stat, enabled, tmp;
u8 val = 0, slave_activity; u8 val = 0, slave_activity;
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
regmap_read(dev->map, DW_IC_ENABLE, &enabled); regmap_read(dev->map, DW_IC_ENABLE, &enabled);
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat); regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
regmap_read(dev->map, DW_IC_STATUS, &tmp); regmap_read(dev->map, DW_IC_STATUS, &tmp);
...@@ -168,32 +167,30 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -168,32 +167,30 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave) if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
return 0; return 0;
stat = i2c_dw_read_clear_intrbits_slave(dev);
dev_dbg(dev->dev, dev_dbg(dev->dev,
"%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n", "%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
enabled, slave_activity, raw_stat, stat); enabled, slave_activity, raw_stat, stat);
if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET)) if (stat & DW_IC_INTR_RX_FULL) {
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val); if (dev->status != STATUS_WRITE_IN_PROGRESS) {
dev->status = STATUS_WRITE_IN_PROGRESS;
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED,
&val);
}
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
val = tmp;
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
&val))
dev_vdbg(dev->dev, "Byte %X acked!", val);
}
if (stat & DW_IC_INTR_RD_REQ) { if (stat & DW_IC_INTR_RD_REQ) {
if (slave_activity) { if (slave_activity) {
if (stat & DW_IC_INTR_RX_FULL) { regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
val = tmp; dev->status = STATUS_READ_IN_PROGRESS;
if (!i2c_slave_event(dev->slave,
I2C_SLAVE_WRITE_RECEIVED,
&val)) {
dev_vdbg(dev->dev, "Byte %X acked!",
val);
}
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
stat = i2c_dw_read_clear_intrbits_slave(dev);
} else {
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
stat = i2c_dw_read_clear_intrbits_slave(dev);
}
if (!i2c_slave_event(dev->slave, if (!i2c_slave_event(dev->slave,
I2C_SLAVE_READ_REQUESTED, I2C_SLAVE_READ_REQUESTED,
&val)) &val))
...@@ -205,21 +202,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) ...@@ -205,21 +202,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
&val)) &val))
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp); regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
stat = i2c_dw_read_clear_intrbits_slave(dev);
return 1;
} }
if (stat & DW_IC_INTR_RX_FULL) { if (stat & DW_IC_INTR_STOP_DET) {
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp); dev->status = STATUS_IDLE;
val = tmp;
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
&val))
dev_vdbg(dev->dev, "Byte %X acked!", val);
} else {
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val); i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
stat = i2c_dw_read_clear_intrbits_slave(dev);
} }
return 1; return 1;
...@@ -230,7 +217,6 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id) ...@@ -230,7 +217,6 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
struct dw_i2c_dev *dev = dev_id; struct dw_i2c_dev *dev = dev_id;
int ret; int ret;
i2c_dw_read_clear_intrbits_slave(dev);
ret = i2c_dw_irq_handler_slave(dev); ret = i2c_dw_irq_handler_slave(dev);
if (ret > 0) if (ret > 0)
complete(&dev->cmd_complete); complete(&dev->cmd_complete);
......
This diff is collapsed.
...@@ -475,6 +475,10 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) ...@@ -475,6 +475,10 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
{ {
u16 control_reg; u16 control_reg;
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
udelay(50);
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET); mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET);
/* Set ioconfig */ /* Set ioconfig */
...@@ -529,10 +533,6 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) ...@@ -529,10 +533,6 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL); mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN); mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
udelay(50);
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
} }
static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed) static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed)
......
...@@ -129,6 +129,7 @@ struct sh_mobile_i2c_data { ...@@ -129,6 +129,7 @@ struct sh_mobile_i2c_data {
int sr; int sr;
bool send_stop; bool send_stop;
bool stop_after_dma; bool stop_after_dma;
bool atomic_xfer;
struct resource *res; struct resource *res;
struct dma_chan *dma_tx; struct dma_chan *dma_tx;
...@@ -330,13 +331,15 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op ...@@ -330,13 +331,15 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op
ret = iic_rd(pd, ICDR); ret = iic_rd(pd, ICDR);
break; break;
case OP_RX_STOP: /* enable DTE interrupt, issue stop */ case OP_RX_STOP: /* enable DTE interrupt, issue stop */
iic_wr(pd, ICIC, if (!pd->atomic_xfer)
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); iic_wr(pd, ICIC,
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
break; break;
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
iic_wr(pd, ICIC, if (!pd->atomic_xfer)
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); iic_wr(pd, ICIC,
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
ret = iic_rd(pd, ICDR); ret = iic_rd(pd, ICDR);
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
break; break;
...@@ -429,7 +432,8 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) ...@@ -429,7 +432,8 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
if (wakeup) { if (wakeup) {
pd->sr |= SW_DONE; pd->sr |= SW_DONE;
wake_up(&pd->wait); if (!pd->atomic_xfer)
wake_up(&pd->wait);
} }
/* defeat write posting to avoid spurious WAIT interrupts */ /* defeat write posting to avoid spurious WAIT interrupts */
...@@ -581,6 +585,9 @@ static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, ...@@ -581,6 +585,9 @@ static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
pd->pos = -1; pd->pos = -1;
pd->sr = 0; pd->sr = 0;
if (pd->atomic_xfer)
return;
pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8); pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
if (pd->dma_buf) if (pd->dma_buf)
sh_mobile_i2c_xfer_dma(pd); sh_mobile_i2c_xfer_dma(pd);
...@@ -637,15 +644,13 @@ static int poll_busy(struct sh_mobile_i2c_data *pd) ...@@ -637,15 +644,13 @@ static int poll_busy(struct sh_mobile_i2c_data *pd)
return i ? 0 : -ETIMEDOUT; return i ? 0 : -ETIMEDOUT;
} }
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
struct i2c_msg *msgs, struct i2c_msg *msgs, int num)
int num)
{ {
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
struct i2c_msg *msg; struct i2c_msg *msg;
int err = 0; int err = 0;
int i; int i;
long timeout; long time_left;
/* Wake up device and enable clock */ /* Wake up device and enable clock */
pm_runtime_get_sync(pd->dev); pm_runtime_get_sync(pd->dev);
...@@ -662,15 +667,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -662,15 +667,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
if (do_start) if (do_start)
i2c_op(pd, OP_START); i2c_op(pd, OP_START);
/* The interrupt handler takes care of the rest... */ if (pd->atomic_xfer) {
timeout = wait_event_timeout(pd->wait, unsigned long j = jiffies + pd->adap.timeout;
pd->sr & (ICSR_TACK | SW_DONE),
adapter->timeout); time_left = time_before_eq(jiffies, j);
while (time_left &&
/* 'stop_after_dma' tells if DMA transfer was complete */ !(pd->sr & (ICSR_TACK | SW_DONE))) {
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma); unsigned char sr = iic_rd(pd, ICSR);
if (sr & (ICSR_AL | ICSR_TACK |
ICSR_WAIT | ICSR_DTE)) {
sh_mobile_i2c_isr(0, pd);
udelay(150);
} else {
cpu_relax();
}
time_left = time_before_eq(jiffies, j);
}
} else {
/* The interrupt handler takes care of the rest... */
time_left = wait_event_timeout(pd->wait,
pd->sr & (ICSR_TACK | SW_DONE),
pd->adap.timeout);
/* 'stop_after_dma' tells if DMA xfer was complete */
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
pd->stop_after_dma);
}
if (!timeout) { if (!time_left) {
dev_err(pd->dev, "Transfer request timed out\n"); dev_err(pd->dev, "Transfer request timed out\n");
if (pd->dma_direction != DMA_NONE) if (pd->dma_direction != DMA_NONE)
sh_mobile_i2c_cleanup_dma(pd); sh_mobile_i2c_cleanup_dma(pd);
...@@ -696,14 +721,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, ...@@ -696,14 +721,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
return err ?: num; return err ?: num;
} }
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs,
int num)
{
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
pd->atomic_xfer = false;
return sh_mobile_xfer(pd, msgs, num);
}
static int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
struct i2c_msg *msgs,
int num)
{
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
pd->atomic_xfer = true;
return sh_mobile_xfer(pd, msgs, num);
}
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
} }
static const struct i2c_algorithm sh_mobile_i2c_algorithm = { static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
.functionality = sh_mobile_i2c_func, .functionality = sh_mobile_i2c_func,
.master_xfer = sh_mobile_i2c_xfer, .master_xfer = sh_mobile_i2c_xfer,
.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
}; };
static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = { static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
......
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