linux/drivers/i2c/busses/i2c-pxa-pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * CE4100 PCI-I2C glue code for PXA's driver
   4 * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
   5 *
   6 * The CE4100's I2C device is more or less the same one as found on PXA.
   7 * It does not support slave mode, the register slightly moved. This PCI
   8 * device provides three bars, every contains a single I2C controller.
   9 */
  10#include <linux/init.h>
  11#include <linux/pci.h>
  12#include <linux/platform_device.h>
  13#include <linux/platform_data/i2c-pxa.h>
  14#include <linux/of.h>
  15#include <linux/of_device.h>
  16#include <linux/of_address.h>
  17
  18#define CE4100_PCI_I2C_DEVS     3
  19
  20struct ce4100_devices {
  21        struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
  22};
  23
  24static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
  25{
  26        struct platform_device *pdev;
  27        struct i2c_pxa_platform_data pdata;
  28        struct resource res[2];
  29        struct device_node *child;
  30        static int devnum;
  31        int ret;
  32
  33        memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
  34        memset(&res, 0, sizeof(res));
  35
  36        res[0].flags = IORESOURCE_MEM;
  37        res[0].start = pci_resource_start(dev, bar);
  38        res[0].end = pci_resource_end(dev, bar);
  39
  40        res[1].flags = IORESOURCE_IRQ;
  41        res[1].start = dev->irq;
  42        res[1].end = dev->irq;
  43
  44        for_each_child_of_node(dev->dev.of_node, child) {
  45                const void *prop;
  46                struct resource r;
  47                int ret;
  48
  49                ret = of_address_to_resource(child, 0, &r);
  50                if (ret < 0)
  51                        continue;
  52                if (r.start != res[0].start)
  53                        continue;
  54                if (r.end != res[0].end)
  55                        continue;
  56                if (r.flags != res[0].flags)
  57                        continue;
  58
  59                prop = of_get_property(child, "fast-mode", NULL);
  60                if (prop)
  61                        pdata.fast_mode = 1;
  62
  63                break;
  64        }
  65
  66        if (!child) {
  67                dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
  68                                bar);
  69                ret = -EINVAL;
  70                goto out;
  71        }
  72
  73        pdev = platform_device_alloc("ce4100-i2c", devnum);
  74        if (!pdev) {
  75                of_node_put(child);
  76                ret = -ENOMEM;
  77                goto out;
  78        }
  79        pdev->dev.parent = &dev->dev;
  80        pdev->dev.of_node = child;
  81
  82        ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
  83        if (ret)
  84                goto err;
  85
  86        ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
  87        if (ret)
  88                goto err;
  89
  90        ret = platform_device_add(pdev);
  91        if (ret)
  92                goto err;
  93        devnum++;
  94        return pdev;
  95err:
  96        platform_device_put(pdev);
  97out:
  98        return ERR_PTR(ret);
  99}
 100
 101static int ce4100_i2c_probe(struct pci_dev *dev,
 102                const struct pci_device_id *ent)
 103{
 104        int ret;
 105        int i;
 106        struct ce4100_devices *sds;
 107
 108        ret = pci_enable_device_mem(dev);
 109        if (ret)
 110                return ret;
 111
 112        if (!dev->dev.of_node) {
 113                dev_err(&dev->dev, "Missing device tree node.\n");
 114                return -EINVAL;
 115        }
 116        sds = kzalloc(sizeof(*sds), GFP_KERNEL);
 117        if (!sds) {
 118                ret = -ENOMEM;
 119                goto err_mem;
 120        }
 121
 122        for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
 123                sds->pdev[i] = add_i2c_device(dev, i);
 124                if (IS_ERR(sds->pdev[i])) {
 125                        ret = PTR_ERR(sds->pdev[i]);
 126                        while (--i >= 0)
 127                                platform_device_unregister(sds->pdev[i]);
 128                        goto err_dev_add;
 129                }
 130        }
 131        pci_set_drvdata(dev, sds);
 132        return 0;
 133
 134err_dev_add:
 135        kfree(sds);
 136err_mem:
 137        pci_disable_device(dev);
 138        return ret;
 139}
 140
 141static const struct pci_device_id ce4100_i2c_devices[] = {
 142        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
 143        { },
 144};
 145
 146static struct pci_driver ce4100_i2c_driver = {
 147        .driver = {
 148                .suppress_bind_attrs = true,
 149        },
 150        .name           = "ce4100_i2c",
 151        .id_table       = ce4100_i2c_devices,
 152        .probe          = ce4100_i2c_probe,
 153};
 154builtin_pci_driver(ce4100_i2c_driver);
 155