1/* 2 * Copyright 2019, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#pragma once 14 15struct gpio_sys; 16typedef struct gpio_sys gpio_sys_t; 17typedef int gpio_id_t; 18 19#include <stdbool.h> 20#include <utils/util.h> 21#include <platsupport/io.h> 22 23#define GPIOID(port, pin) ((port) * 32 + (pin)) 24#define GPIOID_PORT(gpio) ((gpio) / 32) 25#define GPIOID_PIN(gpio) ((gpio) % 32) 26 27typedef struct gpio gpio_t; 28struct gpio { 29/// GPIO port identifier 30 gpio_id_t id; 31/// GPIO subsystem handle 32 gpio_sys_t *gpio_sys; 33}; 34 35typedef enum gpio_dir { 36/// Input direction 37 GPIO_DIR_IN, 38 /* Output direction: 39 * DEFAULT_LOW will ensure that the pin stays low even while the driver is 40 * initializing the pin. 41 * DEFAULT_HIGH will ensure that the pin stays high even while the driver is 42 * initializing the pin. 43 */ 44 GPIO_DIR_OUT_DEFAULT_LOW, 45 GPIO_DIR_OUT = GPIO_DIR_OUT_DEFAULT_LOW, 46 GPIO_DIR_OUT_DEFAULT_HIGH, 47 48/// Input direction with IRQ on low logic level 49 GPIO_DIR_IRQ_LOW, 50/// Input direction with IRQ on high logic level 51 GPIO_DIR_IRQ_HIGH, 52/// Input direction with IRQ on falling edge 53 GPIO_DIR_IRQ_FALL, 54/// Input direction with IRQ on rising edge 55 GPIO_DIR_IRQ_RISE, 56/// Input direction with IRQ on both rising and falling edges 57 GPIO_DIR_IRQ_EDGE 58} gpio_dir_t; 59 60typedef enum gpio_level { 61 /* GPIO input/output levels */ 62 GPIO_LEVEL_LOW, 63 GPIO_LEVEL_HIGH 64} gpio_level_t; 65 66struct gpio_sys { 67 /** Initialize a GPIO pin. 68 * @param gpio_sys Initialized gpio driver instance. 69 * @param id ID of the pin to initialize a handle to. 70 * @param gpio_dir Configure the pin for input/output/IRQ. 71 * Use GPIO_DIR_OUT_DEFAULT_HIGH and 72 * GPIO_DIR_OUT_DEFAULT_LOW to set the pin's 73 * default logic level. Can be useful for things 74 * like GPIO pins used as SPI chipselects where 75 * you want to ensure that a pin stays in a certain 76 * logic level even while this initialization 77 * function is running. 78 * @param gpio[out] Pointer to a gpio_t structure to be initialised. 79 * @return 0 on success. Non-zero on error. 80 */ 81 int (*init)(gpio_sys_t *gpio_sys, gpio_id_t id, enum gpio_dir dir, gpio_t *gpio); 82 83 /** 84 * Set a GPIO's output level. The pin must be configured for output 85 * for this to work. 86 * @param gpio Initialised GPIO pin instance. 87 * @param level The output level to set for the pin. 88 * @return 0 on success. Non-zero on error. 89 */ 90 int (*set_level)(gpio_t *gpio, enum gpio_level level); 91 92 /** 93 * Read a pin's input level. The pin must be configured for input for 94 * this to work. 95 * @param gpio Initialised GPIO pin instance. 96 * @return GPIO_LEVEL_LOW or GPIO_LEVEL_HIGH depending on the input level. 97 * Negative integer on error. 98 */ 99 int (*read_level)(gpio_t *gpio); 100 101 /** 102 * Read and manipulate the status of a pending IRQ. 103 * @param gpio Initialised GPIO pin instance. 104 * @param clear Flag indicating whether or not the pending IRQ 105 * should be cleared. 106 * @return 0 (none) or 1 (pending) depending on the status of the IRQ. 107 * Negative integer on error. 108 */ 109 int (*pending_status)(gpio_t *gpio, bool clear); 110 111 /** 112 * Enable or disable the IRQ signal from the pin. 113 * @param gpio Initialised GPIO pin instance. 114 * @param enable Flag indicating whether or not the IRQ signal 115 * should be enabled. 116 * @return 0 on success. Non-zero on error. 117 */ 118 int (*irq_enable_disable)(gpio_t *gpio, bool enable); 119 120/// platform specific private data 121 void *priv; 122}; 123 124static inline bool gpio_sys_valid(const gpio_sys_t *gpio_sys) 125{ 126 return gpio_sys != NULL && gpio_sys->priv != NULL; 127} 128 129static inline bool gpio_instance_valid(const gpio_t *gpio) 130{ 131 if (!gpio) { 132 ZF_LOGE("Handle to GPIO not supplied!"); 133 return false; 134 } 135 if (!gpio->gpio_sys) { 136 ZF_LOGE("GPIO pin's parent controller handle invalid!"); 137 return false; 138 } 139 return true; 140} 141 142/** 143 * Initialise the GPIO subsystem and provide a handle for access 144 * @param[in] io_ops io operations for device initialisation 145 * @param[out] gpio_sys A gpio handle structure to initialise 146 * @return 0 on success, errno value otherwise 147 */ 148int gpio_sys_init(ps_io_ops_t *io_ops, gpio_sys_t *gpio_sys); 149 150/** 151 * Clear a GPIO pin 152 * @param[in] a handle to a GPIO 153 * @return 0 on success, otherwise errno value 154 */ 155static inline int gpio_clr(gpio_t *gpio) 156{ 157 if (!gpio_instance_valid(gpio)) { 158 return -EINVAL; 159 } 160 if (!gpio->gpio_sys->set_level) { 161 ZF_LOGE("Unimplemented"); 162 return -ENOSYS; 163 } 164 return gpio->gpio_sys->set_level(gpio, GPIO_LEVEL_LOW); 165} 166 167/** 168 * Return the state of a GPIO pin 169 * @param[in] a handle to a GPIO 170 * @return the value of the pin, otherwise errno value 171 */ 172static inline int gpio_get(gpio_t *gpio) 173{ 174 if (!gpio_instance_valid(gpio)) { 175 return -EINVAL; 176 } 177 if (!gpio->gpio_sys->read_level) { 178 ZF_LOGE("Unimplemented"); 179 return -ENOSYS; 180 } 181 return gpio->gpio_sys->read_level(gpio); 182} 183 184/** 185 * Set a GPIO pin 186 * @param[in] a handle to a GPIO 187 * @return 0 on success, otherwise errno value 188 */ 189static inline int gpio_set(gpio_t *gpio) 190{ 191 if (!gpio_instance_valid(gpio)) { 192 return -EINVAL; 193 } 194 if (!gpio->gpio_sys->set_level) { 195 ZF_LOGE("Unimplemented"); 196 return -ENOSYS; 197 } 198 return gpio->gpio_sys->set_level(gpio, GPIO_LEVEL_HIGH); 199} 200 201/** 202 * Check if an IRQ is pending for this GPIO 203 * @param[in] a handle to a GPIO 204 * @return errno value on error 205 * 0 if an IRQ is not pending 206 * 1 if an IRQ is pending 207 */ 208static inline int gpio_is_pending(gpio_t *gpio) 209{ 210 if (!gpio_instance_valid(gpio)) { 211 return -EINVAL; 212 } 213 if (!gpio->gpio_sys->pending_status) { 214 ZF_LOGE("Unimplemented"); 215 return -ENOSYS; 216 } 217 return gpio->gpio_sys->pending_status(gpio, false); 218} 219 220/** 221 * Clear pending IRQs for this GPIO 222 * @param[in] a handle to a GPIO 223 * @return 0 on success, errno value on error 224 */ 225static inline int gpio_pending_clear(gpio_t *gpio) 226{ 227 if (!gpio_instance_valid(gpio)) { 228 return -EINVAL; 229 } 230 if (!gpio->gpio_sys->pending_status) { 231 ZF_LOGE("Unimplemented"); 232 return -ENOSYS; 233 } 234 int ret = gpio->gpio_sys->pending_status(gpio, true); 235 if (ret < 0) { 236 return ret; 237 } 238 return 0; 239} 240 241/** 242 * Enable the IRQ signal from the pin. 243 * @param[in] gpio Handle to the pin to manipulate 244 * @return 0 for success, errno value on error. 245 */ 246static inline int gpio_irq_enable(gpio_t *gpio) 247{ 248 if (!gpio_instance_valid(gpio)) { 249 return -EINVAL; 250 } 251 if (!gpio->gpio_sys->irq_enable_disable) { 252 ZF_LOGE("Unimplemented"); 253 return -ENOSYS; 254 } 255 return gpio->gpio_sys->irq_enable_disable(gpio, true); 256} 257 258/** 259 * Disable the IRQ signal from the pin. 260 * @param[in] gpio Handle to the pin to manipulate 261 * @return 0 for success, errno value on error. 262 */ 263static inline int gpio_irq_disable(gpio_t *gpio) 264{ 265 if (!gpio_instance_valid(gpio)) { 266 return -EINVAL; 267 } 268 if (!gpio->gpio_sys->irq_enable_disable) { 269 ZF_LOGE("Unimplemented"); 270 return -ENOSYS; 271 } 272 return gpio->gpio_sys->irq_enable_disable(gpio, false); 273} 274 275/** 276 * Acquire a handle to a GPIO pin 277 * @param[in] gpio_sys a handle to an initialised GPIO subsystem\ 278 * @param[in] id A pin identifier obtained from the macro 279 * GPIOID(port, pin) 280 * @param[in] dir The direction of the pin 281 * @param[out] gpio a GPIO handle to initialise 282 * @return 0 on success 283 */ 284static inline int gpio_new(gpio_sys_t *gpio_sys, gpio_id_t id, enum gpio_dir dir, gpio_t *gpio) 285{ 286 if (!gpio_sys) { 287 ZF_LOGE("Handle to GPIO controller not supplied!"); 288 return -EINVAL; 289 } 290 291 if (!gpio_sys->init) { 292 ZF_LOGE("Unimplemented"); 293 return -ENOSYS; 294 } 295 296 if (!gpio) { 297 ZF_LOGE("Handle to output pin structure not supplied!"); 298 return -EINVAL; 299 } 300 301 return gpio_sys->init(gpio_sys, id, dir, gpio); 302} 303