linux/drivers/mfd/janz-cmodio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Janz CMOD-IO MODULbus Carrier Board PCI Driver
   4 *
   5 * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
   6 *
   7 * Lots of inspiration and code was copied from drivers/mfd/sm501.c
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/pci.h>
  13#include <linux/interrupt.h>
  14#include <linux/delay.h>
  15#include <linux/platform_device.h>
  16#include <linux/slab.h>
  17#include <linux/mfd/core.h>
  18
  19#include <linux/mfd/janz.h>
  20
  21#define DRV_NAME "janz-cmodio"
  22
  23/* Size of each MODULbus module in PCI BAR4 */
  24#define CMODIO_MODULBUS_SIZE    0x200
  25
  26/* Maximum number of MODULbus modules on a CMOD-IO carrier board */
  27#define CMODIO_MAX_MODULES      4
  28
  29/* Module Parameters */
  30static unsigned int num_modules = CMODIO_MAX_MODULES;
  31static char *modules[CMODIO_MAX_MODULES] = {
  32        "empty", "empty", "empty", "empty",
  33};
  34
  35module_param_array(modules, charp, &num_modules, S_IRUGO);
  36MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
  37
  38/* Unique Device Id */
  39static unsigned int cmodio_id;
  40
  41struct cmodio_device {
  42        /* Parent PCI device */
  43        struct pci_dev *pdev;
  44
  45        /* PLX control registers */
  46        struct janz_cmodio_onboard_regs __iomem *ctrl;
  47
  48        /* hex switch position */
  49        u8 hex;
  50
  51        /* mfd-core API */
  52        struct mfd_cell cells[CMODIO_MAX_MODULES];
  53        struct resource resources[3 * CMODIO_MAX_MODULES];
  54        struct janz_platform_data pdata[CMODIO_MAX_MODULES];
  55};
  56
  57/*
  58 * Subdevices using the mfd-core API
  59 */
  60
  61static int cmodio_setup_subdevice(struct cmodio_device *priv,
  62                                            char *name, unsigned int devno,
  63                                            unsigned int modno)
  64{
  65        struct janz_platform_data *pdata;
  66        struct mfd_cell *cell;
  67        struct resource *res;
  68        struct pci_dev *pci;
  69
  70        pci = priv->pdev;
  71        cell = &priv->cells[devno];
  72        res = &priv->resources[devno * 3];
  73        pdata = &priv->pdata[devno];
  74
  75        cell->name = name;
  76        cell->resources = res;
  77        cell->num_resources = 3;
  78
  79        /* Setup the subdevice ID -- must be unique */
  80        cell->id = cmodio_id++;
  81
  82        /* Add platform data */
  83        pdata->modno = modno;
  84        cell->platform_data = pdata;
  85        cell->pdata_size = sizeof(*pdata);
  86
  87        /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
  88        res->flags = IORESOURCE_MEM;
  89        res->parent = &pci->resource[3];
  90        res->start = pci->resource[3].start + (CMODIO_MODULBUS_SIZE * modno);
  91        res->end = res->start + CMODIO_MODULBUS_SIZE - 1;
  92        res++;
  93
  94        /* PLX Control Registers -- PCI BAR4 is interrupt and other registers */
  95        res->flags = IORESOURCE_MEM;
  96        res->parent = &pci->resource[4];
  97        res->start = pci->resource[4].start;
  98        res->end = pci->resource[4].end;
  99        res++;
 100
 101        /*
 102         * IRQ
 103         *
 104         * The start and end fields are used as an offset to the irq_base
 105         * parameter passed into the mfd_add_devices() function call. All
 106         * devices share the same IRQ.
 107         */
 108        res->flags = IORESOURCE_IRQ;
 109        res->parent = NULL;
 110        res->start = 0;
 111        res->end = 0;
 112        res++;
 113
 114        return 0;
 115}
 116
 117/* Probe each submodule using kernel parameters */
 118static int cmodio_probe_submodules(struct cmodio_device *priv)
 119{
 120        struct pci_dev *pdev = priv->pdev;
 121        unsigned int num_probed = 0;
 122        char *name;
 123        int i;
 124
 125        for (i = 0; i < num_modules; i++) {
 126                name = modules[i];
 127                if (!strcmp(name, "") || !strcmp(name, "empty"))
 128                        continue;
 129
 130                dev_dbg(&priv->pdev->dev, "MODULbus %d: name %s\n", i, name);
 131                cmodio_setup_subdevice(priv, name, num_probed, i);
 132                num_probed++;
 133        }
 134
 135        /* print an error message if no modules were probed */
 136        if (num_probed == 0) {
 137                dev_err(&priv->pdev->dev, "no MODULbus modules specified, "
 138                                          "please set the ``modules'' kernel "
 139                                          "parameter according to your "
 140                                          "hardware configuration\n");
 141                return -ENODEV;
 142        }
 143
 144        return mfd_add_devices(&pdev->dev, 0, priv->cells,
 145                               num_probed, NULL, pdev->irq, NULL);
 146}
 147
 148/*
 149 * SYSFS Attributes
 150 */
 151
 152static ssize_t modulbus_number_show(struct device *dev,
 153                                    struct device_attribute *attr, char *buf)
 154{
 155        struct cmodio_device *priv = dev_get_drvdata(dev);
 156
 157        return snprintf(buf, PAGE_SIZE, "%x\n", priv->hex);
 158}
 159
 160static DEVICE_ATTR_RO(modulbus_number);
 161
 162static struct attribute *cmodio_sysfs_attrs[] = {
 163        &dev_attr_modulbus_number.attr,
 164        NULL,
 165};
 166
 167static const struct attribute_group cmodio_sysfs_attr_group = {
 168        .attrs = cmodio_sysfs_attrs,
 169};
 170
 171/*
 172 * PCI Driver
 173 */
 174
 175static int cmodio_pci_probe(struct pci_dev *dev,
 176                                      const struct pci_device_id *id)
 177{
 178        struct cmodio_device *priv;
 179        int ret;
 180
 181        priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
 182        if (!priv)
 183                return -ENOMEM;
 184
 185        pci_set_drvdata(dev, priv);
 186        priv->pdev = dev;
 187
 188        /* Hardware Initialization */
 189        ret = pci_enable_device(dev);
 190        if (ret) {
 191                dev_err(&dev->dev, "unable to enable device\n");
 192                return ret;
 193        }
 194
 195        pci_set_master(dev);
 196        ret = pci_request_regions(dev, DRV_NAME);
 197        if (ret) {
 198                dev_err(&dev->dev, "unable to request regions\n");
 199                goto out_pci_disable_device;
 200        }
 201
 202        /* Onboard configuration registers */
 203        priv->ctrl = pci_ioremap_bar(dev, 4);
 204        if (!priv->ctrl) {
 205                dev_err(&dev->dev, "unable to remap onboard regs\n");
 206                ret = -ENOMEM;
 207                goto out_pci_release_regions;
 208        }
 209
 210        /* Read the hex switch on the carrier board */
 211        priv->hex = ioread8(&priv->ctrl->int_enable);
 212
 213        /* Add the MODULbus number (hex switch value) to the device's sysfs */
 214        ret = sysfs_create_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
 215        if (ret) {
 216                dev_err(&dev->dev, "unable to create sysfs attributes\n");
 217                goto out_unmap_ctrl;
 218        }
 219
 220        /*
 221         * Disable all interrupt lines, each submodule will enable its
 222         * own interrupt line if needed
 223         */
 224        iowrite8(0xf, &priv->ctrl->int_disable);
 225
 226        /* Register drivers for all submodules */
 227        ret = cmodio_probe_submodules(priv);
 228        if (ret) {
 229                dev_err(&dev->dev, "unable to probe submodules\n");
 230                goto out_sysfs_remove_group;
 231        }
 232
 233        return 0;
 234
 235out_sysfs_remove_group:
 236        sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
 237out_unmap_ctrl:
 238        iounmap(priv->ctrl);
 239out_pci_release_regions:
 240        pci_release_regions(dev);
 241out_pci_disable_device:
 242        pci_disable_device(dev);
 243
 244        return ret;
 245}
 246
 247static void cmodio_pci_remove(struct pci_dev *dev)
 248{
 249        struct cmodio_device *priv = pci_get_drvdata(dev);
 250
 251        mfd_remove_devices(&dev->dev);
 252        sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
 253        iounmap(priv->ctrl);
 254        pci_release_regions(dev);
 255        pci_disable_device(dev);
 256}
 257
 258#define PCI_VENDOR_ID_JANZ              0x13c3
 259
 260/* The list of devices that this module will support */
 261static const struct pci_device_id cmodio_pci_ids[] = {
 262        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
 263        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
 264        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0201 },
 265        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0202 },
 266        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0201 },
 267        { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0202 },
 268        { 0, }
 269};
 270MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
 271
 272static struct pci_driver cmodio_pci_driver = {
 273        .name     = DRV_NAME,
 274        .id_table = cmodio_pci_ids,
 275        .probe    = cmodio_pci_probe,
 276        .remove   = cmodio_pci_remove,
 277};
 278
 279module_pci_driver(cmodio_pci_driver);
 280
 281MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
 282MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
 283MODULE_LICENSE("GPL");
 284