i2c for v7.3

Core and helpers:
 - support bus recovery with single-ended GPIOs
 - acpi: clean up resource handling
 - acpi: force ELAN1300 to 100 kHz
 - algo-bit: allow consumers to skip the optional bus test
 
 Drivers:
 - use generic bus frequency definitions in nomadik,
   octeon-core, microchip-corei2c, k1, davinci and pnx
 - i2c-gpio: support multiple buses sharing the same SCL line
 - qup: propagate clock enable failures
 - spacemit: configure SCL timing and clean up clock handling
 - amd-asf: guard against oversized firmware length
 
 qcom-geni:
 - add tracepoints for bus setup, interrupts and errors
 - use dedicated completion events for abort and reset
 - distinguish address and data NACK handling
 - cancel transfers before falling back to abort
 - simplify runtime PM and resource management
 - refactor resource and serial engine initialization
 
 DT bindings:
 - convert Altera bindings to DT schema
 - convert Axxia bindings to DT schema
 
 New support:
 - R-Car Gen5 and R-Car X5H
 - Axiado AX3005
 - Qualcomm Nord SA8797P
 - Qualcomm SA8255p
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQScDfrjQa34uOld1VLaeAVmJtMtbgUCaoA//QAKCRDaeAVmJtMt
 bvzYAQDPhRd2O6BruFmCkxKKvlrxZ2AaHQX/ZHLNqLAq/oX4NwD8CSecgva9faf/
 bC+kTGoTMBhje3FEJFufHKe2YtmJdgg=
 =u6az
 -----END PGP SIGNATURE-----

Merge tag 'i2c-7.3-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux

Pull i2c updates from Andi Shyti:
 "The main changes are support for shared SCL lines in i2c-gpio, a
  larger qcom-geni update covering tracing and transfer recovery and
  support for R-Car Gen5.

  The rest is mostly smaller driver, core and DT binding updates.

  Core and helpers:
   - support bus recovery with single-ended GPIOs
   - acpi: clean up resource handling
   - acpi: force ELAN1300 to 100 kHz
   - algo-bit: allow consumers to skip the optional bus test

  Drivers:
   - use generic bus frequency definitions in nomadik, octeon-core,
     microchip-corei2c, k1, davinci and pnx
   - i2c-gpio: support multiple buses sharing the same SCL line
   - qup: propagate clock enable failures
   - spacemit: configure SCL timing and clean up clock handling
   - amd-asf: guard against oversized firmware length

  qcom-geni:
   - add tracepoints for bus setup, interrupts and errors
   - use dedicated completion events for abort and reset
   - distinguish address and data NACK handling
   - cancel transfers before falling back to abort
   - simplify runtime PM and resource management
   - refactor resource and serial engine initialization

  DT bindings:
   - convert Altera bindings to DT schema
   - convert Axxia bindings to DT schema

  New support:
   - R-Car Gen5 and R-Car X5H
   - Axiado AX3005
   - Qualcomm Nord SA8797P
   - Qualcomm SA8255p"

* tag 'i2c-7.3-part1' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux: (33 commits)
  i2c: core: support recovery for single-ended GPIOs
  i2c: rcar: add R-Car Gen5 support
  dt-bindings: i2c: rcar-i2c: Document R-Car X5H support
  i2c: i2c-gpio: Enhance driver for buses with shared SCL
  i2c: algo: bit: Allow to skip bit test
  i2c: qcom-geni: Add trace events for Qualcomm GENI I2C driver
  i2c: qcom-geni: trace: Add trace events for Qualcomm GENI I2C
  i2c: qup: Propagate clock enable failures
  i2c: qcom-geni: distinguish address-phase and data-phase NACK
  i2c: qcom-geni: use dedicated completions for abort and reset events
  i2c: qcom-geni: use cancel command before abort on transfer timeout
  dt-bindings: i2c: cdns: add Axiado AX3005 I2C variant
  i2c: qcom-geni: Use devm_pm_runtime_enable() for PM management
  dt-bindings: i2c: qcom,sa8255p-geni-i2c: Add compatible for Nord SA8797P
  i2c: nomadik: Use generic definitions for bus frequencies
  i2c: octeon-core: Use generic definitions for bus frequencies
  i2c: microchip-corei2c: Use generic definitions for bus frequencies
  i2c: k1: Use generic definitions for bus frequencies
  i2c: davinci: Use generic definitions for bus frequencies
  i2c: pnx: Use generic definitions for bus frequencies
  ...
This commit is contained in:
Linus Torvalds 2026-08-19 09:23:13 -07:00
commit abea5c3493
24 changed files with 966 additions and 339 deletions

View File

@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/altr,softip-i2c-v1.0.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Altera I2C Controller
maintainers:
- Thor Thayer <thor.thayer@linux.intel.com>
- Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
description:
Altera's synthesizable logic block I2C Controller for use in Altera's FPGAs.
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: altr,softip-i2c-v1.0
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
fifo-size:
$ref: /schemas/types.yaml#/definitions/uint32
description: Size of the RX and TX FIFOs in bytes.
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
i2c@80000 {
compatible = "altr,softip-i2c-v1.0";
reg = <0x80000 0x40>;
interrupt-parent = <&intc>;
interrupts = <0 43 4>;
clocks = <&clk_0>;
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
fifo-size = <4>;
eeprom@51 {
compatible = "atmel,24c32";
reg = <0x51>;
pagesize = <32>;
};
};

View File

@ -14,9 +14,13 @@ allOf:
properties:
compatible:
enum:
- cdns,i2c-r1p10 # cadence i2c controller version 1.0
- cdns,i2c-r1p14 # cadence i2c controller version 1.4
oneOf:
- enum:
- cdns,i2c-r1p10 # cadence i2c controller version 1.0
- cdns,i2c-r1p14 # cadence i2c controller version 1.4
- items:
- const: axiado,ax3005-i2c
- const: cdns,i2c-r1p14
reg:
maxItems: 1

View File

@ -1,39 +0,0 @@
* Altera I2C Controller
* This is Altera's synthesizable logic block I2C Controller for use
* in Altera's FPGAs.
Required properties :
- compatible : should be "altr,softip-i2c-v1.0"
- reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number.
- clocks : phandle to input clock.
- #address-cells = <1>;
- #size-cells = <0>;
Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties :
- fifo-size : Size of the RX and TX FIFOs in bytes.
- Child nodes conforming to i2c bus binding
Example :
i2c@100080000 {
compatible = "altr,softip-i2c-v1.0";
reg = <0x00000001 0x00080000 0x00000040>;
interrupt-parent = <&intc>;
interrupts = <0 43 4>;
clocks = <&clk_0>;
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
fifo-size = <4>;
eeprom@51 {
compatible = "atmel,24c32";
reg = <0x51>;
pagesize = <32>;
};
};

View File

@ -1,30 +0,0 @@
LSI Axxia I2C
Required properties :
- compatible : Must be "lsi,api2c"
- reg : Offset and length of the register set for the device
- interrupts : the interrupt specifier
- #address-cells : Must be <1>;
- #size-cells : Must be <0>;
- clock-names : Must contain "i2c".
- clocks: Must contain an entry for each name in clock-names. See the common
clock bindings.
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.
Example :
i2c@2010084000 {
compatible = "lsi,api2c";
device_type = "i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x20 0x10084000 0x00 0x1000>;
interrupts = <0 19 4>;
clocks = <&clk_per>;
clock-names = "i2c";
clock-frequency = <400000>;
};

