Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Janz CMOD-IO MODULbus Carrier Board PCI Driver
0004  *
0005  * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
0006  *
0007  * Lots of inspiration and code was copied from drivers/mfd/sm501.c
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/pci.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/delay.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/slab.h>
0017 #include <linux/mfd/core.h>
0018 
0019 #include <linux/mfd/janz.h>
0020 
0021 #define DRV_NAME "janz-cmodio"
0022 
0023 /* Size of each MODULbus module in PCI BAR4 */
0024 #define CMODIO_MODULBUS_SIZE    0x200
0025 
0026 /* Maximum number of MODULbus modules on a CMOD-IO carrier board */
0027 #define CMODIO_MAX_MODULES  4
0028 
0029 /* Module Parameters */
0030 static unsigned int num_modules = CMODIO_MAX_MODULES;
0031 static char *modules[CMODIO_MAX_MODULES] = {
0032     "empty", "empty", "empty", "empty",
0033 };
0034 
0035 module_param_array(modules, charp, &num_modules, S_IRUGO);
0036 MODULE_PARM_DESC(modules, "MODULbus modules attached to the carrier board");
0037 
0038 /* Unique Device Id */
0039 static unsigned int cmodio_id;
0040 
0041 struct cmodio_device {
0042     /* Parent PCI device */
0043     struct pci_dev *pdev;
0044 
0045     /* PLX control registers */
0046     struct janz_cmodio_onboard_regs __iomem *ctrl;
0047 
0048     /* hex switch position */
0049     u8 hex;
0050 
0051     /* mfd-core API */
0052     struct mfd_cell cells[CMODIO_MAX_MODULES];
0053     struct resource resources[3 * CMODIO_MAX_MODULES];
0054     struct janz_platform_data pdata[CMODIO_MAX_MODULES];
0055 };
0056 
0057 /*
0058  * Subdevices using the mfd-core API
0059  */
0060 
0061 static int cmodio_setup_subdevice(struct cmodio_device *priv,
0062                         char *name, unsigned int devno,
0063                         unsigned int modno)
0064 {
0065     struct janz_platform_data *pdata;
0066     struct mfd_cell *cell;
0067     struct resource *res;
0068     struct pci_dev *pci;
0069 
0070     pci = priv->pdev;
0071     cell = &priv->cells[devno];
0072     res = &priv->resources[devno * 3];
0073     pdata = &priv->pdata[devno];
0074 
0075     cell->name = name;
0076     cell->resources = res;
0077     cell->num_resources = 3;
0078 
0079     /* Setup the subdevice ID -- must be unique */
0080     cell->id = cmodio_id++;
0081 
0082     /* Add platform data */
0083     pdata->modno = modno;
0084     cell->platform_data = pdata;
0085     cell->pdata_size = sizeof(*pdata);
0086 
0087     /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
0088     res->flags = IORESOURCE_MEM;
0089     res->parent = &pci->resource[3];
0090     res->start = pci->resource[3].start + (CMODIO_MODULBUS_SIZE * modno);
0091     res->end = res->start + CMODIO_MODULBUS_SIZE - 1;
0092     res++;
0093 
0094     /* PLX Control Registers -- PCI BAR4 is interrupt and other registers */
0095     res->flags = IORESOURCE_MEM;
0096     res->parent = &pci->resource[4];
0097     res->start = pci->resource[4].start;
0098     res->end = pci->resource[4].end;
0099     res++;
0100 
0101     /*
0102      * IRQ
0103      *
0104      * The start and end fields are used as an offset to the irq_base
0105      * parameter passed into the mfd_add_devices() function call. All
0106      * devices share the same IRQ.
0107      */
0108     res->flags = IORESOURCE_IRQ;
0109     res->parent = NULL;
0110     res->start = 0;
0111     res->end = 0;
0112     res++;
0113 
0114     return 0;
0115 }
0116 
0117 /* Probe each submodule using kernel parameters */
0118 static int cmodio_probe_submodules(struct cmodio_device *priv)
0119 {
0120     struct pci_dev *pdev = priv->pdev;
0121     unsigned int num_probed = 0;
0122     char *name;
0123     int i;
0124 
0125     for (i = 0; i < num_modules; i++) {
0126         name = modules[i];
0127         if (!strcmp(name, "") || !strcmp(name, "empty"))
0128             continue;
0129 
0130         dev_dbg(&priv->pdev->dev, "MODULbus %d: name %s\n", i, name);
0131         cmodio_setup_subdevice(priv, name, num_probed, i);
0132         num_probed++;
0133     }
0134 
0135     /* print an error message if no modules were probed */
0136     if (num_probed == 0) {
0137         dev_err(&priv->pdev->dev, "no MODULbus modules specified, "
0138                       "please set the ``modules'' kernel "
0139                       "parameter according to your "
0140                       "hardware configuration\n");
0141         return -ENODEV;
0142     }
0143 
0144     return mfd_add_devices(&pdev->dev, 0, priv->cells,
0145                    num_probed, NULL, pdev->irq, NULL);
0146 }
0147 
0148 /*
0149  * SYSFS Attributes
0150  */
0151 
0152 static ssize_t modulbus_number_show(struct device *dev,
0153                     struct device_attribute *attr, char *buf)
0154 {
0155     struct cmodio_device *priv = dev_get_drvdata(dev);
0156 
0157     return sysfs_emit(buf, "%x\n", priv->hex);
0158 }
0159 
0160 static DEVICE_ATTR_RO(modulbus_number);
0161 
0162 static struct attribute *cmodio_sysfs_attrs[] = {
0163     &dev_attr_modulbus_number.attr,
0164     NULL,
0165 };
0166 
0167 static const struct attribute_group cmodio_sysfs_attr_group = {
0168     .attrs = cmodio_sysfs_attrs,
0169 };
0170 
0171 /*
0172  * PCI Driver
0173  */
0174 
0175 static int cmodio_pci_probe(struct pci_dev *dev,
0176                       const struct pci_device_id *id)
0177 {
0178     struct cmodio_device *priv;
0179     int ret;
0180 
0181     priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
0182     if (!priv)
0183         return -ENOMEM;
0184 
0185     pci_set_drvdata(dev, priv);
0186     priv->pdev = dev;
0187 
0188     /* Hardware Initialization */
0189     ret = pci_enable_device(dev);
0190     if (ret) {
0191         dev_err(&dev->dev, "unable to enable device\n");
0192         return ret;
0193     }
0194 
0195     pci_set_master(dev);
0196     ret = pci_request_regions(dev, DRV_NAME);
0197     if (ret) {
0198         dev_err(&dev->dev, "unable to request regions\n");
0199         goto out_pci_disable_device;
0200     }
0201 
0202     /* Onboard configuration registers */
0203     priv->ctrl = pci_ioremap_bar(dev, 4);
0204     if (!priv->ctrl) {
0205         dev_err(&dev->dev, "unable to remap onboard regs\n");
0206         ret = -ENOMEM;
0207         goto out_pci_release_regions;
0208     }
0209 
0210     /* Read the hex switch on the carrier board */
0211     priv->hex = ioread8(&priv->ctrl->int_enable);
0212 
0213     /* Add the MODULbus number (hex switch value) to the device's sysfs */
0214     ret = sysfs_create_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
0215     if (ret) {
0216         dev_err(&dev->dev, "unable to create sysfs attributes\n");
0217         goto out_unmap_ctrl;
0218     }
0219 
0220     /*
0221      * Disable all interrupt lines, each submodule will enable its
0222      * own interrupt line if needed
0223      */
0224     iowrite8(0xf, &priv->ctrl->int_disable);
0225 
0226     /* Register drivers for all submodules */
0227     ret = cmodio_probe_submodules(priv);
0228     if (ret) {
0229         dev_err(&dev->dev, "unable to probe submodules\n");
0230         goto out_sysfs_remove_group;
0231     }
0232 
0233     return 0;
0234 
0235 out_sysfs_remove_group:
0236     sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
0237 out_unmap_ctrl:
0238     iounmap(priv->ctrl);
0239 out_pci_release_regions:
0240     pci_release_regions(dev);
0241 out_pci_disable_device:
0242     pci_disable_device(dev);
0243 
0244     return ret;
0245 }
0246 
0247 static void cmodio_pci_remove(struct pci_dev *dev)
0248 {
0249     struct cmodio_device *priv = pci_get_drvdata(dev);
0250 
0251     mfd_remove_devices(&dev->dev);
0252     sysfs_remove_group(&dev->dev.kobj, &cmodio_sysfs_attr_group);
0253     iounmap(priv->ctrl);
0254     pci_release_regions(dev);
0255     pci_disable_device(dev);
0256 }
0257 
0258 #define PCI_VENDOR_ID_JANZ      0x13c3
0259 
0260 /* The list of devices that this module will support */
0261 static const struct pci_device_id cmodio_pci_ids[] = {
0262     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0101 },
0263     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0100 },
0264     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0201 },
0265     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_JANZ, 0x0202 },
0266     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0201 },
0267     { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_JANZ, 0x0202 },
0268     { 0, }
0269 };
0270 MODULE_DEVICE_TABLE(pci, cmodio_pci_ids);
0271 
0272 static struct pci_driver cmodio_pci_driver = {
0273     .name     = DRV_NAME,
0274     .id_table = cmodio_pci_ids,
0275     .probe    = cmodio_pci_probe,
0276     .remove   = cmodio_pci_remove,
0277 };
0278 
0279 module_pci_driver(cmodio_pci_driver);
0280 
0281 MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
0282 MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
0283 MODULE_LICENSE("GPL");