summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-designware-platdrv.c
diff options
context:
space:
mode:
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;