diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-15 15:53:50 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-15 15:53:50 -0800 |
commit | 9d0d886799e49e0f6d51e70c823416919544fdb7 (patch) | |
tree | a0392a5a11884941f62b4db270e75a9451e280a2 | |
parent | 605ea5aafe1341ac9b2144516f898ac78ad49c40 (diff) | |
parent | 4e970a0ada5299d017a4263074f725227c2d2852 (diff) |
Merge branch 'i2c/for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"A bit smaller this time with mostly usual driver updates. Slave
support for imx stands out a little"
* 'i2c/for-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (30 commits)
i2c: remove check that can never be true
i2c: Warn when device removing fails
dt-bindings: i2c: Update DT binding docs to support SiFive FU740 SoC
dt-bindings: i2c: Add compatible string for AM64 SoC
i2c: designware: Make register offsets all of the same width
i2c: designware: Switch header to use BIT() and GENMASK()
i2c: pxa: move to generic GPIO recovery
i2c: sh_mobile: Mark adapter suspended during suspend
i2c: owl: Add compatible for the Actions Semi S500 I2C controller
dt-bindings: i2c: owl: Convert Actions Semi Owl binding to a schema
i2c: imx: support slave mode for imx I2C driver
i2c: ismt: Adding support for I2C_SMBUS_BLOCK_PROC_CALL
i2c: ocores: Avoid false-positive error log message.
Revert "i2c: qcom-geni: Disable DMA processing on the Lenovo Yoga C630"
i2c: mxs: Remove unneeded platform_device_id
i2c: pca-platform: drop two members from driver data that are assigned to only
i2c: imx: Remove unused .id_table support
i2c: nvidia-gpu: drop empty stub for runtime pm
dt-bindings: i2c: mellanox,i2c-mlxbf: convert txt to YAML schema
i2c: mv64xxx: Add bus error recovery
...
25 files changed, 604 insertions, 340 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt index 6b25a80ae8d3..a37c9455b244 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-ocores.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-ocores.txt @@ -5,8 +5,12 @@ Required properties: "aeroflexgaisler,i2cmst" "sifive,fu540-c000-i2c", "sifive,i2c0" For Opencore based I2C IP block reimplemented in - FU540-C000 SoC. Please refer to sifive-blocks-ip-versioning.txt - for additional details. + FU540-C000 SoC. + "sifive,fu740-c000-i2c", "sifive,i2c0" + For Opencore based I2C IP block reimplemented in + FU740-C000 SoC. + Please refer to sifive-blocks-ip-versioning.txt for + additional details. - reg : bus address start and address range size of device - clocks : handle to the controller clock; see the note below. Mutually exclusive with opencores,ip-clock-frequency diff --git a/Documentation/devicetree/bindings/i2c/i2c-omap.txt b/Documentation/devicetree/bindings/i2c/i2c-omap.txt index a44573d7c118..a425b91af48f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-omap.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-omap.txt @@ -8,6 +8,7 @@ Required properties : "ti,omap4-i2c" for OMAP4+ SoCs "ti,am654-i2c", "ti,omap4-i2c" for AM654 SoCs "ti,j721e-i2c", "ti,omap4-i2c" for J721E SoCs + "ti,am64-i2c", "ti,omap4-i2c" for AM64 SoCs - ti,hwmods : Must be "i2c<n>", n being the instance number (1-based) - #address-cells = <1>; - #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-owl.txt b/Documentation/devicetree/bindings/i2c/i2c-owl.txt deleted file mode 100644 index 54c05dbdb2e4..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-owl.txt +++ /dev/null @@ -1,29 +0,0 @@ -Actions Semiconductor Owl I2C controller - -Required properties: - -- compatible : Should be one of the following: - - "actions,s700-i2c" for S700 SoC - - "actions,s900-i2c" for S900 SoC -- reg : Offset and length of the register set for the device. -- #address-cells : Should be 1. -- #size-cells : Should be 0. -- interrupts : A single interrupt specifier. -- clocks : Phandle of the clock feeding the I2C controller. - -Optional properties: - -- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and - Fast modes are supported, possible values are 100000 and - 400000. -Examples: - - i2c0: i2c@e0170000 { - compatible = "actions,s900-i2c"; - reg = <0 0xe0170000 0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clock CLK_I2C0>; - clock-frequency = <100000>; - }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-owl.yaml b/Documentation/devicetree/bindings/i2c/i2c-owl.yaml new file mode 100644 index 000000000000..d96908badf81 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-owl.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/i2c-owl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Actions Semi Owl I2C Controller + +maintainers: + - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + +description: | + This I2C controller is found in the Actions Semi Owl SoCs: + S500, S700 and S900. + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + enum: + - actions,s500-i2c # Actions Semi S500 compatible SoCs + - actions,s700-i2c # Actions Semi S700 compatible SoCs + - actions,s900-i2c # Actions Semi S900 compatible SoCs + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + description: Phandle of the clock feeding the I2C controller. + minItems: 1 + + clock-frequency: + description: | + Desired I2C bus clock frequency in Hz. As only Standard and Fast + modes are supported, possible values are 100000 and 400000. + enum: [100000, 400000] + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/actions,s900-cmu.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + i2c@e0170000 { + compatible = "actions,s900-i2c"; + reg = <0xe0170000 0x1000>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cmu CLK_I2C0>; + clock-frequency = <100000>; + }; + +... diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt deleted file mode 100644 index 566ea861aa00..000000000000 --- a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.txt +++ /dev/null @@ -1,42 +0,0 @@ -Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs - -Required Properties: - -- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2". - -- reg : address offset and length of the device registers. The - registers consist of the following set of resources: - 1) Smbus block registers. - 2) Cause master registers. - 3) Cause slave registers. - 4) Cause coalesce registers (if compatible isn't set - to "mellanox,i2c-mlxbf1"). - -- interrupts : interrupt number. - -Optional Properties: - -- clock-frequency : bus frequency used to configure timing registers; - allowed values are 100000, 400000 and 1000000; - those are expressed in Hz. Default is 100000. - -Example: - -i2c@2804000 { - compatible = "mellanox,i2c-mlxbf1"; - reg = <0x02804000 0x800>, - <0x02801200 0x020>, - <0x02801260 0x020>; - interrupts = <57>; - clock-frequency = <100000>; -}; - -i2c@2808800 { - compatible = "mellanox,i2c-mlxbf2"; - reg = <0x02808800 0x600>, - <0x02808e00 0x020>, - <0x02808e20 0x020>, - <0x02808e40 0x010>; - interrupts = <57>; - clock-frequency = <400000>; -}; diff --git a/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml new file mode 100644 index 000000000000..d2b401d062b9 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mellanox I2C SMBus on BlueField SoCs + +maintainers: + - Khalil Blaiech <kblaiech@nvidia.com> + +allOf: + - $ref: /schemas/i2c/i2c-controller.yaml# + +properties: + compatible: + enum: + - mellanox,i2c-mlxbf1 + - mellanox,i2c-mlxbf2 + + reg: + minItems: 3 + maxItems: 4 + items: + - description: Smbus block registers + - description: Cause master registers + - description: Cause slave registers + - description: Cause coalesce registers + + interrupts: + maxItems: 1 + + clock-frequency: + enum: [ 100000, 400000, 1000000 ] + description: + bus frequency used to configure timing registers; + The frequency is expressed in Hz. Default is 100000. + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +if: + properties: + compatible: + contains: + enum: + - mellanox,i2c-mlxbf1 + +then: + properties: + reg: + maxItems: 3 + +examples: + - | + i2c@2804000 { + compatible = "mellanox,i2c-mlxbf1"; + reg = <0x02804000 0x800>, + <0x02801200 0x020>, + <0x02801260 0x020>; + interrupts = <57>; + clock-frequency = <100000>; + }; + + - | + i2c@2808800 { + compatible = "mellanox,i2c-mlxbf2"; + reg = <0x02808800 0x600>, + <0x02808e00 0x020>, + <0x02808e20 0x020>, + <0x02808e40 0x010>; + interrupts = <57>; + clock-frequency = <400000>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 125819e4857d..fdb7003bc1f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1502,7 +1502,7 @@ S: Maintained F: Documentation/devicetree/bindings/arm/actions.yaml F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt F: Documentation/devicetree/bindings/dma/owl-dma.yaml -F: Documentation/devicetree/bindings/i2c/i2c-owl.txt +F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml F: Documentation/devicetree/bindings/pinctrl/actions,* @@ -11254,6 +11254,7 @@ MELLANOX BLUEFIELD I2C DRIVER M: Khalil Blaiech <kblaiech@nvidia.com> L: linux-i2c@vger.kernel.org S: Supported +F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml F: drivers/i2c/busses/i2c-mlxbf.c MELLANOX ETHERNET DRIVER (mlx4_en) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a49e0ed4a599..d4d60ad0eda0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -675,6 +675,7 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE + select I2C_SLAVE help Say Y here if you want to use the IIC bus controller on the Freescale i.MX/MXC, Layerscape or ColdFire processors. diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 66864f9cf7ac..1cceb6866689 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -26,7 +26,6 @@ #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> -#include <linux/platform_data/dma-atmel.h> #include <linux/pm_runtime.h> #include "i2c-at91.h" diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h index eae673ae786c..942e9c3973bb 100644 --- a/drivers/i2c/busses/i2c-at91.h +++ b/drivers/i2c/busses/i2c-at91.h @@ -18,7 +18,6 @@ #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/i2c.h> -#include <linux/platform_data/dma-atmel.h> #include <linux/platform_device.h> #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */ @@ -123,7 +122,6 @@ struct at91_twi_pdata { bool has_adv_dig_filtr; bool has_ana_filtr; bool has_clear_cmd; - struct at_dma_slave dma_slave; }; struct at91_twi_dma { diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index eb5ef4d0f463..85307cfa7109 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -25,25 +25,25 @@ I2C_FUNC_SMBUS_BLOCK_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) -#define DW_IC_CON_MASTER 0x1 -#define DW_IC_CON_SPEED_STD 0x2 -#define DW_IC_CON_SPEED_FAST 0x4 -#define DW_IC_CON_SPEED_HIGH 0x6 -#define DW_IC_CON_SPEED_MASK 0x6 -#define DW_IC_CON_10BITADDR_SLAVE 0x8 -#define DW_IC_CON_10BITADDR_MASTER 0x10 -#define DW_IC_CON_RESTART_EN 0x20 -#define DW_IC_CON_SLAVE_DISABLE 0x40 -#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80 -#define DW_IC_CON_TX_EMPTY_CTRL 0x100 -#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200 +#define DW_IC_CON_MASTER BIT(0) +#define DW_IC_CON_SPEED_STD (1 << 1) +#define DW_IC_CON_SPEED_FAST (2 << 1) +#define DW_IC_CON_SPEED_HIGH (3 << 1) +#define DW_IC_CON_SPEED_MASK GENMASK(2, 1) +#define DW_IC_CON_10BITADDR_SLAVE BIT(3) +#define DW_IC_CON_10BITADDR_MASTER BIT(4) +#define DW_IC_CON_RESTART_EN BIT(5) +#define DW_IC_CON_SLAVE_DISABLE BIT(6) +#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7) +#define DW_IC_CON_TX_EMPTY_CTRL BIT(8) +#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) /* * Registers offset */ -#define DW_IC_CON 0x0 -#define DW_IC_TAR 0x4 -#define DW_IC_SAR 0x8 +#define DW_IC_CON 0x00 +#define DW_IC_TAR 0x04 +#define DW_IC_SAR 0x08 #define DW_IC_DATA_CMD 0x10 #define DW_IC_SS_SCL_HCNT 0x14 #define DW_IC_SS_SCL_LCNT 0x18 @@ -81,19 +81,19 @@ #define DW_IC_COMP_TYPE 0xfc #define DW_IC_COMP_TYPE_VALUE 0x44570140 -#define DW_IC_INTR_RX_UNDER 0x001 -#define DW_IC_INTR_RX_OVER 0x002 -#define DW_IC_INTR_RX_FULL 0x004 -#define DW_IC_INTR_TX_OVER 0x008 -#define DW_IC_INTR_TX_EMPTY 0x010 -#define DW_IC_INTR_RD_REQ 0x020 -#define DW_IC_INTR_TX_ABRT 0x040 -#define DW_IC_INTR_RX_DONE 0x080 -#define DW_IC_INTR_ACTIVITY 0x100 -#define DW_IC_INTR_STOP_DET 0x200 -#define DW_IC_INTR_START_DET 0x400 -#define DW_IC_INTR_GEN_CALL 0x800 -#define DW_IC_INTR_RESTART_DET 0x1000 +#define DW_IC_INTR_RX_UNDER BIT(0) +#define DW_IC_INTR_RX_OVER BIT(1) +#define DW_IC_INTR_RX_FULL BIT(2) +#define DW_IC_INTR_TX_OVER BIT(3) +#define DW_IC_INTR_TX_EMPTY BIT(4) +#define DW_IC_INTR_RD_REQ BIT(5) +#define DW_IC_INTR_TX_ABRT BIT(6) +#define DW_IC_INTR_RX_DONE BIT(7) +#define DW_IC_INTR_ACTIVITY BIT(8) +#define DW_IC_INTR_STOP_DET BIT(9) +#define DW_IC_INTR_START_DET BIT(10) +#define DW_IC_INTR_GEN_CALL BIT(11) +#define DW_IC_INTR_RESTART_DET BIT(12) #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ DW_IC_INTR_TX_ABRT | \ @@ -105,13 +105,13 @@ DW_IC_INTR_RX_UNDER | \ DW_IC_INTR_RD_REQ) -#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_ACTIVITY BIT(0) #define DW_IC_STATUS_TFE BIT(2) #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) #define DW_IC_SDA_HOLD_RX_SHIFT 16 -#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT) +#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) #define DW_IC_ERR_TX_ABRT 0x1 @@ -154,20 +154,20 @@ #define ABRT_SLAVE_ARBLOST 14 #define ABRT_SLAVE_RD_INTX 15 -#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK) -#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK) -#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK) -#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK) -#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK) -#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ) -#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET) -#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT) -#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT) -#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS) -#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST) -#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX) -#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST) -#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO) +#define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK) +#define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK) +#define DW_IC_TX_ABRT_10ADDR2_NOACK BIT(ABRT_10ADDR2_NOACK) +#define DW_IC_TX_ABRT_TXDATA_NOACK BIT(ABRT_TXDATA_NOACK) +#define DW_IC_TX_ABRT_GCALL_NOACK BIT(ABRT_GCALL_NOACK) +#define DW_IC_TX_ABRT_GCALL_READ BIT(ABRT_GCALL_READ) +#define DW_IC_TX_ABRT_SBYTE_ACKDET BIT(ABRT_SBYTE_ACKDET) +#define DW_IC_TX_ABRT_SBYTE_NORSTRT BIT(ABRT_SBYTE_NORSTRT) +#define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(ABRT_10B_RD_NORSTRT) +#define DW_IC_TX_ABRT_MASTER_DIS BIT(ABRT_MASTER_DIS) +#define DW_IC_TX_ARB_LOST BIT(ARB_LOST) +#define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX) +#define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) +#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) #define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ DW_IC_TX_ABRT_10ADDR1_NOACK | \ @@ -288,12 +288,12 @@ struct dw_i2c_dev { bool suspended; }; -#define ACCESS_INTR_MASK 0x00000001 -#define ACCESS_NO_IRQ_SUSPEND 0x00000002 +#define ACCESS_INTR_MASK BIT(0) +#define ACCESS_NO_IRQ_SUSPEND BIT(1) -#define MODEL_MSCC_OCELOT 0x00000100 -#define MODEL_BAIKAL_BT1 0x00000200 -#define MODEL_MASK 0x00000f00 +#define MODEL_MSCC_OCELOT BIT(8) +#define MODEL_BAIKAL_BT1 BIT(9) +#define MODEL_MASK GENMASK(11, 8) int i2c_dw_init_regmap(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 6ce3ec03b595..20a9881a0d6c 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -778,11 +778,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev) init_completion(&i2c->msg_complete); i2c->irq = ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n"); - ret = -EINVAL; + if (ret < 0) goto err_clk; - } ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq, IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index e6f8d6e45a15..b444fbf1a262 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -17,6 +17,7 @@ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> * * Copyright 2013 Freescale Semiconductor, Inc. + * Copyright 2020 NXP * */ @@ -73,6 +74,11 @@ #define IMX_I2C_I2SR 0x03 /* i2c status */ #define IMX_I2C_I2DR 0x04 /* i2c transfer data */ +/* + * All of the layerscape series SoCs support IBIC register. + */ +#define IMX_I2C_IBIC 0x05 /* i2c bus interrupt config */ + #define IMX_I2C_REGSHIFT 2 #define VF610_I2C_REGSHIFT 0 @@ -91,6 +97,7 @@ #define I2CR_MSTA 0x20 #define I2CR_IIEN 0x40 #define I2CR_IEN 0x80 +#define IBIC_BIIE 0x80 /* Bus idle interrupt enable */ /* register bits different operating codes definition: * 1) I2SR: Interrupt flags clear operation differ between SoCs: @@ -201,6 +208,7 @@ struct imx_i2c_struct { struct pinctrl_state *pinctrl_pins_gpio; struct imx_i2c_dma *dma; + struct i2c_client *slave; }; static const struct imx_i2c_hwdata imx1_i2c_hwdata = { @@ -233,19 +241,6 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = { }; -static const struct platform_device_id imx_i2c_devtype[] = { - { - .name = "imx1-i2c", - .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata, - }, { - .name = "imx21-i2c", - .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); - static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, @@ -265,6 +260,11 @@ static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) return i2c_imx->hwdata->devtype == IMX1_I2C; } +static inline int is_vf610_i2c(struct imx_i2c_struct *i2c_imx) +{ + return i2c_imx->hwdata->devtype == VF610_I2C; +} + static inline void imx_i2c_write_reg(unsigned int val, struct imx_i2c_struct *i2c_imx, unsigned int reg) { @@ -277,6 +277,27 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); } +static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits) +{ + unsigned int temp; + + /* + * i2sr_clr_opcode is the value to clear all interrupts. Here we want to + * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits> + * toggled. This is required because i.MX needs W0C and Vybrid uses W1C. + */ + temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); +} + +/* Set up i2c controller register and i2c status register to default value. */ +static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx) +{ + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, + i2c_imx, IMX_I2C_I2CR); + i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL); +} + /* Functions for DMA support */ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_addr_t phy_addr) @@ -412,19 +433,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) dma->chan_using = NULL; } -static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits) -{ - unsigned int temp; - - /* - * i2sr_clr_opcode is the value to clear all interrupts. Here we want to - * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits> - * toggled. This is required because i.MX needs W0C and Vybrid uses W1C. - */ - temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); -} - static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic) { unsigned long orig_jiffies = jiffies; @@ -638,18 +646,165 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic) imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); } +/* + * Enable bus idle interrupts + * Note: IBIC register will be cleared after disabled i2c module. + * All of layerscape series SoCs support IBIC register. + */ +static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx) +{ + if (is_vf610_i2c(i2c_imx)) { + unsigned int temp; + + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_IBIC); + temp |= IBIC_BIIE; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_IBIC); + } +} + +static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, + unsigned int status, unsigned int ctl) +{ + u8 value; + + if (status & I2SR_IAL) { /* Arbitration lost */ + i2c_imx_clear_irq(i2c_imx, I2SR_IAL); + if (!(status & I2SR_IAAS)) + return IRQ_HANDLED; + } + + if (status & I2SR_IAAS) { /* Addressed as a slave */ + if (status & I2SR_SRW) { /* Master wants to read from us*/ + dev_dbg(&i2c_imx->adapter.dev, "read requested"); + i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value); + + /* Slave transmit */ + ctl |= I2CR_MTX; + imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); + + /* Send data */ + imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); + } else { /* Master wants to write to us */ + dev_dbg(&i2c_imx->adapter.dev, "write requested"); + i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + + /* Slave receive */ + ctl &= ~I2CR_MTX; + imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); + /* Dummy read */ + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + } + } else if (!(ctl & I2CR_MTX)) { /* Receive mode */ + if (status & I2SR_IBB) { /* No STOP signal detected */ + value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value); + } else { /* STOP signal is detected */ + dev_dbg(&i2c_imx->adapter.dev, + "STOP signal detected"); + i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value); + } + } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ + ctl |= I2CR_MTX; + imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); + + i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value); + + imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); + } else { /* Transmit mode received NAK */ + ctl &= ~I2CR_MTX; + imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + } + + return IRQ_HANDLED; +} + +static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx) +{ + int temp; + + /* Set slave addr. */ + imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR); + + i2c_imx_reset_regs(i2c_imx); + + /* Enable module */ + temp = i2c_imx->hwdata->i2cr_ien_opcode; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + /* Enable interrupt from i2c module */ + temp |= I2CR_IIEN; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + i2c_imx_enable_bus_idle(i2c_imx); +} + +static int i2c_imx_reg_slave(struct i2c_client *client) +{ + struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); + int ret; + + if (i2c_imx->slave) + return -EBUSY; + + i2c_imx->slave = client; + + /* Resume */ + ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); + if (ret < 0) { + dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller"); + return ret; + } + + i2c_imx_slave_init(i2c_imx); + + return 0; +} + +static int i2c_imx_unreg_slave(struct i2c_client *client) +{ + struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); + int ret; + + if (!i2c_imx->slave) + return -EINVAL; + + /* Reset slave address. */ + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); + + i2c_imx_reset_regs(i2c_imx); + + i2c_imx->slave = NULL; + + /* Suspend */ + ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent); + if (ret < 0) + dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller"); + + return ret; +} + +static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status) +{ + /* save status register */ + i2c_imx->i2csr = status; + wake_up(&i2c_imx->queue); + + return IRQ_HANDLED; +} + static irqreturn_t i2c_imx_isr(int irq, void *dev_id) { struct imx_i2c_struct *i2c_imx = dev_id; - unsigned int temp; + unsigned int ctl, status; - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); - if (temp & I2SR_IIF) { - /* save status register */ - i2c_imx->i2csr = temp; + status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + if (status & I2SR_IIF) { i2c_imx_clear_irq(i2c_imx, I2SR_IIF); - wake_up(&i2c_imx->queue); - return IRQ_HANDLED; + if (i2c_imx->slave && !(ctl & I2CR_MSTA)) + return i2c_imx_slave_isr(i2c_imx, status, ctl); + return i2c_imx_master_isr(i2c_imx, status); } return IRQ_NONE; @@ -1027,6 +1182,10 @@ fail0: dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, (result < 0) ? "error" : "success msg", (result < 0) ? result : num); + /* After data is transferred, switch to slave mode(as a receiver) */ + if (i2c_imx->slave) + i2c_imx_slave_init(i2c_imx); + return (result < 0) ? result : num; } @@ -1140,6 +1299,8 @@ static const struct i2c_algorithm i2c_imx_algo = { .master_xfer = i2c_imx_xfer, .master_xfer_atomic = i2c_imx_xfer_atomic, .functionality = i2c_imx_func, + .reg_slave = i2c_imx_reg_slave, + .unreg_slave = i2c_imx_unreg_slave, }; static int i2c_imx_probe(struct platform_device *pdev) @@ -1169,11 +1330,7 @@ static int i2c_imx_probe(struct platform_device *pdev) return -ENOMEM; match = device_get_match_data(&pdev->dev); - if (match) - i2c_imx->hwdata = match; - else - i2c_imx->hwdata = (struct imx_i2c_hwdata *) - platform_get_device_id(pdev)->driver_data; + i2c_imx->hwdata = match; /* Setup i2c_imx driver structure */ strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); @@ -1233,10 +1390,7 @@ static int i2c_imx_probe(struct platform_device *pdev) clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); - /* Set up chip registers to defaults */ - imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, - i2c_imx, IMX_I2C_I2CR); |