1 /**
2 * \file
3 *
4 * \brief SAM architecture specific IOPORT service implementation header file.
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 #ifndef IOPORT_SAM_H
47 #define IOPORT_SAM_H
48
49 #include <sysclk.h>
50
51 #define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 32 + (pin))
52 #define IOPORT_BASE_ADDRESS (uintptr_t)PIOA
53 #define IOPORT_PIO_OFFSET ((uintptr_t)PIOB - (uintptr_t)PIOA)
54
55 #define IOPORT_PIOA 0
56 #define IOPORT_PIOB 1
57 #define IOPORT_PIOC 2
58 #define IOPORT_PIOD 3
59 #define IOPORT_PIOE 4
60 #define IOPORT_PIOF 5
61
62 /**
63 * \weakgroup ioport_group
64 * \section ioport_modes IOPORT Modes
65 *
66 * For details on these please see the SAM Manual.
67 *
68 * @{
69 */
70
71 /** \name IOPORT Mode bit definitions */
72 /** @{ */
73 #define IOPORT_MODE_MUX_MASK (0x7 << 0) /*!< MUX bits mask */
74 #define IOPORT_MODE_MUX_BIT0 ( 1 << 0) /*!< MUX BIT0 mask */
75
76 #if SAM3N || SAM3S || SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAMG || SAM4CP || SAMV71 || SAMV70 || SAME70 || SAMS70
77 #define IOPORT_MODE_MUX_BIT1 ( 1 << 1) /*!< MUX BIT1 mask */
78 #endif
79
80 #define IOPORT_MODE_MUX_A ( 0 << 0) /*!< MUX function A */
81 #define IOPORT_MODE_MUX_B ( 1 << 0) /*!< MUX function B */
82
83 #if SAM3N || SAM3S || SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAMG || SAM4CP || SAMV71 || SAMV70 || SAME70 || SAMS70
84 #define IOPORT_MODE_MUX_C ( 2 << 0) /*!< MUX function C */
85 #define IOPORT_MODE_MUX_D ( 3 << 0) /*!< MUX function D */
86 #endif
87
88 #define IOPORT_MODE_PULLUP ( 1 << 3) /*!< Pull-up */
89
90 #if SAM3N || SAM3S || SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAMG || SAM4CP || SAMV71 || SAMV70 || SAME70 || SAMS70
91 #define IOPORT_MODE_PULLDOWN ( 1 << 4) /*!< Pull-down */
92 #endif
93
94 #define IOPORT_MODE_OPEN_DRAIN ( 1 << 5) /*!< Open drain */
95
96 #define IOPORT_MODE_GLITCH_FILTER ( 1 << 6) /*!< Glitch filter */
97 #define IOPORT_MODE_DEBOUNCE ( 1 << 7) /*!< Input debounce */
98 /** @} */
99
100 /** @} */
101
102 typedef uint32_t ioport_mode_t;
103 typedef uint32_t ioport_pin_t;
104 typedef uint32_t ioport_port_t;
105 typedef uint32_t ioport_port_mask_t;
106
arch_ioport_pin_to_port_id(ioport_pin_t pin)107 __always_inline static ioport_port_t arch_ioport_pin_to_port_id(ioport_pin_t pin)
108 {
109 return pin >> 5;
110 }
111
arch_ioport_port_to_base(ioport_port_t port)112 __always_inline static Pio *arch_ioport_port_to_base(ioport_port_t port)
113 {
114 #if (SAM4C || SAM4CM || SAM4CP)
115 if (port == IOPORT_PIOC) {
116 return (Pio *)(uintptr_t)PIOC;
117 # ifdef ID_PIOD
118 } else if (port == IOPORT_PIOD) {
119 return (Pio *)(uintptr_t)PIOD;
120 # endif
121 } else {
122 return (Pio *)((uintptr_t)IOPORT_BASE_ADDRESS +
123 (IOPORT_PIO_OFFSET * port));
124 }
125 #else
126 return (Pio *)((uintptr_t)IOPORT_BASE_ADDRESS +
127 (IOPORT_PIO_OFFSET * port));
128 #endif
129 }
130
arch_ioport_pin_to_base(ioport_pin_t pin)131 __always_inline static Pio *arch_ioport_pin_to_base(ioport_pin_t pin)
132 {
133 return arch_ioport_port_to_base(arch_ioport_pin_to_port_id(pin));
134 }
135
arch_ioport_pin_to_mask(ioport_pin_t pin)136 __always_inline static ioport_port_mask_t arch_ioport_pin_to_mask(ioport_pin_t pin)
137 {
138 return 1U << (pin & 0x1F);
139 }
140
arch_ioport_init(void)141 __always_inline static void arch_ioport_init(void)
142 {
143 #ifdef ID_PIOA
144 sysclk_enable_peripheral_clock(ID_PIOA);
145 #endif
146 #ifdef ID_PIOB
147 sysclk_enable_peripheral_clock(ID_PIOB);
148 #endif
149 #ifdef ID_PIOC
150 sysclk_enable_peripheral_clock(ID_PIOC);
151 #endif
152 #ifdef ID_PIOD
153 sysclk_enable_peripheral_clock(ID_PIOD);
154 #endif
155 #ifdef ID_PIOE
156 sysclk_enable_peripheral_clock(ID_PIOE);
157 #endif
158 #ifdef ID_PIOF
159 sysclk_enable_peripheral_clock(ID_PIOF);
160 #endif
161 }
162
arch_ioport_enable_port(ioport_port_t port,ioport_port_mask_t mask)163 __always_inline static void arch_ioport_enable_port(ioport_port_t port,
164 ioport_port_mask_t mask)
165 {
166 arch_ioport_port_to_base(port)->PIO_PER = mask;
167 }
168
arch_ioport_disable_port(ioport_port_t port,ioport_port_mask_t mask)169 __always_inline static void arch_ioport_disable_port(ioport_port_t port,
170 ioport_port_mask_t mask)
171 {
172 arch_ioport_port_to_base(port)->PIO_PDR = mask;
173 }
174
arch_ioport_enable_pin(ioport_pin_t pin)175 __always_inline static void arch_ioport_enable_pin(ioport_pin_t pin)
176 {
177 arch_ioport_enable_port(arch_ioport_pin_to_port_id(pin),
178 arch_ioport_pin_to_mask(pin));
179 }
180
arch_ioport_disable_pin(ioport_pin_t pin)181 __always_inline static void arch_ioport_disable_pin(ioport_pin_t pin)
182 {
183 arch_ioport_disable_port(arch_ioport_pin_to_port_id(pin),
184 arch_ioport_pin_to_mask(pin));
185 }
186
arch_ioport_set_port_mode(ioport_port_t port,ioport_port_mask_t mask,ioport_mode_t mode)187 __always_inline static void arch_ioport_set_port_mode(ioport_port_t port,
188 ioport_port_mask_t mask, ioport_mode_t mode)
189 {
190 Pio *base = arch_ioport_port_to_base(port);
191
192 if (mode & IOPORT_MODE_PULLUP) {
193 base->PIO_PUER = mask;
194 } else {
195 base->PIO_PUDR = mask;
196 }
197
198 #if defined(IOPORT_MODE_PULLDOWN)
199 if (mode & IOPORT_MODE_PULLDOWN) {
200 base->PIO_PPDER = mask;
201 } else {
202 base->PIO_PPDDR = mask;
203 }
204 #endif
205
206 if (mode & IOPORT_MODE_OPEN_DRAIN) {
207 base->PIO_MDER = mask;
208 } else {
209 base->PIO_MDDR = mask;
210 }
211
212 if (mode & (IOPORT_MODE_GLITCH_FILTER | IOPORT_MODE_DEBOUNCE)) {
213 base->PIO_IFER = mask;
214 } else {
215 base->PIO_IFDR = mask;
216 }
217
218 if (mode & IOPORT_MODE_DEBOUNCE) {
219 #if SAM3U || SAM3XA
220 base->PIO_DIFSR = mask;
221 #else
222 base->PIO_IFSCER = mask;
223 #endif
224 } else {
225 #if SAM3U || SAM3XA
226 base->PIO_SCIFSR = mask;
227 #else
228 base->PIO_IFSCDR = mask;
229 #endif
230 }
231
232 #if !defined(IOPORT_MODE_MUX_BIT1)
233 if (mode & IOPORT_MODE_MUX_BIT0) {
234 base->PIO_ABSR |= mask;
235 } else {
236 base->PIO_ABSR &= ~mask;
237 }
238 #else
239 if (mode & IOPORT_MODE_MUX_BIT0) {
240 base->PIO_ABCDSR[0] |= mask;
241 } else {
242 base->PIO_ABCDSR[0] &= ~mask;
243 }
244
245 if (mode & IOPORT_MODE_MUX_BIT1) {
246 base->PIO_ABCDSR[1] |= mask;
247 } else {
248 base->PIO_ABCDSR[1] &= ~mask;
249 }
250 #endif
251 }
252
arch_ioport_set_pin_mode(ioport_pin_t pin,ioport_mode_t mode)253 __always_inline static void arch_ioport_set_pin_mode(ioport_pin_t pin,
254 ioport_mode_t mode)
255 {
256 arch_ioport_set_port_mode(arch_ioport_pin_to_port_id(pin),
257 arch_ioport_pin_to_mask(pin), mode);
258 }
259
arch_ioport_set_port_dir(ioport_port_t port,ioport_port_mask_t mask,enum ioport_direction group_direction)260 __always_inline static void arch_ioport_set_port_dir(ioport_port_t port,
261 ioport_port_mask_t mask, enum ioport_direction group_direction)
262 {
263 Pio *base = arch_ioport_port_to_base(port);
264
265 if (group_direction == IOPORT_DIR_OUTPUT) {
266 base->PIO_OER = mask;
267 } else if (group_direction == IOPORT_DIR_INPUT) {
268 base->PIO_ODR = mask;
269 }
270
271 base->PIO_OWER = mask;
272 }
273
arch_ioport_set_pin_dir(ioport_pin_t pin,enum ioport_direction dir)274 __always_inline static void arch_ioport_set_pin_dir(ioport_pin_t pin,
275 enum ioport_direction dir)
276 {
277 Pio *base = arch_ioport_pin_to_base(pin);
278
279 if (dir == IOPORT_DIR_OUTPUT) {
280 base->PIO_OER = arch_ioport_pin_to_mask(pin);
281 } else if (dir == IOPORT_DIR_INPUT) {
282 base->PIO_ODR = arch_ioport_pin_to_mask(pin);
283 }
284
285 base->PIO_OWER = arch_ioport_pin_to_mask(pin);
286 }
287
arch_ioport_set_pin_level(ioport_pin_t pin,bool level)288 __always_inline static void arch_ioport_set_pin_level(ioport_pin_t pin,
289 bool level)
290 {
291 Pio *base = arch_ioport_pin_to_base(pin);
292
293 if (level) {
294 base->PIO_SODR = arch_ioport_pin_to_mask(pin);
295 } else {
296 base->PIO_CODR = arch_ioport_pin_to_mask(pin);
297 }
298 }
299
arch_ioport_set_port_level(ioport_port_t port,ioport_port_mask_t mask,ioport_port_mask_t level)300 __always_inline static void arch_ioport_set_port_level(ioport_port_t port,
301 ioport_port_mask_t mask, ioport_port_mask_t level)
302 {
303 Pio *base = arch_ioport_port_to_base(port);
304
305 base->PIO_SODR = mask & level;
306 base->PIO_CODR = mask & ~level;
307 }
308
arch_ioport_get_pin_level(ioport_pin_t pin)309 __always_inline static bool arch_ioport_get_pin_level(ioport_pin_t pin)
310 {
311 return arch_ioport_pin_to_base(pin)->PIO_PDSR & arch_ioport_pin_to_mask(pin);
312 }
313
arch_ioport_get_port_level(ioport_port_t port,ioport_port_mask_t mask)314 __always_inline static ioport_port_mask_t arch_ioport_get_port_level(
315 ioport_port_t port, ioport_port_mask_t mask)
316 {
317 return arch_ioport_port_to_base(port)->PIO_PDSR & mask;
318 }
319
arch_ioport_toggle_pin_level(ioport_pin_t pin)320 __always_inline static void arch_ioport_toggle_pin_level(ioport_pin_t pin)
321 {
322 Pio *port = arch_ioport_pin_to_base(pin);
323 ioport_port_mask_t mask = arch_ioport_pin_to_mask(pin);
324
325 if (port->PIO_PDSR & arch_ioport_pin_to_mask(pin)) {
326 port->PIO_CODR = mask;
327 } else {
328 port->PIO_SODR = mask;
329 }
330 }
331
arch_ioport_toggle_port_level(ioport_port_t port,ioport_port_mask_t mask)332 __always_inline static void arch_ioport_toggle_port_level(ioport_port_t port,
333 ioport_port_mask_t mask)
334 {
335 arch_ioport_port_to_base(port)->PIO_ODSR ^= mask;
336 }
337
arch_ioport_set_port_sense_mode(ioport_port_t port,ioport_port_mask_t mask,enum ioport_sense pin_sense)338 __always_inline static void arch_ioport_set_port_sense_mode(ioport_port_t port,
339 ioport_port_mask_t mask, enum ioport_sense pin_sense)
340 {
341 Pio *base = arch_ioport_port_to_base(port);
342 /* AIMMR ELSR FRLHSR
343 * 0 X X IOPORT_SENSE_BOTHEDGES (Default)
344 * 1 0 0 IOPORT_SENSE_FALLING
345 * 1 0 1 IOPORT_SENSE_RISING
346 * 1 1 0 IOPORT_SENSE_LEVEL_LOW
347 * 1 1 1 IOPORT_SENSE_LEVEL_HIGH
348 */
349 switch(pin_sense) {
350 case IOPORT_SENSE_LEVEL_LOW:
351 base->PIO_LSR = mask;
352 base->PIO_FELLSR = mask;
353 break;
354 case IOPORT_SENSE_LEVEL_HIGH:
355 base->PIO_LSR = mask;
356 base->PIO_REHLSR = mask;
357 break;
358 case IOPORT_SENSE_FALLING:
359 base->PIO_ESR = mask;
360 base->PIO_FELLSR = mask;
361 break;
362 case IOPORT_SENSE_RISING:
363 base->PIO_ESR = mask;
364 base->PIO_REHLSR = mask;
365 break;
366 default:
367 base->PIO_AIMDR = mask;
368 return;
369 }
370 base->PIO_AIMER = mask;
371 }
372
arch_ioport_set_pin_sense_mode(ioport_pin_t pin,enum ioport_sense pin_sense)373 __always_inline static void arch_ioport_set_pin_sense_mode(ioport_pin_t pin,
374 enum ioport_sense pin_sense)
375 {
376 arch_ioport_set_port_sense_mode(arch_ioport_pin_to_port_id(pin),
377 arch_ioport_pin_to_mask(pin), pin_sense);
378 }
379
380 #endif /* IOPORT_SAM_H */
381