summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/gpio-x1000.h
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/gpio-x1000.h')
-rw-r--r--firmware/target/mips/ingenic_x1000/gpio-x1000.h164
1 files changed, 116 insertions, 48 deletions
diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.h b/firmware/target/mips/ingenic_x1000/gpio-x1000.h
index cfbe86338a..5d147fc18f 100644
--- a/firmware/target/mips/ingenic_x1000/gpio-x1000.h
+++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.h
@@ -22,33 +22,6 @@
22#ifndef __GPIO_X1000_H__ 22#ifndef __GPIO_X1000_H__
23#define __GPIO_X1000_H__ 23#define __GPIO_X1000_H__
24 24
25/* GPIO API
26 * --------
27 *
28 * To assign a new function to a GPIO, call gpio_config(). This uses the
29 * hardware's GPIO Z facility to atomically set most GPIO registers at once,
30 * so it can be used to make any state transition safely. Since GPIO Z is
31 * a global hardware resource, it is unsafe to call gpio_config() from IRQ
32 * context -- if the interrupted code was also running gpio_config(), then
33 * the results would be unpredictable.
34 *
35 * Depending on the current GPIO state, certain state transitions are safe to
36 * perform without locking, as they only change one register:
37 *
38 * - for pins in GPIO_OUTPUT state:
39 * - use gpio_out_level() to change the output level
40 *
41 * - for pins in GPIO_IRQ_LEVEL or GPIO_IRQ_EDGE state:
42 * - use gpio_irq_level() to change the trigger level
43 * - use gpio_irq_mask() to mask/unmask the IRQ
44 *
45 * - for pins in GPIO_DEVICE or GPIO_INPUT state:
46 * - no special transitions allowed
47 *
48 * - in all states:
49 * - use gpio_set_pull() to change the pull-up/pull-down state
50 */
51
52#include "x1000/gpio.h" 25#include "x1000/gpio.h"
53 26
54/* GPIO port numbers */ 27/* GPIO port numbers */
@@ -66,42 +39,137 @@
66#define GPIO_F_PAT0 1 39#define GPIO_F_PAT0 1
67 40
68/* GPIO function numbers */ 41/* GPIO function numbers */
69#define GPIO_DEVICE(i) ((i)&3) 42#define GPIOF_DEVICE(i) ((i)&3)
70#define GPIO_OUTPUT(i) (0x4|((i)&1)) 43#define GPIOF_OUTPUT(i) (0x4|((i)&1))
71#define GPIO_INPUT 0x16 44#define GPIOF_INPUT 0x16
72#define GPIO_IRQ_LEVEL(i) (0x1c|((i)&1)) 45#define GPIOF_IRQ_LEVEL(i) (0x1c|((i)&1))
73#define GPIO_IRQ_EDGE(i) (0x1e|((i)&1)) 46#define GPIOF_IRQ_EDGE(i) (0x1e|((i)&1))
47
48/* GPIO pin numbers */
49#define GPION_CREATE(port, pin) ((((port) & 3) << 5) | ((pin) & 0x1f))
50#define GPION_PORT(gpio) (((gpio) >> 5) & 3)
51#define GPION_PIN(gpio) ((gpio) & 0x1f)
52#define GPION_MASK(gpio) (1u << GPION_PIN(gpio))
53
54/* Easy pin number macros */
55#define GPIO_PA(x) GPION_CREATE(GPIO_A, x)
56#define GPIO_PB(x) GPION_CREATE(GPIO_B, x)
57#define GPIO_PC(x) GPION_CREATE(GPIO_C, x)
58#define GPIO_PD(x) GPION_CREATE(GPIO_D, x)
59
60/* Pingroup settings are used for system devices */
61struct pingroup_setting {
62 int port;
63 uint32_t pins;
64 int func;
65};
66
67/* GPIO settings are used for single pins under software control */
68struct gpio_setting {
69 int gpio;
70 int func;
71};
72
73/* Target pins are defined as GPIO_XXX constants usable with the GPIO API */
74enum {
75#define DEFINE_GPIO(_name, _gpio, _func) GPIO_##_name = _gpio,
76#define DEFINE_PINGROUP(...)
77#include "gpio-target.h"
78#undef DEFINE_GPIO
79#undef DEFINE_PINGROUP
80 GPIO_NONE = -1,
81};
82
83/* These are pin IDs which index gpio_settings */
84enum {
85#define DEFINE_GPIO(_name, ...) PIN_##_name,
86#define DEFINE_PINGROUP(...)
87#include "gpio-target.h"
88#undef DEFINE_GPIO
89#undef DEFINE_PINGROUP
90 PIN_COUNT,
91};
92
93/* Pingroup IDs which index pingroup_settings */
94enum {
95#define DEFINE_GPIO(...)
96#define DEFINE_PINGROUP(_name, ...) PINGROUP_##_name,
97#include "gpio-target.h"
98#undef DEFINE_GPIO
99#undef DEFINE_PINGROUP
100 PINGROUP_COUNT,
101};
102
103/* arrays which define the target's GPIO settings */
104extern const struct gpio_setting gpio_settings[PIN_COUNT];
105extern const struct pingroup_setting pingroup_settings[PINGROUP_COUNT];
74 106
107/* stringified names for use in debug menus */
108extern const char* const gpio_names[PIN_COUNT];
109extern const char* const pingroup_names[PINGROUP_COUNT];
110
111/* called at early init to set up GPIOs */
75extern void gpio_init(void); 112extern void gpio_init(void);
76extern void gpio_config(int port, unsigned pinmask, int func);
77 113
78static inline void gpio_out_level(int port, unsigned pinmask, int level) 114/* Use GPIO Z to reconfigure several pins atomically */
115extern void gpioz_configure(int port, uint32_t pins, int func);
116
117static inline void gpio_set_function(int gpio, int func)
118{
119 gpioz_configure(GPION_PORT(gpio), GPION_MASK(gpio), func);
120}
121
122static inline int gpio_get_level(int gpio)
123{
124 return REG_GPIO_PIN(GPION_PORT(gpio)) & GPION_MASK(gpio) ? 1 : 0;
125}
126
127static inline void gpio_set_level(int gpio, int value)
79{ 128{
80 if(level) 129 if(value)
81 jz_set(GPIO_PAT0(port), pinmask); 130 jz_set(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
82 else 131 else
83 jz_clr(GPIO_PAT0(port), pinmask); 132 jz_clr(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
84} 133}
85 134
86#define gpio_irq_level gpio_out_level 135static inline void gpio_set_pull(int gpio, int state)
136{
137 if(state)
138 jz_set(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
139 else
140 jz_clr(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
141}
87 142
88static inline void gpio_irq_mask(int port, unsigned pinmask, int masked) 143static inline void gpio_mask_irq(int gpio, int mask)
89{ 144{
90 if(masked) 145 if(mask)
91 jz_set(GPIO_MSK(port), pinmask); 146 jz_set(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
92 else 147 else
93 jz_clr(GPIO_MSK(port), pinmask); 148 jz_clr(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
94} 149}
95 150
96#define gpio_enable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 0) 151#define gpio_set_irq_level gpio_set_level
97#define gpio_disable_irq(port, pinmask) gpio_irq_mask((port), (pinmask), 1) 152#define gpio_enable_irq(gpio) gpio_mask_irq((gpio), 0)
153#define gpio_disable_irq(gpio) gpio_mask_irq((gpio), 1)
98 154
99static inline void gpio_set_pull(int port, unsigned pinmask, int state) 155/* Helper function for edge-triggered IRQs when you want to get an
156 * interrupt on both the rising and falling edges. The hardware can
157 * only be set up to interrupt on one edge, so interrupt handlers
158 * can call this function to flip the trigger to the other edge.
159 *
160 * Despite the name, this doesn't depend on the currently set edge,
161 * it just reads the GPIO state and sets up an edge trigger to detect
162 * a change to the other state -- if some transitions were missed the
163 * IRQ trigger may remain unchanged.
164 *
165 * It can be safely used to initialize the IRQ level.
166 */
167static inline void gpio_flip_edge_irq(int gpio)
100{ 168{
101 if(state) 169 if(gpio_get_level(gpio))
102 jz_set(GPIO_PULL(port), pinmask); 170 gpio_set_irq_level(gpio, 0);
103 else 171 else
104 jz_clr(GPIO_PULL(port), pinmask); 172 gpio_set_irq_level(gpio, 1);
105} 173}
106 174
107#endif /* __GPIO_X1000_H__ */ 175#endif /* __GPIO_X1000_H__ */