root/drivers/mfd/janz-cmodio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cmodio_setup_subdevice
  2. cmodio_probe_submodules
  3. mbus_show
  4. cmodio_pci_probe
  5. cmodio_pci_remove

   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 */
  30 static unsigned int num_modules = CMODIO_MAX_MODULES;
  31 static char *modules[CMODIO_MAX_MODULES] = {
  32         "empty", "empty", "empty", "empty",
  33 };
  34 
  35 module_param_array(modules, charp, &num_modules, S_IRUGO);
  36 MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
  37 
  38 /* Unique Device Id */
  39 static unsigned int cmodio_id;
  40 
  41 struct 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 
  61 static 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 */
 118 static 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 
 152 static ssize_t mbus_show(struct device *dev, struct device_attribute *attr,
 153                          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 
 160 static DEVICE_ATTR(modulbus_number, S_IRUGO, mbus_show, NULL);
 161 
 162 static struct attribute *cmodio_sysfs_attrs[] = {
 163         &dev_attr_modulbus_number.attr,
 164         NULL,
 165 };
 166 
 167 static const struct attribute_group cmodio_sysfs_attr_group = {
 168         .attrs = cmodio_sysfs_attrs,
 169 };
 170 
 171 /*
 172  * PCI Driver
 173  */
 174 
 175 static 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 
 235 out_sysfs_remove_group:
 236         sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
 237 out_unmap_ctrl:
 238         iounmap(priv->ctrl);
 239 out_pci_release_regions:
 240         pci_release_regions(dev);
 241 out_pci_disable_device:
 242         pci_disable_device(dev);
 243 
 244         return ret;
 245 }
 246 
 247 static 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 */
 261 static 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 };
 270 MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
 271 
 272 static 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 
 279 module_pci_driver(cmodio_pci_driver);
 280 
 281 MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
 282 MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
 283 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */