1 /*
2 * Copyright (c) 2012 Travis Geiselbrecht
3 * Copyright (c) 2016 Erik Gilling
4 *
5 * Use of this source code is governed by a MIT-style
6 * license that can be found in the LICENSE file or at
7 * https://opensource.org/licenses/MIT
8 */
9
10 #include <assert.h>
11 #include <lk/debug.h>
12 #include <dev/gpio.h>
13 #include <platform/gpio.h>
14 #include <platform/rcc.h>
15 #include <platform/stm32.h>
16 #include <stm32f0xx.h>
17
18 typedef GPIO_TypeDef stm32_gpio_t;
19
20 typedef enum {
21 STM32_GPIO_SPEED_2_MHZ = 0x0,
22 STM32_GPIO_SPEED_20_MHZ = 0x1,
23 STM32_GPIO_SPEED_50_MHZ = 0x3,
24 } stm32_goio_speed_t;
25
26 typedef enum {
27 STM32_GPIO_OTYPE_PP = 0x0,
28 STM32_GPIO_OTYPE_OD = 0x1,
29 } stm32_gpio_otype_t;
30
31 typedef enum {
32 STM32_GPIO_MODE_IN = 0x0,
33 STM32_GPIO_MODE_OUT = 0x1,
34 STM32_GPIO_MODE_AF = 0x2,
35 STM32_GPIO_MODE_AN = 0x3,
36 } stm32_gpio_mode_t;
37
38 typedef enum {
39 STM32_GPIO_PUPD_NONE = 0x0,
40 STM32_GPIO_PUPD_UP = 0x1,
41 STM32_GPIO_PUPD_DOWN = 0x2,
42 } stm32_gpio_pupd_t;
43
stm32_gpio_port_to_pointer(unsigned int port)44 static stm32_gpio_t *stm32_gpio_port_to_pointer(unsigned int port) {
45 switch (port) {
46 default:
47 #ifdef GPIOA
48 case GPIO_PORT_A:
49 return GPIOA;
50 #endif
51 #ifdef GPIOB
52 case GPIO_PORT_B:
53 return GPIOB;
54 #endif
55 #ifdef GPIOC
56 case GPIO_PORT_C:
57 return GPIOC;
58 #endif
59 #ifdef GPIOD
60 case GPIO_PORT_D:
61 return GPIOD;
62 #endif
63 #ifdef GPIOE
64 case GPIO_PORT_E:
65 return GPIOE;
66 #endif
67 #ifdef GPIOF
68 case GPIO_PORT_F:
69 return GPIOF;
70 #endif
71 }
72 }
73
stm32_gpio_enable_port(unsigned int port)74 static void stm32_gpio_enable_port(unsigned int port) {
75 DEBUG_ASSERT(port <= GPIO_PORT_F);
76
77 switch (port) {
78 default:
79 #ifdef GPIOA
80 case GPIO_PORT_A:
81 stm32_rcc_set_enable(STM32_RCC_CLK_IOPA, true);
82 break;
83 #endif
84 #ifdef GPIOB
85 case GPIO_PORT_B:
86 stm32_rcc_set_enable(STM32_RCC_CLK_IOPB, true);
87 break;
88 #endif
89 #ifdef GPIOC
90 case GPIO_PORT_C:
91 stm32_rcc_set_enable(STM32_RCC_CLK_IOPC, true);
92 break;
93 #endif
94 #ifdef GPIOD
95 case GPIO_PORT_D:
96 stm32_rcc_set_enable(STM32_RCC_CLK_IOPD, true);
97 break;
98 #endif
99 #ifdef GPIOE
100 case GPIO_PORT_E:
101 stm32_rcc_set_enable(STM32_RCC_CLK_IOPE, true);
102 break;
103 #endif
104 #ifdef GPIOF
105 case GPIO_PORT_F:
106 stm32_rcc_set_enable(STM32_RCC_CLK_IOPF, true);
107 break;
108 #endif
109 }
110 }
111
stm32_gpio_early_init(void)112 void stm32_gpio_early_init(void) {
113 }
114
stm32_gpio_af_config(stm32_gpio_t * gpio,uint32_t pin,uint32_t af_num)115 static void stm32_gpio_af_config(stm32_gpio_t *gpio, uint32_t pin,
116 uint32_t af_num) {
117 // 8 AF entries per register
118 uint32_t reg_index = pin >> 3;
119 uint32_t entry_shift = (pin & 0x7) * 4;
120
121 gpio->AFR[reg_index] &= ~(0xf << entry_shift);
122 gpio->AFR[reg_index] |= (af_num & 0xf) << entry_shift;
123 }
124
gpio_config(unsigned nr,unsigned flags)125 int gpio_config(unsigned nr, unsigned flags) {
126 uint32_t port = GPIO_PORT(nr);
127 uint32_t pin = GPIO_PIN(nr);
128 stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(port);
129
130 assert(pin < 16);
131
132 stm32_gpio_enable_port(port);
133
134 if (flags & GPIO_STM32_AF) {
135 stm32_gpio_af_config(gpio, pin, GPIO_AFNUM(flags));
136 }
137
138 if ((flags & GPIO_OUTPUT) || (flags & GPIO_STM32_AF)) {
139 // All pins configured to 50MHz.
140 gpio->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pin * 2));
141 gpio->OSPEEDR |= STM32_GPIO_SPEED_50_MHZ << (pin * 2);
142
143 // Output mode configuration
144 gpio->OTYPER &= ~((GPIO_OTYPER_OT_0) << pin);
145 if (flags & GPIO_STM32_OD) {
146 gpio->OTYPER |= STM32_GPIO_OTYPE_OD << pin;
147 } else {
148 gpio->OTYPER |= STM32_GPIO_OTYPE_PP << pin;
149 }
150 }
151
152 stm32_gpio_mode_t mode;
153 if (flags & GPIO_OUTPUT) {
154 mode = STM32_GPIO_MODE_OUT;
155 } else if (flags & GPIO_STM32_AF) {
156 mode = STM32_GPIO_MODE_AF;
157 } else {
158 mode = STM32_GPIO_MODE_IN;
159 }
160
161 gpio->MODER &= ~(GPIO_MODER_MODER0 << (pin * 2));
162 gpio->MODER |= (mode << (pin * 2));
163
164 stm32_gpio_pupd_t pupd = STM32_GPIO_PUPD_NONE;
165 if (flags & GPIO_PULLUP) {
166 pupd = STM32_GPIO_PUPD_UP;
167 } else if (flags & GPIO_PULLDOWN) {
168 pupd = STM32_GPIO_PUPD_DOWN;
169 }
170
171 gpio->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (pin * 2));
172 gpio->PUPDR |= pupd << (pin * 2);
173
174 return 0;
175 }
176
gpio_set(unsigned nr,unsigned on)177 void gpio_set(unsigned nr, unsigned on) {
178 stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(GPIO_PORT(nr));
179 if (on) {
180 gpio->BSRR = 1 << GPIO_PIN(nr);
181 } else {
182 gpio->BRR = 1 << GPIO_PIN(nr);
183 }
184 }
185
gpio_get(unsigned nr)186 int gpio_get(unsigned nr) {
187 stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(GPIO_PORT(nr));
188 return (gpio->IDR & (1 << GPIO_PIN(nr))) != 0;
189 }
190
191