402 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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/clk-provider.h>12#include <linux/clk.h>13#include <linux/delay.h>14#include <linux/dmi.h>15#include <linux/err.h>16#include <linux/errno.h>17#include <linux/i2c.h>18#include <linux/interrupt.h>19#include <linux/io.h>20#include <linux/kernel.h>21#include <linux/mfd/syscon.h>22#include <linux/module.h>23#include <linux/platform_device.h>24#include <linux/pm.h>25#include <linux/pm_runtime.h>26#include <linux/property.h>27#include <linux/regmap.h>28#include <linux/reset.h>29#include <linux/sched.h>30#include <linux/slab.h>31#include <linux/units.h>32 33#include "i2c-designware-core.h"34 35static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)36{37 return clk_get_rate(dev->clk) / KILO;38}39 40#ifdef CONFIG_OF41#define BT1_I2C_CTL 0x10042#define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0)43#define BT1_I2C_CTL_WR BIT(8)44#define BT1_I2C_CTL_GO BIT(31)45#define BT1_I2C_DI 0x10446#define BT1_I2C_DO 0x10847 48static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)49{50 struct dw_i2c_dev *dev = context;51 int ret;52 53 /*54 * Note these methods shouldn't ever fail because the system controller55 * registers are memory mapped. We check the return value just in case.56 */57 ret = regmap_write(dev->sysmap, BT1_I2C_CTL,58 BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));59 if (ret)60 return ret;61 62 return regmap_read(dev->sysmap, BT1_I2C_DO, val);63}64 65static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)66{67 struct dw_i2c_dev *dev = context;68 int ret;69 70 ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);71 if (ret)72 return ret;73 74 return regmap_write(dev->sysmap, BT1_I2C_CTL,75 BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));76}77 78static const struct regmap_config bt1_i2c_cfg = {79 .reg_bits = 32,80 .val_bits = 32,81 .reg_stride = 4,82 .fast_io = true,83 .reg_read = bt1_i2c_read,84 .reg_write = bt1_i2c_write,85 .max_register = DW_IC_COMP_TYPE,86};87 88static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)89{90 dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);91 if (IS_ERR(dev->sysmap))92 return PTR_ERR(dev->sysmap);93 94 dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);95 return PTR_ERR_OR_ZERO(dev->map);96}97#else98static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)99{100 return -ENODEV;101}102#endif103 104static int txgbe_i2c_request_regs(struct dw_i2c_dev *dev)105{106 dev->map = dev_get_regmap(dev->dev->parent, NULL);107 if (!dev->map)108 return -ENODEV;109 110 return 0;111}112 113static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)114{115 pm_runtime_disable(dev->dev);116 117 if (dev->shared_with_punit)118 pm_runtime_put_noidle(dev->dev);119}120 121static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)122{123 struct platform_device *pdev = to_platform_device(dev->dev);124 int ret;125 126 switch (dev->flags & MODEL_MASK) {127 case MODEL_BAIKAL_BT1:128 ret = bt1_i2c_request_regs(dev);129 break;130 case MODEL_WANGXUN_SP:131 ret = txgbe_i2c_request_regs(dev);132 break;133 default:134 dev->base = devm_platform_ioremap_resource(pdev, 0);135 ret = PTR_ERR_OR_ZERO(dev->base);136 break;137 }138 139 return ret;140}141 142static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {143 {144 .ident = "Qtechnology QT5222",145 .matches = {146 DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology"),147 DMI_MATCH(DMI_PRODUCT_NAME, "QT5222"),148 },149 },150 { } /* terminate list */151};152 153static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = {154#ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL155 {156 .probe = i2c_dw_baytrail_probe_lock_support,157 },158#endif159#ifdef CONFIG_I2C_DESIGNWARE_AMDPSP160 {161 .probe = i2c_dw_amdpsp_probe_lock_support,162 },163#endif164 {}165};166 167static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)168{169 const struct i2c_dw_semaphore_callbacks *ptr;170 int i = 0;171 int ret;172 173 dev->semaphore_idx = -1;174 175 for (ptr = i2c_dw_semaphore_cb_table; ptr->probe; ptr++) {176 ret = ptr->probe(dev);177 if (ret) {178 /*179 * If there is no semaphore device attached to this180 * controller, we shouldn't abort general i2c_controller181 * probe.182 */183 if (ret != -ENODEV)184 return ret;185 186 i++;187 continue;188 }189 190 dev->semaphore_idx = i;191 break;192 }193 194 return 0;195}196 197static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev)198{199 if (dev->semaphore_idx < 0)200 return;201 202 if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove)203 i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev);204}205 206static int dw_i2c_plat_probe(struct platform_device *pdev)207{208 struct i2c_adapter *adap;209 struct dw_i2c_dev *dev;210 int irq, ret;211 212 irq = platform_get_irq(pdev, 0);213 if (irq < 0)214 return irq;215 216 dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);217 if (!dev)218 return -ENOMEM;219 220 dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);221 if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))222 dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING;223 224 dev->dev = &pdev->dev;225 dev->irq = irq;226 platform_set_drvdata(pdev, dev);227 228 ret = dw_i2c_plat_request_regs(dev);229 if (ret)230 return ret;231 232 dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);233 if (IS_ERR(dev->rst))234 return PTR_ERR(dev->rst);235 236 reset_control_deassert(dev->rst);237 238 ret = i2c_dw_fw_parse_and_configure(dev);239 if (ret)240 goto exit_reset;241 242 ret = i2c_dw_probe_lock_support(dev);243 if (ret)244 goto exit_reset;245 246 i2c_dw_configure(dev);247 248 /* Optional interface clock */249 dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");250 if (IS_ERR(dev->pclk)) {251 ret = PTR_ERR(dev->pclk);252 goto exit_reset;253 }254 255 dev->clk = devm_clk_get_optional(&pdev->dev, NULL);256 if (IS_ERR(dev->clk)) {257 ret = PTR_ERR(dev->clk);258 goto exit_reset;259 }260 261 ret = i2c_dw_prepare_clk(dev, true);262 if (ret)263 goto exit_reset;264 265 if (dev->clk) {266 struct i2c_timings *t = &dev->timings;267 u64 clk_khz;268 269 dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;270 clk_khz = dev->get_clk_rate_khz(dev);271 272 if (!dev->sda_hold_time && t->sda_hold_ns)273 dev->sda_hold_time =274 DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO);275 }276 277 adap = &dev->adapter;278 adap->owner = THIS_MODULE;279 adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?280 I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;281 adap->nr = -1;282 283 if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {284 dev_pm_set_driver_flags(&pdev->dev,285 DPM_FLAG_SMART_PREPARE);286 } else {287 dev_pm_set_driver_flags(&pdev->dev,288 DPM_FLAG_SMART_PREPARE |289 DPM_FLAG_SMART_SUSPEND);290 }291 292 device_enable_async_suspend(&pdev->dev);293 294 /* The code below assumes runtime PM to be disabled. */295 WARN_ON(pm_runtime_enabled(&pdev->dev));296 297 pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);298 pm_runtime_use_autosuspend(&pdev->dev);299 pm_runtime_set_active(&pdev->dev);300 301 if (dev->shared_with_punit)302 pm_runtime_get_noresume(&pdev->dev);303 304 pm_runtime_enable(&pdev->dev);305 306 ret = i2c_dw_probe(dev);307 if (ret)308 goto exit_probe;309 310 return ret;311 312exit_probe:313 dw_i2c_plat_pm_cleanup(dev);314exit_reset:315 reset_control_assert(dev->rst);316 return ret;317}318 319static void dw_i2c_plat_remove(struct platform_device *pdev)320{321 struct dw_i2c_dev *dev = platform_get_drvdata(pdev);322 323 pm_runtime_get_sync(&pdev->dev);324 325 i2c_del_adapter(&dev->adapter);326 327 i2c_dw_disable(dev);328 329 pm_runtime_dont_use_autosuspend(&pdev->dev);330 pm_runtime_put_sync(&pdev->dev);331 dw_i2c_plat_pm_cleanup(dev);332 333 i2c_dw_remove_lock_support(dev);334 335 reset_control_assert(dev->rst);336}337 338static const struct of_device_id dw_i2c_of_match[] = {339 { .compatible = "snps,designware-i2c", },340 { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },341 { .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },342 {}343};344MODULE_DEVICE_TABLE(of, dw_i2c_of_match);345 346static const struct acpi_device_id dw_i2c_acpi_match[] = {347 { "80860F41", ACCESS_NO_IRQ_SUSPEND },348 { "808622C1", ACCESS_NO_IRQ_SUSPEND },349 { "AMD0010", ACCESS_INTR_MASK },350 { "AMDI0010", ACCESS_INTR_MASK },351 { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE },352 { "AMDI0510", 0 },353 { "APMC0D0F", 0 },354 { "HISI02A1", 0 },355 { "HISI02A2", 0 },356 { "HISI02A3", 0 },357 { "HYGO0010", ACCESS_INTR_MASK },358 { "INT33C2", 0 },359 { "INT33C3", 0 },360 { "INT3432", 0 },361 { "INT3433", 0 },362 { "INTC10EF", 0 },363 {}364};365MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);366 367static const struct platform_device_id dw_i2c_platform_ids[] = {368 { "i2c_designware" },369 {}370};371MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids);372 373static struct platform_driver dw_i2c_driver = {374 .probe = dw_i2c_plat_probe,375 .remove_new = dw_i2c_plat_remove,376 .driver = {377 .name = "i2c_designware",378 .of_match_table = dw_i2c_of_match,379 .acpi_match_table = dw_i2c_acpi_match,380 .pm = pm_ptr(&i2c_dw_dev_pm_ops),381 },382 .id_table = dw_i2c_platform_ids,383};384 385static int __init dw_i2c_init_driver(void)386{387 return platform_driver_register(&dw_i2c_driver);388}389subsys_initcall(dw_i2c_init_driver);390 391static void __exit dw_i2c_exit_driver(void)392{393 platform_driver_unregister(&dw_i2c_driver);394}395module_exit(dw_i2c_exit_driver);396 397MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");398MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");399MODULE_LICENSE("GPL");400MODULE_IMPORT_NS(I2C_DW);401MODULE_IMPORT_NS(I2C_DW_COMMON);402