janz-cmodio.c 7.3 KB

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