janz-cmodio.c 7.3 KB

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