gpio-clps711x.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * CLPS711X GPIO driver
  3. *
  4. * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. */
  11. #include <linux/io.h>
  12. #include <linux/slab.h>
  13. #include <linux/gpio.h>
  14. #include <linux/module.h>
  15. #include <linux/spinlock.h>
  16. #include <linux/platform_device.h>
  17. #include <mach/hardware.h>
  18. #define CLPS711X_GPIO_PORTS 5
  19. #define CLPS711X_GPIO_NAME "gpio-clps711x"
  20. struct clps711x_gpio {
  21. struct gpio_chip chip[CLPS711X_GPIO_PORTS];
  22. spinlock_t lock;
  23. };
  24. static void __iomem *clps711x_ports[] = {
  25. CLPS711X_VIRT_BASE + PADR,
  26. CLPS711X_VIRT_BASE + PBDR,
  27. CLPS711X_VIRT_BASE + PCDR,
  28. CLPS711X_VIRT_BASE + PDDR,
  29. CLPS711X_VIRT_BASE + PEDR,
  30. };
  31. static void __iomem *clps711x_pdirs[] = {
  32. CLPS711X_VIRT_BASE + PADDR,
  33. CLPS711X_VIRT_BASE + PBDDR,
  34. CLPS711X_VIRT_BASE + PCDDR,
  35. CLPS711X_VIRT_BASE + PDDDR,
  36. CLPS711X_VIRT_BASE + PEDDR,
  37. };
  38. #define clps711x_port(x) clps711x_ports[x->base / 8]
  39. #define clps711x_pdir(x) clps711x_pdirs[x->base / 8]
  40. static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset)
  41. {
  42. return !!(readb(clps711x_port(chip)) & (1 << offset));
  43. }
  44. static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset,
  45. int value)
  46. {
  47. int tmp;
  48. unsigned long flags;
  49. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  50. spin_lock_irqsave(&gpio->lock, flags);
  51. tmp = readb(clps711x_port(chip)) & ~(1 << offset);
  52. if (value)
  53. tmp |= 1 << offset;
  54. writeb(tmp, clps711x_port(chip));
  55. spin_unlock_irqrestore(&gpio->lock, flags);
  56. }
  57. static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset)
  58. {
  59. int tmp;
  60. unsigned long flags;
  61. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  62. spin_lock_irqsave(&gpio->lock, flags);
  63. tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
  64. writeb(tmp, clps711x_pdir(chip));
  65. spin_unlock_irqrestore(&gpio->lock, flags);
  66. return 0;
  67. }
  68. static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset,
  69. int value)
  70. {
  71. int tmp;
  72. unsigned long flags;
  73. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  74. spin_lock_irqsave(&gpio->lock, flags);
  75. tmp = readb(clps711x_pdir(chip)) | (1 << offset);
  76. writeb(tmp, clps711x_pdir(chip));
  77. tmp = readb(clps711x_port(chip)) & ~(1 << offset);
  78. if (value)
  79. tmp |= 1 << offset;
  80. writeb(tmp, clps711x_port(chip));
  81. spin_unlock_irqrestore(&gpio->lock, flags);
  82. return 0;
  83. }
  84. static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset)
  85. {
  86. int tmp;
  87. unsigned long flags;
  88. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  89. spin_lock_irqsave(&gpio->lock, flags);
  90. tmp = readb(clps711x_pdir(chip)) | (1 << offset);
  91. writeb(tmp, clps711x_pdir(chip));
  92. spin_unlock_irqrestore(&gpio->lock, flags);
  93. return 0;
  94. }
  95. static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset,
  96. int value)
  97. {
  98. int tmp;
  99. unsigned long flags;
  100. struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev);
  101. spin_lock_irqsave(&gpio->lock, flags);
  102. tmp = readb(clps711x_pdir(chip)) & ~(1 << offset);
  103. writeb(tmp, clps711x_pdir(chip));
  104. tmp = readb(clps711x_port(chip)) & ~(1 << offset);
  105. if (value)
  106. tmp |= 1 << offset;
  107. writeb(tmp, clps711x_port(chip));
  108. spin_unlock_irqrestore(&gpio->lock, flags);
  109. return 0;
  110. }
  111. static struct {
  112. char *name;
  113. int nr;
  114. int inv_dir;
  115. } clps711x_gpio_ports[] __initconst = {
  116. { "PORTA", 8, 0, },
  117. { "PORTB", 8, 0, },
  118. { "PORTC", 8, 0, },
  119. { "PORTD", 8, 1, },
  120. { "PORTE", 3, 0, },
  121. };
  122. static int __init gpio_clps711x_init(void)
  123. {
  124. int i;
  125. struct platform_device *pdev;
  126. struct clps711x_gpio *gpio;
  127. pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0);
  128. if (!pdev) {
  129. pr_err("Cannot create platform device: %s\n",
  130. CLPS711X_GPIO_NAME);
  131. return -ENOMEM;
  132. }
  133. platform_device_add(pdev);
  134. gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio),
  135. GFP_KERNEL);
  136. if (!gpio) {
  137. dev_err(&pdev->dev, "GPIO allocating memory error\n");
  138. platform_device_unregister(pdev);
  139. return -ENOMEM;
  140. }
  141. platform_set_drvdata(pdev, gpio);
  142. spin_lock_init(&gpio->lock);
  143. for (i = 0; i < CLPS711X_GPIO_PORTS; i++) {
  144. gpio->chip[i].owner = THIS_MODULE;
  145. gpio->chip[i].dev = &pdev->dev;
  146. gpio->chip[i].label = clps711x_gpio_ports[i].name;
  147. gpio->chip[i].base = i * 8;
  148. gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr;
  149. gpio->chip[i].get = gpio_clps711x_get;
  150. gpio->chip[i].set = gpio_clps711x_set;
  151. if (!clps711x_gpio_ports[i].inv_dir) {
  152. gpio->chip[i].direction_input = gpio_clps711x_dir_in;
  153. gpio->chip[i].direction_output = gpio_clps711x_dir_out;
  154. } else {
  155. gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv;
  156. gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv;
  157. }
  158. WARN_ON(gpiochip_add(&gpio->chip[i]));
  159. }
  160. dev_info(&pdev->dev, "GPIO driver initialized\n");
  161. return 0;
  162. }
  163. arch_initcall(gpio_clps711x_init);
  164. MODULE_LICENSE("GPL v2");
  165. MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
  166. MODULE_DESCRIPTION("CLPS711X GPIO driver");