pinmux.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /**
  2. * \file
  3. *
  4. * \brief SAM Pin Multiplexer Driver
  5. *
  6. * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
  7. *
  8. * \asf_license_start
  9. *
  10. * \page License
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions are met:
  14. *
  15. * 1. Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. *
  18. * 2. Redistributions in binary form must reproduce the above copyright notice,
  19. * this list of conditions and the following disclaimer in the documentation
  20. * and/or other materials provided with the distribution.
  21. *
  22. * 3. The name of Atmel may not be used to endorse or promote products derived
  23. * from this software without specific prior written permission.
  24. *
  25. * 4. This software may only be redistributed and used in connection with an
  26. * Atmel microcontroller product.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  30. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  31. * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
  32. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  36. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  37. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  38. * POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. * \asf_license_stop
  41. *
  42. */
  43. /*
  44. * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
  45. */
  46. #include <pinmux.h>
  47. /**
  48. * \internal
  49. * Writes out a given configuration of a Port pin configuration to the
  50. * hardware module.
  51. *
  52. * \note If the pin direction is set as an output, the pull-up/pull-down input
  53. * configuration setting is ignored.
  54. *
  55. * \param[in] port Base of the PORT module to configure
  56. * \param[in] pin_mask Mask of the port pin to configure
  57. * \param[in] config Configuration settings for the pin
  58. */
  59. static void _system_pinmux_config(
  60. PortGroup *const port,
  61. const uint32_t pin_mask,
  62. const struct system_pinmux_config *const config)
  63. {
  64. Assert(port);
  65. Assert(config);
  66. /* Track the configuration bits into a temporary variable before writing */
  67. uint32_t pin_cfg = 0;
  68. /* Enabled powersave mode, don't create configuration */
  69. if (!config->powersave) {
  70. /* Enable the pin peripheral MUX flag if non-GPIO selected (pinmux will
  71. * be written later) and store the new MUX mask */
  72. if (config->mux_position != SYSTEM_PINMUX_GPIO) {
  73. pin_cfg |= PORT_WRCONFIG_PMUXEN;
  74. pin_cfg |= (config->mux_position << PORT_WRCONFIG_PMUX_Pos);
  75. }
  76. /* Check if the user has requested that the input buffer be enabled */
  77. if ((config->direction == SYSTEM_PINMUX_PIN_DIR_INPUT) ||
  78. (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
  79. /* Enable input buffer flag */
  80. pin_cfg |= PORT_WRCONFIG_INEN;
  81. /* Enable pull-up/pull-down control flag if requested */
  82. if (config->input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) {
  83. pin_cfg |= PORT_WRCONFIG_PULLEN;
  84. }
  85. /* Clear the port DIR bits to disable the output buffer */
  86. port->DIRCLR.reg = pin_mask;
  87. }
  88. /* Check if the user has requested that the output buffer be enabled */
  89. if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
  90. (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
  91. /* Cannot use a pull-up if the output driver is enabled,
  92. * if requested the input buffer can only sample the current
  93. * output state */
  94. pin_cfg &= ~PORT_WRCONFIG_PULLEN;
  95. }
  96. } else {
  97. port->DIRCLR.reg = pin_mask;
  98. }
  99. /* The Write Configuration register (WRCONFIG) requires the
  100. * pins to to grouped into two 16-bit half-words - split them out here */
  101. uint32_t lower_pin_mask = (pin_mask & 0xFFFF);
  102. uint32_t upper_pin_mask = (pin_mask >> 16);
  103. /* Configure the lower 16-bits of the port to the desired configuration,
  104. * including the pin peripheral multiplexer just in case it is enabled */
  105. port->WRCONFIG.reg
  106. = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
  107. pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;
  108. /* Configure the upper 16-bits of the port to the desired configuration,
  109. * including the pin peripheral multiplexer just in case it is enabled */
  110. port->WRCONFIG.reg
  111. = (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
  112. pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG |
  113. PORT_WRCONFIG_HWSEL;
  114. if(!config->powersave) {
  115. /* Set the pull-up state once the port pins are configured if one was
  116. * requested and it does not violate the valid set of port
  117. * configurations */
  118. if (pin_cfg & PORT_WRCONFIG_PULLEN) {
  119. /* Set the OUT register bits to enable the pull-up if requested,
  120. * clear to enable pull-down */
  121. if (config->input_pull == SYSTEM_PINMUX_PIN_PULL_UP) {
  122. port->OUTSET.reg = pin_mask;
  123. } else {
  124. port->OUTCLR.reg = pin_mask;
  125. }
  126. }
  127. /* Check if the user has requested that the output buffer be enabled */
  128. if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
  129. (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
  130. /* Set the port DIR bits to enable the output buffer */
  131. port->DIRSET.reg = pin_mask;
  132. }
  133. }
  134. }
  135. /**
  136. * \brief Writes a Port pin configuration to the hardware module.
  137. *
  138. * Writes out a given configuration of a Port pin configuration to the hardware
  139. * module.
  140. *
  141. * \note If the pin direction is set as an output, the pull-up/pull-down input
  142. * configuration setting is ignored.
  143. *
  144. * \param[in] gpio_pin Index of the GPIO pin to configure
  145. * \param[in] config Configuration settings for the pin
  146. */
  147. void system_pinmux_pin_set_config(
  148. const uint8_t gpio_pin,
  149. const struct system_pinmux_config *const config)
  150. {
  151. PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin);
  152. uint32_t pin_mask = (1UL << (gpio_pin % 32));
  153. _system_pinmux_config(port, pin_mask, config);
  154. }
  155. /**
  156. * \brief Writes a Port pin group configuration to the hardware module.
  157. *
  158. * Writes out a given configuration of a Port pin group configuration to the
  159. * hardware module.
  160. *
  161. * \note If the pin direction is set as an output, the pull-up/pull-down input
  162. * configuration setting is ignored.
  163. *
  164. * \param[in] port Base of the PORT module to configure
  165. * \param[in] mask Mask of the port pin(s) to configure
  166. * \param[in] config Configuration settings for the pin
  167. */
  168. void system_pinmux_group_set_config(
  169. PortGroup *const port,
  170. const uint32_t mask,
  171. const struct system_pinmux_config *const config)
  172. {
  173. Assert(port);
  174. for (int i = 0; i < 32; i++) {
  175. if (mask & (1UL << i)) {
  176. _system_pinmux_config(port, (1UL << i), config);
  177. }
  178. }
  179. }
  180. /**
  181. * \brief Configures the input sampling mode for a group of pins.
  182. *
  183. * Configures the input sampling mode for a group of pins, to
  184. * control when the physical I/O pin value is sampled and
  185. * stored inside the microcontroller.
  186. *
  187. * \param[in] port Base of the PORT module to configure
  188. * \param[in] mask Mask of the port pin(s) to configure
  189. * \param[in] mode New pin sampling mode to configure
  190. */
  191. void system_pinmux_group_set_input_sample_mode(
  192. PortGroup *const port,
  193. const uint32_t mask,
  194. const enum system_pinmux_pin_sample mode)
  195. {
  196. Assert(port);
  197. if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) {
  198. port->CTRL.reg |= mask;
  199. } else {
  200. port->CTRL.reg &= ~mask;
  201. }
  202. }
  203. #ifdef FEATURE_SYSTEM_PINMUX_SLEWRATE_LIMITER
  204. /**
  205. * \brief Configures the output slew rate mode for a group of pins.
  206. *
  207. * Configures the output slew rate mode for a group of pins, to
  208. * control the speed at which the physical output pin can react to
  209. * logical changes of the I/O pin value.
  210. *
  211. * \param[in] port Base of the PORT module to configure
  212. * \param[in] mask Mask of the port pin(s) to configure
  213. * \param[in] mode New pin slew rate mode to configure
  214. */
  215. void system_pinmux_group_set_output_slew_rate(
  216. PortGroup *const port,
  217. const uint32_t mask,
  218. const enum system_pinmux_pin_slew_rate mode)
  219. {
  220. Assert(port);
  221. for (int i = 0; i < 32; i++) {
  222. if (mask & (1UL << i)) {
  223. if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) {
  224. port->PINCFG[i].reg |= PORT_PINCFG_SLEWLIM;
  225. } else {
  226. port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM;
  227. }
  228. }
  229. }
  230. }
  231. #endif
  232. #ifdef FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH
  233. /**
  234. * \brief Configures the output driver strength mode for a group of pins.
  235. *
  236. * Configures the output drive strength for a group of pins, to
  237. * control the amount of current the pad is able to sink/source.
  238. *
  239. * \param[in] port Base of the PORT module to configure
  240. * \param[in] mask Mask of the port pin(s) to configure
  241. * \param[in] mode New output driver strength mode to configure
  242. */
  243. void system_pinmux_group_set_output_strength(
  244. PortGroup *const port,
  245. const uint32_t mask,
  246. const enum system_pinmux_pin_strength mode)
  247. {
  248. Assert(port);
  249. for (int i = 0; i < 32; i++) {
  250. if (mask & (1UL << i)) {
  251. if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) {
  252. port->PINCFG[i].reg |= PORT_PINCFG_DRVSTR;
  253. } else {
  254. port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR;
  255. }
  256. }
  257. }
  258. }
  259. #endif
  260. #ifdef FEATURE_SYSTEM_PINMUX_OPEN_DRAIN
  261. /**
  262. * \brief Configures the output driver mode for a group of pins.
  263. *
  264. * Configures the output driver mode for a group of pins, to
  265. * control the pad behavior.
  266. *
  267. * \param[in] port Base of the PORT module to configure
  268. * \param[in] mask Mask of the port pin(s) to configure
  269. * \param[in] mode New pad output driver mode to configure
  270. */
  271. void system_pinmux_group_set_output_drive(
  272. PortGroup *const port,
  273. const uint32_t mask,
  274. const enum system_pinmux_pin_drive mode)
  275. {
  276. Assert(port);
  277. for (int i = 0; i < 32; i++) {
  278. if (mask & (1UL << i)) {
  279. if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) {
  280. port->PINCFG[i].reg |= PORT_PINCFG_ODRAIN;
  281. } else {
  282. port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN;
  283. }
  284. }
  285. }
  286. }
  287. #endif