opamp.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /****************************************************************************
  2. * drivers/analog/opamp.c
  3. *
  4. * Copyright (C) 2017 Gregory Nutt. All rights reserved.
  5. * Author: Mateusz Szafoni <raiden00@railab.me>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <stdint.h>
  41. #include <unistd.h>
  42. #include <semaphore.h>
  43. #include <fcntl.h>
  44. #include <errno.h>
  45. #include <debug.h>
  46. #include <nuttx/arch.h>
  47. #include <nuttx/semaphore.h>
  48. #include <nuttx/fs/fs.h>
  49. #include <nuttx/analog/opamp.h>
  50. #include <nuttx/irq.h>
  51. /****************************************************************************
  52. * Private Function Prototypes
  53. ****************************************************************************/
  54. static int opamp_open(FAR struct file *filep);
  55. static int opamp_close(FAR struct file *filep);
  56. static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
  57. /****************************************************************************
  58. * Private Data
  59. ****************************************************************************/
  60. static const struct file_operations opamp_fops =
  61. {
  62. opamp_open, /* open */
  63. opamp_close, /* close */
  64. NULL, /* read */
  65. NULL, /* write */
  66. NULL, /* seek */
  67. opamp_ioctl, /* ioctl */
  68. NULL /* poll */
  69. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  70. , NULL /* unlink */
  71. #endif
  72. };
  73. /****************************************************************************
  74. * Private Functions
  75. ****************************************************************************/
  76. /****************************************************************************
  77. * Name: opamp_open
  78. *
  79. * Description:
  80. * This function is called whenever the OPAMP device is opened.
  81. *
  82. ****************************************************************************/
  83. static int opamp_open(FAR struct file *filep)
  84. {
  85. FAR struct inode *inode = filep->f_inode;
  86. FAR struct opamp_dev_s *dev = inode->i_private;
  87. uint8_t tmp;
  88. int ret;
  89. /* If the port is the middle of closing, wait until the close is finished */
  90. ret = nxsem_wait(&dev->ad_closesem);
  91. if (ret >= 0)
  92. {
  93. /* Increment the count of references to the device. If this the first
  94. * time that the driver has been opened for this device, then initialize
  95. * the device.
  96. */
  97. tmp = dev->ad_ocount + 1;
  98. if (tmp == 0)
  99. {
  100. /* More than 255 opens; uint8_t overflows to zero */
  101. ret = -EMFILE;
  102. }
  103. else
  104. {
  105. /* Check if this is the first time that the driver has been opened. */
  106. if (tmp == 1)
  107. {
  108. /* Yes.. perform one time hardware initialization. */
  109. irqstate_t flags = enter_critical_section();
  110. ret = dev->ad_ops->ao_setup(dev);
  111. if (ret == OK)
  112. {
  113. /* Save the new open count on success */
  114. dev->ad_ocount = tmp;
  115. }
  116. leave_critical_section(flags);
  117. }
  118. }
  119. nxsem_post(&dev->ad_closesem);
  120. }
  121. return ret;
  122. }
  123. /****************************************************************************
  124. * Name: opamp_close
  125. *
  126. * Description:
  127. * This routine is called when the OPAMP device is closed.
  128. * It waits for the last remaining data to be sent.
  129. *
  130. ****************************************************************************/
  131. static int opamp_close(FAR struct file *filep)
  132. {
  133. FAR struct inode *inode = filep->f_inode;
  134. FAR struct opamp_dev_s *dev = inode->i_private;
  135. irqstate_t flags;
  136. int ret;
  137. ret = nxsem_wait(&dev->ad_closesem);
  138. if (ret >= 0)
  139. {
  140. /* Decrement the references to the driver. If the reference count will
  141. * decrement to 0, then uninitialize the driver.
  142. */
  143. if (dev->ad_ocount > 1)
  144. {
  145. dev->ad_ocount--;
  146. nxsem_post(&dev->ad_closesem);
  147. }
  148. else
  149. {
  150. /* There are no more references to the port */
  151. dev->ad_ocount = 0;
  152. /* Free the IRQ and disable the OPAMP device */
  153. flags = enter_critical_section(); /* Disable interrupts */
  154. dev->ad_ops->ao_shutdown(dev); /* Disable the OPAMP */
  155. leave_critical_section(flags);
  156. nxsem_post(&dev->ad_closesem);
  157. }
  158. }
  159. return ret;
  160. }
  161. /****************************************************************************
  162. * Name: opamp_ioctl
  163. ****************************************************************************/
  164. static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  165. {
  166. FAR struct inode *inode = filep->f_inode;
  167. FAR struct opamp_dev_s *dev = inode->i_private;
  168. int ret;
  169. ret = dev->ad_ops->ao_ioctl(dev, cmd, arg);
  170. return ret;
  171. }
  172. /****************************************************************************
  173. * Public Functions
  174. ****************************************************************************/
  175. /****************************************************************************
  176. * Name: opamp_register
  177. ****************************************************************************/
  178. int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev)
  179. {
  180. int ret;
  181. /* Initialize the OPAMP device structure */
  182. dev->ad_ocount = 0;
  183. /* Initialize semaphores */
  184. nxsem_init(&dev->ad_closesem, 0, 1);
  185. /* Register the OPAMP character driver */
  186. ret = register_driver(path, &opamp_fops, 0444, dev);
  187. if (ret < 0)
  188. {
  189. nxsem_destroy(&dev->ad_closesem);
  190. }
  191. return ret;
  192. }