pruss_intc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*
  2. * PRU-ICSS INTC IRQChip driver for various TI SoCs
  3. *
  4. * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
  5. * Andrew F. Davis <afd@ti.com>
  6. * Suman Anna <s-anna@ti.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/irq.h>
  18. #include <linux/irqchip/chained_irq.h>
  19. #include <linux/irqdomain.h>
  20. #include <linux/module.h>
  21. #include <linux/of_device.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/pruss.h>
  24. #include "pruss.h"
  25. #define MAX_HOST_NUM_IRQS 8
  26. static const char * const irq_names[] = {
  27. "host2", "host3", "host4", "host5", "host6", "host7", "host8", "host9",
  28. };
  29. /**
  30. * struct pruss_intc_match_data - match data to handle SoC variations
  31. * @no_host7_intr: flag denoting the absence of host7 interrupt into MPU
  32. */
  33. struct pruss_intc_match_data {
  34. bool no_host7_intr;
  35. };
  36. /**
  37. * struct pruss_intc - PRUSS interrupt controller structure
  38. * @pruss: back-reference to parent PRUSS structure
  39. * @irqs: kernel irq numbers corresponding to PRUSS host interrupts
  40. * @mem: kernel-mapping data for the INTC register space
  41. * @irqchip: irq chip for this interrupt controller
  42. * @domain: irq domain for this interrupt controller
  43. * @config_map: stored INTC configuration mapping data
  44. * @lock: mutex to serialize access to INTC
  45. */
  46. struct pruss_intc {
  47. struct pruss *pruss;
  48. unsigned int irqs[MAX_HOST_NUM_IRQS];
  49. struct pruss_mem_region mem;
  50. struct irq_chip *irqchip;
  51. struct irq_domain *domain;
  52. struct pruss_intc_config config_map;
  53. struct mutex lock; /* PRUSS INTC lock */
  54. };
  55. static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg)
  56. {
  57. return readl_relaxed(intc->mem.va + reg);
  58. }
  59. static inline void pruss_intc_write_reg(struct pruss_intc *intc,
  60. unsigned int reg, u32 val)
  61. {
  62. writel_relaxed(val, intc->mem.va + reg);
  63. }
  64. static int pruss_intc_check_write(struct pruss_intc *intc, unsigned int reg,
  65. unsigned int sysevent)
  66. {
  67. if (!intc)
  68. return -EINVAL;
  69. if (sysevent >= MAX_PRU_SYS_EVENTS)
  70. return -EINVAL;
  71. pruss_intc_write_reg(intc, reg, sysevent);
  72. return 0;
  73. }
  74. static struct pruss_intc *to_pruss_intc(struct pruss *pruss)
  75. {
  76. struct device_node *parent = pruss->dev->of_node;
  77. struct device_node *np;
  78. struct platform_device *pdev;
  79. struct pruss_intc *intc = NULL;
  80. np = of_get_child_by_name(parent, "intc");
  81. if (!np) {
  82. dev_err(pruss->dev, "pruss does not have an intc node\n");
  83. return NULL;
  84. }
  85. pdev = of_find_device_by_node(np);
  86. if (!pdev) {
  87. dev_err(pruss->dev, "no associated platform device\n");
  88. goto out;
  89. }
  90. intc = platform_get_drvdata(pdev);
  91. out:
  92. of_node_put(np);
  93. return intc;
  94. }
  95. /**
  96. * pruss_intc_configure() - configure the PRUSS INTC
  97. * @pruss: the pruss instance
  98. * @intc_config: PRU core-specific INTC configuration
  99. *
  100. * Configures the PRUSS INTC with the provided configuration from
  101. * a PRU core. Any existing event to channel mappings or channel to
  102. * host interrupt mappings are checked to make sure there are no
  103. * conflicting configuration between both the PRU cores. The function
  104. * is intended to be only used by the PRU remoteproc driver.
  105. *
  106. * Returns 0 on success, or a suitable error code otherwise
  107. */
  108. int pruss_intc_configure(struct pruss *pruss,
  109. struct pruss_intc_config *intc_config)
  110. {
  111. struct device *dev = pruss->dev;
  112. struct pruss_intc *intc = to_pruss_intc(pruss);
  113. int i, idx, ch, host, ret;
  114. u64 sysevt_mask = 0;
  115. u32 ch_mask = 0;
  116. u32 host_mask = 0;
  117. u32 val;
  118. if (!intc)
  119. return -EINVAL;
  120. mutex_lock(&intc->lock);
  121. /*
  122. * configure channel map registers - each register holds map info
  123. * for 4 events, with each event occupying the lower nibble in
  124. * a register byte address in little-endian fashion
  125. */
  126. for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
  127. ch = intc_config->sysev_to_ch[i];
  128. if (ch < 0)
  129. continue;
  130. /* check if sysevent already assigned */
  131. if (intc->config_map.sysev_to_ch[i] != -1) {
  132. dev_err(dev, "event %d (req. channel %d) already assigned to channel %d\n",
  133. i, ch, intc->config_map.sysev_to_ch[i]);
  134. ret = -EEXIST;
  135. goto unlock;
  136. }
  137. intc->config_map.sysev_to_ch[i] = ch;
  138. idx = i / 4;
  139. val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx));
  140. val |= ch << ((i & 3) * 8);
  141. pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val);
  142. sysevt_mask |= BIT_ULL(i);
  143. ch_mask |= BIT(ch);
  144. dev_dbg(dev, "SYSEV%d -> CH%d (CMR%d 0x%08x)\n", i, ch, idx,
  145. pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)));
  146. }
  147. /*
  148. * set host map registers - each register holds map info for
  149. * 4 channels, with each channel occupying the lower nibble in
  150. * a register byte address in little-endian fashion
  151. */
  152. for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
  153. host = intc_config->ch_to_host[i];
  154. if (host < 0)
  155. continue;
  156. /* check if channel already assigned */
  157. if (intc->config_map.ch_to_host[i] != -1) {
  158. dev_err(dev, "channel %d (req. intr_no %d) already assigned to intr_no %d\n",
  159. i, host, intc->config_map.ch_to_host[i]);
  160. ret = -EEXIST;
  161. goto unlock;
  162. }
  163. /* check if host intr is already in use by other PRU */
  164. if (pruss->host_mask & (1U << host)) {
  165. dev_err(dev, "%s: host intr %d already in use\n",
  166. __func__, host);
  167. ret = -EEXIST;
  168. goto unlock;
  169. }
  170. intc->config_map.ch_to_host[i] = host;
  171. idx = i / 4;
  172. val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx));
  173. val |= host << ((i & 3) * 8);
  174. pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val);
  175. ch_mask |= BIT(i);
  176. host_mask |= BIT(host);
  177. dev_dbg(dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", i, host, idx,
  178. pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)));
  179. }
  180. dev_info(dev, "configured system_events = 0x%016llx intr_channels = 0x%08x host_intr = 0x%08x\n",
  181. sysevt_mask, ch_mask, host_mask);
  182. /* enable system events, writing 0 has no-effect */
  183. pruss_intc_write_reg(intc, PRU_INTC_ESR0, lower_32_bits(sysevt_mask));
  184. pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
  185. pruss_intc_write_reg(intc, PRU_INTC_ESR1, upper_32_bits(sysevt_mask));
  186. pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
  187. /* enable host interrupts */
  188. for (i = 0; i < MAX_PRU_HOST_INT; i++) {
  189. if (host_mask & BIT(i))
  190. pruss_intc_write_reg(intc, PRU_INTC_HIEISR, i);
  191. }
  192. /* global interrupt enable */
  193. pruss_intc_write_reg(intc, PRU_INTC_GER, 1);
  194. pruss->host_mask |= host_mask;
  195. mutex_unlock(&intc->lock);
  196. return 0;
  197. unlock:
  198. mutex_unlock(&intc->lock);
  199. return ret;
  200. }
  201. EXPORT_SYMBOL_GPL(pruss_intc_configure);
  202. /**
  203. * pruss_intc_unconfigure() - unconfigure the PRUSS INTC
  204. * @pruss: the pruss instance
  205. * @intc_config: PRU core specific INTC configuration
  206. *
  207. * Undo whatever was done in pruss_intc_configure() for a PRU core.
  208. * It should be sufficient to just mark the resources free in the
  209. * global map and disable the host interrupts and sysevents.
  210. */
  211. int pruss_intc_unconfigure(struct pruss *pruss,
  212. struct pruss_intc_config *intc_config)
  213. {
  214. struct device *dev = pruss->dev;
  215. struct pruss_intc *intc = to_pruss_intc(pruss);
  216. int i, ch, host;
  217. u64 sysevt_mask = 0;
  218. u32 host_mask = 0;
  219. if (!intc)
  220. return -EINVAL;
  221. mutex_lock(&intc->lock);
  222. for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++) {
  223. ch = intc_config->sysev_to_ch[i];
  224. if (ch < 0)
  225. continue;
  226. /* mark sysevent free in global map */
  227. intc->config_map.sysev_to_ch[i] = -1;
  228. sysevt_mask |= BIT_ULL(i);
  229. }
  230. for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++) {
  231. host = intc_config->ch_to_host[i];
  232. if (host < 0)
  233. continue;
  234. /* mark channel free in global map */
  235. intc->config_map.ch_to_host[i] = -1;
  236. host_mask |= BIT(host);
  237. }
  238. dev_info(dev, "unconfigured system_events = 0x%016llx host_intr = 0x%08x\n",
  239. sysevt_mask, host_mask);
  240. /* disable system events, writing 0 has no-effect */
  241. pruss_intc_write_reg(intc, PRU_INTC_ECR0, lower_32_bits(sysevt_mask));
  242. pruss_intc_write_reg(intc, PRU_INTC_ECR1, upper_32_bits(sysevt_mask));
  243. /* clear any pending status */
  244. pruss_intc_write_reg(intc, PRU_INTC_SECR0, lower_32_bits(sysevt_mask));
  245. pruss_intc_write_reg(intc, PRU_INTC_SECR1, upper_32_bits(sysevt_mask));
  246. /* disable host interrupts */
  247. for (i = 0; i < MAX_PRU_HOST_INT; i++) {
  248. if (host_mask & BIT(i))
  249. pruss_intc_write_reg(intc, PRU_INTC_HIDISR, i);
  250. }
  251. pruss->host_mask &= ~host_mask;
  252. mutex_unlock(&intc->lock);
  253. return 0;
  254. }
  255. EXPORT_SYMBOL_GPL(pruss_intc_unconfigure);
  256. static void pruss_intc_init(struct pruss_intc *intc)
  257. {
  258. int i;
  259. /* configure polarity to active high for all system interrupts */
  260. pruss_intc_write_reg(intc, PRU_INTC_SIPR0, 0xffffffff);
  261. pruss_intc_write_reg(intc, PRU_INTC_SIPR1, 0xffffffff);
  262. /* configure type to pulse interrupt for all system interrupts */
  263. pruss_intc_write_reg(intc, PRU_INTC_SITR0, 0);
  264. pruss_intc_write_reg(intc, PRU_INTC_SITR1, 0);
  265. /* clear all 16 interrupt channel map registers */
  266. for (i = 0; i < 16; i++)
  267. pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0);
  268. /* clear all 3 host interrupt map registers */
  269. for (i = 0; i < 3; i++)
  270. pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0);
  271. }
  272. static void pruss_intc_irq_ack(struct irq_data *data)
  273. {
  274. struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
  275. unsigned int hwirq = data->hwirq;
  276. pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq);
  277. }
  278. static void pruss_intc_irq_mask(struct irq_data *data)
  279. {
  280. struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
  281. unsigned int hwirq = data->hwirq;
  282. pruss_intc_check_write(intc, PRU_INTC_EICR, hwirq);
  283. }
  284. static void pruss_intc_irq_unmask(struct irq_data *data)
  285. {
  286. struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
  287. unsigned int hwirq = data->hwirq;
  288. pruss_intc_check_write(intc, PRU_INTC_EISR, hwirq);
  289. }
  290. static int pruss_intc_irq_retrigger(struct irq_data *data)
  291. {
  292. struct pruss_intc *intc = irq_data_get_irq_chip_data(data);
  293. unsigned int hwirq = data->hwirq;
  294. return pruss_intc_check_write(intc, PRU_INTC_SISR, hwirq);
  295. }
  296. static int pruss_intc_irq_reqres(struct irq_data *data)
  297. {
  298. if (!try_module_get(THIS_MODULE))
  299. return -ENODEV;
  300. return 0;
  301. }
  302. static void pruss_intc_irq_relres(struct irq_data *data)
  303. {
  304. module_put(THIS_MODULE);
  305. }
  306. /**
  307. * pruss_intc_trigger() - trigger a PRU system event
  308. * @irq: linux IRQ number associated with a PRU system event
  309. *
  310. * Trigger an interrupt by signalling a specific PRU system event.
  311. * This can be used by PRUSS client users to raise/send an event to
  312. * a PRU or any other core that is listening on the host interrupt
  313. * mapped to that specific PRU system event. The @irq variable is the
  314. * Linux IRQ number associated with a specific PRU system event that
  315. * a client user/application uses. The interrupt mappings for this is
  316. * provided by the PRUSS INTC irqchip instance.
  317. *
  318. * Returns 0 on success, or an error value upon failure.
  319. */
  320. int pruss_intc_trigger(unsigned int irq)
  321. {
  322. struct irq_desc *desc;
  323. if (irq <= 0)
  324. return -EINVAL;
  325. desc = irq_to_desc(irq);
  326. if (!desc)
  327. return -EINVAL;
  328. pruss_intc_irq_retrigger(&desc->irq_data);
  329. return 0;
  330. }
  331. EXPORT_SYMBOL_GPL(pruss_intc_trigger);
  332. static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq,
  333. irq_hw_number_t hw)
  334. {
  335. struct pruss_intc *intc = d->host_data;
  336. irq_set_chip_data(virq, intc);
  337. irq_set_chip_and_handler(virq, intc->irqchip, handle_level_irq);
  338. return 0;
  339. }
  340. static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
  341. {
  342. irq_set_chip_and_handler(virq, NULL, NULL);
  343. irq_set_chip_data(virq, NULL);
  344. }
  345. static const struct irq_domain_ops pruss_intc_irq_domain_ops = {
  346. .xlate = irq_domain_xlate_onecell,
  347. .map = pruss_intc_irq_domain_map,
  348. .unmap = pruss_intc_irq_domain_unmap,
  349. };
  350. static void pruss_intc_irq_handler(struct irq_desc *desc)
  351. {
  352. unsigned int irq = irq_desc_get_irq(desc);
  353. struct irq_chip *chip = irq_desc_get_chip(desc);
  354. struct pruss_intc *intc = irq_get_handler_data(irq);
  355. u32 hipir;
  356. unsigned int virq;
  357. int i, hwirq;
  358. chained_irq_enter(chip, desc);
  359. /* find our host irq number */
  360. for (i = 0; i < MAX_HOST_NUM_IRQS; i++)
  361. if (intc->irqs[i] == irq)
  362. break;
  363. if (i == MAX_HOST_NUM_IRQS)
  364. goto err;
  365. i += MIN_PRU_HOST_INT;
  366. /* get highest priority pending PRUSS system event */
  367. hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i));
  368. while (!(hipir & BIT(31))) {
  369. hwirq = hipir & GENMASK(9, 0);
  370. virq = irq_linear_revmap(intc->domain, hwirq);
  371. /*
  372. * XXX: manually ACK any system events that do not have a
  373. * handler mapped yet
  374. */
  375. if (unlikely(!virq))
  376. pruss_intc_check_write(intc, PRU_INTC_SICR, hwirq);
  377. else
  378. generic_handle_irq(virq);
  379. /* get next system event */
  380. hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(i));
  381. }
  382. err:
  383. chained_irq_exit(chip, desc);
  384. }
  385. static const struct of_device_id pruss_intc_of_match[];
  386. static int pruss_intc_probe(struct platform_device *pdev)
  387. {
  388. struct device *dev = &pdev->dev;
  389. struct platform_device *ppdev = to_platform_device(dev->parent);
  390. struct pruss_intc *intc;
  391. struct resource *res;
  392. struct irq_chip *irqchip;
  393. int i, irq;
  394. const struct pruss_intc_match_data *data;
  395. bool skip_host7;
  396. data = of_match_device(pruss_intc_of_match, dev)->data;
  397. skip_host7 = data ? data->no_host7_intr : false;
  398. intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL);
  399. if (!intc)
  400. return -ENOMEM;
  401. platform_set_drvdata(pdev, intc);
  402. res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intc");
  403. intc->mem.va = devm_ioremap_resource(dev, res);
  404. if (IS_ERR(intc->mem.va)) {
  405. dev_err(dev, "failed to parse and map intc memory resource\n");
  406. return PTR_ERR(intc->mem.va);
  407. }
  408. intc->mem.pa = res->start;
  409. intc->mem.size = resource_size(res);
  410. dev_dbg(dev, "intc memory: pa %pa size 0x%x va %p\n", &intc->mem.pa,
  411. intc->mem.size, intc->mem.va);
  412. mutex_init(&intc->lock);
  413. for (i = 0; i < ARRAY_SIZE(intc->config_map.sysev_to_ch); i++)
  414. intc->config_map.sysev_to_ch[i] = -1;
  415. for (i = 0; i < ARRAY_SIZE(intc->config_map.ch_to_host); i++)
  416. intc->config_map.ch_to_host[i] = -1;
  417. intc->pruss = platform_get_drvdata(ppdev);
  418. pruss_intc_init(intc);
  419. irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL);
  420. if (!irqchip)
  421. return -ENOMEM;
  422. irqchip->irq_ack = pruss_intc_irq_ack;
  423. irqchip->irq_mask = pruss_intc_irq_mask;
  424. irqchip->irq_unmask = pruss_intc_irq_unmask;
  425. irqchip->irq_retrigger = pruss_intc_irq_retrigger;
  426. irqchip->irq_request_resources = pruss_intc_irq_reqres;
  427. irqchip->irq_release_resources = pruss_intc_irq_relres;
  428. irqchip->name = dev_name(dev);
  429. intc->irqchip = irqchip;
  430. /* always 64 events */
  431. intc->domain = irq_domain_add_linear(dev->of_node, MAX_PRU_SYS_EVENTS,
  432. &pruss_intc_irq_domain_ops, intc);
  433. if (!intc->domain)
  434. return -ENOMEM;
  435. for (i = 0; i < MAX_HOST_NUM_IRQS; i++) {
  436. irq = platform_get_irq_byname(pdev, irq_names[i]);
  437. if (irq < 0) {
  438. if (!strcmp(irq_names[i], "host7") && !!skip_host7)
  439. continue;
  440. dev_err(dev, "platform_ger_irq_byname failed for %s : %d\n",
  441. irq_names[i], irq);
  442. goto fail_irq;
  443. }
  444. intc->irqs[i] = irq;
  445. irq_set_handler_data(irq, intc);
  446. irq_set_chained_handler(irq, pruss_intc_irq_handler);
  447. }
  448. return 0;
  449. fail_irq:
  450. irq_domain_remove(intc->domain);
  451. return irq;
  452. }
  453. static int pruss_intc_remove(struct platform_device *pdev)
  454. {
  455. struct pruss_intc *intc = platform_get_drvdata(pdev);
  456. unsigned int hwirq;
  457. if (intc->domain) {
  458. for (hwirq = 0; hwirq < MAX_PRU_SYS_EVENTS; hwirq++)
  459. irq_dispose_mapping(irq_find_mapping(intc->domain,
  460. hwirq));
  461. irq_domain_remove(intc->domain);
  462. }
  463. return 0;
  464. }
  465. static struct pruss_intc_match_data am437x_pruss_intc_data = {
  466. .no_host7_intr = true,
  467. };
  468. static struct pruss_intc_match_data k2g_pruss_intc_data = {
  469. .no_host7_intr = true,
  470. };
  471. static const struct of_device_id pruss_intc_of_match[] = {
  472. {
  473. .compatible = "ti,am3356-pruss-intc",
  474. .data = NULL,
  475. },
  476. {
  477. .compatible = "ti,am4376-pruss-intc",
  478. .data = &am437x_pruss_intc_data,
  479. },
  480. {
  481. .compatible = "ti,am5728-pruss-intc",
  482. .data = NULL,
  483. },
  484. {
  485. .compatible = "ti,k2g-pruss-intc",
  486. .data = &k2g_pruss_intc_data,
  487. },
  488. { /* sentinel */ },
  489. };
  490. MODULE_DEVICE_TABLE(of, pruss_intc_of_match);
  491. static struct platform_driver pruss_intc_driver = {
  492. .driver = {
  493. .name = "pruss-intc",
  494. .of_match_table = pruss_intc_of_match,
  495. },
  496. .probe = pruss_intc_probe,
  497. .remove = pruss_intc_remove,
  498. };
  499. module_platform_driver(pruss_intc_driver);
  500. MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
  501. MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
  502. MODULE_DESCRIPTION("PRU-ICSS INTC Driver");
  503. MODULE_LICENSE("GPL v2");