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

Pull more i2c updates from Andi Shyti:
 "Cleanups:
   - generic cleanups in qcom, qcom-cci and pxa, plus core cleanups in
     algo-bit and atr

  Fixes:
   - davinci: clean up cpufreq notifier on probe failure
   - imx-lpi2c: suspend the adapter while hardware is powered down
   - ls2x-v2: return IRQ_HANDLED after servicing error interrupts
   - stm32f7: fix timing calculation accuracy

  DT bindings:
   - microchip: permit resets
   - i2c-mux-pinctrl: update maintainer entry
   - i2c-mux-reg: convert bindings to DT schema"

* tag 'i2c-7.2-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux:
  i2c: pxa: Use named initializers for the platform_device_id array
  i2c: imx-lpi2c: mark I2C adapter when hardware is powered down
  i2c: stm32f7: truncate clock period instead of rounding it
  dt-bindings: i2c: microchip,corei2c: permit resets
  i2c: qcom: Unify user-visible "Qualcomm" name
  i2c: ls2x-v2: return IRQ_HANDLED after servicing an error
  i2c: atr: annotate i2c_atr_adap_desc->aliases with __counted_by_ptr
  i2c: algo: bit: use str_plural helper in bit_xfer
  dt-bindings: i2c: i2c-mux-pinctrl: change maintainer
  dt-bindings: i2c: convert i2c-mux-reg to DT schema
  i2c: davinci: Unregister cpufreq notifier on probe failure
  i2c: qcom-cci: Remove overcautious disable_irq() calls
  i2c: qcom-cci: Move cci_init() under cci_reset() function
  i2c: qcom-cci: Do not check return value of cci_init()
This commit is contained in:
Linus Torvalds
2026-06-22 09:30:31 -07:00
13 changed files with 151 additions and 117 deletions

View File

@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Pinctrl-based I2C Bus Mux
maintainers:
- Wolfram Sang <wsa@kernel.org>
- Thierry Reding <thierry.reding@kernel.org>
description: |
This binding describes an I2C bus multiplexer that uses pin multiplexing to route the I2C

View File

@@ -1,74 +0,0 @@
Register-based I2C Bus Mux
This binding describes an I2C bus multiplexer that uses a single register
to route the I2C signals.
Required properties:
- compatible: i2c-mux-reg
- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
port is connected to.
* Standard I2C mux properties. See i2c-mux.yaml in this directory.
* I2C child bus nodes. See i2c-mux.yaml in this directory.
Optional properties:
- reg: this pair of <offset size> specifies the register to control the mux.
The <offset size> depends on its parent node. It can be any memory-mapped
address. The size must be either 1, 2, or 4 bytes. If reg is omitted, the
resource of this device will be used.
- little-endian: The existence indicates the register is in little endian.
- big-endian: The existence indicates the register is in big endian.
If both little-endian and big-endian are omitted, the endianness of the
CPU will be used.
- write-only: The existence indicates the register is write-only.
- idle-state: value to set the muxer to when idle. When no value is
given, it defaults to the last value used.
Whenever an access is made to a device on a child bus, the value set
in the relevant node's reg property will be output to the register.
If an idle state is defined, using the idle-state (optional) property,
whenever an access is not being made to a device on a child bus, the
register will be set according to the idle value.
If an idle state is not defined, the most recently used value will be
left programmed into the register.
Example of a mux on PCIe card, the host is a powerpc SoC (big endian):
i2c-mux {
/* the <offset size> depends on the address translation
* of the parent device. If omitted, device resource
* will be used instead. The size is to determine
* whether iowrite32, iowrite16, or iowrite8 will be used.
*/
reg = <0x6028 0x4>;
little-endian; /* little endian register on PCIe */
compatible = "i2c-mux-reg";
#address-cells = <1>;
#size-cells = <0>;
i2c-parent = <&i2c1>;
i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
si5338: clock-generator@70 {
compatible = "silabs,si5338";
reg = <0x70>;
/* other stuff */
};
};
i2c@1 {
/* data is written using iowrite32 */
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
si5338: clock-generator@70 {
compatible = "silabs,si5338";
reg = <0x70>;
/* other stuff */
};
};
};

