From 1fa5beaedcab4e58ed755fc59ad05eda028d47ab Mon Sep 17 00:00:00 2001 From: domingo-nexthop Date: Mon, 4 May 2026 03:01:55 -0700 Subject: [PATCH 1/3] Include the i2c-xiic driver and add kernel patches Cherry-pick the i2c-xiic upstream patches and pull in the one PM-runtime devm helper they depend on, since v6.12.41 predates it. Patches added (in series order, each cherry-picked from upstream; v6.12.41 lacks 73db799bf5ef so 0006 is needed by 0010 and 0013): - 0006-PM-runtime-Add-new-devm-functions.patch (stable 69a837b75edc / mainline 73db799bf5ef, in v6.12.55+) Adds devm_pm_runtime_set_active_enabled() and devm_pm_runtime_get_noresume(). Link: https://lore.kernel.org/r/20250327195928.680771-3-csokas.bence@prolan.hu - 0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch Link: https://lore.kernel.org/r/20241210095242.1982770-2-manikanta.guntupalli@amd.com - 0008-i2c-xiic-Add-atomic-transfer-support.patch Link: https://lore.kernel.org/r/20241210095242.1982770-3-manikanta.guntupalli@amd.com - 0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch Link: https://lore.kernel.org/r/20250415183447.396277-10-e.zanda1@gmail.com - 0010-i2c-xiic-switch-to-devres-managed-APIs.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-1-b6c9ce4e4f3c@nexthop.ai - 0011-i2c-xiic-remove-duplicate-error-message.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-2-b6c9ce4e4f3c@nexthop.ai - 0012-i2c-xiic-switch-to-generic-device-property-accessors.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-3-b6c9ce4e4f3c@nexthop.ai - 0013-i2c-xiic-cosmetic-cleanup.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-4-b6c9ce4e4f3c@nexthop.ai - 0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-5-b6c9ce4e4f3c@nexthop.ai - 0015-i2c-xiic-use-numbered-adapter-registration.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-6-b6c9ce4e4f3c@nexthop.ai - 0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-7-b6c9ce4e4f3c@nexthop.ai Also enable CONFIG_I2C_XILINX=m in config.local/amd64/config.sonic so the driver is actually built into the SONIC kernel. Resolves [sonic-net/sonic-linux-kernel#543](https://github.com/sonic-net/sonic-linux-kernel/issues/543) Resolves [sonic-net/sonic-linux-kernel#544](https://github.com/sonic-net/sonic-linux-kernel/issues/544) Signed-off-by: domingo-nexthop --- config.local/amd64/config.sonic | 1 + ...06-PM-runtime-Add-new-devm-functions.patch | 114 +++++ ...e-xiic_i2c_runtime_suspend-and-xiic_.patch | 84 ++++ ...i2c-xiic-Add-atomic-transfer-support.patch | 464 ++++++++++++++++++ ...lace-dev_err-with-dev_err_probe-in-p.patch | 40 ++ ...c-xiic-switch-to-devres-managed-APIs.patch | 107 ++++ ...-xiic-remove-duplicate-error-message.patch | 38 ++ ...to-generic-device-property-accessors.patch | 100 ++++ .../0013-i2c-xiic-cosmetic-cleanup.patch | 92 ++++ ...c-use-resource-format-specifier-in-d.patch | 34 ++ ...ic-use-numbered-adapter-registration.patch | 45 ++ ...-input-clock-setup-on-non-OF-systems.patch | 42 ++ patches-sonic/series | 13 +- 13 files changed, 1173 insertions(+), 1 deletion(-) create mode 100644 patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch create mode 100644 patches-sonic/0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch create mode 100644 patches-sonic/0008-i2c-xiic-Add-atomic-transfer-support.patch create mode 100644 patches-sonic/0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch create mode 100644 patches-sonic/0010-i2c-xiic-switch-to-devres-managed-APIs.patch create mode 100644 patches-sonic/0011-i2c-xiic-remove-duplicate-error-message.patch create mode 100644 patches-sonic/0012-i2c-xiic-switch-to-generic-device-property-accessors.patch create mode 100644 patches-sonic/0013-i2c-xiic-cosmetic-cleanup.patch create mode 100644 patches-sonic/0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch create mode 100644 patches-sonic/0015-i2c-xiic-use-numbered-adapter-registration.patch create mode 100644 patches-sonic/0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch diff --git a/config.local/amd64/config.sonic b/config.local/amd64/config.sonic index 65eb60496..8ab62f716 100644 --- a/config.local/amd64/config.sonic +++ b/config.local/amd64/config.sonic @@ -166,6 +166,7 @@ CONFIG_SENSORS_INA3221=m CONFIG_RTC_DRV_DS1307=m CONFIG_SENSORS_TMP464=m # For Nexthop +CONFIG_I2C_XILINX=m CONFIG_PCI_STUB=y CONFIG_SENSORS_ADM1266=m CONFIG_SENSORS_TMP464=m diff --git a/patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch b/patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch new file mode 100644 index 000000000..fcd458066 --- /dev/null +++ b/patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch @@ -0,0 +1,114 @@ +From 69a837b75edcea8861ea3a851d10fd138e7f7406 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bence=20Cs=C3=B3k=C3=A1s?= +Date: Mon, 20 Oct 2025 09:02:38 -0400 +Subject: [PATCH] PM: runtime: Add new devm functions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit 73db799bf5efc5a04654bb3ff6c9bf63a0dfa473 ] + +Add `devm_pm_runtime_set_active_enabled()` and +`devm_pm_runtime_get_noresume()` for simplifying +common cases in drivers. + +Signed-off-by: Bence Csókás +Link: https://patch.msgid.link/20250327195928.680771-3-csokas.bence@prolan.hu +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 0792c1984a45 ("iio: imu: inv_icm42600: Simplify pm_runtime setup") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/power/runtime.c | 44 ++++++++++++++++++++++++++++++++++++ + include/linux/pm_runtime.h | 4 ++++ + 2 files changed, 48 insertions(+) + +diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c +index c7ec69597a95..d8aaa5b61628 100644 +--- a/drivers/base/power/runtime.c ++++ b/drivers/base/power/runtime.c +@@ -1554,6 +1554,32 @@ void pm_runtime_enable(struct device *dev) + } + EXPORT_SYMBOL_GPL(pm_runtime_enable); + ++static void pm_runtime_set_suspended_action(void *data) ++{ ++ pm_runtime_set_suspended(data); ++} ++ ++/** ++ * devm_pm_runtime_set_active_enabled - set_active version of devm_pm_runtime_enable. ++ * ++ * @dev: Device to handle. ++ */ ++int devm_pm_runtime_set_active_enabled(struct device *dev) ++{ ++ int err; ++ ++ err = pm_runtime_set_active(dev); ++ if (err) ++ return err; ++ ++ err = devm_add_action_or_reset(dev, pm_runtime_set_suspended_action, dev); ++ if (err) ++ return err; ++ ++ return devm_pm_runtime_enable(dev); ++} ++EXPORT_SYMBOL_GPL(devm_pm_runtime_set_active_enabled); ++ + static void pm_runtime_disable_action(void *data) + { + pm_runtime_dont_use_autosuspend(data); +@@ -1576,6 +1602,24 @@ int devm_pm_runtime_enable(struct device *dev) + } + EXPORT_SYMBOL_GPL(devm_pm_runtime_enable); + ++static void pm_runtime_put_noidle_action(void *data) ++{ ++ pm_runtime_put_noidle(data); ++} ++ ++/** ++ * devm_pm_runtime_get_noresume - devres-enabled version of pm_runtime_get_noresume. ++ * ++ * @dev: Device to handle. ++ */ ++int devm_pm_runtime_get_noresume(struct device *dev) ++{ ++ pm_runtime_get_noresume(dev); ++ ++ return devm_add_action_or_reset(dev, pm_runtime_put_noidle_action, dev); ++} ++EXPORT_SYMBOL_GPL(devm_pm_runtime_get_noresume); ++ + /** + * pm_runtime_forbid - Block runtime PM of a device. + * @dev: Device to handle. +diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h +index d0b29cd1fd20..142ab39a3b38 100644 +--- a/include/linux/pm_runtime.h ++++ b/include/linux/pm_runtime.h +@@ -94,7 +94,9 @@ extern void pm_runtime_new_link(struct device *dev); + extern void pm_runtime_drop_link(struct device_link *link); + extern void pm_runtime_release_supplier(struct device_link *link); + ++int devm_pm_runtime_set_active_enabled(struct device *dev); + extern int devm_pm_runtime_enable(struct device *dev); ++int devm_pm_runtime_get_noresume(struct device *dev); + + /** + * pm_suspend_ignore_children - Set runtime PM behavior regarding children. +@@ -278,7 +280,9 @@ static inline void __pm_runtime_disable(struct device *dev, bool c) {} + static inline void pm_runtime_allow(struct device *dev) {} + static inline void pm_runtime_forbid(struct device *dev) {} + ++static inline int devm_pm_runtime_set_active_enabled(struct device *dev) { return 0; } + static inline int devm_pm_runtime_enable(struct device *dev) { return 0; } ++static inline int devm_pm_runtime_get_noresume(struct device *dev) { return 0; } + + static inline void pm_suspend_ignore_children(struct device *dev, bool enable) {} + static inline void pm_runtime_get_noresume(struct device *dev) {} +-- +2.43.0 + diff --git a/patches-sonic/0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch b/patches-sonic/0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch new file mode 100644 index 000000000..a104a850e --- /dev/null +++ b/patches-sonic/0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch @@ -0,0 +1,84 @@ +From a085b9385bfbc6b6887a9fa21f3cd40bd3811b37 Mon Sep 17 00:00:00 2001 +From: Manikanta Guntupalli +Date: Tue, 10 Dec 2024 15:22:41 +0530 +Subject: [PATCH 07/22] i2c: xiic: Relocate xiic_i2c_runtime_suspend and + xiic_i2c_runtime_resume to facilitate atomic mode + +Relocate xiic_i2c_runtime_suspend and xiic_i2c_runtime_resume functions +to avoid prototype statements in atomic mode changes. + +Signed-off-by: Manikanta Guntupalli +Acked-by: Michal Simek +Link: https://lore.kernel.org/r/20241210095242.1982770-2-manikanta.guntupalli@amd.com +Signed-off-by: Andi Shyti +--- + drivers/i2c/busses/i2c-xiic.c | 46 +++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 1d68177241a6..2d26b6d0721b 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -238,6 +238,29 @@ static const struct timing_regs timing_reg_values[] = { + static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num); + static void __xiic_start_xfer(struct xiic_i2c *i2c); + ++static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) ++{ ++ struct xiic_i2c *i2c = dev_get_drvdata(dev); ++ ++ clk_disable(i2c->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev) ++{ ++ struct xiic_i2c *i2c = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_enable(i2c->clk); ++ if (ret) { ++ dev_err(dev, "Cannot enable clock.\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ + /* + * For the register read and write functions, a little-endian and big-endian + * version are necessary. Endianness is detected during the probe function. +@@ -1365,29 +1388,6 @@ static void xiic_i2c_remove(struct platform_device *pdev) + pm_runtime_dont_use_autosuspend(&pdev->dev); + } + +-static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) +-{ +- struct xiic_i2c *i2c = dev_get_drvdata(dev); +- +- clk_disable(i2c->clk); +- +- return 0; +-} +- +-static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev) +-{ +- struct xiic_i2c *i2c = dev_get_drvdata(dev); +- int ret; +- +- ret = clk_enable(i2c->clk); +- if (ret) { +- dev_err(dev, "Cannot enable clock.\n"); +- return ret; +- } +- +- return 0; +-} +- + static const struct dev_pm_ops xiic_dev_pm_ops = { + SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend, + xiic_i2c_runtime_resume, NULL) +-- +2.53.0 + diff --git a/patches-sonic/0008-i2c-xiic-Add-atomic-transfer-support.patch b/patches-sonic/0008-i2c-xiic-Add-atomic-transfer-support.patch new file mode 100644 index 000000000..d0526846d --- /dev/null +++ b/patches-sonic/0008-i2c-xiic-Add-atomic-transfer-support.patch @@ -0,0 +1,464 @@ +From d6daa038c128013607b5fae67bb4fb737b5009e2 Mon Sep 17 00:00:00 2001 +From: Manikanta Guntupalli +Date: Tue, 10 Dec 2024 15:22:42 +0530 +Subject: [PATCH 08/22] i2c: xiic: Add atomic transfer support + +Rework the read and write code paths in the driver to support operation +in atomic contexts. + +Similar changes have been implemented in other drivers, including: +commit 3a5ee18d2a32 ("i2c: imx: implement master_xfer_atomic callback") +commit 445094c8a9fb ("i2c: exynos5: add support for atomic transfers") +commit ede2299f7101 ("i2c: tegra: Support atomic transfers") +commit fe402bd09049 ("i2c: meson: implement the master_xfer_atomic +callback") + +Signed-off-by: Manikanta Guntupalli +Acked-by: Michal Simek +Link: https://lore.kernel.org/r/20241210095242.1982770-3-manikanta.guntupalli@amd.com +Signed-off-by: Andi Shyti +--- + drivers/i2c/busses/i2c-xiic.c | 239 +++++++++++++++++++++++++++++----- + 1 file changed, 206 insertions(+), 33 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 2d26b6d0721b..b142380ed251 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + + #define DRIVER_NAME "xiic-i2c" + #define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0) +@@ -74,6 +76,9 @@ enum i2c_scl_freq { + * @smbus_block_read: Flag to handle block read + * @input_clk: Input clock to I2C controller + * @i2c_clk: I2C SCL frequency ++ * @atomic: Mode of transfer ++ * @atomic_lock: Lock for atomic transfer mode ++ * @atomic_xfer_state: See STATE_ + */ + struct xiic_i2c { + struct device *dev; +@@ -96,6 +101,9 @@ struct xiic_i2c { + bool smbus_block_read; + unsigned long input_clk; + unsigned int i2c_clk; ++ bool atomic; ++ spinlock_t atomic_lock; /* Lock for atomic transfer mode */ ++ enum xilinx_i2c_state atomic_xfer_state; + }; + + struct xiic_version_data { +@@ -224,6 +232,8 @@ static const struct timing_regs timing_reg_values[] = { + #define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000)) + /* timeout waiting for the controller finish transfers */ + #define XIIC_XFER_TIMEOUT (msecs_to_jiffies(10000)) ++/* timeout waiting for the controller finish transfers in micro seconds */ ++#define XIIC_XFER_TIMEOUT_US 10000000 + + /* + * The following constant is used for the device global interrupt enable +@@ -238,7 +248,7 @@ static const struct timing_regs timing_reg_values[] = { + static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num); + static void __xiic_start_xfer(struct xiic_i2c *i2c); + +-static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) ++static int xiic_i2c_runtime_suspend(struct device *dev) + { + struct xiic_i2c *i2c = dev_get_drvdata(dev); + +@@ -247,7 +257,7 @@ static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) + return 0; + } + +-static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev) ++static int xiic_i2c_runtime_resume(struct device *dev) + { + struct xiic_i2c *i2c = dev_get_drvdata(dev); + int ret; +@@ -397,9 +407,10 @@ static int xiic_setclk(struct xiic_i2c *i2c) + unsigned int index = 0; + u32 reg_val; + +- dev_dbg(i2c->adap.dev.parent, +- "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n", +- __func__, i2c->input_clk, i2c->i2c_clk); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, ++ "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n", ++ __func__, i2c->input_clk, i2c->i2c_clk); + + /* If not specified in DT, do not configure in SW. Rely only on Vivado design */ + if (!i2c->i2c_clk || !i2c->input_clk) +@@ -490,7 +501,8 @@ static int xiic_reinit(struct xiic_i2c *i2c) + return ret; + + /* Enable interrupts */ +- xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); ++ if (!i2c->atomic) ++ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); + + xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK); + +@@ -572,11 +584,12 @@ static void xiic_read_rx(struct xiic_i2c *i2c) + + bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1; + +- dev_dbg(i2c->adap.dev.parent, +- "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n", +- __func__, bytes_in_fifo, xiic_rx_space(i2c), +- xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), +- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, ++ "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n", ++ __func__, bytes_in_fifo, xiic_rx_space(i2c), ++ xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), ++ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + + if (bytes_in_fifo > xiic_rx_space(i2c)) + bytes_in_fifo = xiic_rx_space(i2c); +@@ -635,6 +648,26 @@ static void xiic_read_rx(struct xiic_i2c *i2c) + } + } + ++static bool xiic_error_check(struct xiic_i2c *i2c) ++{ ++ bool status = false; ++ u32 pend, isr, ier; ++ ++ isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); ++ ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); ++ pend = isr & ier; ++ ++ if ((pend & XIIC_INTR_ARB_LOST_MASK) || ++ ((pend & XIIC_INTR_TX_ERROR_MASK) && ++ !(pend & XIIC_INTR_RX_FULL_MASK))) { ++ xiic_reinit(i2c); ++ status = true; ++ if (i2c->tx_msg || i2c->rx_msg) ++ i2c->atomic_xfer_state = STATE_ERROR; ++ } ++ return status; ++} ++ + static int xiic_tx_fifo_space(struct xiic_i2c *i2c) + { + /* return the actual space left in the FIFO */ +@@ -648,8 +681,9 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c) + + len = (len > fifo_space) ? fifo_space : len; + +- dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n", +- __func__, len, fifo_space); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n", ++ __func__, len, fifo_space); + + while (len--) { + u16 data = i2c->tx_msg->buf[i2c->tx_pos++]; +@@ -672,9 +706,13 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c) + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & + ~XIIC_CR_MSMS_MASK); + } +- dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); + } + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); ++ ++ if (i2c->atomic && xiic_error_check(i2c)) ++ return; + } + } + +@@ -877,22 +915,51 @@ static int xiic_wait_not_busy(struct xiic_i2c *i2c) + */ + err = xiic_bus_busy(i2c); + while (err && tries--) { +- msleep(1); ++ if (i2c->atomic) ++ udelay(1000); ++ else ++ usleep_range(1000, 1100); + err = xiic_bus_busy(i2c); + } + + return err; + } + ++static void xiic_recv_atomic(struct xiic_i2c *i2c) ++{ ++ while (xiic_rx_space(i2c)) { ++ if (xiic_getreg32(i2c, XIIC_IISR_OFFSET) & XIIC_INTR_RX_FULL_MASK) { ++ xiic_read_rx(i2c); ++ ++ /* Clear Rx full and Tx error interrupts. */ ++ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | ++ XIIC_INTR_TX_ERROR_MASK); ++ } ++ if (xiic_error_check(i2c)) ++ return; ++ } ++ ++ i2c->rx_msg = NULL; ++ xiic_irq_clr_en(i2c, XIIC_INTR_TX_ERROR_MASK); ++ ++ /* send next message if this wasn't the last. */ ++ if (i2c->nmsgs > 1) { ++ i2c->nmsgs--; ++ i2c->tx_msg++; ++ __xiic_start_xfer(i2c); ++ } ++} ++ + static void xiic_start_recv(struct xiic_i2c *i2c) + { + u16 rx_watermark; + u8 cr = 0, rfd_set = 0; + struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; + +- dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", +- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), +- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", ++ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), ++ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + + /* Disable Tx interrupts */ + xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK | XIIC_INTR_TX_EMPTY_MASK); +@@ -990,9 +1057,10 @@ static void xiic_start_recv(struct xiic_i2c *i2c) + XIIC_CR_MSMS_MASK) + & ~(XIIC_CR_DIR_IS_TX_MASK)); + } +- dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n", +- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), +- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n", ++ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), ++ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + } + + if (i2c->nmsgs == 1) +@@ -1002,10 +1070,55 @@ static void xiic_start_recv(struct xiic_i2c *i2c) + /* the message is tx:ed */ + i2c->tx_pos = msg->len; + ++ i2c->prev_msg_tx = false; ++ + /* Enable interrupts */ +- xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); ++ if (!i2c->atomic) ++ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); ++ else ++ xiic_recv_atomic(i2c); ++} + +- i2c->prev_msg_tx = false; ++static void xiic_send_rem_atomic(struct xiic_i2c *i2c) ++{ ++ while (xiic_tx_space(i2c)) { ++ if (xiic_tx_fifo_space(i2c)) { ++ u16 data; ++ ++ data = i2c->tx_msg->buf[i2c->tx_pos]; ++ i2c->tx_pos++; ++ if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) { ++ /* last message in transfer -> STOP */ ++ if (i2c->dynamic) { ++ data |= XIIC_TX_DYN_STOP_MASK; ++ } else { ++ u8 cr; ++ int status; ++ ++ /* Wait till FIFO is empty so STOP is sent last */ ++ status = xiic_wait_tx_empty(i2c); ++ if (status) ++ return; ++ ++ /* Write to CR to stop */ ++ cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); ++ xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ++ ~XIIC_CR_MSMS_MASK); ++ } ++ } ++ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); ++ } ++ if (xiic_error_check(i2c)) ++ return; ++ } ++ ++ if (i2c->nmsgs > 1) { ++ i2c->nmsgs--; ++ i2c->tx_msg++; ++ __xiic_start_xfer(i2c); ++ } else { ++ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); ++ } + } + + static void xiic_start_send(struct xiic_i2c *i2c) +@@ -1014,11 +1127,13 @@ static void xiic_start_send(struct xiic_i2c *i2c) + u16 data; + struct i2c_msg *msg = i2c->tx_msg; + +- dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", +- __func__, msg, msg->len); +- dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", +- __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), +- xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); ++ if (!i2c->atomic) { ++ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", ++ __func__, msg, msg->len); ++ dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", ++ __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), ++ xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); ++ } + + if (i2c->dynamic) { + /* write the address */ +@@ -1083,19 +1198,27 @@ static void xiic_start_send(struct xiic_i2c *i2c) + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_BNB_MASK); + } ++ + i2c->prev_msg_tx = true; ++ ++ if (i2c->atomic && !i2c->atomic_xfer_state) ++ xiic_send_rem_atomic(i2c); + } + + static void __xiic_start_xfer(struct xiic_i2c *i2c) + { + int fifo_space = xiic_tx_fifo_space(i2c); + +- dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n", +- __func__, i2c->tx_msg, fifo_space); ++ if (!i2c->atomic) ++ dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n", ++ __func__, i2c->tx_msg, fifo_space); + + if (!i2c->tx_msg) + return; + ++ if (i2c->atomic && xiic_error_check(i2c)) ++ return; ++ + i2c->rx_pos = 0; + i2c->tx_pos = 0; + i2c->state = STATE_START; +@@ -1112,7 +1235,10 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) + bool broken_read, max_read_len, smbus_blk_read; + int ret, count; + +- mutex_lock(&i2c->lock); ++ if (i2c->atomic) ++ spin_lock(&i2c->atomic_lock); ++ else ++ mutex_lock(&i2c->lock); + + if (i2c->tx_msg || i2c->rx_msg) { + dev_err(i2c->adap.dev.parent, +@@ -1121,6 +1247,8 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) + goto out; + } + ++ i2c->atomic_xfer_state = STATE_DONE; ++ + /* In single master mode bus can only be busy, when in use by this + * driver. If the register indicates bus being busy for some reason we + * should ignore it, since bus will never be released and i2c will be +@@ -1147,7 +1275,9 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) + i2c->tx_msg = msgs; + i2c->rx_msg = NULL; + i2c->nmsgs = num; +- init_completion(&i2c->completion); ++ ++ if (!i2c->atomic) ++ init_completion(&i2c->completion); + + /* Decide standard mode or Dynamic mode */ + i2c->dynamic = true; +@@ -1182,7 +1312,10 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) + __xiic_start_xfer(i2c); + + out: +- mutex_unlock(&i2c->lock); ++ if (i2c->atomic) ++ spin_unlock(&i2c->atomic_lock); ++ else ++ mutex_unlock(&i2c->lock); + + return ret; + } +@@ -1221,6 +1354,44 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) + return err; + } + ++static int xiic_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ++{ ++ struct xiic_i2c *i2c = i2c_get_adapdata(adap); ++ u32 status_reg; ++ int err; ++ ++ err = xiic_i2c_runtime_resume(i2c->dev); ++ if (err) ++ return err; ++ ++ i2c->atomic = true; ++ err = xiic_start_xfer(i2c, msgs, num); ++ if (err < 0) ++ return err; ++ ++ err = readl_poll_timeout_atomic(i2c->base + XIIC_SR_REG_OFFSET, ++ status_reg, !(status_reg & XIIC_SR_BUS_BUSY_MASK), ++ 1, XIIC_XFER_TIMEOUT_US); ++ ++ if (err) /* Timeout */ ++ err = -ETIMEDOUT; ++ ++ spin_lock(&i2c->atomic_lock); ++ if (err || i2c->state) { ++ i2c->tx_msg = NULL; ++ i2c->rx_msg = NULL; ++ i2c->nmsgs = 0; ++ } ++ ++ err = (i2c->atomic_xfer_state == STATE_DONE) ? num : -EIO; ++ spin_unlock(&i2c->atomic_lock); ++ ++ i2c->atomic = false; ++ xiic_i2c_runtime_suspend(i2c->dev); ++ ++ return err; ++} ++ + static u32 xiic_func(struct i2c_adapter *adap) + { + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +@@ -1228,6 +1399,7 @@ static u32 xiic_func(struct i2c_adapter *adap) + + static const struct i2c_algorithm xiic_algorithm = { + .master_xfer = xiic_xfer, ++ .master_xfer_atomic = xiic_xfer_atomic, + .functionality = xiic_func, + }; + +@@ -1291,6 +1463,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + DRIVER_NAME " %s", pdev->name); + + mutex_init(&i2c->lock); ++ spin_lock_init(&i2c->atomic_lock); + + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) +-- +2.53.0 + diff --git a/patches-sonic/0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch b/patches-sonic/0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch new file mode 100644 index 000000000..a0758adf8 --- /dev/null +++ b/patches-sonic/0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch @@ -0,0 +1,40 @@ +From 4806583e1e41dbd9c8061c7c6434c263daea00b0 Mon Sep 17 00:00:00 2001 +From: Enrico Zanda +Date: Tue, 15 Apr 2025 20:34:46 +0200 +Subject: [PATCH 09/22] i2c: i2c-xiic: Replace dev_err() with dev_err_probe() + in probe function + +This simplifies the code while improving log. + +Signed-off-by: Enrico Zanda +Link: https://lore.kernel.org/r/20250415183447.396277-10-e.zanda1@gmail.com +Signed-off-by: Andi Shyti +--- + drivers/i2c/busses/i2c-xiic.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index b142380ed251..072edc6c12da 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1489,7 +1489,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + pdev->name, i2c); + + if (ret < 0) { +- dev_err(&pdev->dev, "Cannot claim IRQ\n"); ++ dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n"); + goto err_pm_disable; + } + +@@ -1510,7 +1510,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + + ret = xiic_reinit(i2c); + if (ret < 0) { +- dev_err(&pdev->dev, "Cannot xiic_reinit\n"); ++ dev_err_probe(&pdev->dev, ret, "Cannot xiic_reinit\n"); + goto err_pm_disable; + } + +-- +2.53.0 + diff --git a/patches-sonic/0010-i2c-xiic-switch-to-devres-managed-APIs.patch b/patches-sonic/0010-i2c-xiic-switch-to-devres-managed-APIs.patch new file mode 100644 index 000000000..941e92ef3 --- /dev/null +++ b/patches-sonic/0010-i2c-xiic-switch-to-devres-managed-APIs.patch @@ -0,0 +1,107 @@ +From fb4beb7d83581052bc47a326fe8e78721ed2dc4c Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:16 +0000 +Subject: [PATCH 10/22] i2c: xiic: switch to devres managed APIs + +Simplify the error code paths by switching to devres managed helper +functions. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-1-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 30 ++++++++++++------------------ + 1 file changed, 12 insertions(+), 18 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 072edc6c12da..ea85fc396033 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1424,6 +1424,7 @@ MODULE_DEVICE_TABLE(of, xiic_of_match); + + static int xiic_i2c_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + struct xiic_i2c *i2c; + struct xiic_i2c_platform_data *pdata; + const struct of_device_id *match; +@@ -1462,7 +1463,10 @@ static int xiic_i2c_probe(struct platform_device *pdev) + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + DRIVER_NAME " %s", pdev->name); + +- mutex_init(&i2c->lock); ++ ret = devm_mutex_init(dev, &i2c->lock); ++ if (ret) ++ return ret; ++ + spin_lock_init(&i2c->atomic_lock); + + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); +@@ -1473,8 +1477,9 @@ static int xiic_i2c_probe(struct platform_device *pdev) + i2c->dev = &pdev->dev; + pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT); + pm_runtime_use_autosuspend(i2c->dev); +- pm_runtime_set_active(i2c->dev); +- pm_runtime_enable(i2c->dev); ++ ret = devm_pm_runtime_set_active_enabled(dev); ++ if (ret) ++ return ret; + + /* SCL frequency configuration */ + i2c->input_clk = clk_get_rate(i2c->clk); +@@ -1490,7 +1495,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + + if (ret < 0) { + dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n"); +- goto err_pm_disable; ++ return ret; + } + + i2c->singlemaster = +@@ -1509,16 +1514,14 @@ static int xiic_i2c_probe(struct platform_device *pdev) + i2c->endianness = BIG; + + ret = xiic_reinit(i2c); +- if (ret < 0) { +- dev_err_probe(&pdev->dev, ret, "Cannot xiic_reinit\n"); +- goto err_pm_disable; +- } ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot xiic_reinit\n"); + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + xiic_deinit(i2c); +- goto err_pm_disable; ++ return ret; + } + + if (pdata) { +@@ -1531,12 +1534,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) + (unsigned long)res->start, irq, i2c->i2c_clk); + + return 0; +- +-err_pm_disable: +- pm_runtime_disable(&pdev->dev); +- pm_runtime_set_suspended(&pdev->dev); +- +- return ret; + } + + static void xiic_i2c_remove(struct platform_device *pdev) +@@ -1556,9 +1553,6 @@ static void xiic_i2c_remove(struct platform_device *pdev) + xiic_deinit(i2c); + + pm_runtime_put_sync(i2c->dev); +- pm_runtime_disable(&pdev->dev); +- pm_runtime_set_suspended(&pdev->dev); +- pm_runtime_dont_use_autosuspend(&pdev->dev); + } + + static const struct dev_pm_ops xiic_dev_pm_ops = { +-- +2.53.0 + diff --git a/patches-sonic/0011-i2c-xiic-remove-duplicate-error-message.patch b/patches-sonic/0011-i2c-xiic-remove-duplicate-error-message.patch new file mode 100644 index 000000000..88cc8278c --- /dev/null +++ b/patches-sonic/0011-i2c-xiic-remove-duplicate-error-message.patch @@ -0,0 +1,38 @@ +From 8809c7f8154d8752a3b5ab2f571160cdc413e394 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:17 +0000 +Subject: [PATCH 11/22] i2c: xiic: remove duplicate error message + +The devm_request_threaded_irq() already prints an error message. Remove +the duplicate. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Reviewed-by: Andrew Lunn +Reviewed-by: Jonathan Cameron +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-2-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index ea85fc396033..5f141acc5306 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1492,11 +1492,8 @@ static int xiic_i2c_probe(struct platform_device *pdev) + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + xiic_process, IRQF_ONESHOT, + pdev->name, i2c); +- +- if (ret < 0) { +- dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n"); ++ if (ret) + return ret; +- } + + i2c->singlemaster = + of_property_read_bool(pdev->dev.of_node, "single-master"); +-- +2.53.0 + diff --git a/patches-sonic/0012-i2c-xiic-switch-to-generic-device-property-accessors.patch b/patches-sonic/0012-i2c-xiic-switch-to-generic-device-property-accessors.patch new file mode 100644 index 000000000..43467523e --- /dev/null +++ b/patches-sonic/0012-i2c-xiic-switch-to-generic-device-property-accessors.patch @@ -0,0 +1,100 @@ +From aba046769d414fb5d6fb3281465e2d7eb3bea7c8 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:18 +0000 +Subject: [PATCH 12/22] i2c: xiic: switch to generic device property accessors + +Use generic device property accessors making them work for ACPI +platforms. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-3-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 21 +++++++-------------- + 1 file changed, 7 insertions(+), 14 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 5f141acc5306..16fd85373e46 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1409,7 +1408,6 @@ static const struct i2c_adapter xiic_adapter = { + .algo = &xiic_algorithm, + }; + +-#if defined(CONFIG_OF) + static const struct xiic_version_data xiic_2_00 = { + .quirks = DYNAMIC_MODE_READ_BROKEN_BIT, + }; +@@ -1420,14 +1418,14 @@ static const struct of_device_id xiic_of_match[] = { + {}, + }; + MODULE_DEVICE_TABLE(of, xiic_of_match); +-#endif + + static int xiic_i2c_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct fwnode_handle *fwnode = dev_fwnode(dev); + struct xiic_i2c *i2c; + struct xiic_i2c_platform_data *pdata; +- const struct of_device_id *match; ++ const struct xiic_version_data *data; + struct resource *res; + int ret, irq; + u8 i; +@@ -1437,12 +1435,9 @@ static int xiic_i2c_probe(struct platform_device *pdev) + if (!i2c) + return -ENOMEM; + +- match = of_match_node(xiic_of_match, pdev->dev.of_node); +- if (match && match->data) { +- const struct xiic_version_data *data = match->data; +- ++ data = device_get_match_data(dev); ++ if (data) + i2c->quirks = data->quirks; +- } + + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(i2c->base)) +@@ -1459,7 +1454,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + i2c->adap = xiic_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; +- i2c->adap.dev.of_node = pdev->dev.of_node; ++ device_set_node(&i2c->adap.dev, fwnode); + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + DRIVER_NAME " %s", pdev->name); + +@@ -1483,8 +1478,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + + /* SCL frequency configuration */ + i2c->input_clk = clk_get_rate(i2c->clk); +- ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", +- &i2c->i2c_clk); ++ ret = device_property_read_u32(dev, "clock-frequency", &i2c->i2c_clk); + /* If clock-frequency not specified in DT, do not configure in SW */ + if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ) + i2c->i2c_clk = 0; +@@ -1495,8 +1489,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + if (ret) + return ret; + +- i2c->singlemaster = +- of_property_read_bool(pdev->dev.of_node, "single-master"); ++ i2c->singlemaster = device_property_read_bool(dev, "single-master"); + + /* + * Detect endianness +-- +2.53.0 + diff --git a/patches-sonic/0013-i2c-xiic-cosmetic-cleanup.patch b/patches-sonic/0013-i2c-xiic-cosmetic-cleanup.patch new file mode 100644 index 000000000..36225def4 --- /dev/null +++ b/patches-sonic/0013-i2c-xiic-cosmetic-cleanup.patch @@ -0,0 +1,92 @@ +From 20c1b78562c141aa7723cbf3b733ea23ae48b4f0 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:19 +0000 +Subject: [PATCH 13/22] i2c: xiic: cosmetic cleanup + +Re-use dev pointer instead of referencing &pdev->dev everywhere. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-4-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 16fd85373e46..6de239d2cfc0 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1431,7 +1431,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + u8 i; + u32 sr; + +- i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); ++ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + +@@ -1447,7 +1447,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + +- pdata = dev_get_platdata(&pdev->dev); ++ pdata = dev_get_platdata(dev); + + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); +@@ -1469,9 +1469,10 @@ static int xiic_i2c_probe(struct platform_device *pdev) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), + "failed to enable input clock.\n"); + +- i2c->dev = &pdev->dev; +- pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT); +- pm_runtime_use_autosuspend(i2c->dev); ++ i2c->dev = dev; ++ ++ pm_runtime_set_autosuspend_delay(dev, XIIC_PM_TIMEOUT); ++ pm_runtime_use_autosuspend(dev); + ret = devm_pm_runtime_set_active_enabled(dev); + if (ret) + return ret; +@@ -1483,9 +1484,8 @@ static int xiic_i2c_probe(struct platform_device *pdev) + if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ) + i2c->i2c_clk = 0; + +- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +- xiic_process, IRQF_ONESHOT, +- pdev->name, i2c); ++ ret = devm_request_threaded_irq(dev, irq, NULL, xiic_process, ++ IRQF_ONESHOT, pdev->name, i2c); + if (ret) + return ret; + +@@ -1528,21 +1528,21 @@ static int xiic_i2c_probe(struct platform_device *pdev) + + static void xiic_i2c_remove(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + struct xiic_i2c *i2c = platform_get_drvdata(pdev); + int ret; + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + +- ret = pm_runtime_get_sync(i2c->dev); +- ++ ret = pm_runtime_get_sync(dev); + if (ret < 0) +- dev_warn(&pdev->dev, "Failed to activate device for removal (%pe)\n", ++ dev_warn(dev, "Failed to activate device for removal (%pe)\n", + ERR_PTR(ret)); + else + xiic_deinit(i2c); + +- pm_runtime_put_sync(i2c->dev); ++ pm_runtime_put_sync(dev); + } + + static const struct dev_pm_ops xiic_dev_pm_ops = { +-- +2.53.0 + diff --git a/patches-sonic/0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch b/patches-sonic/0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch new file mode 100644 index 000000000..bb1e4160c --- /dev/null +++ b/patches-sonic/0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch @@ -0,0 +1,34 @@ +From d902afc2c1847903bafa2d9e5a8f311c8d123fc4 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:20 +0000 +Subject: [PATCH 14/22] i2c: xiic: cosmetic: use resource format specifier in + debug log + +Use standard resource format specifier %pR in debug log. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-5-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 6de239d2cfc0..b9880609a92d 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1520,8 +1520,8 @@ static int xiic_i2c_probe(struct platform_device *pdev) + i2c_new_client_device(&i2c->adap, pdata->devices + i); + } + +- dev_dbg(&pdev->dev, "mmio %08lx irq %d scl clock frequency %d\n", +- (unsigned long)res->start, irq, i2c->i2c_clk); ++ dev_dbg(dev, "mmio %pR irq %d scl clock frequency %d\n", ++ res, irq, i2c->i2c_clk); + + return 0; + } +-- +2.53.0 + diff --git a/patches-sonic/0015-i2c-xiic-use-numbered-adapter-registration.patch b/patches-sonic/0015-i2c-xiic-use-numbered-adapter-registration.patch new file mode 100644 index 000000000..f2e6819ff --- /dev/null +++ b/patches-sonic/0015-i2c-xiic-use-numbered-adapter-registration.patch @@ -0,0 +1,45 @@ +From f7b0e31e45365fd8b5e7b71b67041eb7d3126c2b Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:21 +0000 +Subject: [PATCH 15/22] i2c: xiic: use numbered adapter registration + +Switch from i2c_add_adapter() to i2c_add_numbered_adapter() to enable +platforms to specify fixed I2C bus numbers via the platform device ID. + +This allows systems to maintain consistent bus numbering across reboots. +On platforms where the device ID is PLATFORM_DEVID_NONE (the default), +the adapter falls back to dynamic allocation, preserving backward +compatibility. + +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Andy Shevchenko +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-6-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index b9880609a92d..56109a38f57b 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1452,6 +1452,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = xiic_adapter; ++ i2c->adap.nr = pdev->id; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + device_set_node(&i2c->adap.dev, fwnode); +@@ -1508,7 +1509,7 @@ static int xiic_i2c_probe(struct platform_device *pdev) + return dev_err_probe(dev, ret, "Cannot xiic_reinit\n"); + + /* add i2c adapter to i2c tree */ +- ret = i2c_add_adapter(&i2c->adap); ++ ret = i2c_add_numbered_adapter(&i2c->adap); + if (ret) { + xiic_deinit(i2c); + return ret; +-- +2.53.0 + diff --git a/patches-sonic/0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch b/patches-sonic/0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch new file mode 100644 index 000000000..27a8d234a --- /dev/null +++ b/patches-sonic/0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch @@ -0,0 +1,42 @@ +From efe64a75e59f17682a6199f0cfc596441e3318f0 Mon Sep 17 00:00:00 2001 +From: Abdurrahman Hussain +Date: Mon, 23 Feb 2026 15:59:22 +0000 +Subject: [PATCH 16/22] i2c: xiic: skip input clock setup on non-OF systems + +Currently Linux does not implement ACPI ClockInput() resource to describe +clocks, unlike DT. However the xiic driver is happy if something +magically enables the clock before the driver probes, and does not +turn it off again. The clock should always be considered optional for +ACPI. + +Signed-off-by: Abdurrahman Hussain +Signed-off-by: Andi Shyti +Link: https://lore.kernel.org/r/20260223-i2c-xiic-v12-7-b6c9ce4e4f3c@nexthop.ai +--- + drivers/i2c/busses/i2c-xiic.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 56109a38f57b..e0626c39a381 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -1465,10 +1465,12 @@ static int xiic_i2c_probe(struct platform_device *pdev) + + spin_lock_init(&i2c->atomic_lock); + +- i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); +- if (IS_ERR(i2c->clk)) +- return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), +- "failed to enable input clock.\n"); ++ if (is_of_node(fwnode)) { ++ i2c->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(i2c->clk)) ++ return dev_err_probe(dev, PTR_ERR(i2c->clk), ++ "failed to enable input clock.\n"); ++ } + + i2c->dev = dev; + +-- +2.53.0 + diff --git a/patches-sonic/series b/patches-sonic/series index a9180fa1b..e0669f579 100644 --- a/patches-sonic/series +++ b/patches-sonic/series @@ -208,7 +208,18 @@ cisco-npu-disable-other-bars.patch 0003-xilinx-spi-make-interrupt-optional.patch 0004-xilinx-spi-platform_get_irq_optional.patch 0005-xilinx-spi-use-device-property.patch -driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending +driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending +0006-PM-runtime-Add-new-devm-functions.patch # Backport 69a837b75edc (in v6.12.55+); required by 0010 +0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch +0008-i2c-xiic-Add-atomic-transfer-support.patch +0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch +0010-i2c-xiic-switch-to-devres-managed-APIs.patch +0011-i2c-xiic-remove-duplicate-error-message.patch +0012-i2c-xiic-switch-to-generic-device-property-accessors.patch +0013-i2c-xiic-cosmetic-cleanup.patch +0014-i2c-xiic-cosmetic-use-resource-format-specifier-in-d.patch +0015-i2c-xiic-use-numbered-adapter-registration.patch +0016-i2c-xiic-skip-input-clock-setup-on-non-OF-systems.patch # Fix to avoid kernel panic on Kernel 6.1.94 # https://github.com/sonic-net/sonic-buildimage/issues/20901 From 8bc88574503e6a802b95ff6ea1e6387d31de0976 Mon Sep 17 00:00:00 2001 From: domingo-nexthop Date: Mon, 4 May 2026 07:12:43 -0700 Subject: [PATCH 2/3] rename patch number Signed-off-by: domingo-nexthop --- ...tions.patch => 0001-PM-runtime-Add-new-devm-functions.patch} | 0 patches-sonic/series | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename patches-sonic/{0006-PM-runtime-Add-new-devm-functions.patch => 0001-PM-runtime-Add-new-devm-functions.patch} (100%) diff --git a/patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch b/patches-sonic/0001-PM-runtime-Add-new-devm-functions.patch similarity index 100% rename from patches-sonic/0006-PM-runtime-Add-new-devm-functions.patch rename to patches-sonic/0001-PM-runtime-Add-new-devm-functions.patch diff --git a/patches-sonic/series b/patches-sonic/series index e0669f579..60c32b11f 100644 --- a/patches-sonic/series +++ b/patches-sonic/series @@ -209,7 +209,7 @@ cisco-npu-disable-other-bars.patch 0004-xilinx-spi-platform_get_irq_optional.patch 0005-xilinx-spi-use-device-property.patch driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending -0006-PM-runtime-Add-new-devm-functions.patch # Backport 69a837b75edc (in v6.12.55+); required by 0010 +0001-PM-runtime-Add-new-devm-functions.patch # Backport 69a837b75edc (in v6.12.55+); required by 0010 0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch 0008-i2c-xiic-Add-atomic-transfer-support.patch 0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch From d4e342b4b7815599877047e474b2fdaac66dcd7a Mon Sep 17 00:00:00 2001 From: domingo-nexthop Date: Mon, 4 May 2026 14:26:11 -0700 Subject: [PATCH 3/3] revert whitespace changes Signed-off-by: domingo-nexthop --- patches-sonic/series | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches-sonic/series b/patches-sonic/series index 60c32b11f..edbe8d31d 100644 --- a/patches-sonic/series +++ b/patches-sonic/series @@ -208,8 +208,8 @@ cisco-npu-disable-other-bars.patch 0003-xilinx-spi-make-interrupt-optional.patch 0004-xilinx-spi-platform_get_irq_optional.patch 0005-xilinx-spi-use-device-property.patch -driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending -0001-PM-runtime-Add-new-devm-functions.patch # Backport 69a837b75edc (in v6.12.55+); required by 0010 +driver-tty-serial-8250-add-support-for-fintek-F81214E.patch # Linux upstream pending +0001-PM-runtime-Add-new-devm-functions.patch 0007-i2c-xiic-Relocate-xiic_i2c_runtime_suspend-and-xiic_.patch 0008-i2c-xiic-Add-atomic-transfer-support.patch 0009-i2c-i2c-xiic-Replace-dev_err-with-dev_err_probe-in-p.patch