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 ...
This commit is contained in:
commit
9d0d886799
@ -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
|
||||
|
@ -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>;
|
||||
|
@ -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>;
|
||||
};
|
62
Documentation/devicetree/bindings/i2c/i2c-owl.yaml
Normal file
62
Documentation/devicetree/bindings/i2c/i2c-owl.yaml
Normal file
@ -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>;
|
||||
};
|
||||
|
||||
...
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
|
||||
i2c_imx_reset_regs(i2c_imx);
|
||||
|
||||
/* Init optional bus recovery function */
|
||||
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
|
||||
@ -1344,7 +1498,6 @@ static struct platform_driver i2c_imx_driver = {
|
||||
.of_match_table = i2c_imx_dt_ids,
|
||||
.acpi_match_table = i2c_imx_acpi_ids,
|
||||
},
|
||||
.id_table = imx_i2c_devtype,
|
||||
};
|
||||
|
||||
static int __init i2c_adap_imx_init(void)
|
||||
|
@ -53,7 +53,7 @@
|
||||
* Features supported by this driver:
|
||||
* Hardware PEC yes
|
||||
* Block buffer yes
|
||||
* Block process call transaction no
|
||||
* Block process call transaction yes
|
||||
* Slave mode no
|
||||
*/
|
||||
|
||||
@ -332,7 +332,8 @@ static int ismt_process_desc(const struct ismt_desc *desc,
|
||||
|
||||
if (desc->status & ISMT_DESC_SCS) {
|
||||
if (read_write == I2C_SMBUS_WRITE &&
|
||||
size != I2C_SMBUS_PROC_CALL)
|
||||
size != I2C_SMBUS_PROC_CALL &&
|
||||
size != I2C_SMBUS_BLOCK_PROC_CALL)
|
||||
return 0;
|
||||
|
||||
switch (size) {
|
||||
@ -345,6 +346,7 @@ static int ismt_process_desc(const struct ismt_desc *desc,
|
||||
data->word = dma_buffer[0] | (dma_buffer[1] << 8);
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
if (desc->rxbytes != dma_buffer[0] + 1)
|
||||
return -EMSGSIZE;
|
||||
|
||||
@ -518,6 +520,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
|
||||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
|
||||
dma_size = I2C_SMBUS_BLOCK_MAX;
|
||||
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
|
||||
desc->wr_len_cmd = data->block[0] + 1;
|
||||
desc->rd_len = dma_size;
|
||||
desc->control |= ISMT_DESC_BLK;
|
||||
dma_direction = DMA_BIDIRECTIONAL;
|
||||
dma_buffer[0] = command;
|
||||
memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
/* Make sure the length is valid */
|
||||
if (data->block[0] < 1)
|
||||
@ -624,6 +638,7 @@ static u32 ismt_func(struct i2c_adapter *adap)
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_PEC;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mv643xx_i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
@ -147,6 +148,7 @@ struct mv64xxx_i2c_data {
|
||||
bool irq_clear_inverted;
|
||||
/* Clk div is 2 to the power n, not 2 to the power n + 1 */
|
||||
bool clk_n_base_0;
|
||||
struct i2c_bus_recovery_info rinfo;
|
||||
};
|
||||
|
||||
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
|
||||
@ -325,7 +327,8 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
|
||||
drv_data->msg->flags);
|
||||
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
|
||||
mv64xxx_i2c_hw_init(drv_data);
|
||||
drv_data->rc = -EIO;
|
||||
i2c_recover_bus(&drv_data->adapter);
|
||||
drv_data->rc = -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,6 +564,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
|
||||
"time_left: %d\n", drv_data->block,
|
||||
(int)time_left);
|
||||
mv64xxx_i2c_hw_init(drv_data);
|
||||
i2c_recover_bus(&drv_data->adapter);
|
||||
}
|
||||
} else
|
||||
spin_unlock_irqrestore(&drv_data->lock, flags);
|
||||
@ -870,6 +874,25 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device *dev)
|
||||
{
|
||||
struct i2c_bus_recovery_info *rinfo = &drv_data->rinfo;
|
||||
|
||||
rinfo->pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(rinfo->pinctrl)) {
|
||||
if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_info(dev, "can't get pinctrl, bus recovery not supported\n");
|
||||
return PTR_ERR(rinfo->pinctrl);
|
||||
} else if (!rinfo->pinctrl) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drv_data->adapter.bus_recovery_info = rinfo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
{
|
||||
@ -926,6 +949,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
goto exit_reset;
|
||||
}
|
||||
|
||||
rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
|
||||
if (rc == -EPROBE_DEFER)
|
||||
goto exit_reset;
|
||||
|
||||
drv_data->adapter.dev.parent = &pd->dev;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
|
@ -781,28 +781,15 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mxs_i2c_devtype[] = {
|
||||
{
|
||||
.name = "imx23-i2c",
|
||||
.driver_data = MXS_I2C_V1,
|
||||
}, {
|
||||
.name = "imx28-i2c",
|
||||
.driver_data = MXS_I2C_V2,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
|
||||
|
||||
static const struct of_device_id mxs_i2c_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
|
||||
{ .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
|
||||
{ .compatible = "fsl,imx23-i2c", .data = (void *)MXS_I2C_V1, },
|
||||
{ .compatible = "fsl,imx28-i2c", .data = (void *)MXS_I2C_V2, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
|
||||
|
||||
static int mxs_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxs_i2c_dt_ids, &pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mxs_i2c_dev *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
@ -812,10 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_id) {
|
||||
const struct platform_device_id *device_id = of_id->data;
|
||||
i2c->dev_type = device_id->driver_data;
|
||||
}
|
||||
i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
|
@ -353,15 +353,7 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
|
||||
* correctly. Without it, lspci shows runtime pm status as "D0" for the card.
|
||||
* Documentation/power/pci.rst also insists for driver to provide this.
|
||||
*/
|
||||
static __maybe_unused int gpu_i2c_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define gpu_i2c_suspend NULL
|
||||
|
||||
static __maybe_unused int gpu_i2c_resume(struct device *dev)
|
||||
{
|
||||
|
@ -83,7 +83,6 @@ struct ocores_i2c {
|
||||
|
||||
#define TYPE_OCORES 0
|
||||
#define TYPE_GRLIB 1
|
||||
#define TYPE_SIFIVE_REV0 2
|
||||
|
||||
#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
|
||||
|
||||
@ -476,11 +475,9 @@ static const struct of_device_id ocores_i2c_match[] = {
|
||||
},
|
||||
{
|
||||
.compatible = "sifive,fu540-c000-i2c",
|
||||
.data = (void *)TYPE_SIFIVE_REV0,
|
||||
},
|
||||
{
|
||||
.compatible = "sifive,i2c0",
|
||||
.data = (void *)TYPE_SIFIVE_REV0,
|
||||
},
|
||||
{},
|
||||
};
|
||||
@ -606,7 +603,6 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ocores_i2c *i2c;
|
||||
struct ocores_i2c_platform_data *pdata;
|
||||
const struct of_device_id *match;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
@ -686,17 +682,20 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
/*
|
||||
* Since the SoC does have an interrupt, its DT has an interrupt
|
||||
* property - But this should be bypassed as the IRQ logic in this
|
||||
* SoC is broken.
|
||||
*/
|
||||
if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"sifive,fu540-c000-i2c")) {
|
||||
i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
|
||||
irq = -ENXIO;
|
||||
}
|
||||
|
||||
if (irq == -ENXIO) {
|
||||
ocores_algorithm.master_xfer = ocores_xfer_polling;
|
||||
|
||||
/*
|
||||
* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
|
||||
* FU540-C000 SoC in polling mode.
|
||||
*/
|
||||
match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
|
||||
if (match && (long)match->data == TYPE_SIFIVE_REV0)
|
||||
i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
|
||||
} else {
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
@ -76,6 +77,7 @@
|
||||
#define OWL_I2C_FIFOCTL_TFR BIT(2)
|
||||
|
||||
/* I2Cc_FIFOSTAT Bit Mask */
|
||||
#define OWL_I2C_FIFOSTAT_CECB BIT(0)
|
||||
#define OWL_I2C_FIFOSTAT_RNB BIT(1)
|
||||
#define OWL_I2C_FIFOSTAT_RFE BIT(2)
|
||||
#define OWL_I2C_FIFOSTAT_TFF BIT(5)
|
||||
@ -83,7 +85,8 @@
|
||||
#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8)
|
||||
|
||||
/* I2C bus timeout */
|
||||
#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000)
|
||||
#define OWL_I2C_TIMEOUT_MS (4 * 1000)
|
||||
#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
|
||||
|
||||
#define OWL_I2C_MAX_RETRIES 50
|
||||
|
||||
@ -161,14 +164,11 @@ static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
|
||||
writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
|
||||
}
|
||||
|
||||
static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = _dev;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
unsigned int stat, fifostat;
|
||||
|
||||
spin_lock(&i2c_dev->lock);
|
||||
|
||||
i2c_dev->err = 0;
|
||||
|
||||
/* Handle NACK from slave */
|
||||
@ -178,7 +178,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
/* Clear NACK error bit by writing "1" */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
|
||||
OWL_I2C_FIFOSTAT_RNB, true);
|
||||
goto stop;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle bus error */
|
||||
@ -188,7 +188,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
/* Clear BUS error bit by writing "1" */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
|
||||
OWL_I2C_STAT_BEB, true);
|
||||
goto stop;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle FIFO read */
|
||||
@ -206,8 +206,16 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
i2c_dev->base + OWL_I2C_REG_TXDAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = _dev;
|
||||
|
||||
spin_lock(&i2c_dev->lock);
|
||||
|
||||
owl_i2c_xfer_data(i2c_dev);
|
||||
|
||||
stop:
|
||||
/* Clear pending interrupts */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
|
||||
OWL_I2C_STAT_IRQP, true);
|
||||
@ -240,8 +248,8 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num, bool atomic)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
struct i2c_msg *msg;
|
||||
@ -285,11 +293,12 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
reinit_completion(&i2c_dev->msg_complete);
|
||||
if (!atomic)
|
||||
reinit_completion(&i2c_dev->msg_complete);
|
||||
|
||||
/* Enable I2C controller interrupt */
|
||||
/* Enable/disable I2C controller interrupt */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
|
||||
OWL_I2C_CTL_IRQE, true);
|
||||
OWL_I2C_CTL_IRQE, !atomic);
|
||||
|
||||
/*
|
||||
* Select: FIFO enable, Master mode, Stop enable, Data count enable,
|
||||
@ -357,20 +366,33 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
|
||||
spin_unlock_irqrestore(&i2c_dev->lock, flags);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
adap->timeout);
|
||||
if (atomic) {
|
||||
/* Wait for Command Execute Completed or NACK Error bits */
|
||||
ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
|
||||
val, val & (OWL_I2C_FIFOSTAT_CECB |
|
||||
OWL_I2C_FIFOSTAT_RNB),
|
||||
10, OWL_I2C_TIMEOUT_MS * 1000);
|
||||
} else {
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
adap->timeout);
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&i2c_dev->lock, flags);
|
||||
if (time_left == 0) {
|
||||
|
||||
if (ret) {
|
||||
dev_err(&adap->dev, "Transaction timed out\n");
|
||||
/* Send stop condition and release the bus */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
|
||||
OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
|
||||
true);
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (atomic)
|
||||
owl_i2c_xfer_data(i2c_dev);
|
||||
|
||||
ret = i2c_dev->err < 0 ? i2c_dev->err : num;
|
||||
|
||||
err_exit:
|
||||
@ -384,9 +406,22 @@ unlocked_err_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
return owl_i2c_xfer_common(adap, msgs, num, false);
|
||||
}
|
||||
|
||||
static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return owl_i2c_xfer_common(adap, msgs, num, true);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm owl_i2c_algorithm = {
|
||||
.master_xfer = owl_i2c_master_xfer,
|
||||
.functionality = owl_i2c_func,
|
||||
.master_xfer = owl_i2c_xfer,
|
||||
.master_xfer_atomic = owl_i2c_xfer_atomic,
|
||||
.functionality = owl_i2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks owl_i2c_quirks = {
|
||||
@ -473,6 +508,7 @@ disable_clk:
|
||||
}
|
||||
|
||||
static const struct of_device_id owl_i2c_of_match[] = {
|
||||
{ .compatible = "actions,s500-i2c" },
|
||||
{ .compatible = "actions,s700-i2c" },
|
||||
{ .compatible = "actions,s900-i2c" },
|
||||
{ /* sentinel */ }
|
||||
@ -484,6 +520,7 @@ static struct platform_driver owl_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "owl-i2c",
|
||||
.of_match_table = of_match_ptr(owl_i2c_of_match),
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
module_platform_driver(owl_i2c_driver);
|
||||
|
@ -33,8 +33,6 @@ struct i2c_pca_pf_data {
|
||||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_pca_data algo_data;
|
||||
unsigned long io_base;
|
||||
unsigned long io_size;
|
||||
};
|
||||
|
||||
/* Read/Write functions for different register alignments */
|
||||
@ -156,8 +154,6 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
|
||||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
i2c->io_base = res->start;
|
||||
i2c->io_size = resource_size(res);
|
||||
i2c->irq = irq;
|
||||
|
||||
i2c->adap.nr = pdev->id;
|
||||
|
@ -264,9 +264,6 @@ struct pxa_i2c {
|
||||
u32 hs_mask;
|
||||
|
||||
struct i2c_bus_recovery_info recovery;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pinctrl_default;
|
||||
struct pinctrl_state *pinctrl_recovery;
|
||||
};
|
||||
|
||||
#define _IBMR(i2c) ((i2c)->reg_ibmr)
|
||||
@ -1305,13 +1302,12 @@ static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap)
|
||||
*/
|
||||
gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS);
|
||||
gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS);
|
||||
|
||||
WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery));
|
||||
}
|
||||
|
||||
static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
|
||||
{
|
||||
struct pxa_i2c *i2c = adap->algo_data;
|
||||
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||
u32 isr;
|
||||
|
||||
/*
|
||||
@ -1325,7 +1321,7 @@ static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
|
||||
i2c_pxa_do_reset(i2c);
|
||||
}
|
||||
|
||||
WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default));
|
||||
WARN_ON(pinctrl_select_state(bri->pinctrl, bri->pins_default));
|
||||
|
||||
dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n",
|
||||
readl(_IBMR(i2c)), readl(_ISR(i2c)));
|
||||
@ -1347,76 +1343,20 @@ static int i2c_pxa_init_recovery(struct pxa_i2c *i2c)
|
||||
if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE))
|
||||
return 0;
|
||||
|
||||
i2c->pinctrl = devm_pinctrl_get(dev);
|
||||
if (PTR_ERR(i2c->pinctrl) == -ENODEV)
|
||||
i2c->pinctrl = NULL;
|
||||
if (IS_ERR(i2c->pinctrl))
|
||||
return PTR_ERR(i2c->pinctrl);
|
||||
|
||||
if (!i2c->pinctrl)
|
||||
return 0;
|
||||
|
||||
i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl,
|
||||
PINCTRL_STATE_DEFAULT);
|
||||
i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery");
|
||||
|
||||
if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) {
|
||||
dev_info(dev, "missing pinmux recovery information: %ld %ld\n",
|
||||
PTR_ERR(i2c->pinctrl_default),
|
||||
PTR_ERR(i2c->pinctrl_recovery));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Claiming GPIOs can influence the pinmux state, and may glitch the
|
||||
* I2C bus. Do this carefully.
|
||||
*/
|
||||
bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||
if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER))
|
||||
return -EPROBE_DEFER;
|
||||
if (IS_ERR(bri->scl_gpiod)) {
|
||||
dev_info(dev, "missing scl gpio recovery information: %pe\n",
|
||||
bri->scl_gpiod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have SCL. Pull SCL low and wait a bit so that SDA glitches
|
||||
* have no effect.
|
||||
*/
|
||||
gpiod_direction_output(bri->scl_gpiod, 0);
|
||||
udelay(10);
|
||||
bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||
|
||||
/* Wait a bit in case of a SDA glitch, and then release SCL. */
|
||||
udelay(10);
|
||||
gpiod_direction_output(bri->scl_gpiod, 1);
|
||||
|
||||
if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (IS_ERR(bri->sda_gpiod)) {
|
||||
dev_info(dev, "missing sda gpio recovery information: %pe\n",
|
||||
bri->sda_gpiod);
|
||||
bri->pinctrl = devm_pinctrl_get(dev);
|
||||
if (PTR_ERR(bri->pinctrl) == -ENODEV) {
|
||||
bri->pinctrl = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (IS_ERR(bri->pinctrl))
|
||||
return PTR_ERR(bri->pinctrl);
|
||||
|
||||
bri->prepare_recovery = i2c_pxa_prepare_recovery;
|
||||
bri->unprepare_recovery = i2c_pxa_unprepare_recovery;
|
||||
bri->recover_bus = i2c_generic_scl_recovery;
|
||||
|
||||
i2c->adap.bus_recovery_info = bri;
|
||||
|
||||
/*
|
||||
* Claiming GPIOs can change the pinmux state, which confuses the
|
||||
* pinctrl since pinctrl's idea of the current setting is unaffected
|
||||
* by the pinmux change caused by claiming the GPIO. Work around that
|
||||
* by switching pinctrl to the GPIO state here. We do it this way to
|
||||
* avoid glitching the I2C bus.
|
||||
*/
|
||||
pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery);
|
||||
|
||||
return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_pxa_probe(struct platform_device *dev)
|
||||
|
@ -353,19 +353,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
{
|
||||
dma_addr_t rx_dma;
|
||||
unsigned long time_left;
|
||||
void *dma_buf = NULL;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_READ, m_param);
|
||||
|
||||
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
@ -373,8 +372,6 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
geni_se_setup_m_cmd(se, I2C_READ, m_param);
|
||||
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!time_left)
|
||||
geni_i2c_abort_xfer(gi2c);
|
||||
@ -395,19 +392,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
{
|
||||
dma_addr_t tx_dma;
|
||||
unsigned long time_left;
|
||||
void *dma_buf = NULL;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
|
||||
|
||||
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
@ -415,8 +411,6 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
||||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
|
||||
|
||||
if (!dma_buf) /* Get FIFO IRQ */
|
||||
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
|
@ -956,10 +956,38 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sh_mobile_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
|
||||
|
||||
i2c_mark_adapter_suspended(&pd->adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
|
||||
|
||||
i2c_mark_adapter_resumed(&pd->adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sh_mobile_i2c_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend,
|
||||
sh_mobile_i2c_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static struct platform_driver sh_mobile_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-sh_mobile",
|
||||
.of_match_table = sh_mobile_i2c_dt_ids,
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
.probe = sh_mobile_i2c_probe,
|
||||
.remove = sh_mobile_i2c_remove,
|
||||
|
@ -549,17 +549,18 @@ put_sync_adapter:
|
||||
|
||||
static int i2c_device_remove(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
int status = 0;
|
||||
|
||||
if (!client || !dev->driver)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (driver->remove) {
|
||||
int status;
|
||||
|
||||
dev_dbg(dev, "remove\n");
|
||||
|
||||
status = driver->remove(client);
|
||||
if (status)
|
||||
dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status));
|
||||
}
|
||||
|
||||
dev_pm_domain_detach(&client->dev, true);
|
||||
@ -571,7 +572,8 @@ static int i2c_device_remove(struct device *dev)
|
||||
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
|
||||
pm_runtime_put(&client->adapter->dev);
|
||||
|
||||
return status;
|
||||
/* return always 0 because there is WIP to make remove-functions void */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_device_shutdown(struct device *dev)
|
||||
|
@ -266,36 +266,63 @@ EXPORT_SYMBOL(geni_se_init);
|
||||
static void geni_se_select_fifo_mode(struct geni_se *se)
|
||||
{
|
||||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val;
|
||||
u32 val, val_old;
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
/*
|
||||
* The RX path for the UART is asynchronous and so needs more
|
||||
* complex logic for enabling / disabling its interrupts.
|
||||
*
|
||||
* Specific notes:
|
||||
* - The done and TX-related interrupts are managed manually.
|
||||
* - We don't RX from the main sequencer (we use the secondary) so
|
||||
* we don't need the RX-related interrupts enabled in the main
|
||||
* sequencer for UART.
|
||||
*/
|
||||
if (proto != GENI_SE_UART) {
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
|
||||
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
|
||||
}
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
if (proto != GENI_SE_UART)
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val |= S_CMD_DONE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val &= ~GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
static void geni_se_select_dma_mode(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val, val_old;
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (proto != GENI_SE_UART) {
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
|
||||
val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val &= ~S_CMD_DONE_EN;
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val |= GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -651,7 +678,7 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
|
||||
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_TX_LEN);
|
||||
writel(len, se->base + SE_DMA_TX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_dma_prep);
|
||||
@ -688,7 +715,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
|
||||
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
|
||||
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_RX_LEN);
|
||||
writel(len, se->base + SE_DMA_RX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_dma_prep);
|
||||
|
Loading…
x
Reference in New Issue
Block a user