1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Synopsys DesignWare I2C adapter driver. |
4 | * |
5 | * Based on the TI DAVINCI I2C adapter driver. |
6 | * |
7 | * Copyright (C) 2006 Texas Instruments. |
8 | * Copyright (C) 2007 MontaVista Software Inc. |
9 | * Copyright (C) 2009 Provigent Ltd. |
10 | */ |
11 | #include <linux/acpi.h> |
12 | #include <linux/clk-provider.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/dmi.h> |
16 | #include <linux/err.h> |
17 | #include <linux/errno.h> |
18 | #include <linux/i2c.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/io.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/mfd/syscon.h> |
23 | #include <linux/module.h> |
24 | #include <linux/of.h> |
25 | #include <linux/platform_device.h> |
26 | #include <linux/pm.h> |
27 | #include <linux/pm_runtime.h> |
28 | #include <linux/property.h> |
29 | #include <linux/regmap.h> |
30 | #include <linux/reset.h> |
31 | #include <linux/sched.h> |
32 | #include <linux/slab.h> |
33 | #include <linux/suspend.h> |
34 | #include <linux/units.h> |
35 | |
36 | #include "i2c-designware-core.h" |
37 | |
38 | static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) |
39 | { |
40 | return clk_get_rate(clk: dev->clk) / KILO; |
41 | } |
42 | |
43 | #ifdef CONFIG_ACPI |
44 | static const struct acpi_device_id dw_i2c_acpi_match[] = { |
45 | { "INT33C2" , 0 }, |
46 | { "INT33C3" , 0 }, |
47 | { "INT3432" , 0 }, |
48 | { "INT3433" , 0 }, |
49 | { "80860F41" , ACCESS_NO_IRQ_SUSPEND }, |
50 | { "808622C1" , ACCESS_NO_IRQ_SUSPEND }, |
51 | { "AMD0010" , ACCESS_INTR_MASK }, |
52 | { "AMDI0010" , ACCESS_INTR_MASK }, |
53 | { "AMDI0019" , ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, |
54 | { "AMDI0510" , 0 }, |
55 | { "APMC0D0F" , 0 }, |
56 | { "HISI02A1" , 0 }, |
57 | { "HISI02A2" , 0 }, |
58 | { "HISI02A3" , 0 }, |
59 | { "HYGO0010" , ACCESS_INTR_MASK }, |
60 | { } |
61 | }; |
62 | MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); |
63 | #endif |
64 | |
65 | #ifdef CONFIG_OF |
66 | #define BT1_I2C_CTL 0x100 |
67 | #define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0) |
68 | #define BT1_I2C_CTL_WR BIT(8) |
69 | #define BT1_I2C_CTL_GO BIT(31) |
70 | #define BT1_I2C_DI 0x104 |
71 | #define BT1_I2C_DO 0x108 |
72 | |
73 | static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val) |
74 | { |
75 | struct dw_i2c_dev *dev = context; |
76 | int ret; |
77 | |
78 | /* |
79 | * Note these methods shouldn't ever fail because the system controller |
80 | * registers are memory mapped. We check the return value just in case. |
81 | */ |
82 | ret = regmap_write(map: dev->sysmap, BT1_I2C_CTL, |
83 | BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK)); |
84 | if (ret) |
85 | return ret; |
86 | |
87 | return regmap_read(map: dev->sysmap, BT1_I2C_DO, val); |
88 | } |
89 | |
90 | static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val) |
91 | { |
92 | struct dw_i2c_dev *dev = context; |
93 | int ret; |
94 | |
95 | ret = regmap_write(map: dev->sysmap, BT1_I2C_DI, val); |
96 | if (ret) |
97 | return ret; |
98 | |
99 | return regmap_write(map: dev->sysmap, BT1_I2C_CTL, |
100 | BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); |
101 | } |
102 | |
103 | static struct regmap_config bt1_i2c_cfg = { |
104 | .reg_bits = 32, |
105 | .val_bits = 32, |
106 | .reg_stride = 4, |
107 | .fast_io = true, |
108 | .reg_read = bt1_i2c_read, |
109 | .reg_write = bt1_i2c_write, |
110 | .max_register = DW_IC_COMP_TYPE, |
111 | }; |
112 | |
113 | static int bt1_i2c_request_regs(struct dw_i2c_dev *dev) |
114 | { |
115 | dev->sysmap = syscon_node_to_regmap(np: dev->dev->of_node->parent); |
116 | if (IS_ERR(ptr: dev->sysmap)) |
117 | return PTR_ERR(ptr: dev->sysmap); |
118 | |
119 | dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg); |
120 | return PTR_ERR_OR_ZERO(ptr: dev->map); |
121 | } |
122 | |
123 | #define MSCC_ICPU_CFG_TWI_DELAY 0x0 |
124 | #define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0) |
125 | #define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4 |
126 | |
127 | static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev) |
128 | { |
129 | writel(val: (dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE, |
130 | addr: dev->ext + MSCC_ICPU_CFG_TWI_DELAY); |
131 | |
132 | return 0; |
133 | } |
134 | |
135 | static int dw_i2c_of_configure(struct platform_device *pdev) |
136 | { |
137 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); |
138 | |
139 | switch (dev->flags & MODEL_MASK) { |
140 | case MODEL_MSCC_OCELOT: |
141 | dev->ext = devm_platform_ioremap_resource(pdev, index: 1); |
142 | if (!IS_ERR(ptr: dev->ext)) |
143 | dev->set_sda_hold_time = mscc_twi_set_sda_hold_time; |
144 | break; |
145 | default: |
146 | break; |
147 | } |
148 | |
149 | return 0; |
150 | } |
151 | |
152 | static const struct of_device_id dw_i2c_of_match[] = { |
153 | { .compatible = "snps,designware-i2c" , }, |
154 | { .compatible = "mscc,ocelot-i2c" , .data = (void *)MODEL_MSCC_OCELOT }, |
155 | { .compatible = "baikal,bt1-sys-i2c" , .data = (void *)MODEL_BAIKAL_BT1 }, |
156 | {}, |
157 | }; |
158 | MODULE_DEVICE_TABLE(of, dw_i2c_of_match); |
159 | #else |
160 | static int bt1_i2c_request_regs(struct dw_i2c_dev *dev) |
161 | { |
162 | return -ENODEV; |
163 | } |
164 | |
165 | static inline int dw_i2c_of_configure(struct platform_device *pdev) |
166 | { |
167 | return -ENODEV; |
168 | } |
169 | #endif |
170 | |
171 | static int txgbe_i2c_request_regs(struct dw_i2c_dev *dev) |
172 | { |
173 | dev->map = dev_get_regmap(dev: dev->dev->parent, NULL); |
174 | if (!dev->map) |
175 | return -ENODEV; |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) |
181 | { |
182 | pm_runtime_disable(dev: dev->dev); |
183 | |
184 | if (dev->shared_with_punit) |
185 | pm_runtime_put_noidle(dev: dev->dev); |
186 | } |
187 | |
188 | static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev) |
189 | { |
190 | struct platform_device *pdev = to_platform_device(dev->dev); |
191 | int ret; |
192 | |
193 | switch (dev->flags & MODEL_MASK) { |
194 | case MODEL_BAIKAL_BT1: |
195 | ret = bt1_i2c_request_regs(dev); |
196 | break; |
197 | case MODEL_WANGXUN_SP: |
198 | ret = txgbe_i2c_request_regs(dev); |
199 | break; |
200 | default: |
201 | dev->base = devm_platform_ioremap_resource(pdev, index: 0); |
202 | ret = PTR_ERR_OR_ZERO(ptr: dev->base); |
203 | break; |
204 | } |
205 | |
206 | return ret; |
207 | } |
208 | |
209 | static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { |
210 | { |
211 | .ident = "Qtechnology QT5222" , |
212 | .matches = { |
213 | DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology" ), |
214 | DMI_MATCH(DMI_PRODUCT_NAME, "QT5222" ), |
215 | }, |
216 | }, |
217 | { } /* terminate list */ |
218 | }; |
219 | |
220 | static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = { |
221 | #ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL |
222 | { |
223 | .probe = i2c_dw_baytrail_probe_lock_support, |
224 | }, |
225 | #endif |
226 | #ifdef CONFIG_I2C_DESIGNWARE_AMDPSP |
227 | { |
228 | .probe = i2c_dw_amdpsp_probe_lock_support, |
229 | }, |
230 | #endif |
231 | {} |
232 | }; |
233 | |
234 | static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) |
235 | { |
236 | const struct i2c_dw_semaphore_callbacks *ptr; |
237 | int i = 0; |
238 | int ret; |
239 | |
240 | ptr = i2c_dw_semaphore_cb_table; |
241 | |
242 | dev->semaphore_idx = -1; |
243 | |
244 | while (ptr->probe) { |
245 | ret = ptr->probe(dev); |
246 | if (ret) { |
247 | /* |
248 | * If there is no semaphore device attached to this |
249 | * controller, we shouldn't abort general i2c_controller |
250 | * probe. |
251 | */ |
252 | if (ret != -ENODEV) |
253 | return ret; |
254 | |
255 | i++; |
256 | ptr++; |
257 | continue; |
258 | } |
259 | |
260 | dev->semaphore_idx = i; |
261 | break; |
262 | } |
263 | |
264 | return 0; |
265 | } |
266 | |
267 | static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) |
268 | { |
269 | if (dev->semaphore_idx < 0) |
270 | return; |
271 | |
272 | if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove) |
273 | i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); |
274 | } |
275 | |
276 | static int dw_i2c_plat_probe(struct platform_device *pdev) |
277 | { |
278 | struct i2c_adapter *adap; |
279 | struct dw_i2c_dev *dev; |
280 | struct i2c_timings *t; |
281 | int irq, ret; |
282 | |
283 | irq = platform_get_irq(pdev, 0); |
284 | if (irq < 0) |
285 | return irq; |
286 | |
287 | dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct dw_i2c_dev), GFP_KERNEL); |
288 | if (!dev) |
289 | return -ENOMEM; |
290 | |
291 | dev->flags = (uintptr_t)device_get_match_data(dev: &pdev->dev); |
292 | if (device_property_present(dev: &pdev->dev, propname: "wx,i2c-snps-model" )) |
293 | dev->flags = MODEL_WANGXUN_SP; |
294 | |
295 | dev->dev = &pdev->dev; |
296 | dev->irq = irq; |
297 | platform_set_drvdata(pdev, data: dev); |
298 | |
299 | ret = dw_i2c_plat_request_regs(dev); |
300 | if (ret) |
301 | return ret; |
302 | |
303 | dev->rst = devm_reset_control_get_optional_exclusive(dev: &pdev->dev, NULL); |
304 | if (IS_ERR(ptr: dev->rst)) |
305 | return PTR_ERR(ptr: dev->rst); |
306 | |
307 | reset_control_deassert(rstc: dev->rst); |
308 | |
309 | t = &dev->timings; |
310 | i2c_parse_fw_timings(dev: &pdev->dev, t, use_defaults: false); |
311 | |
312 | i2c_dw_adjust_bus_speed(dev); |
313 | |
314 | if (pdev->dev.of_node) |
315 | dw_i2c_of_configure(pdev); |
316 | |
317 | if (has_acpi_companion(dev: &pdev->dev)) |
318 | i2c_dw_acpi_configure(device: &pdev->dev); |
319 | |
320 | ret = i2c_dw_validate_speed(dev); |
321 | if (ret) |
322 | goto exit_reset; |
323 | |
324 | ret = i2c_dw_probe_lock_support(dev); |
325 | if (ret) |
326 | goto exit_reset; |
327 | |
328 | i2c_dw_configure(dev); |
329 | |
330 | /* Optional interface clock */ |
331 | dev->pclk = devm_clk_get_optional(dev: &pdev->dev, id: "pclk" ); |
332 | if (IS_ERR(ptr: dev->pclk)) { |
333 | ret = PTR_ERR(ptr: dev->pclk); |
334 | goto exit_reset; |
335 | } |
336 | |
337 | dev->clk = devm_clk_get_optional(dev: &pdev->dev, NULL); |
338 | if (IS_ERR(ptr: dev->clk)) { |
339 | ret = PTR_ERR(ptr: dev->clk); |
340 | goto exit_reset; |
341 | } |
342 | |
343 | ret = i2c_dw_prepare_clk(dev, prepare: true); |
344 | if (ret) |
345 | goto exit_reset; |
346 | |
347 | if (dev->clk) { |
348 | u64 clk_khz; |
349 | |
350 | dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; |
351 | clk_khz = dev->get_clk_rate_khz(dev); |
352 | |
353 | if (!dev->sda_hold_time && t->sda_hold_ns) |
354 | dev->sda_hold_time = |
355 | DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO); |
356 | } |
357 | |
358 | adap = &dev->adapter; |
359 | adap->owner = THIS_MODULE; |
360 | adap->class = dmi_check_system(list: dw_i2c_hwmon_class_dmi) ? |
361 | I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; |
362 | ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); |
363 | adap->dev.of_node = pdev->dev.of_node; |
364 | adap->nr = -1; |
365 | |
366 | if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { |
367 | dev_pm_set_driver_flags(dev: &pdev->dev, |
368 | DPM_FLAG_SMART_PREPARE); |
369 | } else { |
370 | dev_pm_set_driver_flags(dev: &pdev->dev, |
371 | DPM_FLAG_SMART_PREPARE | |
372 | DPM_FLAG_SMART_SUSPEND); |
373 | } |
374 | |
375 | device_enable_async_suspend(dev: &pdev->dev); |
376 | |
377 | /* The code below assumes runtime PM to be disabled. */ |
378 | WARN_ON(pm_runtime_enabled(&pdev->dev)); |
379 | |
380 | pm_runtime_set_autosuspend_delay(dev: &pdev->dev, delay: 1000); |
381 | pm_runtime_use_autosuspend(dev: &pdev->dev); |
382 | pm_runtime_set_active(dev: &pdev->dev); |
383 | |
384 | if (dev->shared_with_punit) |
385 | pm_runtime_get_noresume(dev: &pdev->dev); |
386 | |
387 | pm_runtime_enable(dev: &pdev->dev); |
388 | |
389 | ret = i2c_dw_probe(dev); |
390 | if (ret) |
391 | goto exit_probe; |
392 | |
393 | return ret; |
394 | |
395 | exit_probe: |
396 | dw_i2c_plat_pm_cleanup(dev); |
397 | exit_reset: |
398 | reset_control_assert(rstc: dev->rst); |
399 | return ret; |
400 | } |
401 | |
402 | static void dw_i2c_plat_remove(struct platform_device *pdev) |
403 | { |
404 | struct dw_i2c_dev *dev = platform_get_drvdata(pdev); |
405 | |
406 | pm_runtime_get_sync(dev: &pdev->dev); |
407 | |
408 | i2c_del_adapter(adap: &dev->adapter); |
409 | |
410 | dev->disable(dev); |
411 | |
412 | pm_runtime_dont_use_autosuspend(dev: &pdev->dev); |
413 | pm_runtime_put_sync(dev: &pdev->dev); |
414 | dw_i2c_plat_pm_cleanup(dev); |
415 | |
416 | i2c_dw_remove_lock_support(dev); |
417 | |
418 | reset_control_assert(rstc: dev->rst); |
419 | } |
420 | |
421 | static int dw_i2c_plat_prepare(struct device *dev) |
422 | { |
423 | /* |
424 | * If the ACPI companion device object is present for this device, it |
425 | * may be accessed during suspend and resume of other devices via I2C |
426 | * operation regions, so tell the PM core and middle layers to avoid |
427 | * skipping system suspend/resume callbacks for it in that case. |
428 | */ |
429 | return !has_acpi_companion(dev); |
430 | } |
431 | |
432 | static int dw_i2c_plat_runtime_suspend(struct device *dev) |
433 | { |
434 | struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); |
435 | |
436 | if (i_dev->shared_with_punit) |
437 | return 0; |
438 | |
439 | i_dev->disable(i_dev); |
440 | i2c_dw_prepare_clk(dev: i_dev, prepare: false); |
441 | |
442 | return 0; |
443 | } |
444 | |
445 | static int dw_i2c_plat_suspend(struct device *dev) |
446 | { |
447 | struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); |
448 | |
449 | i2c_mark_adapter_suspended(adap: &i_dev->adapter); |
450 | |
451 | return dw_i2c_plat_runtime_suspend(dev); |
452 | } |
453 | |
454 | static int dw_i2c_plat_runtime_resume(struct device *dev) |
455 | { |
456 | struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); |
457 | |
458 | if (!i_dev->shared_with_punit) |
459 | i2c_dw_prepare_clk(dev: i_dev, prepare: true); |
460 | |
461 | i_dev->init(i_dev); |
462 | |
463 | return 0; |
464 | } |
465 | |
466 | static int dw_i2c_plat_resume(struct device *dev) |
467 | { |
468 | struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); |
469 | |
470 | dw_i2c_plat_runtime_resume(dev); |
471 | i2c_mark_adapter_resumed(adap: &i_dev->adapter); |
472 | |
473 | return 0; |
474 | } |
475 | |
476 | static const struct dev_pm_ops dw_i2c_dev_pm_ops = { |
477 | .prepare = pm_sleep_ptr(dw_i2c_plat_prepare), |
478 | LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) |
479 | RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) |
480 | }; |
481 | |
482 | /* Work with hotplug and coldplug */ |
483 | MODULE_ALIAS("platform:i2c_designware" ); |
484 | |
485 | static struct platform_driver dw_i2c_driver = { |
486 | .probe = dw_i2c_plat_probe, |
487 | .remove_new = dw_i2c_plat_remove, |
488 | .driver = { |
489 | .name = "i2c_designware" , |
490 | .of_match_table = of_match_ptr(dw_i2c_of_match), |
491 | .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), |
492 | .pm = pm_ptr(&dw_i2c_dev_pm_ops), |
493 | }, |
494 | }; |
495 | |
496 | static int __init dw_i2c_init_driver(void) |
497 | { |
498 | return platform_driver_register(&dw_i2c_driver); |
499 | } |
500 | subsys_initcall(dw_i2c_init_driver); |
501 | |
502 | static void __exit dw_i2c_exit_driver(void) |
503 | { |
504 | platform_driver_unregister(&dw_i2c_driver); |
505 | } |
506 | module_exit(dw_i2c_exit_driver); |
507 | |
508 | MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>" ); |
509 | MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter" ); |
510 | MODULE_LICENSE("GPL" ); |
511 | |