drivers: syscon: Add generic syscon API

A syscon device is a device managing a memory region containing a set of
registers that are not cohesive enough to represent as any specific type
of device. We need a driver for that because several other drivers could
use the same region at the same time and we need to io-map the region at
boot for MMU enabled platforms.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2021-06-03 11:03:48 +02:00 committed by Christopher Friedt
commit bc30598456
8 changed files with 249 additions and 0 deletions

View file

@ -186,6 +186,7 @@
/drivers/adc/adc_stm32.c @cybertale /drivers/adc/adc_stm32.c @cybertale
/drivers/bluetooth/ @joerchan @jhedberg @Vudentz /drivers/bluetooth/ @joerchan @jhedberg @Vudentz
/drivers/cache/ @carlocaione /drivers/cache/ @carlocaione
/drivers/syscon/ @carlocaione
/drivers/can/ @alexanderwachter /drivers/can/ @alexanderwachter
/drivers/can/*mcp2515* @karstenkoenig /drivers/can/*mcp2515* @karstenkoenig
/drivers/can/*rcar* @julien-massot /drivers/can/*rcar* @julien-massot

View file

@ -57,3 +57,4 @@ add_subdirectory_ifdef(CONFIG_NEURAL_NET_ACCEL neural_net)
add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock) add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock)
add_subdirectory_ifdef(CONFIG_EDAC edac) add_subdirectory_ifdef(CONFIG_EDAC edac)
add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache) add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache)
add_subdirectory_ifdef(CONFIG_SYSCON syscon)

View file

@ -115,4 +115,6 @@ source "drivers/disk/Kconfig"
source "drivers/cache/Kconfig" source "drivers/cache/Kconfig"
source "drivers/syscon/Kconfig"
endmenu endmenu

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_SYSCON syscon.c)

43
drivers/syscon/Kconfig Normal file
View file

@ -0,0 +1,43 @@
# SYSCON configuration options
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
# SPDX-License-Identifier: Apache-2.0
#
# SYSCON options
#
menuconfig SYSCON
bool "SYSCON (System Controller) drivers"
help
SYSCON (System Controller) drivers. System controller node represents
a register region containing a set of miscellaneous registers. The
registers are not cohesive enough to represent as any specific type
of device. The typical use-case is for some other node's driver, or
platform-specific code, to acquire a reference to the syscon node and
extract information from there.
if SYSCON
module = SYSCON
module-str = syscon
source "subsys/logging/Kconfig.template.log_config"
DT_COMPAT_SYSCON := syscon
config SYSCON_GENERIC
bool "Generic SYSCON (System Controller) driver"
default $(dt_compat_enabled,$(DT_COMPAT_SYSCON))
help
Enable generic SYSCON (System Controller) driver
config SYSCON_GENERIC_INIT_PRIORITY_DEVICE
int "SYSCON (System Controller) generic init device priority"
default 50
depends on SYSCON_GENERIC
help
This option controls the priority of the syscon device
initialization. Higher priority ensures that the device is
initialized earlier in the startup cycle. If unsure, leave at default
value
endif # SYSCON

117
drivers/syscon/syscon.c Normal file
View file

@ -0,0 +1,117 @@
/*
* Copyright (c) Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT syscon
#include <sys/util.h>
#include <device.h>
#include <init.h>
#include <drivers/syscon.h>
static const struct device *syscon_dev;
struct syscon_generic_config {
DEVICE_MMIO_ROM;
};
static struct syscon_generic_config syscon_generic_config_0 = {
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(0)),
};
struct syscon_generic_data {
DEVICE_MMIO_RAM;
size_t size;
};
static struct syscon_generic_data syscon_generic_data_0;
uintptr_t syscon_generic_get_base(void)
{
if (!syscon_dev) {
return -ENODEV;
}
return DEVICE_MMIO_GET(syscon_dev);
}
static int sanitize_reg(uint16_t *reg, size_t reg_size)
{
/* Avoid unaligned readings */
*reg = ROUND_DOWN(*reg, sizeof(uint32_t));
/* Check for out-of-bounds readings */
if (*reg >= reg_size) {
return -EINVAL;
}
return 0;
}
int syscon_generic_read_reg(uint16_t reg, uint32_t *val)
{
struct syscon_generic_data *data;
uintptr_t base_address;
if (!syscon_dev) {
return -ENODEV;
}
data = syscon_dev->data;
if (!val) {
return -EINVAL;
}
if (sanitize_reg(&reg, data->size)) {
return -EINVAL;
}
base_address = DEVICE_MMIO_GET(syscon_dev);
*val = sys_read32(base_address + reg);
return 0;
}
int syscon_generic_write_reg(uint16_t reg, uint32_t val)
{
struct syscon_generic_data *data;
uintptr_t base_address;
if (!syscon_dev) {
return -ENODEV;
}
data = syscon_dev->data;
if (sanitize_reg(&reg, data->size)) {
return -EINVAL;
}
base_address = DEVICE_MMIO_GET(syscon_dev);
sys_write32(val, (base_address + reg));
return 0;
}
int syscon_generic_init(const struct device *dev)
{
struct syscon_generic_data *data = dev->data;
syscon_dev = dev;
DEVICE_MMIO_MAP(syscon_dev, K_MEM_CACHE_NONE);
data->size = DT_REG_SIZE(DT_DRV_INST(0));
return 0;
}
DEVICE_DT_INST_DEFINE(0, syscon_generic_init, NULL, &syscon_generic_data_0,
&syscon_generic_config_0, PRE_KERNEL_1,
CONFIG_SYSCON_GENERIC_INIT_PRIORITY_DEVICE, NULL);

View file

@ -0,0 +1,12 @@
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
# SPDX-License-Identifier: Apache-2.0
description: System Controller Registers R/W
compatible: "syscon"
include: base.yaml
properties:
reg:
required: true

70
include/drivers/syscon.h Normal file
View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Public SYSCON driver APIs
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_
#define ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_
/**
* @brief SYSCON Interface
* @defgroup syscon_interface SYSCON Interface
* @ingroup io_interfaces
* @{
*/
#include <zephyr/types.h>
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the syscon base address
*
* This function returns the syscon base address
*
* @return 0 on error, the base address on success
*/
uintptr_t syscon_get_base(void);
/**
* @brief Read from syscon register
*
* This function reads from a specific register in the syscon area
*
* @param reg The register offset
* @param val The returned value read from the syscon register
*
* @return 0 on success, negative on error
*/
int syscon_read_reg(uint16_t reg, uint32_t *val);
/**
* @brief Write to syscon register
*
* This function writes to a specific register in the syscon area
*
* @param reg The register offset
* @param val The value to be written in the register
*
* @return 0 on success, negative on error
*/
int syscon_write_reg(uint16_t reg, uint32_t val);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_DRIVERS_SYSCON_H_ */