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/bluetooth/ @joerchan @jhedberg @Vudentz
|
||||
/drivers/cache/ @carlocaione
|
||||
/drivers/syscon/ @carlocaione
|
||||
/drivers/can/ @alexanderwachter
|
||||
/drivers/can/*mcp2515* @karstenkoenig
|
||||
/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_EDAC edac)
|
||||
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/syscon/Kconfig"
|
||||
|
||||
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