Commit 4e2c9cd7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'i2c-for-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "I2C core:

   - finally remove the I2C_COMPAT symbol after 15 years of deprecation

   - lock client addresses during initialization to prevent race
     conditions between different kinds of instantiation

   - use scoped foreach OF child loops

   - testunit cleanups and documentation improvements, as well as two
     new tests, one for repeated start and one for triggering SMBusAlert
     interrupts

  I2C host drivers:

   - DesignWare and Renesas I2C driver updates.

     The first has has undergone through a series of cleanups that have
     been sent to the mailing list a year ago for the first time and
     finally get merged in this pull request. They are many, from typos
     (e.g. i2/i2c), to cosmetics, to refactoring (e.g. move inline
     functions to librarieas) and many others.

   - all the DesignWare Kconfig options have been grouped under the
     I2C_DESIGNWARE_CORE and this required some adaptation in many of
     the kernel configuration files for different arm and mips boards

  Cleanups:

   - improve the exit path in the runtime resume function for the
     Qualcomm Geni platform

   - get rid of the unused "target_addr" parameter in the Intel LJCA
     driver

   - intialize the restart_flag in the MediaTek controller in one single
     place

   - constify a few global data structures in the virtio driver

   - simplify the bus speed handling in the Renesas driver init function
     making it more readable

   - improved probe function of the Renesas R-Car driver

   - switch the iMX/MXC driver to use RUNTIME_PM_OPS() instead of
     SET_RUNTIME_PM_OPS()

   - iMX/MXC driver cleanups

   - use devm_clk_get_enabled() to simplify the Renesas EMEV2, Ingenic
     and MPC drivers

  Refactoring:

   - Fix a potential out of boundary array access in the Nuvoton driver.

     This is not a bug fix because the issue could never occur due to
     hardware not having the properties listed in the array. The change
     makes the driver more future proof and, at the same time, silences
     code analyzers.

  Improvements:

   - several patches improving the runtime power management handling of
     the Renesas I2C (riic) driver

   - use a more descriptive adapter name in the Intel i801 driver to
     show the presence of the IDF feature

   - kill pending transactions when irq's can't complete their handling
     in the Intel Denverton (ismt) driver, triggering a timeout

  New Feature:

   - support fast mode plus in the Renesas I2C (riic) driver

  New support:

   - Added support for:
      - Renesas R9A08G045
      - Rockchip RK3576
      - KEBA I2C
      - Theobroma Systems Mule Multiplexer.

   - new i2c-keba.c driver

   - new driver for The Mule i2c multiplexer

  Core I2C framework:

   - move runtime PM functions in order to allow them to be accessed
     during device add

  Devicetree:

   - nVidia and Qualcomm binding improvements

   - get rid of redundant "multi-master" property in the aspeed binding

   - convert i2c-sprd binding to YAML

  AT24 updates:

  - document a new model from giantec in DT bindings"

* tag 'i2c-for-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (69 commits)
  i2c: designware: Use pci_get_drvdata()
  i2c: designware: Propagate firmware node
  i2c: designware: Uninline i2c_dw_probe()
  i2c: ljca: Remove unused "target_addr" parameter
  i2c: keba: Add KEBA I2C controller support
  i2c: i801: Use a different adapter-name for IDF adapters
  i2c: core: Setup i2c_adapter runtime-pm before calling device_add()
  dt-bindings: i2c: i2c-sprd: convert to YAML
  i2c: ismt: kill transaction in hardware on timeout
  i2c: designware: Group all DesignWare drivers under a single option
  net: txgbe: Fix I2C Kconfig dependencies
  RISC-V: configs: enable I2C_DESIGNWARE_CORE with I2C_DESIGNWARE_PLATFORM
  mips: configs: enable I2C_DESIGNWARE_CORE with I2C_DESIGNWARE_PLATFORM
  arm64: defconfig: enable I2C_DESIGNWARE_CORE with I2C_DESIGNWARE_PLATFORM
  ARM: configs: enable I2C_DESIGNWARE_CORE with I2C_DESIGNWARE_PLATFORM
  ARC: configs: enable I2C_DESIGNWARE_CORE with I2C_DESIGNWARE_PLATFORM
  i2c: virtio: Constify struct i2c_algorithm and struct virtio_device_id
  i2c: rcar: tidyup priv->devtype handling on rcar_i2c_probe()
  i2c: imx: Convert comma to semicolon
  i2c: jz4780: Use devm_clk_get_enabled() helpers
  ...
