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:
parent
5b939ea731
commit
bc30598456
8 changed files with 249 additions and 0 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -115,4 +115,6 @@ source "drivers/disk/Kconfig"
|
||||||
|
|
||||||
source "drivers/cache/Kconfig"
|
source "drivers/cache/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/syscon/Kconfig"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
3
drivers/syscon/CMakeLists.txt
Normal file
3
drivers/syscon/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(CONFIG_SYSCON syscon.c)
|
43
drivers/syscon/Kconfig
Normal file
43
drivers/syscon/Kconfig
Normal 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
117
drivers/syscon/syscon.c
Normal 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(®, 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(®, 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);
|
12
dts/bindings/syscon/syscon.yaml
Normal file
12
dts/bindings/syscon/syscon.yaml
Normal 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
70
include/drivers/syscon.h
Normal 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_ */
|
Loading…
Add table
Add a link
Reference in a new issue