Created
March 28, 2022 20:59
-
-
Save macromorgan/9509cd18a83faab399e2e8e38dbc237a to your computer and use it in GitHub Desktop.
Fix i2c for Sunxi-R8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 805fec0c5aa2f1c11d7859a3995ae0e5c74e3355 Mon Sep 17 00:00:00 2001 | |
From: Chris Morgan <[email protected]> | |
Date: Mon, 28 Mar 2022 15:53:11 -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 is sets a bool flag in the driver | |
data, doesn't unmask the interrupt upon transfer start, and invokes | |
the IRQ handler manually while waiting for pending transfers to | |
complete. | |
Signed-off-by: Chris Morgan <[email protected]> | |
--- | |
drivers/i2c/busses/i2c-mv64xxx.c | 54 +++++++++++++++++++++++++++----- | |
1 file changed, 47 insertions(+), 7 deletions(-) | |
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c | |
index 424c53e4c513..af3b594fa153 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; | |
} | |
@@ -716,8 +737,8 @@ mv64xxx_i2c_functionality(struct i2c_adapter *adap) | |
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; | |
} | |
-static int | |
-mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |
+static int 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 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 9d1d8e9781e2756c4c3c5c9ee292c7b286dd6fd3 Mon Sep 17 00:00:00 2001 | |
From: Chris Morgan <[email protected]> | |
Date: Fri, 25 Mar 2022 12:58:23 -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 <[email protected]> | |
--- | |
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 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment