linux/drivers/i2c/busses/i2c-designware-platdrv.c
<<
>>
Prefs
   1/*
   2 * Synopsys DesignWare I2C adapter driver (master only).
   3 *
   4 * Based on the TI DAVINCI I2C adapter driver.
   5 *
   6 * Copyright (C) 2006 Texas Instruments.
   7 * Copyright (C) 2007 MontaVista Software Inc.
   8 * Copyright (C) 2009 Provigent Ltd.
   9 *
  10 * ----------------------------------------------------------------------------
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 * ----------------------------------------------------------------------------
  22 *
  23 */
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/delay.h>
  27#include <linux/dmi.h>
  28#include <linux/i2c.h>
  29#include <linux/clk.h>
  30#include <linux/clk-provider.h>
  31#include <linux/errno.h>
  32#include <linux/sched.h>
  33#include <linux/err.h>
  34#include <linux/interrupt.h>
  35#include <linux/of.h>
  36#include <linux/platform_device.h>
  37#include <linux/pm.h>
  38#include <linux/pm_runtime.h>
  39#include <linux/io.h>
  40#include <linux/slab.h>
  41#include <linux/acpi.h>
  42#include <linux/platform_data/i2c-designware.h>
  43#include "i2c-designware-core.h"
  44
  45static struct i2c_algorithm i2c_dw_algo = {
  46        .master_xfer    = i2c_dw_xfer,
  47        .functionality  = i2c_dw_func,
  48};
  49static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
  50{
  51        return clk_get_rate(dev->clk)/1000;
  52}
  53
  54#ifdef CONFIG_ACPI
  55/*
  56 * The HCNT/LCNT information coming from ACPI should be the most accurate
  57 * for given platform. However, some systems get it wrong. On such systems
  58 * we get better results by calculating those based on the input clock.
  59 */
  60static const struct dmi_system_id dw_i2c_no_acpi_params[] = {
  61        {
  62                .ident = "Dell Inspiron 7348",
  63                .matches = {
  64                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
  65                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7348"),
  66                },
  67        },
  68        { }
  69};
  70
  71static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
  72                               u16 *hcnt, u16 *lcnt, u32 *sda_hold)
  73{
  74        struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
  75        acpi_handle handle = ACPI_HANDLE(&pdev->dev);
  76        union acpi_object *obj;
  77
  78        if (dmi_check_system(dw_i2c_no_acpi_params))
  79                return;
  80
  81        if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
  82                return;
  83
  84        obj = (union acpi_object *)buf.pointer;
  85        if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
  86                const union acpi_object *objs = obj->package.elements;
  87
  88                *hcnt = (u16)objs[0].integer.value;
  89                *lcnt = (u16)objs[1].integer.value;
  90                if (sda_hold)
  91                        *sda_hold = (u32)objs[2].integer.value;
  92        }
  93
  94        kfree(buf.pointer);
  95}
  96
  97static int dw_i2c_acpi_configure(struct platform_device *pdev)
  98{
  99        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 100        const struct acpi_device_id *id;
 101
 102        dev->adapter.nr = -1;
 103        dev->tx_fifo_depth = 32;
 104        dev->rx_fifo_depth = 32;
 105
 106        /*
 107         * Try to get SDA hold time and *CNT values from an ACPI method if
 108         * it exists for both supported speed modes.
 109         */
 110        dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL);
 111        dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
 112                           &dev->sda_hold_time);
 113
 114        /*
 115         * Provide a way for Designware I2C host controllers that are not
 116         * based on Intel LPSS to specify their input clock frequency via
 117         * id->driver_data.
 118         */
 119        id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
 120        if (id && id->driver_data)
 121                clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL,
 122                                        CLK_IS_ROOT, id->driver_data);
 123
 124        return 0;
 125}
 126
 127static void dw_i2c_acpi_unconfigure(struct platform_device *pdev)
 128{
 129        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 130        const struct acpi_device_id *id;
 131
 132        id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
 133        if (id && id->driver_data)
 134                clk_unregister(dev->clk);
 135}
 136
 137static const struct acpi_device_id dw_i2c_acpi_match[] = {
 138        { "INT33C2", 0 },
 139        { "INT33C3", 0 },
 140        { "INT3432", 0 },
 141        { "INT3433", 0 },
 142        { "80860F41", 0 },
 143        { "808622C1", 0 },
 144        { "AMD0010", 133 * 1000 * 1000 },
 145        { }
 146};
 147MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
 148#else
 149static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
 150{
 151        return -ENODEV;
 152}
 153static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { }
 154#endif
 155
 156static int dw_i2c_probe(struct platform_device *pdev)
 157{
 158        struct dw_i2c_dev *dev;
 159        struct i2c_adapter *adap;
 160        struct resource *mem;
 161        struct dw_i2c_platform_data *pdata;
 162        int irq, r;
 163        u32 clk_freq, ht = 0;
 164
 165        irq = platform_get_irq(pdev, 0);
 166        if (irq < 0)
 167                return irq;
 168
 169        dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
 170        if (!dev)
 171                return -ENOMEM;
 172
 173        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 174        dev->base = devm_ioremap_resource(&pdev->dev, mem);
 175        if (IS_ERR(dev->base))
 176                return PTR_ERR(dev->base);
 177
 178        init_completion(&dev->cmd_complete);
 179        mutex_init(&dev->lock);
 180        dev->dev = &pdev->dev;
 181        dev->irq = irq;
 182        platform_set_drvdata(pdev, dev);
 183
 184        /* fast mode by default because of legacy reasons */
 185        clk_freq = 400000;
 186
 187        if (has_acpi_companion(&pdev->dev)) {
 188                dw_i2c_acpi_configure(pdev);
 189        } else if (pdev->dev.of_node) {
 190                of_property_read_u32(pdev->dev.of_node,
 191                                        "i2c-sda-hold-time-ns", &ht);
 192
 193                of_property_read_u32(pdev->dev.of_node,
 194                                     "i2c-sda-falling-time-ns",
 195                                     &dev->sda_falling_time);
 196                of_property_read_u32(pdev->dev.of_node,
 197                                     "i2c-scl-falling-time-ns",
 198                                     &dev->scl_falling_time);
 199
 200                of_property_read_u32(pdev->dev.of_node, "clock-frequency",
 201                                     &clk_freq);
 202
 203                /* Only standard mode at 100kHz and fast mode at 400kHz
 204                 * are supported.
 205                 */
 206                if (clk_freq != 100000 && clk_freq != 400000) {
 207                        dev_err(&pdev->dev, "Only 100kHz and 400kHz supported");
 208                        return -EINVAL;
 209                }
 210        } else {
 211                pdata = dev_get_platdata(&pdev->dev);
 212                if (pdata)
 213                        clk_freq = pdata->i2c_scl_freq;
 214        }
 215
 216        r = i2c_dw_eval_lock_support(dev);
 217        if (r)
 218                return r;
 219
 220        dev->functionality =
 221                I2C_FUNC_I2C |
 222                I2C_FUNC_10BIT_ADDR |
 223                I2C_FUNC_SMBUS_BYTE |
 224                I2C_FUNC_SMBUS_BYTE_DATA |
 225                I2C_FUNC_SMBUS_WORD_DATA |
 226                I2C_FUNC_SMBUS_I2C_BLOCK;
 227        if (clk_freq == 100000)
 228                dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
 229                        DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_STD;
 230        else
 231                dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
 232                        DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
 233
 234        dev->clk = devm_clk_get(&pdev->dev, NULL);
 235        dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
 236        if (IS_ERR(dev->clk))
 237                return PTR_ERR(dev->clk);
 238        clk_prepare_enable(dev->clk);
 239
 240        if (!dev->sda_hold_time && ht) {
 241                u32 ic_clk = dev->get_clk_rate_khz(dev);
 242
 243                dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
 244                                             1000000);
 245        }
 246
 247        if (!dev->tx_fifo_depth) {
 248                u32 param1 = i2c_dw_read_comp_param(dev);
 249
 250                dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
 251                dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
 252                dev->adapter.nr = pdev->id;
 253        }
 254        r = i2c_dw_init(dev);
 255        if (r)
 256                return r;
 257
 258        i2c_dw_disable_int(dev);
 259        r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
 260                        pdev->name, dev);
 261        if (r) {
 262                dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
 263                return r;
 264        }
 265
 266        adap = &dev->adapter;
 267        i2c_set_adapdata(adap, dev);
 268        adap->owner = THIS_MODULE;
 269        adap->class = I2C_CLASS_DEPRECATED;
 270        strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
 271                        sizeof(adap->name));
 272        adap->algo = &i2c_dw_algo;
 273        adap->dev.parent = &pdev->dev;
 274        adap->dev.of_node = pdev->dev.of_node;
 275
 276        if (dev->pm_runtime_disabled) {
 277                pm_runtime_forbid(&pdev->dev);
 278        } else {
 279                pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
 280                pm_runtime_use_autosuspend(&pdev->dev);
 281                pm_runtime_set_active(&pdev->dev);
 282                pm_runtime_enable(&pdev->dev);
 283        }
 284
 285        r = i2c_add_numbered_adapter(adap);
 286        if (r) {
 287                dev_err(&pdev->dev, "failure adding adapter\n");
 288                pm_runtime_disable(&pdev->dev);
 289                return r;
 290        }
 291
 292        return 0;
 293}
 294
 295static int dw_i2c_remove(struct platform_device *pdev)
 296{
 297        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
 298
 299        pm_runtime_get_sync(&pdev->dev);
 300
 301        i2c_del_adapter(&dev->adapter);
 302
 303        i2c_dw_disable(dev);
 304
 305        pm_runtime_dont_use_autosuspend(&pdev->dev);
 306        pm_runtime_put_sync(&pdev->dev);
 307        pm_runtime_disable(&pdev->dev);
 308
 309        if (has_acpi_companion(&pdev->dev))
 310                dw_i2c_acpi_unconfigure(pdev);
 311
 312        return 0;
 313}
 314
 315#ifdef CONFIG_OF
 316static const struct of_device_id dw_i2c_of_match[] = {
 317        { .compatible = "snps,designware-i2c", },
 318        {},
 319};
 320MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
 321#endif
 322
 323#ifdef CONFIG_PM_SLEEP
 324static int dw_i2c_prepare(struct device *dev)
 325{
 326        return pm_runtime_suspended(dev);
 327}
 328
 329static void dw_i2c_complete(struct device *dev)
 330{
 331        if (dev->power.direct_complete)
 332                pm_request_resume(dev);
 333}
 334#else
 335#define dw_i2c_prepare  NULL
 336#define dw_i2c_complete NULL
 337#endif
 338
 339#ifdef CONFIG_PM
 340static int dw_i2c_suspend(struct device *dev)
 341{
 342        struct platform_device *pdev = to_platform_device(dev);
 343        struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
 344
 345        i2c_dw_disable(i_dev);
 346        clk_disable_unprepare(i_dev->clk);
 347
 348        return 0;
 349}
 350
 351static int dw_i2c_resume(struct device *dev)
 352{
 353        struct platform_device *pdev = to_platform_device(dev);
 354        struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
 355
 356        clk_prepare_enable(i_dev->clk);
 357
 358        if (!i_dev->pm_runtime_disabled)
 359                i2c_dw_init(i_dev);
 360
 361        return 0;
 362}
 363
 364static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
 365        .prepare = dw_i2c_prepare,
 366        .complete = dw_i2c_complete,
 367        SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume)
 368        SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL)
 369};
 370
 371#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
 372#else
 373#define DW_I2C_DEV_PMOPS NULL
 374#endif
 375
 376/* work with hotplug and coldplug */
 377MODULE_ALIAS("platform:i2c_designware");
 378
 379static struct platform_driver dw_i2c_driver = {
 380        .probe = dw_i2c_probe,
 381        .remove = dw_i2c_remove,
 382        .driver         = {
 383                .name   = "i2c_designware",
 384                .of_match_table = of_match_ptr(dw_i2c_of_match),
 385                .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
 386                .pm     = DW_I2C_DEV_PMOPS,
 387        },
 388};
 389
 390static int __init dw_i2c_init_driver(void)
 391{
 392        return platform_driver_register(&dw_i2c_driver);
 393}
 394subsys_initcall(dw_i2c_init_driver);
 395
 396static void __exit dw_i2c_exit_driver(void)
 397{
 398        platform_driver_unregister(&dw_i2c_driver);
 399}
 400module_exit(dw_i2c_exit_driver);
 401
 402MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
 403MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
 404MODULE_LICENSE("GPL");
 405