View File

@@ -0,0 +1,92 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/i2c-mux-reg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Register-based I2C Bus Mux
maintainers:
- Peter Rosin <peda@axentia.se>
description: |
This binding describes an I2C bus multiplexer that uses a single
memory-mapped register to route the I2C signals.
Whenever an access is made to a device on a child bus, the value
set in the relevant node's reg property is output to the register.
If an idle state is defined via the idle-state property, the
register is set to that value whenever no access is being made.
Otherwise the most recently used value is left programmed.
allOf:
- $ref: /schemas/i2c/i2c-mux.yaml#
properties:
compatible:
const: i2c-mux-reg
reg:
maxItems: 1
description: |
Offset and size of the register that selects the active child
bus, relative to the parent node's address space. The size
determines the access width and must be 1, 2, or 4 bytes. If
omitted, the platform device's own memory resource is used
instead.
i2c-parent:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Phandle of the I2C bus that this multiplexer's master-side port
is connected to.
little-endian:
type: boolean
description: Register is accessed in little-endian byte order.
big-endian:
type: boolean
description: Register is accessed in big-endian byte order.
write-only:
type: boolean
description:
Register is write-only; the driver must not read back the
current selection.
idle-state:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Value to write to the register when no child bus is selected.
required:
- compatible
- i2c-parent
unevaluatedProperties: false
examples:
- |
i2c-mux@6028 {
compatible = "i2c-mux-reg";
reg = <0x6028 0x4>;
little-endian;
#address-cells = <1>;
#size-cells = <0>;
i2c-parent = <&i2c1>;
i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
};
i2c@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
};
...

View File

@@ -37,6 +37,9 @@ properties:
modes are supported, possible values are 100000 and 400000.
enum: [100000, 400000]
resets:
maxItems: 1
required:
- compatible
- reg

View File

@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/string_choices.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -562,7 +563,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
ret, ret == 1 ? "" : "s");
ret, str_plural(ret));
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;
@@ -573,7 +574,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
ret, ret == 1 ? "" : "s");
ret, str_plural(ret));
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EIO;

View File

@@ -1058,7 +1058,7 @@ config I2C_QCOM_CCI
will be called i2c-qcom-cci.
config I2C_QCOM_GENI
tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
tristate "Qualcomm GENI based I2C controller"
depends on ARCH_QCOM || COMPILE_TEST
depends on QCOM_GENI_SE
help

View File

@@ -818,12 +818,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
if (r)
goto err_unuse_clocks;
goto err_cpufreq;
pm_runtime_put_autosuspend(dev->dev);
return 0;
err_cpufreq:
i2c_davinci_cpufreq_deregister(dev);
err_unuse_clocks:
pm_runtime_dont_use_autosuspend(dev->dev);
pm_runtime_put_sync(dev->dev);

View File

@@ -1646,7 +1646,18 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
static int __maybe_unused lpi2c_suspend_noirq(struct device *dev)
{
return pm_runtime_force_suspend(dev);
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
int ret;
i2c_mark_adapter_suspended(&lpi2c_imx->adapter);
ret = pm_runtime_force_suspend(dev);
if (ret) {
i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
return ret;
}
return 0;
}
static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
@@ -1666,6 +1677,8 @@ static int __maybe_unused lpi2c_resume_noirq(struct device *dev)
if (lpi2c_imx->target)
lpi2c_imx_target_init(lpi2c_imx);
i2c_mark_adapter_resumed(&lpi2c_imx->adapter);
return 0;
}

View File

@@ -304,7 +304,7 @@ static irqreturn_t loongson2_i2c_isr_event(int irq, void *data)
regmap_read(priv->regmap, LOONGSON2_I2C_SR1, &status);
if (status & LOONGSON2_I2C_SR1_ITERREN_MASK) {
loongson2_i2c_isr_error(status, data);
return IRQ_NONE;
return IRQ_HANDLED;
}
regmap_read(priv->regmap, LOONGSON2_I2C_CR2, &cr2);

