forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsyscon.c
150 lines (119 loc) · 3.41 KB
/
syscon.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Copyright (c) Carlo Caione <[email protected]>
*
* 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)
{
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_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);