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-20 17:55:41 +01: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-19 19:45:34 +02: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-20 17:55:41 +01: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-19 19:45:34 +02: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-20 17:55:41 +01: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.
|
|
|
|
*/
|
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/gpio/gpio_mmio32.h>
|
2022-10-04 15:33:53 +02:00
|
|
|
#include <zephyr/irq.h>
|
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-20 17:55:41 +01:00
|
|
|
#include <errno.h>
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_config(const struct device *dev,
|
2020-01-30 19:12:39 +01:00
|
|
|
gpio_pin_t pin, gpio_flags_t 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-20 17:55:41 +01:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
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-20 17:55:41 +01:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
|
|
|
|
|
|
|
if ((config->mask & (1 << pin)) == 0) {
|
|
|
|
return -EINVAL; /* Pin not in our validity mask */
|
|
|
|
}
|
|
|
|
|
2019-10-03 04:19:41 +02:00
|
|
|
if (flags & ~(GPIO_INPUT | GPIO_OUTPUT |
|
|
|
|
GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH |
|
|
|
|
GPIO_ACTIVE_LOW)) {
|
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-20 17:55:41 +01:00
|
|
|
/* We ignore direction and fake polarity, rest is unsupported */
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2019-10-03 04:19:41 +02:00
|
|
|
if ((flags & GPIO_OUTPUT) != 0) {
|
|
|
|
unsigned int key;
|
2020-05-27 18:26:57 +02:00
|
|
|
volatile uint32_t *reg = config->reg;
|
2019-10-03 04:19:41 +02:00
|
|
|
|
|
|
|
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);
|
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-20 17:55:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_port_get_raw(const struct device *dev, uint32_t *value)
|
2019-10-03 04:19:41 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2019-10-03 04:19:41 +02:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
|
|
|
|
|
|
|
*value = *config->reg & config->mask;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_port_set_masked_raw(const struct device *dev,
|
|
|
|
uint32_t mask,
|
|
|
|
uint32_t value)
|
2019-10-03 04:19:41 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2019-10-03 04:19:41 +02:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2020-05-27 18:26:57 +02:00
|
|
|
volatile uint32_t *reg = config->reg;
|
2019-10-03 04:19:41 +02:00
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
mask &= config->mask;
|
|
|
|
value &= mask;
|
|
|
|
|
|
|
|
/* Update pin state atomically */
|
|
|
|
key = irq_lock();
|
|
|
|
*reg = (*reg & ~mask) | value;
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_port_set_bits_raw(const struct device *dev,
|
|
|
|
uint32_t mask)
|
2019-10-03 04:19:41 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2019-10-03 04:19:41 +02:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2020-05-27 18:26:57 +02:00
|
|
|
volatile uint32_t *reg = config->reg;
|
2019-10-03 04:19:41 +02:00
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
mask &= config->mask;
|
|
|
|
|
|
|
|
/* Update pin state atomically */
|
|
|
|
key = irq_lock();
|
|
|
|
*reg = (*reg | mask);
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_port_clear_bits_raw(const struct device *dev,
|
|
|
|
uint32_t mask)
|
2019-10-03 04:19:41 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2019-10-03 04:19:41 +02:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2020-05-27 18:26:57 +02:00
|
|
|
volatile uint32_t *reg = config->reg;
|
2019-10-03 04:19:41 +02:00
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
mask &= config->mask;
|
|
|
|
|
|
|
|
/* Update pin state atomically */
|
|
|
|
key = irq_lock();
|
|
|
|
*reg = (*reg & ~mask);
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int gpio_mmio32_port_toggle_bits(const struct device *dev,
|
|
|
|
uint32_t mask)
|
2019-10-03 04:19:41 +02:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2019-10-03 04:19:41 +02:00
|
|
|
const struct gpio_mmio32_config *config = context->config;
|
2020-05-27 18:26:57 +02:00
|
|
|
volatile uint32_t *reg = config->reg;
|
2019-10-03 04:19:41 +02:00
|
|
|
unsigned int key;
|
|
|
|
|
|
|
|
mask &= config->mask;
|
|
|
|
|
|
|
|
/* Update pin state atomically */
|
|
|
|
key = irq_lock();
|
|
|
|
*reg = (*reg ^ mask);
|
|
|
|
irq_unlock(key);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-30 21:01:27 +02:00
|
|
|
const struct gpio_driver_api gpio_mmio32_api = {
|
2020-01-30 19:12:39 +01:00
|
|
|
.pin_configure = gpio_mmio32_config,
|
2019-10-03 04:19:41 +02:00
|
|
|
.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,
|
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-20 17:55:41 +01:00
|
|
|
};
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
int gpio_mmio32_init(const struct device *dev)
|
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-20 17:55:41 +01:00
|
|
|
{
|
2020-05-28 21:23:02 +02:00
|
|
|
struct gpio_mmio32_context *context = dev->data;
|
2020-05-28 20:44:16 +02:00
|
|
|
const struct gpio_mmio32_config *config = dev->config;
|
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-20 17:55:41 +01:00
|
|
|
|
|
|
|
context->config = config;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|