View File

@ -0,0 +1,52 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/lsi,api2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LSI Axxia I2C Controller
maintainers:
- Anders Berg <anders.berg@lsi.com>
- Chaitanya Sabnis <chaitanya.msabnis@gmail.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
const: lsi,api2c
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
const: i2c
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
i2c@10084000 {
compatible = "lsi,api2c";
reg = <0x10084000 0x1000>;
interrupts = <0 19 4>;
clocks = <&clk_per>;
clock-names = "i2c";
clock-frequency = <400000>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/qcom,sa8255p-geni-i2c.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SA8255p QUP GENI I2C Controller
maintainers:
- Praveen Talari <praveen.talari@oss.qualcomm.com>
properties:
compatible:
oneOf:
- const: qcom,sa8255p-geni-i2c
- items:
- const: qcom,sa8797p-geni-i2c
- const: qcom,sa8255p-geni-i2c
reg:
maxItems: 1
dmas:
maxItems: 2
dma-names:
items:
- const: tx
- const: rx
interrupts:
maxItems: 1
power-domains:
maxItems: 2
power-domain-names:
items:
- const: power
- const: perf
required:
- compatible
- reg
- interrupts
- power-domains
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/dma/qcom-gpi.h>
i2c@a90000 {
compatible = "qcom,sa8255p-geni-i2c";
reg = <0xa90000 0x4000>;
interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>,
<&gpi_dma0 1 0 QCOM_GPI_I2C>;
dma-names = "tx", "rx";
power-domains = <&scmi0_pd 0>, <&scmi0_dvfs 0>;
power-domain-names = "power", "perf";
};
...

View File

@ -56,6 +56,11 @@ properties:
- renesas,i2c-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-i2c # R-Car Gen4
- items:
- enum:
- renesas,i2c-r8a78000 # R-Car X5H
- const: renesas,rcar-gen5-i2c # R-Car Gen5
reg:
maxItems: 1
@ -140,6 +145,7 @@ allOf:
- renesas,rcar-gen2-i2c
- renesas,rcar-gen3-i2c
- renesas,rcar-gen4-i2c
- renesas,rcar-gen5-i2c
then:
required:
- resets

View File

@ -639,7 +639,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
int ret;
if (bit_test) {
if (bit_test && !bit_adap->skip_bit_test) {
ret = test_bus(adap);
if (bit_test >= 2 && ret < 0)
return -ENODEV;

View File

@ -793,7 +793,7 @@ config I2C_JZ4780
config I2C_K1
tristate "SpacemiT K1 I2C adapter"
depends on ARCH_SPACEMIT || COMPILE_TEST
depends on OF
depends on OF && COMMON_CLK
default ARCH_SPACEMIT
help
This option enables support for the I2C interface on the SpacemiT K1

View File

@ -89,6 +89,10 @@ static void amd_asf_process_target(struct work_struct *work)
outb_p(reg, ASFDATABNKSEL);
cmd = inb_p(ASFINDEX);
len = inb_p(ASFDATARWPTR);
if (len > ASF_BLOCK_MAX_BYTES)
return;
for (idx = 0; idx < len; idx++)
data[idx] = inb_p(ASFINDEX);

View File

@ -117,8 +117,6 @@
/* timeout for pm runtime autosuspend */
#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */
#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100000
struct davinci_i2c_dev {
struct device *dev;
void __iomem *base;
@ -760,7 +758,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
if (r)
prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
prop = I2C_MAX_STANDARD_MODE_FREQ;
dev->bus_freq = prop / 1000;

View File

@ -18,9 +18,21 @@
#include <linux/property.h>
#include <linux/slab.h>
static LIST_HEAD(i2c_gpio_scl_list);
static DEFINE_MUTEX(i2c_gpio_scl_list_lock);
static struct lock_class_key i2c_gpio_scl_lock_key;
struct i2c_gpio_scl_data {
struct fwnode_reference_args args;
struct gpio_desc *gpio;
struct rt_mutex lock;
struct list_head list;
refcount_t ref;
};
struct i2c_gpio_private_data {
struct gpio_desc *sda;
struct gpio_desc *scl;
struct i2c_gpio_scl_data *scl;
struct i2c_adapter adap;
struct i2c_algo_bit_data bit_data;
struct i2c_gpio_platform_data pdata;
@ -31,6 +43,11 @@ struct i2c_gpio_private_data {
#endif
};
static inline struct i2c_gpio_private_data *adap_to_priv(struct i2c_adapter *adap)
{
return container_of(adap, struct i2c_gpio_private_data, adap);
}
/*
* Toggle SDA by changing the output value of the pin. This is only
* valid for pins configured as open drain (i.e. setting the value
@ -53,7 +70,7 @@ static void i2c_gpio_setscl_val(void *data, int state)
{
struct i2c_gpio_private_data *priv = data;
gpiod_set_value_cansleep(priv->scl, state);
gpiod_set_value_cansleep(priv->scl->gpio, state);
}
static int i2c_gpio_getsda(void *data)
@ -67,9 +84,41 @@ static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_private_data *priv = data;
return gpiod_get_value_cansleep(priv->scl);
return gpiod_get_value_cansleep(priv->scl->gpio);
}
static void i2c_gpio_lock_bus(struct i2c_adapter *adap, unsigned int flags)
{
/* Take care about adapter lock. See i2c_adapter_lock_bus() and others. */
rt_mutex_lock_nested(&adap->bus_lock, i2c_adapter_depth(adap));
rt_mutex_lock(&adap_to_priv(adap)->scl->lock);
}
static int i2c_gpio_trylock_bus(struct i2c_adapter *adap, unsigned int flags)
{
if (!rt_mutex_trylock(&adap->bus_lock))
return 0;
if (!rt_mutex_trylock(&adap_to_priv(adap)->scl->lock)) {
rt_mutex_unlock(&adap->bus_lock);
return 0;
}
return 1;
}
static void i2c_gpio_unlock_bus(struct i2c_adapter *adap, unsigned int flags)
{
rt_mutex_unlock(&adap_to_priv(adap)->scl->lock);
rt_mutex_unlock(&adap->bus_lock);
}
static const struct i2c_lock_operations i2c_gpio_lock_ops = {
.lock_bus = i2c_gpio_lock_bus,
.trylock_bus = i2c_gpio_trylock_bus,
.unlock_bus = i2c_gpio_unlock_bus,
};
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
#define setsda(bd, val) ((bd)->setsda((bd)->data, val))
@ -165,14 +214,14 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write
static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
irqreturn_t handler(int, void*))
{
int ret, irq = gpiod_to_irq(priv->scl);
int ret, irq = gpiod_to_irq(priv->scl->gpio);
if (irq < 0)
return irq;
i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
ret = gpiod_direction_input(priv->scl);
ret = gpiod_direction_input(priv->scl->gpio);
if (ret)
goto unlock;
@ -187,7 +236,7 @@ static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
free_irq(irq, priv);
output:
ret = gpiod_direction_output(priv->scl, 1) ?: ret;
ret = gpiod_direction_output(priv->scl->gpio, 1) ?: ret;
unlock:
i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
@ -308,13 +357,17 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
struct gpio_desc *retdesc;
int ret;
retdesc = devm_gpiod_get(dev, con_id, gflags);
/*
* Don't use resource-managed functions. SCL may be shared across adapters and has
* its own lifetime management. SDA uses the same path for consistency.
*/
retdesc = gpiod_get(dev, con_id, gflags);
if (!IS_ERR(retdesc)) {
dev_dbg(dev, "got GPIO from name %s\n", con_id);
return retdesc;
}
retdesc = devm_gpiod_get_index(dev, NULL, index, gflags);
retdesc = gpiod_get_index(dev, NULL, index, gflags);
if (!IS_ERR(retdesc)) {
dev_dbg(dev, "got GPIO from index %u\n", index);
return retdesc;
@ -336,6 +389,134 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
return retdesc;
}
static struct i2c_gpio_scl_data *i2c_gpio_create_scl(struct device *dev)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct fwnode_reference_args args;
struct i2c_gpio_scl_data *scl;
bool sharable = false;
int ret;
/*
* SCL gpios can be shared if they are defined in the devicetree and have at least one
* cell in addition to the phandle. This is usually the pin. To support complex designs
* with arbitrary of_xlate() mappings handle the node cells opaque.
*/
if (fwnode) {
ret = fwnode_property_get_reference_args(fwnode, "scl-gpios",
"#gpio-cells", 0, 0, &args);
if (ret)
/* try the ancient way */
ret = fwnode_property_get_reference_args(fwnode, "gpios",
"#gpio-cells", 0, 1, &args);
if (!ret) {
if (args.nargs >= 1)
sharable = true;
else
fwnode_handle_put(args.fwnode);
}
}
scl = kzalloc(sizeof(*scl), GFP_KERNEL);
if (!scl) {
if (sharable)
fwnode_handle_put(args.fwnode);
return ERR_PTR(-ENOMEM);
}
if (sharable) {
scl->args.fwnode = args.fwnode;
scl->args.nargs = args.nargs;
memcpy(scl->args.args, args.args, sizeof(args.args[0]) * args.nargs);
}
rt_mutex_init(&scl->lock);
lockdep_set_class(&scl->lock, &i2c_gpio_scl_lock_key);
refcount_set(&scl->ref, 1);
return scl;
}
static void i2c_gpio_free_scl(struct i2c_gpio_scl_data *scl)
{
if (scl->args.fwnode)
fwnode_handle_put(scl->args.fwnode);
kfree(scl);
}
static bool i2c_gpio_scl_matches(struct i2c_gpio_scl_data *a, struct i2c_gpio_scl_data *b)
{
if (!a->args.fwnode || !b->args.fwnode ||
a->args.fwnode != b->args.fwnode || a->args.nargs != b->args.nargs)
return false;
return memcmp(a->args.args, b->args.args, sizeof(a->args.args[0]) * a->args.nargs) == 0;
}
/*
* Look up an existing or create a new shared SCL structure. Optimistic setup sequence always
* creates and tries to add a new entry to the list. This uses minimum locking and afterwards
* requests the GPIO without a lock held. Concurrent probes for the same SCL pin see the entry
* and do not race into a second gpiod_get(). Until everything is setup they terminate with
* -EPROBE_DEFER.
*/
static struct i2c_gpio_scl_data *i2c_gpio_lookup_scl(struct device *dev, enum gpiod_flags gflags)
{
struct i2c_gpio_scl_data *scl, *new_scl;
struct gpio_desc *gpio;
new_scl = i2c_gpio_create_scl(dev);
if (IS_ERR(new_scl))
return new_scl;
scoped_guard(mutex, &i2c_gpio_scl_list_lock) {
list_for_each_entry(scl, &i2c_gpio_scl_list, list) {
if (!i2c_gpio_scl_matches(scl, new_scl))
continue;
i2c_gpio_free_scl(new_scl);
if (!scl->gpio)
return ERR_PTR(-EPROBE_DEFER);
refcount_inc(&scl->ref);
if (scl->args.fwnode)
dev_dbg(dev, "reusing shared SCL (%pfwP)\n", scl->args.fwnode);
return scl;
}
list_add(&new_scl->list, &i2c_gpio_scl_list);
}
gpio = i2c_gpio_get_desc(dev, "scl", 1, gflags);
if (IS_ERR(gpio)) {
scoped_guard(mutex, &i2c_gpio_scl_list_lock)
list_del(&new_scl->list);
i2c_gpio_free_scl(new_scl);
return ERR_CAST(gpio);
}
scoped_guard(mutex, &i2c_gpio_scl_list_lock)
new_scl->gpio = gpio;
if (new_scl->args.fwnode)
dev_dbg(dev, "registered shared SCL (%pfwP)\n", new_scl->args.fwnode);
return new_scl;
}
static void i2c_gpio_cleanup_scl(struct i2c_gpio_scl_data *scl)
{
if (!refcount_dec_and_mutex_lock(&scl->ref, &i2c_gpio_scl_list_lock))
return;
list_del(&scl->list);
mutex_unlock(&i2c_gpio_scl_list_lock);
gpiod_put(scl->gpio);
i2c_gpio_free_scl(scl);
}
static int i2c_gpio_probe(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv;
@ -386,15 +567,18 @@ static int i2c_gpio_probe(struct platform_device *pdev)
gflags = GPIOD_OUT_HIGH;
else
gflags = GPIOD_OUT_HIGH_OPEN_DRAIN;
priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags);
if (IS_ERR(priv->scl))
return PTR_ERR(priv->scl);
priv->scl = i2c_gpio_lookup_scl(dev, gflags);
if (IS_ERR(priv->scl)) {
ret = PTR_ERR(priv->scl);
goto err_cleanup_sda;
}
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl))
if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl->gpio))
dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing");
else
bit_data->can_do_atomic = true;
bit_data->skip_bit_test = !!priv->scl->args.fwnode;
bit_data->setsda = i2c_gpio_setsda_val;
bit_data->setscl = i2c_gpio_setscl_val;
@ -423,6 +607,8 @@ static int i2c_gpio_probe(struct platform_device *pdev)
else
snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
/* Always use shared SCL aware locking */
adap->lock_ops = &i2c_gpio_lock_ops;
adap->algo_data = bit_data;
adap->class = I2C_CLASS_HWMON;
adap->dev.parent = dev;
@ -431,7 +617,7 @@ static int i2c_gpio_probe(struct platform_device *pdev)
adap->nr = pdev->id;
ret = i2c_bit_add_numbered_bus(adap);
if (ret)
return ret;
goto err_cleanup_scl;
platform_set_drvdata(pdev, priv);
@ -441,13 +627,20 @@ static int i2c_gpio_probe(struct platform_device *pdev)
* from the descriptor, then provide that instead.
*/
dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n",
desc_to_gpio(priv->sda), desc_to_gpio(priv->scl),
desc_to_gpio(priv->sda), desc_to_gpio(priv->scl->gpio),
pdata->scl_is_output_only
? ", no clock stretching" : "");
i2c_gpio_fault_injector_init(pdev);
return 0;
err_cleanup_scl:
i2c_gpio_cleanup_scl(priv->scl);
err_cleanup_sda:
gpiod_put(priv->sda);
return ret;
}
static void i2c_gpio_remove(struct platform_device *pdev)
@ -459,6 +652,8 @@ static void i2c_gpio_remove(struct platform_device *pdev)
adap = &priv->adap;
i2c_del_adapter(adap);
i2c_gpio_cleanup_scl(priv->scl);
gpiod_put(priv->sda);
}
static const struct of_device_id i2c_gpio_dt_ids[] = {

View File

@ -4,7 +4,9 @@
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@ -17,6 +19,8 @@
#define SPACEMIT_ISR 0x4 /* Status register */
#define SPACEMIT_IDBR 0xc /* Data buffer register */
#define SPACEMIT_IRCR 0x18 /* Reset cycle counter */
#define SPACEMIT_ILCR 0x10 /* Load Count Register */
#define SPACEMIT_IWCR 0x14 /* Wait Count Register */
#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
/* SPACEMIT_ICR register fields */
@ -88,12 +92,22 @@
#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
#define SPACEMIT_LCR_LV_STANDARD_MASK GENMASK(8, 0)
#define SPACEMIT_LCR_LV_FAST_MASK GENMASK(17, 9)
/* SPACEMIT_IWCR register fields */
#define SPACEMIT_WCR_COUNT GENMASK(4, 0)
#define SPACEMIT_WCR_HS_COUNT1 GENMASK(9, 5)
#define SPACEMIT_WCR_HS_COUNT2 GENMASK(14, 10)
/* Required by I2C IP for correct SCL timing */
#define SPACEMIT_IWCR_INIT_VALUE (FIELD_PREP(SPACEMIT_WCR_COUNT, 10) | \
FIELD_PREP(SPACEMIT_WCR_HS_COUNT1, 1) | \
FIELD_PREP(SPACEMIT_WCR_HS_COUNT2, 5))
/* i2c bus recover timeout: us */
#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9
@ -109,11 +123,20 @@ enum spacemit_i2c_state {
SPACEMIT_STATE_WRITE,
};
enum spacemit_i2c_mode {
SPACEMIT_MODE_STANDARD,
SPACEMIT_MODE_FAST
};
/* i2c-spacemit driver's main struct */
struct spacemit_i2c_dev {
struct device *dev;
struct i2c_adapter adapt;
struct clk_hw scl_clk_hw;
struct clk *scl_clk;
enum spacemit_i2c_mode mode;
/* hardware resources */
void __iomem *base;
int irq;
@ -135,6 +158,85 @@ struct spacemit_i2c_dev {
u32 status;
};
static void spacemit_i2c_scl_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
/*
* Calculate the ILCR divider value (lv) from the target SCL rate.
*
* Hardware timing formulas:
* - standard mode: SCL = FCLK / (2 * SLV + 8)
* - fast mode: SCL = FCLK / (2 * FLV + 10)
*/
static u32 spacemit_i2c_calc_lv(struct spacemit_i2c_dev *i2c,
unsigned long parent_rate,
unsigned long target_rate)
{
u32 offset, denom;
offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
denom = DIV_ROUND_CLOSEST(parent_rate, target_rate);
return (denom <= offset) ? 0 : DIV_ROUND_CLOSEST(denom - offset, 2);
}
static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
u32 lv, lcr, mask;
lv = spacemit_i2c_calc_lv(i2c, parent_rate, rate);
mask = (i2c->mode == SPACEMIT_MODE_STANDARD) ?
SPACEMIT_LCR_LV_STANDARD_MASK : SPACEMIT_LCR_LV_FAST_MASK;
lcr = readl(i2c->base + SPACEMIT_ILCR);
lcr &= ~mask;
lcr |= field_prep(mask, lv);
writel(lcr, i2c->base + SPACEMIT_ILCR);
return 0;
}
static int spacemit_i2c_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
u32 lv, offset;
lv = spacemit_i2c_calc_lv(i2c, req->best_parent_rate, req->rate);
offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
req->rate = DIV_ROUND_CLOSEST(req->best_parent_rate, lv * 2 + offset);
return 0;
}
static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
u32 lcr, lv = 0;
lcr = readl(i2c->base + SPACEMIT_ILCR);
if (i2c->mode == SPACEMIT_MODE_STANDARD) {
lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr);
return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 8);
}
lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr);
return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 10);
}
static const struct clk_ops spacemit_i2c_clk_ops = {
.set_rate = spacemit_i2c_clk_set_rate,
.determine_rate = spacemit_i2c_clk_determine_rate,
.recalc_rate = spacemit_i2c_clk_recalc_rate,
};
static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
{
u32 val;
@ -153,6 +255,28 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
writel(val, i2c->base + SPACEMIT_ICR);
}
static int spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c)
{
struct clk_init_data init = {};
char name[64];
int ret;
ret = snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev));
if (ret >= ARRAY_SIZE(name))
dev_warn(i2c->dev, "scl clock name truncated");
init.name = name;
init.ops = &spacemit_i2c_clk_ops;
init.parent_data = (struct clk_parent_data[]) {
{ .fw_name = "func" },
};
init.num_parents = 1;
i2c->scl_clk_hw.init = &init;
return devm_clk_hw_register(i2c->dev, &i2c->scl_clk_hw);
}
static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
{
writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
@ -286,7 +410,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
val |= SPACEMIT_CR_MSDIE;
}
if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
if (i2c->mode == SPACEMIT_MODE_FAST)
val |= SPACEMIT_CR_MODE_FAST;
/* disable response to general call */
@ -309,6 +433,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
writel(val, i2c->base + SPACEMIT_IRCR);
spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
/*
* Initialize IWCR to the value specified by the I2C IP designer.
* The SCL frequency formulas (SCL = FCLK / (2*SLV+8) for standard
* mode, SCL = FCLK / (2*FLV+10) for fast mode) are only valid when
* IWCR contains this specific value.
*/
writel(SPACEMIT_IWCR_INIT_VALUE, i2c->base + SPACEMIT_IWCR);
}
static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
@ -698,19 +830,18 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
if (!i2c)
return -ENOMEM;
ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
if (ret && ret != -EINVAL)
dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
/* For now, this driver doesn't support high-speed. */
if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
} else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
if (i2c->clock_freq > I2C_MAX_STANDARD_MODE_FREQ &&
i2c->clock_freq <= I2C_MAX_FAST_MODE_FREQ) {
i2c->mode = SPACEMIT_MODE_FAST;
} else if (i2c->clock_freq && i2c->clock_freq <= I2C_MAX_STANDARD_MODE_FREQ) {
i2c->mode = SPACEMIT_MODE_STANDARD;
} else {
dev_info(dev, "clock-frequency not set or out of range, using fast mode\n");
i2c->mode = SPACEMIT_MODE_FAST;
i2c->clock_freq = I2C_MAX_FAST_MODE_FREQ;
}
i2c->dev = &pdev->dev;
@ -727,6 +858,15 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
ret = spacemit_i2c_register_scl_clk(i2c);
if (ret)
return dev_err_probe(dev, ret, "failed to register scl clock\n");
i2c->scl_clk = devm_clk_hw_get_clk(dev, &i2c->scl_clk_hw, "scl");
if (IS_ERR(i2c->scl_clk))
return dev_err_probe(dev, PTR_ERR(i2c->scl_clk),
"failed to get scl clock\n");
clk = devm_clk_get_enabled(dev, "bus");
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
@ -736,6 +876,19 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(rst),
"failed to acquire deasserted reset\n");
ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq);
if (ret)
return dev_err_probe(dev, ret, "failed to set rate for SCL clock");
ret = clk_prepare_enable(i2c->scl_clk);
if (ret)
return dev_err_probe(dev, ret, "failed to prepare and enable clock");
ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare,
i2c->scl_clk);
if (ret)
return ret;
spacemit_i2c_reset(i2c);
i2c_set_adapdata(&i2c->adapt, i2c);

