From 51c87f0e6cca2b9762d10dfab52618318444d746 Mon Sep 17 00:00:00 2001 From: Animesh Agarwal Date: Wed, 20 Mar 2024 14:16:20 +0530 Subject: dt-bindings: i2c: nxp,pnx-i2c: Convert to dtschema Convert the NXP PNX I2C Controller bindings to DT schema. Keep only one example in DT schema to remove redundancy. Reviewed-by: Conor Dooley Signed-off-by: Animesh Agarwal Signed-off-by: Andi Shyti --- Documentation/devicetree/bindings/i2c/i2c-pnx.txt | 34 ---------------- .../devicetree/bindings/i2c/nxp,pnx-i2c.yaml | 46 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 34 deletions(-) delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-pnx.txt create mode 100644 Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml diff --git a/Documentation/devicetree/bindings/i2c/i2c-pnx.txt b/Documentation/devicetree/bindings/i2c/i2c-pnx.txt deleted file mode 100644 index 2a59006cf79e..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-pnx.txt +++ /dev/null @@ -1,34 +0,0 @@ -* NXP PNX I2C Controller - -Required properties: - - - reg: Offset and length of the register set for the device - - compatible: should be "nxp,pnx-i2c" - - interrupts: configure one interrupt line - - #address-cells: always 1 (for i2c addresses) - - #size-cells: always 0 - -Optional properties: - - - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz - -Examples: - - i2c1: i2c@400a0000 { - compatible = "nxp,pnx-i2c"; - reg = <0x400a0000 0x100>; - interrupt-parent = <&mic>; - interrupts = <51 0>; - #address-cells = <1>; - #size-cells = <0>; - }; - - i2c2: i2c@400a8000 { - compatible = "nxp,pnx-i2c"; - reg = <0x400a8000 0x100>; - interrupt-parent = <&mic>; - interrupts = <50 0>; - #address-cells = <1>; - #size-cells = <0>; - clock-frequency = <100000>; - }; diff --git a/Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml b/Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml new file mode 100644 index 000000000000..798a6939b894 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/nxp,pnx-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PNX I2C Controller + +maintainers: + - Animesh Agarwal + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + const: nxp,pnx-i2c + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clock-frequency: + default: 100000 + +required: + - compatible + - reg + - interrupts + - "#address-cells" + - "#size-cells" + +unevaluatedProperties: false + +examples: + - | + i2c@400a0000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a0000 0x100>; + interrupt-parent = <&mic>; + interrupts = <51 0>; + #address-cells = <1>; + #size-cells = <0>; + }; -- cgit v1.2.3 From c1f39c62eb09fa2e692a9377295ecbd0740c0914 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 Mar 2024 13:25:00 +0000 Subject: dt-bindings: i2c: renesas,riic: Document R9A09G057 support Document support for the I2C Bus Interface (RIIC) available in the Renesas RZ/V2H(P) (R9A09G057) SoC. The RIIC interface in the Renesas RZ/V2H(P) differs from RZ/A in a couple of ways: - Register offsets for the RZ/V2H(P) SoC differ from those of the RZ/A SoC. - RZ/V2H register access is limited to 8-bit, whereas RZ/A supports 8/16/32-bit. - RZ/V2H has bit differences in the slave address register. To accommodate these differences, a new compatible string "renesas,riic-r9a09g057" is added. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Acked-by: Rob Herring Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- .../devicetree/bindings/i2c/renesas,riic.yaml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/renesas,riic.yaml b/Documentation/devicetree/bindings/i2c/renesas,riic.yaml index 2291a7cd619b..91ecf17b7a81 100644 --- a/Documentation/devicetree/bindings/i2c/renesas,riic.yaml +++ b/Documentation/devicetree/bindings/i2c/renesas,riic.yaml @@ -15,14 +15,17 @@ allOf: properties: compatible: - items: - - enum: - - renesas,riic-r7s72100 # RZ/A1H - - renesas,riic-r7s9210 # RZ/A2M - - renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five - - renesas,riic-r9a07g044 # RZ/G2{L,LC} - - renesas,riic-r9a07g054 # RZ/V2L - - const: renesas,riic-rz # RZ/A or RZ/G2L + oneOf: + - items: + - enum: + - renesas,riic-r7s72100 # RZ/A1H + - renesas,riic-r7s9210 # RZ/A2M + - renesas,riic-r9a07g043 # RZ/G2UL and RZ/Five + - renesas,riic-r9a07g044 # RZ/G2{L,LC} + - renesas,riic-r9a07g054 # RZ/V2L + - const: renesas,riic-rz # RZ/A or RZ/G2L + + - const: renesas,riic-r9a09g057 # RZ/V2H(P) reg: maxItems: 1 -- cgit v1.2.3 From 26c7871100f2933a2827b217320366e89cef5a4c Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 Mar 2024 13:25:01 +0000 Subject: i2c: riic: Introduce helper functions for I2C read/write operations Introduce helper functions for performing I2C read and write operations in the RIIC driver. These helper functions lay the groundwork for adding support for the RZ/V2H SoC. This is essential because the register offsets for the RZ/V2H SoC differ from those of the RZ/A SoC. By abstracting the read and write operations, we can seamlessly adapt the driver to support different SoC variants without extensive modifications. This patch is part of the preparation process for integrating support for the RZ/V2H SoC into the RIIC driver. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-riic.c | 56 +++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index e43ff483c56e..ef35e67839fa 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -105,9 +105,19 @@ struct riic_irq_desc { char *name; }; +static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset) +{ + writeb(val, riic->base + offset); +} + +static inline u8 riic_readb(struct riic_dev *riic, u8 offset) +{ + return readb(riic->base + offset); +} + static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg) { - writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg); + riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); } static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -119,7 +129,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) pm_runtime_get_sync(adap->dev.parent); - if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) { + if (riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) { riic->err = -EBUSY; goto out; } @@ -127,7 +137,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) reinit_completion(&riic->msg_done); riic->err = 0; - writeb(0, riic->base + RIIC_ICSR2); + riic_writeb(riic, 0, RIIC_ICSR2); for (i = 0, start_bit = ICCR2_ST; i < num; i++) { riic->bytes_left = RIIC_INIT_MSG; @@ -135,9 +145,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) riic->msg = &msgs[i]; riic->is_last = (i == num - 1); - writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER); + riic_writeb(riic, ICIER_NAKIE | ICIER_TIE, RIIC_ICIER); - writeb(start_bit, riic->base + RIIC_ICCR2); + riic_writeb(riic, start_bit, RIIC_ICCR2); time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout); if (time_left == 0) @@ -191,7 +201,7 @@ static irqreturn_t riic_tdre_isr(int irq, void *data) * value could be moved to the shadow shift register right away. So * this must be after updates to ICIER (where we want to disable TIE)! */ - writeb(val, riic->base + RIIC_ICDRT); + riic_writeb(riic, val, RIIC_ICDRT); return IRQ_HANDLED; } @@ -200,9 +210,9 @@ static irqreturn_t riic_tend_isr(int irq, void *data) { struct riic_dev *riic = data; - if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) { + if (riic_readb(riic, RIIC_ICSR2) & ICSR2_NACKF) { /* We got a NACKIE */ - readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic_readb(riic, RIIC_ICDRR); /* dummy read */ riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2); riic->err = -ENXIO; } else if (riic->bytes_left) { @@ -211,7 +221,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data) if (riic->is_last || riic->err) { riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER); - writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + riic_writeb(riic, ICCR2_SP, RIIC_ICCR2); } else { /* Transfer is complete, but do not send STOP */ riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER); @@ -230,7 +240,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) if (riic->bytes_left == RIIC_INIT_MSG) { riic->bytes_left = riic->msg->len; - readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic_readb(riic, RIIC_ICDRR); /* dummy read */ return IRQ_HANDLED; } @@ -238,7 +248,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) /* STOP must come before we set ACKBT! */ if (riic->is_last) { riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER); - writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + riic_writeb(riic, ICCR2_SP, RIIC_ICCR2); } riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3); @@ -248,7 +258,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) } /* Reading acks the RIE interrupt */ - *riic->buf = readb(riic->base + RIIC_ICDRR); + *riic->buf = riic_readb(riic, RIIC_ICDRR); riic->buf++; riic->bytes_left--; @@ -260,10 +270,10 @@ static irqreturn_t riic_stop_isr(int irq, void *data) struct riic_dev *riic = data; /* read back registers to confirm writes have fully propagated */ - writeb(0, riic->base + RIIC_ICSR2); - readb(riic->base + RIIC_ICSR2); - writeb(0, riic->base + RIIC_ICIER); - readb(riic->base + RIIC_ICIER); + riic_writeb(riic, 0, RIIC_ICSR2); + riic_readb(riic, RIIC_ICSR2); + riic_writeb(riic, 0, RIIC_ICIER); + riic_readb(riic, RIIC_ICIER); complete(&riic->msg_done); @@ -365,15 +375,15 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) t->scl_rise_ns / (1000000000 / rate), cks, brl, brh); /* Changing the order of accessing IICRST and ICE may break things! */ - writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); + riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1); riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); - writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1); - writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH); - writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL); + riic_writeb(riic, ICMR1_CKS(cks), RIIC_ICMR1); + riic_writeb(riic, brh | ICBR_RESERVED, RIIC_ICBRH); + riic_writeb(riic, brl | ICBR_RESERVED, RIIC_ICBRL); - writeb(0, riic->base + RIIC_ICSER); - writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); + riic_writeb(riic, 0, RIIC_ICSER); + riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, RIIC_ICMR3); riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1); @@ -481,7 +491,7 @@ static void riic_i2c_remove(struct platform_device *pdev) struct riic_dev *riic = platform_get_drvdata(pdev); pm_runtime_get_sync(&pdev->dev); - writeb(0, riic->base + RIIC_ICIER); + riic_writeb(riic, 0, RIIC_ICIER); pm_runtime_put(&pdev->dev); i2c_del_adapter(&riic->adapter); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From 748ee3b2a477821957adfe0ee7d1fd11d0f9a512 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 Mar 2024 13:25:02 +0000 Subject: i2c: riic: Pass register offsets and chip details as OF data With an increasing number of SoCs reusing this driver, each with slight variations in the RIIC IP, it becomes necessary to support passing these details as OF data. This approach simplifies the extension of the driver for other SoCs. This patch lays the groundwork for adding support for the Renesas RZ/V2H SoC. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-riic.c | 56 +++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index ef35e67839fa..3cd5033286ca 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -46,18 +46,6 @@ #include #include -#define RIIC_ICCR1 0x00 -#define RIIC_ICCR2 0x04 -#define RIIC_ICMR1 0x08 -#define RIIC_ICMR3 0x10 -#define RIIC_ICSER 0x18 -#define RIIC_ICIER 0x1c -#define RIIC_ICSR2 0x24 -#define RIIC_ICBRL 0x34 -#define RIIC_ICBRH 0x38 -#define RIIC_ICDRT 0x3c -#define RIIC_ICDRR 0x40 - #define ICCR1_ICE 0x80 #define ICCR1_IICRST 0x40 #define ICCR1_SOWP 0x10 @@ -87,6 +75,25 @@ #define RIIC_INIT_MSG -1 +enum riic_reg_list { + RIIC_ICCR1 = 0, + RIIC_ICCR2, + RIIC_ICMR1, + RIIC_ICMR3, + RIIC_ICSER, + RIIC_ICIER, + RIIC_ICSR2, + RIIC_ICBRL, + RIIC_ICBRH, + RIIC_ICDRT, + RIIC_ICDRR, + RIIC_REG_END, +}; + +struct riic_of_data { + u8 regs[RIIC_REG_END]; +}; + struct riic_dev { void __iomem *base; u8 *buf; @@ -94,6 +101,7 @@ struct riic_dev { int bytes_left; int err; int is_last; + const struct riic_of_data *info; struct completion msg_done; struct i2c_adapter adapter; struct clk *clk; @@ -107,12 +115,12 @@ struct riic_irq_desc { static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset) { - writeb(val, riic->base + offset); + writeb(val, riic->base + riic->info->regs[offset]); } static inline u8 riic_readb(struct riic_dev *riic, u8 offset) { - return readb(riic->base + offset); + return readb(riic->base + riic->info->regs[offset]); } static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg) @@ -453,6 +461,8 @@ static int riic_i2c_probe(struct platform_device *pdev) } } + riic->info = of_device_get_match_data(&pdev->dev); + adap = &riic->adapter; i2c_set_adapdata(adap, riic); strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name)); @@ -497,8 +507,24 @@ static void riic_i2c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } +static const struct riic_of_data riic_rz_a_info = { + .regs = { + [RIIC_ICCR1] = 0x00, + [RIIC_ICCR2] = 0x04, + [RIIC_ICMR1] = 0x08, + [RIIC_ICMR3] = 0x10, + [RIIC_ICSER] = 0x18, + [RIIC_ICIER] = 0x1c, + [RIIC_ICSR2] = 0x24, + [RIIC_ICBRL] = 0x34, + [RIIC_ICBRH] = 0x38, + [RIIC_ICDRT] = 0x3c, + [RIIC_ICDRR] = 0x40, + }, +}; + static const struct of_device_id riic_i2c_dt_ids[] = { - { .compatible = "renesas,riic-rz", }, + { .compatible = "renesas,riic-rz", .data = &riic_rz_a_info }, { /* Sentinel */ }, }; -- cgit v1.2.3 From a45f95d7480544fdaa9d566cb4956d0ca5d0dc33 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Tue, 19 Mar 2024 13:25:03 +0000 Subject: i2c: riic: Add support for R9A09G057 SoC Extend the RIIC driver to support the RZ/V2H(P) ("R9A09G057") SoC. It accomplishes this by appending the compatible string list and passing the RZ/V2H-specific OF data. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-riic.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 3cd5033286ca..f608b1838cad 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -523,8 +523,25 @@ static const struct riic_of_data riic_rz_a_info = { }, }; +static const struct riic_of_data riic_rz_v2h_info = { + .regs = { + [RIIC_ICCR1] = 0x00, + [RIIC_ICCR2] = 0x01, + [RIIC_ICMR1] = 0x02, + [RIIC_ICMR3] = 0x04, + [RIIC_ICSER] = 0x06, + [RIIC_ICIER] = 0x07, + [RIIC_ICSR2] = 0x09, + [RIIC_ICBRL] = 0x10, + [RIIC_ICBRH] = 0x11, + [RIIC_ICDRT] = 0x12, + [RIIC_ICDRR] = 0x13, + }, +}; + static const struct of_device_id riic_i2c_dt_ids[] = { { .compatible = "renesas,riic-rz", .data = &riic_rz_a_info }, + { .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info }, { /* Sentinel */ }, }; -- cgit v1.2.3 From 5bffbda7ad5465605d12ed7432dc844cfff625c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Mar 2024 18:47:05 +0100 Subject: i2c: viperboard: drop driver owner assignment Core in platform_driver_register() already sets the .owner, so driver does not need to. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-viperboard.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 9e153b5b0e8e..3784b07f5371 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -416,7 +416,6 @@ static void vprbrd_i2c_remove(struct platform_device *pdev) static struct platform_driver vprbrd_i2c_driver = { .driver.name = "viperboard-i2c", - .driver.owner = THIS_MODULE, .probe = vprbrd_i2c_probe, .remove_new = vprbrd_i2c_remove, }; -- cgit v1.2.3 From 893fef0bc6aaedd482b7592d18d9b17682c1f94a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 26 Mar 2024 21:42:44 +0100 Subject: i2c: i801: Call i2c_register_spd for muxed child segments Once the gpio mux driver binds to the "i2c-mux-gpio" platform device, this creates the i2c adapters for the muxed child segments. We can use the bus notifier mechanism to check for creation of the child i2c adapters, and call i2c_register_spd() for them. This allows to detect all DIMM's on systems with more than 8 memory slots. Reviewed-by: Wolfram Sang Signed-off-by: Heiner Kallweit Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-i801.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 79870dd7a014..4294c0c63cef 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include #include @@ -291,6 +292,7 @@ struct i801_priv { #if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI struct platform_device *mux_pdev; struct gpiod_lookup_table *lookup; + struct notifier_block mux_notifier_block; #endif struct platform_device *tco_pdev; @@ -1394,6 +1396,23 @@ static const struct dmi_system_id mux_dmi_table[] = { { } }; +static int i801_notifier_call(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct i801_priv *priv = container_of(nb, struct i801_priv, mux_notifier_block); + struct device *dev = data; + + if (action != BUS_NOTIFY_ADD_DEVICE || + dev->type != &i2c_adapter_type || + i2c_root_adapter(dev) != &priv->adapter) + return NOTIFY_DONE; + + /* Call i2c_register_spd for muxed child segments */ + i2c_register_spd(to_i2c_adapter(dev)); + + return NOTIFY_OK; +} + /* Setup multiplexing if needed */ static void i801_add_mux(struct i801_priv *priv) { @@ -1430,6 +1449,9 @@ static void i801_add_mux(struct i801_priv *priv) mux_config->gpios[i], "mux", 0); gpiod_add_lookup_table(lookup); + priv->mux_notifier_block.notifier_call = i801_notifier_call; + if (bus_register_notifier(&i2c_bus_type, &priv->mux_notifier_block)) + return; /* * Register the mux device, we use PLATFORM_DEVID_NONE here * because since we are referring to the GPIO chip by name we are @@ -1451,6 +1473,7 @@ static void i801_add_mux(struct i801_priv *priv) static void i801_del_mux(struct i801_priv *priv) { + bus_unregister_notifier(&i2c_bus_type, &priv->mux_notifier_block); platform_device_unregister(priv->mux_pdev); gpiod_remove_lookup_table(priv->lookup); } -- cgit v1.2.3 From 47c21d2d52e0da05abdae63faa3de65cfb3afb74 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Fri, 5 Apr 2024 12:10:09 +0200 Subject: i2c: add HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will disable inb()/outb() and friends at compile time. We thus need to add HAS_IOPORT as dependency for those drivers using them. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Signed-off-by: Niklas Schnelle Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/Kconfig | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 97989c914260..5f4dc31ed142 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -18,7 +18,7 @@ config I2C_CCGX_UCSI config I2C_ALI1535 tristate "ALI 1535" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -30,7 +30,7 @@ config I2C_ALI1535 config I2C_ALI1563 tristate "ALI 1563" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB @@ -42,7 +42,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -52,7 +52,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -77,7 +77,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -107,7 +107,7 @@ config I2C_HIX5HD2 config I2C_I801 tristate "Intel 82801 (ICH/PCH)" - depends on PCI + depends on PCI && HAS_IOPORT select P2SB if X86 select CHECK_SIGNATURE if X86 && DMI select I2C_SMBUS @@ -165,7 +165,7 @@ config I2C_I801 config I2C_ISCH tristate "Intel SCH SMBus 1.0" - depends on PCI + depends on PCI && HAS_IOPORT select LPC_SCH help Say Y here if you want to use SMBus controller on the Intel SCH @@ -186,7 +186,7 @@ config I2C_ISMT config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following @@ -232,7 +232,7 @@ config I2C_CHT_WC config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the Nvidia nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. @@ -265,7 +265,7 @@ config I2C_NVIDIA_GPU config I2C_SIS5595 tristate "SiS 5595" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -275,7 +275,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730/964" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface. @@ -285,7 +285,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -303,7 +303,7 @@ config I2C_SIS96X config I2C_VIA tristate "VIA VT82C586B" - depends on PCI + depends on PCI && HAS_IOPORT select I2C_ALGOBIT help If you say yes to this option, support will be included for the VIA @@ -314,7 +314,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the VIA VT82C596 and later SMBus interface. Specifically, the following @@ -885,6 +885,7 @@ config I2C_NPCM config I2C_OCORES tristate "OpenCores I2C Controller" + depends on HAS_IOPORT help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see @@ -1397,6 +1398,7 @@ config I2C_ICY config I2C_MLXCPLD tristate "Mellanox I2C driver" depends on X86_64 || (ARM64 && ACPI) || COMPILE_TEST + depends on HAS_IOPORT help This exposes the Mellanox platform I2C busses to the linux I2C layer for X86 and ARM64/ACPI based systems. -- cgit v1.2.3 From c2e55b449de7298a751ed0256251019d302af453 Mon Sep 17 00:00:00 2001 From: Sai Pavan Boddu Date: Fri, 3 May 2024 15:12:08 +0530 Subject: i2c: cadence: Avoid fifo clear after start The Driver unintentionally programs ctrl reg to clear the fifo, which happens after the start of transaction. Previously, this was not an issue as it involved read-modified-write. However, this issue breaks i2c reads on QEMU, as i2c-read is executed before guest starts programming control register. Fixes: ff0cf7bca630 ("i2c: cadence: Remove unnecessary register reads") Signed-off-by: Sai Pavan Boddu Acked-by: Michal Simek Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-cadence.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 4bb7d6756947..2fce3e84ba64 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -633,6 +633,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) if (hold_clear) { ctrl_reg &= ~CDNS_I2C_CR_HOLD; + ctrl_reg &= ~CDNS_I2C_CR_CLR_FIFO; /* * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size * register reaches '0'. This is an IP bug which causes transfer size -- cgit v1.2.3 From 48ace624878d01ed19df2191d5a5e902631e9dd3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 8 Apr 2024 11:28:36 +0200 Subject: i2c: ocores: convert to ioport_map() for IORESOURCE_IO There is at least one machine that uses this driver but does not have support for inb()/outb() instructions. Convert this to using ioport_map() so it can build on architectures that don't provide these but work correctly on machines that require using port I/O. Fixes: 47c21d2d52e0 ("i2c: add HAS_IOPORT dependencies") Reported-by: Geert Uytterhoeven Link: https://lore.kernel.org/lkml/CAMuHMdVUQ2WgtpYPYfO2T=itMmZ7w=geREqDtsP8Q3ODh9rxdw@mail.gmail.com/ Signed-off-by: Arnd Bergmann Acked-by: Peter Korsgaard Signed-off-by: Andi Shyti --- drivers/i2c/busses/Kconfig | 1 - drivers/i2c/busses/i2c-ocores.c | 21 +++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 5f4dc31ed142..760e14b04f95 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -885,7 +885,6 @@ config I2C_NPCM config I2C_OCORES tristate "OpenCores I2C Controller" - depends on HAS_IOPORT help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index e106af83cef4..56a4dabf5a38 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -32,7 +32,6 @@ */ struct ocores_i2c { void __iomem *base; - int iobase; u32 reg_shift; u32 reg_io_width; unsigned long flags; @@ -136,16 +135,6 @@ static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) return ioread32be(i2c->base + (reg << i2c->reg_shift)); } -static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) -{ - outb(value, i2c->iobase + reg); -} - -static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) -{ - return inb(i2c->iobase + reg); -} - static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { i2c->setreg(i2c, reg, value); @@ -618,15 +607,19 @@ static int ocores_i2c_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) return -EINVAL; - i2c->iobase = res->start; if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Can't get I/O resource.\n"); return -EBUSY; } - i2c->setreg = oc_setreg_io_8; - i2c->getreg = oc_getreg_io_8; + i2c->base = devm_ioport_map(&pdev->dev, res->start, + resource_size(res)); + if (!i2c->base) { + dev_err(&pdev->dev, "Can't map I/O resource.\n"); + return -EBUSY; + } + i2c->reg_io_width = 1; } pdata = dev_get_platdata(&pdev->dev); -- cgit v1.2.3 From 9c535237245e4bf21758604277279b8ead58a724 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 4 Apr 2024 22:09:50 +0200 Subject: i2c: i801: Fix missing Kconfig dependency The original change adds usage of i2c_root_adapter(), which is implemented in i2c-mux.c. Therefore we can't use the multiplexing if I2C_I801=y and I2C_MUX=m. Handling the dependencies in the code would become unnecessarily complex, therefore create a new config symbol. Fixes: 893fef0bc6aa ("i2c: i801: Call i2c_register_spd for muxed child segments") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202404042206.MjAQC32x-lkp@intel.com/ Signed-off-by: Heiner Kallweit Reviewed-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/Kconfig | 8 ++++++++ drivers/i2c/busses/i2c-i801.c | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 760e14b04f95..27d3ef565ca8 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -163,6 +163,14 @@ config I2C_I801 This driver can also be built as a module. If so, the module will be called i2c-i801. +config I2C_I801_MUX + def_bool I2C_I801 + depends on DMI && I2C_MUX_GPIO + depends on !(I2C_I801=y && I2C_MUX=m) + help + Optional support for multiplexed SMBUS on certain systems with + more than 8 memory slots. + config I2C_ISCH tristate "Intel SCH SMBus 1.0" depends on PCI && HAS_IOPORT diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 4294c0c63cef..92b53b480c47 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -120,7 +120,7 @@ #include #include -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#ifdef CONFIG_I2C_I801_MUX #include #include #endif @@ -289,7 +289,7 @@ struct i801_priv { int len; u8 *data; -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#ifdef CONFIG_I2C_I801_MUX struct platform_device *mux_pdev; struct gpiod_lookup_table *lookup; struct notifier_block mux_notifier_block; @@ -1300,7 +1300,7 @@ static void i801_probe_optional_slaves(struct i801_priv *priv) register_dell_lis3lv02d_i2c_device(priv); /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) +#ifdef CONFIG_I2C_I801_MUX if (!priv->mux_pdev) #endif i2c_register_spd(&priv->adapter); @@ -1310,7 +1310,7 @@ static void __init input_apanel_init(void) {} static void i801_probe_optional_slaves(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#ifdef CONFIG_I2C_I801_MUX static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, -- cgit v1.2.3 From 31a18e4139e0ad6019aad740e1f84cd4b5079e15 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Thu, 11 Apr 2024 07:02:57 +0200 Subject: MAINTAINERS: adjust file entry in ARM/LPC32XX SOC SUPPORT Commit 51c87f0e6cca ("dt-bindings: i2c: nxp,pnx-i2c: Convert to dtschema") converts i2c-pnx.txt to nxp,pnx-i2c.yaml, but misses to adjust the file entry in ARM/LPC32XX SOC SUPPORT. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Adjust the file entry in ARM/LPC32XX SOC SUPPORT after this conversion. Signed-off-by: Lukas Bulwahn Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ec0284125e8f..75554f93e555 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2320,7 +2320,7 @@ M: Vladimir Zapolskiy L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained T: git git://github.com/vzapolskiy/linux-lpc32xx.git -F: Documentation/devicetree/bindings/i2c/i2c-pnx.txt +F: Documentation/devicetree/bindings/i2c/nxp,pnx-i2c.yaml F: arch/arm/boot/dts/nxp/lpc/lpc32* F: arch/arm/mach-lpc32xx/ F: drivers/i2c/busses/i2c-pnx.c -- cgit v1.2.3 From f32a32ad5b5a7b5108d142f0a9430f9eac798f9e Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Fri, 12 Apr 2024 14:53:25 +0100 Subject: dt-bindings: i2c: qcom-cci: Document sc8280xp compatible Add sc8280xp compatible consistent with recent CAMSS CCI interfaces. sc8280xp has the following clock list and so requires its own compat string and sc8280xp specific clock definition in the yaml. - const: camnoc_axi - const: slow_ahb_src - const: cpas_ahb - const: cci Signed-off-by: Bryan O'Donoghue Reviewed-by: Krzysztof Kozlowski Reviewed-by: Vladimir Zapolskiy Signed-off-by: Andi Shyti --- .../devicetree/bindings/i2c/qcom,i2c-cci.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index f0eabff86310..daf4e71b8e7f 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: - qcom,sc7280-cci + - qcom,sc8280xp-cci - qcom,sdm845-cci - qcom,sm6350-cci - qcom,sm8250-cci @@ -176,6 +177,24 @@ allOf: - const: cci - const: cci_src + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-cci + then: + properties: + clocks: + minItems: 4 + maxItems: 4 + clock-names: + items: + - const: camnoc_axi + - const: slow_ahb_src + - const: cpas_ahb + - const: cci + additionalProperties: false examples: -- cgit v1.2.3 From 6104b99b14d9cbc2dab48ca3de8e526ced987ddb Mon Sep 17 00:00:00 2001 From: Abhinav Jain Date: Mon, 15 Apr 2024 16:12:20 +0000 Subject: i2c: mpc: Removal of of_node_put with __free for auto cleanup Remove of_node_put from node_ctrl and node struct device_nodes. Move the declaration to initialization for ensuring scope sanity. Suggested-by: Julia Lawall Signed-off-by: Abhinav Jain Reviewed-by: Chris Packham Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-mpc.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 8d73c0f405ed..c4223556b3b8 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -304,13 +304,12 @@ static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, u32 clock) { - struct device_node *node_ctrl; void __iomem *ctrl; u32 idx; /* Enable I2C interrupts for mpc5121 */ - node_ctrl = of_find_compatible_node(NULL, NULL, - "fsl,mpc5121-i2c-ctrl"); + struct device_node *node_ctrl __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,mpc5121-i2c-ctrl"); if (node_ctrl) { ctrl = of_iomap(node_ctrl, 0); if (ctrl) { @@ -321,7 +320,6 @@ static void mpc_i2c_setup_512x(struct device_node *node, setbits32(ctrl, 1 << (24 + idx * 2)); iounmap(ctrl); } - of_node_put(node_ctrl); } /* The clock setup for the 52xx works also fine for the 512x */ @@ -358,11 +356,11 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { static u32 mpc_i2c_get_sec_cfg_8xxx(void) { - struct device_node *node; u32 __iomem *reg; u32 val = 0; - node = of_find_node_by_name(NULL, "global-utilities"); + struct device_node *node __free(device_node) = + of_find_node_by_name(NULL, "global-utilities"); if (node) { const u32 *prop = of_get_property(node, "reg", NULL); if (prop) { @@ -383,7 +381,6 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) iounmap(reg); } } - of_node_put(node); return val; } -- cgit v1.2.3 From 864d1d83879b238f0c89963bfe9e28594da214ec Mon Sep 17 00:00:00 2001 From: Shanth Murthy Date: Tue, 16 Apr 2024 09:31:25 +0300 Subject: i2c: designware: Add ACPI ID for Granite Rapids-D I2C controller Granite Rapids-D has additional I2C controller that is enumerated via ACPI. Add ACPI ID for it. Signed-off-by: Shanth Murthy Signed-off-by: Jarkko Nikula Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-designware-platdrv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 4ab41ba39d55..926fb74a8570 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -46,6 +46,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "INT33C3", 0 }, { "INT3432", 0 }, { "INT3433", 0 }, + { "INTC10EF", 0 }, { "80860F41", ACCESS_NO_IRQ_SUSPEND }, { "808622C1", ACCESS_NO_IRQ_SUSPEND }, { "AMD0010", ACCESS_INTR_MASK }, -- cgit v1.2.3 From 780868fc480ee8e89e8db89c7946716cc75a36e9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 15 Apr 2024 22:47:55 +0200 Subject: i2c: i801: Remove usage of I2C_CLASS_SPD Only remaining client driver supporting I2C_CLASS_SPD is jc42. This type of thermal sensor can be found on several DDR3/DDR4 modules. i2c_register_spd() instantiates also such thermal sensor i2c devices. Since 893fef0bc6aa ("i2c: i801: Call i2c_register_spd for muxed child segments") i2c_register_spd() is called also for the remaining use case, systems with muxed SMBUS segments for SPD EEPROMs. Therefore I2C_CLASS_SPD class-based instantiation isn't needed any longer in this driver, so remove it. Signed-off-by: Heiner Kallweit Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-i801.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 92b53b480c47..6d027a77d1dd 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -264,7 +264,6 @@ struct i801_mux_config { char *gpio_chip; unsigned values[3]; int n_values; - unsigned classes[3]; unsigned gpios[2]; /* Relative to gpio_chip->base */ int n_gpios; }; @@ -1315,7 +1314,6 @@ static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, .n_values = 2, - .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, .gpios = { 52, 53 }, .n_gpios = 2, }; @@ -1324,7 +1322,6 @@ static struct i801_mux_config i801_mux_config_asus_z8_d18 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03, 0x01 }, .n_values = 3, - .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, .gpios = { 52, 53 }, .n_gpios = 2, }; @@ -1434,7 +1431,6 @@ static void i801_add_mux(struct i801_priv *priv) gpio_data.parent = priv->adapter.nr; gpio_data.values = mux_config->values; gpio_data.n_values = mux_config->n_values; - gpio_data.classes = mux_config->classes; gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; /* Register GPIO descriptor lookup table */ -- cgit v1.2.3 From 073e58bf6b1a689da2ffcfc7fc515005f8794018 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 15 Apr 2024 22:48:42 +0200 Subject: i2c: mux: gpio: remove support for class-based device instantiation i801 as only user of gpio i2c mux removed support for class-based device instantiation on muxed busses. Class-based device instantiation is a legacy mechanism and shouldn't be used in new code, therefore remove support also here. Signed-off-by: Heiner Kallweit Signed-off-by: Andi Shyti --- drivers/i2c/muxes/i2c-mux-gpio.c | 3 +-- include/linux/platform_data/i2c-mux-gpio.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 6b979a0a6ab8..0fbb33a3d518 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -206,9 +206,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], 0); if (ret) goto add_adapter_failed; } diff --git a/include/linux/platform_data/i2c-mux-gpio.h b/include/linux/platform_data/i2c-mux-gpio.h index 5e4c2c272a73..816a4cd3ccb5 100644 --- a/include/linux/platform_data/i2c-mux-gpio.h +++ b/include/linux/platform_data/i2c-mux-gpio.h @@ -18,7 +18,6 @@ * @values: Array of bitmasks of GPIO settings (low/high) for each * position * @n_values: Number of multiplexer positions (busses to instantiate) - * @classes: Optional I2C auto-detection classes * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used */ struct i2c_mux_gpio_platform_data { @@ -26,7 +25,6 @@ struct i2c_mux_gpio_platform_data { int base_nr; const unsigned *values; int n_values; - const unsigned *classes; unsigned idle; }; -- cgit v1.2.3 From 355b1513b1e97b6cef84b786c6480325dfd3753d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 12 Apr 2024 12:21:58 +0200 Subject: i2c: i801: Annotate apanel_addr as __ro_after_init Annotate this variable as __ro_after_init to protect it from being overwritten later. Signed-off-by: Heiner Kallweit Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 6d027a77d1dd..e577abc776c1 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1060,7 +1060,7 @@ static const struct pci_device_id i801_ids[] = { MODULE_DEVICE_TABLE(pci, i801_ids); #if defined CONFIG_X86 && defined CONFIG_DMI -static unsigned char apanel_addr; +static unsigned char apanel_addr __ro_after_init; /* Scan the system ROM for the signature "FJKEYINF" */ static __init const void __iomem *bios_signature(const void __iomem *bios) -- cgit v1.2.3 From 4268254a39484fc11ba991ae148bacbe75d9cc0a Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 22 Apr 2024 13:36:29 +0200 Subject: i2c: lpi2c: Avoid calling clk_get_rate during transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of repeatedly calling clk_get_rate for each transfer, lock the clock rate and cache the value. A deadlock has been observed while adding tlv320aic32x4 audio codec to the system. When this clock provider adds its clock, the clk mutex is locked already, it needs to access i2c, which in return needs the mutex for clk_get_rate as well. Signed-off-by: Alexander Stein Reviewed-by: Uwe Kleine-König Reviewed-by: Andi Shyti Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-imx-lpi2c.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 6d72e4e126dd..36e8f6196a87 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -99,6 +99,7 @@ struct lpi2c_imx_struct { __u8 *rx_buf; __u8 *tx_buf; struct completion complete; + unsigned long rate_per; unsigned int msglen; unsigned int delivered; unsigned int block_data; @@ -212,9 +213,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) lpi2c_imx_set_mode(lpi2c_imx); - clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); - if (!clk_rate) - return -EINVAL; + clk_rate = lpi2c_imx->rate_per; if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) filt = 0; @@ -611,6 +610,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) return ret; + /* + * Lock the parent clock rate to avoid getting parent clock upon + * each transfer + */ + ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't lock I2C peripheral clock rate\n"); + + lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk); + if (!lpi2c_imx->rate_per) + return dev_err_probe(&pdev->dev, -EINVAL, + "can't get I2C peripheral clock rate\n"); + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); -- cgit v1.2.3 From 375ee8d223b4a08e09041f7fdb20d8428ea1e918 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:15 +0200 Subject: i2c: at91-master: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-at91-master.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index d311981d3e60..ee3b469ddfb9 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -591,7 +591,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) dev->adapter.timeout); if (time_left == 0) { dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR); - dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; goto error; -- cgit v1.2.3 From 796e2c260187e32530cf343546ba1cdf2e2f5491 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:16 +0200 Subject: i2c: bcm-iproc: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-bcm-iproc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index e905734c26a0..133d02899c6b 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -811,8 +811,6 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c, } if (!time_left && !iproc_i2c->xfer_is_done) { - dev_err(iproc_i2c->device, "transaction timed out\n"); - /* flush both TX/RX FIFOs */ val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT); iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val); -- cgit v1.2.3 From 09a40cbc996e8cd6633930a58ccf4fe1fa12e60e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:17 +0200 Subject: i2c: bcm2835: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-bcm2835.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index b92de1944221..3045ba82380d 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -370,7 +370,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!time_left) { bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); - dev_err(i2c_dev->dev, "i2c transfer timed out\n"); return -ETIMEDOUT; } -- cgit v1.2.3 From 6808d67f512ab0db5d6f44c2f13e7d6a6fd5e4f5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:18 +0200 Subject: i2c: cadence: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Acked-by: Michal Simek Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-cadence.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 4bb7d6756947..1b0006e3b95c 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -789,8 +789,6 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); if (time_left == 0) { cdns_i2c_master_reset(adap); - dev_err(id->adap.dev.parent, - "timeout waiting on completion\n"); return -ETIMEDOUT; } -- cgit v1.2.3 From fc93dcd7ebdd2543da7ebaaa8c2d51ce2ec689eb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:19 +0200 Subject: i2c: davinci: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-davinci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 02b3b1160fb0..7ae611120cfa 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -489,7 +489,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) time_left = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); if (!time_left) { - dev_err(dev->dev, "controller timed out\n"); i2c_recover_bus(adap); dev->buf_len = 0; return -ETIMEDOUT; -- cgit v1.2.3 From b752b21e6f84edb5b0e27f00e41d897bc671fe17 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:21 +0200 Subject: i2c: img-scb: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout and simplify the logic a little. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-img-scb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index f9d4bfef511c..e0e87185f6bb 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1124,11 +1124,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, IMG_I2C_TIMEOUT); del_timer_sync(&i2c->check_timer); - if (time_left == 0) { - dev_err(adap->dev.parent, "i2c transfer timed out\n"); + if (time_left == 0) i2c->msg_status = -ETIMEDOUT; - break; - } if (i2c->msg_status) break; -- cgit v1.2.3 From 4828450ad17d2966d2429156146797db3ec8182d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:22 +0200 Subject: i2c: ismt: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-ismt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index c74985d77b0e..655b5d851c48 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -623,7 +623,6 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_unmap_single(dev, dma_addr, dma_size, dma_direction); if (unlikely(!time_left)) { - dev_err(dev, "completion wait timed out\n"); ret = -ETIMEDOUT; goto out; } -- cgit v1.2.3 From 60b36100f815d0f75abecabffa31efe9caa16f04 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:23 +0200 Subject: i2c: nomadik: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Linus Walleij Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-nomadik.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 4f41a3c7824d..45c6df26fcbf 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -542,12 +542,9 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) xfer_done = nmk_i2c_wait_xfer_done(priv); - if (!xfer_done) { - /* Controller timed out */ - dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n", - priv->cli.slave_adr); + if (!xfer_done) status = -ETIMEDOUT; - } + return status; } -- cgit v1.2.3 From 760b37b373a8d1d90011265307225bb26be5cda1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:24 +0200 Subject: i2c: omap: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 42165ef57946..36bebef36740 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -752,7 +752,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, } if (timeout == 0) { - dev_err(omap->dev, "controller timed out\n"); omap_i2c_reset(omap); __omap_i2c_init(omap); return -ETIMEDOUT; -- cgit v1.2.3 From 6d128e73c7820356a3481024166b9f3dc3aee99c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:25 +0200 Subject: i2c: qcom-geni: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Bjorn Andersson Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-qcom-geni.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index da94df466e83..090b4846ed62 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -630,11 +630,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i dma_async_issue_pending(gi2c->tx_c); timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!timeout) { - dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n", - gi2c->cur->flags, gi2c->cur->addr); + if (!timeout) gi2c->err = -ETIMEDOUT; - } if (gi2c->err) { ret = gi2c->err; -- cgit v1.2.3 From 1667b35535bb2242b296513642fee1d3291a4503 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:26 +0200 Subject: i2c: qup: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Bjorn Andersson Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-qup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 598102d16677..c9b43a3c4bd3 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -793,10 +793,8 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup) dma_async_issue_pending(qup->brx.dma); } - if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) { - dev_err(qup->dev, "normal trans timed out\n"); + if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) ret = -ETIMEDOUT; - } if (ret || qup->bus_err || qup->qup_err) { reinit_completion(&qup->xfer); -- cgit v1.2.3 From 0ee55dc9edd03a7d98e3ce8f8f03380f090d520b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:27 +0200 Subject: i2c: rk3x: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Acked-by: Heiko Stuebner Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-rk3x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 086fdf262e7b..8c7367f289d3 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1106,9 +1106,6 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, spin_lock_irqsave(&i2c->lock, flags); if (timeout == 0) { - dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", - i2c_readl(i2c, REG_IPD), i2c->state); - /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; -- cgit v1.2.3 From 03bc6a248ab6e3d021b45bee3f324256b0008fbd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:28 +0200 Subject: i2c: sh_mobile: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-sh_mobile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index c65ac3d7eadc..f86c29737df1 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -688,7 +688,6 @@ static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd, } if (!time_left) { - dev_err(pd->dev, "Transfer request timed out\n"); if (pd->dma_direction != DMA_NONE) sh_mobile_i2c_cleanup_dma(pd, true); -- cgit v1.2.3 From bc19b5fe972b39516d6eafd4b61830b58bcd5c54 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:29 +0200 Subject: i2c: st: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-st.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index ce2333408904..dbb93394ff94 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -689,11 +689,8 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, i2c_dev->adap.timeout); ret = c->result; - if (!timeout) { - dev_err(i2c_dev->dev, "Write to slave 0x%x timed out\n", - c->addr); + if (!timeout) ret = -ETIMEDOUT; - } i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG; st_i2c_clr_bits(i2c_dev->base + SSC_I2C, i2c); -- cgit v1.2.3 From f757ec37efd2190e213f3fbcf17bdad8c10e9104 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:30 +0200 Subject: i2c: tegra: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 920d5a8cbf4c..85b31edc558d 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -1331,7 +1331,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, dmaengine_terminate_sync(i2c_dev->dma_chan); if (!time_left && !completion_done(&i2c_dev->dma_complete)) { - dev_err(i2c_dev->dev, "DMA transfer timed out\n"); tegra_i2c_init(i2c_dev); return -ETIMEDOUT; } @@ -1351,7 +1350,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, tegra_i2c_mask_irq(i2c_dev, int_mask); if (time_left == 0) { - dev_err(i2c_dev->dev, "I2C transfer timed out\n"); tegra_i2c_init(i2c_dev); return -ETIMEDOUT; } -- cgit v1.2.3 From 58859d9b62d874a69ecb5243d347f1ce47286d49 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:31 +0200 Subject: i2c: uniphier-f: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-uniphier-f.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index dbc91c7c3788..6c3dac2cf568 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -358,7 +358,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, spin_unlock_irqrestore(&priv->lock, flags); if (!time_left) { - dev_err(&adap->dev, "transaction timeout.\n"); uniphier_fi2c_recover(priv); return -ETIMEDOUT; } -- cgit v1.2.3 From 1d428f5d3827fd9826abe3b14609aaa2037bc00c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Apr 2024 13:24:32 +0200 Subject: i2c: uniphier: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-uniphier.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 854ac25b5862..e1b4c80e0285 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -71,10 +71,8 @@ static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata, writel(txdata, priv->membase + UNIPHIER_I2C_DTRM); time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); - if (unlikely(!time_left)) { - dev_err(&adap->dev, "transaction timeout\n"); + if (unlikely(!time_left)) return -ETIMEDOUT; - } rxdata = readl(priv->membase + UNIPHIER_I2C_DREC); if (rxdatap) -- cgit v1.2.3 From 29914dac94d490001bdfc5b9fdb8a5c29a724c1b Mon Sep 17 00:00:00 2001 From: Ji Sheng Teoh Date: Tue, 23 Apr 2024 10:48:06 +0800 Subject: i2c: cadence: Add RISCV architecture support Add RISCV support to Cadence I2C Kconfig which is used in platform such as the StarFive JH8100. Signed-off-by: Eng Lee Teh Signed-off-by: Ji Sheng Teoh Signed-off-by: Andi Shyti --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 27d3ef565ca8..a5aff29c559d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -508,7 +508,7 @@ config I2C_BRCMSTB config I2C_CADENCE tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST + depends on ARCH_ZYNQ || ARM64 || XTENSA || RISCV || COMPILE_TEST help Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. -- cgit v1.2.3 From 114c69f4be3f3a55355b2f1db46a820bb0364457 Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Tue, 23 Apr 2024 00:46:04 -0700 Subject: i2c: thunderx: Clock divisor logic changes Handle changes to clock divisor logic for OcteonTX2 SoC family using subsystem ID and using default reference clock source as 100MHz. Signed-off-by: Suneel Garapati Signed-off-by: Piyush Malgujar Acked-by: Andi Shyti Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-octeon-core.c | 39 ++++++++++++++++++++++++++++---- drivers/i2c/busses/i2c-octeon-core.h | 17 ++++++++++++++ drivers/i2c/busses/i2c-thunderx-pcidrv.c | 7 ++++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 845eda70b8ca..75efb375d8e4 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -17,9 +17,14 @@ #include #include #include +#include #include "i2c-octeon-core.h" +#define INITIAL_DELTA_HZ 1000000 +#define TWSI_MASTER_CLK_REG_DEF_VAL 0x18 +#define TWSI_MASTER_CLK_REG_OTX2_VAL 0x3 + /* interrupt service routine */ irqreturn_t octeon_i2c_isr(int irq, void *dev_id) { @@ -658,31 +663,57 @@ out: void octeon_i2c_set_clock(struct octeon_i2c *i2c) { int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; - int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; + bool is_plat_otx2; + unsigned int mdiv_min = 2; + /* + * Find divisors to produce target frequency, start with large delta + * to cover wider range of divisors, note thp = TCLK half period. + */ + unsigned int thp = TWSI_MASTER_CLK_REG_DEF_VAL, mdiv = 2, ndiv = 0; + unsigned int delta_hz = INITIAL_DELTA_HZ; + + is_plat_otx2 = octeon_i2c_is_otx2(to_pci_dev(i2c->dev)); + + if (is_plat_otx2) { + thp = TWSI_MASTER_CLK_REG_OTX2_VAL; + mdiv_min = 0; + } for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) { /* * An mdiv value of less than 2 seems to not work well * with ds1337 RTCs, so we constrain it to larger values. */ - for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) { + for (mdiv_idx = 15; mdiv_idx >= mdiv_min && delta_hz != 0; mdiv_idx--) { /* * For given ndiv and mdiv values check the * two closest thp values. */ tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; tclk *= (1 << ndiv_idx); - thp_base = (i2c->sys_freq / (tclk * 2)) - 1; + if (is_plat_otx2) + thp_base = (i2c->sys_freq / tclk) - 2; + else + thp_base = (i2c->sys_freq / (tclk * 2)) - 1; for (inc = 0; inc <= 1; inc++) { thp_idx = thp_base + inc; if (thp_idx < 5 || thp_idx > 0xff) continue; - foscl = i2c->sys_freq / (2 * (thp_idx + 1)); + if (is_plat_otx2) + foscl = i2c->sys_freq / (thp_idx + 2); + else + foscl = i2c->sys_freq / + (2 * (thp_idx + 1)); foscl = foscl / (1 << ndiv_idx); foscl = foscl / (mdiv_idx + 1) / 10; diff = abs(foscl - i2c->twsi_freq); + /* + * Diff holds difference between calculated frequency + * value vs desired frequency. + * Delta_hz is updated with last minimum diff. + */ if (diff < delta_hz) { delta_hz = diff; thp = thp_idx; diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 9bb9f64fdda0..69bd62940f99 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include /* Controller command patterns */ #define SW_TWSI_V BIT_ULL(63) /* Valid bit */ @@ -211,6 +213,21 @@ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c)); } +#define PCI_SUBSYS_DEVID_9XXX 0xB +#define PCI_SUBSYS_MASK GENMASK(15, 12) +/** + * octeon_i2c_is_otx2 - check for chip ID + * @pdev: PCI dev structure + * + * Returns true if the device is an OcteonTX2, false otherwise. + */ +static inline bool octeon_i2c_is_otx2(struct pci_dev *pdev) +{ + u32 chip_id = FIELD_GET(PCI_SUBSYS_MASK, pdev->subsystem_device); + + return (chip_id == PCI_SUBSYS_DEVID_9XXX); +} + /* Prototypes */ irqreturn_t octeon_i2c_isr(int irq, void *dev_id); int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index a77cd86fe75e..755697740038 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -28,6 +28,7 @@ #define PCI_DEVICE_ID_THUNDER_TWSI 0xa012 #define SYS_FREQ_DEFAULT 700000000 +#define OTX2_REF_FREQ_DEFAULT 100000000 #define TWSI_INT_ENA_W1C 0x1028 #define TWSI_INT_ENA_W1S 0x1030 @@ -205,6 +206,12 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, if (ret) goto error; + /* + * For OcteonTX2 chips, set reference frequency to 100MHz + * as refclk_src in TWSI_MODE register defaults to 100MHz. + */ + if (octeon_i2c_is_otx2(pdev)) + i2c->sys_freq = OTX2_REF_FREQ_DEFAULT; octeon_i2c_set_clock(i2c); i2c->adap = thunderx_i2c_ops; -- cgit v1.2.3 From 03240f826b02929476abd7c3a3cc132cc65c8614 Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Tue, 23 Apr 2024 00:46:05 -0700 Subject: i2c: thunderx: Support for High speed mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support bus operations for high speed bus frequencies greater than 400KHZ following control bits need to be setup accordingly - hs_mode (bit 0) field in Mode register to switch controller between low-speed and high-speed frequency operating mode. - Setup clock divisors for desired TWSI bus frequency using FOSCL output frequency divisor (D): 0 - sets the divisor to 10 for low speed mode 1 - sets the divisor to 15 for high speed mode. The TWSI bus output frequency, in master mode is based on: TCLK = 100MHz / (THP + 2) FOSCL = FSAMP / (M+1)×D = TCLK / (2 ^ N × (M + 1) × 15) FSAMP = TCLK / 2 ^ N where, N is <2:0> and M is <6:3> of TWSI Clock Control Register D is 10 for low speed or 15 for HS_MODE With high speed mode support, HLC mode usage is limited to low speed frequency (<=400KHz) bus transfers in hardware. Signed-off-by: Suneel Garapati Signed-off-by: Piyush Malgujar Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-octeon-core.c | 68 +++++++++++++++++++++----------- drivers/i2c/busses/i2c-octeon-core.h | 8 ++++ drivers/i2c/busses/i2c-thunderx-pcidrv.c | 3 +- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 75efb375d8e4..86be597866f8 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -612,25 +612,27 @@ int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct octeon_i2c *i2c = i2c_get_adapdata(adap); int i, ret = 0; - if (num == 1) { - if (msgs[0].len > 0 && msgs[0].len <= 8) { - if (msgs[0].flags & I2C_M_RD) - ret = octeon_i2c_hlc_read(i2c, msgs); - else - ret = octeon_i2c_hlc_write(i2c, msgs); - goto out; - } - } else if (num == 2) { - if ((msgs[0].flags & I2C_M_RD) == 0 && - (msgs[1].flags & I2C_M_RECV_LEN) == 0 && - msgs[0].len > 0 && msgs[0].len <= 2 && - msgs[1].len > 0 && msgs[1].len <= 8 && - msgs[0].addr == msgs[1].addr) { - if (msgs[1].flags & I2C_M_RD) - ret = octeon_i2c_hlc_comp_read(i2c, msgs); - else - ret = octeon_i2c_hlc_comp_write(i2c, msgs); - goto out; + if (IS_LS_FREQ(i2c->twsi_freq)) { + if (num == 1) { + if (msgs[0].len > 0 && msgs[0].len <= 8) { + if (msgs[0].flags & I2C_M_RD) + ret = octeon_i2c_hlc_read(i2c, msgs); + else + ret = octeon_i2c_hlc_write(i2c, msgs); + goto out; + } + } else if (num == 2) { + if ((msgs[0].flags & I2C_M_RD) == 0 && + (msgs[1].flags & I2C_M_RECV_LEN) == 0 && + msgs[0].len > 0 && msgs[0].len <= 2 && + msgs[1].len > 0 && msgs[1].len <= 8 && + msgs[0].addr == msgs[1].addr) { + if (msgs[1].flags & I2C_M_RD) + ret = octeon_i2c_hlc_comp_read(i2c, msgs); + else + ret = octeon_i2c_hlc_comp_write(i2c, msgs); + goto out; + } } } @@ -664,12 +666,12 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) { int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; bool is_plat_otx2; - unsigned int mdiv_min = 2; /* * Find divisors to produce target frequency, start with large delta - * to cover wider range of divisors, note thp = TCLK half period. + * to cover wider range of divisors, note thp = TCLK half period and + * ds is OSCL output frequency divisor. */ - unsigned int thp = TWSI_MASTER_CLK_REG_DEF_VAL, mdiv = 2, ndiv = 0; + unsigned int thp, mdiv_min, mdiv = 2, ndiv = 0, ds = 10; unsigned int delta_hz = INITIAL_DELTA_HZ; is_plat_otx2 = octeon_i2c_is_otx2(to_pci_dev(i2c->dev)); @@ -677,6 +679,11 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) if (is_plat_otx2) { thp = TWSI_MASTER_CLK_REG_OTX2_VAL; mdiv_min = 0; + if (!IS_LS_FREQ(i2c->twsi_freq)) + ds = 15; + } else { + thp = TWSI_MASTER_CLK_REG_DEF_VAL; + mdiv_min = 2; } for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) { @@ -689,7 +696,7 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) * For given ndiv and mdiv values check the * two closest thp values. */ - tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; + tclk = i2c->twsi_freq * (mdiv_idx + 1) * ds; tclk *= (1 << ndiv_idx); if (is_plat_otx2) thp_base = (i2c->sys_freq / tclk) - 2; @@ -707,7 +714,9 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) foscl = i2c->sys_freq / (2 * (thp_idx + 1)); foscl = foscl / (1 << ndiv_idx); - foscl = foscl / (mdiv_idx + 1) / 10; + foscl = foscl / (mdiv_idx + 1) / ds; + if (foscl > i2c->twsi_freq) + continue; diff = abs(foscl - i2c->twsi_freq); /* * Diff holds difference between calculated frequency @@ -725,6 +734,17 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) } octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp); octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); + if (is_plat_otx2) { + u64 mode; + + mode = __raw_readq(i2c->twsi_base + MODE(i2c)); + /* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */ + if (!IS_LS_FREQ(i2c->twsi_freq)) + mode |= TWSX_MODE_HS_MASK; + else + mode &= ~TWSX_MODE_HS_MASK; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + MODE(i2c)); + } } int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 69bd62940f99..94c4401a4a56 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -94,11 +94,18 @@ struct octeon_i2c_reg_offset { unsigned int sw_twsi; unsigned int twsi_int; unsigned int sw_twsi_ext; + unsigned int mode; }; #define SW_TWSI(x) (x->roff.sw_twsi) #define TWSI_INT(x) (x->roff.twsi_int) #define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext) +#define MODE(x) ((x)->roff.mode) + +/* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */ +#define TWSX_MODE_REFCLK_SRC BIT(4) +#define TWSX_MODE_HS_MODE BIT(0) +#define TWSX_MODE_HS_MASK (TWSX_MODE_REFCLK_SRC | TWSX_MODE_HS_MODE) struct octeon_i2c { wait_queue_head_t queue; @@ -213,6 +220,7 @@ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c)); } +#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000) #define PCI_SUBSYS_DEVID_9XXX 0xB #define PCI_SUBSYS_MASK GENMASK(15, 12) /** diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index 755697740038..31f11b77ab66 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -166,6 +166,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, i2c->roff.sw_twsi = 0x1000; i2c->roff.twsi_int = 0x1010; i2c->roff.sw_twsi_ext = 0x1018; + i2c->roff.mode = 0x1038; i2c->dev = dev; pci_set_drvdata(pdev, i2c); @@ -210,7 +211,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, * For OcteonTX2 chips, set reference frequency to 100MHz * as refclk_src in TWSI_MODE register defaults to 100MHz. */ - if (octeon_i2c_is_otx2(pdev)) + if (octeon_i2c_is_otx2(pdev) && IS_LS_FREQ(i2c->twsi_freq)) i2c->sys_freq = OTX2_REF_FREQ_DEFAULT; octeon_i2c_set_clock(i2c); -- cgit v1.2.3 From 0b042c72d90de2f53d6d6d768158614f4b717b16 Mon Sep 17 00:00:00 2001 From: Piyush Malgujar Date: Tue, 23 Apr 2024 00:46:06 -0700 Subject: i2c: octeon: Add platform prefix to macros The macros for TWSI register's offset are generically named, rename them to be platform specific macros by adding 'OCTEON_REG' as prefix. Signed-off-by: Piyush Malgujar Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-octeon-core.c | 36 ++++++++++++++++++------------------ drivers/i2c/busses/i2c-octeon-core.h | 26 +++++++++++++------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 86be597866f8..76a5ec100d30 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -85,7 +85,7 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) { - return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0; + return (__raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)) & SW_TWSI_V) == 0; } static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) @@ -185,10 +185,10 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) /* * This is ugly... in HLC mode the status is not in the status register - * but in the lower 8 bits of SW_TWSI. + * but in the lower 8 bits of OCTEON_REG_SW_TWSI. */ if (i2c->hlc_enabled) - stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + stat = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); else stat = octeon_i2c_stat_read(i2c); @@ -424,12 +424,12 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) else cmd |= SW_TWSI_OP_7; - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -437,7 +437,7 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[0].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -474,15 +474,15 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) ext |= (u64)msgs[0].buf[j] << (8 * i); - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); } - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -515,19 +515,19 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs cmd |= SW_TWSI_EIA; ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT; - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); } else { cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; } octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -535,7 +535,7 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[1].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -582,16 +582,16 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg set_ext = true; } if (set_ext) - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -737,13 +737,13 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) if (is_plat_otx2) { u64 mode; - mode = __raw_readq(i2c->twsi_base + MODE(i2c)); + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); /* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */ if (!IS_LS_FREQ(i2c->twsi_freq)) mode |= TWSX_MODE_HS_MASK; else mode &= ~TWSX_MODE_HS_MASK; - octeon_i2c_writeq_flush(mode, i2c->twsi_base + MODE(i2c)); + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); } } diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 94c4401a4a56..39481e23e36f 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -97,10 +97,10 @@ struct octeon_i2c_reg_offset { unsigned int mode; }; -#define SW_TWSI(x) (x->roff.sw_twsi) -#define TWSI_INT(x) (x->roff.twsi_int) -#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext) -#define MODE(x) ((x)->roff.mode) +#define OCTEON_REG_SW_TWSI(x) ((x)->roff.sw_twsi) +#define OCTEON_REG_TWSI_INT(x) ((x)->roff.twsi_int) +#define OCTEON_REG_SW_TWSI_EXT(x) ((x)->roff.sw_twsi_ext) +#define OCTEON_REG_MODE(x) ((x)->roff.mode) /* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */ #define TWSX_MODE_REFCLK_SRC BIT(4) @@ -143,16 +143,16 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) * @eop_reg: Register selector * @data: Value to be written * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + * The I2C core registers are accessed indirectly via the OCTEON_REG_SW_TWSI CSR. */ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) { int tries = 1000; u64 tmp; - __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c)); + __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if (--tries < 0) return; } while ((tmp & SW_TWSI_V) != 0); @@ -178,9 +178,9 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, int tries = 1000; u64 tmp; - __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c)); + __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if (--tries < 0) { /* signal that the returned data is invalid */ if (error) @@ -200,24 +200,24 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL) /** - * octeon_i2c_read_int - read the TWSI_INT register + * octeon_i2c_read_int - read the OCTEON_REG_TWSI_INT register * @i2c: The struct octeon_i2c * * Returns the value of the register. */ static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c) { - return __raw_readq(i2c->twsi_base + TWSI_INT(i2c)); + return __raw_readq(i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c)); } /** - * octeon_i2c_write_int - write the TWSI_INT register + * octeon_i2c_write_int - write the OCTEON_REG_TWSI_INT register * @i2c: The struct octeon_i2c * @data: Value to be written */ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) { - octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c)); + octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c)); } #define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000) -- cgit v1.2.3 From b9960b902f42c80ef436bf172666f20acbda32ac Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Tue, 23 Apr 2024 00:46:07 -0700 Subject: i2c: octeon: Handle watchdog timeout Add watchdog timeout handling to cater to the unhandled warnings seen during validation on boards with different I2C slaves. This status code reflects the state that controller couldn't receive any response from slave while being in non-idle state and HW recommends to reset before any further bus access. Signed-off-by: Suneel Garapati Signed-off-by: Piyush Malgujar Acked-by: Andi Shyti Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-octeon-core.c | 8 ++++++++ drivers/i2c/busses/i2c-octeon-core.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 76a5ec100d30..5b7b942141e7 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -182,6 +182,7 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) { u8 stat; + u64 mode; /* * This is ugly... in HLC mode the status is not in the status register @@ -244,6 +245,13 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) case STAT_RXADDR_NAK: case STAT_AD2W_NAK: return -ENXIO; + + case STAT_WDOG_TOUT: + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); + /* Set BUS_MON_RST to reset bus monitor */ + mode |= BUS_MON_RST_MASK; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); + return -EIO; default: dev_err(i2c->dev, "unhandled state: %d\n", stat); return -EIO; diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 39481e23e36f..7af01864da75 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -73,6 +73,7 @@ #define STAT_SLAVE_ACK 0xC8 #define STAT_AD2W_ACK 0xD0 #define STAT_AD2W_NAK 0xD8 +#define STAT_WDOG_TOUT 0xF0 #define STAT_IDLE 0xF8 /* TWSI_INT values */ @@ -107,6 +108,9 @@ struct octeon_i2c_reg_offset { #define TWSX_MODE_HS_MODE BIT(0) #define TWSX_MODE_HS_MASK (TWSX_MODE_REFCLK_SRC | TWSX_MODE_HS_MODE) +/* Set BUS_MON_RST to reset bus monitor */ +#define BUS_MON_RST_MASK BIT(3) + struct octeon_i2c { wait_queue_head_t queue; struct i2c_adapter adap; -- cgit v1.2.3 From 53e3d528ba723c8fd5bf968f517c9bc6a369f3ea Mon Sep 17 00:00:00 2001 From: Piyush Malgujar Date: Tue, 23 Apr 2024 00:46:08 -0700 Subject: i2c: thunderx: Adding ioclk support Read the ioclk property as reference clock if sclk not present in acpi table to make it SOC agnostic. In case, it's not populated from dts/acpi table, use the default clock of 800 MHz which is optimal in either case of sclk/ioclk. Signed-off-by: Piyush Malgujar Acked-by: Andi Shyti Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-thunderx-pcidrv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index 31f11b77ab66..32d0e3930b67 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -27,7 +27,7 @@ #define PCI_DEVICE_ID_THUNDER_TWSI 0xa012 -#define SYS_FREQ_DEFAULT 700000000 +#define SYS_FREQ_DEFAULT 800000000 #define OTX2_REF_FREQ_DEFAULT 100000000 #define TWSI_INT_ENA_W1C 0x1028 @@ -100,7 +100,8 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) i2c->sys_freq = clk_get_rate(i2c->clk); } else { /* ACPI */ - device_property_read_u32(dev, "sclk", &i2c->sys_freq); + if (device_property_read_u32(dev, "sclk", &i2c->sys_freq)) + device_property_read_u32(dev, "ioclk", &i2c->sys_freq); } skip: -- cgit v1.2.3 From 8525205fd51f543cdf92f6c9aa65a9720cda9513 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:43 +0800 Subject: i2c: wmt: create wmt_i2c_init for general init Some common initialization actions are put in the function wmt_i2c_init(), which is convenient to share with zhaoxin. Reviewed-by: Andi Shyti Reviewed-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-wmt.c | 65 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 198afee5233c..76ede433f65c 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -109,7 +109,7 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) unsigned long wait_result; wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); + msecs_to_jiffies(500)); if (!wait_result) return -ETIMEDOUT; @@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data) return IRQ_HANDLED; } +static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +{ + int err; + struct wmt_i2c_dev *i2c_dev; + struct device_node *np = pdev->dev.of_node; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) + return -EINVAL; + + err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, + 0, pdev->name, i2c_dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq %i\n", i2c_dev->irq); + + i2c_dev->dev = &pdev->dev; + init_completion(&i2c_dev->complete); + platform_set_drvdata(pdev, i2c_dev); + + *pi2c_dev = i2c_dev; + return 0; +} + static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) { int err; @@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev) int err; u32 clk_rate; - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) - return -ENOMEM; - - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); - - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) { - dev_err(&pdev->dev, "irq missing or invalid\n"); - return -EINVAL; - } + err = wmt_i2c_init(pdev, &i2c_dev); + if (err) + return err; i2c_dev->clk = of_clk_get(np, 0); if (IS_ERR(i2c_dev->clk)) { @@ -348,18 +370,9 @@ static int wmt_i2c_probe(struct platform_device *pdev) } err = of_property_read_u32(np, "clock-frequency", &clk_rate); - if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ)) + if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) i2c_dev->tcr = TCR_FAST_MODE; - i2c_dev->dev = &pdev->dev; - - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0, - "i2c", i2c_dev); - if (err) { - dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq); - return err; - } - adap = &i2c_dev->adapter; i2c_set_adapdata(adap, i2c_dev); strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); @@ -368,8 +381,6 @@ static int wmt_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - init_completion(&i2c_dev->complete); - err = wmt_i2c_reset_hardware(i2c_dev); if (err) { dev_err(&pdev->dev, "error initializing hardware\n"); @@ -380,8 +391,6 @@ static int wmt_i2c_probe(struct platform_device *pdev) if (err) goto err_disable_clk; - platform_set_drvdata(pdev, i2c_dev); - return 0; err_disable_clk: -- cgit v1.2.3 From 5acd48fa72ad16b824a9117254ce48ed69c914e8 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:44 +0800 Subject: i2c: wmt: split out common files Since the I2C IP of both wmt and zhaoxin originates from VIA, it is better to separate the common code first. The common driver is named as i2c-viai2c-common.c. Old i2c-wmt.c renamed to i2c-viai2c-wmt.c. The MAINTAINERS file will be updated accordingly in upcoming commits. Reviewed-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- MAINTAINERS | 2 +- drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++++++ drivers/i2c/busses/i2c-viai2c-common.h | 71 ++++++ drivers/i2c/busses/i2c-viai2c-wmt.c | 148 ++++++++++++ drivers/i2c/busses/i2c-wmt.c | 430 --------------------------------- 6 files changed, 442 insertions(+), 431 deletions(-) create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c delete mode 100644 drivers/i2c/busses/i2c-wmt.c diff --git a/MAINTAINERS b/MAINTAINERS index 75554f93e555..a3491d1aa7c3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3017,7 +3017,7 @@ S: Orphan F: Documentation/devicetree/bindings/i2c/i2c-wmt.txt F: arch/arm/mach-vt8500/ F: drivers/clocksource/timer-vt8500.c -F: drivers/i2c/busses/i2c-wmt.c +F: drivers/i2c/busses/i2c-viai2c-wmt.c F: drivers/mmc/host/wmt-sdmmc.c F: drivers/pwm/pwm-vt8500.c F: drivers/rtc/rtc-vt8500.c diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index aa0ee8ecd6f2..63c7bbad8134 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -118,6 +118,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 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c new file mode 100644 index 000000000000..b36a5d902990 --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include "i2c-viai2c-common.h" + +int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) +{ + unsigned long timeout; + + timeout = jiffies + WMT_I2C_TIMEOUT; + while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); + return -EBUSY; + } + msleep(20); + } + + return 0; +} + +int wmt_check_status(struct wmt_i2c_dev *i2c_dev) +{ + int ret = 0; + unsigned long wait_result; + + wait_result = wait_for_completion_timeout(&i2c_dev->complete, + msecs_to_jiffies(500)); + if (!wait_result) + return -ETIMEDOUT; + + if (i2c_dev->cmd_status & ISR_NACK_ADDR) + ret = -EIO; + + if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) + ret = -ETIMEDOUT; + + return ret; +} + +static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last) +{ + u16 val, tcr_val = i2c_dev->tcr; + int ret; + int xfer_len = 0; + + if (pmsg->len == 0) { + /* + * We still need to run through the while (..) once, so + * start at -1 and break out early from the loop + */ + xfer_len = -1; + writew(0, i2c_dev->base + REG_CDR); + } else { + writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); + } + + if (!(pmsg->flags & I2C_M_NOSTART)) { + val = readw(i2c_dev->base + REG_CR); + val &= ~CR_TX_END; + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + reinit_completion(&i2c_dev->complete); + + tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + xfer_len++; + + val = readw(i2c_dev->base + REG_CSR); + if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { + dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); + return -EIO; + } + + if (pmsg->len == 0) { + val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; + writew(val, i2c_dev->base + REG_CR); + break; + } + + if (xfer_len == pmsg->len) { + if (last != 1) + writew(CR_ENABLE, i2c_dev->base + REG_CR); + } else { + writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + + REG_CDR); + writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); + } + } + + return 0; +} + +static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) +{ + u16 val, tcr_val = i2c_dev->tcr; + int ret; + u32 xfer_len = 0; + + val = readw(i2c_dev->base + REG_CR); + val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); + + if (!(pmsg->flags & I2C_M_NOSTART)) + val |= CR_CPU_RDY; + + if (pmsg->len == 1) + val |= CR_TX_NEXT_NO_ACK; + + writew(val, i2c_dev->base + REG_CR); + + reinit_completion(&i2c_dev->complete); + + tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; + xfer_len++; + + val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; + if (xfer_len == pmsg->len - 1) + val |= CR_TX_NEXT_NO_ACK; + writew(val, i2c_dev->base + REG_CR); + } + + return 0; +} + +int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + + for (i = 0; ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + if (!(pmsg->flags & I2C_M_NOSTART)) { + ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + if (ret < 0) + return ret; + } + + if (pmsg->flags & I2C_M_RD) + ret = wmt_i2c_read(i2c_dev, pmsg); + else + ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); + } + + return (ret < 0) ? ret : i; +} + +static irqreturn_t wmt_i2c_isr(int irq, void *data) +{ + struct wmt_i2c_dev *i2c_dev = data; + + /* save the status and write-clear it */ + i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); + writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); + + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +{ + int err; + struct wmt_i2c_dev *i2c_dev; + struct device_node *np = pdev->dev.of_node; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) + return -ENOMEM; + + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c_dev->base)) + return PTR_ERR(i2c_dev->base); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) + return -EINVAL; + + err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, + 0, pdev->name, i2c_dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq %i\n", i2c_dev->irq); + + i2c_dev->dev = &pdev->dev; + init_completion(&i2c_dev->complete); + platform_set_drvdata(pdev, i2c_dev); + + *pi2c_dev = i2c_dev; + return 0; +} diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h new file mode 100644 index 000000000000..fcff8e4456eb --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __I2C_VIAI2C_COMMON_H_ +#define __I2C_VIAI2C_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CR 0x00 +#define REG_TCR 0x02 +#define REG_CSR 0x04 +#define REG_ISR 0x06 +#define REG_IMR 0x08 +#define REG_CDR 0x0A +#define REG_TR 0x0C +#define REG_MCR 0x0E + +/* REG_CR Bit fields */ +#define CR_TX_NEXT_ACK 0x0000 +#define CR_ENABLE 0x0001 +#define CR_TX_NEXT_NO_ACK 0x0002 +#define CR_TX_END 0x0004 +#define CR_CPU_RDY 0x0008 +#define SLAV_MODE_SEL 0x8000 + +/* REG_TCR Bit fields */ +#define TCR_STANDARD_MODE 0x0000 +#define TCR_MASTER_WRITE 0x0000 +#define TCR_HS_MODE 0x2000 +#define TCR_MASTER_READ 0x4000 +#define TCR_FAST_MODE 0x8000 +#define TCR_SLAVE_ADDR_MASK 0x007F + +/* REG_ISR Bit fields */ +#define ISR_NACK_ADDR 0x0001 +#define ISR_BYTE_END 0x0002 +#define ISR_SCL_TIMEOUT 0x0004 +#define ISR_WRITE_ALL 0x0007 + +/* REG_IMR Bit fields */ +#define IMR_ENABLE_ALL 0x0007 + +/* REG_CSR Bit fields */ +#define CSR_RCV_NOT_ACK 0x0001 +#define CSR_RCV_ACK_MASK 0x0001 +#define CSR_READY_MASK 0x0002 + +#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) + +struct wmt_i2c_dev { + struct i2c_adapter adapter; + struct completion complete; + struct device *dev; + void __iomem *base; + struct clk *clk; + u16 tcr; + int irq; + u16 cmd_status; +}; + +int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev); +int wmt_check_status(struct wmt_i2c_dev *i2c_dev); +int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); +int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev); + +#endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c new file mode 100644 index 000000000000..3125374cc2c0 --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Wondermedia I2C Master Mode Driver + * + * Copyright (C) 2012 Tony Prisk + * + * Derived from GPLv2+ licensed source: + * - Copyright (C) 2008 WonderMedia Technologies, Inc. + */ + +#include +#include +#include +#include "i2c-viai2c-common.h" + +#define REG_SLAVE_CR 0x10 +#define REG_SLAVE_SR 0x12 +#define REG_SLAVE_ISR 0x14 +#define REG_SLAVE_IMR 0x16 +#define REG_SLAVE_DR 0x18 +#define REG_SLAVE_TR 0x1A + +/* REG_TR */ +#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) +#define TR_STD 0x0064 +#define TR_HS 0x0019 + +/* REG_MCR */ +#define MCR_APB_96M 7 +#define MCR_APB_166M 12 + +static u32 wmt_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm wmt_i2c_algo = { + .master_xfer = wmt_i2c_xfer, + .functionality = wmt_i2c_func, +}; + +static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) +{ + int err; + + err = clk_prepare_enable(i2c_dev->clk); + if (err) { + dev_err(i2c_dev->dev, "failed to enable clock\n"); + return err; + } + + err = clk_set_rate(i2c_dev->clk, 20000000); + if (err) { + dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); + clk_disable_unprepare(i2c_dev->clk); + return err; + } + + writew(0, i2c_dev->base + REG_CR); + writew(MCR_APB_166M, i2c_dev->base + REG_MCR); + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); + writew(CR_ENABLE, i2c_dev->base + REG_CR); + readw(i2c_dev->base + REG_CSR); /* read clear */ + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + + if (i2c_dev->tcr == TCR_FAST_MODE) + writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + else + writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); + + return 0; +} + +static int wmt_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct wmt_i2c_dev *i2c_dev; + struct i2c_adapter *adap; + int err; + u32 clk_rate; + + err = wmt_i2c_init(pdev, &i2c_dev); + if (err) + return err; + + i2c_dev->clk = of_clk_get(np, 0); + if (IS_ERR(i2c_dev->clk)) { + dev_err(&pdev->dev, "unable to request clock\n"); + return PTR_ERR(i2c_dev->clk); + } + + err = of_property_read_u32(np, "clock-frequency", &clk_rate); + if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) + i2c_dev->tcr = TCR_FAST_MODE; + + adap = &i2c_dev->adapter; + i2c_set_adapdata(adap, i2c_dev); + strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->algo = &wmt_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + err = wmt_i2c_reset_hardware(i2c_dev); + if (err) { + dev_err(&pdev->dev, "error initializing hardware\n"); + return err; + } + + err = i2c_add_adapter(adap); + if (err) + /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ + clk_disable_unprepare(i2c_dev->clk); + + return err; +} + +static void wmt_i2c_remove(struct platform_device *pdev) +{ + struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + /* Disable interrupts, clock and delete adapter */ + writew(0, i2c_dev->base + REG_IMR); + clk_disable_unprepare(i2c_dev->clk); + i2c_del_adapter(&i2c_dev->adapter); +} + +static const struct of_device_id wmt_i2c_dt_ids[] = { + { .compatible = "wm,wm8505-i2c" }, + { /* Sentinel */ }, +}; + +static struct platform_driver wmt_i2c_driver = { + .probe = wmt_i2c_probe, + .remove_new = wmt_i2c_remove, + .driver = { + .name = "wmt-i2c", + .of_match_table = wmt_i2c_dt_ids, + }, +}; + +module_platform_driver(wmt_i2c_driver); + +MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); +MODULE_AUTHOR("Tony Prisk "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c deleted file mode 100644 index 76ede433f65c..000000000000 --- a/drivers/i2c/busses/i2c-wmt.c +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Wondermedia I2C Master Mode Driver - * - * Copyright (C) 2012 Tony Prisk - * - * Derived from GPLv2+ licensed source: - * - Copyright (C) 2008 WonderMedia Technologies, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REG_CR 0x00 -#define REG_TCR 0x02 -#define REG_CSR 0x04 -#define REG_ISR 0x06 -#define REG_IMR 0x08 -#define REG_CDR 0x0A -#define REG_TR 0x0C -#define REG_MCR 0x0E -#define REG_SLAVE_CR 0x10 -#define REG_SLAVE_SR 0x12 -#define REG_SLAVE_ISR 0x14 -#define REG_SLAVE_IMR 0x16 -#define REG_SLAVE_DR 0x18 -#define REG_SLAVE_TR 0x1A - -/* REG_CR Bit fields */ -#define CR_TX_NEXT_ACK 0x0000 -#define CR_ENABLE 0x0001 -#define CR_TX_NEXT_NO_ACK 0x0002 -#define CR_TX_END 0x0004 -#define CR_CPU_RDY 0x0008 -#define SLAV_MODE_SEL 0x8000 - -/* REG_TCR Bit fields */ -#define TCR_STANDARD_MODE 0x0000 -#define TCR_MASTER_WRITE 0x0000 -#define TCR_HS_MODE 0x2000 -#define TCR_MASTER_READ 0x4000 -#define TCR_FAST_MODE 0x8000 -#define TCR_SLAVE_ADDR_MASK 0x007F - -/* REG_ISR Bit fields */ -#define ISR_NACK_ADDR 0x0001 -#define ISR_BYTE_END 0x0002 -#define ISR_SCL_TIMEOUT 0x0004 -#define ISR_WRITE_ALL 0x0007 - -/* REG_IMR Bit fields */ -#define IMR_ENABLE_ALL 0x0007 - -/* REG_CSR Bit fields */ -#define CSR_RCV_NOT_ACK 0x0001 -#define CSR_RCV_ACK_MASK 0x0001 -#define CSR_READY_MASK 0x0002 - -/* REG_TR */ -#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) -#define TR_STD 0x0064 -#define TR_HS 0x0019 - -/* REG_MCR */ -#define MCR_APB_96M 7 -#define MCR_APB_166M 12 - -#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) - -struct wmt_i2c_dev { - struct i2c_adapter adapter; - struct completion complete; - struct device *dev; - void __iomem *base; - struct clk *clk; - u16 tcr; - int irq; - u16 cmd_status; -}; - -static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) -{ - unsigned long timeout; - - timeout = jiffies + WMT_I2C_TIMEOUT; - while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { - if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); - return -EBUSY; - } - msleep(20); - } - - return 0; -} - -static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) -{ - int ret = 0; - unsigned long wait_result; - - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - if (!wait_result) - return -ETIMEDOUT; - - if (i2c_dev->cmd_status & ISR_NACK_ADDR) - ret = -EIO; - - if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) - ret = -ETIMEDOUT; - - return ret; -} - -static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, - int last) -{ - u16 val, tcr_val = i2c_dev->tcr; - int ret; - int xfer_len = 0; - - if (pmsg->len == 0) { - /* - * We still need to run through the while (..) once, so - * start at -1 and break out early from the loop - */ - xfer_len = -1; - writew(0, i2c_dev->base + REG_CDR); - } else { - writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); - } - - if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - reinit_completion(&i2c_dev->complete); - - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - xfer_len++; - - val = readw(i2c_dev->base + REG_CSR); - if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { - dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); - return -EIO; - } - - if (pmsg->len == 0) { - val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; - writew(val, i2c_dev->base + REG_CR); - break; - } - - if (xfer_len == pmsg->len) { - if (last != 1) - writew(CR_ENABLE, i2c_dev->base + REG_CR); - } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + - REG_CDR); - writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); - } - } - - return 0; -} - -static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) -{ - u16 val, tcr_val = i2c_dev->tcr; - int ret; - u32 xfer_len = 0; - - val = readw(i2c_dev->base + REG_CR); - val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); - - if (!(pmsg->flags & I2C_M_NOSTART)) - val |= CR_CPU_RDY; - - if (pmsg->len == 1) - val |= CR_TX_NEXT_NO_ACK; - - writew(val, i2c_dev->base + REG_CR); - - reinit_completion(&i2c_dev->complete); - - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; - xfer_len++; - - val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; - if (xfer_len == pmsg->len - 1) - val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - } - - return 0; -} - -static int wmt_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], - int num) -{ - struct i2c_msg *pmsg; - int i; - int ret = 0; - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - - for (i = 0; ret >= 0 && i < num; i++) { - pmsg = &msgs[i]; - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - - if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(i2c_dev, pmsg); - else - ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); - } - - return (ret < 0) ? ret : i; -} - -static u32 wmt_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; -} - -static const struct i2c_algorithm wmt_i2c_algo = { - .master_xfer = wmt_i2c_xfer, - .functionality = wmt_i2c_func, -}; - -static irqreturn_t wmt_i2c_isr(int irq, void *data) -{ - struct wmt_i2c_dev *i2c_dev = data; - - /* save the status and write-clear it */ - i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); - writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); - - complete(&i2c_dev->complete); - - return IRQ_HANDLED; -} - -static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) -{ - int err; - struct wmt_i2c_dev *i2c_dev; - struct device_node *np = pdev->dev.of_node; - - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) - return -ENOMEM; - - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); - - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) - return -EINVAL; - - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, - 0, pdev->name, i2c_dev); - if (err) - return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c_dev->irq); - - i2c_dev->dev = &pdev->dev; - init_completion(&i2c_dev->complete); - platform_set_drvdata(pdev, i2c_dev); - - *pi2c_dev = i2c_dev; - return 0; -} - -static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) -{ - int err; - - err = clk_prepare_enable(i2c_dev->clk); - if (err) { - dev_err(i2c_dev->dev, "failed to enable clock\n"); - return err; - } - - err = clk_set_rate(i2c_dev->clk, 20000000); - if (err) { - dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); - clk_disable_unprepare(i2c_dev->clk); - return err; - } - - writew(0, i2c_dev->base + REG_CR); - writew(MCR_APB_166M, i2c_dev->base + REG_MCR); - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); - writew(CR_ENABLE, i2c_dev->base + REG_CR); - readw(i2c_dev->base + REG_CSR); /* read clear */ - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - - if (i2c_dev->tcr == TCR_FAST_MODE) - writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); - else - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); - - return 0; -} - -static int wmt_i2c_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct wmt_i2c_dev *i2c_dev; - struct i2c_adapter *adap; - int err; - u32 clk_rate; - - err = wmt_i2c_init(pdev, &i2c_dev); - if (err) - return err; - - i2c_dev->clk = of_clk_get(np, 0); - if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "unable to request clock\n"); - return PTR_ERR(i2c_dev->clk); - } - - err = of_property_read_u32(np, "clock-frequency", &clk_rate); - if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) - i2c_dev->tcr = TCR_FAST_MODE; - - adap = &i2c_dev->adapter; - i2c_set_adapdata(adap, i2c_dev); - strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); - adap->owner = THIS_MODULE; - adap->algo = &wmt_i2c_algo; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; - - err = wmt_i2c_reset_hardware(i2c_dev); - if (err) { - dev_err(&pdev->dev, "error initializing hardware\n"); - return err; - } - - err = i2c_add_adapter(adap); - if (err) - goto err_disable_clk; - - return 0; - -err_disable_clk: - clk_disable_unprepare(i2c_dev->clk); - return err; -} - -static void wmt_i2c_remove(struct platform_device *pdev) -{ - struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - - /* Disable interrupts, clock and delete adapter */ - writew(0, i2c_dev->base + REG_IMR); - clk_disable_unprepare(i2c_dev->clk); - i2c_del_adapter(&i2c_dev->adapter); -} - -static const struct of_device_id wmt_i2c_dt_ids[] = { - { .compatible = "wm,wm8505-i2c" }, - { /* Sentinel */ }, -}; - -static struct platform_driver wmt_i2c_driver = { - .probe = wmt_i2c_probe, - .remove_new = wmt_i2c_remove, - .driver = { - .name = "wmt-i2c", - .of_match_table = wmt_i2c_dt_ids, - }, -}; - -module_platform_driver(wmt_i2c_driver); - -MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); -MODULE_AUTHOR("Tony Prisk "); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); -- cgit v1.2.3 From 013fa161a4b584e416b98a31c6fda67753e9d7b8 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:45 +0800 Subject: i2c: wmt: rename something 1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename common registers, functions, and variable names to follow the VIAI2C_ and viai2c_ naming conventions for consistency and clarity. 2. rename i2c_dev to i2c, to shorten the length of a line. 3. rename wait_result to time_left, make it better to reflect the meaning of the value returned by wait_for_completion_timeout(). 4. remove TCR_MASTER_WRITE, its value is 0. Reviewed-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-viai2c-common.c | 157 ++++++++++++++++----------------- drivers/i2c/busses/i2c-viai2c-common.h | 70 +++++++-------- drivers/i2c/busses/i2c-viai2c-wmt.c | 62 ++++++------- 3 files changed, 143 insertions(+), 146 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index b36a5d902990..59901c53ad48 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -2,14 +2,14 @@ #include #include "i2c-viai2c-common.h" -int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) +int viai2c_wait_bus_not_busy(struct viai2c *i2c) { unsigned long timeout; - timeout = jiffies + WMT_I2C_TIMEOUT; - while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { + timeout = jiffies + VIAI2C_TIMEOUT; + while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) { if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); + dev_warn(i2c->dev, "timeout waiting for bus ready\n"); return -EBUSY; } msleep(20); @@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) return 0; } -int wmt_check_status(struct wmt_i2c_dev *i2c_dev) +int viai2c_check_status(struct viai2c *i2c) { int ret = 0; - unsigned long wait_result; + unsigned long time_left; - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - if (!wait_result) + time_left = wait_for_completion_timeout(&i2c->complete, + msecs_to_jiffies(500)); + if (!time_left) return -ETIMEDOUT; - if (i2c_dev->cmd_status & ISR_NACK_ADDR) + if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR) ret = -EIO; - if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) + if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT) ret = -ETIMEDOUT; return ret; } -static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last) +static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) { - u16 val, tcr_val = i2c_dev->tcr; + u16 val, tcr_val = i2c->tcr; int ret; int xfer_len = 0; @@ -49,173 +49,172 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int * start at -1 and break out early from the loop */ xfer_len = -1; - writew(0, i2c_dev->base + REG_CDR); + writew(0, i2c->base + VIAI2C_REG_CDR); } else { - writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); + writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); } if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~VIAI2C_CR_TX_END; + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } - reinit_completion(&i2c_dev->complete); + reinit_completion(&i2c->complete); - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); + tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK; - writew(tcr_val, i2c_dev->base + REG_TCR); + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); + ret = viai2c_check_status(i2c); if (ret) return ret; xfer_len++; - val = readw(i2c_dev->base + REG_CSR); - if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { - dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); + val = readw(i2c->base + VIAI2C_REG_CSR); + if (val & VIAI2C_CSR_RCV_NOT_ACK) { + dev_dbg(i2c->dev, "write RCV NACK error\n"); return -EIO; } if (pmsg->len == 0) { - val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; - writew(val, i2c_dev->base + REG_CR); + val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; + writew(val, i2c->base + VIAI2C_REG_CR); break; } if (xfer_len == pmsg->len) { if (last != 1) - writew(CR_ENABLE, i2c_dev->base + REG_CR); + writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + - REG_CDR); - writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); + writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR); + writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); } } return 0; } -static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg) +static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) { - u16 val, tcr_val = i2c_dev->tcr; + u16 val, tcr_val = i2c->tcr; int ret; u32 xfer_len = 0; - val = readw(i2c_dev->base + REG_CR); - val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK); + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); if (!(pmsg->flags & I2C_M_NOSTART)) - val |= CR_CPU_RDY; + val |= VIAI2C_CR_CPU_RDY; if (pmsg->len == 1) - val |= CR_TX_NEXT_NO_ACK; + val |= VIAI2C_CR_RX_END; - writew(val, i2c_dev->base + REG_CR); + writew(val, i2c->base + VIAI2C_REG_CR); - reinit_completion(&i2c_dev->complete); + reinit_completion(&i2c->complete); - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); + tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK); - writew(tcr_val, i2c_dev->base + REG_TCR); + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); } while (xfer_len < pmsg->len) { - ret = wmt_check_status(i2c_dev); + ret = viai2c_check_status(i2c); if (ret) return ret; - pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; + pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8; xfer_len++; - val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY; + val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; if (xfer_len == pmsg->len - 1) - val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); + val |= VIAI2C_CR_RX_END; + writew(val, i2c->base + VIAI2C_REG_CR); } return 0; } -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct i2c_msg *pmsg; int i; int ret = 0; - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + struct viai2c *i2c = i2c_get_adapdata(adap); for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + ret = viai2c_wait_bus_not_busy(i2c); if (ret < 0) return ret; } if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(i2c_dev, pmsg); + ret = viai2c_read(i2c, pmsg); else - ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num); + ret = viai2c_write(i2c, pmsg, (i + 1) == num); } return (ret < 0) ? ret : i; } -static irqreturn_t wmt_i2c_isr(int irq, void *data) +static irqreturn_t viai2c_isr(int irq, void *data) { - struct wmt_i2c_dev *i2c_dev = data; + struct viai2c *i2c = data; /* save the status and write-clear it */ - i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); - writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); + i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR); + writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR); - complete(&i2c_dev->complete); + complete(&i2c->complete); return IRQ_HANDLED; } -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev) +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) { int err; - struct wmt_i2c_dev *i2c_dev; + struct viai2c *i2c; struct device_node *np = pdev->dev.of_node; - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) return -ENOMEM; - i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) + i2c->irq = irq_of_parse_and_map(np, 0); + if (!i2c->irq) return -EINVAL; - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, - 0, pdev->name, i2c_dev); + err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr, + 0, pdev->name, i2c); if (err) return dev_err_probe(&pdev->dev, err, - "failed to request irq %i\n", i2c_dev->irq); + "failed to request irq %i\n", i2c->irq); - i2c_dev->dev = &pdev->dev; - init_completion(&i2c_dev->complete); - platform_set_drvdata(pdev, i2c_dev); + i2c->dev = &pdev->dev; + init_completion(&i2c->complete); + platform_set_drvdata(pdev, i2c); - *pi2c_dev = i2c_dev; + *pi2c = i2c; return 0; } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index fcff8e4456eb..28799e7e97f0 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -11,48 +11,46 @@ #include #include -#define REG_CR 0x00 -#define REG_TCR 0x02 -#define REG_CSR 0x04 -#define REG_ISR 0x06 -#define REG_IMR 0x08 -#define REG_CDR 0x0A -#define REG_TR 0x0C -#define REG_MCR 0x0E - /* REG_CR Bit fields */ -#define CR_TX_NEXT_ACK 0x0000 -#define CR_ENABLE 0x0001 -#define CR_TX_NEXT_NO_ACK 0x0002 -#define CR_TX_END 0x0004 -#define CR_CPU_RDY 0x0008 -#define SLAV_MODE_SEL 0x8000 +#define VIAI2C_REG_CR 0x00 +#define VIAI2C_CR_ENABLE BIT(0) +#define VIAI2C_CR_RX_END BIT(1) +#define VIAI2C_CR_TX_END BIT(2) +#define VIAI2C_CR_CPU_RDY BIT(3) +#define VIAI2C_CR_END_MASK GENMASK(2, 1) /* REG_TCR Bit fields */ -#define TCR_STANDARD_MODE 0x0000 -#define TCR_MASTER_WRITE 0x0000 -#define TCR_HS_MODE 0x2000 -#define TCR_MASTER_READ 0x4000 -#define TCR_FAST_MODE 0x8000 -#define TCR_SLAVE_ADDR_MASK 0x007F +#define VIAI2C_REG_TCR 0x02 +#define VIAI2C_TCR_HS_MODE BIT(13) +#define VIAI2C_TCR_READ BIT(14) +#define VIAI2C_TCR_FAST BIT(15) +#define VIAI2C_TCR_ADDR_MASK GENMASK(6, 0) + +/* REG_CSR Bit fields */ +#define VIAI2C_REG_CSR 0x04 +#define VIAI2C_CSR_RCV_NOT_ACK BIT(0) +#define VIAI2C_CSR_RCV_ACK_MASK BIT(0) +#define VIAI2C_CSR_READY_MASK BIT(1) /* REG_ISR Bit fields */ -#define ISR_NACK_ADDR 0x0001 -#define ISR_BYTE_END 0x0002 -#define ISR_SCL_TIMEOUT 0x0004 -#define ISR_WRITE_ALL 0x0007 +#define VIAI2C_REG_ISR 0x06 +#define VIAI2C_ISR_NACK_ADDR BIT(0) +#define VIAI2C_ISR_BYTE_END BIT(1) +#define VIAI2C_ISR_SCL_TIMEOUT BIT(2) +#define VIAI2C_ISR_MASK_ALL GENMASK(2, 0) /* REG_IMR Bit fields */ -#define IMR_ENABLE_ALL 0x0007 +#define VIAI2C_REG_IMR 0x08 +#define VIAI2C_IMR_BYTE BIT(1) +#define VIAI2C_IMR_ENABLE_ALL GENMASK(2, 0) -/* REG_CSR Bit fields */ -#define CSR_RCV_NOT_ACK 0x0001 -#define CSR_RCV_ACK_MASK 0x0001 -#define CSR_READY_MASK 0x0002 +#define VIAI2C_REG_CDR 0x0A +#define VIAI2C_REG_TR 0x0C +#define VIAI2C_REG_MCR 0x0E -#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) +#define VIAI2C_TIMEOUT (msecs_to_jiffies(1000)) -struct wmt_i2c_dev { +struct viai2c { struct i2c_adapter adapter; struct completion complete; struct device *dev; @@ -63,9 +61,9 @@ struct wmt_i2c_dev { u16 cmd_status; }; -int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev); -int wmt_check_status(struct wmt_i2c_dev *i2c_dev); -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev); +int viai2c_wait_bus_not_busy(struct viai2c *i2c); +int viai2c_check_status(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); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 3125374cc2c0..1e9db735e1fa 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm wmt_i2c_algo = { - .master_xfer = wmt_i2c_xfer, + .master_xfer = viai2c_xfer, .functionality = wmt_i2c_func, }; -static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) +static int wmt_i2c_reset_hardware(struct viai2c *i2c) { int err; - err = clk_prepare_enable(i2c_dev->clk); + err = clk_prepare_enable(i2c->clk); if (err) { - dev_err(i2c_dev->dev, "failed to enable clock\n"); + dev_err(i2c->dev, "failed to enable clock\n"); return err; } - err = clk_set_rate(i2c_dev->clk, 20000000); + err = clk_set_rate(i2c->clk, 20000000); if (err) { - dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); - clk_disable_unprepare(i2c_dev->clk); + dev_err(i2c->dev, "failed to set clock = 20Mhz\n"); + clk_disable_unprepare(i2c->clk); return err; } - writew(0, i2c_dev->base + REG_CR); - writew(MCR_APB_166M, i2c_dev->base + REG_MCR); - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); - writew(CR_ENABLE, i2c_dev->base + REG_CR); - readw(i2c_dev->base + REG_CSR); /* read clear */ - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + writew(0, i2c->base + VIAI2C_REG_CR); + writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR); + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); + writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR); + writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); + readw(i2c->base + VIAI2C_REG_CSR); /* read clear */ + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); - if (i2c_dev->tcr == TCR_FAST_MODE) - writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + if (i2c->tcr == VIAI2C_TCR_FAST) + writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR); else - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); + writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR); return 0; } @@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) static int wmt_i2c_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct wmt_i2c_dev *i2c_dev; + struct viai2c *i2c; struct i2c_adapter *adap; int err; u32 clk_rate; - err = wmt_i2c_init(pdev, &i2c_dev); + err = viai2c_init(pdev, &i2c); if (err) return err; - i2c_dev->clk = of_clk_get(np, 0); - if (IS_ERR(i2c_dev->clk)) { + i2c->clk = of_clk_get(np, 0); + if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "unable to request clock\n"); - return PTR_ERR(i2c_dev->clk); + return PTR_ERR(i2c->clk); } err = of_property_read_u32(np, "clock-frequency", &clk_rate); if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) - i2c_dev->tcr = TCR_FAST_MODE; + i2c->tcr = VIAI2C_TCR_FAST; - adap = &i2c_dev->adapter; - i2c_set_adapdata(adap, i2c_dev); + adap = &i2c->adapter; + i2c_set_adapdata(adap, i2c); strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); adap->owner = THIS_MODULE; adap->algo = &wmt_i2c_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - err = wmt_i2c_reset_hardware(i2c_dev); + err = wmt_i2c_reset_hardware(i2c); if (err) { dev_err(&pdev->dev, "error initializing hardware\n"); return err; @@ -111,19 +111,19 @@ static int wmt_i2c_probe(struct platform_device *pdev) err = i2c_add_adapter(adap); if (err) /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ - clk_disable_unprepare(i2c_dev->clk); + clk_disable_unprepare(i2c->clk); return err; } static void wmt_i2c_remove(struct platform_device *pdev) { - struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + struct viai2c *i2c = platform_get_drvdata(pdev); /* Disable interrupts, clock and delete adapter */ - writew(0, i2c_dev->base + REG_IMR); - clk_disable_unprepare(i2c_dev->clk); - i2c_del_adapter(&i2c_dev->adapter); + writew(0, i2c->base + VIAI2C_REG_IMR); + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adapter); } static const struct of_device_id wmt_i2c_dt_ids[] = { -- cgit v1.2.3 From 2e829ccc2779d4ea47050a2f41e7531a247a46e5 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:46 +0800 Subject: i2c: wmt: fix a bug when thread blocked During each byte access, the host performs clock stretching. To reduce the host performs clock stretching, move most of the per-msg processing to the interrupt context. Suggested-by: Wolfram Sang Reviewed-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-viai2c-common.c | 145 +++++++++++++++++---------------- drivers/i2c/busses/i2c-viai2c-common.h | 6 +- 2 files changed, 80 insertions(+), 71 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 59901c53ad48..1b39cf4f0d6c 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -18,37 +18,18 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c) return 0; } -int viai2c_check_status(struct viai2c *i2c) -{ - int ret = 0; - unsigned long time_left; - - time_left = wait_for_completion_timeout(&i2c->complete, - msecs_to_jiffies(500)); - if (!time_left) - return -ETIMEDOUT; - - if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR) - ret = -EIO; - - if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT) - ret = -ETIMEDOUT; - - return ret; -} - static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) { u16 val, tcr_val = i2c->tcr; - int ret; - int xfer_len = 0; + + i2c->last = last; if (pmsg->len == 0) { /* * We still need to run through the while (..) once, so * start at -1 and break out early from the loop */ - xfer_len = -1; + i2c->xfered_len = -1; writew(0, i2c->base + VIAI2C_REG_CDR); } else { writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); @@ -73,42 +54,15 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(val, i2c->base + VIAI2C_REG_CR); } - while (xfer_len < pmsg->len) { - ret = viai2c_check_status(i2c); - if (ret) - return ret; - - xfer_len++; - - val = readw(i2c->base + VIAI2C_REG_CSR); - if (val & VIAI2C_CSR_RCV_NOT_ACK) { - dev_dbg(i2c->dev, "write RCV NACK error\n"); - return -EIO; - } - - if (pmsg->len == 0) { - val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; - writew(val, i2c->base + VIAI2C_REG_CR); - break; - } - - if (xfer_len == pmsg->len) { - if (last != 1) - writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); - } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR); - writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); - } - } + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; - return 0; + return i2c->ret; } static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) { u16 val, tcr_val = i2c->tcr; - int ret; - u32 xfer_len = 0; val = readw(i2c->base + VIAI2C_REG_CR); val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); @@ -133,21 +87,10 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(val, i2c->base + VIAI2C_REG_CR); } - while (xfer_len < pmsg->len) { - ret = viai2c_check_status(i2c); - if (ret) - return ret; - - pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8; - xfer_len++; - - val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; - if (xfer_len == pmsg->len - 1) - val |= VIAI2C_CR_RX_END; - writew(val, i2c->base + VIAI2C_REG_CR); - } + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; - return 0; + return i2c->ret; } int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -165,6 +108,9 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return ret; } + i2c->msg = pmsg; + i2c->xfered_len = 0; + if (pmsg->flags & I2C_M_RD) ret = viai2c_read(i2c, pmsg); else @@ -174,15 +120,76 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) return (ret < 0) ? ret : i; } +/* + * Main process of the byte mode xfer + * + * Return value indicates whether the transfer is complete + * 1: all the data has been successfully transferred + * 0: there is still data that needs to be transferred + * -EIO: error occurred + */ +static int viai2c_irq_xfer(struct viai2c *i2c) +{ + u16 val; + struct i2c_msg *msg = i2c->msg; + u8 read = msg->flags & I2C_M_RD; + void __iomem *base = i2c->base; + + if (read) { + msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8; + + val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; + if (i2c->xfered_len == msg->len - 2) + val |= VIAI2C_CR_RX_END; + writew(val, base + VIAI2C_REG_CR); + } else { + val = readw(base + VIAI2C_REG_CSR); + if (val & VIAI2C_CSR_RCV_NOT_ACK) + return -EIO; + + /* I2C_SMBUS_QUICK */ + if (msg->len == 0) { + val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; + writew(val, base + VIAI2C_REG_CR); + return 1; + } + + if ((i2c->xfered_len + 1) == msg->len) { + if (!i2c->last) + writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + } else { + writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); + writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + } + } + + i2c->xfered_len++; + + return i2c->xfered_len == msg->len; +} + static irqreturn_t viai2c_isr(int irq, void *data) { struct viai2c *i2c = data; + u8 status; /* save the status and write-clear it */ - i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR); - writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR); + 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); - complete(&i2c->complete); + /* All the data has been successfully transferred or error occurred */ + if (i2c->ret) + complete(&i2c->complete); return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index 28799e7e97f0..c92e054ac7e7 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -58,11 +58,13 @@ struct viai2c { struct clk *clk; u16 tcr; int irq; - u16 cmd_status; + u16 xfered_len; + struct i2c_msg *msg; + int ret; + bool last; }; int viai2c_wait_bus_not_busy(struct viai2c *i2c); -int viai2c_check_status(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); -- cgit v1.2.3 From b06204c7d4f4a4059c16d20bd9eb618edad49aa1 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:47 +0800 Subject: i2c: wmt: add platform type VIAI2C_PLAT_WMT Enumeration variables are added to differentiate between different platforms. Acked-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-viai2c-common.c | 32 ++++++++++++++++++++------------ drivers/i2c/busses/i2c-viai2c-common.h | 7 ++++++- drivers/i2c/busses/i2c-viai2c-wmt.c | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 1b39cf4f0d6c..22a2e31e9c14 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -35,7 +35,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); } - if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { val = readw(i2c->base + VIAI2C_REG_CR); val &= ~VIAI2C_CR_TX_END; val |= VIAI2C_CR_CPU_RDY; @@ -48,7 +48,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (pmsg->flags & I2C_M_NOSTART) { + if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -67,7 +67,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) val = readw(i2c->base + VIAI2C_REG_CR); val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); - if (!(pmsg->flags & I2C_M_NOSTART)) + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) val |= VIAI2C_CR_CPU_RDY; if (pmsg->len == 1) @@ -81,7 +81,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (pmsg->flags & I2C_M_NOSTART) { + if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -102,7 +102,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; - if (!(pmsg->flags & I2C_M_NOSTART)) { + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { ret = viai2c_wait_bus_not_busy(i2c); if (ret < 0) return ret; @@ -155,7 +155,7 @@ static int viai2c_irq_xfer(struct viai2c *i2c) } if ((i2c->xfered_len + 1) == msg->len) { - if (!i2c->last) + if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last) writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); } else { writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); @@ -181,7 +181,7 @@ static irqreturn_t viai2c_isr(int irq, void *data) if (status & VIAI2C_ISR_NACK_ADDR) i2c->ret = -EIO; - if (status & VIAI2C_ISR_SCL_TIMEOUT) + if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT)) i2c->ret = -ETIMEDOUT; if (!i2c->ret) @@ -194,9 +194,10 @@ static irqreturn_t viai2c_isr(int irq, void *data) return IRQ_HANDLED; } -int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) +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; @@ -208,12 +209,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c) if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); - i2c->irq = irq_of_parse_and_map(np, 0); - if (!i2c->irq) - return -EINVAL; + if (plat == VIAI2C_PLAT_WMT) { + irq_flags = 0; + i2c->irq = irq_of_parse_and_map(np, 0); + if (!i2c->irq) + return -EINVAL; + } 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, - 0, pdev->name, i2c); + irq_flags, pdev->name, i2c); if (err) return dev_err_probe(&pdev->dev, err, "failed to request irq %i\n", i2c->irq); diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index c92e054ac7e7..cfe5ab2bd779 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -50,6 +50,10 @@ #define VIAI2C_TIMEOUT (msecs_to_jiffies(1000)) +enum { + VIAI2C_PLAT_WMT, +}; + struct viai2c { struct i2c_adapter adapter; struct completion complete; @@ -62,10 +66,11 @@ struct viai2c { struct i2c_msg *msg; int ret; bool last; + unsigned int platform; }; 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 viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 1e9db735e1fa..e1988f946026 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev) int err; u32 clk_rate; - err = viai2c_init(pdev, &i2c); + err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); if (err) return err; -- cgit v1.2.3 From a06b80e83011c996147e94a3bcd9c7387c14abd9 Mon Sep 17 00:00:00 2001 From: Hans Hu Date: Mon, 8 Apr 2024 10:54:48 +0800 Subject: i2c: add zhaoxin i2c controller driver Add Zhaoxin I2C controller driver. It provides the access to the i2c busses, which connects to the touchpad, eeprom, I2S, etc. Zhaoxin I2C controller has two separate busses, so may accommodate up to two I2C adapters. Those adapters are listed in the ACPI namespace with the IIC1D17 HID, and probed by a platform driver. The driver works with IRQ mode, and supports basic I2C features. Flags I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit the unsupported access. Acked-by: Wolfram Sang Signed-off-by: Hans Hu Signed-off-by: Andi Shyti --- MAINTAINERS | 8 + drivers/i2c/busses/Kconfig | 10 ++ drivers/i2c/busses/Makefile | 2 + drivers/i2c/busses/i2c-viai2c-common.c | 31 +++- drivers/i2c/busses/i2c-viai2c-common.h | 9 + drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 ++++++++++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 5 deletions(-) create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c diff --git a/MAINTAINERS b/MAINTAINERS index a3491d1aa7c3..0927ea8c36f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10258,6 +10258,14 @@ L: linux-i2c@vger.kernel.org F: Documentation/i2c/busses/i2c-ismt.rst F: drivers/i2c/busses/i2c-ismt.c +I2C/SMBUS ZHAOXIN DRIVER +M: Hans Hu +L: linux-i2c@vger.kernel.org +S: Maintained +W: https://www.zhaoxin.com +F: drivers/i2c/busses/i2c-viai2c-common.c +F: drivers/i2c/busses/i2c-viai2c-zhaoxin.c + I2C/SMBUS STUB DRIVER M: Jean Delvare L: linux-i2c@vger.kernel.org diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a5aff29c559d..fe6e8a1bb607 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -344,6 +344,16 @@ config I2C_VIAPRO if ACPI +config I2C_ZHAOXIN + tristate "Zhaoxin I2C Interface" + depends on PCI || COMPILE_TEST + help + If you say yes to this option, support will be included for the + ZHAOXIN I2C interface + + This driver can also be built as a module. If so, the module + will be called i2c-zhaoxin. + comment "ACPI drivers" config I2C_SCMI diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 63c7bbad8134..3d65934f5eb4 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -29,6 +29,8 @@ 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 # Mac SMBus host controller drivers obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c index 22a2e31e9c14..1844d13f1f79 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.c +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) return i2c->ret; } -static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) +static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first) { u16 val, tcr_val = i2c->tcr; @@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg) writew(tcr_val, i2c->base + VIAI2C_REG_TCR); - if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) { + if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) || + (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) { val = readw(i2c->base + VIAI2C_REG_CR); val |= VIAI2C_CR_CPU_RDY; writew(val, i2c->base + VIAI2C_REG_CR); @@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) int ret = 0; struct viai2c *i2c = i2c_get_adapdata(adap); + i2c->mode = VIAI2C_BYTE_MODE; for (i = 0; ret >= 0 && i < num; i++) { pmsg = &msgs[i]; if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { @@ -112,7 +114,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c->xfered_len = 0; if (pmsg->flags & I2C_M_RD) - ret = viai2c_read(i2c, pmsg); + ret = viai2c_read(i2c, pmsg, i == 0); else ret = viai2c_write(i2c, pmsg, (i + 1) == num); } @@ -157,6 +159,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c) if ((i2c->xfered_len + 1) == msg->len) { if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last) writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last) + writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR); } else { writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); @@ -168,6 +172,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; @@ -175,6 +184,9 @@ static irqreturn_t viai2c_isr(int irq, void *data) /* 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; @@ -184,8 +196,12 @@ static irqreturn_t viai2c_isr(int irq, void *data) if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT)) i2c->ret = -ETIMEDOUT; - if (!i2c->ret) - i2c->ret = viai2c_irq_xfer(i2c); + 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) @@ -214,6 +230,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) 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"); } diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h index cfe5ab2bd779..81e827c54434 100644 --- a/drivers/i2c/busses/i2c-viai2c-common.h +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -52,6 +52,12 @@ enum { VIAI2C_PLAT_WMT, + VIAI2C_PLAT_ZHAOXIN +}; + +enum { + VIAI2C_BYTE_MODE, + VIAI2C_FIFO_MODE }; struct viai2c { @@ -66,11 +72,14 @@ struct viai2c { struct i2c_msg *msg; int ret; bool last; + unsigned int mode; unsigned int platform; + void *pltfm_priv; }; 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); #endif diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c new file mode 100644 index 000000000000..7e3ac2a3e1fd --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation. + * All rights reserved. + */ + +#include +#include "i2c-viai2c-common.h" + +/* + * registers + */ +/* Zhaoxin specific register bit fields */ +/* REG_CR Bit fields */ +#define ZXI2C_CR_MST_RST BIT(7) +#define ZXI2C_CR_FIFO_MODE BIT(14) +/* REG_ISR/IMR Bit fields */ +#define ZXI2C_IRQ_FIFONACK BIT(4) +#define ZXI2C_IRQ_FIFOEND BIT(3) +#define ZXI2C_IRQ_MASK (VIAI2C_ISR_MASK_ALL \ + | ZXI2C_IRQ_FIFOEND \ + | ZXI2C_IRQ_FIFONACK) +/* Zhaoxin specific registers */ +#define ZXI2C_REG_CLK 0x10 +#define ZXI2C_CLK_50M BIT(0) +#define ZXI2C_REG_REV 0x11 +#define ZXI2C_REG_HCR 0x12 +#define ZXI2C_HCR_RST_FIFO GENMASK(1, 0) +#define ZXI2C_REG_HTDR 0x13 +#define ZXI2C_REG_HRDR 0x14 +#define ZXI2C_REG_HTLR 0x15 +#define ZXI2C_REG_HRLR 0x16 +#define ZXI2C_REG_HWCNTR 0x18 +#define ZXI2C_REG_HRCNTR 0x19 + +/* parameters Constants */ +#define ZXI2C_GOLD_FSTP_100K 0xF3 +#define ZXI2C_GOLD_FSTP_400K 0x38 +#define ZXI2C_GOLD_FSTP_1M 0x13 +#define ZXI2C_GOLD_FSTP_3400K 0x37 +#define ZXI2C_HS_MASTER_CODE (0x08 << 8) + +#define ZXI2C_FIFO_SIZE 32 + +struct viai2c_zhaoxin { + u8 hrv; + u16 tr; + u16 mcr; + u16 xfer_len; +}; + +/* 'irq == true' means in interrupt context */ +int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq) +{ + 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; + + 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); + + /* 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); + } + + 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; +} + +static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + u8 tmp; + int ret; + struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + void __iomem *base = i2c->base; + + ret = viai2c_wait_bus_not_busy(i2c); + if (ret) + return ret; + + tmp = ioread8(base + VIAI2C_REG_CR); + tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END); + + if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) { + /* enable fifo mode */ + iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable fifo irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR); + + i2c->msg = msgs; + i2c->mode = VIAI2C_FIFO_MODE; + priv->xfer_len = 0; + i2c->xfered_len = 0; + + viai2c_fifo_irq_xfer(i2c, 0); + + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; + + ret = i2c->ret; + } else { + /* enable byte mode */ + iowrite16(tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable byte irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR); + + ret = viai2c_xfer(adap, msgs, num); + if (ret == -ETIMEDOUT) + iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR); + } + /* dis interrupt */ + iowrite8(0, base + VIAI2C_REG_IMR); + + return ret; +} + +static u32 zxi2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm zxi2c_algorithm = { + .master_xfer = zxi2c_master_xfer, + .functionality = zxi2c_func, +}; + +static const struct i2c_adapter_quirks zxi2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ, +}; + +static const u32 zxi2c_speed_params_table[][3] = { + /* speed, ZXI2C_TCR, ZXI2C_FSTP */ + { I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K }, + { I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K }, + { I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M }, + { I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST, + ZXI2C_GOLD_FSTP_3400K }, +}; + +static void zxi2c_set_bus_speed(struct viai2c *i2c) +{ + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR); + iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK); + iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR); +} + +static void zxi2c_get_bus_speed(struct viai2c *i2c) +{ + u8 i, count; + u8 fstp; + const u32 *params; + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev); + + count = ARRAY_SIZE(zxi2c_speed_params_table); + for (i = 0; i < count; i++) + if (acpi_speed == zxi2c_speed_params_table[i][0]) + break; + /* if not found, use 400k as default */ + i = i < count ? i : 1; + + params = zxi2c_speed_params_table[i]; + fstp = ioread8(i2c->base + VIAI2C_REG_TR); + if (abs(fstp - params[2]) > 0x10) { + /* + * if BIOS setting value far from golden value, + * use golden value and warn user + */ + dev_warn(i2c->dev, "FW FSTP[%x] might cause wrong timings, dropped\n", fstp); + priv->tr = params[2] | 0xff00; + } else { + priv->tr = fstp | 0xff00; + } + + i2c->tcr = params[1]; + priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR); + /* for Hs-mode, use 0x80 as master code */ + if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ) + priv->mcr |= ZXI2C_HS_MASTER_CODE; + + dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0])); +} + +static int zxi2c_probe(struct platform_device *pdev) +{ + int error; + struct viai2c *i2c; + struct i2c_adapter *adap; + struct viai2c_zhaoxin *priv; + + error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN); + if (error) + return error; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + i2c->pltfm_priv = priv; + + zxi2c_get_bus_speed(i2c); + zxi2c_set_bus_speed(i2c); + + priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV); + + adap = &i2c->adapter; + adap->owner = THIS_MODULE; + adap->algo = &zxi2c_algorithm; + adap->quirks = &zxi2c_quirks; + adap->dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); + snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s", + dev_name(pdev->dev.parent), dev_name(i2c->dev)); + i2c_set_adapdata(adap, i2c); + + return devm_i2c_add_adapter(&pdev->dev, adap); +} + +static int __maybe_unused zxi2c_resume(struct device *dev) +{ + struct viai2c *i2c = dev_get_drvdata(dev); + + iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR); + zxi2c_set_bus_speed(i2c); + + return 0; +} + +static const struct dev_pm_ops zxi2c_pm = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume) +}; + +static const struct acpi_device_id zxi2c_acpi_match[] = { + {"IIC1D17", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match); + +static struct platform_driver zxi2c_driver = { + .probe = zxi2c_probe, + .driver = { + .name = "i2c_zhaoxin", + .acpi_match_table = zxi2c_acpi_match, + .pm = &zxi2c_pm, + }, +}; + +module_platform_driver(zxi2c_driver); + +MODULE_AUTHOR("HansHu@zhaoxin.com"); +MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b757eb090fbdac31e2f144492c17202d3cf41d9b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Apr 2024 14:13:18 +0200 Subject: i2c: i801: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout and turn the SMBus-specific termination message to debug. Signed-off-by: Wolfram Sang Reviewed-by: Jean Delvare Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-i801.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e577abc776c1..d2d2a6dbe29f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -399,9 +399,7 @@ static int i801_check_post(struct i801_priv *priv, int status) * If the SMBus is still busy, we give up */ if (unlikely(status < 0)) { - dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); /* try to stop the current command */ - dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); usleep_range(1000, 2000); outb_p(0, SMBHSTCNT(priv)); @@ -410,7 +408,7 @@ static int i801_check_post(struct i801_priv *priv, int status) status = inb_p(SMBHSTSTS(priv)); if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED)) - dev_err(&priv->pci_dev->dev, + dev_dbg(&priv->pci_dev->dev, "Failed terminating the transaction\n"); return -ETIMEDOUT; } -- cgit v1.2.3 From aaf20dbceb063760eb1c8beb5e6a11c5ebacd3d5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Apr 2024 14:13:19 +0200 Subject: i2c: ali1535: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Jean Delvare Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-ali1535.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 461eb23f9d47..9d7b4efe26ad 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -285,10 +285,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ - if (timeout > MAX_TIMEOUT) { + if (timeout > MAX_TIMEOUT) result = -ETIMEDOUT; - dev_err(&adap->dev, "SMBus Timeout!\n"); - } if (temp & ALI1535_STS_FAIL) { result = -EIO; @@ -313,10 +311,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) } /* check to see if the "command complete" indication is set */ - if (!(temp & ALI1535_STS_DONE)) { + if (!(temp & ALI1535_STS_DONE)) result = -ETIMEDOUT; - dev_err(&adap->dev, "Error: command never completed\n"); - } dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, " "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", -- cgit v1.2.3 From d178a2fc252d4790841f6c841ad5b43940c71a8f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Apr 2024 14:13:20 +0200 Subject: i2c: ali1563: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Jean Delvare Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-ali1563.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 307fb0666ecb..63897a89bb35 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -99,7 +99,6 @@ static int ali1563_transaction(struct i2c_adapter *a, int size) return 0; if (!timeout) { - dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n"); /* Issue 'kill' to host controller */ outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2); data = inb_p(SMB_HST_STS); -- cgit v1.2.3 From 5895a867bbdd7fb8a678baaf0c8746f592727edd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 23 Apr 2024 14:13:21 +0200 Subject: i2c: ali15x3: remove printout on handled timeouts I2C and SMBus timeouts are not something the user needs to be informed about on controller level. The client driver may know if that really is a problem and give more detailed information to the user. The controller should just pass this information upwards. Remove the printout. Signed-off-by: Wolfram Sang Reviewed-by: Jean Delvare Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-ali15x3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index d2fa30deb054..956e5020d71e 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -294,10 +294,8 @@ static int ali15x3_transaction(struct i2c_adapter *adap) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ - if (timeout > MAX_TIMEOUT) { + if (timeout > MAX_TIMEOUT) result = -ETIMEDOUT; - dev_err(&adap->dev, "SMBus Timeout!\n"); - } if (temp & ALI15X3_STS_TERM) { result = -EIO; -- cgit v1.2.3 From 571b90f5d43c8846bc33dded9366d972f4290bae Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:53 +0200 Subject: i2c: amd-mp2-plat: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-amd-mp2-plat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 112fe2bc5662..d3ac1c77a509 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -97,17 +97,17 @@ static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common) static int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev) { struct amd_i2c_common *i2c_common = &i2c_dev->common; - unsigned long timeout; + unsigned long time_left; - timeout = wait_for_completion_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->cmd_complete, + i2c_dev->adap.timeout); if ((i2c_common->reqcmd == i2c_read || i2c_common->reqcmd == i2c_write) && i2c_common->msg->len > 32) i2c_amd_dma_unmap(i2c_common); - if (timeout == 0) { + if (time_left == 0) { amd_mp2_rw_timeout(i2c_common); return -ETIMEDOUT; } -- cgit v1.2.3 From 4804a8b786c81bb9c6d3e749ff0a841fa1d7dba5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:54 +0200 Subject: i2c: digicolor: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Acked-by: Baruch Siach Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-digicolor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 3462f2bc0fa8..737604ae11fc 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -213,7 +213,7 @@ out: static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, int last) { - unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS); + unsigned long time_left = msecs_to_jiffies(TIMEOUT_MS); unsigned long flags; spin_lock_irqsave(&i2c->lock, flags); @@ -227,9 +227,9 @@ static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, dc_i2c_start_msg(i2c, first); spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->done, timeout); + time_left = wait_for_completion_timeout(&i2c->done, time_left); dc_i2c_set_irq(i2c, 0); - if (timeout == 0) { + if (time_left == 0) { i2c->state = STATE_IDLE; return -ETIMEDOUT; } -- cgit v1.2.3 From 9b238f0d5612a2f48b99696c9d24c22e5c4e617e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:55 +0200 Subject: i2c: exynos5: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-exynos5.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 385ef9d9e4d4..d8baca9b610c 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -763,7 +763,7 @@ static bool exynos5_i2c_poll_irqs_timeout(struct exynos5_i2c *i2c, static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, struct i2c_msg *msgs, int stop) { - unsigned long timeout; + unsigned long time_left; int ret; i2c->msg = msgs; @@ -775,13 +775,13 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, exynos5_i2c_message_start(i2c, stop); if (!i2c->atomic) - timeout = wait_for_completion_timeout(&i2c->msg_complete, - EXYNOS5_I2C_TIMEOUT); - else - timeout = exynos5_i2c_poll_irqs_timeout(i2c, + time_left = wait_for_completion_timeout(&i2c->msg_complete, EXYNOS5_I2C_TIMEOUT); + else + time_left = exynos5_i2c_poll_irqs_timeout(i2c, + EXYNOS5_I2C_TIMEOUT); - if (timeout == 0) + if (time_left == 0) ret = -ETIMEDOUT; else ret = i2c->state; -- cgit v1.2.3 From b557e267c543b1a1732841fa276f4630a85470d8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:56 +0200 Subject: i2c: hix5hd2: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-hix5hd2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 8e75515c3ca4..a47b9939fa2c 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -314,7 +314,7 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop) static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, struct i2c_msg *msgs, int stop) { - unsigned long timeout; + unsigned long time_left; int ret; priv->msg = msgs; @@ -327,9 +327,9 @@ static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, reinit_completion(&priv->msg_complete); hix5hd2_i2c_message_start(priv, stop); - timeout = wait_for_completion_timeout(&priv->msg_complete, - priv->adap.timeout); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&priv->msg_complete, + priv->adap.timeout); + if (time_left == 0) { priv->state = HIX5I2C_STAT_RW_ERR; priv->err = -ETIMEDOUT; dev_warn(priv->dev, "%s timeout=%d\n", -- cgit v1.2.3 From 8dacd79fec3cd86ddf6b8c87b0179c5b13250a9c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:57 +0200 Subject: i2c: imx-lpi2c: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Reviewed-by: Peng Fan Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-imx-lpi2c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 36e8f6196a87..0197786892a2 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -307,11 +307,11 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx) { - unsigned long timeout; + unsigned long time_left; - timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ); + time_left = wait_for_completion_timeout(&lpi2c_imx->complete, HZ); - return timeout ? 0 : -ETIMEDOUT; + return time_left ? 0 : -ETIMEDOUT; } static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) -- cgit v1.2.3 From c1f8f664678a50997dee8a92db4800f900711e73 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:58 +0200 Subject: i2c: omap: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-omap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 36bebef36740..30a5ea282a8b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -660,7 +660,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop, bool polling) { struct omap_i2c_dev *omap = i2c_get_adapdata(adap); - unsigned long timeout; + unsigned long time_left; u16 w; int ret; @@ -740,18 +740,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * into arbitration and we're currently unable to recover from it. */ if (!polling) { - timeout = wait_for_completion_timeout(&omap->cmd_complete, - OMAP_I2C_TIMEOUT); + time_left = wait_for_completion_timeout(&omap->cmd_complete, + OMAP_I2C_TIMEOUT); } else { do { omap_i2c_wait(omap); ret = omap_i2c_xfer_data(omap); } while (ret == -EAGAIN); - timeout = !ret; + time_left = !ret; } - if (timeout == 0) { + if (time_left == 0) { omap_i2c_reset(omap); __omap_i2c_init(omap); return -ETIMEDOUT; -- cgit v1.2.3 From 7ae38232ebc4dd19627c5a5c2cc797aa487fd511 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:35:59 +0200 Subject: i2c: st: use 'time_left' variable with wait_for_completion_timeout() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Reviewed-by: Uwe Kleine-König Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-st.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index dbb93394ff94..5e01fe3dbb63 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -647,7 +647,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, { struct st_i2c_client *c = &i2c_dev->client; u32 ctl, i2c, it; - unsigned long timeout; + unsigned long time_left; int ret; c->addr = i2c_8bit_addr_from_msg(msg); @@ -685,11 +685,11 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG); } - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = c->result; - if (!timeout) + if (!time_left) ret = -ETIMEDOUT; i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG; -- cgit v1.2.3 From 8839a8df93077bfb10710a1fd8ad8b7ac3ac2abe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:00 +0200 Subject: i2c: stm32f4: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-stm32f4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 859ac0cf7f6c..f8b12be6ef55 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -681,7 +681,7 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev, { struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg; void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1; - unsigned long timeout; + unsigned long time_left; u32 mask; int ret; @@ -706,11 +706,11 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev, stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START); } - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = f4_msg->result; - if (!timeout) + if (!time_left) ret = -ETIMEDOUT; return ret; -- cgit v1.2.3 From 197264d377b875dfc5be3c12125bc35fc3643204 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:01 +0200 Subject: i2c: stm32f7: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-stm32f7.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 01210452216b..cfee2d9c09de 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1789,7 +1789,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; struct stm32_i2c_dma *dma = i2c_dev->dma; struct device *dev = i2c_dev->dev; - unsigned long timeout; + unsigned long time_left; int i, ret; f7_msg->addr = addr; @@ -1809,8 +1809,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, if (ret) goto pm_free; - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = f7_msg->result; if (ret) { if (i2c_dev->use_dma) @@ -1826,7 +1826,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, goto pm_free; } - if (!timeout) { + if (!time_left) { dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); if (i2c_dev->use_dma) dmaengine_terminate_sync(dma->chan_using); -- cgit v1.2.3 From 4259964b4a5299cb4fb9f5e06dccafb2ae05cb20 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:02 +0200 Subject: i2c: synquacer: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Acked-by: Ard Biesheuvel Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-synquacer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index bbea521b05dd..bf9bcfefa30e 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -311,7 +311,7 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned char bsr; - unsigned long timeout; + unsigned long time_left; int ret; synquacer_i2c_hw_init(i2c); @@ -335,9 +335,9 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, return ret; } - timeout = wait_for_completion_timeout(&i2c->completion, - msecs_to_jiffies(i2c->timeout_ms)); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&i2c->completion, + msecs_to_jiffies(i2c->timeout_ms)); + if (time_left == 0) { dev_dbg(i2c->dev, "timeout\n"); return -EAGAIN; } -- cgit v1.2.3 From 66aa72ced659c5cf3e14674e04450f92e845a699 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:03 +0200 Subject: i2c: jz4780: use 'time_left' variable with wait_for_completion_timeout() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Acked-by: Paul Cercueil Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-jz4780.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 55035cca0ae5..7951891d6b97 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -565,7 +565,7 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, int idx) { int ret = 0; - long timeout; + unsigned long time_left; int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); unsigned short tmp; unsigned long flags; @@ -600,10 +600,10 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->trans_waitq, - msecs_to_jiffies(wait_time)); + time_left = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); - if (!timeout) { + if (!time_left) { dev_err(&i2c->adap.dev, "irq read timeout\n"); dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n", i2c->cmd, i2c->cmd_buf[i2c->cmd]); @@ -627,7 +627,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, { int ret = 0; int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); - long timeout; + unsigned long time_left; unsigned short tmp; unsigned long flags; @@ -655,14 +655,14 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->trans_waitq, - msecs_to_jiffies(wait_time)); - if (timeout && !i2c->stop_hold) { + time_left = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + if (time_left && !i2c->stop_hold) { unsigned short i2c_sta; int write_in_process; - timeout = JZ4780_I2C_TIMEOUT * 100; - for (; timeout > 0; timeout--) { + time_left = JZ4780_I2C_TIMEOUT * 100; + for (; time_left > 0; time_left--) { i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) || @@ -673,7 +673,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, } } - if (!timeout) { + if (!time_left) { dev_err(&i2c->adap.dev, "write wait timeout\n"); ret = -EIO; } -- cgit v1.2.3 From f9288ff67a8f4bc2645d32a512d4b30f73f956d5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:04 +0200 Subject: i2c: qcom-geni: use 'time_left' variable with wait_for_completion_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_for_completion_timeout() causing patterns like: timeout = wait_for_completion_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'unsigned long' while here. Signed-off-by: Wolfram Sang Reviewed-by: Bjorn Andersson Reviewed-by: Bryan O'Donoghue Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-qcom-geni.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 090b4846ed62..0a8b95ce35f7 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -586,7 +586,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i { struct dma_slave_config config = {}; struct gpi_i2c_config peripheral = {}; - int i, ret = 0, timeout; + int i, ret = 0; + unsigned long time_left; dma_addr_t tx_addr, rx_addr; void *tx_buf = NULL, *rx_buf = NULL; const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; @@ -629,8 +630,8 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i dma_async_issue_pending(gi2c->tx_c); - timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!timeout) + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) gi2c->err = -ETIMEDOUT; if (gi2c->err) { -- cgit v1.2.3 From 749de720c7e568836e62c09508c92f00634c9bc3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:05 +0200 Subject: i2c: rk3x: use 'time_left' variable with wait_event_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_timeout() causing patterns like: timeout = wait_event_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'long' while here. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-rk3x.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 8c7367f289d3..beca61700c89 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1060,7 +1060,8 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, bool polling) { struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; - unsigned long timeout, flags; + unsigned long flags; + long time_left; u32 val; int ret = 0; int i; @@ -1092,20 +1093,20 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, if (!polling) { rk3x_i2c_start(i2c); - timeout = wait_event_timeout(i2c->wait, !i2c->busy, - msecs_to_jiffies(WAIT_TIMEOUT)); + time_left = wait_event_timeout(i2c->wait, !i2c->busy, + msecs_to_jiffies(WAIT_TIMEOUT)); } else { disable_irq(i2c->irq); rk3x_i2c_start(i2c); - timeout = rk3x_i2c_wait_xfer_poll(i2c); + time_left = rk3x_i2c_wait_xfer_poll(i2c); enable_irq(i2c->irq); } spin_lock_irqsave(&i2c->lock, flags); - if (timeout == 0) { + if (time_left == 0) { /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; -- cgit v1.2.3 From bc0ff8022f26f8ee65dfea31fe590daf8adc8012 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:06 +0200 Subject: i2c: s3c2410: use 'time_left' variable with wait_event_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_timeout() causing patterns like: timeout = wait_event_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Fix to the proper variable type 'long' while here. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-s3c2410.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 275f7c42165c..01419c738cfc 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -685,7 +685,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long timeout = 0; + long time_left = 0; int ret; ret = s3c24xx_i2c_set_master(i2c); @@ -715,7 +715,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, dev_err(i2c->dev, "deal with arbitration loss\n"); } } else { - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); } ret = i2c->msg_idx; @@ -724,7 +724,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, * Having these next two as dev_err() makes life very * noisy when doing an i2cdetect */ - if (timeout == 0) + if (time_left == 0) dev_dbg(i2c->dev, "timeout\n"); else if (ret != num) dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); -- cgit v1.2.3 From 1ce1ad6de56591b7e8ea7d056f0a179b47ed9480 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 27 Apr 2024 22:36:07 +0200 Subject: i2c: pxa: use 'time_left' variable with wait_event_timeout() There is a confusing pattern in the kernel to use a variable named 'timeout' to store the result of wait_event_timeout() causing patterns like: timeout = wait_event_timeout(...) if (!timeout) return -ETIMEDOUT; with all kinds of permutations. Use 'time_left' as a variable to make the code self explaining. Signed-off-by: Wolfram Sang Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-pxa.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 888ca636f3f3..f495560bd99c 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -826,7 +826,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) { u32 icr; - long timeout; + long time_left; spin_lock_irq(&i2c->lock); i2c->highmode_enter = true; @@ -837,12 +837,12 @@ static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) writel(icr, _ICR(i2c)); spin_unlock_irq(&i2c->lock); - timeout = wait_event_timeout(i2c->wait, - i2c->highmode_enter == false, HZ * 1); + time_left = wait_event_timeout(i2c->wait, + i2c->highmode_enter == false, HZ * 1); i2c->highmode_enter = false; - return (timeout == 0) ? I2C_RETRY : 0; + return (time_left == 0) ? I2C_RETRY : 0; } /* @@ -1050,7 +1050,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) */ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) { - long timeout; + long time_left; int ret; /* @@ -1095,7 +1095,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) /* * The rest of the processing occurs in the interrupt handler. */ - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); i2c_pxa_stop_message(i2c); /* @@ -1103,7 +1103,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) */ ret = i2c->msg_idx; - if (!timeout && i2c->msg_num) { + if (!time_left && i2c->msg_num) { i2c_pxa_scream_blue_murder(i2c, "timeout with active message"); i2c_recover_bus(&i2c->adap); ret = I2C_RETRY; -- cgit v1.2.3 From 61e05bad821cb293418794738e7cc359949f44fe Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 25 Apr 2024 14:44:34 -0700 Subject: i2c: designware: Replace MODULE_ALIAS() with MODULE_DEVICE_TABLE() As Krzysztof Kozlowski pointed out the better is to use MODULE_DEVICE_TABLE() as it will be consistent with the content of the real ID table of the platform devices. While at it, drop unneeded and unused module alias in PCI glue driver as PCI already has its own ID table and automatic loading should just work. Reviewed-by: Andi Shyti Reviewed-by: Mario Limonciello Acked-by: Jarkko Nikula Tested-by: Jarkko Nikula Tested-by: Serge Semin Link: https://lore.kernel.org/r/20231120144641.1660574-9-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 -- drivers/i2c/busses/i2c-designware-platdrv.c | 8 ++++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 9be9a2658e1f..a1b379a1e904 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -424,8 +424,6 @@ static struct pci_driver dw_i2c_driver = { }; module_pci_driver(dw_i2c_driver); -/* Work with hotplug and coldplug */ -MODULE_ALIAS("i2c_designware-pci"); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 926fb74a8570..29aac9c87368 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -480,8 +480,11 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = { RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) }; -/* Work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c_designware"); +static const struct platform_device_id dw_i2c_platform_ids[] = { + { "i2c_designware" }, + {} +}; +MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids); static struct platform_driver dw_i2c_driver = { .probe = dw_i2c_plat_probe, @@ -492,6 +495,7 @@ static struct platform_driver dw_i2c_driver = { .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), .pm = pm_ptr(&dw_i2c_dev_pm_ops), }, + .id_table = dw_i2c_platform_ids, }; static int __init dw_i2c_init_driver(void) -- cgit v1.2.3 From 3f858bbf04dbac934ac279aaee05d49eb9910051 Mon Sep 17 00:00:00 2001 From: Hamish Martin Date: Wed, 13 Mar 2024 11:16:32 +1300 Subject: i2c: acpi: Unbind mux adapters before delete There is an issue with ACPI overlay table removal specifically related to I2C multiplexers. Consider an ACPI SSDT Overlay that defines a PCA9548 I2C mux on an existing I2C bus. When this table is loaded we see the creation of a device for the overall PCA9548 chip and 8 further devices - one i2c_adapter each for the mux channels. These are all bound to their ACPI equivalents via an eventual invocation of acpi_bind_one(). When we unload the SSDT overlay we run into the problem. The ACPI devices are deleted as normal via acpi_device_del_work_fn() and the acpi_device_del_list. However, the following warning and stack trace is output as the deletion does not go smoothly: ------------[ cut here ]------------ kernfs: can not remove 'physical_node', no directory WARNING: CPU: 1 PID: 11 at fs/kernfs/dir.c:1674 kernfs_remove_by_name_ns+0xb9/0xc0 Modules linked in: CPU: 1 PID: 11 Comm: kworker/u128:0 Not tainted 6.8.0-rc6+ #1 Hardware name: congatec AG conga-B7E3/conga-B7E3, BIOS 5.13 05/16/2023 Workqueue: kacpi_hotplug acpi_device_del_work_fn RIP: 0010:kernfs_remove_by_name_ns+0xb9/0xc0 Code: e4 00 48 89 ef e8 07 71 db ff 5b b8 fe ff ff ff 5d 41 5c 41 5d e9 a7 55 e4 00 0f 0b eb a6 48 c7 c7 f0 38 0d 9d e8 97 0a d5 ff <0f> 0b eb dc 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 RSP: 0018:ffff9f864008fb28 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff8ef90a8d4940 RCX: 0000000000000000 RDX: ffff8f000e267d10 RSI: ffff8f000e25c780 RDI: ffff8f000e25c780 RBP: ffff8ef9186f9870 R08: 0000000000013ffb R09: 00000000ffffbfff R10: 00000000ffffbfff R11: ffff8f000e0a0000 R12: ffff9f864008fb50 R13: ffff8ef90c93dd60 R14: ffff8ef9010d0958 R15: ffff8ef9186f98c8 FS: 0000000000000000(0000) GS:ffff8f000e240000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f48f5253a08 CR3: 00000003cb82e000 CR4: 00000000003506f0 Call Trace: ? kernfs_remove_by_name_ns+0xb9/0xc0 ? __warn+0x7c/0x130 ? kernfs_remove_by_name_ns+0xb9/0xc0 ? report_bug+0x171/0x1a0 ? handle_bug+0x3c/0x70 ? exc_invalid_op+0x17/0x70 ? asm_exc_invalid_op+0x1a/0x20 ? kernfs_remove_by_name_ns+0xb9/0xc0 ? kernfs_remove_by_name_ns+0xb9/0xc0 acpi_unbind_one+0x108/0x180 device_del+0x18b/0x490 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f device_unregister+0xd/0x30 i2c_del_adapter.part.0+0x1bf/0x250 i2c_mux_del_adapters+0xa1/0xe0 i2c_device_remove+0x1e/0x80 device_release_driver_internal+0x19a/0x200 bus_remove_device+0xbf/0x100 device_del+0x157/0x490 ? __pfx_device_match_fwnode+0x10/0x10 ? srso_return_thunk+0x5/0x5f device_unregister+0xd/0x30 i2c_acpi_notify+0x10f/0x140 notifier_call_chain+0x58/0xd0 blocking_notifier_call_chain+0x3a/0x60 acpi_device_del_work_fn+0x85/0x1d0 process_one_work+0x134/0x2f0 worker_thread+0x2f0/0x410 ? __pfx_worker_thread+0x10/0x10 kthread+0xe3/0x110 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x2f/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1b/0x30 ---[ end trace 0000000000000000 ]--- ... repeated 7 more times, 1 for each channel of the mux ... The issue is that the binding of the ACPI devices to their peer I2C adapters is not correctly cleaned up. Digging deeper into the issue we see that the deletion order is such that the ACPI devices matching the mux channel i2c adapters are deleted first during the SSDT overlay removal. For each of the channels we see a call to i2c_acpi_notify() with ACPI_RECONFIG_DEVICE_REMOVE but, because these devices are not actually i2c_clients, nothing is done for them. Later on, after each of the mux channels has been dealt with, we come to delete the i2c_client representing the PCA9548 device. This is the call stack we see above, whereby the kernel cleans up the i2c_client including destruction of the mux and its channel adapters. At this point we do attempt to unbind from the ACPI peers but those peers no longer exist and so we hit the kernfs errors. The fix is to augment i2c_acpi_notify() to handle i2c_adapters. But, given that the life cycle of the adapters is linked to the i2c_client, instead of deleting the i2c_adapters during the i2c_acpi_notify(), we just trigger unbinding of the ACPI device from the adapter device, and allow the clean up of the adapter to continue in the way it always has. Signed-off-by: Hamish Martin Reviewed-by: Mika Westerberg Reviewed-by: Andi Shyti Fixes: 525e6fabeae2 ("i2c / ACPI: add support for ACPI reconfigure notifications") Cc: # v4.8+ Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core-acpi.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index d6037a328669..14ae0cfc325e 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -445,6 +445,11 @@ static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev)); } +static struct i2c_adapter *i2c_acpi_find_adapter_by_adev(struct acpi_device *adev) +{ + return i2c_find_adapter_by_fwnode(acpi_fwnode_handle(adev)); +} + static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, void *arg) { @@ -471,11 +476,17 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, break; client = i2c_acpi_find_client_by_adev(adev); - if (!client) - break; + if (client) { + i2c_unregister_device(client); + put_device(&client->dev); + } + + adapter = i2c_acpi_find_adapter_by_adev(adev); + if (adapter) { + acpi_unbind_one(&adapter->dev); + put_device(&adapter->dev); + } - i2c_unregister_device(client); - put_device(&client->dev); break; } -- cgit v1.2.3 From 55750148e5595bb85605e8fbb40b2759c2c4c2d7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2024 13:48:24 +0100 Subject: i2c: synquacer: Fix an error handling path in synquacer_i2c_probe() If an error occurs after the clk_prepare_enable() call, it should be undone by a corresponding clk_disable_unprepare() call, as already done in the remove() function. As devm_clk_get() is used, we can switch to devm_clk_get_enabled() to handle it automatically and fix the probe. Update the remove() function accordingly and remove the now useless clk_disable_unprepare() call. Fixes: 0d676a6c4390 ("i2c: add support for Socionext SynQuacer I2C controller") Signed-off-by: Christophe JAILLET Acked-by: Ard Biesheuvel Signed-off-by: Andi Shyti --- drivers/i2c/busses/i2c-synquacer.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index bbea521b05dd..a73f5bb9a164 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -550,17 +550,13 @@ static int synquacer_i2c_probe(struct platform_device *pdev) device_property_read_u32(&pdev->dev, "socionext,pclk-rate", &i2c->pclkrate); - i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (PTR_ERR(i2c->pclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR_OR_NULL(i2c->pclk)) { - dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); - - ret = clk_prepare_enable(i2c->pclk); - if (ret) - return dev_err_probe(&pdev->dev, ret, "failed to enable clock\n"); - i2c->pclkrate = clk_get_rate(i2c->pclk); - } + i2c->pclk = devm_clk_get_enabled(&pdev->dev, "pclk"); + if (IS_ERR(i2c->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), + "failed to get and enable clock\n"); + + dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); + i2c->pclkrate = clk_get_rate(i2c->pclk); if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE || i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) @@ -615,8 +611,6 @@ static void synquacer_i2c_remove(struct platform_device *pdev) struct synquacer_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adapter); - if (!IS_ERR(i2c->pclk)) - clk_disable_unprepare(i2c->pclk); }; static const struct of_device_id synquacer_i2c_dt_ids[] __maybe_unused = { -- cgit v1.2.3 From fec1982d70721c0062758861fec7e4e9d1103fb6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 18 Apr 2024 22:55:39 +0200 Subject: i2c: mux: Remove class argument from i2c_mux_add_adapter() 99a741aa7a2d ("i2c: mux: gpio: remove support for class-based device instantiation") removed the last call to i2c_mux_add_adapter() with a non-null class argument. Therefore the class argument can be removed. Note: Class-based device instantiation is a legacy mechanism which shouldn't be used in new code, so we can rule out that this argument may be needed again in the future. Signed-off-by: Heiner Kallweit Reviewed-by: Thomas Zimmermann Acked-by: Peter Rosin Reviewed-by: Laurent Pinchart Acked-by: Jonathan Cameron Acked-by: Rob Herring (Arm) Signed-off-by: Wolfram Sang --- drivers/gpu/drm/bridge/sii902x.c | 2 +- drivers/i2c/i2c-mux.c | 24 +----------------------- drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 2 +- drivers/i2c/muxes/i2c-mux-gpio.c | 2 +- drivers/i2c/muxes/i2c-mux-gpmux.c | 2 +- drivers/i2c/muxes/i2c-mux-ltc4306.c | 2 +- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 2 +- drivers/i2c/muxes/i2c-mux-pca9541.c | 2 +- drivers/i2c/muxes/i2c-mux-pca954x.c | 2 +- drivers/i2c/muxes/i2c-mux-pinctrl.c | 2 +- drivers/i2c/muxes/i2c-mux-reg.c | 2 +- drivers/iio/gyro/mpu3050-i2c.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 2 +- drivers/media/dvb-frontends/af9013.c | 2 +- drivers/media/dvb-frontends/lgdt3306a.c | 2 +- drivers/media/dvb-frontends/m88ds3103.c | 2 +- drivers/media/dvb-frontends/rtl2830.c | 2 +- drivers/media/dvb-frontends/rtl2832.c | 2 +- drivers/media/dvb-frontends/si2168.c | 2 +- drivers/media/i2c/max9286.c | 2 +- drivers/media/usb/cx231xx/cx231xx-i2c.c | 5 +---- drivers/of/unittest.c | 2 +- include/linux/i2c-mux.h | 3 +-- 23 files changed, 23 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 8f84e98249c7..2fbeda9025bf 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1092,7 +1092,7 @@ static int sii902x_init(struct sii902x *sii902x) } sii902x->i2cmux->priv = sii902x; - ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0); if (ret) goto err_unreg_audio; diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 57ff09f18c37..fda72e8be885 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -127,19 +127,6 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap) return parent->algo->functionality(parent); } -/* Return all parent classes, merged */ -static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent) -{ - unsigned int class = 0; - - do { - class |= parent->class; - parent = i2c_parent_is_i2c_adapter(parent); - } while (parent); - - return class; -} - static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { struct i2c_mux_priv *priv = adapter->algo_data; @@ -281,8 +268,7 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { }; int i2c_mux_add_adapter(struct i2c_mux_core *muxc, - u32 force_nr, u32 chan_id, - unsigned int class) + u32 force_nr, u32 chan_id) { struct i2c_adapter *parent = muxc->parent; struct i2c_mux_priv *priv; @@ -340,14 +326,6 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, else priv->adap.lock_ops = &i2c_parent_lock_ops; - /* Sanity check on class */ - if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED) - dev_err(&parent->dev, - "Segment %d behind mux can't share classes with ancestors\n", - chan_id); - else - priv->adap.class = class; - /* * Try to populate the mux adapter's of_node, expands to * nothing if !CONFIG_OF. diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 24168e9f7df4..7aa6e795d833 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -167,7 +167,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) } /* Actually add the mux adapter */ - ret = i2c_mux_add_adapter(muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(muxc, 0, 0); if (ret) i2c_put_adapter(muxc->parent); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 0fbb33a3d518..d6bbb8b68333 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -207,7 +207,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], 0); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]); if (ret) goto add_adapter_failed; } diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index 8305661e1253..10d63307b14d 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -124,7 +124,7 @@ static int i2c_mux_probe(struct platform_device *pdev) goto err_children; } - ret = i2c_mux_add_adapter(muxc, 0, chan, 0); + ret = i2c_mux_add_adapter(muxc, 0, chan); if (ret) goto err_children; } diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 23766d853e76..19a7c370946d 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -279,7 +279,7 @@ static int ltc4306_probe(struct i2c_client *client) /* Now create an adapter for each channel */ for (num = 0; num < chip->nchans; num++) { - ret = i2c_mux_add_adapter(muxc, 0, num, 0); + ret = i2c_mux_add_adapter(muxc, 0, num); if (ret) { i2c_mux_del_adapters(muxc); return ret; diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 4c6ed1d58c79..3f06aa3331a7 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -154,7 +154,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) /* Create an adapter for each channel. */ for (num = 0; num < pdata->num_adaps; num++) { - err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0); + err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num]); if (err) goto virt_reg_failed; } diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index ce0fb69249a8..e28694d991fb 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -314,7 +314,7 @@ static int pca9541_probe(struct i2c_client *client) i2c_set_clientdata(client, muxc); - ret = i2c_mux_add_adapter(muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(muxc, 0, 0); if (ret) return ret; diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index c3f4ff08ac38..6f84018258c4 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -644,7 +644,7 @@ static int pca954x_probe(struct i2c_client *client) /* Now create an adapter for each channel */ for (num = 0; num < data->chip->nchans; num++) { - ret = i2c_mux_add_adapter(muxc, 0, num, 0); + ret = i2c_mux_add_adapter(muxc, 0, num); if (ret) goto fail_cleanup; } diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 6ebca7bfd8a2..02aaf0781e9c 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -151,7 +151,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) /* Do not add any adapter for the idle state (if it's there at all). */ for (i = 0; i < num_names - !!muxc->deselect; i++) { - ret = i2c_mux_add_adapter(muxc, 0, i, 0); + ret = i2c_mux_add_adapter(muxc, 0, i); if (ret) goto err_del_adapter; } diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 8489971babd3..ef765fcd33f5 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -213,7 +213,7 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], 0); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]); if (ret) goto err_del_mux_adapters; } diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index 52b6feed2637..29ecfa6fd633 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -72,7 +72,7 @@ static int mpu3050_i2c_probe(struct i2c_client *client) else { mpu3050->i2cmux->priv = mpu3050; /* Ignore failure, not critical */ - i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0); + i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0); } return 0; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 410ea39fd495..0e03137fb3d4 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -142,7 +142,7 @@ static int inv_mpu_probe(struct i2c_client *client) if (!st->muxc) return -ENOMEM; st->muxc->priv = dev_get_drvdata(&client->dev); - result = i2c_mux_add_adapter(st->muxc, 0, 0, 0); + result = i2c_mux_add_adapter(st->muxc, 0, 0); if (result) return result; result = inv_mpu_acpi_create_mux_client(client); diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a829c89792a4..5afdbe244596 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1480,7 +1480,7 @@ static int af9013_probe(struct i2c_client *client) goto err_regmap_exit; } state->muxc->priv = state; - ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(state->muxc, 0, 0); if (ret) goto err_regmap_exit; diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 263887592415..91c71b24cacb 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -2203,7 +2203,7 @@ static int lgdt3306a_probe(struct i2c_client *client) goto err_kfree; } state->muxc->priv = client; - ret = i2c_mux_add_adapter(state->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(state->muxc, 0, 0); if (ret) goto err_kfree; diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index e0272054fca5..6c69bcc7a1bc 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1866,7 +1866,7 @@ static int m88ds3103_probe(struct i2c_client *client) goto err_kfree; } dev->muxc->priv = dev; - ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(dev->muxc, 0, 0); if (ret) goto err_kfree; diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index 35c969fd2cb5..30d10fe4b33e 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -838,7 +838,7 @@ static int rtl2830_probe(struct i2c_client *client) goto err_regmap_exit; } dev->muxc->priv = client; - ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(dev->muxc, 0, 0); if (ret) goto err_regmap_exit; diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 601cf45c3935..5142820b1b3d 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -1082,7 +1082,7 @@ static int rtl2832_probe(struct i2c_client *client) goto err_regmap_exit; } dev->muxc->priv = dev; - ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(dev->muxc, 0, 0); if (ret) goto err_regmap_exit; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index dae1f2153e8b..26828fd41e68 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -744,7 +744,7 @@ static int si2168_probe(struct i2c_client *client) goto err_kfree; } dev->muxc->priv = client; - ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(dev->muxc, 0, 0); if (ret) goto err_kfree; diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index d685d445cf23..dfcb3fc03350 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -383,7 +383,7 @@ static int max9286_i2c_mux_init(struct max9286_priv *priv) for_each_source(priv, source) { unsigned int index = to_index(priv, source); - ret = i2c_mux_add_adapter(priv->mux, 0, index, 0); + ret = i2c_mux_add_adapter(priv->mux, 0, index); if (ret < 0) goto error; } diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index c6659253c6fb..6da8e7943d94 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -567,10 +567,7 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev) int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no) { - return i2c_mux_add_adapter(dev->muxc, - 0, - mux_no /* chan_id */, - 0 /* class */); + return i2c_mux_add_adapter(dev->muxc, 0, mux_no); } void cx231xx_i2c_mux_unregister(struct cx231xx *dev) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 6b5c36b6a758..c8ee866d76d4 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -2815,7 +2815,7 @@ static int unittest_i2c_mux_probe(struct i2c_client *client) if (!muxc) return -ENOMEM; for (i = 0; i < nchans; i++) { - if (i2c_mux_add_adapter(muxc, 0, i, 0)) { + if (i2c_mux_add_adapter(muxc, 0, i)) { dev_err(dev, "Failed to register mux #%d\n", i); i2c_mux_del_adapters(muxc); return -ENODEV; diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h index 98ef73b7c8fd..1784ac7afb11 100644 --- a/include/linux/i2c-mux.h +++ b/include/linux/i2c-mux.h @@ -56,8 +56,7 @@ struct i2c_adapter *i2c_root_adapter(struct device *dev); * callback functions to perform hardware-specific mux control. */ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, - u32 force_nr, u32 chan_id, - unsigned int class); + u32 force_nr, u32 chan_id); void i2c_mux_del_adapters(struct i2c_mux_core *muxc); -- cgit v1.2.3 From 068a95ef3945033b5355e50fecea18737680d43d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Apr 2024 22:55:39 +0200 Subject: power: supply: sbs-manager: Remove class argument from i2c_mux_add_adapter() Commit 99a741aa7a2d ("i2c: mux: gpio: remove support for class-based device instantiation") removed the last call to i2c_mux_add_adapter() with a non-null class argument. Therefore the class argument can be removed. Note: Class-based device instantiation is a legacy mechanism which shouldn't be used in new code, so we can rule out that this argument may be needed again in the future. This driver was forgotten by the patch in the Fixes tag. Fixes: fec1982d7072 ("i2c: mux: Remove class argument from i2c_mux_add_adapter()") Signed-off-by: Wolfram Sang Acked-by: Sebastian Reichel --- drivers/power/supply/sbs-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/sbs-manager.c b/drivers/power/supply/sbs-manager.c index 9e4141cffbf9..933b04806d10 100644 --- a/drivers/power/supply/sbs-manager.c +++ b/drivers/power/supply/sbs-manager.c @@ -358,7 +358,7 @@ static int sbsm_probe(struct i2c_client *client) /* register muxed i2c channels. One for each supported battery */ for (i = 0; i < SBSM_MAX_BATS; ++i) { if (data->supported_bats & BIT(i)) { - ret = i2c_mux_add_adapter(data->muxc, 0, i + 1, 0); + ret = i2c_mux_add_adapter(data->muxc, 0, i + 1); if (ret) break; } -- cgit v1.2.3