Loading...
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 | /*
* Copyright (c) 2016 Linaro Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Driver to provide the GPIO API for a simple 32-bit i/o register
*
* This is a driver for accessing a simple, fixed purpose, 32-bit
* memory-mapped i/o register using the same APIs as GPIO drivers. This is
* useful when an SoC or board has registers that aren't part of a GPIO IP
* block and these registers are used to control things that Zephyr normally
* expects to be specified using a GPIO pin, e.g. for driving an LED, or
* chip-select line for an SPI device.
*
* The implementation expects that all bits of the hardware register are both
* readable and writable, and that for any bits that act as outputs, the value
* read will have the value that was last written to it. This requirement
* stems from the use of a read-modify-write method for all changes.
*
* It is possible to specify a restricted mask of bits that are valid for
* access, and whenever the register is written, the value of bits outside this
* mask will be preserved, even when the whole port is written to using
* gpio_port_write.
*/
#include <drivers/gpio/gpio_mmio32.h>
#include <errno.h>
static int gpio_mmio32_config(const struct device *dev,
gpio_pin_t pin, gpio_flags_t flags)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
if ((config->mask & (1 << pin)) == 0) {
return -EINVAL; /* Pin not in our validity mask */
}
if (flags & ~(GPIO_INPUT | GPIO_OUTPUT |
GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH |
GPIO_ACTIVE_LOW)) {
/* We ignore direction and fake polarity, rest is unsupported */
return -ENOTSUP;
}
if ((flags & GPIO_OUTPUT) != 0) {
unsigned int key;
volatile uint32_t *reg = config->reg;
key = irq_lock();
if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
*reg = (*reg | (1 << pin));
} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
*reg = (*reg & (config->mask & ~(1 << pin)));
}
irq_unlock(key);
}
return 0;
}
static int gpio_mmio32_port_get_raw(const struct device *dev, uint32_t *value)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
*value = *config->reg & config->mask;
return 0;
}
static int gpio_mmio32_port_set_masked_raw(const struct device *dev,
uint32_t mask,
uint32_t value)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
volatile uint32_t *reg = config->reg;
unsigned int key;
mask &= config->mask;
value &= mask;
/* Update pin state atomically */
key = irq_lock();
*reg = (*reg & ~mask) | value;
irq_unlock(key);
return 0;
}
static int gpio_mmio32_port_set_bits_raw(const struct device *dev,
uint32_t mask)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
volatile uint32_t *reg = config->reg;
unsigned int key;
mask &= config->mask;
/* Update pin state atomically */
key = irq_lock();
*reg = (*reg | mask);
irq_unlock(key);
return 0;
}
static int gpio_mmio32_port_clear_bits_raw(const struct device *dev,
uint32_t mask)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
volatile uint32_t *reg = config->reg;
unsigned int key;
mask &= config->mask;
/* Update pin state atomically */
key = irq_lock();
*reg = (*reg & ~mask);
irq_unlock(key);
return 0;
}
static int gpio_mmio32_port_toggle_bits(const struct device *dev,
uint32_t mask)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = context->config;
volatile uint32_t *reg = config->reg;
unsigned int key;
mask &= config->mask;
/* Update pin state atomically */
key = irq_lock();
*reg = (*reg ^ mask);
irq_unlock(key);
return 0;
}
static int gpio_mmio32_pin_interrupt_configure(const struct device *dev,
gpio_pin_t pin,
enum gpio_int_mode mode,
enum gpio_int_trig trig)
{
if (mode != GPIO_INT_MODE_DISABLED) {
return -ENOTSUP;
}
return 0;
}
const struct gpio_driver_api gpio_mmio32_api = {
.pin_configure = gpio_mmio32_config,
.port_get_raw = gpio_mmio32_port_get_raw,
.port_set_masked_raw = gpio_mmio32_port_set_masked_raw,
.port_set_bits_raw = gpio_mmio32_port_set_bits_raw,
.port_clear_bits_raw = gpio_mmio32_port_clear_bits_raw,
.port_toggle_bits = gpio_mmio32_port_toggle_bits,
.pin_interrupt_configure = gpio_mmio32_pin_interrupt_configure,
};
int gpio_mmio32_init(const struct device *dev)
{
struct gpio_mmio32_context *context = dev->data;
const struct gpio_mmio32_config *config = dev->config;
context->config = config;
return 0;
}
|