View File

@ -565,10 +565,10 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
&idev->bus_clk_rate);
if (ret || !idev->bus_clk_rate) {
dev_info(&pdev->dev, "default to 100kHz\n");
idev->bus_clk_rate = 100000;
idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ;
}
if (idev->bus_clk_rate > 400000)
if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
return dev_err_probe(&pdev->dev, -EINVAL,
"clock-frequency too high: %d\n",
idev->bus_clk_rate);

View File

@ -1050,9 +1050,9 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv)
if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks))
return -ENOENT;
if (priv->clk_freq <= 400000)
if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ)
speed_mode = I2C_EYEQ5_SPEED_FAST;
else if (priv->clk_freq <= 1000000)
else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ)
speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS;
else
speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED;

View File

@ -235,7 +235,7 @@ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c));
}
#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000)
#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= I2C_MAX_FAST_MODE_FREQ)
#define PCI_SUBSYS_DEVID_9XXX 0xB
#define PCI_SUBSYS_MASK GENMASK(15, 12)
/**

View File

@ -24,7 +24,6 @@
#include <linux/of.h>
#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
#define I2C_PNX_SPEED_KHZ_DEFAULT 100
#define I2C_PNX_REGION_SIZE 0x100
struct i2c_pnx_mif {
@ -606,12 +605,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
static int i2c_pnx_probe(struct platform_device *pdev)
{
u32 speed = I2C_MAX_STANDARD_MODE_FREQ;
unsigned long tmp;
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
unsigned long freq;
struct resource *res;
u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
alg_data = devm_kzalloc(&pdev->dev, sizeof(*alg_data), GFP_KERNEL);
if (!alg_data)

View File

@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
#define CREATE_TRACE_POINTS
#include <trace/events/qcom_geni_i2c.h>
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
@ -56,7 +59,8 @@
enum geni_i2c_err_code {
GP_IRQ0,
NACK,
ADDR_NACK,
DATA_NACK,
GP_IRQ2,
BUS_PROTO,
ARB_LOST,
@ -67,16 +71,26 @@ enum geni_i2c_err_code {
GENI_TIMEOUT,
};
#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
#define DM_I2C_CB_ERR ((BIT(ADDR_NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
<< 5)
#define I2C_AUTO_SUSPEND_DELAY 250
#define PACKING_BYTES_PW 4
#define ABORT_TIMEOUT HZ
#define CANCEL_TIMEOUT HZ
#define XFER_TIMEOUT HZ
#define RST_TIMEOUT HZ
struct geni_i2c_desc {
bool no_dma_support;
unsigned int tx_fifo_depth;
int (*resources_init)(struct geni_se *se);
int (*set_rate)(struct geni_se *se, unsigned long freq);
int (*power_on)(struct geni_se *se);
int (*power_off)(struct geni_se *se);
};
#define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2
/**
@ -103,11 +117,14 @@ struct geni_i2c_dev {
int err;
struct i2c_adapter adap;
struct completion done;
struct completion abort_done;
struct completion cancel_done;
struct completion tx_reset_done;
struct completion rx_reset_done;
struct i2c_msg *cur;
int cur_wr;
int cur_rd;
spinlock_t lock;
struct clk *core_clk;
u32 clk_freq_out;
const struct geni_i2c_clk_fld *clk_fld;
void *dma_buf;
@ -117,17 +134,10 @@ struct geni_i2c_dev {
struct dma_chan *rx_c;
bool no_dma;
bool gpi_mode;
bool abort_done;
bool is_tx_multi_desc_xfer;
u32 num_msgs;
struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config;
};
struct geni_i2c_desc {
bool has_core_clk;
char *icc_ddr;
bool no_dma_support;
unsigned int tx_fifo_depth;
const struct geni_i2c_desc *dev_data;
};
struct geni_i2c_err_log {
@ -137,7 +147,8 @@ struct geni_i2c_err_log {
static const struct geni_i2c_err_log gi2c_log[] = {
[GP_IRQ0] = {-EIO, "Unknown I2C err GP_IRQ0"},
[NACK] = {-ENXIO, "NACK: slv unresponsive, check its power/reset-ln"},
[ADDR_NACK] = {-ENXIO, "NACK: target device unresponsive, check its power/reset-ln"},
[DATA_NACK] = {-EIO, "Data NACK: TX transfer NACK"},
[GP_IRQ2] = {-EIO, "Unknown I2C err GP IRQ2"},
[BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unexpected start/stop"},
[ARB_LOST] = {-EAGAIN, "Bus arbitration lost, clock line undriveable"},
@ -202,8 +213,9 @@ static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
return -EINVAL;
}
static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
static int qcom_geni_i2c_conf(struct geni_se *se, unsigned long freq)
{
struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev);
const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
u32 val;
@ -216,6 +228,10 @@ static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
val |= itr->t_cycle_cnt;
writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
itr->clk_div, itr->t_high_cnt,
itr->t_low_cnt, itr->t_cycle_cnt);
return 0;
}
static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c)
@ -248,11 +264,12 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
trace_geni_i2c_err(gi2c->se.dev, gi2c_log[err].err, gi2c_log[err].msg);
switch (err) {
case GENI_ABORT_DONE:
gi2c->abort_done = true;
break;
case NACK:
case ADDR_NACK:
case DATA_NACK:
case GENI_TIMEOUT:
dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
break;
@ -263,6 +280,14 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
}
}
static void geni_i2c_check_addr_data_nack(struct geni_i2c_dev *gi2c)
{
if (!readl_relaxed(gi2c->se.base + SE_GENI_M_GP_LENGTH))
geni_i2c_err(gi2c, ADDR_NACK);
else if (!(gi2c->cur->flags & I2C_M_RD))
geni_i2c_err(gi2c, DATA_NACK);
}
static irqreturn_t geni_i2c_irq(int irq, void *dev)
{
struct geni_i2c_dev *gi2c = dev;
@ -284,11 +309,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
cur = gi2c->cur;
trace_geni_i2c_irq(gi2c->se.dev, m_stat, rx_st, dm_tx_st, dm_rx_st);
if (!cur ||
m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
dm_rx_st & (DM_I2C_CB_ERR)) {
if (m_stat & M_GP_IRQ_1_EN)
geni_i2c_err(gi2c, NACK);
geni_i2c_check_addr_data_nack(gi2c);
if (m_stat & M_GP_IRQ_3_EN)
geni_i2c_err(gi2c, BUS_PROTO);
if (m_stat & M_GP_IRQ_4_EN)
@ -353,10 +380,18 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
/* if this is err with done-bit not set, handle that through timeout. */
if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
if (m_stat & M_CMD_DONE_EN ||
dm_tx_st & TX_DMA_DONE ||
dm_rx_st & RX_DMA_DONE)
complete(&gi2c->done);
if (m_stat & M_CMD_CANCEL_EN)
complete(&gi2c->cancel_done);
if (m_stat & M_CMD_ABORT_EN)
complete(&gi2c->abort_done);
if (dm_tx_st & TX_RESET_DONE)
complete(&gi2c->tx_reset_done);
if (dm_rx_st & RX_RESET_DONE)
complete(&gi2c->rx_reset_done);
spin_unlock(&gi2c->lock);
@ -368,48 +403,59 @@ static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
unsigned long time_left = ABORT_TIMEOUT;
unsigned long flags;
reinit_completion(&gi2c->abort_done);
spin_lock_irqsave(&gi2c->lock, flags);
geni_i2c_err(gi2c, GENI_TIMEOUT);
gi2c->cur = NULL;
gi2c->abort_done = false;
geni_se_abort_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
do {
time_left = wait_for_completion_timeout(&gi2c->done, time_left);
} while (!gi2c->abort_done && time_left);
time_left = wait_for_completion_timeout(&gi2c->abort_done, time_left);
if (!time_left)
dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
}
static void geni_i2c_cancel_xfer(struct geni_i2c_dev *gi2c)
{
unsigned long time_left = msecs_to_jiffies(CANCEL_TIMEOUT);
unsigned long flags;
reinit_completion(&gi2c->cancel_done);
spin_lock_irqsave(&gi2c->lock, flags);
if (!gi2c->err)
geni_i2c_err(gi2c, GENI_TIMEOUT);
gi2c->cur = NULL;
geni_se_cancel_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
time_left = wait_for_completion_timeout(&gi2c->cancel_done, time_left);
if (!time_left) {
dev_err(gi2c->se.dev, "Timeout cancel_m_cmd\n");
geni_i2c_abort_xfer(gi2c);
}
}
static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
{
u32 val;
unsigned long time_left = RST_TIMEOUT;
reinit_completion(&gi2c->rx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
do {
time_left = wait_for_completion_timeout(&gi2c->done, time_left);
val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
} while (!(val & RX_RESET_DONE) && time_left);
if (!(val & RX_RESET_DONE))
time_left = wait_for_completion_timeout(&gi2c->rx_reset_done, time_left);
if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
}
static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
{
u32 val;
unsigned long time_left = RST_TIMEOUT;
reinit_completion(&gi2c->tx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
do {
time_left = wait_for_completion_timeout(&gi2c->done, time_left);
val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
} while (!(val & TX_RESET_DONE) && time_left);
if (!(val & TX_RESET_DONE))
time_left = wait_for_completion_timeout(&gi2c->tx_reset_done, time_left);
if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
}
@ -418,7 +464,7 @@ static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c,
{
gi2c->cur_rd = 0;
if (gi2c->dma_buf) {
if (gi2c->err)
if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)
geni_i2c_rx_fsm_rst(gi2c);
geni_se_rx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
@ -430,7 +476,7 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
{
gi2c->cur_wr = 0;
if (gi2c->dma_buf) {
if (gi2c->err)
if (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err)
geni_i2c_tx_fsm_rst(gi2c);
geni_se_tx_dma_unprep(&gi2c->se, gi2c->dma_addr, gi2c->xfer_len);
i2c_put_dma_safe_msg_buf(gi2c->dma_buf, cur, !gi2c->err);
@ -468,8 +514,8 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err))
geni_i2c_cancel_xfer(gi2c);
geni_i2c_rx_msg_cleanup(gi2c, cur);
@ -510,8 +556,8 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
cur = gi2c->cur;
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
if (!time_left || (gi2c->err && gi2c->err != gi2c_log[ADDR_NACK].err))
geni_i2c_cancel_xfer(gi2c);
geni_i2c_tx_msg_cleanup(gi2c, cur);
@ -784,6 +830,10 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
peripheral.set_config = 1;
peripheral.multi_msg = false;
trace_geni_i2c_bus_setup(gi2c->se.dev, gi2c->clk_freq_out,
itr->clk_div, itr->t_high_cnt,
itr->t_low_cnt, itr->t_cycle_cnt);
gi2c->num_msgs = num;
gi2c->is_tx_multi_desc_xfer = false;
@ -822,6 +872,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
for (i = 0; i < num; i++) {
gi2c->cur = &msgs[i];
gi2c->err = 0;
reinit_completion(&gi2c->done);
dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
peripheral.stretch = 0;
@ -891,6 +942,8 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
gi2c->cur = &msgs[i];
gi2c->err = 0;
reinit_completion(&gi2c->done);
if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else
@ -910,8 +963,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
int ret;
gi2c->err = 0;
reinit_completion(&gi2c->done);
ret = pm_runtime_get_sync(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
@ -921,7 +972,9 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
return ret;
}
qcom_geni_i2c_conf(gi2c);
ret = gi2c->dev_data->set_rate(&gi2c->se, gi2c->clk_freq_out);
if (ret)
return ret;
if (gi2c->gpi_mode)
ret = geni_i2c_gpi_xfer(gi2c, msgs, num);
@ -944,15 +997,6 @@ static const struct i2c_algorithm geni_i2c_algo = {
.functionality = geni_i2c_func,
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id geni_i2c_acpi_match[] = {
{ "QCOM0220"},
{ "QCOM0411" },
{ }
};
MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
#endif
static void release_gpi_dma(struct geni_i2c_dev *gi2c)
{
if (gi2c->rx_c)
@ -990,13 +1034,95 @@ static int setup_gpi_dma(struct geni_i2c_dev *gi2c)
return ret;
}
static int geni_i2c_init(struct geni_i2c_dev *gi2c)
{
u32 proto, tx_depth;
bool fifo_disable;
int ret;
ret = pm_runtime_resume_and_get(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "error turning on device :%d\n", ret);
return ret;
}
proto = geni_se_read_proto(&gi2c->se);
if (proto == GENI_SE_INVALID_PROTO) {
ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
if (ret) {
dev_err_probe(gi2c->se.dev, ret, "i2c firmware load failed ret: %d\n", ret);
goto err;
}
} else if (proto != GENI_SE_I2C) {
ret = dev_err_probe(gi2c->se.dev, -ENXIO, "Invalid proto %d\n", proto);
goto err;
}
if (gi2c->dev_data->no_dma_support) {
fifo_disable = false;
gi2c->no_dma = true;
} else {
fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
}
if (fifo_disable) {
/* FIFO is disabled, so we can only use GPI DMA */
gi2c->gpi_mode = true;
ret = setup_gpi_dma(gi2c);
if (ret)
goto err;
dev_dbg(gi2c->se.dev, "Using GPI DMA mode for I2C\n");
} else {
gi2c->gpi_mode = false;
tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
/* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
if (!tx_depth && gi2c->se.core_clk)
tx_depth = gi2c->dev_data->tx_fifo_depth;
if (!tx_depth) {
ret = dev_err_probe(gi2c->se.dev, -EINVAL,
"Invalid TX FIFO depth\n");
goto err;
}
gi2c->tx_wm = tx_depth - 1;
geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
PACKING_BYTES_PW, true, true, true);
dev_dbg(gi2c->se.dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
}
err:
pm_runtime_put(gi2c->se.dev);
return ret;
}
static int geni_i2c_resources_init(struct geni_se *se)
{
struct geni_i2c_dev *gi2c = dev_get_drvdata(se->dev);
int ret;
ret = geni_se_resources_init(&gi2c->se);
if (ret)
return ret;
ret = geni_i2c_clk_map_idx(gi2c);
if (ret)
return dev_err_probe(gi2c->se.dev, ret, "Invalid clk frequency %d Hz\n",
gi2c->clk_freq_out);
return geni_icc_set_bw_ab(&gi2c->se, GENI_DEFAULT_BW, GENI_DEFAULT_BW,
Bps_to_icc(gi2c->clk_freq_out));
}
static int geni_i2c_probe(struct platform_device *pdev)
{
struct geni_i2c_dev *gi2c;
u32 proto, tx_depth, fifo_disable;
int ret;
struct device *dev = &pdev->dev;
const struct geni_i2c_desc *desc = NULL;
gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL);
if (!gi2c)
@ -1008,17 +1134,9 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (IS_ERR(gi2c->se.base))
return PTR_ERR(gi2c->se.base);
desc = device_get_match_data(&pdev->dev);
if (desc && desc->has_core_clk) {
gi2c->core_clk = devm_clk_get(dev, "core");
if (IS_ERR(gi2c->core_clk))
return PTR_ERR(gi2c->core_clk);
}
gi2c->se.clk = devm_clk_get(dev, "se");
if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev))
return PTR_ERR(gi2c->se.clk);
gi2c->dev_data = device_get_match_data(&pdev->dev);
if (!gi2c->dev_data)
return -EINVAL;
ret = device_property_read_u32(dev, "clock-frequency",
&gi2c->clk_freq_out);
@ -1034,16 +1152,19 @@ static int geni_i2c_probe(struct platform_device *pdev)
if (gi2c->irq < 0)
return gi2c->irq;
ret = geni_i2c_clk_map_idx(gi2c);
if (ret)
return dev_err_probe(dev, ret, "Invalid clk frequency %d Hz\n",
gi2c->clk_freq_out);
gi2c->adap.algo = &geni_i2c_algo;
init_completion(&gi2c->done);
init_completion(&gi2c->abort_done);
init_completion(&gi2c->cancel_done);
init_completion(&gi2c->tx_reset_done);
init_completion(&gi2c->rx_reset_done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
ret = gi2c->dev_data->resources_init(&gi2c->se);
if (ret)
return ret;
/* Keep interrupts disabled initially to allow for low-power modes */
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
dev_name(dev), gi2c);
@ -1056,119 +1177,25 @@ static int geni_i2c_probe(struct platform_device *pdev)
gi2c->adap.dev.of_node = dev->of_node;
strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory");
if (ret)
return ret;
/*
* Set the bus quota for core and cpu to a reasonable value for
* register access.
* Set quota for DDR based on bus speed.
*/
gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW;
gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
if (!desc || desc->icc_ddr)
gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out);
pm_runtime_set_suspended(dev);
pm_runtime_set_autosuspend_delay(dev, I2C_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
ret = geni_icc_set_bw(&gi2c->se);
ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
ret = clk_prepare_enable(gi2c->core_clk);
if (ret)
ret = geni_i2c_init(gi2c);
if (ret < 0)
return ret;
ret = geni_se_resources_on(&gi2c->se);
if (ret) {
dev_err_probe(dev, ret, "Error turning on resources\n");
goto err_clk;
}
proto = geni_se_read_proto(&gi2c->se);
if (proto == GENI_SE_INVALID_PROTO) {
ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C);
if (ret) {
dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret);
goto err_resources;
}
} else if (proto != GENI_SE_I2C) {
ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto);
goto err_resources;
}
if (desc && desc->no_dma_support) {
fifo_disable = false;
gi2c->no_dma = true;
} else {
fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE;
}
if (fifo_disable) {
/* FIFO is disabled, so we can only use GPI DMA */
gi2c->gpi_mode = true;
ret = setup_gpi_dma(gi2c);
if (ret)
goto err_resources;
dev_dbg(dev, "Using GPI DMA mode for I2C\n");
} else {
gi2c->gpi_mode = false;
tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
/* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */
if (!tx_depth && desc)
tx_depth = desc->tx_fifo_depth;
if (!tx_depth) {
ret = dev_err_probe(dev, -EINVAL,
"Invalid TX FIFO depth\n");
goto err_resources;
}
gi2c->tx_wm = tx_depth - 1;
geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
geni_se_config_packing(&gi2c->se, BITS_PER_BYTE,
PACKING_BYTES_PW, true, true, true);
dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
}
clk_disable_unprepare(gi2c->core_clk);
ret = geni_se_resources_off(&gi2c->se);
if (ret) {
dev_err_probe(dev, ret, "Error turning off resources\n");
goto err_dma;
}
ret = geni_icc_disable(&gi2c->se);
if (ret)
goto err_dma;
pm_runtime_set_suspended(gi2c->se.dev);
pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
pm_runtime_use_autosuspend(gi2c->se.dev);
pm_runtime_enable(gi2c->se.dev);
ret = i2c_add_adapter(&gi2c->adap);
if (ret) {
dev_err_probe(dev, ret, "Error adding i2c adapter\n");
pm_runtime_disable(gi2c->se.dev);
goto err_dma;
}
if (ret)
return dev_err_probe(dev, ret, "Error adding i2c adapter\n");
dev_dbg(dev, "Geni-I2C adaptor successfully added\n");
return ret;
err_resources:
geni_se_resources_off(&gi2c->se);
err_clk:
clk_disable_unprepare(gi2c->core_clk);
return ret;
err_dma:
release_gpi_dma(gi2c);
return ret;
return 0;
}
static void geni_i2c_remove(struct platform_device *pdev)
@ -1177,7 +1204,6 @@ static void geni_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&gi2c->adap);
release_gpi_dma(gi2c);
pm_runtime_disable(gi2c->se.dev);
}
static void geni_i2c_shutdown(struct platform_device *pdev)
@ -1190,48 +1216,36 @@ static void geni_i2c_shutdown(struct platform_device *pdev)
static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
{
int ret;
int ret = 0;
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
disable_irq(gi2c->irq);
ret = geni_se_resources_off(&gi2c->se);
if (ret) {
enable_irq(gi2c->irq);
return ret;
if (gi2c->dev_data->power_off) {
ret = gi2c->dev_data->power_off(&gi2c->se);
if (ret) {
enable_irq(gi2c->irq);
return ret;
}
}
clk_disable_unprepare(gi2c->core_clk);
return geni_icc_disable(&gi2c->se);
return 0;
}
static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
{
int ret;
int ret = 0;
struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
ret = geni_icc_enable(&gi2c->se);
if (ret)
return ret;
ret = clk_prepare_enable(gi2c->core_clk);
if (ret)
goto out_icc_disable;
ret = geni_se_resources_on(&gi2c->se);
if (ret)
goto out_clk_disable;
if (gi2c->dev_data->power_on) {
ret = gi2c->dev_data->power_on(&gi2c->se);
if (ret)
return ret;
}
enable_irq(gi2c->irq);
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)
@ -1267,16 +1281,40 @@ static const struct dev_pm_ops geni_i2c_pm_ops = {
NULL)
};
static const struct geni_i2c_desc i2c_master_hub = {
.has_core_clk = true,
.icc_ddr = NULL,
.no_dma_support = true,
.tx_fifo_depth = 16,
static const struct geni_i2c_desc geni_i2c = {
.resources_init = geni_i2c_resources_init,
.set_rate = qcom_geni_i2c_conf,
.power_on = geni_se_resources_activate,
.power_off = geni_se_resources_deactivate,
};
static const struct geni_i2c_desc i2c_master_hub = {
.no_dma_support = true,
.tx_fifo_depth = 16,
.resources_init = geni_i2c_resources_init,
.set_rate = qcom_geni_i2c_conf,
.power_on = geni_se_resources_activate,
.power_off = geni_se_resources_deactivate,
};
static const struct geni_i2c_desc sa8255p_geni_i2c = {
.resources_init = geni_se_domain_attach,
.set_rate = geni_se_set_perf_opp,
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id geni_i2c_acpi_match[] = {
{ "QCOM0220", (kernel_ulong_t)&geni_i2c},
{ "QCOM0411", (kernel_ulong_t)&geni_i2c},
{ }
};
MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match);
#endif
static const struct of_device_id geni_i2c_dt_match[] = {
{ .compatible = "qcom,geni-i2c" },
{ .compatible = "qcom,geni-i2c", .data = &geni_i2c },
{ .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub },
{ .compatible = "qcom,sa8255p-geni-i2c", .data = &sa8255p_geni_i2c },
{}
};
MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);

