gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
/*
|
|
|
|
* 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
|
2017-04-20 01:45:34 +08:00
|
|
|
* block and these registers are used to control things that Zephyr normally
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
* 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
|
2017-04-20 01:45:34 +08:00
|
|
|
* readable and writable, and that for any bits that act as outputs, the value
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
* 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 <gpio/gpio_mmio32.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
static int gpio_mmio32_config(struct device *dev, int access_op,
|
2017-04-21 23:03:20 +08:00
|
|
|
u32_t pin, int flags)
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
{
|
|
|
|
struct gpio_mmio32_context *context = dev->driver_data;
|
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
|
|
|
|
|
|
|
if (access_op != GPIO_ACCESS_BY_PIN) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((config->mask & (1 << pin)) == 0) {
|
|
|
|
return -EINVAL; /* Pin not in our validity mask */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & ~(GPIO_DIR_MASK | GPIO_POL_MASK)) {
|
|
|
|
/* We ignore direction and fake polarity, rest is unsupported */
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((flags & GPIO_POL_MASK) == GPIO_POL_INV) {
|
|
|
|
context->invert |= (1 << pin);
|
|
|
|
} else {
|
|
|
|
context->invert &= ~(1 << pin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gpio_mmio32_write(struct device *dev, int access_op,
|
2017-04-21 23:03:20 +08:00
|
|
|
u32_t pin, u32_t value)
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
{
|
|
|
|
struct gpio_mmio32_context *context = dev->driver_data;
|
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2017-04-21 23:03:20 +08:00
|
|
|
volatile u32_t *reg = config->reg;
|
|
|
|
u32_t mask = config->mask;
|
|
|
|
u32_t invert = context->invert;
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
if (access_op == GPIO_ACCESS_BY_PIN) {
|
|
|
|
mask &= 1 << pin;
|
|
|
|
if (!mask) {
|
|
|
|
return -EINVAL; /* Pin not in our validity mask */
|
|
|
|
}
|
|
|
|
value = value ? mask : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
value = (value ^ invert) & mask;
|
|
|
|
|
|
|
|
/* Update pin state atomically */
|
|
|
|
key = irq_lock();
|
|
|
|
*reg = (*reg & ~mask) | value;
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gpio_mmio32_read(struct device *dev, int access_op,
|
2017-04-21 23:03:20 +08:00
|
|
|
u32_t pin, u32_t *value)
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
{
|
|
|
|
struct gpio_mmio32_context *context = dev->driver_data;
|
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2017-04-21 23:03:20 +08:00
|
|
|
u32_t bits;
|
gpio: Add gpio_mmio32 driver to access basic 32-bit i/o registers
It is envisaged that this will be used by SoC or board code to make
available fixed purpose memory-mapped i/o registers to the rest of the
system which normally expects to use GPIO devices, e.g. for driving chip
select lines, LEDs or reading button states.
As such, the driver code doesn't provide a kconfig based configuration
mechanism, instead SoC/board code can hard-wire the devices it wants
with something simple like:
GPIO_MMIO32_INIT(misc_reg1, "MISC1", 0x12345678, 0xffffffffu)
Then, for example, if bit N of the register at 0x12345678 is wired up as
an SPI device chip select line, the SPI driver could be configured to
use pin N of the "MISC1" GPIO driver and not need any other board
specific code.
Change-Id: Ib02fcbab73fcf9637e25834db060fb3108626f47
Signed-off-by: Jon Medhurst <tixy@linaro.org>
2016-12-21 00:55:41 +08:00
|
|
|
|
|
|
|
bits = (*config->reg ^ context->invert) & config->mask;
|
|
|
|
if (access_op == GPIO_ACCESS_BY_PIN) {
|
|
|
|
*value = (bits >> pin) & 1;
|
|
|
|
if ((config->mask & (1 << pin)) == 0) {
|
|
|
|
return -EINVAL; /* Pin not in our validity mask */
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*value = bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct gpio_driver_api gpio_mmio32_api = {
|
|
|
|
.config = gpio_mmio32_config,
|
|
|
|
.write = gpio_mmio32_write,
|
|
|
|
.read = gpio_mmio32_read,
|
|
|
|
};
|
|
|
|
|
|
|
|
int gpio_mmio32_init(struct device *dev)
|
|
|
|
{
|
|
|
|
struct gpio_mmio32_context *context = dev->driver_data;
|
|
|
|
const struct gpio_mmio32_config *config = dev->config->config_info;
|
|
|
|
|
|
|
|
context->config = config;
|
|
|
|
dev->driver_api = &gpio_mmio32_api;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|