parents 00b43f85 c24999e6
......@@ -116,6 +116,7 @@ properties:
- const: atmel,24c02
- items:
- enum:
- giantec,gt24c04a
- onnn,cat24c04
- onnn,cat24c05
- rohm,br24g04
......
......@@ -44,11 +44,6 @@ properties:
description: frequency of the bus clock in Hz defaults to 100 kHz when not
specified
multi-master:
type: boolean
description:
states that there is another master active on this bus
required:
- reg
- compatible
......
......@@ -38,6 +38,7 @@ properties:
- rockchip,rk3308-i2c
- rockchip,rk3328-i2c
- rockchip,rk3568-i2c
- rockchip,rk3576-i2c
- rockchip,rk3588-i2c
- rockchip,rv1126-i2c
- const: rockchip,rk3399-i2c
......
I2C for Spreadtrum platforms
Required properties:
- compatible: Should be "sprd,sc9860-i2c".
- reg: Specify the physical base address of the controller and length
of memory mapped region.
- interrupts: Should contain I2C interrupt.
- clock-names: Should contain following entries:
"i2c" for I2C clock,
"source" for I2C source (parent) clock,
"enable" for I2C module enable clock.
- clocks: Should contain a clock specifier for each entry in clock-names.
- clock-frequency: Contains desired I2C bus clock frequency in Hz.
- #address-cells: Should be 1 to describe address cells for I2C device address.
- #size-cells: Should be 0 means no size cell for I2C device address.
Optional properties:
- Child nodes conforming to I2C bus binding
Examples:
i2c0: i2c@70500000 {
compatible = "sprd,sc9860-i2c";
reg = <0 0x70500000 0 0x1000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "i2c", "source", "enable";
clocks = <&clk_i2c3>, <&ext_26m>, <&clk_ap_apb_gates 11>;
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
};
......@@ -103,6 +103,9 @@ properties:
items:
- const: i2c
power-domains:
maxItems: 1
dmas:
items:
- description: DMA channel for the reception FIFO
......@@ -124,6 +127,8 @@ allOf:
- nvidia,tegra30-i2c
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: div-clk
......@@ -133,20 +138,13 @@ allOf:
properties:
compatible:
contains:
const: nvidia,tegra114-i2c
then:
properties:
clock-names:
items:
- const: div-clk
- if:
properties:
compatible:
contains:
const: nvidia,tegra210-i2c
enum:
- nvidia,tegra114-i2c
- nvidia,tegra210-i2c
then:
properties:
clocks:
maxItems: 1
clock-names:
items:
- const: div-clk
......@@ -158,6 +156,8 @@ allOf:
const: nvidia,tegra210-i2c-vi
then:
properties:
clocks:
minItems: 2
clock-names:
items:
- const: div-clk
......@@ -165,6 +165,9 @@ allOf:
power-domains:
items:
- description: phandle to the VENC power domain
else:
properties:
power-domains: false
unevaluatedProperties: false
......
......@@ -130,6 +130,7 @@ allOf:
then:
properties:
clocks:
minItems: 4
maxItems: 4
clock-names:
items:
......
......@@ -25,6 +25,10 @@ properties:
- renesas,riic-r9a07g054 # RZ/V2L
- const: renesas,riic-rz # RZ/A or RZ/G2L
- items:
- const: renesas,riic-r9a08g045 # RZ/G3S
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
reg:
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/sprd,sc9860-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Spreadtrum SC9860 I2C controller
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: sprd,sc9860-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: I2C clock
- description: I2C source (parent) clock
- description: I2C module enable clock
clock-names:
items:
- const: i2c
- const: source
- const: enable
clock-frequency: true
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- clock-frequency
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c@70500000 {
compatible = "sprd,sc9860-i2c";
reg = <0x70500000 0x1000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_i2c3>, <&ext_26m>, <&clk_ap_apb_gates 11>;
clock-names = "i2c", "source", "enable";
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/tsd,mule-i2c-mux.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Theobroma Systems Mule I2C multiplexer
maintainers:
- Farouk Bouabid <farouk.bouabid@cherry.de>
- Quentin Schulz <quentin.schulz@cherry.de>
description: |
Theobroma Systems Mule is an MCU that emulates a set of I2C devices, among
which devices that are reachable through an I2C-mux. The devices on the mux
can be selected by writing the appropriate device number to an I2C config
register.
+--------------------------------------------------+
| Mule |
0x18| +---------------+ |
-------->|Config register|----+ |
| +---------------+ | |
| V_ |
| | \ +--------+ |
| | \-------->| dev #0 | |
| | | +--------+ |
0x6f| | M |-------->| dev #1 | |
---------------------------->| U | +--------+ |
| | X |-------->| dev #2 | |
| | | +--------+ |
| | /-------->| dev #3 | |
| |__/ +--------+ |
+--------------------------------------------------+
allOf:
- $ref: /schemas/i2c/i2c-mux.yaml#
properties:
compatible:
const: tsd,mule-i2c-mux
required:
- compatible
unevaluatedProperties: false
examples:
- |
i2c-mux {
compatible = "tsd,mule-i2c-mux";
#address-cells = <1>;
#size-cells = <0>;
i2c@0 {
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
rtc@6f {
compatible = "isil,isl1208";
reg = <0x6f>;
};
};
};
...
......@@ -20,11 +20,25 @@ Instantiating the device is regular. Example for bus 0, address 0x30::
# echo "slave-testunit 0x1030" > /sys/bus/i2c/devices/i2c-0/new_device
After that, you will have a write-only device listening. Reads will just return
an 8-bit version number of the testunit. When writing, the device consists of 4
8-bit registers and, except for some "partial" commands, all registers must be
written to start a testcase, i.e. you usually write 4 bytes to the device. The
registers are:
Or using firmware nodes. Here is a devicetree example (note this is only a
debug device, so there are no official DT bindings)::
&i2c0 {
...
testunit@30 {
compatible = "slave-testunit";
reg = <(0x30 | I2C_OWN_SLAVE_ADDRESS)>;
};
};
After that, you will have the device listening. Reading will return a single
byte. Its value is 0 if the testunit is idle, otherwise the command number of
the currently running command.
When writing, the device consists of 4 8-bit registers and, except for some
"partial" commands, all registers must be written to start a testcase, i.e. you
usually write 4 bytes to the device. The registers are:
.. csv-table::
:header: "Offset", "Name", "Description"
......@@ -75,7 +89,7 @@ from another device on the bus. If the bus master under test also wants to
access the bus at the same time, the bus will be busy. Example to read 128
bytes from device 0x50 after 50ms of delay::
# i2cset -y 0 0x30 0x01 0x50 0x80 0x05 i
# i2cset -y 0 0x30 1 0x50 0x80 5 i
0x02 SMBUS_HOST_NOTIFY
~~~~~~~~~~~~~~~~~~~~~~
......@@ -95,9 +109,9 @@ bytes from device 0x50 after 50ms of delay::
Also needs master mode. This test will send an SMBUS_HOST_NOTIFY message to the
host. Note that the status word is currently ignored in the Linux Kernel.
Example to send a notification after 10ms::
Example to send a notification with status word 0x6442 after 10ms::
# i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i
# i2cset -y 0 0x30 2 0x42 0x64 1 i
If the host controller supports HostNotify, this message with debug level
should appear (Linux 6.11 and later)::
......@@ -116,7 +130,7 @@ should appear (Linux 6.11 and later)::
- DELAY
* - 0x03
- must be '1', i.e. one further byte will be written
- 0x01 (i.e. one further byte will be written)
- number of bytes to be sent back
- leave out, partial command!
......@@ -131,5 +145,91 @@ from length-1 to 0. Here is an example which emulates
i2c_smbus_block_process_call() using i2ctransfer (you need i2c-tools v4.2 or
later)::
# i2ctransfer -y 0 w3@0x30 0x03 0x01 0x10 r?
# i2ctransfer -y 0 w3@0x30 3 1 0x10 r?
0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
0x04 GET_VERSION_WITH_REP_START
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. list-table::
:header-rows: 1
* - CMD
- DATAL
- DATAH
- DELAY
* - 0x04
- currently unused
- currently unused
- leave out, partial command!
Partial command. After sending this command, the testunit will reply to a read
message with a NUL terminated version string based on UTS_RELEASE. The first
character is always a 'v' and the length of the version string is at maximum
128 bytes. However, it will only respond if the read message is connected to
the write message via repeated start. If your controller driver handles
repeated start correctly, this will work::
# i2ctransfer -y 0 w3@0x30 4 0 0 r128
0x76 0x36 0x2e 0x31 0x31 0x2e 0x30 0x2d 0x72 0x63 0x31 0x2d 0x30 0x30 0x30 0x30 ...
If you have i2c-tools 4.4 or later, you can print out the data right away::
# i2ctransfer -y -b 0 w3@0x30 4 0 0 r128
v6.11.0-rc1-00009-gd37a1b4d3fd0
STOP/START combinations between the two messages will *not* work because they
are not equivalent to a REPEATED START. As an example, this returns just the
default response::
# i2cset -y 0 0x30 4 0 0 i; i2cget -y 0 0x30
0x00
0x05 SMBUS_ALERT_REQUEST
~~~~~~~~~~~~~~~~~~~~~~~~
.. list-table::
:header-rows: 1
* - CMD
- DATAL
- DATAH
- DELAY
* - 0x05
- response value (7 MSBs interpreted as I2C address)
- currently unused
- n * 10ms
This test raises an interrupt via the SMBAlert pin which the host controller
must handle. The pin must be connected to the testunit as a GPIO. GPIO access
is not allowed to sleep. Currently, this can only be described using firmware
nodes. So, for devicetree, you would add something like this to the testunit
node::
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
The following command will trigger the alert with a response of 0xc9 after 1
second of delay::
# i2cset -y 0 0x30 5 0xc9 0x00 100 i
If the host controller supports SMBusAlert, this message with debug level
should appear::
smbus_alert 0-000c: SMBALERT# from dev 0x64, flag 1
This message may appear more than once because the testunit is software not
hardware and, thus, may not be able to react to the response of the host fast
enough. The interrupt count should increase only by one, though::
# cat /proc/interrupts | grep smbus_alert
93: 1 gpio-rcar 26 Edge smbus_alert
If the host does not respond to the alert within 1 second, the test will be
aborted and the testunit will report an error.
For this test, the testunit will shortly drop its assigned address and listen
on the SMBus Alert Response Address (0x0c). It will reassign its original
address afterwards.
......@@ -66,6 +66,7 @@ CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
# CONFIG_HWMON is not set
CONFIG_DRM=m
......
......@@ -66,6 +66,7 @@ CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
# CONFIG_HWMON is not set
CONFIG_FB=y
......
......@@ -66,6 +66,7 @@ CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
# CONFIG_HWMON is not set
CONFIG_DRM=m
......
......@@ -60,6 +60,7 @@ CONFIG_SERIAL_8250_DW=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
......
......@@ -43,6 +43,7 @@ CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
......
......@@ -413,6 +413,7 @@ CONFIG_I2C_AT91=m
CONFIG_I2C_BCM2835=y
CONFIG_I2C_CADENCE=y
CONFIG_I2C_DAVINCI=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_DIGICOLOR=m
CONFIG_I2C_EMEV2=m
......
......@@ -277,6 +277,7 @@ CONFIG_HW_RANDOM=y
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_MUX_PCA954x=m
CONFIG_I2C_MUX_PINCTRL=m
CONFIG_I2C_DESIGNWARE_CORE=m
CONFIG_I2C_DESIGNWARE_PLATFORM=m
CONFIG_I2C_GPIO=y
CONFIG_I2C_PXA_SLAVE=y
......
......@@ -83,6 +83,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=2
CONFIG_SERIAL_8250_DW=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_CADENCE_QUADSPI=y
......
......@@ -62,6 +62,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_RAW_DRIVER=y
CONFIG_I2C=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
......
......@@ -42,6 +42,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_HW_RANDOM is not set
CONFIG_RAW_DRIVER=y
CONFIG_I2C=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
......
......@@ -33,6 +33,7 @@ CONFIG_STMMAC_ETH=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_I2C=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
......
......@@ -518,6 +518,7 @@ CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_BCM2835=m
CONFIG_I2C_CADENCE=m
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_GPIO=m
CONFIG_I2C_IMX=y
......
......@@ -31,6 +31,7 @@ CONFIG_MICROSEMI_PHY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
......
......@@ -157,6 +157,7 @@ CONFIG_HW_RANDOM_VIRTIO=y
CONFIG_HW_RANDOM_JH7110=m
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_I2C_MV64XXX=m
CONFIG_I2C_RIIC=y
......
......@@ -58,6 +58,7 @@ CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_HELPER_AUTO is not set
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
# CONFIG_SPI_MEM is not set
......
......@@ -50,6 +50,7 @@ CONFIG_DEVTMPFS_MOUNT=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_HELPER_AUTO is not set
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
# CONFIG_SPI_MEM is not set
......
......@@ -40,14 +40,6 @@ config I2C_BOARDINFO
bool
default y
config I2C_COMPAT
bool "Enable compatibility bits for old user-space"
default y
help
Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
other user-space package which expects i2c adapters to be class
devices. If you don't know, say Y.
config I2C_CHARDEV
tristate "I2C device interface"
help
......
......@@ -559,28 +559,33 @@ config I2C_DAVINCI
For details please see http://www.ti.com/davinci
config I2C_DESIGNWARE_CORE
tristate
tristate "Synopsys DesignWare I2C adapter"
select REGMAP
help
This option enables support for the Synopsys DesignWare I2C adapter.
This driver includes support for the I2C host on the Synopsys
Designware I2C adapter.
To compile the driver as a module, choose M here: the module will be
called i2c-designware-core.
if I2C_DESIGNWARE_CORE
config I2C_DESIGNWARE_SLAVE
bool "Synopsys DesignWare Slave"
depends on I2C_DESIGNWARE_CORE
select I2C_SLAVE
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C slave adapter.
This is not a standalone module, this module compiles together with
i2c-designware-core.
config I2C_DESIGNWARE_PLATFORM
tristate "Synopsys DesignWare Platform"
tristate "Synopsys DesignWare Platform driver"
depends on (ACPI && COMMON_CLK) || !ACPI
select I2C_DESIGNWARE_CORE
select MFD_SYSCON if MIPS_BAIKAL_T1
default I2C_DESIGNWARE_CORE
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter.
Synopsys DesignWare I2C adapters on the platform bus.
This driver can also be built as a module. If so, the module
will be called i2c-designware-platform.
......@@ -613,17 +618,19 @@ config I2C_DESIGNWARE_BAYTRAIL
a BayTrail system using the AXP288.
config I2C_DESIGNWARE_PCI
tristate "Synopsys DesignWare PCI"
tristate "Synopsys DesignWare PCI driver"
depends on PCI
select I2C_DESIGNWARE_CORE
select I2C_CCGX_UCSI
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
Synopsys DesignWare I2C adapters on the PCI bus. Only master mode is
supported.
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
endif
config I2C_DIGICOLOR
tristate "Conexant Digicolor I2C driver"
depends on ARCH_DIGICOLOR || COMPILE_TEST
......@@ -772,6 +779,17 @@ config I2C_JZ4780
If you don't know what to do here, say N.
config I2C_KEBA
tristate "KEBA I2C controller support"
depends on HAS_IOMEM
select AUXILIARY_BUS
help
This driver supports the I2C controller found in KEBA system FPGA
devices.
This driver can also be built as a module. If so, the module
will be called i2c-keba.
config I2C_KEMPLD
tristate "Kontron COM I2C Controller"
depends on MFD_KEMPLD
......
......@@ -76,6 +76,7 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEBA) += i2c-keba.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
......
......@@ -479,9 +479,8 @@ static struct i2c_adapter ali1535_adapter = {
static const struct pci_device_id ali1535_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ },
{ }
};
MODULE_DEVICE_TABLE(pci, ali1535_ids);
static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
......
......@@ -340,7 +340,7 @@ static void i2c_amd_remove(struct platform_device *pdev)
static const struct acpi_device_id i2c_amd_acpi_match[] = {
{ "AMDI0011" },
{ },
{ }
};
MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match);
......
......@@ -991,7 +991,7 @@ static const struct of_device_id aspeed_i2c_bus_of_table[] = {
.compatible = "aspeed,ast2600-i2c-bus",
.data = aspeed_i2c_25xx_get_clk_reg_val,
},
{ },
{ }
};
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
......
......@@ -20,12 +20,17 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/swab.h>
#include <linux/types.h>
#include <linux/units.h>
#define DEFAULT_SYMBOL_NAMESPACE I2C_DW_COMMON
#include "i2c-designware-core.h"
static char *abort_sources[] = {
......@@ -188,7 +193,7 @@ static const u32 supported_speeds[] = {
I2C_MAX_STANDARD_MODE_FREQ,
};
int i2c_dw_validate_speed(struct dw_i2c_dev *dev)
static int i2c_dw_validate_speed(struct dw_i2c_dev *dev)
{
struct i2c_timings *t = &dev->timings;
unsigned int i;
......@@ -208,7 +213,44 @@ int i2c_dw_validate_speed(struct dw_i2c_dev *dev)
return -EINVAL;
}
EXPORT_SYMBOL_GPL(i2c_dw_validate_speed);
#ifdef CONFIG_OF
#include <linux/platform_device.h>
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
{
writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
return 0;
}
static void i2c_dw_of_configure(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct dw_i2c_dev *dev = dev_get_drvdata(device);
switch (dev->flags & MODEL_MASK) {
case MODEL_MSCC_OCELOT:
dev->ext = devm_platform_ioremap_resource(pdev, 1);
if (!IS_ERR(dev->ext))
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
break;
default:
break;
}
}
#else /* CONFIG_OF */
static inline void i2c_dw_of_configure(struct device *device) { }
#endif /* CONFIG_OF */
#ifdef CONFIG_ACPI
......@@ -255,7 +297,7 @@ static void i2c_dw_acpi_params(struct device *device, char method[],
kfree(buf.pointer);
}
int i2c_dw_acpi_configure(struct device *device)
static void i2c_dw_acpi_configure(struct device *device)
{
struct dw_i2c_dev *dev = dev_get_drvdata(device);
struct i2c_timings *t = &dev->timings;
......@@ -285,10 +327,7 @@ int i2c_dw_acpi_configure(struct device *device)
dev->sda_hold_time = fs_ht;
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(i2c_dw_acpi_configure);
static u32 i2c_dw_acpi_round_bus_speed(struct device *device)
{
......@@ -310,11 +349,13 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device)
#else /* CONFIG_ACPI */
static inline void i2c_dw_acpi_configure(struct device *device) { }
static inline u32 i2c_dw_acpi_round_bus_speed(struct device *device) { return 0; }
#endif /* CONFIG_ACPI */
void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
static void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
{
u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev);
struct i2c_timings *t = &dev->timings;
......@@ -330,10 +371,47 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
else
t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
}
EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed);
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev)
{
struct i2c_timings *t = &dev->timings;
struct device *device = dev->dev;
struct fwnode_handle *fwnode = dev_fwnode(device);
i2c_parse_fw_timings(device, t, false);
i2c_dw_adjust_bus_speed(dev);
if (is_of_node(fwnode))
i2c_dw_of_configure(device);
else if (is_acpi_node(fwnode))
i2c_dw_acpi_configure(device);
return i2c_dw_validate_speed(dev);
}
EXPORT_SYMBOL_GPL(i2c_dw_fw_parse_and_configure);
static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg)
{
u32 val;
int ret;
ret = i2c_dw_acquire_lock(dev);
if (ret)
return 0;
ret = regmap_read(dev->map, reg, &val);
i2c_dw_release_lock(dev);
return ret ? 0 : val;
}
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tSYMBOL, u32 tf, int cond, int offset)
{
if (!ic_clk)
return i2c_dw_read_scl_reg(dev, reg);
/*
* DesignWare I2C core doesn't seem to have solid strategy to meet
* the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
......@@ -372,8 +450,12 @@ u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
3 + offset;
}
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tLOW, u32 tf, int offset)
{
if (!ic_clk)
return i2c_dw_read_scl_reg(dev, reg);
/*
* Conditional expression:
*
......@@ -653,6 +735,84 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
i2c_dw_release_lock(dev);
}
EXPORT_SYMBOL_GPL(i2c_dw_disable);
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
device_set_node(&dev->adapter.dev, dev_fwnode(dev->dev));
switch (dev->mode) {
case DW_IC_SLAVE:
return i2c_dw_probe_slave(dev);
case DW_IC_MASTER:
return i2c_dw_probe_master(dev);
default:
dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode);
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(i2c_dw_probe);
static int i2c_dw_prepare(struct device *device)
{
/*
* If the ACPI companion device object is present for this device,
* it may be accessed during suspend and resume of other devices via
* I2C operation regions, so tell the PM core and middle layers to
* avoid skipping system suspend/resume callbacks for it in that case.
*/
return !has_acpi_companion(device);
}
static int i2c_dw_runtime_suspend(struct device *device)
{
struct dw_i2c_dev *dev = dev_get_drvdata(device);
if (dev->shared_with_punit)
return 0;
i2c_dw_disable(dev);
i2c_dw_prepare_clk(dev, false);
return 0;
}
static int i2c_dw_suspend(struct device *device)
{
struct dw_i2c_dev *dev = dev_get_drvdata(device);
i2c_mark_adapter_suspended(&dev->adapter);
return i2c_dw_runtime_suspend(device);
}
static int i2c_dw_runtime_resume(struct device *device)
{
struct dw_i2c_dev *dev = dev_get_drvdata(device);
if (!dev->shared_with_punit)
i2c_dw_prepare_clk(dev, true);
dev->init(dev);
return 0;
}
static int i2c_dw_resume(struct device *device)
{
struct dw_i2c_dev *dev = dev_get_drvdata(device);
i2c_dw_runtime_resume(device);
i2c_mark_adapter_resumed(&dev->adapter);
return 0;
}
EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = {
.prepare = pm_sleep_ptr(i2c_dw_prepare),
LATE_SYSTEM_SLEEP_PM_OPS(i2c_dw_suspend, i2c_dw_resume)
RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL)
};
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
MODULE_LICENSE("GPL");
......@@ -10,11 +10,10 @@
*/
#include <linux/bits.h>
#include <linux/compiler_types.h>
#include <linux/completion.h>
#include <linux/dev_printk.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/types.h>
......@@ -237,7 +236,6 @@ struct reset_control;
* @semaphore_idx: Index of table with semaphore type attached to the bus. It's
* -1 if there is no semaphore.
* @shared_with_punit: true if this bus is shared with the SoCs PUNIT
* @disable: function to disable the controller
* @init: function to initialize the I2C hardware
* @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
......@@ -295,7 +293,6 @@ struct dw_i2c_dev {
void (*release_lock)(void);
int semaphore_idx;
bool shared_with_punit;
void (*disable)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode;
......@@ -329,8 +326,10 @@ struct i2c_dw_semaphore_callbacks {
};
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);
u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tSYMBOL, u32 tf, int cond, int offset);
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
u32 tLOW, u32 tf, int offset);
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev);
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
......@@ -340,7 +339,8 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
u32 i2c_dw_func(struct i2c_adapter *adap);
void i2c_dw_disable(struct dw_i2c_dev *dev);
extern const struct dev_pm_ops i2c_dw_dev_pm_ops;
static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
{
......@@ -373,6 +373,7 @@ static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
}
void __i2c_dw_disable(struct dw_i2c_dev *dev);
void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
extern int i2c_dw_probe_master(struct dw_i2c_dev *dev);
......@@ -385,19 +386,6 @@ static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { }
static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
#endif
static inline int i2c_dw_probe(struct dw_i2c_dev *dev)
{
switch (dev->mode) {
case DW_IC_SLAVE:
return i2c_dw_probe_slave(dev);
case DW_IC_MASTER:
return i2c_dw_probe_master(dev);
default:
dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode);
return -EINVAL;
}
}
static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
{
if (i2c_detect_slave_mode(dev->dev))
......@@ -406,6 +394,8 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
i2c_dw_configure_master(dev);
}
int i2c_dw_probe(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev);
#endif
......@@ -414,11 +404,4 @@ int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev);
int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev);
#endif
int i2c_dw_validate_speed(struct dw_i2c_dev *dev);
void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_ACPI)
int i2c_dw_acpi_configure(struct device *device);
#else
static inline int i2c_dw_acpi_configure(struct device *device) { return -ENODEV; }
#endif
int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev);
......@@ -22,6 +22,8 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#define DEFAULT_SYMBOL_NAMESPACE I2C_DW
#include "i2c-designware-core.h"
#define AMD_TIMEOUT_MIN_US 25
......@@ -64,13 +66,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
if (!dev->ss_hcnt || !dev->ss_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
dev->ss_hcnt =
i2c_dw_scl_hcnt(ic_clk,
i2c_dw_scl_hcnt(dev,
DW_IC_SS_SCL_HCNT,
ic_clk,
4000, /* tHD;STA = tHIGH = 4.0 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->ss_lcnt =
i2c_dw_scl_lcnt(ic_clk,
i2c_dw_scl_lcnt(dev,
DW_IC_SS_SCL_LCNT,
ic_clk,
4700, /* tLOW = 4.7 us */
scl_falling_time,
0); /* No offset */
......@@ -94,13 +100,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
} else {
ic_clk = i2c_dw_clk_rate(dev);
dev->fs_hcnt =
i2c_dw_scl_hcnt(ic_clk,
i2c_dw_scl_hcnt(dev,
DW_IC_FS_SCL_HCNT,
ic_clk,
260, /* tHIGH = 260 ns */
sda_falling_time,
0, /* DW default */
0); /* No offset */
dev->fs_lcnt =
i2c_dw_scl_lcnt(ic_clk,
i2c_dw_scl_lcnt(dev,
DW_IC_FS_SCL_LCNT,
ic_clk,
500, /* tLOW = 500 ns */
scl_falling_time,
0); /* No offset */
......@@ -114,13 +124,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
if (!dev->fs_hcnt || !dev->fs_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
dev->fs_hcnt =
i2c_dw_scl_hcnt(ic_clk,
i2c_dw_scl_hcnt(dev,
DW_IC_FS_SCL_HCNT,
ic_clk,
600, /* tHD;STA = tHIGH = 0.6 us */
sda_falling_time,
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
dev->fs_lcnt =
i2c_dw_scl_lcnt(ic_clk,
i2c_dw_scl_lcnt(dev,
DW_IC_FS_SCL_LCNT,
ic_clk,
1300, /* tLOW = 1.3 us */
scl_falling_time,
0); /* No offset */
......@@ -142,13 +156,17 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
} else if (!dev->hs_hcnt || !dev->hs_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
dev->hs_hcnt =
i2c_dw_scl_hcnt(ic_clk,
i2c_dw_scl_hcnt(dev,
DW_IC_HS_SCL_HCNT,
ic_clk,
160, /* tHIGH = 160 ns */
sda_falling_time,
0, /* DW default */
0); /* No offset */
dev->hs_lcnt =
i2c_dw_scl_lcnt(ic_clk,
i2c_dw_scl_lcnt(dev,
DW_IC_HS_SCL_LCNT,
ic_clk,
320, /* tLOW = 320 ns */
scl_falling_time,
0); /* No offset */
......@@ -931,7 +949,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
init_completion(&dev->cmd_complete);
dev->init = i2c_dw_init_master;
dev->disable = i2c_dw_disable;
ret = i2c_dw_init_regmap(dev);
if (ret)
......@@ -1021,3 +1038,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_master);
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(I2C_DW_COMMON);
......@@ -9,7 +9,6 @@
* Copyright (C) 2009 Provigent Ltd.
* Copyright (C) 2011, 2015, 2016 Intel Corporation.
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
......@@ -19,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/power_supply.h>
#include <linux/sched.h>
......@@ -102,7 +102,7 @@ static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev)
static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
switch (pdev->device) {
case 0x0817:
......@@ -152,7 +152,7 @@ static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev)
static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING;
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
......@@ -194,47 +194,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
},
};
static int __maybe_unused i2c_dw_pci_runtime_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i_dev->disable(i_dev);
return 0;
}
static int __maybe_unused i2c_dw_pci_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i2c_mark_adapter_suspended(&i_dev->adapter);
return i2c_dw_pci_runtime_suspend(dev);
}
static int __maybe_unused i2c_dw_pci_runtime_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
return i_dev->init(i_dev);
}
static int __maybe_unused i2c_dw_pci_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
int ret;
ret = i2c_dw_pci_runtime_resume(dev);
i2c_mark_adapter_resumed(&i_dev->adapter);
return ret;
}
static const struct dev_pm_ops i2c_dw_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume)
SET_RUNTIME_PM_OPS(i2c_dw_pci_runtime_suspend, i2c_dw_pci_runtime_resume, NULL)
};
static const struct property_entry dgpu_properties[] = {
/* USB-C doesn't power the system */
PROPERTY_ENTRY_U8("scope", POWER_SUPPLY_SCOPE_DEVICE),
......@@ -253,7 +212,6 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
int r;
struct dw_pci_controller *controller;
struct dw_scl_sda_cfg *cfg;
struct i2c_timings *t;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers))
return dev_err_probe(&pdev->dev, -EINVAL,
......@@ -288,29 +246,17 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->irq = pci_irq_vector(pdev, 0);
dev->flags |= controller->flags;
t = &dev->timings;
i2c_parse_fw_timings(&pdev->dev, t, false);
pci_set_drvdata(pdev, dev);
if (controller->setup) {
r = controller->setup(pdev, controller);
if (r) {
pci_free_irq_vectors(pdev);
if (r)
return r;
}
}
i2c_dw_adjust_bus_speed(dev);
if (has_acpi_companion(&pdev->dev))
i2c_dw_acpi_configure(&pdev->dev);
r = i2c_dw_validate_speed(dev);
if (r) {
pci_free_irq_vectors(pdev);
r = i2c_dw_fw_parse_and_configure(dev);
if (r)
return r;
}
i2c_dw_configure(dev);
......@@ -326,14 +272,11 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
adap = &dev->adapter;
adap->owner = THIS_MODULE;
adap->class = 0;
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->nr = controller->bus_num;
r = i2c_dw_probe(dev);
if (r) {
pci_free_irq_vectors(pdev);
if (r)
return r;
}
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node);
......@@ -354,16 +297,15 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
{
struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
dev->disable(dev);
i2c_dw_disable(dev);
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
i2c_del_adapter(&dev->adapter);
devm_free_irq(&pdev->dev, dev->irq, dev);
pci_free_irq_vectors(pdev);
}
static const struct pci_device_id i2_designware_pci_ids[] = {
static const struct pci_device_id i2c_designware_pci_ids[] = {
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), medfield },
{ PCI_VDEVICE(INTEL, 0x0818), medfield },
......@@ -409,21 +351,23 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(ATI, 0x73c4), navi_amd },
{ PCI_VDEVICE(ATI, 0x7444), navi_amd },
{ PCI_VDEVICE(ATI, 0x7464), navi_amd },
{ 0,}
{}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
MODULE_DEVICE_TABLE(pci, i2c_designware_pci_ids);
static struct pci_driver dw_i2c_driver = {
.name = DRIVER_NAME,
.id_table = i2_designware_pci_ids,
.probe = i2c_dw_pci_probe,
.remove = i2c_dw_pci_remove,
.driver = {
.pm = &i2c_dw_pm_ops,
.pm = pm_ptr(&i2c_dw_dev_pm_ops),
},
.id_table = i2c_designware_pci_ids,
};
module_pci_driver(dw_i2c_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(I2C_DW);
MODULE_IMPORT_NS(I2C_DW_COMMON);
......@@ -8,7 +8,6 @@
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
*/
#include <linux/acpi.h>
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/delay.h>
......@@ -21,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
......@@ -30,7 +28,6 @@
#include <linux/reset.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/units.h>
#include "i2c-designware-core.h"
......@@ -40,29 +37,6 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
return clk_get_rate(dev->clk) / KILO;
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
{ "INTC10EF", 0 },
{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ "HISI02A1", 0 },
{ "HISI02A2", 0 },
{ "HISI02A3", 0 },
{ "HYGO0010", ACCESS_INTR_MASK },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
#endif
#ifdef CONFIG_OF
#define BT1_I2C_CTL 0x100
#define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0)
......@@ -120,53 +94,11 @@ static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
return PTR_ERR_OR_ZERO(dev->map);
}
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
{
writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
return 0;
}
static int dw_i2c_of_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
switch (dev->flags & MODEL_MASK) {
case MODEL_MSCC_OCELOT:
dev->ext = devm_platform_ioremap_resource(pdev, 1);
if (!IS_ERR(dev->ext))
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
break;
default:
break;
}
return 0;
}
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#else
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
{
return -ENODEV;
}
static inline int dw_i2c_of_configure(struct platform_device *pdev)
{
return -ENODEV;
}
#endif
static int txgbe_i2c_request_regs(struct dw_i2c_dev *dev)
......@@ -238,11 +170,9 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
int i = 0;
int ret;
ptr = i2c_dw_semaphore_cb_table;
dev->semaphore_idx = -1;
while (ptr->probe) {
for (ptr = i2c_dw_semaphore_cb_table; ptr->probe; ptr++) {
ret = ptr->probe(dev);
if (ret) {
/*
......@@ -254,7 +184,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
return ret;
i++;
ptr++;
continue;
}
......@@ -278,7 +207,6 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct i2c_adapter *adap;
struct dw_i2c_dev *dev;
struct i2c_timings *t;
int irq, ret;
irq = platform_get_irq(pdev, 0);
......@@ -307,18 +235,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
reset_control_deassert(dev->rst);
t = &dev->timings;
i2c_parse_fw_timings(&pdev->dev, t, false);
i2c_dw_adjust_bus_speed(dev);
if (pdev->dev.of_node)
dw_i2c_of_configure(pdev);
if (has_acpi_companion(&pdev->dev))
i2c_dw_acpi_configure(&pdev->dev);
ret = i2c_dw_validate_speed(dev);
ret = i2c_dw_fw_parse_and_configure(dev);
if (ret)
goto exit_reset;
......@@ -346,6 +263,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
goto exit_reset;
if (dev->clk) {
struct i2c_timings *t = &dev->timings;
u64 clk_khz;
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
......@@ -360,8 +278,6 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
adap->owner = THIS_MODULE;
adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?
I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
adap->nr = -1;
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
......@@ -408,7 +324,7 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
i2c_del_adapter(&dev->adapter);
dev->disable(dev);
i2c_dw_disable(dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
......@@ -419,66 +335,34 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
reset_control_assert(dev->rst);
}
static int dw_i2c_plat_prepare(struct device *dev)
{
/*
* If the ACPI companion device object is present for this device, it
* may be accessed during suspend and resume of other devices via I2C
* operation regions, so tell the PM core and middle layers to avoid
* skipping system suspend/resume callbacks for it in that case.
*/
return !has_acpi_companion(dev);
}
static int dw_i2c_plat_runtime_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (i_dev->shared_with_punit)
return 0;
i_dev->disable(i_dev);
i2c_dw_prepare_clk(i_dev, false);
return 0;
}
static int dw_i2c_plat_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i2c_mark_adapter_suspended(&i_dev->adapter);
return dw_i2c_plat_runtime_suspend(dev);
}
static int dw_i2c_plat_runtime_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (!i_dev->shared_with_punit)
i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
return 0;
}
static int dw_i2c_plat_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
dw_i2c_plat_runtime_resume(dev);
i2c_mark_adapter_resumed(&i_dev->adapter);
return 0;
}
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
{}
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
.prepare = pm_sleep_ptr(dw_i2c_plat_prepare),
LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL)
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "80860F41", ACCESS_NO_IRQ_SUSPEND },
{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ "HISI02A1", 0 },
{ "HISI02A2", 0 },
{ "HISI02A3", 0 },
{ "HYGO0010", ACCESS_INTR_MASK },
{ "INT33C2", 0 },
{ "INT33C3", 0 },
{ "INT3432", 0 },
{ "INT3433", 0 },
{ "INTC10EF", 0 },
{}
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
static const struct platform_device_id dw_i2c_platform_ids[] = {
{ "i2c_designware" },
......@@ -491,9 +375,9 @@ static struct platform_driver dw_i2c_driver = {
.remove_new = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
.pm = pm_ptr(&dw_i2c_dev_pm_ops),
.of_match_table = dw_i2c_of_match,
.acpi_match_table = dw_i2c_acpi_match,
.pm = pm_ptr(&i2c_dw_dev_pm_ops),
},
.id_table = dw_i2c_platform_ids,
};
......@@ -513,3 +397,5 @@ module_exit(dw_i2c_exit_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(I2C_DW);
MODULE_IMPORT_NS(I2C_DW_COMMON);
......@@ -16,6 +16,8 @@
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#define DEFAULT_SYMBOL_NAMESPACE I2C_DW
#include "i2c-designware-core.h"
static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
......@@ -88,7 +90,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
dev->disable(dev);
i2c_dw_disable(dev);
synchronize_irq(dev->irq);
dev->slave = NULL;
pm_runtime_put(dev->dev);
......@@ -235,7 +237,6 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
int ret;
dev->init = i2c_dw_init_slave;
dev->disable = i2c_dw_disable;
ret = i2c_dw_init_regmap(dev);
if (ret)
......@@ -279,3 +280,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(I2C_DW_COMMON);
......@@ -357,7 +357,7 @@ static void dc_i2c_remove(struct platform_device *pdev)
static const struct of_device_id dc_i2c_match[] = {
{ .compatible = "cnxt,cx92755-i2c" },
{ },
{ }
};
MODULE_DEVICE_TABLE(of, dc_i2c_match);
......
......@@ -67,7 +67,6 @@ struct em_i2c_device {
void __iomem *base;
struct i2c_adapter adap;
struct completion msg_done;
struct clk *sclk;
struct i2c_client *slave;
int irq;
};
......@@ -361,6 +360,7 @@ static const struct i2c_algorithm em_i2c_algo = {
static int em_i2c_probe(struct platform_device *pdev)
{
struct em_i2c_device *priv;
struct clk *sclk;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
......@@ -373,13 +373,9 @@ static int em_i2c_probe(struct platform_device *pdev)
strscpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name));
priv->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(priv->sclk))
return PTR_ERR(priv->sclk);
ret = clk_prepare_enable(priv->sclk);
if (ret)
return ret;
sclk = devm_clk_get_enabled(&pdev->dev, "sclk");
if (IS_ERR(sclk))
return PTR_ERR(sclk);
priv->adap.timeout = msecs_to_jiffies(100);
priv->adap.retries = 5;
......@@ -397,26 +393,22 @@ static int em_i2c_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto err_clk;
return ret;
priv->irq = ret;
ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0,
"em_i2c", priv);
if (ret)
goto err_clk;
return ret;
ret = i2c_add_adapter(&priv->adap);
if (ret)
goto err_clk;
return ret;
dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr,
priv->irq);
return 0;
err_clk:
clk_disable_unprepare(priv->sclk);
return ret;
}
static void em_i2c_remove(struct platform_device *dev)
......@@ -424,7 +416,6 @@ static void em_i2c_remove(struct platform_device *dev)
struct em_i2c_device *priv = platform_get_drvdata(dev);
i2c_del_adapter(&priv->adap);
clk_disable_unprepare(priv->sclk);
}
static const struct of_device_id em_i2c_ids[] = {
......
......@@ -1763,8 +1763,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
i801_add_tco(priv);
/*
* adapter.name is used by platform code to find the main I801 adapter
* to instantiante i2c_clients, do not change.
*/
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
"SMBus I801 adapter at %04lx", priv->smba);
"SMBus %s adapter at %04lx",
(priv->features & FEATURE_IDF) ? "I801 IDF" : "I801",
priv->smba);
err = i2c_add_adapter(&priv->adapter);
if (err) {
platform_device_unregister(priv->tco_pdev);
......
......@@ -559,7 +559,7 @@ static const struct i2c_algorithm lpi2c_imx_algo = {
static const struct of_device_id lpi2c_imx_of_match[] = {
{ .compatible = "fsl,imx7ulp-lpi2c" },
{ },
{ }
};
MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
......
......@@ -687,7 +687,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
i2c_imx_bus_busy(i2c_imx, 0, atomic);
/* Disable I2C controller */
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
......@@ -1549,7 +1549,7 @@ static void i2c_imx_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
static int i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
......@@ -1558,7 +1558,7 @@ static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
return 0;
}
static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
static int i2c_imx_runtime_resume(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
......@@ -1571,8 +1571,7 @@ static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL)
};
static struct platform_driver i2c_imx_driver = {
......@@ -1580,7 +1579,7 @@ static struct platform_driver i2c_imx_driver = {
.remove_new = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &i2c_imx_pm_ops,
.pm = pm_ptr(&i2c_imx_pm_ops),
.of_match_table = i2c_imx_dt_ids,
.acpi_match_table = i2c_imx_acpi_ids,
},
......
......@@ -381,6 +381,15 @@ static int ismt_process_desc(const struct ismt_desc *desc,
return -EIO;
}
/**
* ismt_kill_transaction() - kill current transaction
* @priv: iSMT private data
*/
static void ismt_kill_transaction(struct ismt_priv *priv)
{
writel(ISMT_GCTRL_KILL, priv->smba + ISMT_GR_GCTRL);
}
/**
* ismt_access() - process an SMBus command
* @adap: the i2c host adapter
......@@ -623,6 +632,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
dma_unmap_single(dev, dma_addr, dma_size, dma_direction);
if (unlikely(!time_left)) {
ismt_kill_transaction(priv);
ret = -ETIMEDOUT;
goto out;
}
......
......@@ -792,26 +792,22 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c);
i2c->clk = devm_clk_get(&pdev->dev, NULL);
i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(i2c->clk))
return PTR_ERR(i2c->clk);
ret = clk_prepare_enable(i2c->clk);
if (ret)
return ret;
ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&clk_freq);
if (ret) {
dev_err(&pdev->dev, "clock-frequency not specified in DT\n");
goto err;
return ret;
}
i2c->speed = clk_freq / 1000;
if (i2c->speed == 0) {
ret = -EINVAL;
dev_err(&pdev->dev, "clock-frequency minimum is 1000\n");
goto err;
return ret;
}
jz4780_i2c_set_speed(i2c);
......@@ -827,29 +823,25 @@ static int jz4780_i2c_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret < 0)
goto err;
return ret;
i2c->irq = ret;
ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
dev_name(&pdev->dev), i2c);
if (ret)
goto err;
return ret;
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0)
goto err;
return ret;
return 0;
err:
clk_disable_unprepare(i2c->clk);
return ret;
}
static void jz4780_i2c_remove(struct platform_device *pdev)
{
struct jz4780_i2c *i2c = platform_get_drvdata(pdev);
clk_disable_unprepare(i2c->clk);
i2c_del_adapter(&i2c->adap);
}
......
This diff is collapsed.
......@@ -107,7 +107,7 @@ static int ljca_i2c_start(struct ljca_i2c_dev *ljca_i2c, u8 target_addr,
return 0;
}
static void ljca_i2c_stop(struct ljca_i2c_dev *ljca_i2c, u8 target_addr)
static void ljca_i2c_stop(struct ljca_i2c_dev *ljca_i2c)
{
struct ljca_i2c_rw_packet *w_packet =
(struct ljca_i2c_rw_packet *)ljca_i2c->obuf;
......@@ -178,7 +178,7 @@ static int ljca_i2c_read(struct ljca_i2c_dev *ljca_i2c, u8 target_addr, u8 *data
if (!ret)
ret = ljca_i2c_pure_read(ljca_i2c, data, len);
ljca_i2c_stop(ljca_i2c, target_addr);
ljca_i2c_stop(ljca_i2c);
return ret;
}
......@@ -222,7 +222,7 @@ static int ljca_i2c_write(struct ljca_i2c_dev *ljca_i2c, u8 target_addr,
if (!ret)
ret = ljca_i2c_pure_write(ljca_i2c, data, len);
ljca_i2c_stop(ljca_i2c, target_addr);
ljca_i2c_stop(ljca_i2c);
return ret;
}
......
......@@ -88,7 +88,6 @@ struct mpc_i2c {
int irq;
u32 real_clk;
u8 fdr, dfsrr;
struct clk *clk_per;
u32 cntl_bits;
enum mpc_i2c_action action;
struct i2c_msg *msgs;
......@@ -779,7 +778,6 @@ static int fsl_i2c_probe(struct platform_device *op)
struct clk *clk;
int result;
u32 clock;
int err;
i2c = devm_kzalloc(&op->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
......@@ -809,18 +807,12 @@ static int fsl_i2c_probe(struct platform_device *op)
* enable clock for the I2C peripheral (non fatal),
* keep a reference upon successful allocation
*/
clk = devm_clk_get_optional(&op->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
err = clk_prepare_enable(clk);
if (err) {
clk = devm_clk_get_optional_enabled(&op->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&op->dev, "failed to enable clock\n");
return err;
return PTR_ERR(clk);
}
i2c->clk_per = clk;
if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) {
clock = MPC_I2C_CLOCK_PRESERVE;
} else {
......@@ -876,14 +868,9 @@ static int fsl_i2c_probe(struct platform_device *op)
result = i2c_add_numbered_adapter(&i2c->adap);
if (result)
goto fail_add;
return result;
return 0;
fail_add:
clk_disable_unprepare(i2c->clk_per);
return result;
};
static void fsl_i2c_remove(struct platform_device *op)
......@@ -891,8 +878,6 @@ static void fsl_i2c_remove(struct platform_device *op)
struct mpc_i2c *i2c = platform_get_drvdata(op);
i2c_del_adapter(&i2c->adap);
clk_disable_unprepare(i2c->clk_per);
};
static int __maybe_unused mpc_i2c_suspend(struct device *dev)
......
......@@ -1306,12 +1306,9 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
{
struct mtk_i2c *i2c = dev_id;
u16 restart_flag = 0;
u16 restart_flag = i2c->auto_restart ? I2C_RS_TRANSFER : 0;
u16 intr_stat;
if (i2c->auto_restart)
restart_flag = I2C_RS_TRANSFER;
intr_stat = mtk_i2c_readw(i2c, OFFSET_INTR_STAT);
mtk_i2c_writew(i2c, intr_stat, OFFSET_INTR_STAT);
......
......@@ -136,11 +136,13 @@ enum i2c_addr {
* Since the addr regs are sprinkled all over the address space,
* use this array to get the address or each register.
*/
#define I2C_NUM_OWN_ADDR 2
#define I2C_NUM_OWN_ADDR 10
#define I2C_NUM_OWN_ADDR_SUPPORTED 2
static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = {
NPCM_I2CADDR1, NPCM_I2CADDR2,
NPCM_I2CADDR1, NPCM_I2CADDR2, NPCM_I2CADDR3, NPCM_I2CADDR4,
NPCM_I2CADDR5, NPCM_I2CADDR6, NPCM_I2CADDR7, NPCM_I2CADDR8,
NPCM_I2CADDR9, NPCM_I2CADDR10,
};
#endif
......
......@@ -1261,7 +1261,7 @@ static const struct of_device_id omap_i2c_of_match[] = {
.compatible = "ti,omap2420-i2c",
.data = &omap2420_pdata,
},
{ },
{ }
};
MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
#endif
......
......@@ -146,7 +146,7 @@ static const struct dmi_system_id piix4_dmi_ibm[] = {
.ident = "IBM",
.matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
},
{ },
{ }
};
/*
......
......@@ -721,7 +721,7 @@ static void i2c_pnx_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id i2c_pnx_of_match[] = {
{ .compatible = "nxp,pnx-i2c" },
{ },
{ }
};
MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
#endif
......
......@@ -135,7 +135,7 @@ static int ce4100_i2c_probe(struct pci_dev *dev,
static const struct pci_device_id ce4100_i2c_devices[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
{ },
{ }
};
static struct pci_driver ce4100_i2c_driver = {
......
......@@ -218,7 +218,7 @@ static const struct platform_device_id i2c_pxa_id_table[] = {
{ "ce4100-i2c", REGS_CE4100 },
{ "pxa910-i2c", REGS_PXA910 },
{ "armada-3700-i2c", REGS_A3700 },
{ },
{ }
};
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
......
......@@ -721,7 +721,7 @@ static const struct i2c_algorithm geni_i2c_algo = {
static const struct acpi_device_id geni_i2c_acpi_match[] = {
{ "QCOM0220"},
{ "QCOM0411" },
{ },
{ }
};
MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
#endif
......@@ -984,21 +984,24 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
return ret;
ret = clk_prepare_enable(gi2c->core_clk);
if (ret) {
geni_icc_disable(&gi2c->se);
return ret;
}
if (ret)
goto out_icc_disable;
ret = geni_se_resources_on(&gi2c->se);
if (ret) {
clk_disable_unprepare(gi2c->core_clk);
geni_icc_disable(&gi2c->se);
return ret;
}
if (ret)
goto out_clk_disable;
enable_irq(gi2c->irq);
gi2c->suspended = 0;
return 0;
out_clk_disable:
clk_disable_unprepare(gi2c->core_clk);
out_icc_disable:
geni_icc_disable(&gi2c->se);
return ret;
}
static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
......
......@@ -1648,7 +1648,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
static const struct acpi_device_id qup_i2c_acpi_match[] = {
{ "QCOM8010"},
{ },
{ }
};
MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match);
......
......@@ -1164,11 +1164,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
rcar_i2c_init(priv);
rcar_i2c_reset_slave(priv);
if (priv->devtype < I2C_RCAR_GEN3) {
irqflags |= IRQF_NO_THREAD;
irqhandler = rcar_i2c_gen2_irq;
}
/* Stay always active when multi-master to keep arbitration working */
if (of_property_read_bool(dev->of_node, "multi-master"))
priv->flags |= ID_P_PM_BLOCKED;
......@@ -1178,8 +1173,11 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (of_property_read_bool(dev->of_node, "smbus"))
priv->flags |= ID_P_HOST_NOTIFY;
if (priv->devtype < I2C_RCAR_GEN3) {
irqflags |= IRQF_NO_THREAD;
irqhandler = rcar_i2c_gen2_irq;
} else {
/* R-Car Gen3+ needs a reset before every transfer */
if (priv->devtype >= I2C_RCAR_GEN3) {
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc)) {
ret = PTR_ERR(priv->rstc);
......
This diff is collapsed.
......@@ -130,7 +130,7 @@ static const struct platform_device_id s3c24xx_driver_ids[] = {
}, {
.name = "s3c2440-hdmiphy-i2c",
.driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO,
}, { },
}, { }
};
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
......
......@@ -182,7 +182,7 @@ static u32 virtio_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static struct i2c_algorithm virtio_algorithm = {
static const struct i2c_algorithm virtio_algorithm = {
.xfer = virtio_i2c_xfer,
.functionality = virtio_i2c_func,
};
......@@ -237,7 +237,7 @@ static void virtio_i2c_remove(struct virtio_device *vdev)
virtio_i2c_del_vqs(vdev);
}
static struct virtio_device_id id_table[] = {
static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_I2C_ADAPTER, VIRTIO_DEV_ANY_ID },
{}
};
......
......@@ -915,6 +915,27 @@ int i2c_dev_irq_from_resources(const struct resource *resources,
return 0;
}
/*
* Serialize device instantiation in case it can be instantiated explicitly
* and by auto-detection
*/
static int i2c_lock_addr(struct i2c_adapter *adap, unsigned short addr,
unsigned short flags)
{
if (!(flags & I2C_CLIENT_TEN) &&
test_and_set_bit(addr, adap->addrs_in_instantiation))
return -EBUSY;
return 0;
}
static void i2c_unlock_addr(struct i2c_adapter *adap, unsigned short addr,
unsigned short flags)
{
if (!(flags & I2C_CLIENT_TEN))
clear_bit(addr, adap->addrs_in_instantiation);
}
/**
* i2c_new_client_device - instantiate an i2c device
* @adap: the adapter managing the device
......@@ -962,6 +983,10 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
goto out_err_silent;
}
status = i2c_lock_addr(adap, client->addr, client->flags);
if (status)
goto out_err_silent;
/* Check for address business */
status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client));
if (status)
......@@ -993,6 +1018,8 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
i2c_unlock_addr(adap, client->addr, client->flags);
return client;
out_remove_swnode:
......@@ -1004,6 +1031,7 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
dev_err(&adap->dev,
"Failed to register i2c client %s at 0x%02x (%d)\n",
client->name, client->addr, status);
i2c_unlock_addr(adap, client->addr, client->flags);
out_err_silent:
if (need_put)
put_device(&client->dev);
......@@ -1068,7 +1096,7 @@ EXPORT_SYMBOL(i2c_find_device_by_fwnode);
static const struct i2c_device_id dummy_id[] = {
{ "dummy", },
{ "smbus_host_notify", },
{ },
{ }
};
static int dummy_probe(struct i2c_client *client)
......@@ -1367,10 +1395,6 @@ struct i2c_adapter *i2c_verify_adapter(struct device *dev)
}
EXPORT_SYMBOL(i2c_verify_adapter);
#ifdef CONFIG_I2C_COMPAT
static struct class_compat *i2c_adapter_compat_class;
#endif
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
struct i2c_devinfo *devinfo;
......@@ -1524,7 +1548,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
device_initialize(&adap->dev);
/*
* This adapter can be used as a parent immediately after device_add(),
* setup runtime-pm (especially ignore-children) before hand.
*/
device_enable_async_suspend(&adap->dev);
pm_runtime_no_callbacks(&adap->dev);
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev);
res = device_add(&adap->dev);
if (res) {
pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
goto out_list;
......@@ -1536,25 +1571,12 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
if (res)
goto out_reg;
device_enable_async_suspend(&adap->dev);
pm_runtime_no_callbacks(&adap->dev);
pm_suspend_ignore_children(&adap->dev, true);
pm_runtime_enable(&adap->dev);
res = i2c_init_recovery(adap);
if (res == -EPROBE_DEFER)
goto out_reg;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
#ifdef CONFIG_I2C_COMPAT
res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
if (res)
dev_warn(&adap->dev,
"Failed to create compatibility class link\n");
#endif
/* create pre-declared device nodes */
of_i2c_register_devices(adap);
i2c_acpi_install_space_handler(adap);
......@@ -1761,11 +1783,6 @@ void i2c_del_adapter(struct i2c_adapter *adap)
device_for_each_child(&adap->dev, NULL, __unregister_client);
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
#ifdef CONFIG_I2C_COMPAT
class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
adap->dev.parent);
#endif
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
......@@ -2074,13 +2091,6 @@ static int __init i2c_init(void)
i2c_debugfs_root = debugfs_create_dir("i2c", NULL);
#ifdef CONFIG_I2C_COMPAT
i2c_adapter_compat_class = class_compat_register("i2c-adapter");
if (!i2c_adapter_compat_class) {
retval = -ENOMEM;
goto bus_err;
}
#endif
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
......@@ -2093,10 +2103,6 @@ static int __init i2c_init(void)
return 0;
class_err:
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
is_registered = false;
bus_unregister(&i2c_bus_type);
return retval;
......@@ -2109,9 +2115,6 @@ static void __exit i2c_exit(void)
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
#endif
debugfs_remove_recursive(i2c_debugfs_root);
bus_unregister(&i2c_bus_type);
tracepoint_synchronize_unregister();
......
......@@ -109,16 +109,13 @@ EXPORT_SYMBOL_GPL(i2c_slave_event);
bool i2c_detect_slave_mode(struct device *dev)
{
if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
struct device_node *child;
u32 reg;
for_each_child_of_node(dev->of_node, child) {
for_each_child_of_node_scoped(dev->of_node, child) {
of_property_read_u32(child, "reg", &reg);
if (reg & I2C_OWN_SLAVE_ADDRESS) {
of_node_put(child);
if (reg & I2C_OWN_SLAVE_ADDRESS)
return true;
}
}
} else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
dev_dbg(dev, "ACPI slave is not supported yet\n");
}
......
......@@ -6,7 +6,10 @@
* Copyright (C) 2020 by Renesas Electronics Corporation
*/
#include <generated/utsrelease.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
......@@ -14,12 +17,14 @@
#include <linux/slab.h>
#include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
#define TU_CUR_VERSION 0x01
#define TU_VERSION_MAX_LENGTH 128
enum testunit_cmds {
TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */
TU_CMD_SMBUS_HOST_NOTIFY,
TU_CMD_SMBUS_BLOCK_PROC_CALL,
TU_CMD_GET_VERSION_WITH_REP_START,
TU_CMD_SMBUS_ALERT_REQUEST,
TU_NUM_CMDS
};
......@@ -39,50 +44,38 @@ struct testunit_data {
unsigned long flags;
u8 regs[TU_NUM_REGS];
u8 reg_idx;
u8 read_idx;
struct i2c_client *client;
struct delayed_work worker;
struct gpio_desc *gpio;
struct completion alert_done;
};
static void i2c_slave_testunit_work(struct work_struct *work)
{
struct testunit_data *tu = container_of(work, struct testunit_data, worker.work);
struct i2c_msg msg;
u8 msgbuf[256];
int ret = 0;
msg.addr = I2C_CLIENT_END;
msg.buf = msgbuf;
static char tu_version_info[] = "v" UTS_RELEASE "\n\0";
switch (tu->regs[TU_REG_CMD]) {
case TU_CMD_READ_BYTES:
msg.addr = tu->regs[TU_REG_DATAL];
msg.flags = I2C_M_RD;
msg.len = tu->regs[TU_REG_DATAH];
break;
static int i2c_slave_testunit_smbalert_cb(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
struct testunit_data *tu = i2c_get_clientdata(client);
case TU_CMD_SMBUS_HOST_NOTIFY:
msg.addr = 0x08;
msg.flags = 0;
msg.len = 3;
msgbuf[0] = tu->client->addr;
msgbuf[1] = tu->regs[TU_REG_DATAL];
msgbuf[2] = tu->regs[TU_REG_DATAH];
switch (event) {
case I2C_SLAVE_READ_PROCESSED:
gpiod_set_value(tu->gpio, 0);
fallthrough;
case I2C_SLAVE_READ_REQUESTED:
*val = tu->regs[TU_REG_DATAL];
break;
default:
case I2C_SLAVE_STOP:
complete(&tu->alert_done);
break;
}
if (msg.addr != I2C_CLIENT_END) {
ret = i2c_transfer(tu->client->adapter, &msg, 1);
/* convert '0 msgs transferred' to errno */
ret = (ret == 0) ? -EIO : ret;
case I2C_SLAVE_WRITE_REQUESTED:
case I2C_SLAVE_WRITE_RECEIVED:
return -EOPNOTSUPP;
}
if (ret < 0)
dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret);
clear_bit(TU_FLAG_IN_PROCESS, &tu->flags);
return 0;
}
static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
......@@ -91,9 +84,20 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
struct testunit_data *tu = i2c_get_clientdata(client);
bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 &&
tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL;
bool is_get_version = tu->reg_idx == 3 &&
tu->regs[TU_REG_CMD] == TU_CMD_GET_VERSION_WITH_REP_START;
int ret = 0;
switch (event) {
case I2C_SLAVE_WRITE_REQUESTED:
if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
return -EBUSY;
memset(tu->regs, 0, TU_NUM_REGS);
tu->reg_idx = 0;
tu->read_idx = 0;
break;
case I2C_SLAVE_WRITE_RECEIVED:
if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
return -EBUSY;
......@@ -127,27 +131,93 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
tu->reg_idx = 0;
break;
case I2C_SLAVE_WRITE_REQUESTED:
if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
return -EBUSY;
memset(tu->regs, 0, TU_NUM_REGS);
tu->reg_idx = 0;
break;
case I2C_SLAVE_READ_PROCESSED:
if (is_proc_call && tu->regs[TU_REG_DATAH])
/* Advance until we reach the NUL character */
if (is_get_version && tu_version_info[tu->read_idx] != 0)
tu->read_idx++;
else if (is_proc_call && tu->regs[TU_REG_DATAH])
tu->regs[TU_REG_DATAH]--;
fallthrough;
case I2C_SLAVE_READ_REQUESTED:
*val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION;
if (is_get_version)
*val = tu_version_info[tu->read_idx];
else if (is_proc_call)
*val = tu->regs[TU_REG_DATAH];
else
*val = test_bit(TU_FLAG_IN_PROCESS, &tu->flags) ?
tu->regs[TU_REG_CMD] : 0;
break;
}
return ret;
}
static void i2c_slave_testunit_work(struct work_struct *work)
{
struct testunit_data *tu = container_of(work, struct testunit_data, worker.work);
unsigned long time_left;
struct i2c_msg msg;
u8 msgbuf[256];
u16 orig_addr;
int ret = 0;
msg.addr = I2C_CLIENT_END;
msg.buf = msgbuf;
switch (tu->regs[TU_REG_CMD]) {
case TU_CMD_READ_BYTES:
msg.addr = tu->regs[TU_REG_DATAL];
msg.flags = I2C_M_RD;
msg.len = tu->regs[TU_REG_DATAH];
break;
case TU_CMD_SMBUS_HOST_NOTIFY:
msg.addr = 0x08;
msg.flags = 0;
msg.len = 3;
msgbuf[0] = tu->client->addr;
msgbuf[1] = tu->regs[TU_REG_DATAL];
msgbuf[2] = tu->regs[TU_REG_DATAH];
break;
case TU_CMD_SMBUS_ALERT_REQUEST:
i2c_slave_unregister(tu->client);
orig_addr = tu->client->addr;
tu->client->addr = 0x0c;
ret = i2c_slave_register(tu->client, i2c_slave_testunit_smbalert_cb);
if (ret)
goto out_smbalert;
reinit_completion(&tu->alert_done);
gpiod_set_value(tu->gpio, 1);
time_left = wait_for_completion_timeout(&tu->alert_done, HZ);
if (!time_left)
ret = -ETIMEDOUT;
i2c_slave_unregister(tu->client);
out_smbalert:
tu->client->addr = orig_addr;
i2c_slave_register(tu->client, i2c_slave_testunit_slave_cb);
break;
default:
break;
}
if (msg.addr != I2C_CLIENT_END) {
ret = i2c_transfer(tu->client->adapter, &msg, 1);
/* convert '0 msgs transferred' to errno */
ret = (ret == 0) ? -EIO : ret;
}
if (ret < 0)
dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret);
clear_bit(TU_FLAG_IN_PROCESS, &tu->flags);
}
static int i2c_slave_testunit_probe(struct i2c_client *client)
{
struct testunit_data *tu;
......@@ -158,8 +228,18 @@ static int i2c_slave_testunit_probe(struct i2c_client *client)
tu->client = client;
i2c_set_clientdata(client, tu);
init_completion(&tu->alert_done);
INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work);
tu->gpio = devm_gpiod_get_index_optional(&client->dev, NULL, 0, GPIOD_OUT_LOW);
if (gpiod_cansleep(tu->gpio)) {
dev_err(&client->dev, "GPIO access which may sleep is not allowed\n");
return -EDEADLK;
}
if (sizeof(tu_version_info) > TU_VERSION_MAX_LENGTH)
tu_version_info[TU_VERSION_MAX_LENGTH - 1] = 0;
return i2c_slave_register(client, i2c_slave_testunit_slave_cb);
};
......
......@@ -119,4 +119,20 @@ config I2C_MUX_MLXCPLD
This driver can also be built as a module. If so, the module
will be called i2c-mux-mlxcpld.
config I2C_MUX_MULE
tristate "Theobroma Systems Mule I2C device multiplexer"
depends on OF && SENSORS_AMC6821
help
Mule is an MCU that emulates a set of I2C devices, among which
devices that are reachable through an I2C-mux. The devices on the mux
can be selected by writing the appropriate device number to an I2C
configuration register.
If you say yes to this option, support will be included for a
Theobroma Systems Mule I2C multiplexer. This driver provides access to
I2C devices connected on this mux.
This driver can also be built as a module. If so, the module
will be called i2c-mux-mule.
endmenu
......@@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
obj-$(CONFIG_I2C_MUX_GPMUX) += i2c-mux-gpmux.o
obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
obj-$(CONFIG_I2C_MUX_MULE) += i2c-mux-mule.o
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Theobroma Systems Mule I2C device multiplexer
*
* Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH
*/
#include <linux/i2c-mux.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#define MULE_I2C_MUX_CONFIG_REG 0xff
#define MULE_I2C_MUX_DEFAULT_DEV 0x0
struct mule_i2c_reg_mux {
struct regmap *regmap;
};
static int mule_i2c_mux_select(struct i2c_mux_core *muxc, u32 dev)
{
struct mule_i2c_reg_mux *mux = muxc->priv;
return regmap_write(mux->regmap, MULE_I2C_MUX_CONFIG_REG, dev);
}
static int mule_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 dev)
{
return mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
}
static void mule_i2c_mux_remove(void *data)
{
struct i2c_mux_core *muxc = data;
i2c_mux_del_adapters(muxc);
mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
}
static int mule_i2c_mux_probe(struct platform_device *pdev)
{
struct device *mux_dev = &pdev->dev;
struct mule_i2c_reg_mux *priv;
struct i2c_client *client;
struct i2c_mux_core *muxc;
struct device_node *dev;
unsigned int readback;
int ndev, ret;
bool old_fw;
/* Count devices on the mux */
ndev = of_get_child_count(mux_dev->of_node);
dev_dbg(mux_dev, "%d devices on the mux\n", ndev);
client = to_i2c_client(mux_dev->parent);
muxc = i2c_mux_alloc(client->adapter, mux_dev, ndev, sizeof(*priv),
I2C_MUX_LOCKED, mule_i2c_mux_select, mule_i2c_mux_deselect);
if (!muxc)
return -ENOMEM;
priv = i2c_mux_priv(muxc);
priv->regmap = dev_get_regmap(mux_dev->parent, NULL);
if (IS_ERR(priv->regmap))
return dev_err_probe(mux_dev, PTR_ERR(priv->regmap),
"No parent i2c register map\n");
platform_set_drvdata(pdev, muxc);
/*
* MULE_I2C_MUX_DEFAULT_DEV is guaranteed to exist on all old and new
* mule fw. Mule fw without mux support will accept write ops to the
* config register, but readback returns 0xff (register not updated).
*/
ret = mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
if (ret)
return dev_err_probe(mux_dev, ret,
"Failed to write config register\n");
ret = regmap_read(priv->regmap, MULE_I2C_MUX_CONFIG_REG, &readback);
if (ret)
return dev_err_probe(mux_dev, ret,
"Failed to read config register\n");
old_fw = (readback != MULE_I2C_MUX_DEFAULT_DEV);
ret = devm_add_action_or_reset(mux_dev, mule_i2c_mux_remove, muxc);
if (ret)
return dev_err_probe(mux_dev, ret,
"Failed to register mux remove\n");
/* Create device adapters */
for_each_child_of_node(mux_dev->of_node, dev) {
u32 reg;
ret = of_property_read_u32(dev, "reg", &reg);
if (ret)
return dev_err_probe(mux_dev, ret,
"No reg property found for %s\n",
of_node_full_name(dev));
if (old_fw && reg != 0) {
dev_warn(mux_dev,
"Mux is not supported, please update Mule FW\n");
continue;
}
ret = mule_i2c_mux_select(muxc, reg);
if (ret) {
dev_warn(mux_dev,
"Device %d not supported, please update Mule FW\n", reg);
continue;
}
ret = i2c_mux_add_adapter(muxc, 0, reg);
if (ret)
return ret;
}
mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
return 0;
}
static const struct of_device_id mule_i2c_mux_of_match[] = {
{ .compatible = "tsd,mule-i2c-mux", },
{},
};
MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match);
static struct platform_driver mule_i2c_mux_driver = {
.driver = {
.name = "mule-i2c-mux",
.of_match_table = mule_i2c_mux_of_match,
},
.probe = mule_i2c_mux_probe,
};
module_platform_driver(mule_i2c_mux_driver);
MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>");
MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule");
MODULE_LICENSE("GPL");
......@@ -41,10 +41,9 @@ config TXGBE
tristate "Wangxun(R) 10GbE PCI Express adapters support"
depends on PCI
depends on COMMON_CLK
depends on I2C_DESIGNWARE_PLATFORM
select MARVELL_10G_PHY
select REGMAP
select I2C
select I2C_DESIGNWARE_PLATFORM
select PHYLINK
select HWMON if TXGBE=y
select SFP
......
......@@ -761,6 +761,9 @@ struct i2c_adapter {
struct regulator *bus_regulator;
struct dentry *debugfs;
/* 7bit address space */
DECLARE_BITMAP(addrs_in_instantiation, 1 << 7);
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment