148 lines
3.3 KiB
C
148 lines
3.3 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>
|
|
|
|
#include "syscon_common.h"
|
|
|
|
struct syscon_generic_config {
|
|
DEVICE_MMIO_ROM;
|
|
uint8_t reg_width;
|
|
};
|
|
|
|
struct syscon_generic_data {
|
|
DEVICE_MMIO_RAM;
|
|
size_t size;
|
|
};
|
|
|
|
static int syscon_generic_get_base(const struct device *dev, uintptr_t *addr)
|
|
{
|
|
if (!dev) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
*addr = DEVICE_MMIO_GET(dev);
|
|
return 0;
|
|
}
|
|
|
|
static int syscon_generic_read_reg(const struct device *dev, uint16_t reg, uint32_t *val)
|
|
{
|
|
const struct syscon_generic_config *config;
|
|
struct syscon_generic_data *data;
|
|
uintptr_t base_address;
|
|
|
|
if (!dev) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
data = dev->data;
|
|
config = dev->config;
|
|
|
|
if (!val) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (syscon_sanitize_reg(®, data->size, config->reg_width)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
base_address = DEVICE_MMIO_GET(dev);
|
|
|
|
switch (config->reg_width) {
|
|
case 1:
|
|
*val = sys_read8(base_address + reg);
|
|
break;
|
|
case 2:
|
|
*val = sys_read16(base_address + reg);
|
|
break;
|
|
case 4:
|
|
*val = sys_read32(base_address + reg);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int syscon_generic_write_reg(const struct device *dev, uint16_t reg, uint32_t val)
|
|
{
|
|
const struct syscon_generic_config *config;
|
|
struct syscon_generic_data *data;
|
|
uintptr_t base_address;
|
|
|
|
if (!dev) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
data = dev->data;
|
|
config = dev->config;
|
|
|
|
if (syscon_sanitize_reg(®, data->size, config->reg_width)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
base_address = DEVICE_MMIO_GET(dev);
|
|
|
|
switch (config->reg_width) {
|
|
case 1:
|
|
sys_write8(val, (base_address + reg));
|
|
break;
|
|
case 2:
|
|
sys_write16(val, (base_address + reg));
|
|
break;
|
|
case 4:
|
|
sys_write32(val, (base_address + reg));
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int syscon_generic_get_size(const struct device *dev, size_t *size)
|
|
{
|
|
struct syscon_generic_data *data = dev->data;
|
|
|
|
*size = data->size;
|
|
return 0;
|
|
}
|
|
|
|
static const struct syscon_driver_api syscon_generic_driver_api = {
|
|
.read = syscon_generic_read_reg,
|
|
.write = syscon_generic_write_reg,
|
|
.get_base = syscon_generic_get_base,
|
|
.get_size = syscon_generic_get_size,
|
|
};
|
|
|
|
static int syscon_generic_init(const struct device *dev)
|
|
{
|
|
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define SYSCON_INIT(inst) \
|
|
static const struct syscon_generic_config syscon_generic_config_##inst = { \
|
|
DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \
|
|
.reg_width = DT_INST_PROP_OR(inst, reg_io_width, 4), \
|
|
}; \
|
|
static struct syscon_generic_data syscon_generic_data_##inst = { \
|
|
.size = DT_REG_SIZE(DT_DRV_INST(inst)), \
|
|
}; \
|
|
DEVICE_DT_INST_DEFINE(inst, syscon_generic_init, NULL, &syscon_generic_data_##inst, \
|
|
&syscon_generic_config_##inst, PRE_KERNEL_1, \
|
|
CONFIG_SYSCON_INIT_PRIORITY, &syscon_generic_driver_api);
|
|
|
|
DT_INST_FOREACH_STATUS_OKAY(SYSCON_INIT);
|