4 * \brief SAM D20 Pin Multiplexer Driver
\r
6 * Copyright (C) 2012-2013 Atmel Corporation. All rights reserved.
\r
12 * Redistribution and use in source and binary forms, with or without
\r
13 * modification, are permitted provided that the following conditions are met:
\r
15 * 1. Redistributions of source code must retain the above copyright notice,
\r
16 * this list of conditions and the following disclaimer.
\r
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
19 * this list of conditions and the following disclaimer in the documentation
\r
20 * and/or other materials provided with the distribution.
\r
22 * 3. The name of Atmel may not be used to endorse or promote products derived
\r
23 * from this software without specific prior written permission.
\r
25 * 4. This software may only be redistributed and used in connection with an
\r
26 * Atmel microcontroller product.
\r
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
\r
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
\r
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
38 * POSSIBILITY OF SUCH DAMAGE.
\r
47 * Writes out a given configuration of a Port pin configuration to the
\r
50 * \note If the pin direction is set as an output, the pull-up/pull-down input
\r
51 * configuration setting is ignored.
\r
53 * \param[in] port Base of the PORT module to configure.
\r
54 * \param[in] pin_mask Mask of the port pin to configure.
\r
55 * \param[in] config Configuration settings for the pin.
\r
57 static void _system_pinmux_config(
\r
58 PortGroup *const port,
\r
59 const uint32_t pin_mask,
\r
60 const struct system_pinmux_config *const config)
\r
65 /* Track the configuration bits into a temporary variable before writing */
\r
66 uint32_t pin_cfg = 0;
\r
68 /* Enable the pin peripheral mux flag if non-GPIO selected (pin mux will
\r
69 * be written later) and store the new mux mask */
\r
70 if (config->mux_position != SYSTEM_PINMUX_GPIO) {
\r
71 pin_cfg |= PORT_WRCONFIG_PMUXEN;
\r
72 pin_cfg |= (config->mux_position << PORT_WRCONFIG_PMUX_Pos);
\r
75 /* Check if the user has requested that the input buffer be enabled */
\r
76 if ((config->direction == SYSTEM_PINMUX_PIN_DIR_INPUT) ||
\r
77 (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
\r
78 /* Enable input buffer flag */
\r
79 pin_cfg |= PORT_WRCONFIG_INEN;
\r
81 /* Enable pull-up/pull-down control flag if requested */
\r
82 if (config->input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) {
\r
83 pin_cfg |= PORT_WRCONFIG_PULLEN;
\r
86 /* Clear the port DIR bits to disable the output buffer */
\r
87 port->DIRCLR.reg = pin_mask;
\r
90 /* Check if the user has requested that the output buffer be enabled */
\r
91 if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
\r
92 (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
\r
93 /* Cannot use a pullup if the output driver is enabled,
\r
94 * if requested the input buffer can only sample the current
\r
96 pin_cfg &= ~PORT_WRCONFIG_PULLEN;
\r
98 /* Set the port DIR bits to enable the output buffer */
\r
99 port->DIRSET.reg = pin_mask;
\r
102 /* The Write Configuration register (WRCONFIG) requires the
\r
103 * pins to to grouped into two 16-bit half-words - split them out here */
\r
104 uint32_t lower_pin_mask = (pin_mask & 0xFFFF);
\r
105 uint32_t upper_pin_mask = (pin_mask >> 16);
\r
107 /* Configure the lower 16-bits of the port to the desired configuration,
\r
108 * including the pin peripheral multiplexer just in case it is enabled */
\r
110 = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
\r
111 pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;
\r
113 /* Configure the upper 16-bits of the port to the desired configuration,
\r
114 * including the pin peripheral multiplexer just in case it is enabled */
\r
116 = (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
\r
117 pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG |
\r
118 PORT_WRCONFIG_HWSEL;
\r
120 /* Set the pull-up state once the port pins are configured if one was
\r
121 * requested and it does not violate the valid set of port
\r
122 * configurations */
\r
123 if (pin_cfg & PORT_WRCONFIG_PULLEN) {
\r
124 /* Set the OUT register bits to enable the pullup if requested,
\r
125 * clear to enable pull-down */
\r
126 if (config->input_pull == SYSTEM_PINMUX_PIN_PULL_UP) {
\r
127 port->OUTSET.reg = pin_mask;
\r
129 port->OUTCLR.reg = pin_mask;
\r
135 * \brief Writes a Port pin configuration to the hardware module.
\r
137 * Writes out a given configuration of a Port pin configuration to the hardware
\r
140 * \note If the pin direction is set as an output, the pull-up/pull-down input
\r
141 * configuration setting is ignored.
\r
143 * \param[in] gpio_pin Index of the GPIO pin to configure.
\r
144 * \param[in] config Configuration settings for the pin.
\r
146 void system_pinmux_pin_set_config(
\r
147 const uint8_t gpio_pin,
\r
148 const struct system_pinmux_config *const config)
\r
150 PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin);
\r
151 uint32_t pin_mask = (1UL << (gpio_pin % 32));
\r
153 _system_pinmux_config(port, pin_mask, config);
\r
157 * \brief Writes a Port pin group configuration to the hardware module.
\r
159 * Writes out a given configuration of a Port pin group configuration to the
\r
162 * \note If the pin direction is set as an output, the pull-up/pull-down input
\r
163 * configuration setting is ignored.
\r
165 * \param[in] port Base of the PORT module to configure.
\r
166 * \param[in] mask Mask of the port pin(s) to configure.
\r
167 * \param[in] config Configuration settings for the pin.
\r
169 void system_pinmux_group_set_config(
\r
170 PortGroup *const port,
\r
171 const uint32_t mask,
\r
172 const struct system_pinmux_config *const config)
\r
176 for (int i = 0; i < 32; i++) {
\r
177 if (mask & (1UL << i)) {
\r
178 _system_pinmux_config(port, (1UL << i), config);
\r
184 * \brief Configures the input sampling mode for a group of pins.
\r
186 * Configures the input sampling mode for a group of pins, to
\r
187 * control when the physical I/O pin value is sampled and
\r
188 * stored inside the microcontroller.
\r
190 * \param[in] port Base of the PORT module to configure.
\r
191 * \param[in] mask Mask of the port pin(s) to configure.
\r
192 * \param[in] mode New pin sampling mode to configure.
\r
194 void system_pinmux_group_set_input_sample_mode(
\r
195 PortGroup *const port,
\r
196 const uint32_t mask,
\r
197 const enum system_pinmux_pin_sample mode)
\r
201 for (int i = 0; i < 32; i++) {
\r
202 if (mask & (1UL << i)) {
\r
203 uint32_t sample_quad_mask = (1UL << (i / 4));
\r
205 if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) {
\r
206 port->CTRL.reg |= sample_quad_mask;
\r
209 port->CTRL.reg &= ~sample_quad_mask;
\r
216 * \brief Configures the output driver strength mode for a group of pins.
\r
218 * Configures the output drive strength for a group of pins, to
\r
219 * control the amount of current the pad is able to sink/source.
\r
221 * \param[in] port Base of the PORT module to configure.
\r
222 * \param[in] mask Mask of the port pin(s) to configure.
\r
223 * \param[in] mode New output driver strength mode to configure.
\r
225 void system_pinmux_group_set_output_strength(
\r
226 PortGroup *const port,
\r
227 const uint32_t mask,
\r
228 const enum system_pinmux_pin_strength mode)
\r
232 for (int i = 0; i < 32; i++) {
\r
233 if (mask & (1UL << i)) {
\r
234 if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) {
\r
235 port->PINCFG[i].reg |= PORT_PINCFG_DRVSTR;
\r
238 port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR;
\r
245 * \brief Configures the output slew rate mode for a group of pins.
\r
247 * Configures the output slew rate mode for a group of pins, to
\r
248 * control the speed at which the physical output pin can react to
\r
249 * logical changes of the I/O pin value.
\r
251 * \param[in] port Base of the PORT module to configure.
\r
252 * \param[in] mask Mask of the port pin(s) to configure.
\r
253 * \param[in] mode New pin slew rate mode to configure.
\r
255 void system_pinmux_group_set_output_slew_rate(
\r
256 PortGroup *const port,
\r
257 const uint32_t mask,
\r
258 const enum system_pinmux_pin_slew_rate mode)
\r
262 for (int i = 0; i < 32; i++) {
\r
263 if (mask & (1UL << i)) {
\r
264 if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) {
\r
265 port->PINCFG[i].reg |= PORT_PINCFG_SLEWLIM;
\r
268 port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM;
\r
275 * \brief Configures the output driver mode for a group of pins.
\r
277 * Configures the output driver mode for a group of pins, to
\r
278 * control the pad behavior.
\r
280 * \param[in] port Base of the PORT module to configure.
\r
281 * \param[in] mask Mask of the port pin(s) to configure.
\r
282 * \param[in] mode New pad output driver mode to configure.
\r
284 void system_pinmux_group_set_output_drive(
\r
285 PortGroup *const port,
\r
286 const uint32_t mask,
\r
287 const enum system_pinmux_pin_drive mode)
\r
291 for (int i = 0; i < 32; i++) {
\r
292 if (mask & (1UL << i)) {
\r
293 if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) {
\r
294 port->PINCFG[i].reg |= PORT_PINCFG_ODRAIN;
\r
297 port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN;
\r