View File

@ -1657,10 +1657,21 @@ static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
static int qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
clk_prepare_enable(qup->clk);
clk_prepare_enable(qup->pclk);
int ret;
ret = clk_prepare_enable(qup->clk);
if (ret)
return ret;
ret = clk_prepare_enable(qup->pclk);
if (ret) {
clk_disable_unprepare(qup->clk);
return ret;
}
return 0;
}
static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
@ -1823,7 +1834,9 @@ static int qup_i2c_probe(struct platform_device *pdev)
ret = PTR_ERR(qup->pclk);
goto fail_dma;
}
qup_i2c_enable_clocks(qup);
ret = qup_i2c_enable_clocks(qup);
if (ret)
goto fail_dma;
src_clk_freq = clk_get_rate(qup->clk);
}
qup->src_clk_freq = src_clk_freq;
@ -1975,8 +1988,7 @@ static int qup_i2c_pm_resume_runtime(struct device *device)
struct qup_i2c_dev *qup = dev_get_drvdata(device);
dev_dbg(device, "pm_runtime: resuming...\n");
qup_i2c_enable_clocks(qup);
return 0;
return qup_i2c_enable_clocks(qup);
}
static int qup_i2c_suspend(struct device *device)
@ -1988,7 +2000,12 @@ static int qup_i2c_suspend(struct device *device)
static int qup_i2c_resume(struct device *device)
{
qup_i2c_pm_resume_runtime(device);
int ret;
ret = qup_i2c_pm_resume_runtime(device);
if (ret)
return ret;
pm_request_autosuspend(device);
return 0;
}

