blob: 2816b971851d87592451fafd2f53be33356c19ce [file] [log] [blame]
Austin Schuh208337d2022-01-01 14:29:11 -08001/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "hardware/gpio.h"
8#include "hardware/sync.h"
9
10#include "hardware/structs/iobank0.h"
11#include "hardware/irq.h"
12
13#if LIB_PICO_BINARY_INFO
14#include "pico/binary_info.h"
15#endif
16
17static gpio_irq_callback_t _callbacks[NUM_CORES];
18
19// Get the raw value from the pin, bypassing any muxing or overrides.
20int gpio_get_pad(uint gpio) {
21 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
22 hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
23 return (iobank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS)
24 >> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB;
25}
26
27/// \tag::gpio_set_function[]
28// Select function for this GPIO, and ensure input/output are enabled at the pad.
29// This also clears the input/output/irq override bits.
30void gpio_set_function(uint gpio, enum gpio_function fn) {
31 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
32 invalid_params_if(GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
33 // Set input enable on, output disable off
34 hw_write_masked(&padsbank0_hw->io[gpio],
35 PADS_BANK0_GPIO0_IE_BITS,
36 PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
37 );
38 // Zero all fields apart from fsel; we want this IO to do what the peripheral tells it.
39 // This doesn't affect e.g. pullup/pulldown, as these are in pad controls.
40 iobank0_hw->io[gpio].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
41}
42/// \end::gpio_set_function[]
43
44enum gpio_function gpio_get_function(uint gpio) {
45 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
46 return (enum gpio_function) ((iobank0_hw->io[gpio].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB);
47}
48
49// Note that, on RP2040, setting both pulls enables a "bus keep" function,
50// i.e. weak pull to whatever is current high/low state of GPIO.
51void gpio_set_pulls(uint gpio, bool up, bool down) {
52 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
53 hw_write_masked(
54 &padsbank0_hw->io[gpio],
55 (bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB),
56 PADS_BANK0_GPIO0_PUE_BITS | PADS_BANK0_GPIO0_PDE_BITS
57 );
58}
59
60// Direct override for per-GPIO IRQ signal
61void gpio_set_irqover(uint gpio, uint value) {
62 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
63 hw_write_masked(&iobank0_hw->io[gpio].ctrl,
64 value << IO_BANK0_GPIO0_CTRL_IRQOVER_LSB,
65 IO_BANK0_GPIO0_CTRL_IRQOVER_BITS
66 );
67}
68
69// Direct overrides for pad controls
70void gpio_set_inover(uint gpio, uint value) {
71 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
72 hw_write_masked(&iobank0_hw->io[gpio].ctrl,
73 value << IO_BANK0_GPIO0_CTRL_INOVER_LSB,
74 IO_BANK0_GPIO0_CTRL_INOVER_BITS
75 );
76}
77
78void gpio_set_outover(uint gpio, uint value) {
79 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
80 hw_write_masked(&iobank0_hw->io[gpio].ctrl,
81 value << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB,
82 IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
83 );
84}
85
86void gpio_set_oeover(uint gpio, uint value) {
87 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
88 hw_write_masked(&iobank0_hw->io[gpio].ctrl,
89 value << IO_BANK0_GPIO0_CTRL_OEOVER_LSB,
90 IO_BANK0_GPIO0_CTRL_OEOVER_BITS
91 );
92}
93
94void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
95 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
96 if (enabled)
97 hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS);
98 else
99 hw_clear_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS);
100}
101
102
103bool gpio_is_input_hysteresis_enabled(uint gpio) {
104 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
105 return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0;
106}
107
108void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) {
109 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
110 hw_write_masked(&padsbank0_hw->io[gpio],
111 (uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB,
112 PADS_BANK0_GPIO0_SLEWFAST_BITS
113 );
114}
115
116enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
117 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
118 return (enum gpio_slew_rate)((padsbank0_hw->io[gpio]
119 & PADS_BANK0_GPIO0_SLEWFAST_BITS)
120 >> PADS_BANK0_GPIO0_SLEWFAST_LSB);
121}
122
123
124// Enum encoding should match hardware encoding on RP2040
125static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, "");
126void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) {
127 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
128 hw_write_masked(&padsbank0_hw->io[gpio],
129 (uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB,
130 PADS_BANK0_GPIO0_DRIVE_BITS
131 );
132}
133
134enum gpio_drive_strength gpio_get_drive_strength(uint gpio) {
135 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
136 return (enum gpio_drive_strength)((padsbank0_hw->io[gpio]
137 & PADS_BANK0_GPIO0_DRIVE_BITS)
138 >> PADS_BANK0_GPIO0_DRIVE_LSB);
139}
140
141static void gpio_irq_handler(void) {
142 io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
143 &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
144 for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio++) {
145 io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
146 uint events = (*status_reg >> 4 * (gpio % 8)) & 0xf;
147 if (events) {
148 // TODO: If both cores care about this event then the second core won't get the irq?
149 gpio_acknowledge_irq(gpio, events);
150 gpio_irq_callback_t callback = _callbacks[get_core_num()];
151 if (callback) {
152 callback(gpio, events);
153 }
154 }
155 }
156}
157
158static void _gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled, io_irq_ctrl_hw_t *irq_ctrl_base) {
159 // Clear stale events which might cause immediate spurious handler entry
160 gpio_acknowledge_irq(gpio, events);
161
162 io_rw_32 *en_reg = &irq_ctrl_base->inte[gpio / 8];
163 events <<= 4 * (gpio % 8);
164
165 if (enabled)
166 hw_set_bits(en_reg, events);
167 else
168 hw_clear_bits(en_reg, events);
169}
170
171void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled) {
172 // Separate mask/force/status per-core, so check which core called, and
173 // set the relevant IRQ controls.
174 io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
175 &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
176 _gpio_set_irq_enabled(gpio, events, enabled, irq_ctrl_base);
177}
178
179void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback) {
180 gpio_set_irq_enabled(gpio, events, enabled);
181
182 // TODO: Do we want to support a callback per GPIO pin?
183 // Install IRQ handler
184 _callbacks[get_core_num()] = callback;
185 irq_set_exclusive_handler(IO_IRQ_BANK0, gpio_irq_handler);
186 irq_set_enabled(IO_IRQ_BANK0, true);
187}
188
189void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled) {
190 io_irq_ctrl_hw_t *irq_ctrl_base = &iobank0_hw->dormant_wake_irq_ctrl;
191 _gpio_set_irq_enabled(gpio, events, enabled, irq_ctrl_base);
192}
193
194void gpio_acknowledge_irq(uint gpio, uint32_t events) {
195 iobank0_hw->intr[gpio / 8] = events << 4 * (gpio % 8);
196}
197
198#define DEBUG_PIN_MASK (((1u << PICO_DEBUG_PIN_COUNT)-1) << PICO_DEBUG_PIN_BASE)
199void gpio_debug_pins_init() {
200 gpio_init_mask(DEBUG_PIN_MASK);
201 gpio_set_dir_masked(DEBUG_PIN_MASK, DEBUG_PIN_MASK);
202#if LIB_PICO_BINARY_INFO
203 bi_decl_if_func_used(bi_pin_mask_with_names(DEBUG_PIN_MASK, "Debug"));
204#endif
205}
206
207void gpio_set_input_enabled(uint gpio, bool enabled) {
208 if (enabled)
209 hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
210 else
211 hw_clear_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
212}
213
214void gpio_init(uint gpio) {
215 sio_hw->gpio_oe_clr = 1ul << gpio;
216 sio_hw->gpio_clr = 1ul << gpio;
217 gpio_set_function(gpio, GPIO_FUNC_SIO);
218}
219
220void gpio_init_mask(uint gpio_mask) {
221 for(uint i=0;i<32;i++) {
222 if (gpio_mask & 1) {
223 gpio_init(i);
224 }
225 gpio_mask >>= 1;
226 }
227}
228