Commit 008128cd authored by Linus Torvalds's avatar Linus Torvalds

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

Pull i2c updates from Wolfram Sang:

 - new drivers for HPE GXP and Loongson 2K/LS7A

 - bigger refactorings for i801 and xiic

 - gpio driver gained ACPI and SDA-write only support

 - the core converted some OF helpers to fwnode helpers

 - usual bunch of driver updates

* tag 'i2c-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (52 commits)
  MAINTAINERS: Add HPE GXP I2C Support
  i2c: Add GXP SoC I2C Controller
  dt-bindings: i2c: Add hpe,gxp-i2c
  i2c: xiic: Remove some dead code
  i2c: xiic: Add SCL frequency configuration support
  i2c: xiic: Update compatible with new IP version
  dt-bindings: i2c: xiic: Add 'xlnx,axi-iic-2.1' to compatible
  i2c: i801: Call i801_check_post() from i801_access()
  i2c: i801: Call i801_check_pre() from i801_access()
  i2c: i801: Centralize configuring block commands in i801_block_transaction
  i2c: i801: Centralize configuring non-block commands in i801_simple_transaction
  i2c: i801: Handle SMBAUXCTL_E32B in i801_block_transaction_by_block only
  i2c: i801: Add i801_simple_transaction(), complementing i801_block_transaction()
  Documentation: i2c: correct spelling
  dt-bindings: i2c: i2c-st: convert to DT schema
  i2c: i801: add helper i801_set_hstadd()
  i2c: i801: make FEATURE_BLOCK_PROC dependent on FEATURE_BLOCK_BUFFER
  i2c: i801: make FEATURE_HOST_NOTIFY dependent on FEATURE_IRQ
  i2c: i801: improve interrupt handler
  i2c: st: use pm_sleep_ptr to avoid ifdef CONFIG_PM_SLEEP
  ...
