Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 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>

authored by

Arnd Bergmann and committed by
Andi Shyti
10345887 f2661062

+140 -90
+2 -4
drivers/i2c/busses/Makefile
··· 29 29 obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o 30 30 obj-$(CONFIG_I2C_VIA) += i2c-via.o 31 31 obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o 32 - i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o 33 - obj-$(CONFIG_I2C_ZHAOXIN) += i2c-zhaoxin.o 32 + obj-$(CONFIG_I2C_ZHAOXIN) += i2c-viai2c-zhaoxin.o i2c-viai2c-common.o 34 33 35 34 # Mac SMBus host controller drivers 36 35 obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o ··· 119 120 obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o 120 121 obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o 121 122 obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o 122 - i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o 123 - obj-$(CONFIG_I2C_WMT) += i2c-wmt.o 123 + obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o 124 124 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o 125 125 obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o 126 126 i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
+9 -62
drivers/i2c/busses/i2c-viai2c-common.c
··· 17 17 18 18 return 0; 19 19 } 20 + EXPORT_SYMBOL_GPL(viai2c_wait_bus_not_busy); 20 21 21 22 static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) 22 23 { ··· 122 121 123 122 return (ret < 0) ? ret : i; 124 123 } 124 + EXPORT_SYMBOL_GPL(viai2c_xfer); 125 125 126 126 /* 127 127 * Main process of the byte mode xfer ··· 132 130 * 0: there is still data that needs to be transferred 133 131 * -EIO: error occurred 134 132 */ 135 - static int viai2c_irq_xfer(struct viai2c *i2c) 133 + int viai2c_irq_xfer(struct viai2c *i2c) 136 134 { 137 135 u16 val; 138 136 struct i2c_msg *msg = i2c->msg; ··· 173 171 174 172 return i2c->xfered_len == msg->len; 175 173 } 176 - 177 - int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) 178 - { 179 - return 0; 180 - } 181 - 182 - static irqreturn_t viai2c_isr(int irq, void *data) 183 - { 184 - struct viai2c *i2c = data; 185 - u8 status; 186 - 187 - /* save the status and write-clear it */ 188 - status = readw(i2c->base + VIAI2C_REG_ISR); 189 - if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN) 190 - return IRQ_NONE; 191 - 192 - writew(status, i2c->base + VIAI2C_REG_ISR); 193 - 194 - i2c->ret = 0; 195 - if (status & VIAI2C_ISR_NACK_ADDR) 196 - i2c->ret = -EIO; 197 - 198 - if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT)) 199 - i2c->ret = -ETIMEDOUT; 200 - 201 - if (!i2c->ret) { 202 - if (i2c->mode == VIAI2C_BYTE_MODE) 203 - i2c->ret = viai2c_irq_xfer(i2c); 204 - else 205 - i2c->ret = viai2c_fifo_irq_xfer(i2c, true); 206 - } 207 - 208 - /* All the data has been successfully transferred or error occurred */ 209 - if (i2c->ret) 210 - complete(&i2c->complete); 211 - 212 - return IRQ_HANDLED; 213 - } 174 + EXPORT_SYMBOL_GPL(viai2c_irq_xfer); 214 175 215 176 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) 216 177 { 217 - int err; 218 - int irq_flags; 219 178 struct viai2c *i2c; 220 - struct device_node *np = pdev->dev.of_node; 221 179 222 180 i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); 223 181 if (!i2c) ··· 187 225 if (IS_ERR(i2c->base)) 188 226 return PTR_ERR(i2c->base); 189 227 190 - if (plat == VIAI2C_PLAT_WMT) { 191 - irq_flags = 0; 192 - i2c->irq = irq_of_parse_and_map(np, 0); 193 - if (!i2c->irq) 194 - return -EINVAL; 195 - } else if (plat == VIAI2C_PLAT_ZHAOXIN) { 196 - irq_flags = IRQF_SHARED; 197 - i2c->irq = platform_get_irq(pdev, 0); 198 - if (i2c->irq < 0) 199 - return i2c->irq; 200 - } else { 201 - return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n"); 202 - } 203 - 204 228 i2c->platform = plat; 205 - 206 - err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr, 207 - irq_flags, pdev->name, i2c); 208 - if (err) 209 - return dev_err_probe(&pdev->dev, err, 210 - "failed to request irq %i\n", i2c->irq); 211 229 212 230 i2c->dev = &pdev->dev; 213 231 init_completion(&i2c->complete); ··· 196 254 *pi2c = i2c; 197 255 return 0; 198 256 } 257 + EXPORT_SYMBOL_GPL(viai2c_init); 258 + 259 + MODULE_DESCRIPTION("Via/Wondermedia/Zhaoxin I2C master-mode bus adapter"); 260 + MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); 261 + MODULE_LICENSE("GPL");
+1 -1
drivers/i2c/busses/i2c-viai2c-common.h
··· 80 80 int viai2c_wait_bus_not_busy(struct viai2c *i2c); 81 81 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); 82 82 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat); 83 - int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq); 83 + int viai2c_irq_xfer(struct viai2c *i2c); 84 84 85 85 #endif
+36
drivers/i2c/busses/i2c-viai2c-wmt.c
··· 72 72 return 0; 73 73 } 74 74 75 + static irqreturn_t wmt_i2c_isr(int irq, void *data) 76 + { 77 + struct viai2c *i2c = data; 78 + u8 status; 79 + 80 + /* save the status and write-clear it */ 81 + status = readw(i2c->base + VIAI2C_REG_ISR); 82 + writew(status, i2c->base + VIAI2C_REG_ISR); 83 + 84 + i2c->ret = 0; 85 + if (status & VIAI2C_ISR_NACK_ADDR) 86 + i2c->ret = -EIO; 87 + 88 + if (status & VIAI2C_ISR_SCL_TIMEOUT) 89 + i2c->ret = -ETIMEDOUT; 90 + 91 + if (!i2c->ret) 92 + i2c->ret = viai2c_irq_xfer(i2c); 93 + 94 + /* All the data has been successfully transferred or error occurred */ 95 + if (i2c->ret) 96 + complete(&i2c->complete); 97 + 98 + return IRQ_HANDLED; 99 + } 100 + 75 101 static int wmt_i2c_probe(struct platform_device *pdev) 76 102 { 77 103 struct device_node *np = pdev->dev.of_node; ··· 109 83 err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); 110 84 if (err) 111 85 return err; 86 + 87 + i2c->irq = platform_get_irq(pdev, 0); 88 + if (i2c->irq < 0) 89 + return i2c->irq; 90 + 91 + err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, 92 + 0, pdev->name, i2c); 93 + if (err) 94 + return dev_err_probe(&pdev->dev, err, 95 + "failed to request irq %i\n", i2c->irq); 112 96 113 97 i2c->clk = of_clk_get(np, 0); 114 98 if (IS_ERR(i2c->clk)) {
+92 -23
drivers/i2c/busses/i2c-viai2c-zhaoxin.c
··· 49 49 u16 xfer_len; 50 50 }; 51 51 52 - /* 'irq == true' means in interrupt context */ 53 - int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) 52 + static int viai2c_fifo_xfer(struct viai2c *i2c) 54 53 { 55 54 u16 i; 56 55 u8 tmp; ··· 57 58 void __iomem *base = i2c->base; 58 59 bool read = !!(msg->flags & I2C_M_RD); 59 60 struct viai2c_zhaoxin *priv = i2c->pltfm_priv; 60 - 61 - if (irq) { 62 - /* get the received data */ 63 - if (read) 64 - for (i = 0; i < priv->xfer_len; i++) 65 - msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR); 66 - 67 - i2c->xfered_len += priv->xfer_len; 68 - if (i2c->xfered_len == msg->len) 69 - return 1; 70 - } 71 61 72 62 /* reset fifo buffer */ 73 63 tmp = ioread8(base + ZXI2C_REG_HCR); ··· 80 92 iowrite8(tmp, base + VIAI2C_REG_CR); 81 93 } 82 94 83 - if (irq) { 84 - /* continue transmission */ 85 - tmp = ioread8(base + VIAI2C_REG_CR); 86 - iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR); 87 - } else { 88 - u16 tcr_val = i2c->tcr; 95 + u16 tcr_val = i2c->tcr; 89 96 90 - /* start transmission */ 91 - tcr_val |= read ? VIAI2C_TCR_READ : 0; 92 - writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR); 97 + /* start transmission */ 98 + tcr_val |= read ? VIAI2C_TCR_READ : 0; 99 + writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR); 100 + 101 + return 0; 102 + } 103 + 104 + static int viai2c_fifo_irq_xfer(struct viai2c *i2c) 105 + { 106 + u16 i; 107 + u8 tmp; 108 + struct i2c_msg *msg = i2c->msg; 109 + void __iomem *base = i2c->base; 110 + bool read = !!(msg->flags & I2C_M_RD); 111 + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; 112 + 113 + /* get the received data */ 114 + if (read) 115 + for (i = 0; i < priv->xfer_len; i++) 116 + msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR); 117 + 118 + i2c->xfered_len += priv->xfer_len; 119 + if (i2c->xfered_len == msg->len) 120 + return 1; 121 + 122 + /* reset fifo buffer */ 123 + tmp = ioread8(base + ZXI2C_REG_HCR); 124 + iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR); 125 + 126 + /* set xfer len */ 127 + priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE); 128 + if (read) { 129 + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR); 130 + } else { 131 + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR); 132 + /* set write data */ 133 + for (i = 0; i < priv->xfer_len; i++) 134 + iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR); 93 135 } 136 + 137 + /* prepare to stop transmission */ 138 + if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) { 139 + tmp = ioread8(base + VIAI2C_REG_CR); 140 + tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END; 141 + iowrite8(tmp, base + VIAI2C_REG_CR); 142 + } 143 + 144 + /* continue transmission */ 145 + tmp = ioread8(base + VIAI2C_REG_CR); 146 + iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR); 94 147 95 148 return 0; 96 149 } ··· 164 135 priv->xfer_len = 0; 165 136 i2c->xfered_len = 0; 166 137 167 - viai2c_fifo_irq_xfer(i2c, 0); 138 + viai2c_fifo_xfer(i2c); 168 139 169 140 if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) 170 141 return -ETIMEDOUT; ··· 257 228 dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0])); 258 229 } 259 230 231 + static irqreturn_t zxi2c_isr(int irq, void *data) 232 + { 233 + struct viai2c *i2c = data; 234 + u8 status; 235 + 236 + /* save the status and write-clear it */ 237 + status = readw(i2c->base + VIAI2C_REG_ISR); 238 + if (!status) 239 + return IRQ_NONE; 240 + 241 + writew(status, i2c->base + VIAI2C_REG_ISR); 242 + 243 + i2c->ret = 0; 244 + if (status & VIAI2C_ISR_NACK_ADDR) 245 + i2c->ret = -EIO; 246 + 247 + if (!i2c->ret) { 248 + if (i2c->mode == VIAI2C_BYTE_MODE) 249 + i2c->ret = viai2c_irq_xfer(i2c); 250 + else 251 + i2c->ret = viai2c_fifo_irq_xfer(i2c); 252 + } 253 + 254 + /* All the data has been successfully transferred or error occurred */ 255 + if (i2c->ret) 256 + complete(&i2c->complete); 257 + 258 + return IRQ_HANDLED; 259 + } 260 + 260 261 static int zxi2c_probe(struct platform_device *pdev) 261 262 { 262 263 int error; ··· 297 238 error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN); 298 239 if (error) 299 240 return error; 241 + 242 + i2c->irq = platform_get_irq(pdev, 0); 243 + if (i2c->irq < 0) 244 + return i2c->irq; 245 + 246 + error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr, 247 + IRQF_SHARED, pdev->name, i2c); 248 + if (error) 249 + return dev_err_probe(&pdev->dev, error, 250 + "failed to request irq %i\n", i2c->irq); 300 251 301 252 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 302 253 if (!priv)