linux/drivers/mfd/intel_quark_i2c_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Intel Quark MFD PCI driver for I2C & GPIO
   4 *
   5 * Copyright(c) 2014 Intel Corporation.
   6 *
   7 * Intel Quark PCI device for I2C and GPIO controller sharing the same
   8 * PCI function. This PCI driver will split the 2 devices into their
   9 * respective drivers.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/pci.h>
  15#include <linux/mfd/core.h>
  16#include <linux/clkdev.h>
  17#include <linux/clk-provider.h>
  18#include <linux/dmi.h>
  19#include <linux/i2c.h>
  20#include <linux/platform_data/gpio-dwapb.h>
  21#include <linux/property.h>
  22
  23/* PCI BAR for register base address */
  24#define MFD_I2C_BAR             0
  25#define MFD_GPIO_BAR            1
  26
  27/* ACPI _ADR value to match the child node */
  28#define MFD_ACPI_MATCH_GPIO     0ULL
  29#define MFD_ACPI_MATCH_I2C      1ULL
  30
  31/* The base GPIO number under GPIOLIB framework */
  32#define INTEL_QUARK_MFD_GPIO_BASE       8
  33
  34/* The default number of South-Cluster GPIO on Quark. */
  35#define INTEL_QUARK_MFD_NGPIO           8
  36
  37/* The DesignWare GPIO ports on Quark. */
  38#define INTEL_QUARK_GPIO_NPORTS 1
  39
  40#define INTEL_QUARK_IORES_MEM   0
  41#define INTEL_QUARK_IORES_IRQ   1
  42
  43#define INTEL_QUARK_I2C_CONTROLLER_CLK "i2c_designware.0"
  44
  45/* The Quark I2C controller source clock */
  46#define INTEL_QUARK_I2C_CLK_HZ  33000000
  47
  48struct intel_quark_mfd {
  49        struct clk              *i2c_clk;
  50        struct clk_lookup       *i2c_clk_lookup;
  51};
  52
  53static const struct property_entry intel_quark_i2c_controller_standard_properties[] = {
  54        PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ),
  55        { }
  56};
  57
  58static const struct software_node intel_quark_i2c_controller_standard_node = {
  59        .name = "intel-quark-i2c-controller",
  60        .properties = intel_quark_i2c_controller_standard_properties,
  61};
  62
  63static const struct property_entry intel_quark_i2c_controller_fast_properties[] = {
  64        PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ),
  65        { }
  66};
  67
  68static const struct software_node intel_quark_i2c_controller_fast_node = {
  69        .name = "intel-quark-i2c-controller",
  70        .properties = intel_quark_i2c_controller_fast_properties,
  71};
  72
  73static const struct dmi_system_id dmi_platform_info[] = {
  74        {
  75                .matches = {
  76                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
  77                },
  78                .driver_data = (void *)&intel_quark_i2c_controller_standard_node,
  79        },
  80        {
  81                .matches = {
  82                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
  83                },
  84                .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
  85        },
  86        {
  87                .matches = {
  88                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
  89                },
  90                .driver_data = (void *)&intel_quark_i2c_controller_fast_node,
  91        },
  92        {}
  93};
  94
  95/* This is used as a place holder and will be modified at run-time */
  96static struct resource intel_quark_i2c_res[] = {
  97        [INTEL_QUARK_IORES_MEM] = {
  98                .flags = IORESOURCE_MEM,
  99        },
 100        [INTEL_QUARK_IORES_IRQ] = {
 101                .flags = IORESOURCE_IRQ,
 102        },
 103};
 104
 105static struct mfd_cell_acpi_match intel_quark_acpi_match_i2c = {
 106        .adr = MFD_ACPI_MATCH_I2C,
 107};
 108
 109/* This is used as a place holder and will be modified at run-time */
 110static struct resource intel_quark_gpio_res[] = {
 111        [INTEL_QUARK_IORES_MEM] = {
 112                .flags = IORESOURCE_MEM,
 113        },
 114};
 115
 116static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
 117        .adr = MFD_ACPI_MATCH_GPIO,
 118};
 119
 120static struct mfd_cell intel_quark_mfd_cells[] = {
 121        [MFD_I2C_BAR] = {
 122                .id = MFD_I2C_BAR,
 123                .name = "i2c_designware",
 124                .acpi_match = &intel_quark_acpi_match_i2c,
 125                .num_resources = ARRAY_SIZE(intel_quark_i2c_res),
 126                .resources = intel_quark_i2c_res,
 127                .ignore_resource_conflicts = true,
 128        },
 129        [MFD_GPIO_BAR] = {
 130                .id = MFD_GPIO_BAR,
 131                .name = "gpio-dwapb",
 132                .acpi_match = &intel_quark_acpi_match_gpio,
 133                .num_resources = ARRAY_SIZE(intel_quark_gpio_res),
 134                .resources = intel_quark_gpio_res,
 135                .ignore_resource_conflicts = true,
 136        },
 137};
 138
 139static const struct pci_device_id intel_quark_mfd_ids[] = {
 140        { PCI_VDEVICE(INTEL, 0x0934), },
 141        {},
 142};
 143MODULE_DEVICE_TABLE(pci, intel_quark_mfd_ids);
 144
 145static int intel_quark_register_i2c_clk(struct device *dev)
 146{
 147        struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
 148        struct clk *i2c_clk;
 149
 150        i2c_clk = clk_register_fixed_rate(dev,
 151                                          INTEL_QUARK_I2C_CONTROLLER_CLK, NULL,
 152                                          0, INTEL_QUARK_I2C_CLK_HZ);
 153        if (IS_ERR(i2c_clk))
 154                return PTR_ERR(i2c_clk);
 155
 156        quark_mfd->i2c_clk = i2c_clk;
 157        quark_mfd->i2c_clk_lookup = clkdev_create(i2c_clk, NULL,
 158                                                INTEL_QUARK_I2C_CONTROLLER_CLK);
 159
 160        if (!quark_mfd->i2c_clk_lookup) {
 161                clk_unregister(quark_mfd->i2c_clk);
 162                dev_err(dev, "Fixed clk register failed\n");
 163                return -ENOMEM;
 164        }
 165
 166        return 0;
 167}
 168
 169static void intel_quark_unregister_i2c_clk(struct device *dev)
 170{
 171        struct intel_quark_mfd *quark_mfd = dev_get_drvdata(dev);
 172
 173        if (!quark_mfd->i2c_clk_lookup)
 174                return;
 175
 176        clkdev_drop(quark_mfd->i2c_clk_lookup);
 177        clk_unregister(quark_mfd->i2c_clk);
 178}
 179
 180static int intel_quark_i2c_setup(struct pci_dev *pdev)
 181{
 182        struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR];
 183        struct resource *res = intel_quark_i2c_res;
 184        const struct dmi_system_id *dmi_id;
 185
 186        res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR);
 187        res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR);
 188
 189        res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
 190        res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
 191
 192        /* Normal mode by default */
 193        cell->swnode = &intel_quark_i2c_controller_standard_node;
 194
 195        dmi_id = dmi_first_match(dmi_platform_info);
 196        if (dmi_id)
 197                cell->swnode = (struct software_node *)dmi_id->driver_data;
 198
 199        return 0;
 200}
 201
 202static int intel_quark_gpio_setup(struct pci_dev *pdev)
 203{
 204        struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR];
 205        struct resource *res = intel_quark_gpio_res;
 206        struct dwapb_platform_data *pdata;
 207        struct device *dev = &pdev->dev;
 208
 209        res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR);
 210        res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR);
 211
 212        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 213        if (!pdata)
 214                return -ENOMEM;
 215
 216        /* For intel quark x1000, it has only one port: portA */
 217        pdata->nports = INTEL_QUARK_GPIO_NPORTS;
 218        pdata->properties = devm_kcalloc(dev, pdata->nports,
 219                                         sizeof(*pdata->properties),
 220                                         GFP_KERNEL);
 221        if (!pdata->properties)
 222                return -ENOMEM;
 223
 224        /* Set the properties for portA */
 225        pdata->properties->fwnode       = NULL;
 226        pdata->properties->idx          = 0;
 227        pdata->properties->ngpio        = INTEL_QUARK_MFD_NGPIO;
 228        pdata->properties->gpio_base    = INTEL_QUARK_MFD_GPIO_BASE;
 229        pdata->properties->irq[0]       = pci_irq_vector(pdev, 0);
 230        pdata->properties->irq_shared   = true;
 231
 232        cell->platform_data = pdata;
 233        cell->pdata_size = sizeof(*pdata);
 234
 235        return 0;
 236}
 237
 238static int intel_quark_mfd_probe(struct pci_dev *pdev,
 239                                 const struct pci_device_id *id)
 240{
 241        struct intel_quark_mfd *quark_mfd;
 242        int ret;
 243
 244        ret = pcim_enable_device(pdev);
 245        if (ret)
 246                return ret;
 247
 248        quark_mfd = devm_kzalloc(&pdev->dev, sizeof(*quark_mfd), GFP_KERNEL);
 249        if (!quark_mfd)
 250                return -ENOMEM;
 251
 252        dev_set_drvdata(&pdev->dev, quark_mfd);
 253
 254        ret = intel_quark_register_i2c_clk(&pdev->dev);
 255        if (ret)
 256                return ret;
 257
 258        pci_set_master(pdev);
 259
 260        /* This driver only requires 1 IRQ vector */
 261        ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 262        if (ret < 0)
 263                goto err_unregister_i2c_clk;
 264
 265        ret = intel_quark_i2c_setup(pdev);
 266        if (ret)
 267                goto err_free_irq_vectors;
 268
 269        ret = intel_quark_gpio_setup(pdev);
 270        if (ret)
 271                goto err_free_irq_vectors;
 272
 273        ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
 274                              ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
 275                              NULL);
 276        if (ret)
 277                goto err_free_irq_vectors;
 278
 279        return 0;
 280
 281err_free_irq_vectors:
 282        pci_free_irq_vectors(pdev);
 283err_unregister_i2c_clk:
 284        intel_quark_unregister_i2c_clk(&pdev->dev);
 285        return ret;
 286}
 287
 288static void intel_quark_mfd_remove(struct pci_dev *pdev)
 289{
 290        mfd_remove_devices(&pdev->dev);
 291        pci_free_irq_vectors(pdev);
 292        intel_quark_unregister_i2c_clk(&pdev->dev);
 293}
 294
 295static struct pci_driver intel_quark_mfd_driver = {
 296        .name           = "intel_quark_mfd_i2c_gpio",
 297        .id_table       = intel_quark_mfd_ids,
 298        .probe          = intel_quark_mfd_probe,
 299        .remove         = intel_quark_mfd_remove,
 300};
 301
 302module_pci_driver(intel_quark_mfd_driver);
 303
 304MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
 305MODULE_DESCRIPTION("Intel Quark MFD PCI driver for I2C & GPIO");
 306MODULE_LICENSE("GPL v2");
 307