summaryrefslogtreecommitdiffstats
path: root/firmware/target/mips/ingenic_x1000/gpio-x1000.h
blob: 5d147fc18f5e0bdeea1e0b54f90ac6f23250b66e (plain)
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
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2021 Aidan MacDonald
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#ifndef __GPIO_X1000_H__
#define __GPIO_X1000_H__

#include "x1000/gpio.h"

/* GPIO port numbers */
#define GPIO_A 0
#define GPIO_B 1
#define GPIO_C 2
#define GPIO_D 3
#define GPIO_Z 7

/* GPIO function bits */
#define GPIO_F_PULL 16
#define GPIO_F_INT  8
#define GPIO_F_MASK 4
#define GPIO_F_PAT1 2
#define GPIO_F_PAT0 1

/* GPIO function numbers */
#define GPIOF_DEVICE(i)     ((i)&3)
#define GPIOF_OUTPUT(i)     (0x4|((i)&1))
#define GPIOF_INPUT         0x16
#define GPIOF_IRQ_LEVEL(i)  (0x1c|((i)&1))
#define GPIOF_IRQ_EDGE(i)   (0x1e|((i)&1))

/* GPIO pin numbers */
#define GPION_CREATE(port, pin) ((((port) & 3) << 5) | ((pin) & 0x1f))
#define GPION_PORT(gpio)        (((gpio) >> 5) & 3)
#define GPION_PIN(gpio)         ((gpio) & 0x1f)
#define GPION_MASK(gpio)        (1u << GPION_PIN(gpio))

/* Easy pin number macros */
#define GPIO_PA(x)  GPION_CREATE(GPIO_A, x)
#define GPIO_PB(x)  GPION_CREATE(GPIO_B, x)
#define GPIO_PC(x)  GPION_CREATE(GPIO_C, x)
#define GPIO_PD(x)  GPION_CREATE(GPIO_D, x)

/* Pingroup settings are used for system devices */
struct pingroup_setting {
    int port;
    uint32_t pins;
    int func;
};

/* GPIO settings are used for single pins under software control */
struct gpio_setting {
    int gpio;
    int func;
};

/* Target pins are defined as GPIO_XXX constants usable with the GPIO API */
enum {
#define DEFINE_GPIO(_name, _gpio, _func) GPIO_##_name = _gpio,
#define DEFINE_PINGROUP(...)
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
    GPIO_NONE = -1,
};

/* These are pin IDs which index gpio_settings */
enum {
#define DEFINE_GPIO(_name, ...) PIN_##_name,
#define DEFINE_PINGROUP(...)
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
    PIN_COUNT,
};

/* Pingroup IDs which index pingroup_settings */
enum {
#define DEFINE_GPIO(...)
#define DEFINE_PINGROUP(_name, ...) PINGROUP_##_name,
#include "gpio-target.h"
#undef DEFINE_GPIO
#undef DEFINE_PINGROUP
    PINGROUP_COUNT,
};

/* arrays which define the target's GPIO settings */
extern const struct gpio_setting gpio_settings[PIN_COUNT];
extern const struct pingroup_setting pingroup_settings[PINGROUP_COUNT];

/* stringified names for use in debug menus */
extern const char* const gpio_names[PIN_COUNT];
extern const char* const pingroup_names[PINGROUP_COUNT];

/* called at early init to set up GPIOs */
extern void gpio_init(void);

/* Use GPIO Z to reconfigure several pins atomically */
extern void gpioz_configure(int port, uint32_t pins, int func);

static inline void gpio_set_function(int gpio, int func)
{
    gpioz_configure(GPION_PORT(gpio), GPION_MASK(gpio), func);
}

static inline int gpio_get_level(int gpio)
{
    return REG_GPIO_PIN(GPION_PORT(gpio)) & GPION_MASK(gpio) ? 1 : 0;
}

static inline void gpio_set_level(int gpio, int value)
{
    if(value)
        jz_set(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
    else
        jz_clr(GPIO_PAT0(GPION_PORT(gpio)), GPION_MASK(gpio));
}

static inline void gpio_set_pull(int gpio, int state)
{
    if(state)
        jz_set(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
    else
        jz_clr(GPIO_PULL(GPION_PORT(gpio)), GPION_MASK(gpio));
}

static inline void gpio_mask_irq(int gpio, int mask)
{
    if(mask)
        jz_set(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
    else
        jz_clr(GPIO_MSK(GPION_PORT(gpio)), GPION_MASK(gpio));
}

#define gpio_set_irq_level      gpio_set_level
#define gpio_enable_irq(gpio)   gpio_mask_irq((gpio), 0)
#define gpio_disable_irq(gpio)  gpio_mask_irq((gpio), 1)

/* Helper function for edge-triggered IRQs when you want to get an
 * interrupt on both the rising and falling edges. The hardware can
 * only be set up to interrupt on one edge, so interrupt handlers
 * can call this function to flip the trigger to the other edge.
 *
 * Despite the name, this doesn't depend on the currently set edge,
 * it just reads the GPIO state and sets up an edge trigger to detect
 * a change to the other state -- if some transitions were missed the
 * IRQ trigger may remain unchanged.
 *
 * It can be safely used to initialize the IRQ level.
 */
static inline void gpio_flip_edge_irq(int gpio)
{
    if(gpio_get_level(gpio))
        gpio_set_irq_level(gpio, 0);
    else
        gpio_set_irq_level(gpio, 1);
}

#endif /* __GPIO_X1000_H__ */