]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M0+_Atmel_SAMD20_XPlained/RTOSDemo/src/ASF/sam0/drivers/system/pinmux/pinmux.c
Starting point for the SAMD20 demo.
[freertos] / FreeRTOS / Demo / CORTEX_M0+_Atmel_SAMD20_XPlained / RTOSDemo / src / ASF / sam0 / drivers / system / pinmux / pinmux.c
1 /**\r
2  * \file\r
3  *\r
4  * \brief SAM D20 Pin Multiplexer Driver\r
5  *\r
6  * Copyright (C) 2012-2013 Atmel Corporation. All rights reserved.\r
7  *\r
8  * \asf_license_start\r
9  *\r
10  * \page License\r
11  *\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
14  *\r
15  * 1. Redistributions of source code must retain the above copyright notice,\r
16  *    this list of conditions and the following disclaimer.\r
17  *\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
21  *\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
24  *\r
25  * 4. This software may only be redistributed and used in connection with an\r
26  *    Atmel microcontroller product.\r
27  *\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
39  *\r
40  * \asf_license_stop\r
41  *\r
42  */\r
43 #include <pinmux.h>\r
44 \r
45 /**\r
46  * \internal\r
47  * Writes out a given configuration of a Port pin configuration to the\r
48  * hardware module.\r
49  *\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
52  *\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
56  */\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
61 {\r
62         Assert(port);\r
63         Assert(config);\r
64 \r
65         /* Track the configuration bits into a temporary variable before writing */\r
66         uint32_t pin_cfg = 0;\r
67 \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
73         }\r
74 \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
80 \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
84                 }\r
85 \r
86                 /* Clear the port DIR bits to disable the output buffer */\r
87                 port->DIRCLR.reg = pin_mask;\r
88         }\r
89 \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
95                  * output state */\r
96                 pin_cfg &= ~PORT_WRCONFIG_PULLEN;\r
97 \r
98                 /* Set the port DIR bits to enable the output buffer */\r
99                 port->DIRSET.reg = pin_mask;\r
100         }\r
101 \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
106 \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
109         port->WRCONFIG.reg\r
110                 = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |\r
111                         pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;\r
112 \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
115         port->WRCONFIG.reg\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
119 \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
128                 } else {\r
129                         port->OUTCLR.reg = pin_mask;\r
130                 }\r
131         }\r
132 }\r
133 \r
134 /**\r
135  * \brief Writes a Port pin configuration to the hardware module.\r
136  *\r
137  * Writes out a given configuration of a Port pin configuration to the hardware\r
138  * module.\r
139  *\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
142  *\r
143  * \param[in] gpio_pin  Index of the GPIO pin to configure.\r
144  * \param[in] config    Configuration settings for the pin.\r
145  */\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
149 {\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
152 \r
153         _system_pinmux_config(port, pin_mask, config);\r
154 }\r
155 \r
156 /**\r
157  * \brief Writes a Port pin group configuration to the hardware module.\r
158  *\r
159  * Writes out a given configuration of a Port pin group configuration to the\r
160  * hardware module.\r
161  *\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
164  *\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
168  */\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
173 {\r
174         Assert(port);\r
175 \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
179                 }\r
180         }\r
181 }\r
182 \r
183 /**\r
184  * \brief Configures the input sampling mode for a group of pins.\r
185  *\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
189  *\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
193  */\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
198 {\r
199         Assert(port);\r
200 \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
204 \r
205                         if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) {\r
206                                 port->CTRL.reg |=  sample_quad_mask;\r
207                         }\r
208                         else {\r
209                                 port->CTRL.reg &= ~sample_quad_mask;\r
210                         }\r
211                 }\r
212         }\r
213 }\r
214 \r
215 /**\r
216  * \brief Configures the output driver strength mode for a group of pins.\r
217  *\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
220  *\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
224  */\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
229 {\r
230         Assert(port);\r
231 \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
236                         }\r
237                         else {\r
238                                 port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR;\r
239                         }\r
240                 }\r
241         }\r
242 }\r
243 \r
244 /**\r
245  * \brief Configures the output slew rate mode for a group of pins.\r
246  *\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
250  *\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
254  */\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
259 {\r
260         Assert(port);\r
261 \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
266                         }\r
267                         else {\r
268                                 port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM;\r
269                         }\r
270                 }\r
271         }\r
272 }\r
273 \r
274 /**\r
275  * \brief Configures the output driver mode for a group of pins.\r
276  *\r
277  * Configures the output driver mode for a group of pins, to\r
278  * control the pad behavior.\r
279  *\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
283  */\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
288 {\r
289         Assert(port);\r
290 \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
295                         }\r
296                         else {\r
297                                 port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN;\r
298                         }\r
299                 }\r
300         }\r
301 }\r