1 /*
2  * Copyright (c) 2016-2017 Piotr Mienkowski
3  * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file
8  * @brief Atmel SAM MCU family General Purpose Input Output (GPIO)
9  * module HAL driver.
10  */
11 
12 #ifndef _ATMEL_SAM_SOC_GPIO_H_
13 #define _ATMEL_SAM_SOC_GPIO_H_
14 
15 #include <zephyr/types.h>
16 #include <soc.h>
17 
18 /*
19  * Pin flags/attributes
20  */
21 
22 /* TODO: replace hard coded pin attribute values with defines provided
23  * in gpio.h, once the official API is clean.
24  */
25 
26 #define SOC_GPIO_DEFAULT                (0)
27 
28 #define SOC_GPIO_FLAGS_POS              (0)
29 #define SOC_GPIO_FLAGS_MASK             (7 << SOC_GPIO_FLAGS_POS)
30 #define SOC_GPIO_PULLUP_POS             (0)
31 #define SOC_GPIO_PULLUP                 (1 << SOC_GPIO_PULLUP_POS)
32 #define SOC_GPIO_PULLDOWN_POS           (1)
33 #define SOC_GPIO_PULLDOWN               (1 << SOC_GPIO_PULLDOWN_POS)
34 #define SOC_GPIO_OPENDRAIN_POS          (2)
35 #define SOC_GPIO_OPENDRAIN              (1 << SOC_GPIO_OPENDRAIN_POS)
36 
37 /* Bit field: SOC_GPIO_IN_FILTER */
38 #define SOC_GPIO_IN_FILTER_POS          (3)
39 #define SOC_GPIO_IN_FILTER_MASK         (3 << SOC_GPIO_IN_FILTER_POS)
40 #define SOC_GPIO_IN_FILTER_NONE         (0 << SOC_GPIO_IN_FILTER_POS)
41 #define SOC_GPIO_IN_FILTER_DEBOUNCE     (1 << SOC_GPIO_IN_FILTER_POS)
42 #define SOC_GPIO_IN_FILTER_DEGLITCH     (2 << SOC_GPIO_IN_FILTER_POS)
43 
44 #define SOC_GPIO_INT_ENABLE             (1 << 5)
45 
46 /* Bit field: SOC_GPIO_INT_TRIG */
47 #define SOC_GPIO_INT_TRIG_POS           (6)
48 #define SOC_GPIO_INT_TRIG_MASK          (3 << SOC_GPIO_INT_TRIG_POS)
49 /** Interrupt is triggered by a level detection event. */
50 #define SOC_GPIO_INT_TRIG_LEVEL         (0 << SOC_GPIO_INT_TRIG_POS)
51 /** Interrupt is triggered by an edge detection event. */
52 #define SOC_GPIO_INT_TRIG_EDGE          (1 << SOC_GPIO_INT_TRIG_POS)
53 /** Interrupt is triggered by any edge detection event. */
54 #define SOC_GPIO_INT_TRIG_DOUBLE_EDGE   (2 << SOC_GPIO_INT_TRIG_POS)
55 
56 /** Interrupt is triggered by a high level / rising edge detection event */
57 #define SOC_GPIO_INT_ACTIVE_HIGH        (1 << 8)
58 
59 /* Bit field: SOC_GPIO_FUNC */
60 #define SOC_GPIO_FUNC_POS               (16)
61 #define SOC_GPIO_FUNC_MASK              (15 << SOC_GPIO_FUNC_POS)
62 /** Connect pin to peripheral A. */
63 #define SOC_GPIO_FUNC_A                 (0 << SOC_GPIO_FUNC_POS)
64 /** Connect pin to peripheral B. */
65 #define SOC_GPIO_FUNC_B                 (1 << SOC_GPIO_FUNC_POS)
66 /** Connect pin to peripheral C. */
67 #define SOC_GPIO_FUNC_C                 (2 << SOC_GPIO_FUNC_POS)
68 /** Connect pin to peripheral D. */
69 #define SOC_GPIO_FUNC_D                 (3 << SOC_GPIO_FUNC_POS)
70 /** Connect pin to peripheral E. */
71 #define SOC_GPIO_FUNC_E                 (4 << SOC_GPIO_FUNC_POS)
72 /** Connect pin to peripheral F. */
73 #define SOC_GPIO_FUNC_F                 (5 << SOC_GPIO_FUNC_POS)
74 /** Connect pin to peripheral G. */
75 #define SOC_GPIO_FUNC_G                 (6 << SOC_GPIO_FUNC_POS)
76 /** Connect pin to peripheral H. */
77 #define SOC_GPIO_FUNC_H                 (7 << SOC_GPIO_FUNC_POS)
78 /** Configure pin as input. */
79 #define SOC_GPIO_FUNC_IN                (8 << SOC_GPIO_FUNC_POS)
80 /** Configure pin as output and set it initial value to 0. */
81 #define SOC_GPIO_FUNC_OUT_0             (9 << SOC_GPIO_FUNC_POS)
82 /** Configure pin as output and set it initial value to 1. */
83 #define SOC_GPIO_FUNC_OUT_1             (10 << SOC_GPIO_FUNC_POS)
84 
85 struct soc_gpio_pin {
86 	uint32_t mask;     /** pin(s) bit mask */
87 #ifdef ID_GPIO
88 	Gpio *regs;        /** pointer to registers of the GPIO controller */
89 #else
90 	Pio *regs;         /** pointer to registers of the PIO controller */
91 #endif
92 	uint8_t periph_id; /** peripheral ID of the PIO controller */
93 	uint32_t flags;    /** pin flags/attributes */
94 };
95 
96 /**
97  * @brief Configure GPIO pin(s).
98  *
99  * Configure one or several pins belonging to the same GPIO port.
100  * Example scenarios:
101  * - configure pin(s) as input with debounce filter enabled.
102  * - connect pin(s) to a peripheral B and enable pull-up.
103  * - configure pin(s) as open drain output.
104  * All pins are configured in the same way.
105  *
106  * @remark The function will enable the GPIO module's clock only if
107  * any of its pins is configured as an input. This is typically what
108  * a user wants. A pin will function correctly without clock enabled
109  * when configured as an output or connected to a peripheral.
110  * In some cases, e.g. when a pin is configured as an output with
111  * a pull-up and user wants to read pin's input value it is necessary
112  * to enable GPIO module's clock separately.
113  *
114  * @param pin  pin's configuration data such as pin mask, pin attributes, etc.
115  */
116 void soc_gpio_configure(const struct soc_gpio_pin *pin);
117 
118 /**
119  * @brief Configure a list of GPIO pin(s).
120  *
121  * Configure an arbitrary amount of pins in an arbitrary way. Each
122  * configuration entry is a single item in an array passed as an
123  * argument to the function.
124  *
125  * @param pins an array where each item contains pin's configuration data.
126  * @param size size of the pin list.
127  */
128 void soc_gpio_list_configure(const struct soc_gpio_pin pins[],
129 			     unsigned int size);
130 
131 /**
132  * @brief Set pin(s) high.
133  *
134  * Set pin(s) defined in the mask parameter to high. The pin(s) have to be
135  * configured as output by the configure function. The flags field which
136  * is part of pin struct is ignored.
137  *
138  * @param pin  pointer to a pin instance describing one or more pins.
139  */
soc_gpio_set(const struct soc_gpio_pin * pin)140 static inline void soc_gpio_set(const struct soc_gpio_pin *pin)
141 {
142 #ifdef ID_GPIO
143 	pin->regs->OVRS = pin->mask;
144 #else
145 	pin->regs->PIO_SODR = pin->mask;
146 #endif
147 }
148 
149 /**
150  * @brief Set pin(s) low.
151  *
152  * Set pin(s) defined in the mask field to low. The pin(s) have to be
153  * configured as output by the configure function. The flags field which
154  * is part of pin struct is ignored.
155  *
156  * @param pin  pointer to a pin instance describing one or more pins.
157  */
soc_gpio_clear(const struct soc_gpio_pin * pin)158 static inline void soc_gpio_clear(const struct soc_gpio_pin *pin)
159 {
160 #ifdef ID_GPIO
161 	pin->regs->OVRC = pin->mask;
162 #else
163 	pin->regs->PIO_CODR = pin->mask;
164 #endif
165 }
166 
167 /**
168  * @brief Get pin(s) value.
169  *
170  * Get value of the pin(s) defined in the mask field.
171  *
172  * @param pin  pointer to a pin instance describing one or more pins.
173  * @return pin(s) value. To assess value of a specific pin the pin's bit
174  * field has to be read.
175  */
soc_gpio_get(const struct soc_gpio_pin * pin)176 static inline uint32_t soc_gpio_get(const struct soc_gpio_pin *pin)
177 {
178 #ifdef ID_GPIO
179 	return pin->regs->PVR & pin->mask;
180 #else
181 	return pin->regs->PIO_PDSR & pin->mask;
182 #endif
183 }
184 
185 /**
186  * @brief Set the length of the debounce window.
187  *
188  * The debouncing filter automatically rejects a pulse with a duration of less
189  * than 1/2 programmable divided slow clock period tdiv_slck, while a pulse with
190  * a duration of one or more tdiv_slck cycles is accepted. For pulse durations
191  * between 1/2 selected clock cycle and one tdiv_slck clock cycle, the pulse may
192  * or may not be taken into account, depending on the precise timing of its
193  * occurrence.
194  *
195  * tdiv_slck = ((div + 1) x 2) x tslck
196  * where tslck is the slow clock, typically 32.768 kHz.
197  *
198  * Setting the length of the debounce window is only meaningful if the pin is
199  * configured as input and the debounce pin option is enabled.
200  *
201  * @param pin  pointer to a pin instance describing one or more pins.
202  * @param div  slow clock divider, valid values: from 0 to 2^14 - 1
203  */
soc_gpio_debounce_length_set(const struct soc_gpio_pin * pin,uint32_t div)204 static inline void soc_gpio_debounce_length_set(const struct soc_gpio_pin *pin,
205 						uint32_t div)
206 {
207 #ifdef ID_GPIO
208 	if (div) {
209 		pin->regs->STERS = pin->mask;
210 	} else {
211 		pin->regs->STERC = pin->mask;
212 	}
213 #else
214 	pin->regs->PIO_SCDR = PIO_SCDR_DIV(div);
215 #endif
216 }
217 
218 #endif /* _ATMEL_SAM_SOC_GPIO_H_ */
219