linux/drivers/i2c/busses/i2c-designware-platdrv.c
<<
>>
Prefs
   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
  35#include "i2c-designware-core.h"
  36
  37static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
  38{
  39        return clk_get_rate(dev->clk)/1000;
  40}
  41
  42#ifdef CONFIG_ACPI
  43static const struct acpi_device_id dw_i2c_acpi_match[] = {
  44        { "INT33C2", 0 },
  45        { "INT33C3", 0 },
  46        { "INT3432", 0 },
  47        { "INT3433", 0 },
  48        { "80860F41", ACCESS_NO_IRQ_SUSPEND },
  49        { "808622C1", ACCESS_NO_IRQ_SUSPEND },
  50        { "AMD0010", ACCESS_INTR_MASK },
  51        { "AMDI0010", ACCESS_INTR_MASK },
  52        { "AMDI0510", 0 },
  53        { "APMC0D0F", 0 },
  54        { "HISI02A1", 0 },
  55        { "HISI02A2", 0 },
  56        { "HISI02A3", 0 },
  57        { "HYGO0010", ACCESS_INTR_MASK },
  58        { }
  59};
  60MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
  61#endif
  62
  63#ifdef CONFIG_OF
  64#define BT1_I2C_CTL                     0x100
  65#define BT1_I2C_CTL_ADDR_MASK           GENMASK(7, 0)
  66#define BT1_I2C_CTL_WR                  BIT(8)
  67#define BT1_I2C_CTL_GO                  BIT(31)
  68#define BT1_I2C_DI                      0x104
  69#define BT1_I2C_DO                      0x108
  70
  71static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
  72{
  73        struct dw_i2c_dev *dev = context;
  74        int ret;
  75
  76        /*
  77         * Note these methods shouldn't ever fail because the system controller
  78         * registers are memory mapped. We check the return value just in case.
  79         */
  80        ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
  81                           BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
  82        if (ret)
  83                return ret;
  84
  85        return regmap_read(dev->sysmap, BT1_I2C_DO, val);
  86}
  87
  88static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
  89{
  90        struct dw_i2c_dev *dev = context;
  91        int ret;
  92
  93        ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
  94        if (ret)
  95                return ret;
  96
  97        return regmap_write(dev->sysmap, BT1_I2C_CTL,
  98                BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
  99}
 100
 101static struct regmap_config bt1_i2c_cfg = {
 102        .reg_bits = 32,
 103        .val_bits = 32,
 104        .reg_stride = 4,
 105        .fast_io = true,
 106        .reg_read = bt1_i2c_read,
 107        .reg_write = bt1_i2c_write,
 108        .max_register = DW_IC_COMP_TYPE,
 109};
 110
 111static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
 112{
 113        dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
 114        if (IS_ERR(dev->sysmap))
 115                return PTR_ERR(dev->sysmap);
 116
 117        dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
 118        return PTR_ERR_OR_ZERO(dev->map);
 119}
 120
 121#define MSCC_ICPU_CFG_TWI_DELAY         0x0
 122#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE  BIT(0)
 123#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER  0x4
 124
 125static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
 126{
 127        writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
 128               dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
 129
 130        return 0;
 131}
 132
 133static int dw_i2c_of_configure(struct platform_device *pdev)
 134{
 135        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 136
 137        switch (dev->flags & MODEL_MASK) {
 138        case MODEL_MSCC_OCELOT:
 139                dev->ext = devm_platform_ioremap_resource(pdev, 1);
 140                if (!IS_ERR(dev->ext))
 141                        dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
 142                break;
 143        default:
 144                break;
 145        }
 146
 147        return 0;
 148}
 149
 150static const struct of_device_id dw_i2c_of_match[] = {
 151        { .compatible = "snps,designware-i2c", },
 152        { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
 153        { .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
 154        {},
 155};
 156MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
 157#else
 158static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
 159{
 160        return -ENODEV;
 161}
 162
 163static inline int dw_i2c_of_configure(struct platform_device *pdev)
 164{
 165        return -ENODEV;
 166}
 167#endif
 168
 169static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
 170{
 171        pm_runtime_disable(dev->dev);
 172
 173        if (dev->shared_with_punit)
 174                pm_runtime_put_noidle(dev->dev);
 175}
 176
 177static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
 178{
 179        struct platform_device *pdev = to_platform_device(dev->dev);
 180        int ret;
 181
 182        switch (dev->flags & MODEL_MASK) {
 183        case MODEL_BAIKAL_BT1:
 184                ret = bt1_i2c_request_regs(dev);
 185                break;
 186        default:
 187                dev->base = devm_platform_ioremap_resource(pdev, 0);
 188                ret = PTR_ERR_OR_ZERO(dev->base);
 189                break;
 190        }
 191
 192        return ret;
 193}
 194
 195static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
 196        {
 197                .ident = "Qtechnology QT5222",
 198                .matches = {
 199                        DMI_MATCH(DMI_SYS_VENDOR, "Qtechnology"),
 200                        DMI_MATCH(DMI_PRODUCT_NAME, "QT5222"),
 201                },
 202        },
 203        { } /* terminate list */
 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        struct i2c_timings *t;
 211        int irq, ret;
 212
 213        irq = platform_get_irq(pdev, 0);
 214        if (irq < 0)
 215                return irq;
 216
 217        dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
 218        if (!dev)
 219                return -ENOMEM;
 220
 221        dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
 222        dev->dev = &pdev->dev;
 223        dev->irq = irq;
 224        platform_set_drvdata(pdev, dev);
 225
 226        ret = dw_i2c_plat_request_regs(dev);
 227        if (ret)
 228                return ret;
 229
 230        dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
 231        if (IS_ERR(dev->rst))
 232                return PTR_ERR(dev->rst);
 233
 234        reset_control_deassert(dev->rst);
 235
 236        t = &dev->timings;
 237        i2c_parse_fw_timings(&pdev->dev, t, false);
 238
 239        i2c_dw_adjust_bus_speed(dev);
 240
 241        if (pdev->dev.of_node)
 242                dw_i2c_of_configure(pdev);
 243
 244        if (has_acpi_companion(&pdev->dev))
 245                i2c_dw_acpi_configure(&pdev->dev);
 246
 247        ret = i2c_dw_validate_speed(dev);
 248        if (ret)
 249                goto exit_reset;
 250
 251        ret = i2c_dw_probe_lock_support(dev);
 252        if (ret)
 253                goto exit_reset;
 254
 255        i2c_dw_configure(dev);
 256
 257        /* Optional interface clock */
 258        dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
 259        if (IS_ERR(dev->pclk)) {
 260                ret = PTR_ERR(dev->pclk);
 261                goto exit_reset;
 262        }
 263
 264        dev->clk = devm_clk_get(&pdev->dev, NULL);
 265        if (!i2c_dw_prepare_clk(dev, true)) {
 266                u64 clk_khz;
 267
 268                dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
 269                clk_khz = dev->get_clk_rate_khz(dev);
 270
 271                if (!dev->sda_hold_time && t->sda_hold_ns)
 272                        dev->sda_hold_time =
 273                                div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000);
 274        }
 275
 276        adap = &dev->adapter;
 277        adap->owner = THIS_MODULE;
 278        adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ?
 279                                        I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED;
 280        ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
 281        adap->dev.of_node = pdev->dev.of_node;
 282        adap->nr = -1;
 283
 284        if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
 285                dev_pm_set_driver_flags(&pdev->dev,
 286                                        DPM_FLAG_SMART_PREPARE |
 287                                        DPM_FLAG_MAY_SKIP_RESUME);
 288        } else {
 289                dev_pm_set_driver_flags(&pdev->dev,
 290                                        DPM_FLAG_SMART_PREPARE |
 291                                        DPM_FLAG_SMART_SUSPEND |
 292                                        DPM_FLAG_MAY_SKIP_RESUME);
 293        }
 294
 295        /* The code below assumes runtime PM to be disabled. */
 296        WARN_ON(pm_runtime_enabled(&pdev->dev));
 297
 298        pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
 299        pm_runtime_use_autosuspend(&pdev->dev);
 300        pm_runtime_set_active(&pdev->dev);
 301
 302        if (dev->shared_with_punit)
 303                pm_runtime_get_noresume(&pdev->dev);
 304
 305        pm_runtime_enable(&pdev->dev);
 306
 307        ret = i2c_dw_probe(dev);
 308        if (ret)
 309                goto exit_probe;
 310
 311        return ret;
 312
 313exit_probe:
 314        dw_i2c_plat_pm_cleanup(dev);
 315exit_reset:
 316        reset_control_assert(dev->rst);
 317        return ret;
 318}
 319
 320static int dw_i2c_plat_remove(struct platform_device *pdev)
 321{
 322        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 323
 324        pm_runtime_get_sync(&pdev->dev);
 325
 326        i2c_del_adapter(&dev->adapter);
 327
 328        dev->disable(dev);
 329
 330        pm_runtime_dont_use_autosuspend(&pdev->dev);
 331        pm_runtime_put_sync(&pdev->dev);
 332        dw_i2c_plat_pm_cleanup(dev);
 333
 334        reset_control_assert(dev->rst);
 335
 336        return 0;
 337}
 338
 339#ifdef CONFIG_PM_SLEEP
 340static int dw_i2c_plat_prepare(struct device *dev)
 341{
 342        /*
 343         * If the ACPI companion device object is present for this device, it
 344         * may be accessed during suspend and resume of other devices via I2C
 345         * operation regions, so tell the PM core and middle layers to avoid
 346         * skipping system suspend/resume callbacks for it in that case.
 347         */
 348        return !has_acpi_companion(dev);
 349}
 350
 351static void dw_i2c_plat_complete(struct device *dev)
 352{
 353        /*
 354         * The device can only be in runtime suspend at this point if it has not
 355         * been resumed throughout the ending system suspend/resume cycle, so if
 356         * the platform firmware might mess up with it, request the runtime PM
 357         * framework to resume it.
 358         */
 359        if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
 360                pm_request_resume(dev);
 361}
 362#else
 363#define dw_i2c_plat_prepare     NULL
 364#define dw_i2c_plat_complete    NULL
 365#endif
 366
 367#ifdef CONFIG_PM
 368static int dw_i2c_plat_suspend(struct device *dev)
 369{
 370        struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
 371
 372        i_dev->suspended = true;
 373
 374        if (i_dev->shared_with_punit)
 375                return 0;
 376
 377        i_dev->disable(i_dev);
 378        i2c_dw_prepare_clk(i_dev, false);
 379
 380        return 0;
 381}
 382
 383static int dw_i2c_plat_resume(struct device *dev)
 384{
 385        struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
 386
 387        if (!i_dev->shared_with_punit)
 388                i2c_dw_prepare_clk(i_dev, true);
 389
 390        i_dev->init(i_dev);
 391        i_dev->suspended = false;
 392
 393        return 0;
 394}
 395
 396static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 397        .prepare = dw_i2c_plat_prepare,
 398        .complete = dw_i2c_plat_complete,
 399        SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
 400        SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
 401};
 402
 403#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
 404#else
 405#define DW_I2C_DEV_PMOPS NULL
 406#endif
 407
 408/* Work with hotplug and coldplug */
 409MODULE_ALIAS("platform:i2c_designware");
 410
 411static struct platform_driver dw_i2c_driver = {
 412        .probe = dw_i2c_plat_probe,
 413        .remove = dw_i2c_plat_remove,
 414        .driver         = {
 415                .name   = "i2c_designware",
 416                .of_match_table = of_match_ptr(dw_i2c_of_match),
 417                .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
 418                .pm     = DW_I2C_DEV_PMOPS,
 419        },
 420};
 421
 422static int __init dw_i2c_init_driver(void)
 423{
 424        return platform_driver_register(&dw_i2c_driver);
 425}
 426subsys_initcall(dw_i2c_init_driver);
 427
 428static void __exit dw_i2c_exit_driver(void)
 429{
 430        platform_driver_unregister(&dw_i2c_driver);
 431}
 432module_exit(dw_i2c_exit_driver);
 433
 434MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
 435MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
 436MODULE_LICENSE("GPL");
 437