From ce4a0294c3c7c775d17799759b9f913d386d63ad Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Mon, 20 Nov 2023 13:30:09 +0100 Subject: [PATCH] linux-mainline: Backport fixes for mv64xxx PMIC For details please see: https://github.com/linux-sunxi/meta-sunxi/issues/397 Signed-off-by: Marek Belisko --- recipes-kernel/linux/linux-mainline.inc | 2 + ...xxx-Add-atomic_xfer-method-to-driver.patch | 145 ++++++++++++++++++ ...x-Remove-shutdown-method-from-driver.patch | 56 +++++++ 3 files changed, 203 insertions(+) create mode 100644 recipes-kernel/linux/linux-mainline/0004-i2c-mv64xxx-Add-atomic_xfer-method-to-driver.patch create mode 100644 recipes-kernel/linux/linux-mainline/0005-i2c-mv64xxx-Remove-shutdown-method-from-driver.patch diff --git a/recipes-kernel/linux/linux-mainline.inc b/recipes-kernel/linux/linux-mainline.inc index 8b218cd..567a1ae 100644 --- a/recipes-kernel/linux/linux-mainline.inc +++ b/recipes-kernel/linux/linux-mainline.inc @@ -26,6 +26,8 @@ SRC_URI = "https://www.kernel.org/pub/linux/kernel/v5.x/linux-${PV}.tar.xz \ file://0001-dts-orange-pi-zero-Add-wifi-support.patch \ file://0002-dts-nanopi-neo-air-add-camera.patch \ file://0003-dts-allwinner-bananapi-m2-zreo-Enforce-consistent-MM.patch \ + file://0004-i2c-mv64xxx-Add-atomic_xfer-method-to-driver.patch \ + file://0005-i2c-mv64xxx-Remove-shutdown-method-from-driver.patch \ file://defconfig \ " diff --git a/recipes-kernel/linux/linux-mainline/0004-i2c-mv64xxx-Add-atomic_xfer-method-to-driver.patch b/recipes-kernel/linux/linux-mainline/0004-i2c-mv64xxx-Add-atomic_xfer-method-to-driver.patch new file mode 100644 index 0000000..b0e512f --- /dev/null +++ b/recipes-kernel/linux/linux-mainline/0004-i2c-mv64xxx-Add-atomic_xfer-method-to-driver.patch @@ -0,0 +1,145 @@ +From 544a8d75f3d6e60e160cd92dc56321484598a993 Mon Sep 17 00:00:00 2001 +From: Chris Morgan +Date: Wed, 30 Mar 2022 12:16:57 -0500 +Subject: [PATCH] i2c: mv64xxx: Add atomic_xfer method to driver + +Add an atomic_xfer method to the driver so that it behaves correctly +when controlling a PMIC that is responsible for device shutdown. + +The atomic_xfer method added is similar to the one from the i2c-rk3x +driver. When running an atomic_xfer a bool flag in the driver data is +set, the interrupt is not unmasked on transfer start, and the IRQ +handler is manually invoked while waiting for pending transfers to +complete. + +Signed-off-by: Chris Morgan +Acked-by: Gregory CLEMENT +Signed-off-by: Wolfram Sang +--- + drivers/i2c/busses/i2c-mv64xxx.c | 52 ++++++++++++++++++++++++++++---- + 1 file changed, 46 insertions(+), 6 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c +index 424c53e4c513..103a05ecc3d6 100644 +--- a/drivers/i2c/busses/i2c-mv64xxx.c ++++ b/drivers/i2c/busses/i2c-mv64xxx.c +@@ -150,6 +150,7 @@ struct mv64xxx_i2c_data { + /* Clk div is 2 to the power n, not 2 to the power n + 1 */ + bool clk_n_base_0; + struct i2c_bus_recovery_info rinfo; ++ bool atomic; + }; + + static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { +@@ -179,7 +180,10 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, + u32 dir = 0; + + drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | +- MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; ++ MV64XXX_I2C_REG_CONTROL_TWSIEN; ++ ++ if (!drv_data->atomic) ++ drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN; + + if (msg->flags & I2C_M_RD) + dir = 1; +@@ -409,7 +413,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) + case MV64XXX_I2C_ACTION_RCV_DATA_STOP: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(drv_data->reg_base + drv_data->reg_offsets.data); +- drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; ++ if (!drv_data->atomic) ++ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + drv_data->reg_offsets.control); + drv_data->block = 0; +@@ -427,7 +432,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) + drv_data->rc = -EIO; + fallthrough; + case MV64XXX_I2C_ACTION_SEND_STOP: +- drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; ++ if (!drv_data->atomic) ++ drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + drv_data->reg_offsets.control); + drv_data->block = 0; +@@ -575,6 +581,17 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) + spin_unlock_irqrestore(&drv_data->lock, flags); + } + ++static void mv64xxx_i2c_wait_polling(struct mv64xxx_i2c_data *drv_data) ++{ ++ ktime_t timeout = ktime_add_ms(ktime_get(), drv_data->adapter.timeout); ++ ++ while (READ_ONCE(drv_data->block) && ++ ktime_compare(ktime_get(), timeout) < 0) { ++ udelay(5); ++ mv64xxx_i2c_intr(0, drv_data); ++ } ++} ++ + static int + mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, + int is_last) +@@ -590,7 +607,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, + mv64xxx_i2c_send_start(drv_data); + spin_unlock_irqrestore(&drv_data->lock, flags); + +- mv64xxx_i2c_wait_for_completion(drv_data); ++ if (!drv_data->atomic) ++ mv64xxx_i2c_wait_for_completion(drv_data); ++ else ++ mv64xxx_i2c_wait_polling(drv_data); ++ + return drv_data->rc; + } + +@@ -717,7 +738,7 @@ mv64xxx_i2c_functionality(struct i2c_adapter *adap) + } + + static int +-mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ++mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + { + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + int rc, ret = num; +@@ -730,7 +751,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + drv_data->msgs = msgs; + drv_data->num_msgs = num; + +- if (mv64xxx_i2c_can_offload(drv_data)) ++ if (mv64xxx_i2c_can_offload(drv_data) && !drv_data->atomic) + rc = mv64xxx_i2c_offload_xfer(drv_data); + else + rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1); +@@ -747,8 +768,27 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) + return ret; + } + ++static int ++mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ++{ ++ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); ++ ++ drv_data->atomic = 0; ++ return mv64xxx_i2c_xfer_core(adap, msgs, num); ++} ++ ++static int mv64xxx_i2c_xfer_atomic(struct i2c_adapter *adap, ++ struct i2c_msg msgs[], int num) ++{ ++ struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); ++ ++ drv_data->atomic = 1; ++ return mv64xxx_i2c_xfer_core(adap, msgs, num); ++} ++ + static const struct i2c_algorithm mv64xxx_i2c_algo = { + .master_xfer = mv64xxx_i2c_xfer, ++ .master_xfer_atomic = mv64xxx_i2c_xfer_atomic, + .functionality = mv64xxx_i2c_functionality, + }; + +-- +2.25.1 + diff --git a/recipes-kernel/linux/linux-mainline/0005-i2c-mv64xxx-Remove-shutdown-method-from-driver.patch b/recipes-kernel/linux/linux-mainline/0005-i2c-mv64xxx-Remove-shutdown-method-from-driver.patch new file mode 100644 index 0000000..8f08f68 --- /dev/null +++ b/recipes-kernel/linux/linux-mainline/0005-i2c-mv64xxx-Remove-shutdown-method-from-driver.patch @@ -0,0 +1,56 @@ +From 09b343038e3470e4d0da45f0ee09fb42107e5314 Mon Sep 17 00:00:00 2001 +From: Chris Morgan +Date: Fri, 25 Mar 2022 13:06:25 -0500 +Subject: [PATCH] i2c: mv64xxx: Remove shutdown method from driver + +When I attempt to shut down (or reboot) my R8 based NTC CHIP with this +i2c driver I get the following error: "i2c i2c-0: mv64xxx: I2C bus +locked, block: 1, time_left: 0". Reboots are successful but shutdowns +freeze. If I comment out the shutdown routine the device both reboots +and shuts down successfully without receiving this error (however it +does receive a warning of missing atomic_xfer). + +It appears that very few i2c drivers have a shutdown method, I assume +because these devices are often used to communicate with PMICs (such +as in my case with the R8 based NTC CHIP). I'm proposing we simply +remove this method so long as it doesn't cause trouble for others +downstream. I'll work on an atomic_xfer method and submit that in +a different patch. + +Signed-off-by: Chris Morgan +Acked-by: Gregory CLEMENT +Signed-off-by: Wolfram Sang +--- + drivers/i2c/busses/i2c-mv64xxx.c | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c +index 5c8e94b6cdb5..424c53e4c513 100644 +--- a/drivers/i2c/busses/i2c-mv64xxx.c ++++ b/drivers/i2c/busses/i2c-mv64xxx.c +@@ -1047,14 +1047,6 @@ mv64xxx_i2c_remove(struct platform_device *pd) + return 0; + } + +-static void +-mv64xxx_i2c_shutdown(struct platform_device *pd) +-{ +- pm_runtime_disable(&pd->dev); +- if (!pm_runtime_status_suspended(&pd->dev)) +- mv64xxx_i2c_runtime_suspend(&pd->dev); +-} +- + static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { + SET_RUNTIME_PM_OPS(mv64xxx_i2c_runtime_suspend, + mv64xxx_i2c_runtime_resume, NULL) +@@ -1065,7 +1057,6 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { + static struct platform_driver mv64xxx_i2c_driver = { + .probe = mv64xxx_i2c_probe, + .remove = mv64xxx_i2c_remove, +- .shutdown = mv64xxx_i2c_shutdown, + .driver = { + .name = MV64XXX_I2C_CTLR_NAME, + .pm = &mv64xxx_i2c_pm_ops, +-- +2.25.1 +