118 lines
2 KiB
C
118 lines
2 KiB
C
|
/*
|
||
|
* 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);
|