Skip to content

Commit 66ca48a

Browse files
nategraff-sifivegalak
authored andcommitted
drivers: gpio_sifive: Update for new GPIO API
Update the Sifive GPIO driver for new API Signed-off-by: Nathaniel Graff <[email protected]>
1 parent 7a38969 commit 66ca48a

File tree

2 files changed

+209
-107
lines changed

2 files changed

+209
-107
lines changed

boards/riscv/hifive1_revb/hifive1_revb.dts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
leds {
2525
compatible = "gpio-leds";
2626
led0: led_0 {
27-
gpios = <&gpio0 19 0>;
27+
gpios = <&gpio0 19 GPIO_ACTIVE_LOW>;
2828
label = "Green LED";
2929
};
3030
led1: led_1 {
31-
gpios = <&gpio0 21 0>;
31+
gpios = <&gpio0 21 GPIO_ACTIVE_LOW>;
3232
label = "Blue LED";
3333
};
3434
led2: led_2 {
35-
gpios = <&gpio0 22 0>;
35+
gpios = <&gpio0 22 GPIO_ACTIVE_LOW>;
3636
label = "Red LED";
3737
};
3838
};

drivers/gpio/gpio_sifive.c

Lines changed: 206 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -61,34 +61,80 @@ struct gpio_sifive_data {
6161
#define DEV_GPIO_DATA(dev) \
6262
((struct gpio_sifive_data *)(dev)->driver_data)
6363

64+
/* _irq_level and _level2_irq are copied from
65+
* soc/riscv/riscv-privileged/common/soc_common_irq.c
66+
* Ideally this kind of thing should be made available in include/irq.h or
67+
* somewhere similar since the multi-level IRQ format is generic to
68+
Zephyr, and then both this copy and the one in riscv-privileged
69+
* be removed for the shared implementation
70+
*/
71+
static inline unsigned int _irq_level(unsigned int irq)
72+
{
73+
return ((irq >> 8) && 0xff) == 0U ? 1 : 2;
74+
}
75+
76+
static inline unsigned int _level2_irq(unsigned int irq)
77+
{
78+
return (irq >> 8) - 1;
79+
}
80+
81+
/* Given gpio_irq_base and the pin number, return the IRQ number for the pin */
82+
static inline unsigned int gpio_sifive_pin_irq(unsigned int base_irq, int pin)
83+
{
84+
unsigned int level = _irq_level(base_irq);
85+
unsigned int pin_irq = 0;
86+
87+
if (level == 1) {
88+
pin_irq = base_irq + pin;
89+
} else if (level == 2) {
90+
pin_irq = base_irq + (pin << 8);
91+
}
92+
93+
return pin_irq;
94+
}
95+
96+
/* Given the PLIC source number, return the number of the GPIO pin associated
97+
* with the interrupt
98+
*/
99+
static inline int gpio_sifive_plic_to_pin(unsigned int base_irq, int plic_irq)
100+
{
101+
unsigned int level = _irq_level(base_irq);
102+
103+
if (level == 2) {
104+
base_irq = _level2_irq(base_irq);
105+
}
106+
107+
return (plic_irq - base_irq);
108+
}
109+
64110
static void gpio_sifive_irq_handler(void *arg)
65111
{
66112
struct device *dev = (struct device *)arg;
67113
struct gpio_sifive_data *data = DEV_GPIO_DATA(dev);
68114
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
69115
const struct gpio_sifive_config *cfg = DEV_GPIO_CFG(dev);
70-
int pin_mask;
116+
int pin;
71117

72118
/* Get the pin number generating the interrupt */
73-
pin_mask = 1 << (riscv_plic_get_irq() - cfg->gpio_irq_base);
74-
75-
/* Call the corresponding callback registered for the pin */
76-
gpio_fire_callbacks(&data->cb, dev, pin_mask);
119+
pin = gpio_sifive_plic_to_pin(cfg->gpio_irq_base, riscv_plic_get_irq());
77120

78121
/*
79122
* Write to either the rise_ip, fall_ip, high_ip or low_ip registers
80123
* to indicate to GPIO controller that interrupt for the corresponding
81124
* pin has been handled.
82125
*/
83-
if (gpio->rise_ip & pin_mask) {
84-
gpio->rise_ip = pin_mask;
85-
} else if (gpio->fall_ip & pin_mask) {
86-
gpio->fall_ip = pin_mask;
87-
} else if (gpio->high_ip & pin_mask) {
88-
gpio->high_ip = pin_mask;
89-
} else if (gpio->low_ip & pin_mask) {
90-
gpio->low_ip = pin_mask;
126+
if (gpio->rise_ip & BIT(pin)) {
127+
gpio->rise_ip = BIT(pin);
128+
} else if (gpio->fall_ip & BIT(pin)) {
129+
gpio->fall_ip = BIT(pin);
130+
} else if (gpio->high_ip & BIT(pin)) {
131+
gpio->high_ip = BIT(pin);
132+
} else if (gpio->low_ip & BIT(pin)) {
133+
gpio->low_ip = BIT(pin);
91134
}
135+
136+
/* Call the corresponding callback registered for the pin */
137+
gpio_fire_callbacks(&data->cb, dev, BIT(pin));
92138
}
93139

94140
/**
@@ -116,94 +162,33 @@ static int gpio_sifive_config(struct device *dev,
116162
return -EINVAL;
117163
}
118164

119-
/* Configure gpio direction */
120-
if (flags & GPIO_DIR_OUT) {
121-
gpio->in_en &= ~BIT(pin);
122-
gpio->out_en |= BIT(pin);
123-
124-
/*
125-
* Account for polarity only for GPIO_DIR_OUT.
126-
* invert register handles only output gpios
127-
*/
128-
if (flags & GPIO_POL_INV) {
129-
gpio->invert |= BIT(pin);
130-
} else {
131-
gpio->invert &= ~BIT(pin);
132-
}
133-
} else {
134-
gpio->out_en &= ~BIT(pin);
135-
gpio->in_en |= BIT(pin);
136-
137-
/* Polarity inversion is not supported for input gpio */
138-
if (flags & GPIO_POL_INV) {
139-
return -EINVAL;
140-
}
141-
142-
/*
143-
* Pull-up can be configured only for input gpios.
144-
* Only Pull-up can be enabled or disabled.
145-
*/
146-
if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) {
147-
return -EINVAL;
148-
}
149-
150-
if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) {
151-
gpio->pue |= BIT(pin);
152-
} else {
153-
gpio->pue &= ~BIT(pin);
154-
}
165+
/* We cannot support open-source open-drain configuration */
166+
if ((flags & GPIO_SINGLE_ENDED) != 0) {
167+
return -ENOTSUP;
155168
}
156169

157-
/*
158-
* Configure interrupt if GPIO_INT is set.
159-
* Here, we just configure the gpio interrupt behavior,
160-
* we do not enable/disable interrupt for a particular
161-
* gpio.
162-
* Interrupt for a gpio is:
163-
* 1) enabled only via a call to gpio_sifive_enable_callback.
164-
* 2) disabled only via a call to gpio_sifive_disabled_callback.
165-
*/
166-
if (!(flags & GPIO_INT)) {
167-
return 0;
170+
/* We only support pull-ups, not pull-downs */
171+
if ((flags & GPIO_PULL_DOWN) != 0) {
172+
return -ENOTSUP;
168173
}
169174

170-
/*
171-
* Interrupt cannot be set for GPIO_DIR_OUT
175+
/* Set pull-up if requested */
176+
WRITE_BIT(gpio->pue, pin, flags & GPIO_PULL_UP);
177+
178+
/* Set the initial output value before enabling output to avoid
179+
* glitches
172180
*/
173-
if (flags & GPIO_DIR_OUT) {
174-
return -EINVAL;
181+
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
182+
gpio->out_val |= BIT(pin);
175183
}
176-
177-
/* Edge or Level triggered ? */
178-
if (flags & GPIO_INT_EDGE) {
179-
gpio->high_ie &= ~BIT(pin);
180-
gpio->low_ie &= ~BIT(pin);
181-
182-
/* Rising Edge, Falling Edge or Double Edge ? */
183-
if (flags & GPIO_INT_DOUBLE_EDGE) {
184-
gpio->rise_ie |= BIT(pin);
185-
gpio->fall_ie |= BIT(pin);
186-
} else if (flags & GPIO_INT_ACTIVE_HIGH) {
187-
gpio->rise_ie |= BIT(pin);
188-
gpio->fall_ie &= ~BIT(pin);
189-
} else {
190-
gpio->rise_ie &= ~BIT(pin);
191-
gpio->fall_ie |= BIT(pin);
192-
}
193-
} else {
194-
gpio->rise_ie &= ~BIT(pin);
195-
gpio->fall_ie &= ~BIT(pin);
196-
197-
/* Level High ? */
198-
if (flags & GPIO_INT_ACTIVE_HIGH) {
199-
gpio->high_ie |= BIT(pin);
200-
gpio->low_ie &= ~BIT(pin);
201-
} else {
202-
gpio->high_ie &= ~BIT(pin);
203-
gpio->low_ie |= BIT(pin);
204-
}
184+
if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
185+
gpio->out_val &= ~BIT(pin);
205186
}
206187

188+
/* Enable input/output */
189+
WRITE_BIT(gpio->out_en, pin, flags & GPIO_OUTPUT);
190+
WRITE_BIT(gpio->in_en, pin, flags & GPIO_INPUT);
191+
207192
return 0;
208193
}
209194

@@ -284,6 +269,117 @@ static int gpio_sifive_read(struct device *dev,
284269
return 0;
285270
}
286271

272+
static int gpio_sifive_port_get_raw(struct device *dev,
273+
gpio_port_value_t *value)
274+
{
275+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
276+
277+
*value = gpio->in_val;
278+
279+
return 0;
280+
}
281+
282+
static int gpio_sifive_port_set_masked_raw(struct device *dev,
283+
gpio_port_pins_t mask,
284+
gpio_port_value_t value)
285+
{
286+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
287+
288+
gpio->out_val = (gpio->out_val & ~mask) | (value & mask);
289+
290+
return 0;
291+
}
292+
293+
static int gpio_sifive_port_set_bits_raw(struct device *dev,
294+
gpio_port_pins_t mask)
295+
{
296+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
297+
298+
gpio->out_val |= mask;
299+
300+
return 0;
301+
}
302+
303+
static int gpio_sifive_port_clear_bits_raw(struct device *dev,
304+
gpio_port_pins_t mask)
305+
{
306+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
307+
308+
gpio->out_val &= ~mask;
309+
310+
return 0;
311+
}
312+
313+
static int gpio_sifive_port_toggle_bits(struct device *dev,
314+
gpio_port_pins_t mask)
315+
{
316+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
317+
318+
gpio->out_val ^= mask;
319+
320+
return 0;
321+
}
322+
323+
static int gpio_sifive_pin_interrupt_configure(struct device *dev,
324+
unsigned int pin,
325+
enum gpio_int_mode mode,
326+
enum gpio_int_trig trig)
327+
{
328+
volatile struct gpio_sifive_t *gpio = DEV_GPIO(dev);
329+
const struct gpio_sifive_config *cfg = DEV_GPIO_CFG(dev);
330+
331+
switch (mode) {
332+
case GPIO_INT_MODE_DISABLED:
333+
gpio->rise_ie &= ~BIT(pin);
334+
gpio->fall_ie &= ~BIT(pin);
335+
gpio->high_ie &= ~BIT(pin);
336+
gpio->low_ie &= ~BIT(pin);
337+
irq_disable(gpio_sifive_pin_irq(cfg->gpio_irq_base, pin));
338+
break;
339+
case GPIO_INT_MODE_LEVEL:
340+
gpio->rise_ie &= ~BIT(pin);
341+
gpio->fall_ie &= ~BIT(pin);
342+
343+
if (trig == GPIO_INT_TRIG_HIGH) {
344+
gpio->high_ip = BIT(pin);
345+
gpio->high_ie |= BIT(pin);
346+
gpio->low_ie &= ~BIT(pin);
347+
} else if (trig == GPIO_INT_TRIG_LOW) {
348+
gpio->high_ie &= ~BIT(pin);
349+
gpio->low_ip = BIT(pin);
350+
gpio->low_ie |= BIT(pin);
351+
}
352+
irq_enable(gpio_sifive_pin_irq(cfg->gpio_irq_base, pin));
353+
break;
354+
case GPIO_INT_MODE_EDGE:
355+
gpio->high_ie &= ~BIT(pin);
356+
gpio->low_ie &= ~BIT(pin);
357+
358+
/* Rising Edge, Falling Edge or Double Edge ? */
359+
if (trig == GPIO_INT_TRIG_HIGH) {
360+
gpio->rise_ip = BIT(pin);
361+
gpio->rise_ie |= BIT(pin);
362+
gpio->fall_ie &= ~BIT(pin);
363+
} else if (trig == GPIO_INT_TRIG_LOW) {
364+
gpio->rise_ie &= ~BIT(pin);
365+
gpio->fall_ip = BIT(pin);
366+
gpio->fall_ie |= BIT(pin);
367+
} else {
368+
gpio->rise_ip = BIT(pin);
369+
gpio->rise_ie |= BIT(pin);
370+
gpio->fall_ip = BIT(pin);
371+
gpio->fall_ie |= BIT(pin);
372+
}
373+
irq_enable(gpio_sifive_pin_irq(cfg->gpio_irq_base, pin));
374+
break;
375+
default:
376+
__ASSERT(false, "Invalid MODE %d passed to driver", mode);
377+
return -ENOTSUP;
378+
}
379+
380+
return 0;
381+
}
382+
287383
static int gpio_sifive_manage_callback(struct device *dev,
288384
struct gpio_callback *callback,
289385
bool set)
@@ -308,7 +404,7 @@ static int gpio_sifive_enable_callback(struct device *dev,
308404
}
309405

310406
/* Enable interrupt for the pin at PLIC level */
311-
irq_enable(cfg->gpio_irq_base + pin);
407+
irq_enable(gpio_sifive_pin_irq(cfg->gpio_irq_base, pin));
312408

313409
return 0;
314410
}
@@ -328,18 +424,24 @@ static int gpio_sifive_disable_callback(struct device *dev,
328424
}
329425

