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.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 4c5fadabe49d..4c1b60539a25 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -35,7 +35,6 @@
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/of.h>
-#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@@ -54,9 +53,33 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
}
#ifdef CONFIG_ACPI
+static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
+ u16 *hcnt, u16 *lcnt, u32 *sda_hold)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+ union acpi_object *obj;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
+ return;
+
+ obj = (union acpi_object *)buf.pointer;
+ if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
+ const union acpi_object *objs = obj->package.elements;
+
+ *hcnt = (u16)objs[0].integer.value;
+ *lcnt = (u16)objs[1].integer.value;
+ if (sda_hold)
+ *sda_hold = (u32)objs[2].integer.value;
+ }
+
+ kfree(buf.pointer);
+}
+
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ bool fs_mode = dev->master_cfg & DW_IC_CON_SPEED_FAST;
if (!ACPI_HANDLE(&pdev->dev))
return -ENODEV;
@@ -64,6 +87,16 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
dev->rx_fifo_depth = 32;
+
+ /*
+ * Try to get SDA hold time and *CNT values from an ACPI method if
+ * it exists for both supported speed modes.
+ */
+ dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt,
+ fs_mode ? NULL : &dev->sda_hold_time);
+ dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
+ fs_mode ? &dev->sda_hold_time : NULL);
+
return 0;
}
@@ -172,8 +205,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failure adding adapter\n");
return r;
}
- of_i2c_register_devices(adap);
- acpi_i2c_register_devices(adap);
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -207,7 +238,7 @@ static const struct of_device_id dw_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int dw_i2c_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -228,9 +259,12 @@ static int dw_i2c_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
+#define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops)
+#else
+#define DW_I2C_DEV_PM_OPS NULL
+#endif
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
@@ -242,7 +276,7 @@ static struct platform_driver dw_i2c_driver = {
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dw_i2c_of_match),
.acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
- .pm = &dw_i2c_dev_pm_ops,
+ .pm = DW_I2C_DEV_PM_OPS,
},
};