solo6x10-gpio.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
  3. *
  4. * Original author:
  5. * Ben Collins <bcollins@ubuntu.com>
  6. *
  7. * Additional work by:
  8. * John Brooks <john.brooks@bluecherry.net>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. */
  20. #include <linux/kernel.h>
  21. #include <linux/fs.h>
  22. #include <linux/delay.h>
  23. #include <linux/uaccess.h>
  24. #include "solo6x10.h"
  25. static void solo_gpio_mode(struct solo_dev *solo_dev,
  26. unsigned int port_mask, unsigned int mode)
  27. {
  28. int port;
  29. unsigned int ret;
  30. ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
  31. /* To set gpio */
  32. for (port = 0; port < 16; port++) {
  33. if (!((1 << port) & port_mask))
  34. continue;
  35. ret &= (~(3 << (port << 1)));
  36. ret |= ((mode & 3) << (port << 1));
  37. }
  38. solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret);
  39. /* To set extended gpio - sensor */
  40. ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
  41. for (port = 0; port < 16; port++) {
  42. if (!((1 << (port + 16)) & port_mask))
  43. continue;
  44. if (!mode)
  45. ret &= ~(1 << port);
  46. else
  47. ret |= 1 << port;
  48. }
  49. /* Enable GPIO[31:16] */
  50. ret |= 0xffff0000;
  51. solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret);
  52. }
  53. static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value)
  54. {
  55. solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
  56. solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value);
  57. }
  58. static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value)
  59. {
  60. solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT,
  61. solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value);
  62. }
  63. static void solo_gpio_config(struct solo_dev *solo_dev)
  64. {
  65. /* Video reset */
  66. solo_gpio_mode(solo_dev, 0x30, 1);
  67. solo_gpio_clear(solo_dev, 0x30);
  68. udelay(100);
  69. solo_gpio_set(solo_dev, 0x30);
  70. udelay(100);
  71. /* Warning: Don't touch the next line unless you're sure of what
  72. * you're doing: first four gpio [0-3] are used for video. */
  73. solo_gpio_mode(solo_dev, 0x0f, 2);
  74. /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */
  75. solo_gpio_mode(solo_dev, 0xff00, 1);
  76. /* Initially set relay status to 0 */
  77. solo_gpio_clear(solo_dev, 0xff00);
  78. /* Set input pins direction */
  79. solo_gpio_mode(solo_dev, 0xffff0000, 0);
  80. }
  81. #ifdef CONFIG_GPIOLIB
  82. /* Pins 0-7 are not exported, because it seems from code above they are
  83. * used for internal purposes. So offset 0 corresponds to pin 8, therefore
  84. * offsets 0-7 are relay GPIOs, 8-23 - input GPIOs.
  85. */
  86. static int solo_gpiochip_get_direction(struct gpio_chip *chip,
  87. unsigned int offset)
  88. {
  89. int ret, mode;
  90. struct solo_dev *solo_dev = gpiochip_get_data(chip);
  91. if (offset < 8) {
  92. ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0);
  93. mode = 3 & (ret >> ((offset + 8) * 2));
  94. } else {
  95. ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1);
  96. mode = 1 & (ret >> (offset - 8));
  97. }
  98. if (!mode)
  99. return 1;
  100. else if (mode == 1)
  101. return 0;
  102. return -1;
  103. }
  104. static int solo_gpiochip_direction_input(struct gpio_chip *chip,
  105. unsigned int offset)
  106. {
  107. return -1;
  108. }
  109. static int solo_gpiochip_direction_output(struct gpio_chip *chip,
  110. unsigned int offset, int value)
  111. {
  112. return -1;
  113. }
  114. static int solo_gpiochip_get(struct gpio_chip *chip,
  115. unsigned int offset)
  116. {
  117. int ret;
  118. struct solo_dev *solo_dev = gpiochip_get_data(chip);
  119. ret = solo_reg_read(solo_dev, SOLO_GPIO_DATA_IN);
  120. return 1 & (ret >> (offset + 8));
  121. }
  122. static void solo_gpiochip_set(struct gpio_chip *chip,
  123. unsigned int offset, int value)
  124. {
  125. struct solo_dev *solo_dev = gpiochip_get_data(chip);
  126. if (value)
  127. solo_gpio_set(solo_dev, 1 << (offset + 8));
  128. else
  129. solo_gpio_clear(solo_dev, 1 << (offset + 8));
  130. }
  131. #endif
  132. int solo_gpio_init(struct solo_dev *solo_dev)
  133. {
  134. #ifdef CONFIG_GPIOLIB
  135. int ret;
  136. #endif
  137. solo_gpio_config(solo_dev);
  138. #ifdef CONFIG_GPIOLIB
  139. solo_dev->gpio_dev.label = SOLO6X10_NAME"_gpio";
  140. solo_dev->gpio_dev.parent = &solo_dev->pdev->dev;
  141. solo_dev->gpio_dev.owner = THIS_MODULE;
  142. solo_dev->gpio_dev.base = -1;
  143. solo_dev->gpio_dev.ngpio = 24;
  144. solo_dev->gpio_dev.can_sleep = 0;
  145. solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction;
  146. solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input;
  147. solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output;
  148. solo_dev->gpio_dev.get = solo_gpiochip_get;
  149. solo_dev->gpio_dev.set = solo_gpiochip_set;
  150. ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev);
  151. if (ret) {
  152. solo_dev->gpio_dev.label = NULL;
  153. return -1;
  154. }
  155. #endif
  156. return 0;
  157. }
  158. void solo_gpio_exit(struct solo_dev *solo_dev)
  159. {
  160. #ifdef CONFIG_GPIOLIB
  161. if (solo_dev->gpio_dev.label) {
  162. gpiochip_remove(&solo_dev->gpio_dev);
  163. solo_dev->gpio_dev.label = NULL;
  164. }
  165. #endif
  166. solo_gpio_clear(solo_dev, 0x30);
  167. solo_gpio_config(solo_dev);
  168. }