1 /*
2 * Copyright (c) 2016 Linaro Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Driver to provide the GPIO API for a simple 32-bit i/o register
10 *
11 * This is a driver for accessing a simple, fixed purpose, 32-bit
12 * memory-mapped i/o register using the same APIs as GPIO drivers. This is
13 * useful when an SoC or board has registers that aren't part of a GPIO IP
14 * block and these registers are used to control things that Zephyr normally
15 * expects to be specified using a GPIO pin, e.g. for driving an LED, or
16 * chip-select line for an SPI device.
17 *
18 * The implementation expects that all bits of the hardware register are both
19 * readable and writable, and that for any bits that act as outputs, the value
20 * read will have the value that was last written to it. This requirement
21 * stems from the use of a read-modify-write method for all changes.
22 *
23 * It is possible to specify a restricted mask of bits that are valid for
24 * access, and whenever the register is written, the value of bits outside this
25 * mask will be preserved, even when the whole port is written to using
26 * gpio_port_write.
27 */
28
29 #include <zephyr/drivers/gpio/gpio_mmio32.h>
30 #include <zephyr/irq.h>
31 #include <errno.h>
32
gpio_mmio32_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)33 static int gpio_mmio32_config(const struct device *dev,
34 gpio_pin_t pin, gpio_flags_t flags)
35 {
36 struct gpio_mmio32_context *context = dev->data;
37 const struct gpio_mmio32_config *config = context->config;
38
39 if ((config->mask & (1 << pin)) == 0) {
40 return -EINVAL; /* Pin not in our validity mask */
41 }
42
43 if (flags & ~(GPIO_INPUT | GPIO_OUTPUT |
44 GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH |
45 GPIO_ACTIVE_LOW)) {
46 /* We ignore direction and fake polarity, rest is unsupported */
47 return -ENOTSUP;
48 }
49
50 if ((flags & GPIO_OUTPUT) != 0) {
51 unsigned int key;
52 volatile uint32_t *reg = config->reg;
53
54 key = irq_lock();
55 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
56 *reg = (*reg | (1 << pin));
57 } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
58 *reg = (*reg & (config->mask & ~(1 << pin)));
59 }
60 irq_unlock(key);
61 }
62
63 return 0;
64 }
65
gpio_mmio32_port_get_raw(const struct device * dev,uint32_t * value)66 static int gpio_mmio32_port_get_raw(const struct device *dev, uint32_t *value)
67 {
68 struct gpio_mmio32_context *context = dev->data;
69 const struct gpio_mmio32_config *config = context->config;
70
71 *value = *config->reg & config->mask;
72
73 return 0;
74 }
75
gpio_mmio32_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)76 static int gpio_mmio32_port_set_masked_raw(const struct device *dev,
77 uint32_t mask,
78 uint32_t value)
79 {
80 struct gpio_mmio32_context *context = dev->data;
81 const struct gpio_mmio32_config *config = context->config;
82 volatile uint32_t *reg = config->reg;
83 unsigned int key;
84
85 mask &= config->mask;
86 value &= mask;
87
88 /* Update pin state atomically */
89 key = irq_lock();
90 *reg = (*reg & ~mask) | value;
91 irq_unlock(key);
92
93 return 0;
94 }
95
gpio_mmio32_port_set_bits_raw(const struct device * dev,uint32_t mask)96 static int gpio_mmio32_port_set_bits_raw(const struct device *dev,
97 uint32_t mask)
98 {
99 struct gpio_mmio32_context *context = dev->data;
100 const struct gpio_mmio32_config *config = context->config;
101 volatile uint32_t *reg = config->reg;
102 unsigned int key;
103
104 mask &= config->mask;
105
106 /* Update pin state atomically */
107 key = irq_lock();
108 *reg = (*reg | mask);
109 irq_unlock(key);
110
111 return 0;
112 }
113
gpio_mmio32_port_clear_bits_raw(const struct device * dev,uint32_t mask)114 static int gpio_mmio32_port_clear_bits_raw(const struct device *dev,
115 uint32_t mask)
116 {
117 struct gpio_mmio32_context *context = dev->data;
118 const struct gpio_mmio32_config *config = context->config;
119 volatile uint32_t *reg = config->reg;
120 unsigned int key;
121
122 mask &= config->mask;
123
124 /* Update pin state atomically */
125 key = irq_lock();
126 *reg = (*reg & ~mask);
127 irq_unlock(key);
128
129 return 0;
130 }
131
gpio_mmio32_port_toggle_bits(const struct device * dev,uint32_t mask)132 static int gpio_mmio32_port_toggle_bits(const struct device *dev,
133 uint32_t mask)
134 {
135 struct gpio_mmio32_context *context = dev->data;
136 const struct gpio_mmio32_config *config = context->config;
137 volatile uint32_t *reg = config->reg;
138 unsigned int key;
139
140 mask &= config->mask;
141
142 /* Update pin state atomically */
143 key = irq_lock();
144 *reg = (*reg ^ mask);
145 irq_unlock(key);
146
147 return 0;
148 }
149
150 const struct gpio_driver_api gpio_mmio32_api = {
151 .pin_configure = gpio_mmio32_config,
152 .port_get_raw = gpio_mmio32_port_get_raw,
153 .port_set_masked_raw = gpio_mmio32_port_set_masked_raw,
154 .port_set_bits_raw = gpio_mmio32_port_set_bits_raw,
155 .port_clear_bits_raw = gpio_mmio32_port_clear_bits_raw,
156 .port_toggle_bits = gpio_mmio32_port_toggle_bits,
157 };
158
gpio_mmio32_init(const struct device * dev)159 int gpio_mmio32_init(const struct device *dev)
160 {
161 struct gpio_mmio32_context *context = dev->data;
162 const struct gpio_mmio32_config *config = dev->config;
163
164 context->config = config;
165
166 return 0;
167 }
168