pinmux.c 14 KB

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