parents 39f01344 e8444bb9
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/hpe,gxp-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HPE GXP SoC I2C Controller
maintainers:
- Nick Hawkins <nick.hawkins@hpe.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: hpe,gxp-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
clock-frequency:
default: 100000
hpe,sysreg:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle to the global status and enable interrupt registers shared
between each I2C engine controller instance. It enables the I2C
engine controller to act as both a master or slave by being able to
arm and respond to interrupts from its engine. Each bit in the
registers represent the respective bit position.
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
i2c@2600 {
compatible = "hpe,gxp-i2c";
reg = <0x2500 0x70>;
interrupts = <9>;
#address-cells = <1>;
#size-cells = <0>;
hpe,sysreg = <&sysreg_system_controller>;
clock-frequency = <10000>;
eeprom@50 {
compatible = "atmel,24c128";
reg = <0x50>;
};
};
......@@ -33,6 +33,10 @@ properties:
open drain.
maxItems: 1
i2c-gpio,sda-output-only:
description: sda as output only
type: boolean
i2c-gpio,scl-output-only:
description: scl as output only
type: boolean
......@@ -63,6 +67,28 @@ properties:
GPIO line used for SCL into open drain mode, and that something is not
the GPIO chip. It is essentially an inconsistency flag.
i2c-gpio,sda-has-no-pullup:
type: boolean
description: sda is used in a non-compliant way and has no pull-up.
Therefore disable open-drain. This property is mutually-exclusive
with i2c-gpio,sda-open-drain.
i2c-gpio,scl-has-no-pullup:
type: boolean
description: scl is used in a non-compliant way and has no pull-up.
Therefore disable open-drain. This property is mutually-exclusive
with i2c-gpio,scl-open-drain.
dependencies:
i2c-gpio,sda-has-no-pullup:
not:
required:
- i2c-gpio,sda-open-drain
i2c-gpio,scl-has-no-pullup:
not:
required:
- i2c-gpio,scl-open-drain
required:
- compatible
- sda-gpios
......
......@@ -41,6 +41,10 @@ properties:
- mediatek,mt6797-i2c
- mediatek,mt7623-i2c
- const: mediatek,mt6577-i2c
- items:
- enum:
- mediatek,mt8365-i2c
- const: mediatek,mt8168-i2c
- items:
- enum:
- mediatek,mt8195-i2c
......
ST SSC binding, for I2C mode operation
Required properties :
- compatible : Must be "st,comms-ssc-i2c" or "st,comms-ssc4-i2c"
- reg : Offset and length of the register set for the device
- interrupts : the interrupt specifier
- clock-names: Must contain "ssc".
- clocks: Must contain an entry for each name in clock-names. See the common
clock bindings.
- A pinctrl state named "default" must be defined to set pins in mode of
operation for I2C transfer.
Optional properties :
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
the default 100 kHz frequency will be used. As only Normal and Fast modes
are supported, possible values are 100000 and 400000.
- st,i2c-min-scl-pulse-width-us : The minimum valid SCL pulse width that is
allowed through the deglitch circuit. In units of us.
- st,i2c-min-sda-pulse-width-us : The minimum valid SDA pulse width that is
allowed through the deglitch circuit. In units of us.
- A pinctrl state named "idle" could be defined to set pins in idle state
when I2C instance is not performing a transfer.
- A pinctrl state named "sleep" could be defined to set pins in sleep state
when driver enters in suspend.
Example :
i2c0: i2c@fed40000 {
compatible = "st,comms-ssc4-i2c";
reg = <0xfed40000 0x110>;
interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_a0_ls CLK_ICN_REG>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0_default>;
st,i2c-min-scl-pulse-width-us = <0>;
st,i2c-min-sda-pulse-width-us = <5>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/loongson,ls2x-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Loongson LS2X I2C Controller
maintainers:
- Binbin Zhou <zhoubinbin@loongson.cn>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
enum:
- loongson,ls2k-i2c
- loongson,ls7a-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0: i2c@1fe21000 {
compatible = "loongson,ls2k-i2c";
reg = <0x1fe21000 0x8>;
interrupt-parent = <&extioiic>;
interrupts = <22 IRQ_TYPE_LEVEL_LOW>;
#address-cells = <1>;
#size-cells = <0>;
eeprom@57 {
compatible = "atmel,24c16";
reg = <0x57>;
pagesize = <16>;
};
};
......@@ -12,14 +12,24 @@ maintainers:
properties:
compatible:
enum:
- qcom,msm8226-cci
- qcom,msm8916-cci
- qcom,msm8974-cci
- qcom,msm8996-cci
- qcom,sdm845-cci
- qcom,sm8250-cci
- qcom,sm8450-cci
oneOf:
- enum:
- qcom,msm8226-cci
- qcom,msm8974-cci
- qcom,msm8996-cci
- items:
- enum:
- qcom,msm8916-cci
- const: qcom,msm8226-cci # CCI v1
- items:
- enum:
- qcom,sdm845-cci
- qcom,sm6350-cci
- qcom,sm8250-cci
- qcom,sm8450-cci
- const: qcom,msm8996-cci # CCI v2
"#address-cells":
const: 1
......@@ -88,10 +98,12 @@ allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8226-cci
- qcom,msm8974-cci
oneOf:
- contains:
enum:
- qcom,msm8974-cci
- const: qcom,msm8226-cci
then:
properties:
clocks:
......@@ -105,10 +117,12 @@ allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8916-cci
- qcom,msm8996-cci
oneOf:
- contains:
enum:
- qcom,msm8916-cci
- const: qcom,msm8996-cci
then:
properties:
clocks:
......@@ -126,6 +140,7 @@ allOf:
contains:
enum:
- qcom,sdm845-cci
- qcom,sm6350-cci
then:
properties:
clocks:
......@@ -169,7 +184,7 @@ examples:
cci@ac4a000 {
reg = <0x0ac4a000 0x4000>;
compatible = "qcom,sdm845-cci";
compatible = "qcom,sdm845-cci", "qcom,msm8996-cci";
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -29,6 +29,9 @@ properties:
minimum: 100000
maximum: 400000
resets:
maxItems: 1
required:
- compatible
- reg
......
......@@ -29,6 +29,9 @@ properties:
minimum: 100000
maximum: 400000
resets:
maxItems: 1
required:
- compatible
- reg
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/st,sti-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: I2C controller embedded in STMicroelectronics STi platform
maintainers:
- Patrice Chotard <patrice.chotard@foss.st.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
enum:
- st,comms-ssc-i2c
- st,comms-ssc4-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
maxItems: 1
clock-frequency:
enum: [ 100000, 400000 ]
default: 100000
st,i2c-min-scl-pulse-width-us:
description:
The minimum valid SCL pulse width that is allowed through the
deglitch circuit. In units of us.
st,i2c-min-sda-pulse-width-us:
description:
The minimum valid SDA pulse width that is allowed through the
deglitch circuit. In units of us.
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stih407-clks.h>
i2c@fed40000 {
compatible = "st,comms-ssc4-i2c";
reg = <0xfed40000 0x110>;
interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_a0_ls CLK_ICN_REG>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c0_default>;
st,i2c-min-scl-pulse-width-us = <0>;
st,i2c-min-sda-pulse-width-us = <5>;
};
......@@ -14,7 +14,9 @@ allOf:
properties:
compatible:
const: xlnx,xps-iic-2.00.a
enum:
- xlnx,axi-iic-2.1
- xlnx,xps-iic-2.00.a
reg:
maxItems: 1
......@@ -30,6 +32,13 @@ properties:
description: |
Input clock name.
clock-frequency:
description:
Optional I2C SCL clock frequency. If not specified, do not configure
in software, rely only on hardware design value.
default: 100000
enum: [ 100000, 400000, 1000000 ]
required:
- compatible
- reg
......
......@@ -93,7 +93,7 @@ bus arbitration against another master in a multi-master setup.
------------------
This file is write only and you need to write the duration of the arbitration
intereference (in µs, maximum is 100ms). The calling process will then sleep
interference (in µs, maximum is 100ms). The calling process will then sleep
and wait for the next bus clock. The process is interruptible, though.
Arbitration lost is achieved by waiting for SCL going down by the master under
......
......@@ -238,7 +238,7 @@ This is implemented in the following way in the Linux kernel:
* I2C bus drivers trigger SMBus Host Notify by a call to
i2c_handle_smbus_host_notify().
* I2C drivers for devices which can trigger SMBus Host Notify will have
client->irq assigned to a Host Notify IRQ if noone else specified an other.
client->irq assigned to a Host Notify IRQ if no one else specified another.
There is currently no way to retrieve the data parameter from the client.
......
......@@ -2240,6 +2240,7 @@ S: Maintained
F: Documentation/hwmon/gxp-fan-ctrl.rst
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml
F: Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml
F: Documentation/devicetree/bindings/i2c/hpe,gxp-i2c.yaml
F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F: arch/arm/boot/dts/hpe-bmc*
......@@ -2247,6 +2248,7 @@ F: arch/arm/boot/dts/hpe-gxp*
F: arch/arm/mach-hpe/
F: drivers/clocksource/timer-gxp.c
F: drivers/hwmon/gxp-fan-ctrl.c
F: drivers/i2c/busses/i2c-gxp.c
F: drivers/spi/spi-gxp.c
F: drivers/watchdog/gxp-wdt.c
......@@ -2795,7 +2797,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
W: http://www.stlinux.com
F: Documentation/devicetree/bindings/spi/st,ssc-spi.yaml
F: Documentation/devicetree/bindings/i2c/i2c-st.txt
F: Documentation/devicetree/bindings/i2c/st,sti-i2c.yaml
F: arch/arm/boot/dts/sti*
F: arch/arm/mach-sti/
F: drivers/ata/ahci_st.c
......@@ -12097,6 +12099,13 @@ F: drivers/*/*loongarch*
F: Documentation/loongarch/
F: Documentation/translations/zh_CN/loongarch/
LOONGSON LS2X I2C DRIVER
M: Binbin Zhou <zhoubinbin@loongson.cn>
L: linux-i2c@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
F: drivers/i2c/busses/i2c-ls2x.c
LOONGSON-2 SOC SERIES GUTS DRIVER
M: Yinbo Zhu <zhuyinbo@loongson.cn>
L: loongarch@lists.linux.dev
......
......@@ -184,8 +184,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
* Always report ACK if SDA is write-only.
*/
ack = !getsda(adap); /* ack: sda is pulled low -> success */
ack = !adap->getsda || !getsda(adap); /* ack: sda is pulled low -> success */
bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
ack ? "A" : "NA");
......@@ -238,71 +239,55 @@ static int test_bus(struct i2c_adapter *i2c_adap)
return -ENODEV;
}
if (adap->getsda == NULL)
pr_info("%s: SDA is write-only, testing not possible\n", name);
if (adap->getscl == NULL)
pr_info("%s: Testing SDA only, SCL is not readable\n", name);
pr_info("%s: SCL is write-only, testing not possible\n", name);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
sda = adap->getsda ? getsda(adap) : 1;
scl = adap->getscl ? getscl(adap) : 1;
if (!scl || !sda) {
printk(KERN_WARNING
"%s: bus seems to be busy (scl=%d, sda=%d)\n",
name, scl, sda);
pr_warn("%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda);
goto bailout;
}
sdalo(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (sda) {
printk(KERN_WARNING "%s: SDA stuck high!\n", name);
if (adap->getsda && getsda(adap)) {
pr_warn("%s: SDA stuck high!\n", name);
goto bailout;
}
if (!scl) {
printk(KERN_WARNING
"%s: SCL unexpected low while pulling SDA low!\n",
name);
if (adap->getscl && !getscl(adap)) {
pr_warn("%s: SCL unexpected low while pulling SDA low!\n", name);
goto bailout;
}
sdahi(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!sda) {
printk(KERN_WARNING "%s: SDA stuck low!\n", name);
if (adap->getsda && !getsda(adap)) {
pr_warn("%s: SDA stuck low!\n", name);
goto bailout;
}
if (!scl) {
printk(KERN_WARNING
"%s: SCL unexpected low while pulling SDA high!\n",
name);
if (adap->getscl && !getscl(adap)) {
pr_warn("%s: SCL unexpected low while pulling SDA high!\n", name);
goto bailout;
}
scllo(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 0 : getscl(adap);
if (scl) {
printk(KERN_WARNING "%s: SCL stuck high!\n", name);
if (adap->getscl && getscl(adap)) {
pr_warn("%s: SCL stuck high!\n", name);
goto bailout;
}
if (!sda) {
printk(KERN_WARNING
"%s: SDA unexpected low while pulling SCL low!\n",
name);
if (adap->getsda && !getsda(adap)) {
pr_warn("%s: SDA unexpected low while pulling SCL low!\n", name);
goto bailout;
}
sclhi(adap);
sda = getsda(adap);
scl = (adap->getscl == NULL) ? 1 : getscl(adap);
if (!scl) {
printk(KERN_WARNING "%s: SCL stuck low!\n", name);
if (adap->getscl && !getscl(adap)) {
pr_warn("%s: SCL stuck low!\n", name);
goto bailout;
}
if (!sda) {
printk(KERN_WARNING
"%s: SDA unexpected low while pulling SCL high!\n",
name);
if (adap->getsda && !getsda(adap)) {
pr_warn("%s: SDA unexpected low while pulling SCL high!\n", name);
goto bailout;
}
......@@ -420,6 +405,10 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
if (!adap->getsda)
return -EOPNOTSUPP;
while (count > 0) {
inval = i2c_inb(i2c_adap);
......@@ -670,11 +659,15 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (ret < 0)
return ret;
/* Complain if SCL can't be read */
if (bit_adap->getscl == NULL) {
if (bit_adap->getsda == NULL)
dev_warn(&adap->dev, "Not I2C compliant: can't read SDA\n");
if (bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
if (bit_adap->getsda == NULL || bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Bus may be unreliable\n");
}
return 0;
}
......
......@@ -659,6 +659,13 @@ config I2C_GPIO_FAULT_INJECTOR
faults to an I2C bus, so another bus master can be stress-tested.
This is for debugging. If unsure, say 'no'.
config I2C_GXP
tristate "GXP I2C Interface"
depends on ARCH_HPE_GXP || COMPILE_TEST
help
This enables support for GXP I2C interface. The I2C engines can be
either I2C master or I2C slaves.
config I2C_HIGHLANDER
tristate "Highlander FPGA SMBus interface"
depends on SH_HIGHLANDER || COMPILE_TEST
......@@ -761,6 +768,17 @@ config I2C_LPC2K
This driver can also be built as a module. If so, the module
will be called i2c-lpc2k.
config I2C_LS2X
tristate "Loongson LS2X I2C adapter"
depends on MACH_LOONGSON64 || COMPILE_TEST
help
If you say yes to this option, support will be included for the
I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge
chip.
This driver can also be built as a module. If so, the module
will be called i2c-ls2x.
config I2C_MLXBF
tristate "Mellanox BlueField I2C controller"
depends on MELLANOX_PLATFORM && ARM64
......
......@@ -77,6 +77,7 @@ obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
......@@ -127,6 +128,7 @@ obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
obj-$(CONFIG_I2C_GXP) += i2c-gxp.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
......
......@@ -979,15 +979,13 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
const struct of_device_id *match;
struct aspeed_i2c_bus *bus;
struct clk *parent_clk;
struct resource *res;
int irq, ret;
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
bus->base = devm_ioremap_resource(&pdev->dev, res);
bus->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(bus->base))
return PTR_ERR(bus->base);
......
......@@ -302,7 +302,6 @@ static int
i2c_au1550_probe(struct platform_device *pdev)
{
struct i2c_au1550_data *priv;
struct resource *r;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
......@@ -310,8 +309,7 @@ i2c_au1550_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
priv->psc_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(priv->psc_base))
return PTR_ERR(priv->psc_base);
......
......@@ -407,7 +407,6 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quirks = {
static int bcm2835_i2c_probe(struct platform_device *pdev)
{
struct bcm2835_i2c_dev *i2c_dev;
struct resource *mem;
int ret;
struct i2c_adapter *adap;
struct clk *mclk;
......@@ -420,8 +419,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
i2c_dev->dev = &pdev->dev;
init_completion(&i2c_dev->completion);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
i2c_dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c_dev->regs))
return PTR_ERR(i2c_dev->regs);
......
......@@ -115,8 +115,6 @@
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
#define CDNS_I2C_FIFO_DEPTH 16
/* FIFO depth at which the DATA interrupt occurs */
#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2)
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
......@@ -175,7 +173,6 @@ enum cdns_i2c_slave_state {
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
* @curr_recv_count: Number of bytes to be received in current transfer
* @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
* @bus_hold_flag: Flag used in repeated start for clearing HOLD bit
......@@ -200,7 +197,6 @@ struct cdns_i2c {
unsigned int send_count;
unsigned int recv_count;
unsigned int curr_recv_count;
int irq;
unsigned long input_clk;
unsigned int i2c_clk;
unsigned int bus_hold_flag;
......@@ -616,9 +612,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
}
/* Determine hold_clear based on number of bytes to receive and hold flag */
if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
(id->recv_count <= CDNS_I2C_FIFO_DEPTH)) {
if (!id->bus_hold_flag && id->recv_count <= CDNS_I2C_FIFO_DEPTH) {
if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) {
hold_clear = true;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
......@@ -1246,7 +1240,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
{
struct resource *r_mem;
struct cdns_i2c *id;
int ret;
int ret, irq;
const struct of_device_id *match;
id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
......@@ -1277,10 +1271,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
if (IS_ERR(id->membase))
return PTR_ERR(id->membase);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
id->irq = ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
id->adap.owner = THIS_MODULE;
id->adap.dev.of_node = pdev->dev.of_node;
......@@ -1331,10 +1324,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
}
ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
ret = devm_request_irq(&pdev->dev, irq, cdns_i2c_isr, 0,
DRIVER_NAME, id);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
dev_err(&pdev->dev, "cannot get irq %d\n", irq);
goto err_clk_dis;
}
cdns_i2c_init(id);
......@@ -1344,7 +1337,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
id->i2c_clk / 1000, (unsigned long)r_mem->start, irq);
return 0;
......
......@@ -391,7 +391,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
{
u32 reg;
unsigned int reg;
int ret;
ret = i2c_dw_acquire_lock(dev);
......@@ -442,7 +442,7 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
void __i2c_dw_disable(struct dw_i2c_dev *dev)
{
int timeout = 100;
u32 status;
unsigned int status;
do {
__i2c_dw_disable_nowait(dev);
......@@ -465,7 +465,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
dev_warn(dev->dev, "timeout in disabling adapter\n");
}
unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev)
{
/*
* Clock is not necessary if we got LCNT/HCNT values directly from
......@@ -527,7 +527,7 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev)
*/
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
{
u32 status;
unsigned int status;
int ret;
ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
......@@ -571,7 +571,8 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
{
u32 param, tx_fifo_depth, rx_fifo_depth;
u32 tx_fifo_depth, rx_fifo_depth;
unsigned int param;
int ret;
/*
......@@ -611,7 +612,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap)
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
u32 dummy;
unsigned int dummy;
int ret;
ret = i2c_dw_acquire_lock(dev);
......
......@@ -37,6 +37,7 @@
#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)
#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11)
#define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
......@@ -264,7 +265,7 @@ struct dw_i2c_dev {
u8 *rx_buf;
int msg_err;
unsigned int status;
u32 abort_source;
unsigned int abort_source;
int irq;
u32 flags;
struct i2c_adapter adapter;
......@@ -320,7 +321,7 @@ 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);
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
unsigned long i2c_dw_clk_rate(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);
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
......
......@@ -39,7 +39,7 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
u32 comp_param1;
unsigned int comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
const char *fp_str = "";
......@@ -211,7 +211,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
u32 ic_con = 0, ic_tar = 0;
u32 dummy;
unsigned int dummy;
/* Disable the adapter */
__i2c_dw_disable(dev);
......@@ -287,7 +287,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
int cmd = 0, status;
u8 *tx_buf;
u32 val;
unsigned int val;
/*
* In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card,
......@@ -505,7 +505,8 @@ i2c_dw_read(struct dw_i2c_dev *dev)
unsigned int rx_valid;
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
u32 len, tmp;
unsigned int tmp;
u32 len;
u8 *buf;
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
......@@ -653,7 +654,7 @@ static const struct i2c_adapter_quirks i2c_dw_quirks = {
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
u32 stat, dummy;
unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
......@@ -714,7 +715,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
unsigned int stat, enabled;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
......@@ -865,6 +866,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
unsigned long irq_flags;
unsigned int ic_con;
int ret;
init_completion(&dev->cmd_complete);
......@@ -884,6 +886,25 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
if (ret)
return ret;
/* Lock the bus for accessing DW_IC_CON */
ret = i2c_dw_acquire_lock(dev);
if (ret)
return ret;
/*
* On AMD platforms BIOS advertises the bus clear feature
* and enables the SCL/SDA stuck low. SMU FW does the
* bus recovery process. Driver should not ignore this BIOS
* advertisement of bus clear feature.
*/
ret = regmap_read(dev->map, DW_IC_CON, &ic_con);
i2c_dw_release_lock(dev);
if (ret)
return ret;
if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL)
dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL;
ret = dev->init(dev);
if (ret)
return ret;
......
......@@ -98,7 +98,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
{
u32 stat, dummy;
unsigned int stat, dummy;
/*
* The IC_INTR_STAT register just indicates "enabled" interrupts.
......@@ -150,7 +150,7 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
u32 raw_stat, stat, enabled, tmp;
unsigned int raw_stat, stat, enabled, tmp;
u8 val = 0, slave_activity;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
......
......@@ -13,9 +13,9 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
struct i2c_gpio_private_data {
......@@ -300,22 +300,29 @@ static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {}
static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {}
#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/
static void of_i2c_gpio_get_props(struct device_node *np,
struct i2c_gpio_platform_data *pdata)
/* Get i2c-gpio properties from DT or ACPI table */
static void i2c_gpio_get_properties(struct device *dev,
struct i2c_gpio_platform_data *pdata)
{
u32 reg;
of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
device_property_read_u32(dev, "i2c-gpio,delay-us", &pdata->udelay);
if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
if (!device_property_read_u32(dev, "i2c-gpio,timeout-ms", &reg))
pdata->timeout = msecs_to_jiffies(reg);
pdata->sda_is_open_drain =
of_property_read_bool(np, "i2c-gpio,sda-open-drain");
device_property_read_bool(dev, "i2c-gpio,sda-open-drain");
pdata->scl_is_open_drain =
of_property_read_bool(np, "i2c-gpio,scl-open-drain");
device_property_read_bool(dev, "i2c-gpio,scl-open-drain");
pdata->scl_is_output_only =
of_property_read_bool(np, "i2c-gpio,scl-output-only");
device_property_read_bool(dev, "i2c-gpio,scl-output-only");
pdata->sda_is_output_only =
device_property_read_bool(dev, "i2c-gpio,sda-output-only");
pdata->sda_has_no_pullup =
device_property_read_bool(dev, "i2c-gpio,sda-has-no-pullup");
pdata->scl_has_no_pullup =
device_property_read_bool(dev, "i2c-gpio,scl-has-no-pullup");
}
static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
......@@ -361,7 +368,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
struct i2c_algo_bit_data *bit_data;
struct i2c_adapter *adap;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct fwnode_handle *fwnode = dev_fwnode(dev);
enum gpiod_flags gflags;
int ret;
......@@ -373,8 +380,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data = &priv->bit_data;
pdata = &priv->pdata;
if (np) {
of_i2c_gpio_get_props(np, pdata);
if (fwnode) {
i2c_gpio_get_properties(dev, pdata);
} else {
/*
* If all platform data settings are zero it is OK
......@@ -392,7 +399,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
* handle them as we handle any other output. Else we enforce open
* drain as this is required for an I2C bus.
*/
if (pdata->sda_is_open_drain)
if (pdata->sda_is_open_drain || pdata->sda_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
......@@ -400,7 +407,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->sda))
return PTR_ERR(priv->sda);
if (pdata->scl_is_open_drain)
if (pdata->scl_is_open_drain || pdata->scl_has_no_pullup)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
......@@ -418,7 +425,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (!pdata->scl_is_output_only)
bit_data->getscl = i2c_gpio_getscl;
bit_data->getsda = i2c_gpio_getsda;
if (!pdata->sda_is_output_only)
bit_data->getsda = i2c_gpio_getsda;
if (pdata->udelay)
bit_data->udelay = pdata->udelay;
......@@ -435,7 +443,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
bit_data->data = priv;
adap->owner = THIS_MODULE;
if (np)
if (fwnode)
strscpy(adap->name, dev_name(dev), sizeof(adap->name));
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
......@@ -443,7 +451,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->dev.parent = dev;
adap->dev.of_node = np;
device_set_node(&adap->dev, fwnode);
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
......@@ -489,10 +497,17 @@ static const struct of_device_id i2c_gpio_dt_ids[] = {
MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
static const struct acpi_device_id i2c_gpio_acpi_match[] = {
{ "LOON0005" }, /* LoongArch */
{ }
};
MODULE_DEVICE_TABLE(acpi, i2c_gpio_acpi_match);
static struct platform_driver i2c_gpio_driver = {
.driver = {
.name = "i2c-gpio",
.of_match_table = i2c_gpio_dt_ids,
.acpi_match_table = i2c_gpio_acpi_match,
},
.probe = i2c_gpio_probe,
.remove = i2c_gpio_remove,
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Loongson-2K/Loongson LS7A I2C master mode driver
*
* Copyright (C) 2013 Loongson Technology Corporation Limited.
* Copyright (C) 2014-2017 Lemote, Inc.
* Copyright (C) 2018-2022 Loongson Technology Corporation Limited.
*
* Originally written by liushaozong
* Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn>
*/
#include <linux/bits.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/iopoll.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/units.h>
/* I2C Registers */
#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */
#define I2C_LS2X_CTR 0x2 /* Control Register */
#define I2C_LS2X_TXR 0x3 /* Transport Data Register */
#define I2C_LS2X_RXR 0x3 /* Receive Data Register */
#define I2C_LS2X_CR 0x4 /* Command Control Register */
#define I2C_LS2X_SR 0x4 /* State Register */
/* Command Control Register Bit */
#define LS2X_CR_START BIT(7) /* Start signal */
#define LS2X_CR_STOP BIT(6) /* Stop signal */
#define LS2X_CR_READ BIT(5) /* Read signal */
#define LS2X_CR_WRITE BIT(4) /* Write signal */
#define LS2X_CR_ACK BIT(3) /* Response signal */
#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */
/* State Register Bit */
#define LS2X_SR_NOACK BIT(7) /* Receive NACK */
#define LS2X_SR_BUSY BIT(6) /* Bus busy state */
#define LS2X_SR_AL BIT(5) /* Arbitration lost */
#define LS2X_SR_TIP BIT(1) /* Transmission state */
#define LS2X_SR_IF BIT(0) /* Interrupt flag */
/* Control Register Bit */
#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */
#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */
#define LS2X_CTR_MST BIT(5) /* 0: Slave mode 1: Master mode */
#define CTR_FREQ_MASK GENMASK(7, 6)
#define CTR_READY_MASK GENMASK(7, 5)
/* The PCLK frequency from LPB */
#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ)
/* The default bus frequency, which is an empirical value */
#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
struct ls2x_i2c_priv {
struct i2c_adapter adapter;
void __iomem *base;
struct i2c_timings i2c_t;
struct completion cmd_complete;
};
/*
* Interrupt service routine.
* This gets called whenever an I2C interrupt occurs.
*/
static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
{
struct ls2x_i2c_priv *priv = dev_id;
if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF))
return IRQ_NONE;
writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR);
complete(&priv->cmd_complete);
return IRQ_HANDLED;
}
/*
* The ls2x i2c controller supports standard mode and fast mode, so the
* maximum bus frequency is '400kHz'.
* The bus frequency is set to the empirical value of '33KHz' by default,
* but it can also be taken from ACPI or FDT for compatibility with more
* devices.
*/
static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
{
struct i2c_timings *t = &priv->i2c_t;
struct device *dev = priv->adapter.dev.parent;
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
i2c_parse_fw_timings(dev, t, false);
if (acpi_speed || t->bus_freq_hz)
t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed);
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
/* Calculate and set i2c frequency. */
writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1,
priv->base + I2C_LS2X_PRER);
}
static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
{
/* Set i2c frequency setting mode and disable interrupts. */
writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK,
priv->base + I2C_LS2X_CTR);
ls2x_i2c_adjust_bus_speed(priv);
/* Set i2c normal operating mode and enable interrupts. */
writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK,
priv->base + I2C_LS2X_CTR);
}
static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap)
{
u8 rxdata;
unsigned long time_left;
writeb(txdata, priv->base + I2C_LS2X_CR);
time_left = wait_for_completion_timeout(&priv->cmd_complete,
priv->adapter.timeout);
if (!time_left)
return -ETIMEDOUT;
rxdata = readb(priv->base + I2C_LS2X_SR);
if (rxdatap)
*rxdatap = rxdata;
return 0;
}
static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata)
{
int ret;
u8 rxdata;
ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata);
if (ret)
return ret;
if (rxdata & LS2X_SR_AL)
return -EAGAIN;
if (rxdata & LS2X_SR_NOACK)
return -ENXIO;
return 0;
}
static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv)
{
u8 value;
writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR);
return readb_poll_timeout(priv->base + I2C_LS2X_SR, value,
!(value & LS2X_SR_BUSY), 100,
jiffies_to_usecs(priv->adapter.timeout));
}
static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs)
{
reinit_completion(&priv->cmd_complete);
writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR);
return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE);
}
static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
{
int ret;
u8 rxdata, *buf = msg->buf;
u16 len = msg->len;
/* Contains steps to send start condition and address. */
ret = ls2x_i2c_start(priv, msg);
if (ret)
return ret;
while (len--) {
ret = ls2x_i2c_xfer_byte(priv,
LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK),
&rxdata);
if (ret)
return ret;
*buf++ = readb(priv->base + I2C_LS2X_RXR);
}
return 0;
}
static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg)
{
int ret;
u8 *buf = msg->buf;
u16 len = msg->len;
/* Contains steps to send start condition and address. */
ret = ls2x_i2c_start(priv, msg);
if (ret)
return ret;
while (len--) {
writeb(*buf++, priv->base + I2C_LS2X_TXR);
ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE);
if (ret)
return ret;
}
return 0;
}
static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv,
struct i2c_msg *msg, bool stop)
{
int ret;
if (msg->flags & I2C_M_RD)
ret = ls2x_i2c_rx(priv, msg);
else
ret = ls2x_i2c_tx(priv, msg);
if (ret < 0) {
/* Fatel error. Needs reinit. */
if (ret == -ETIMEDOUT)
ls2x_i2c_init(priv);
return ret;
}
if (stop) {
/* Failed to issue STOP. Needs reinit. */
ret = ls2x_i2c_stop(priv);
if (ret)
ls2x_i2c_init(priv);
}
return ret;
}
static int ls2x_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
int ret;
struct i2c_msg *msg, *emsg = msgs + num;
struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap);
for (msg = msgs; msg < emsg; msg++) {
ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1);
if (ret)
return ret;
}
return num;
}
static unsigned int ls2x_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm ls2x_i2c_algo = {
.master_xfer = ls2x_i2c_master_xfer,
.functionality = ls2x_i2c_func,
};
static int ls2x_i2c_probe(struct platform_device *pdev)
{
int ret, irq;
struct i2c_adapter *adap;
struct ls2x_i2c_priv *priv;
struct device *dev = &pdev->dev;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* Map hardware registers */
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
/* Add the i2c adapter */
adap = &priv->adapter;
adap->retries = 5;
adap->nr = pdev->id;
adap->dev.parent = dev;
adap->owner = THIS_MODULE;
adap->algo = &ls2x_i2c_algo;
adap->timeout = msecs_to_jiffies(100);
device_set_node(&adap->dev, dev_fwnode(dev));
i2c_set_adapdata(adap, priv);
strscpy(adap->name, pdev->name, sizeof(adap->name));
init_completion(&priv->cmd_complete);
platform_set_drvdata(pdev, priv);
ls2x_i2c_init(priv);
ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
priv);
if (ret < 0)
return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq);
return devm_i2c_add_adapter(dev, adap);
}
static int ls2x_i2c_suspend(struct device *dev)
{
struct ls2x_i2c_priv *priv = dev_get_drvdata(dev);
/* Disable interrupts */
writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN,
priv->base + I2C_LS2X_CTR);
return 0;
}
static int ls2x_i2c_resume(struct device *dev)
{
ls2x_i2c_init(dev_get_drvdata(dev));
return 0;
}
static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
static const struct of_device_id ls2x_i2c_id_table[] = {
{ .compatible = "loongson,ls2k-i2c" },
{ .compatible = "loongson,ls7a-i2c" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);
static const struct acpi_device_id ls2x_i2c_acpi_match[] = {
{ "LOON0004" }, /* Loongson LS7A */
{ }
};
MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match);
static struct platform_driver ls2x_i2c_driver = {
.probe = ls2x_i2c_probe,
.driver = {
.name = "ls2x-i2c",
.pm = pm_sleep_ptr(&ls2x_i2c_pm_ops),
.of_match_table = ls2x_i2c_id_table,
.acpi_match_table = ls2x_i2c_acpi_match,
},
};
module_platform_driver(ls2x_i2c_driver);
MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver");
MODULE_AUTHOR("Loongson Technology Corporation Limited");
MODULE_LICENSE("GPL");
......@@ -1366,20 +1366,17 @@ static int mtk_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mtk_i2c *i2c;
struct resource *res;
int i, irq, speed_clk;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
i2c->pdmabase = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
if (IS_ERR(i2c->pdmabase))
return PTR_ERR(i2c->pdmabase);
......
......@@ -811,9 +811,15 @@ static const struct cci_data cci_v2_data = {
static const struct of_device_id cci_dt_match[] = {
{ .compatible = "qcom,msm8226-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data},
{ .compatible = "qcom,msm8996-cci", .data = &cci_v2_data},
/*
* Legacy compatibles kept for backwards compatibility.
* Do not add any new ones unless they introduce a new config
*/
{ .compatible = "qcom,msm8916-cci", .data = &cci_v1_data},
{ .compatible = "qcom,sdm845-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8250-cci", .data = &cci_v2_data},
{ .compatible = "qcom,sm8450-cci", .data = &cci_v2_data},
......
......@@ -1025,7 +1025,7 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
NULL)
};
const struct geni_i2c_desc i2c_master_hub = {
static const struct geni_i2c_desc i2c_master_hub = {
.has_core_clk = true,
.icc_ddr = NULL,
.no_dma_support = true,
......
......@@ -740,7 +740,6 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap,
return (ret < 0) ? ret : i;
}
#ifdef CONFIG_PM_SLEEP
static int st_i2c_suspend(struct device *dev)
{
struct st_i2c_dev *i2c_dev = dev_get_drvdata(dev);
......@@ -762,11 +761,7 @@ static int st_i2c_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
#define ST_I2C_PM (&st_i2c_pm)
#else
#define ST_I2C_PM NULL
#endif
static DEFINE_SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume);
static u32 st_i2c_func(struct i2c_adapter *adap)
{
......@@ -901,7 +896,7 @@ static struct platform_driver st_i2c_driver = {
.driver = {
.name = "st-i2c",
.of_match_table = st_i2c_match,
.pm = ST_I2C_PM,
.pm = pm_sleep_ptr(&st_i2c_pm),
},
.probe = st_i2c_probe,
.remove = st_i2c_remove,
......
This diff is collapsed.
......@@ -34,6 +34,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
......@@ -282,7 +283,9 @@ static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
struct device *dev = &adap->dev;
struct pinctrl *p = bri->pinctrl;
struct pinctrl *p = bri->pinctrl ?: dev_pinctrl(dev->parent);
bri->pinctrl = p;
/*
* we can't change states without pinctrl, so remove the states if
......
......@@ -653,12 +653,12 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
int res;
if (dev->type != &i2c_adapter_type)
return 0;
return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
return NOTIFY_DONE;
cdev_init(&i2c_dev->cdev, &i2cdev_fops);
i2c_dev->cdev.owner = THIS_MODULE;
......@@ -678,11 +678,11 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy)
goto err_put_i2c_dev;
pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr);
return 0;
return NOTIFY_OK;
err_put_i2c_dev:
put_i2c_dev(i2c_dev, false);
return res;
return NOTIFY_DONE;
}
static int i2cdev_detach_adapter(struct device *dev, void *dummy)
......@@ -691,17 +691,17 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy)
struct i2c_dev *i2c_dev;
if (dev->type != &i2c_adapter_type)
return 0;
return NOTIFY_DONE;
adap = to_i2c_adapter(dev);
i2c_dev = i2c_dev_get_by_minor(adap->nr);
if (!i2c_dev) /* attach_adapter must have failed */
return 0;
return NOTIFY_DONE;
put_i2c_dev(i2c_dev, true);
pr_debug("adapter [%s] unregistered\n", adap->name);
return 0;
return NOTIFY_OK;
}
static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
......@@ -716,7 +716,7 @@ static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
return i2cdev_detach_adapter(dev, NULL);
}
return 0;
return NOTIFY_DONE;
}
static struct notifier_block i2cdev_notifier = {
......
......@@ -18,6 +18,8 @@ struct device;
#ifdef CONFIG_PINCTRL
#include <linux/device.h>
/* The device core acts as a consumer toward pinctrl */
#include <linux/pinctrl/consumer.h>
......@@ -44,6 +46,14 @@ struct dev_pin_info {
extern int pinctrl_bind_pins(struct device *dev);
extern int pinctrl_init_done(struct device *dev);
static inline struct pinctrl *dev_pinctrl(struct device *dev)
{
if (!dev->pins)
return NULL;
return dev->pins->p;
}
#else
/* Stubs if we're not using pinctrl */
......@@ -58,5 +68,10 @@ static inline int pinctrl_init_done(struct device *dev)
return 0;
}
static inline struct pinctrl *dev_pinctrl(struct device *dev)
{
return NULL;
}
#endif /* CONFIG_PINCTRL */
#endif /* PINCTRL_DEVINFO_H */
......@@ -16,16 +16,25 @@
* isn't actively driven high when setting the output value high.
* gpio_get_value() must return the actual pin state even if the
* pin is configured as an output.
* @sda_is_output_only: SDA output drivers can't be turned off.
* This is for clients that can only read SDA/SCL.
* @sda_has_no_pullup: SDA is used in a non-compliant way and has no pull-up.
* Therefore disable open-drain.
* @scl_is_open_drain: SCL is set up as open drain. Same requirements
* as for sda_is_open_drain apply.
* @scl_is_output_only: SCL output drivers cannot be turned off.
* @scl_has_no_pullup: SCL is used in a non-compliant way and has no pull-up.
* Therefore disable open-drain.
*/
struct i2c_gpio_platform_data {
int udelay;
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int sda_is_output_only:1;
unsigned int sda_has_no_pullup:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
unsigned int scl_has_no_pullup:1;
};
#endif /* _LINUX_I2C_GPIO_H */
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