Commit 4e9a1a47 authored by Wolfram Sang's avatar Wolfram Sang

Merge tag 'i2c-host-fixes-6.10-rc6' of...

Merge tag 'i2c-host-fixes-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-current

Fixed a build error following the major refactoring involving the
VIA-I2C modules. Originally, the code was split to group together
parts that would be used by different drivers. This caused build
issues when two modules linked to the same code.
parents f2661062 10345887
......@@ -29,8 +29,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o
obj-$(CONFIG_I2C_ZHAOXIN) += i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
# Mac SMBus host controller drivers
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
......@@ -120,8 +119,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o
obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o
i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
......
......@@ -17,6 +17,7 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c)
return 0;
}
EXPORT_SYMBOL_GPL(viai2c_wait_bus_not_busy);
static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
{
......@@ -121,6 +122,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return (ret < 0) ? ret : i;
}
EXPORT_SYMBOL_GPL(viai2c_xfer);
/*
* Main process of the byte mode xfer
......@@ -130,7 +132,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
* 0: there is still data that needs to be transferred
* -EIO: error occurred
*/
static int viai2c_irq_xfer(struct viai2c *i2c)
int viai2c_irq_xfer(struct viai2c *i2c)
{
u16 val;
struct i2c_msg *msg = i2c->msg;
......@@ -171,51 +173,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
return i2c->xfered_len == msg->len;
}
int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
{
return 0;
}
static irqreturn_t viai2c_isr(int irq, void *data)
{
struct viai2c *i2c = data;
u8 status;
/* save the status and write-clear it */
status = readw(i2c->base + VIAI2C_REG_ISR);
if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
return IRQ_NONE;
writew(status, i2c->base + VIAI2C_REG_ISR);
i2c->ret = 0;
if (status & VIAI2C_ISR_NACK_ADDR)
i2c->ret = -EIO;
if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
i2c->ret = -ETIMEDOUT;
if (!i2c->ret) {
if (i2c->mode == VIAI2C_BYTE_MODE)
i2c->ret = viai2c_irq_xfer(i2c);
else
i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
}
/* All the data has been successfully transferred or error occurred */
if (i2c->ret)
complete(&i2c->complete);
return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(viai2c_irq_xfer);
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
{
int err;
int irq_flags;
struct viai2c *i2c;
struct device_node *np = pdev->dev.of_node;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
......@@ -225,28 +187,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
if (plat == VIAI2C_PLAT_WMT) {
irq_flags = 0;
i2c->irq = irq_of_parse_and_map(np, 0);
if (!i2c->irq)
return -EINVAL;
} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
irq_flags = IRQF_SHARED;
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0)
return i2c->irq;
} else {
return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
}
i2c->platform = plat;
err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
irq_flags, pdev->name, i2c);
if (err)
return dev_err_probe(&pdev->dev, err,
"failed to request irq %i\n", i2c->irq);
i2c->dev = &pdev->dev;
init_completion(&i2c->complete);
platform_set_drvdata(pdev, i2c);
......@@ -254,3 +196,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
*pi2c = i2c;
return 0;
}
EXPORT_SYMBOL_GPL(viai2c_init);
MODULE_DESCRIPTION("Via/Wondermedia/Zhaoxin I2C master-mode bus adapter");
MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
MODULE_LICENSE("GPL");
......@@ -80,6 +80,6 @@ struct viai2c {
int viai2c_wait_bus_not_busy(struct viai2c *i2c);
int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
int viai2c_irq_xfer(struct viai2c *i2c);
#endif
......@@ -72,6 +72,32 @@ static int wmt_i2c_reset_hardware(struct viai2c *i2c)
return 0;
}
static irqreturn_t wmt_i2c_isr(int irq, void *data)
{
struct viai2c *i2c = data;
u8 status;
/* save the status and write-clear it */
status = readw(i2c->base + VIAI2C_REG_ISR);
writew(status, i2c->base + VIAI2C_REG_ISR);
i2c->ret = 0;
if (status & VIAI2C_ISR_NACK_ADDR)
i2c->ret = -EIO;
if (status & VIAI2C_ISR_SCL_TIMEOUT)
i2c->ret = -ETIMEDOUT;
if (!i2c->ret)
i2c->ret = viai2c_irq_xfer(i2c);
/* All the data has been successfully transferred or error occurred */
if (i2c->ret)
complete(&i2c->complete);
return IRQ_HANDLED;
}
static int wmt_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
......@@ -84,6 +110,16 @@ static int wmt_i2c_probe(struct platform_device *pdev)
if (err)
return err;
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0)
return i2c->irq;
err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
0, pdev->name, i2c);
if (err)
return dev_err_probe(&pdev->dev, err,
"failed to request irq %i\n", i2c->irq);
i2c->clk = of_clk_get(np, 0);
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "unable to request clock\n");
......
......@@ -49,8 +49,47 @@ struct viai2c_zhaoxin {
u16 xfer_len;
};
/* 'irq == true' means in interrupt context */
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
static int viai2c_fifo_xfer(struct viai2c *i2c)
{
u16 i;
u8 tmp;
struct i2c_msg *msg = i2c->msg;
void __iomem *base = i2c->base;
bool read = !!(msg->flags & I2C_M_RD);
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
/* reset fifo buffer */
tmp = ioread8(base + ZXI2C_REG_HCR);
iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
/* set xfer len */
priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE);
if (read) {
iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR);
} else {
iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR);
/* set write data */
for (i = 0; i < priv->xfer_len; i++)
iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR);
}
/* prepare to stop transmission */
if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
tmp = ioread8(base + VIAI2C_REG_CR);
tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
iowrite8(tmp, base + VIAI2C_REG_CR);
}
u16 tcr_val = i2c->tcr;
/* start transmission */
tcr_val |= read ? VIAI2C_TCR_READ : 0;
writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
return 0;
}
static int viai2c_fifo_irq_xfer(struct viai2c *i2c)
{
u16 i;
u8 tmp;
......@@ -59,7 +98,6 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
bool read = !!(msg->flags & I2C_M_RD);
struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
if (irq) {
/* get the received data */
if (read)
for (i = 0; i < priv->xfer_len; i++)
......@@ -68,7 +106,6 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
i2c->xfered_len += priv->xfer_len;
if (i2c->xfered_len == msg->len)
return 1;
}
/* reset fifo buffer */
tmp = ioread8(base + ZXI2C_REG_HCR);
......@@ -92,17 +129,9 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
iowrite8(tmp, base + VIAI2C_REG_CR);
}
if (irq) {
/* continue transmission */
tmp = ioread8(base + VIAI2C_REG_CR);
iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
} else {
u16 tcr_val = i2c->tcr;
/* start transmission */
tcr_val |= read ? VIAI2C_TCR_READ : 0;
writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
}
return 0;
}
......@@ -135,7 +164,7 @@ static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int
priv->xfer_len = 0;
i2c->xfered_len = 0;
viai2c_fifo_irq_xfer(i2c, 0);
viai2c_fifo_xfer(i2c);
if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
return -ETIMEDOUT;
......@@ -228,6 +257,36 @@ static void zxi2c_get_bus_speed(struct viai2c *i2c)
dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
}
static irqreturn_t zxi2c_isr(int irq, void *data)
{
struct viai2c *i2c = data;
u8 status;
/* save the status and write-clear it */
status = readw(i2c->base + VIAI2C_REG_ISR);
if (!status)
return IRQ_NONE;
writew(status, i2c->base + VIAI2C_REG_ISR);
i2c->ret = 0;
if (status & VIAI2C_ISR_NACK_ADDR)
i2c->ret = -EIO;
if (!i2c->ret) {
if (i2c->mode == VIAI2C_BYTE_MODE)
i2c->ret = viai2c_irq_xfer(i2c);
else
i2c->ret = viai2c_fifo_irq_xfer(i2c);
}
/* All the data has been successfully transferred or error occurred */
if (i2c->ret)
complete(&i2c->complete);
return IRQ_HANDLED;
}
static int zxi2c_probe(struct platform_device *pdev)
{
int error;
......@@ -239,6 +298,16 @@ static int zxi2c_probe(struct platform_device *pdev)
if (error)
return error;
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0)
return i2c->irq;
error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr,
IRQF_SHARED, pdev->name, i2c);
if (error)
return dev_err_probe(&pdev->dev, error,
"failed to request irq %i\n", i2c->irq);
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......
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