330426
/* Disable interrupt for the pin at PLIC level */
331-
irq_disable(cfg->gpio_irq_base + pin);
427+
irq_disable(gpio_sifive_pin_irq(cfg->gpio_irq_base, pin));
332428

333429
return 0;
334430
}
335431

336432
static const struct gpio_driver_api gpio_sifive_driver = {
337-
.config = gpio_sifive_config,
338-
.write = gpio_sifive_write,
339-
.read = gpio_sifive_read,
340-
.manage_callback = gpio_sifive_manage_callback,
341-
.enable_callback = gpio_sifive_enable_callback,
342-
.disable_callback = gpio_sifive_disable_callback,
433+
.config = gpio_sifive_config,
434+
.write = gpio_sifive_write,
435+
.read = gpio_sifive_read,
436+
.port_get_raw = gpio_sifive_port_get_raw,
437+
.port_set_masked_raw = gpio_sifive_port_set_masked_raw,
438+
.port_set_bits_raw = gpio_sifive_port_set_bits_raw,
439+
.port_clear_bits_raw = gpio_sifive_port_clear_bits_raw,
440+
.port_toggle_bits = gpio_sifive_port_toggle_bits,
441+
.pin_interrupt_configure = gpio_sifive_pin_interrupt_configure,
442+
.manage_callback = gpio_sifive_manage_callback,
443+
.enable_callback = gpio_sifive_enable_callback,
444+
.disable_callback = gpio_sifive_disable_callback,
343445
};
344446

345447
/**
@@ -375,9 +477,9 @@ static int gpio_sifive_init(struct device *dev)
375477
static void gpio_sifive_cfg_0(void);
376478

377479
static const struct gpio_sifive_config gpio_sifive_config0 = {
378-
.gpio_base_addr = DT_INST_0_SIFIVE_GPIO0_BASE_ADDRESS,
379-
.gpio_irq_base = DT_INST_0_SIFIVE_GPIO0_IRQ_0,
380-
.gpio_cfg_func = gpio_sifive_cfg_0,
480+
.gpio_base_addr = DT_INST_0_SIFIVE_GPIO0_BASE_ADDRESS,
481+
.gpio_irq_base = DT_INST_0_SIFIVE_GPIO0_IRQ_0,
482+
.gpio_cfg_func = gpio_sifive_cfg_0,
381483
};
382484

383485
static struct gpio_sifive_data gpio_sifive_data0;

0 commit comments

Comments
 (0)