aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-designware-platdrv.c
diff options
context:
space:
mode:
authorJan Dabros <jsd@semihalf.com>2022-02-08 15:12:18 +0100
committerWolfram Sang <wsa@kernel.org>2022-02-11 15:38:23 +0100
commit78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c (patch)
tree8b5d5d765f5b3068645db94da8553e76483098ad /drivers/i2c/busses/i2c-designware-platdrv.c
parenti2c: designware: Add missing locks (diff)
downloadlinux-dev-78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c.tar.xz
linux-dev-78d5e9e299e31bc2deaaa94a45bf8ea024f27e8c.zip
i2c: designware: Add AMD PSP I2C bus support
Implement an I2C controller sharing mechanism between the host (kernel) and PSP co-processor on some platforms equipped with AMD Cezanne SoC. On these platforms we need to implement "software" i2c arbitration. Default arbitration owner is PSP and kernel asks for acquire as well as inform about release of the i2c bus via mailbox mechanism. +---------+ <- ACQUIRE | | +---------| CPU |\ | | | \ +----------+ SDA | +---------+ \ | |------- MAILBOX +--> | I2C-DW | SCL | +---------+ | |------- | | | +----------+ +---------| PSP | <- ACK | | +---------+ +---------+ <- RELEASE | | +---------| CPU | | | | +----------+ SDA | +---------+ | |------- MAILBOX +--> | I2C-DW | SCL | +---------+ / | |------- | | | / +----------+ +---------| PSP |/ <- ACK | | +---------+ The solution is similar to i2c-designware-baytrail.c implementation, where we are using a generic i2c-designware-* driver with a small "wrapper". In contrary to baytrail semaphore implementation, beside internal acquire_lock() and release_lock() methods we are also applying quirks to lock_bus() and unlock_bus() global adapter methods. With this in place all i2c clients drivers may lock i2c bus for a desired number of i2c transactions (e.g. write-wait-read) without being aware of that such bus is shared with another entity. Modify i2c_dw_probe_lock_support() to select correct semaphore implementation at runtime, since now we have more than one available. Configure new matching ACPI ID "AMDI0019" and register ARBITRATION_SEMAPHORE flag in order to distinguish setup with PSP arbitration. Add myself as a reviewer for I2C DesignWare in order to help with reviewing and testing possible changes touching new i2c-designware-amdpsp.c module. Signed-off-by: Jan Dabros <jsd@semihalf.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> [wsa: removed unneeded blank line and curly braces] Signed-off-by: Wolfram Sang <wsa@kernel.org>
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-platdrv.c')
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 2bd81abc86f6..9973ac894a51 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -50,6 +50,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "808622C1", ACCESS_NO_IRQ_SUSPEND },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
+ { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },
{ "AMDI0510", 0 },
{ "APMC0D0F", 0 },
{ "HISI02A1", 0 },
@@ -204,6 +205,63 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
{ } /* terminate list */
};
+static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = {
+#ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL
+ {
+ .probe = i2c_dw_baytrail_probe_lock_support,
+ },
+#endif
+#ifdef CONFIG_I2C_DESIGNWARE_AMDPSP
+ {
+ .probe = i2c_dw_amdpsp_probe_lock_support,
+ .remove = i2c_dw_amdpsp_remove_lock_support,
+ },
+#endif
+ {}
+};
+
+static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
+{
+ const struct i2c_dw_semaphore_callbacks *ptr;
+ int i = 0;
+ int ret;
+
+ ptr = i2c_dw_semaphore_cb_table;
+
+ dev->semaphore_idx = -1;
+
+ while (ptr->probe) {
+ ret = ptr->probe(dev);
+ if (ret) {
+ /*
+ * If there is no semaphore device attached to this
+ * controller, we shouldn't abort general i2c_controller
+ * probe.
+ */
+ if (ret != -ENODEV)
+ return ret;
+
+ i++;
+ ptr++;
+ continue;
+ }
+
+ dev->semaphore_idx = i;
+ break;
+ }
+
+ return 0;
+}
+
+static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)
+{
+ if (dev->semaphore_idx < 0)
+ return;
+
+ if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove)
+ i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev);
+}
+
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct i2c_adapter *adap;
@@ -334,6 +392,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
dw_i2c_plat_pm_cleanup(dev);
+ i2c_dw_remove_lock_support(dev);
+
reset_control_assert(dev->rst);
return 0;