View File

@@ -214,11 +214,11 @@ static const struct of_device_id i2c_pxa_dt_ids[] = {
MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
static const struct platform_device_id i2c_pxa_id_table[] = {
{ "pxa2xx-i2c", REGS_PXA2XX },
{ "pxa3xx-pwri2c", REGS_PXA3XX },
{ "ce4100-i2c", REGS_CE4100 },
{ "pxa910-i2c", REGS_PXA910 },
{ "armada-3700-i2c", REGS_A3700 },
{ .name = "pxa2xx-i2c", .driver_data = REGS_PXA2XX },
{ .name = "pxa3xx-pwri2c", .driver_data = REGS_PXA3XX },
{ .name = "ce4100-i2c", .driver_data = REGS_CE4100 },
{ .name = "pxa910-i2c", .driver_data = REGS_PXA910 },
{ .name = "armada-3700-i2c", .driver_data = REGS_A3700 },
{ }
};
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);

View File

@@ -225,25 +225,7 @@ static int cci_halt(struct cci *cci, u8 master_num)
return 0;
}
static int cci_reset(struct cci *cci)
{
/*
* we reset the whole controller, here and for implicity use
* master[0].xxx for waiting on it.
*/
reinit_completion(&cci->master[0].irq_complete);
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
CCI_TIMEOUT)) {
dev_err(cci->dev, "CCI reset timeout\n");
return -ETIMEDOUT;
}
return 0;
}
static int cci_init(struct cci *cci)
static void cci_init(struct cci *cci)
{
u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE |
CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT |
@@ -284,6 +266,24 @@ static int cci_init(struct cci *cci)
val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp;
writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i));
}
}
static int cci_reset(struct cci *cci)
{
/*
* we reset the whole controller, here and for implicity use
* master[0].xxx for waiting on it.
*/
reinit_completion(&cci->master[0].irq_complete);
writel(CCI_RESET_CMD_MASK, cci->base + CCI_RESET_CMD);
if (!wait_for_completion_timeout(&cci->master[0].irq_complete,
CCI_TIMEOUT)) {
dev_err(cci->dev, "CCI reset timeout\n");
return -ETIMEDOUT;
}
cci_init(cci);
return 0;
}
@@ -304,7 +304,6 @@ static int cci_run_queue(struct cci *cci, u8 master, u8 queue)
dev_err(cci->dev, "master %d queue %d timeout\n",
master, queue);
cci_reset(cci);
cci_init(cci);
return -ETIMEDOUT;
}
@@ -609,11 +608,7 @@ static int cci_probe(struct platform_device *pdev)
ret = cci_reset(cci);
if (ret < 0)
goto error;
ret = cci_init(cci);
if (ret < 0)
goto error;
goto disable_clocks;
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(dev);
@@ -643,8 +638,6 @@ static int cci_probe(struct platform_device *pdev)
of_node_put(cci->master[i].adap.dev.of_node);
}
}
error:
disable_irq(cci->irq);
disable_clocks:
cci_disable_clocks(cci);
@@ -664,7 +657,6 @@ static void cci_remove(struct platform_device *pdev)
}
}
disable_irq(cci->irq);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
}

View File

@@ -464,8 +464,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
{
struct stm32f7_i2c_spec *specs;
u32 p_prev = STM32F7_PRESC_MAX;
u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
setup->clock_src);
/*
* Truncate instead of rounding to closest: if the clock period is
* overestimated, the computed SCL timings will come out shorter on
* the wire, which can push the bus above the target rate and below
* the spec's tLOW/tHIGH minimums.
*/
u32 i2cclk = NSEC_PER_SEC / setup->clock_src;
u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,
setup->speed_freq);
u32 clk_error_prev = i2cbus;

View File

@@ -71,7 +71,7 @@ struct i2c_atr_adap_desc {
struct device *parent;
struct fwnode_handle *bus_handle;
size_t num_aliases;
u16 *aliases;
u16 *aliases __counted_by_ptr(num_aliases);
};
/**