View File

@ -137,6 +137,7 @@ enum rcar_i2c_type {
I2C_RCAR_GEN2,
I2C_RCAR_GEN3,
I2C_RCAR_GEN4,
I2C_RCAR_GEN5,
};
struct rcar_i2c_priv {
@ -900,8 +901,12 @@ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
if (ret)
return ret;
return read_poll_timeout_atomic(reset_control_status, ret, ret == 0, 1,
100, false, priv->rstc);
/* SCMI based resets don't need to poll for success */
if (priv->devtype < I2C_RCAR_GEN5)
return read_poll_timeout_atomic(reset_control_status, ret, ret == 0,
1, 100, false, priv->rstc);
return 0;
}
static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
@ -1111,6 +1116,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 },
{ .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN4 },
{ .compatible = "renesas,rcar-gen5-i2c", .data = (void *)I2C_RCAR_GEN5 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@ -1194,9 +1200,15 @@ static int rcar_i2c_probe(struct platform_device *pdev)
goto out_pm_put;
}
ret = reset_control_status(priv->rstc);
if (ret < 0)
goto out_pm_put;
/*
* Gen5+ uses SCMI based reset which cannot report status.
* Firmware has to ensure proper reset
*/
if (priv->devtype < I2C_RCAR_GEN5) {
ret = reset_control_status(priv->rstc);
if (ret < 0)
goto out_pm_put;
}
/* hard reset disturbs HostNotify local target, so disable it */
priv->flags &= ~ID_P_HOST_NOTIFY;

