]> www.infradead.org Git - nvme.git/commitdiff
i2c: viai2c: turn common code into a proper module
authorArnd Bergmann <arnd@arndb.de>
Tue, 28 May 2024 12:06:30 +0000 (14:06 +0200)
committerAndi Shyti <andi.shyti@kernel.org>
Wed, 26 Jun 2024 14:07:21 +0000 (16:07 +0200)
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: a06b80e83011 ("i2c: add zhaoxin i2c controller driver")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Tested-by: Hans Hu <HansHu-oc@zhaoxin.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-viai2c-common.c
drivers/i2c/busses/i2c-viai2c-common.h
drivers/i2c/busses/i2c-viai2c-wmt.c
drivers/i2c/busses/i2c-viai2c-zhaoxin.c

index 3d65934f5eb4863f59ef2979850c5554395cc955..78d0561339e5beadcb810196be1139a4248469b4 100644 (file)
@@ -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
index 1844d13f1f79866fbe81d7960d7c13c816868966..162b31306cba8db2a4cb45cf1ba8b186c723f62e 100644 (file)
@@ -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");
index 81e827c544347d7b27003829388fec56f014c3fa..00f17733223c57eb92828a3806c23f6c3f589e8a 100644 (file)
@@ -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
index e1988f94602662119579fc63b4ded97eacaa2763..420fd10fe3aa5512c8fc5cedf2bd96a8f9f01360 100644 (file)
@@ -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");
index 7e3ac2a3e1fd73928b2beb1097406639faf7a01e..ab3e44e147e91a4190e4cc2c04f127525a2fd433 100644 (file)
@@ -49,8 +49,7 @@ 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;
@@ -59,17 +58,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++)
-                               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);
@@ -92,18 +80,59 @@ 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);
+       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;
+       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 {
-               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 */
-               tcr_val |= read ? VIAI2C_TCR_READ : 0;
-               writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+       /* 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);
        }
 
+       /* continue transmission */
+       tmp = ioread8(base + VIAI2C_REG_CR);
+       iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
+
        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;