pinmux.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Freescale STMP378X/STMP378X Pin Multiplexing
  3. *
  4. * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
  5. *
  6. * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
  7. * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
  8. */
  9. /*
  10. * The code contained herein is licensed under the GNU General Public
  11. * License. You may obtain a copy of the GNU General Public License
  12. * Version 2 or later at the following locations:
  13. *
  14. * http://www.opensource.org/licenses/gpl-license.html
  15. * http://www.gnu.org/copyleft/gpl.html
  16. */
  17. #define DEBUG
  18. #include <linux/module.h>
  19. #include <linux/kernel.h>
  20. #include <linux/errno.h>
  21. #include <linux/sysdev.h>
  22. #include <linux/string.h>
  23. #include <linux/bitops.h>
  24. #include <linux/irq.h>
  25. #include <mach/hardware.h>
  26. #include <mach/platform.h>
  27. #include <mach/regs-pinctrl.h>
  28. #include <mach/pins.h>
  29. #include <mach/pinmux.h>
  30. #define NR_BANKS ARRAY_SIZE(pinmux_banks)
  31. static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
  32. [0] = {
  33. .hw_muxsel = {
  34. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
  35. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
  36. },
  37. .hw_drive = {
  38. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
  39. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
  40. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
  41. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
  42. },
  43. .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
  44. .functions = { 0x0, 0x1, 0x2, 0x3 },
  45. .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
  46. .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
  47. .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
  48. .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
  49. .irq = IRQ_GPIO0,
  50. .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
  51. .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
  52. .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
  53. .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
  54. .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
  55. },
  56. [1] = {
  57. .hw_muxsel = {
  58. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
  59. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
  60. },
  61. .hw_drive = {
  62. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
  63. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
  64. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
  65. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
  66. },
  67. .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
  68. .functions = { 0x0, 0x1, 0x2, 0x3 },
  69. .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
  70. .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
  71. .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
  72. .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
  73. .irq = IRQ_GPIO1,
  74. .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
  75. .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
  76. .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
  77. .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
  78. .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
  79. },
  80. [2] = {
  81. .hw_muxsel = {
  82. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
  83. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
  84. },
  85. .hw_drive = {
  86. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
  87. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
  88. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
  89. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
  90. },
  91. .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
  92. .functions = { 0x0, 0x1, 0x2, 0x3 },
  93. .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
  94. .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
  95. .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
  96. .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
  97. .irq = IRQ_GPIO2,
  98. .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
  99. .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
  100. .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
  101. .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
  102. .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
  103. },
  104. [3] = {
  105. .hw_muxsel = {
  106. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
  107. REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
  108. },
  109. .hw_drive = {
  110. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
  111. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
  112. REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
  113. NULL,
  114. },
  115. .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
  116. .functions = {0x0, 0x1, 0x2, 0x3},
  117. .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
  118. },
  119. };
  120. static inline struct stmp3xxx_pinmux_bank *
  121. stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
  122. {
  123. unsigned b, p;
  124. b = STMP3XXX_PINID_TO_BANK(id);
  125. p = STMP3XXX_PINID_TO_PINNUM(id);
  126. BUG_ON(b >= NR_BANKS);
  127. if (bank)
  128. *bank = b;
  129. if (pin)
  130. *pin = p;
  131. return &pinmux_banks[b];
  132. }
  133. /* Check if requested pin is owned by caller */
  134. static int stmp3xxx_check_pin(unsigned id, const char *label)
  135. {
  136. unsigned pin;
  137. struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
  138. if (!test_bit(pin, &pm->pin_map)) {
  139. printk(KERN_WARNING
  140. "%s: Accessing free pin %x, caller %s\n",
  141. __func__, id, label);
  142. return -EINVAL;
  143. }
  144. if (label && pm->pin_labels[pin] &&
  145. strcmp(label, pm->pin_labels[pin])) {
  146. printk(KERN_WARNING
  147. "%s: Wrong pin owner %x, caller %s owner %s\n",
  148. __func__, id, label, pm->pin_labels[pin]);
  149. return -EINVAL;
  150. }
  151. return 0;
  152. }
  153. void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
  154. const char *label)
  155. {
  156. struct stmp3xxx_pinmux_bank *pbank;
  157. void __iomem *hwdrive;
  158. u32 shift, val;
  159. u32 bank, pin;
  160. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  161. pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
  162. bank, pin, strength);
  163. hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
  164. shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
  165. val = pbank->strengths[strength];
  166. if (val == 0xff) {
  167. printk(KERN_WARNING
  168. "%s: strength is not supported for bank %d, caller %s",
  169. __func__, bank, label);
  170. return;
  171. }
  172. if (stmp3xxx_check_pin(id, label))
  173. return;
  174. pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
  175. val << shift, hwdrive);
  176. stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
  177. stmp3xxx_setl(val << shift, hwdrive);
  178. }
  179. void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
  180. const char *label)
  181. {
  182. struct stmp3xxx_pinmux_bank *pbank;
  183. void __iomem *hwdrive;
  184. u32 shift;
  185. u32 bank, pin;
  186. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  187. pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
  188. bank, pin, voltage);
  189. hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
  190. shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
  191. if (stmp3xxx_check_pin(id, label))
  192. return;
  193. pr_debug("%s: changing 0x%x bit in 0x%p register\n",
  194. __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
  195. if (voltage == PIN_1_8V)
  196. stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
  197. else
  198. stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
  199. }
  200. void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
  201. {
  202. struct stmp3xxx_pinmux_bank *pbank;
  203. void __iomem *hwpull;
  204. u32 bank, pin;
  205. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  206. pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
  207. bank, pin, enable);
  208. hwpull = pbank->hw_pull;
  209. if (stmp3xxx_check_pin(id, label))
  210. return;
  211. pr_debug("%s: changing 0x%x bit in 0x%p register\n",
  212. __func__, 1 << pin, hwpull);
  213. if (enable)
  214. stmp3xxx_setl(1 << pin, hwpull);
  215. else
  216. stmp3xxx_clearl(1 << pin, hwpull);
  217. }
  218. int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
  219. {
  220. struct stmp3xxx_pinmux_bank *pbank;
  221. u32 bank, pin;
  222. int ret = 0;
  223. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  224. pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
  225. bank, pin, fun);
  226. if (test_bit(pin, &pbank->pin_map)) {
  227. printk(KERN_WARNING
  228. "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
  229. __func__, bank, pin, label, pbank->pin_labels[pin]);
  230. return -EBUSY;
  231. }
  232. set_bit(pin, &pbank->pin_map);
  233. pbank->pin_labels[pin] = label;
  234. stmp3xxx_set_pin_type(id, fun);
  235. return ret;
  236. }
  237. void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
  238. {
  239. struct stmp3xxx_pinmux_bank *pbank;
  240. void __iomem *hwmux;
  241. u32 shift, val;
  242. u32 bank, pin;
  243. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  244. hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
  245. shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
  246. val = pbank->functions[fun];
  247. shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
  248. pr_debug("%s: writing 0x%x to 0x%p register\n",
  249. __func__, val << shift, hwmux);
  250. stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
  251. stmp3xxx_setl(val << shift, hwmux);
  252. }
  253. void stmp3xxx_release_pin(unsigned id, const char *label)
  254. {
  255. struct stmp3xxx_pinmux_bank *pbank;
  256. u32 bank, pin;
  257. pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
  258. pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
  259. if (stmp3xxx_check_pin(id, label))
  260. return;
  261. clear_bit(pin, &pbank->pin_map);
  262. pbank->pin_labels[pin] = NULL;
  263. }
  264. int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
  265. {
  266. struct pin_desc *pin;
  267. int p;
  268. int err = 0;
  269. /* Allocate and configure pins */
  270. for (p = 0; p < pin_group->nr_pins; p++) {
  271. pr_debug("%s: #%d\n", __func__, p);
  272. pin = &pin_group->pins[p];
  273. err = stmp3xxx_request_pin(pin->id, pin->fun, label);
  274. if (err)
  275. goto out_err;
  276. stmp3xxx_pin_strength(pin->id, pin->strength, label);
  277. stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
  278. stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
  279. }
  280. return 0;
  281. out_err:
  282. /* Release allocated pins in case of error */
  283. while (--p >= 0) {
  284. pr_debug("%s: releasing #%d\n", __func__, p);
  285. stmp3xxx_release_pin(pin_group->pins[p].id, label);
  286. }
  287. return err;
  288. }
  289. EXPORT_SYMBOL(stmp3xxx_request_pin_group);
  290. void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
  291. {
  292. struct pin_desc *pin;
  293. int p;
  294. for (p = 0; p < pin_group->nr_pins; p++) {
  295. pin = &pin_group->pins[p];
  296. stmp3xxx_release_pin(pin->id, label);
  297. }
  298. }
  299. EXPORT_SYMBOL(stmp3xxx_release_pin_group);
  300. static int stmp3xxx_irq_to_gpio(int irq,
  301. struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
  302. {
  303. struct stmp3xxx_pinmux_bank *pm;
  304. for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
  305. if (pm->virq <= irq && irq < pm->virq + 32) {
  306. *bank = pm;
  307. *gpio = irq - pm->virq;
  308. return 0;
  309. }
  310. return -ENOENT;
  311. }
  312. static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
  313. {
  314. struct stmp3xxx_pinmux_bank *pm;
  315. unsigned gpio;
  316. int l, p;
  317. stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
  318. switch (type) {
  319. case IRQ_TYPE_EDGE_RISING:
  320. l = 0; p = 1; break;
  321. case IRQ_TYPE_EDGE_FALLING:
  322. l = 0; p = 0; break;
  323. case IRQ_TYPE_LEVEL_HIGH:
  324. l = 1; p = 1; break;
  325. case IRQ_TYPE_LEVEL_LOW:
  326. l = 1; p = 0; break;
  327. default:
  328. pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
  329. __func__, type);
  330. return -ENXIO;
  331. }
  332. if (l)
  333. stmp3xxx_setl(1 << gpio, pm->irqlevel);
  334. else
  335. stmp3xxx_clearl(1 << gpio, pm->irqlevel);
  336. if (p)
  337. stmp3xxx_setl(1 << gpio, pm->irqpolarity);
  338. else
  339. stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
  340. return 0;
  341. }
  342. static void stmp3xxx_pin_ack_irq(unsigned irq)
  343. {
  344. u32 stat;
  345. struct stmp3xxx_pinmux_bank *pm;
  346. unsigned gpio;
  347. stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
  348. stat = __raw_readl(pm->irqstat) & (1 << gpio);
  349. stmp3xxx_clearl(stat, pm->irqstat);
  350. }
  351. static void stmp3xxx_pin_mask_irq(unsigned irq)
  352. {
  353. struct stmp3xxx_pinmux_bank *pm;
  354. unsigned gpio;
  355. stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
  356. stmp3xxx_clearl(1 << gpio, pm->irqen);
  357. stmp3xxx_clearl(1 << gpio, pm->pin2irq);
  358. }
  359. static void stmp3xxx_pin_unmask_irq(unsigned irq)
  360. {
  361. struct stmp3xxx_pinmux_bank *pm;
  362. unsigned gpio;
  363. stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
  364. stmp3xxx_setl(1 << gpio, pm->irqen);
  365. stmp3xxx_setl(1 << gpio, pm->pin2irq);
  366. }
  367. static inline
  368. struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
  369. {
  370. return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
  371. }
  372. static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  373. {
  374. struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
  375. return pm->virq + offset;
  376. }
  377. static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
  378. {
  379. struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
  380. unsigned v;
  381. v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
  382. return v ? 1 : 0;
  383. }
  384. static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
  385. {
  386. struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
  387. if (v)
  388. stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
  389. else
  390. stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
  391. }
  392. static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
  393. {
  394. struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
  395. stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
  396. stmp3xxx_gpio_set(chip, offset, v);
  397. return 0;
  398. }
  399. static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
  400. {
  401. struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
  402. stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
  403. return 0;
  404. }
  405. static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
  406. {
  407. return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
  408. }
  409. static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
  410. {
  411. stmp3xxx_release_pin(chip->base + offset, "gpio");
  412. }
  413. static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
  414. {
  415. struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
  416. int gpio_irq = pm->virq;
  417. u32 stat = __raw_readl(pm->irqstat);
  418. while (stat) {
  419. if (stat & 1)
  420. irq_desc[gpio_irq].handle_irq(gpio_irq,
  421. &irq_desc[gpio_irq]);
  422. gpio_irq++;
  423. stat >>= 1;
  424. }
  425. }
  426. static struct irq_chip gpio_irq_chip = {
  427. .ack = stmp3xxx_pin_ack_irq,
  428. .mask = stmp3xxx_pin_mask_irq,
  429. .unmask = stmp3xxx_pin_unmask_irq,
  430. .set_type = stmp3xxx_set_irqtype,
  431. };
  432. int __init stmp3xxx_pinmux_init(int virtual_irq_start)
  433. {
  434. int b, r = 0;
  435. struct stmp3xxx_pinmux_bank *pm;
  436. int virq;
  437. for (b = 0; b < 3; b++) {
  438. /* only banks 0,1,2 are allowed to GPIO */
  439. pm = pinmux_banks + b;
  440. pm->chip.base = 32 * b;
  441. pm->chip.ngpio = 32;
  442. pm->chip.owner = THIS_MODULE;
  443. pm->chip.can_sleep = 1;
  444. pm->chip.exported = 1;
  445. pm->chip.to_irq = stmp3xxx_gpio_to_irq;
  446. pm->chip.direction_input = stmp3xxx_gpio_input;
  447. pm->chip.direction_output = stmp3xxx_gpio_output;
  448. pm->chip.get = stmp3xxx_gpio_get;
  449. pm->chip.set = stmp3xxx_gpio_set;
  450. pm->chip.request = stmp3xxx_gpio_request;
  451. pm->chip.free = stmp3xxx_gpio_free;
  452. pm->virq = virtual_irq_start + b * 32;
  453. for (virq = pm->virq; virq < pm->virq; virq++) {
  454. gpio_irq_chip.mask(virq);
  455. set_irq_chip(virq, &gpio_irq_chip);
  456. set_irq_handler(virq, handle_level_irq);
  457. set_irq_flags(virq, IRQF_VALID);
  458. }
  459. r = gpiochip_add(&pm->chip);
  460. if (r < 0)
  461. break;
  462. set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
  463. set_irq_data(pm->irq, pm);
  464. }
  465. return r;
  466. }
  467. MODULE_AUTHOR("Vladislav Buzov");
  468. MODULE_LICENSE("GPL");