xref: /btstack/port/samv71-xplained-atwilc3000/ASF/common/services/ioport/sam/ioport_pio.h (revision 1b2596b5303dd8caeea8565532c93cca8dab8cc4)
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