diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-platdrv.c')
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 46 |
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 @@ | |||
35 | #include <linux/err.h> | 35 | #include <linux/err.h> |
36 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
37 | #include <linux/of.h> | 37 | #include <linux/of.h> |
38 | #include <linux/of_i2c.h> | ||
39 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
40 | #include <linux/pm.h> | 39 | #include <linux/pm.h> |
41 | #include <linux/pm_runtime.h> | 40 | #include <linux/pm_runtime.h> |
@@ -54,9 +53,33 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) | |||
54 | } | 53 | } |
55 | 54 | ||
56 | #ifdef CONFIG_ACPI | 55 | #ifdef CONFIG_ACPI |
56 | static void dw_i2c_acpi_params(struct platform_device *pdev, char method[], | ||
57 | u16 *hcnt, u16 *lcnt, u32 *sda_hold) | ||
58 | { | ||
59 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; | ||
60 | acpi_handle handle = ACPI_HANDLE(&pdev->dev); | ||
61 | union acpi_object *obj; | ||
62 | |||
63 | if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf))) | ||
64 | return; | ||
65 | |||
66 | obj = (union acpi_object *)buf.pointer; | ||
67 | if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) { | ||
68 | const union acpi_object *objs = obj->package.elements; | ||
69 | |||
70 | *hcnt = (u16)objs[0].integer.value; | ||
71 | *lcnt = (u16)objs[1].integer.value; | ||
72 | if (sda_hold) | ||
73 | *sda_hold = (u32)objs[2].integer.value; | ||
74 | } | ||
75 | |||
76 | kfree(buf.pointer); | ||
77 | } | ||
78 | |||
57 | static int dw_i2c_acpi_configure(struct platform_device *pdev) | 79 | static int dw_i2c_acpi_configure(struct platform_device *pdev) |
58 | { | 80 | { |
59 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | 81 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); |
82 | bool fs_mode = dev->master_cfg & DW_IC_CON_SPEED_FAST; | ||
60 | 83 | ||
61 | if (!ACPI_HANDLE(&pdev->dev)) | 84 | if (!ACPI_HANDLE(&pdev->dev)) |
62 | return -ENODEV; | 85 | return -ENODEV; |
@@ -64,6 +87,16 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) | |||
64 | dev->adapter.nr = -1; | 87 | dev->adapter.nr = -1; |
65 | dev->tx_fifo_depth = 32; | 88 | dev->tx_fifo_depth = 32; |
66 | dev->rx_fifo_depth = 32; | 89 | dev->rx_fifo_depth = 32; |
90 | |||
91 | /* | ||
92 | * Try to get SDA hold time and *CNT values from an ACPI method if | ||
93 | * it exists for both supported speed modes. | ||
94 | */ | ||
95 | dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, | ||
96 | fs_mode ? NULL : &dev->sda_hold_time); | ||
97 | dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, | ||
98 | fs_mode ? &dev->sda_hold_time : NULL); | ||
99 | |||
67 | return 0; | 100 | return 0; |
68 | } | 101 | } |
69 | 102 | ||
@@ -172,8 +205,6 @@ static int dw_i2c_probe(struct platform_device *pdev) | |||
172 | dev_err(&pdev->dev, "failure adding adapter\n"); | 205 | dev_err(&pdev->dev, "failure adding adapter\n"); |
173 | return r; | 206 | return r; |
174 | } | 207 | } |
175 | of_i2c_register_devices(adap); | ||
176 | acpi_i2c_register_devices(adap); | ||
177 | 208 | ||
178 | pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); | 209 | pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); |
179 | pm_runtime_use_autosuspend(&pdev->dev); | 210 | pm_runtime_use_autosuspend(&pdev->dev); |
@@ -207,7 +238,7 @@ static const struct of_device_id dw_i2c_of_match[] = { | |||
207 | MODULE_DEVICE_TABLE(of, dw_i2c_of_match); | 238 | MODULE_DEVICE_TABLE(of, dw_i2c_of_match); |
208 | #endif | 239 | #endif |
209 | 240 | ||
210 | #ifdef CONFIG_PM | 241 | #ifdef CONFIG_PM_SLEEP |
211 | static int dw_i2c_suspend(struct device *dev) | 242 | static int dw_i2c_suspend(struct device *dev) |
212 | { | 243 | { |
213 | struct platform_device *pdev = to_platform_device(dev); | 244 | struct platform_device *pdev = to_platform_device(dev); |
@@ -228,9 +259,12 @@ static int dw_i2c_resume(struct device *dev) | |||
228 | 259 | ||
229 | return 0; | 260 | return 0; |
230 | } | 261 | } |
231 | #endif | ||
232 | 262 | ||
233 | static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume); | 263 | static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume); |
264 | #define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops) | ||
265 | #else | ||
266 | #define DW_I2C_DEV_PM_OPS NULL | ||
267 | #endif | ||
234 | 268 | ||
235 | /* work with hotplug and coldplug */ | 269 | /* work with hotplug and coldplug */ |
236 | MODULE_ALIAS("platform:i2c_designware"); | 270 | MODULE_ALIAS("platform:i2c_designware"); |
@@ -242,7 +276,7 @@ static struct platform_driver dw_i2c_driver = { | |||
242 | .owner = THIS_MODULE, | 276 | .owner = THIS_MODULE, |
243 | .of_match_table = of_match_ptr(dw_i2c_of_match), | 277 | .of_match_table = of_match_ptr(dw_i2c_of_match), |
244 | .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), | 278 | .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), |
245 | .pm = &dw_i2c_dev_pm_ops, | 279 | .pm = DW_I2C_DEV_PM_OPS, |
246 | }, | 280 | }, |
247 | }; | 281 | }; |
248 | 282 | ||