You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.3 KiB
132 lines
3.3 KiB
/* |
|
* Copyright (c) Carlo Caione <ccaione@baylibre.com> |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT syscon |
|
|
|
#include <errno.h> |
|
|
|
#include <zephyr/arch/cpu.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/device.h> |
|
#include <zephyr/init.h> |
|
|
|
#include <zephyr/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) |
|
{ |
|
*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 = dev->config; |
|
struct syscon_generic_data *data = dev->data; |
|
uintptr_t base_address; |
|
|
|
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 = dev->config; |
|
struct syscon_generic_data *data = dev->data; |
|
uintptr_t base_address; |
|
|
|
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 DEVICE_API(syscon, 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_INST_REG_SIZE(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);
|
|
|