View File

@ -163,9 +163,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
i2c_acpi_fill_info, lookup);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info->addr)
if (!info->addr)
return -EINVAL;
return 0;
@ -371,6 +374,7 @@ static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = {
{ "DLL0945", 0 },
{ "ELAN0678", 0 },
{ "ELAN06FA", 0 },
{ "ELAN1300", 0 },
{}
};

View File

@ -446,7 +446,8 @@ static int i2c_init_recovery(struct i2c_adapter *adap)
bri->set_scl = set_scl_gpio_value;
if (bri->sda_gpiod) {
bri->get_sda = get_sda_gpio_value;
if (gpiod_get_direction(bri->sda_gpiod) == GPIO_LINE_DIRECTION_OUT)
if (gpiod_get_direction(bri->sda_gpiod) == GPIO_LINE_DIRECTION_OUT ||
gpiod_is_single_ended(bri->sda_gpiod))
bri->set_sda = set_sda_gpio_value;
}
} else if (bri->recover_bus == i2c_generic_scl_recovery) {

View File

@ -34,6 +34,7 @@ struct i2c_algo_bit_data {
maximum 50 us for SMBus */
int timeout; /* in jiffies */
bool can_do_atomic; /* callbacks don't sleep, we can be atomic */
bool skip_bit_test; /* override bit_test module parameter */
};
int i2c_bit_add_bus(struct i2c_adapter *);

View File

@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM qcom_geni_i2c
#if !defined(_TRACE_QCOM_GENI_I2C_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_QCOM_GENI_I2C_H
#include <linux/tracepoint.h>
TRACE_EVENT(geni_i2c_bus_setup,
TP_PROTO(struct device *dev, u32 clk_freq, u8 clk_div,
u8 t_high_cnt, u8 t_low_cnt, u8 t_cycle_cnt),
TP_ARGS(dev, clk_freq, clk_div, t_high_cnt, t_low_cnt, t_cycle_cnt),
TP_STRUCT__entry(__string(name, dev_name(dev))
__field(u32, clk_freq)
__field(u8, clk_div)
__field(u8, t_high_cnt)
__field(u8, t_low_cnt)
__field(u8, t_cycle_cnt)
),
TP_fast_assign(__assign_str(name);
__entry->clk_freq = clk_freq;
__entry->clk_div = clk_div;
__entry->t_high_cnt = t_high_cnt;
__entry->t_low_cnt = t_low_cnt;
__entry->t_cycle_cnt = t_cycle_cnt;
),
TP_printk("%s: clk_freq=%u clk_div=%u t_high=%u t_low=%u t_cycle=%u",
__get_str(name), __entry->clk_freq, __entry->clk_div,
__entry->t_high_cnt, __entry->t_low_cnt,
__entry->t_cycle_cnt)
);
TRACE_EVENT(geni_i2c_irq,
TP_PROTO(struct device *dev, u32 m_stat, u32 rx_st,
u32 dm_tx_st, u32 dm_rx_st),
TP_ARGS(dev, m_stat, rx_st, dm_tx_st, dm_rx_st),
TP_STRUCT__entry(__string(name, dev_name(dev))
__field(u32, m_stat)
__field(u32, rx_st)
__field(u32, dm_tx_st)
__field(u32, dm_rx_st)
),
TP_fast_assign(__assign_str(name);
__entry->m_stat = m_stat;
__entry->rx_st = rx_st;
__entry->dm_tx_st = dm_tx_st;
__entry->dm_rx_st = dm_rx_st;
),
TP_printk("%s: m_stat=0x%08x rx_st=0x%08x dm_tx=0x%08x dm_rx=0x%08x",
__get_str(name), __entry->m_stat, __entry->rx_st,
__entry->dm_tx_st, __entry->dm_rx_st)
);
TRACE_EVENT(geni_i2c_err,
TP_PROTO(struct device *dev, int err, const char *msg),
TP_ARGS(dev, err, msg),
TP_STRUCT__entry(__string(name, dev_name(dev))
__field(int, err)
__string(msg, msg)
),
TP_fast_assign(__assign_str(name);
__entry->err = err;
__assign_str(msg);
),
TP_printk("%s: err=%d msg=%s",
__get_str(name), __entry->err, __get_str(msg))
);
#endif /* _TRACE_QCOM_GENI_I2C_H */
/* This part must be outside protection */
#include <trace/define_trace.h>