/
gpio_sam0.c
158 lines (126 loc) · 3.45 KB
/
gpio_sam0.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
151
152
153
154
155
156
157
158
/*
* Copyright (c) 2017 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <device.h>
#include <gpio.h>
#include <soc.h>
struct gpio_sam0_config {
PortGroup *regs;
};
#define DEV_CFG(dev) \
((const struct gpio_sam0_config *const)(dev)->config->config_info)
static int gpio_sam0_config(struct device *dev, int access_op, u32_t pin,
int flags)
{
const struct gpio_sam0_config *config = DEV_CFG(dev);
PortGroup *regs = config->regs;
u32_t mask = 1 << pin;
bool is_out = (flags & GPIO_DIR_MASK) == GPIO_DIR_OUT;
int pud = flags & GPIO_PUD_MASK;
PORT_PINCFG_Type pincfg;
if (access_op != GPIO_ACCESS_BY_PIN) {
return -ENOTSUP;
}
/* Builds the configuration and writes it in one go */
pincfg.reg = 0;
pincfg.bit.INEN = 1;
/* Direction */
if (is_out) {
regs->DIRSET.bit.DIRSET = mask;
} else {
regs->DIRCLR.bit.DIRCLR = mask;
}
/* Pull up / pull down */
if (is_out && pud != GPIO_PUD_NORMAL) {
return -ENOTSUP;
}
switch (pud) {
case GPIO_PUD_NORMAL:
break;
case GPIO_PUD_PULL_UP:
pincfg.bit.PULLEN = 1;
regs->OUTSET.reg = mask;
break;
case GPIO_PUD_PULL_DOWN:
pincfg.bit.PULLEN = 1;
regs->OUTCLR.reg = mask;
break;
default:
return -ENOTSUP;
}
/* Write the now-built pin configuration */
regs->PINCFG[pin] = pincfg;
if ((flags & GPIO_INT) != 0) {
/* TODO(mlhx): implement. */
return -ENOTSUP;
}
if ((flags & GPIO_POL_MASK) != GPIO_POL_NORMAL) {
return -ENOTSUP;
}
return 0;
}
static int gpio_sam0_write(struct device *dev, int access_op, u32_t pin,
u32_t value)
{
const struct gpio_sam0_config *config = DEV_CFG(dev);
u32_t mask = 1 << pin;
if (access_op != GPIO_ACCESS_BY_PIN) {
/* TODO(mlhx): support GPIO_ACCESS_BY_PORT */
return -ENOTSUP;
}
if (value != 0U) {
config->regs->OUTSET.bit.OUTSET = mask;
} else {
config->regs->OUTCLR.bit.OUTCLR = mask;
}
return 0;
}
static int gpio_sam0_read(struct device *dev, int access_op, u32_t pin,
u32_t *value)
{
const struct gpio_sam0_config *config = DEV_CFG(dev);
u32_t bits;
if (access_op != GPIO_ACCESS_BY_PIN) {
/* TODO(mlhx): support GPIO_ACCESS_BY_PORT */
return -ENOTSUP;
}
bits = config->regs->IN.bit.IN;
*value = (bits >> pin) & 1;
return 0;
}
static const struct gpio_driver_api gpio_sam0_api = {
.config = gpio_sam0_config,
.write = gpio_sam0_write,
.read = gpio_sam0_read,
};
static int gpio_sam0_init(struct device *dev) { return 0; }
/* Port A */
#ifdef DT_GPIO_SAM0_PORTA_BASE_ADDRESS
static const struct gpio_sam0_config gpio_sam0_config_0 = {
.regs = (PortGroup *)DT_GPIO_SAM0_PORTA_BASE_ADDRESS,
};
DEVICE_AND_API_INIT(gpio_sam0_0, DT_GPIO_SAM0_PORTA_LABEL, gpio_sam0_init,
NULL, &gpio_sam0_config_0, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_sam0_api);
#endif
/* Port B */
#ifdef DT_GPIO_SAM0_PORTB_BASE_ADDRESS
static const struct gpio_sam0_config gpio_sam0_config_1 = {
.regs = (PortGroup *)DT_GPIO_SAM0_PORTB_BASE_ADDRESS,
};
DEVICE_AND_API_INIT(gpio_sam0_1, DT_GPIO_SAM0_PORTB_LABEL, gpio_sam0_init,
NULL, &gpio_sam0_config_1, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_sam0_api);
#endif
/* Port C */
#ifdef DT_GPIO_SAM0_PORTC_BASE_ADDRESS
static const struct gpio_sam0_config gpio_sam0_config_2 = {
.regs = (PortGroup *)DT_GPIO_SAM0_PORTC_BASE_ADDRESS,
};
DEVICE_AND_API_INIT(gpio_sam0_2, DT_GPIO_SAM0_PORTC_LABEL, gpio_sam0_init,
NULL, &gpio_sam0_config_2, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_sam0_api);
#endif