Commit 10345887 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Andi Shyti

i2c: viai2c: turn common code into a proper module

The i2c-viai2c-common.c file is used by two drivers, but is not a proper
abstraction and can get linked into both modules in the same configuration,
which results in a warning:

scripts/Makefile.build:236: drivers/i2c/busses/Makefile: i2c-viai2c-common.o is added to multiple modules: i2c-wmt i2c-zhaoxin

The other problems with this include the incorrect use of a __weak function
when both are built-in, and the fact that the "common" module is sprinked
with 'if (i2c->plat == ...)' checks that have knowledge about the differences
between the drivers using it.

Avoid the link time warning by making the common driver a proper module
with MODULE_LICENCE()/MODULE_AUTHOR() tags, and remove the __weak function
by slightly rearranging the code.

This adds a little more duplication between the two main drivers, but
those versions get more readable in the process.

Fixes: a06b80e8 ("i2c: add zhaoxin i2c controller driver")
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Tested-by: default avatarHans Hu <HansHu-oc@zhaoxin.com>
Signed-off-by: default avatarAndi Shyti <andi.shyti@kernel.org>
parent f2661062
...@@ -29,8 +29,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o ...@@ -29,8 +29,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIA) += i2c-via.o
obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o obj-$(CONFIG_I2C_ZHAOXIN) += i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o
# Mac SMBus host controller drivers # Mac SMBus host controller drivers
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
...@@ -120,8 +119,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.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) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.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) ...@@ -17,6 +17,7 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(viai2c_wait_bus_not_busy);
static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) 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) ...@@ -121,6 +122,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return (ret < 0) ? ret : i; return (ret < 0) ? ret : i;
} }
EXPORT_SYMBOL_GPL(viai2c_xfer);
/* /*
* Main process of the byte mode 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) ...@@ -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 * 0: there is still data that needs to be transferred
* -EIO: error occurred * -EIO: error occurred
*/ */
static int viai2c_irq_xfer(struct viai2c *i2c) int viai2c_irq_xfer(struct viai2c *i2c)
{ {
u16 val; u16 val;
struct i2c_msg *msg = i2c->msg; struct i2c_msg *msg = i2c->msg;
...@@ -171,51 +173,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c) ...@@ -171,51 +173,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
return i2c->xfered_len == msg->len; return i2c->xfered_len == msg->len;
} }
EXPORT_SYMBOL_GPL(viai2c_irq_xfer);
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;
}
int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
{ {
int err;
int irq_flags;
struct viai2c *i2c; struct viai2c *i2c;
struct device_node *np = pdev->dev.of_node;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c) if (!i2c)
...@@ -225,28 +187,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) ...@@ -225,28 +187,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
if (IS_ERR(i2c->base)) if (IS_ERR(i2c->base))
return PTR_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; 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; i2c->dev = &pdev->dev;
init_completion(&i2c->complete); init_completion(&i2c->complete);
platform_set_drvdata(pdev, i2c); platform_set_drvdata(pdev, i2c);
...@@ -254,3 +196,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) ...@@ -254,3 +196,8 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
*pi2c = i2c; *pi2c = i2c;
return 0; 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 { ...@@ -80,6 +80,6 @@ struct viai2c {
int viai2c_wait_bus_not_busy(struct viai2c *i2c); int viai2c_wait_bus_not_busy(struct viai2c *i2c);
int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); 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_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 #endif
...@@ -72,6 +72,32 @@ static int wmt_i2c_reset_hardware(struct viai2c *i2c) ...@@ -72,6 +72,32 @@ static int wmt_i2c_reset_hardware(struct viai2c *i2c)
return 0; 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) static int wmt_i2c_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -84,6 +110,16 @@ static int wmt_i2c_probe(struct platform_device *pdev) ...@@ -84,6 +110,16 @@ static int wmt_i2c_probe(struct platform_device *pdev)
if (err) if (err)
return 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); i2c->clk = of_clk_get(np, 0);
if (IS_ERR(i2c->clk)) { if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "unable to request clock\n"); dev_err(&pdev->dev, "unable to request clock\n");
......
...@@ -49,8 +49,7 @@ struct viai2c_zhaoxin { ...@@ -49,8 +49,7 @@ struct viai2c_zhaoxin {
u16 xfer_len; u16 xfer_len;
}; };
/* 'irq == true' means in interrupt context */ static int viai2c_fifo_xfer(struct viai2c *i2c)
int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
{ {
u16 i; u16 i;
u8 tmp; u8 tmp;
...@@ -59,17 +58,6 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) ...@@ -59,17 +58,6 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
bool read = !!(msg->flags & I2C_M_RD); bool read = !!(msg->flags & I2C_M_RD);
struct viai2c_zhaoxin *priv = i2c->pltfm_priv; struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
if (irq) {
/* get the received data */
if (read)
for (i = 0; i < priv->xfer_len; i++)
msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
i2c->xfered_len += priv->xfer_len;
if (i2c->xfered_len == msg->len)
return 1;
}
/* reset fifo buffer */ /* reset fifo buffer */
tmp = ioread8(base + ZXI2C_REG_HCR); tmp = ioread8(base + ZXI2C_REG_HCR);
iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR); iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
...@@ -92,18 +80,59 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) ...@@ -92,18 +80,59 @@ int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
iowrite8(tmp, base + VIAI2C_REG_CR); iowrite8(tmp, base + VIAI2C_REG_CR);
} }
if (irq) { u16 tcr_val = i2c->tcr;
/* continue transmission */
tmp = ioread8(base + VIAI2C_REG_CR); /* start transmission */
iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR); 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;
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;
/* get the received data */
if (read)
for (i = 0; i < priv->xfer_len; i++)
msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
i2c->xfered_len += priv->xfer_len;
if (i2c->xfered_len == msg->len)
return 1;
/* 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 { } else {
u16 tcr_val = i2c->tcr; 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);
}
/* start transmission */ /* prepare to stop transmission */
tcr_val |= read ? VIAI2C_TCR_READ : 0; if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR); tmp = ioread8(base + VIAI2C_REG_CR);
tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
iowrite8(tmp, base + VIAI2C_REG_CR);
} }
/* continue transmission */
tmp = ioread8(base + VIAI2C_REG_CR);
iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
return 0; return 0;
} }
...@@ -135,7 +164,7 @@ static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int ...@@ -135,7 +164,7 @@ static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int
priv->xfer_len = 0; priv->xfer_len = 0;
i2c->xfered_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)) if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -228,6 +257,36 @@ static void zxi2c_get_bus_speed(struct viai2c *i2c) ...@@ -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])); 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) static int zxi2c_probe(struct platform_device *pdev)
{ {
int error; int error;
...@@ -239,6 +298,16 @@ static int zxi2c_probe(struct platform_device *pdev) ...@@ -239,6 +298,16 @@ static int zxi2c_probe(struct platform_device *pdev)
if (error) if (error)
return 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); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
return -ENOMEM; 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