aboutsummaryrefslogtreecommitdiff
path: root/include/kern/gpio/gpio_manager.h
blob: 922a4235bda704a2d0d228ddf9f490289af8d0ef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#ifndef KERN_GPIO_GPIO_MANAGE_H_
#define KERN_GPIO_GPIO_MANAGE_H_

#include "kern/common.h"
#include "arch/stm32l4xxx/peripherals/gpio.h"

#define GPIO_ERROR_IN_USE 1
#define GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION 2
#define GPIO_ERROR_INVALID_PIN 3

typedef enum {
/* Creates vaules GPIO_PIN_<port><num> i.e. GPIO_PIN_A0 */
#define PORT(p, pn) \
  GPIO_PIN_P ## p ## pn,
#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
#undef PORT

  N_GPIO_PINS
} gpio_pin_t;

/* Alternate functions. */
typedef enum {
#define AFN(fn, ...) \
  GPIO_ALTERNATE_FUNCTION_ ## fn,
#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc"
#undef AFN
  GPIO_ALTERNATE_FUNCTION_EVENTOUT,
} gpio_alternate_function_t;

#define gpio_pin_for_alternate_function(af) ((af) / 16)
#define gpio_pin_out_of_range(pin) \
  ((pin) < 0 || (pin) >= N_GPIO_PINS)

typedef enum {
  GPIO_PORT_A,
  GPIO_PORT_B,
  GPIO_PORT_C,
  GPIO_PORT_D,
  GPIO_PORT_E,
  GPIO_PORT_F,
  GPIO_PORT_G,
  GPIO_PORT_H,
  GPIO_PORT_I,

  N_GPIO_PORTS,
} gpio_port_t;

typedef enum {
  GPIO_MODE_INPUT,
  GPIO_MODE_OUTPUT,
  GPIO_MODE_ALTERNATE,
  GPIO_MODE_ANALOG
} gpio_mode_t;

/*
 * Enum defining the pin speeds that are possible.
 */
typedef enum {
  SPEED_2MHZ = 0,
  SPEED_10MHZ = 1,
  SPEED_50MHZ = 3,
} gpio_speed_t;

typedef enum {
  GPIO_OUTPUT_TYPE_PUSH_PULL,
  GPIO_OUTPUT_TYPE_OPEN_DRAIN
} gpio_output_type_t;

typedef enum {
  GPIO_OUTPUT_SPEED_LOW,
  GPIO_OUTPUT_SPEED_MEDIUM,
  GPIO_OUTPUT_SPEED_HIGH,
  GPIO_OUTPUT_SPEED_VERY_HIGH,
} gpio_output_speed_t;

typedef enum {
  GPIO_PULL_DIR_NONE,
  GPIO_PULL_DIR_UP,
  GPIO_PULL_DIR_DOWN,
} gpio_pull_dir_t;

/* Returns the appropriate gpio_port for the provided pin. */
inline static gpio_port_t get_port_for_pin(gpio_pin_t pin)
{
  switch (pin) {
#define PORT(p, pn) \
    case GPIO_PIN_P ## p ## pn: return GPIO_PORT_ ## p;
#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
#undef PORT
    case N_GPIO_PINS: return N_GPIO_PORTS;
  }

  /* Should be unreachable. */
}

#define DEFAULT_GPIO_OPTS_OUTPUT \
  (gpio_pin_opts_t) { \
    .mode = GPIO_MODE_OUTPUT, \
    .pull_dir = GPIO_PULL_DIR_DOWN, \
    .output_opts.speed = GPIO_OUTPUT_SPEED_MEDIUM, \
    .output_opts.type = GPIO_OUTPUT_TYPE_PUSH_PULL, \
  }

#define DEFAULT_GPIO_OPTS_INPUT \
  (gpio_pin_opts_t) { \
    .mode = GPIO_MODE_OUTPUT, \
    .pull_dir = GPIO_PULL_DIR_DOWN, \
  }

typedef struct {
  gpio_mode_t      mode;
  gpio_pull_dir_t  pull_dir;

  union {
    struct {
    } input_opts;

    struct {
      gpio_output_speed_t        speed;
      gpio_output_type_t  type;
    } output_opts;

    struct {
      uint8_t function;
    } alternate_opts;

    struct {
    } analog_opts;
  };
} gpio_pin_opts_t;

/* Differentiates at compile-time from the a gpio_pin_t enum value and a pin
 * that's been reserved. */
typedef struct {
  gpio_pin_t v_;
} gpio_reserved_pin_t;

/* Returns a pointer to the GPIO pin bus and offset.  This is useful for when
 * raw access to the values are needed. I.e. time critical applications. */
void get_gpio_pin_port_off(
    gpio_pin_t pin, gpio_port_config_t** out_cfg, int* out_off);

/* Sets the given GPIO pin to high. */
void set_gpio_pin_high(gpio_reserved_pin_t pin);

/* Sets the given GPIO pin to low. */
void set_gpio_pin_low(gpio_reserved_pin_t pin);

/** returns true if a GPIO pin is in use. */
bool gpio_pin_in_use(gpio_pin_t pin);

/*
 * Reserve the provided GPIO pin using the opts provided.
 *
 * sets error_out to GPIO_ERROR_IN_USE if the GPIO pin could not be reserved
 * because it already has been reserved.
 *
 * The function will automatically enable the correct GPIO port bus.
 */
gpio_reserved_pin_t reserve_gpio_pin(
    gpio_pin_t pin, gpio_pin_opts_t* opts, int* error_out);

/* Enables and returns the pin reserved for the alternate function.
 *
 * If the `hint` parameter is defined (non -1) the manager will try
 * to reserve that pin for the alternate function and fail if it can't.
 *
 * If `hint` is -1 then the first available pin for that alternate function
 * will be reserved and returned.
 *
 *
 */
gpio_reserved_pin_t gpio_enable_alternate_function(
    gpio_alternate_function_t fn,
    gpio_pin_t hint,
    int* error_out);

/*
 * Releases the GPIO pin so it can be reserved again in the future.
 *
 * The pin is reset during this process and if there are no more reserved pins
 * on the corresponding port this function will disable the port. (last one out
 * gets the lights.).
 */
void release_gpio_pin(gpio_reserved_pin_t gpio_pin);

#endif /* KERN_GPIO_GPIO_MANAGE_H_ */