1 /* 2 * SPDX-License-Identifier: Apache-2.0 3 * 4 * Date Author Notes 5 * 2018-03-13 ZeroFree first implementation 6 */ 7 8 #include <rtthread.h> 9 #include <rtdevice.h> 10 #include <rthw.h> 11 12 #include "drv_gpio.h" 13 #include "nrf.h" 14 15 #define MCU_GPIO_USE_PORT_EVENT 1 16 17 #define NRF_GPIO_INDEX(pin) (pin) 18 #define NRF_GPIO_PORT(pin) (NRF_P0) 19 #define NRF_GPIO_MASK(pin) (1 << NRF_GPIO_INDEX(pin)) 20 #define NRF_GPIOTE_PIN_MASK GPIOTE_CONFIG_PSEL_Msk 21 22 /* GPIO interrupts */ 23 #define NRF_GPIO_MAX_IRQ 8 24 25 #if MCU_GPIO_USE_PORT_EVENT 26 #define NRF_GPIO_SENSE_TRIG_NONE 0x00 /* just 0 */ 27 #define NRF_GPIO_SENSE_TRIG_BOTH 0x01 /* something else than both below */ 28 #define NRF_GPIO_SENSE_TRIG_HIGH 0x02 /* GPIO_PIN_CNF_SENSE_High */ 29 #define NRF_GPIO_SENSE_TRIG_LOW 0x03 /* GPIO_PIN_CNF_SENSE_Low */ 30 #endif 31 32 /* Storage for GPIO callbacks */ 33 struct nrf_gpio_irq 34 { 35 void (*func)(void *args); 36 void *args; 37 #if MCU_GPIO_USE_PORT_EVENT 38 rt_int16_t pin; 39 uint8_t sense_trig; 40 #endif 41 }; 42 43 static struct nrf_gpio_irq nrf_gpio_irqs[NRF_GPIO_MAX_IRQ]; 44 45 static void nrf_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode) 46 { 47 uint32_t conf; 48 NRF_GPIO_Type *port; 49 uint8_t dir = 0; 50 int index = NRF_GPIO_INDEX(pin); 51 52 switch (mode) 53 { 54 case PIN_MODE_OUTPUT: 55 conf = GPIO_PIN_CNF_DIR_Output | 56 (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos); 57 dir = 1; 58 break; 59 case PIN_MODE_INPUT: 60 conf = 0; 61 break; 62 case PIN_MODE_INPUT_PULLUP: 63 conf = GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos; 64 break; 65 case PIN_MODE_INPUT_PULLDOWN: 66 conf = GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos; 67 break; 68 default: 69 conf = 0; 70 break; 71 } 72 73 port = NRF_GPIO_PORT(pin); 74 port->PIN_CNF[index] = conf; 75 76 if (dir == 1) 77 { 78 /* output */ 79 port->DIRSET = NRF_GPIO_MASK(pin); 80 port->OUTCLR = NRF_GPIO_MASK(pin); 81 } 82 else 83 { 84 /* input */ 85 port->DIRCLR = NRF_GPIO_MASK(pin); 86 } 87 } 88 89 static void nrf_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t value) 90 { 91 NRF_GPIO_Type *port; 92 93 port = NRF_GPIO_PORT(pin); 94 if (value) 95 { 96 port->OUTSET = NRF_GPIO_MASK(pin); 97 } 98 else 99 { 100 port->OUTCLR = NRF_GPIO_MASK(pin); 101 } 102 } 103 104 static int nrf_pin_read(struct rt_device *device, rt_base_t pin) 105 { 106 NRF_GPIO_Type *port; 107 port = NRF_GPIO_PORT(pin); 108 109 return (port->DIR & NRF_GPIO_MASK(pin)) ? 110 (port->OUT >> NRF_GPIO_INDEX(pin)) & 1UL : 111 (port->IN >> NRF_GPIO_INDEX(pin)) & 1UL; 112 } 113 114 /* 115 * GPIO irq handler 116 * 117 * Handles the gpio interrupt attached to a gpio pin. 118 * 119 * @param index 120 */ 121 static void nrf_gpio_irq_handler(void) 122 { 123 #if MCU_GPIO_USE_PORT_EVENT 124 NRF_GPIO_Type *gpio_port; 125 int pin_index; 126 int pin_state; 127 uint8_t sense_trig; 128 uint32_t gpio_state; 129 #endif 130 int i; 131 132 rt_interrupt_enter(); 133 134 #if MCU_GPIO_USE_PORT_EVENT 135 NRF_GPIOTE->EVENTS_PORT = 0; 136 gpio_state = NRF_P0->IN; 137 138 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 139 { 140 if ((!nrf_gpio_irqs[i].func) || 141 (nrf_gpio_irqs[i].sense_trig == NRF_GPIO_SENSE_TRIG_NONE)) 142 { 143 continue; 144 } 145 146 gpio_port = NRF_GPIO_PORT(nrf_gpio_irqs[i].pin); 147 pin_index = NRF_GPIO_INDEX(nrf_gpio_irqs[i].pin); 148 149 /* Store current SENSE setting */ 150 sense_trig = (gpio_port->PIN_CNF[pin_index] & GPIO_PIN_CNF_SENSE_Msk) >> GPIO_PIN_CNF_SENSE_Pos; 151 152 if (!sense_trig) 153 { 154 continue; 155 } 156 157 /* 158 * SENSE values are 0x02 for high and 0x03 for low, so bit #0 is the 159 * opposite of state which triggers interrupt (thus its value should be 160 * different than pin state). 161 */ 162 pin_state = (gpio_state >> nrf_gpio_irqs[i].pin) & 0x01; 163 if (pin_state == (sense_trig & 0x01)) 164 { 165 continue; 166 } 167 168 /* 169 * Toggle sense to clear interrupt or allow detection of opposite edge 170 * when trigger on both edges is requested. 171 */ 172 gpio_port->PIN_CNF[pin_index] &= ~GPIO_PIN_CNF_SENSE_Msk; 173 if (sense_trig == NRF_GPIO_SENSE_TRIG_HIGH) 174 { 175 gpio_port->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos; 176 } 177 else 178 { 179 gpio_port->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos; 180 } 181 182 /* 183 * Call handler in case SENSE configuration matches requested one or 184 * trigger on both edges is requested. 185 */ 186 if ((nrf_gpio_irqs[i].sense_trig == NRF_GPIO_SENSE_TRIG_BOTH) || 187 (nrf_gpio_irqs[i].sense_trig == sense_trig)) 188 { 189 nrf_gpio_irqs[i].func(nrf_gpio_irqs[i].args); 190 } 191 } 192 #else 193 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 194 { 195 if (NRF_GPIOTE->EVENTS_IN[i] && (NRF_GPIOTE->INTENSET & (1 << i))) 196 { 197 NRF_GPIOTE->EVENTS_IN[i] = 0; 198 if (nrf_gpio_irqs[i].func) 199 { 200 nrf_gpio_irqs[i].func(nrf_gpio_irqs[i].args); 201 } 202 } 203 } 204 #endif 205 206 rt_interrupt_leave(); 207 } 208 209 void GPIOTE_IRQHandler(void) 210 { 211 nrf_gpio_irq_handler(); 212 } 213 214 static void nrf_gpio_irq_setup(void) 215 { 216 static uint8_t irq_setup = 0; 217 218 if (!irq_setup) 219 { 220 NVIC_EnableIRQ(GPIOTE_IRQn); 221 irq_setup = 1; 222 223 #if MCU_GPIO_USE_PORT_EVENT 224 NRF_GPIOTE->INTENCLR = GPIOTE_INTENCLR_PORT_Msk; 225 NRF_GPIOTE->EVENTS_PORT = 0; 226 #endif 227 } 228 } 229 230 /* 231 * Find out whether we have an GPIOTE pin event to use. 232 */ 233 static int hal_gpio_find_empty_slot(void) 234 { 235 int i; 236 237 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 238 { 239 if (nrf_gpio_irqs[i].func == NULL) 240 { 241 return i; 242 } 243 } 244 return -1; 245 } 246 247 /* 248 * Find the GPIOTE event which handles this pin. 249 */ 250 static int nrf_gpio_find_pin(int pin) 251 { 252 int i; 253 254 #if MCU_GPIO_USE_PORT_EVENT 255 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 256 { 257 if (nrf_gpio_irqs[i].func && nrf_gpio_irqs[i].pin == pin) 258 { 259 return i; 260 } 261 } 262 #else 263 pin = pin << GPIOTE_CONFIG_PSEL_Pos; 264 265 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 266 { 267 if (nrf_gpio_irqs[i].func && 268 (NRF_GPIOTE->CONFIG[i] & NRF_GPIOTE_PIN_MASK) == pin) 269 { 270 return i; 271 } 272 } 273 #endif 274 275 return -1; 276 } 277 278 static rt_err_t nrf_pin_attach_irq(struct rt_device *device, rt_int32_t pin, 279 rt_uint32_t mode, void (*hdr)(void *args), void *args) 280 { 281 uint32_t conf; 282 int i; 283 284 nrf_gpio_irq_setup(); 285 i = hal_gpio_find_empty_slot(); 286 if (i < 0) 287 { 288 return -RT_EFULL; 289 } 290 291 #if MCU_GPIO_USE_PORT_EVENT 292 (void)conf; 293 nrf_gpio_irqs[i].pin = pin; 294 295 switch (mode) 296 { 297 case PIN_IRQ_MODE_RISING: 298 nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_HIGH; 299 break; 300 case PIN_IRQ_MODE_FALLING: 301 nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_LOW; 302 break; 303 case PIN_IRQ_MODE_RISING_FALLING: 304 nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_BOTH; 305 break; 306 default: 307 nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_NONE; 308 return -1; 309 } 310 #else 311 switch (mode) 312 { 313 case PIN_IRQ_MODE_RISING: 314 conf = GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos; 315 break; 316 case PIN_IRQ_MODE_FALLING: 317 conf = GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos; 318 break; 319 case PIN_IRQ_MODE_RISING_FALLING: 320 conf = GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos; 321 break; 322 default: 323 return -RT_ERROR; 324 } 325 326 conf |= pin << GPIOTE_CONFIG_PSEL_Pos; 327 conf |= GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos; 328 NRF_GPIOTE->CONFIG[i] = conf; 329 #endif 330 331 nrf_gpio_irqs[i].func = hdr; 332 nrf_gpio_irqs[i].args = args; 333 334 return RT_EOK; 335 } 336 337 static rt_err_t nrf_pin_detach_irq(struct rt_device *device, rt_int32_t pin) 338 { 339 rt_err_t ret = RT_EOK; 340 341 int i; 342 343 i = nrf_gpio_find_pin(pin); 344 if (i < 0) 345 { 346 return -RT_ERROR; 347 } 348 /* disable pin irq */ 349 rt_pin_irq_enable(pin, 0); 350 351 #if MCU_GPIO_USE_PORT_EVENT 352 nrf_gpio_irqs[i].sense_trig = NRF_GPIO_SENSE_TRIG_NONE; 353 #else 354 NRF_GPIOTE->CONFIG[i] = 0; 355 NRF_GPIOTE->EVENTS_IN[i] = 0; 356 #endif 357 358 nrf_gpio_irqs[i].args = NULL; 359 nrf_gpio_irqs[i].func = NULL; 360 361 return ret; 362 } 363 364 static rt_err_t nrf_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled) 365 { 366 #if MCU_GPIO_USE_PORT_EVENT 367 NRF_GPIO_Type *nrf_gpio; 368 int pin_index, sense_enabled = 0; 369 #endif 370 int i; 371 372 i = nrf_gpio_find_pin(pin); 373 if (i < 0) 374 { 375 return -RT_ERROR; 376 } 377 378 #if MCU_GPIO_USE_PORT_EVENT 379 nrf_gpio = NRF_GPIO_PORT(pin); 380 pin_index = NRF_GPIO_INDEX(pin); 381 nrf_gpio->PIN_CNF[pin_index] &= ~GPIO_PIN_CNF_SENSE_Msk; 382 383 if (enabled) 384 { 385 /* 386 * Always set initial SENSE to opposite of current pin state to avoid 387 * triggering immediately 388 */ 389 if (nrf_gpio->IN & (1 << pin_index)) 390 { 391 nrf_gpio->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos; 392 } 393 else 394 { 395 nrf_gpio->PIN_CNF[pin_index] |= GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos; 396 } 397 398 NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_PORT_Msk; 399 } 400 else 401 { 402 for (i = 0; i < NRF_GPIO_MAX_IRQ; i++) 403 { 404 if (nrf_gpio_irqs[i].sense_trig != NRF_GPIO_SENSE_TRIG_NONE) 405 { 406 sense_enabled = 1; 407 break; 408 } 409 } 410 if (!sense_enabled) 411 { 412 NRF_GPIOTE->INTENCLR = GPIOTE_INTENCLR_PORT_Msk; 413 } 414 } 415 #else 416 if (enabled) 417 { 418 NRF_GPIOTE->EVENTS_IN[i] = 0; 419 NRF_GPIOTE->INTENSET = 1 << i; 420 } 421 else 422 { 423 NRF_GPIOTE->INTENCLR = 1 << i; 424 } 425 426 #endif 427 428 return RT_EOK; 429 } 430 431 const static struct rt_pin_ops nrf_pin_ops = 432 { 433 nrf_pin_mode, 434 nrf_pin_write, 435 nrf_pin_read, 436 437 nrf_pin_attach_irq, 438 nrf_pin_detach_irq, 439 nrf_pin_irq_enable 440 }; 441 442 int rt_hw_pin_init(void) 443 { 444 rt_err_t ret = RT_EOK; 445 446 ret = rt_device_pin_register("pin", &nrf_pin_ops, RT_NULL); 447 448 return ret; 449 } 450 451 INIT_BOARD_EXPORT(rt_hw_pin_init); 452