Remove building with NOCRYPTO option
[minix3.git] / minix / drivers / system / gpio / gpio.c
blobe6c2928fbfa49fa22dd9cbc391ad82c0798a1fa4
1 /*
2 * GPIO driver. This driver acts as a file system to allow
3 * reading and toggling of GPIO's.
4 */
5 /* kernel headers */
6 #include <minix/driver.h>
7 #include <minix/drvlib.h>
8 #include <minix/vtreefs.h>
9 #include <minix/syslib.h>
10 #include <minix/log.h>
11 #include <minix/mmio.h>
12 #include <minix/gpio.h>
13 #include <minix/padconf.h>
14 #include <minix/type.h>
15 #include <minix/board.h>
17 /* system headers */
18 #include <sys/stat.h>
19 #include <sys/queue.h>
20 #include <sys/queue.h>
22 /* usr headers */
23 #include <assert.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <string.h>
31 /* local headers */
33 /* used for logging */
34 static struct log log = {
35 .name = "gpio",
36 .log_level = LEVEL_INFO,
37 .log_func = default_log
40 #define GPIO_CB_READ 0
41 #define GPIO_CB_INTR_READ 1
42 #define GPIO_CB_ON 2
43 #define GPIO_CB_OFF 3
45 /* The vtreefs library provides callback data when calling
46 * the read function of inode. gpio_cbdata is used here to
47 * map between inodes and gpio's. VTreeFS is read-only. to work
48 * around that issue for a single GPIO we create multiple virtual
49 * files that can be *read* to read the gpio value and power on
50 * and off the gpio.
52 struct gpio_cbdata
54 struct gpio *gpio; /* obtained from the driver */
55 int type; /* read=0/on=1/off=2 */
56 TAILQ_ENTRY(gpio_cbdata) next;
59 /* list of inodes used in this driver */
60 /* *INDENT-OFF* */
61 TAILQ_HEAD(gpio_cbdata_head, gpio_cbdata)
62 gpio_cbdata_list = TAILQ_HEAD_INITIALIZER(gpio_cbdata_list);
63 /* *INDENT-ON* */
65 /* Sane file stats for a directory */
66 static struct inode_stat default_file_stat = {
67 .mode = S_IFREG | 04,
68 .uid = 0,
69 .gid = 0,
70 .size = 0,
71 .dev = NO_DEV,
74 /* Buffer size for read requests */
75 #define DATA_SIZE 26
77 int
78 add_gpio_inode(char *name, int nr, int mode)
80 /* Create 2 files nodes for "name" "nameon" and "nameoff" to read and
81 * set values as we don't support writing yet */
82 char tmpname[200];
83 struct gpio_cbdata *cb;
84 struct gpio *gpio;
86 /* claim and configure the gpio */
87 if (gpio_claim("gpiofs", nr, &gpio)) {
88 log_warn(&log, "Failed to claim GPIO %d\n", nr);
89 return EIO;
91 assert(gpio != NULL);
93 if (gpio_pin_mode(gpio, mode)) {
94 log_warn(&log, "Failed to switch GPIO %d to mode %d\n", nr,
95 mode);
96 return EIO;
99 /* read value */
100 cb = malloc(sizeof(struct gpio_cbdata));
101 if (cb == NULL) {
102 return ENOMEM;
104 memset(cb, 0, sizeof(*cb));
106 cb->type = GPIO_CB_READ;
107 cb->gpio = gpio;
109 snprintf(tmpname, 200, "%s", name);
110 add_inode(get_root_inode(), tmpname, NO_INDEX, &default_file_stat, 0,
111 (cbdata_t) cb);
112 TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
114 if (mode == GPIO_MODE_OUTPUT) {
115 /* if we configured the GPIO pin as output mode also create
116 * two additional files to turn on and off the GPIO. */
117 /* turn on */
118 cb = malloc(sizeof(struct gpio_cbdata));
119 if (cb == NULL) {
120 return ENOMEM;
122 memset(cb, 0, sizeof(*cb));
124 cb->type = GPIO_CB_ON;
125 cb->gpio = gpio;
127 snprintf(tmpname, 200, "%sOn", name);
128 add_inode(get_root_inode(), tmpname, NO_INDEX,
129 &default_file_stat, 0, (cbdata_t) cb);
130 TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
132 /* turn off */
133 cb = malloc(sizeof(struct gpio_cbdata));
134 if (cb == NULL) {
135 return ENOMEM;
137 memset(cb, 0, sizeof(*cb));
139 cb->type = GPIO_CB_OFF;
140 cb->gpio = gpio;
142 snprintf(tmpname, 200, "%sOff", name);
143 add_inode(get_root_inode(), tmpname, NO_INDEX,
144 &default_file_stat, 0, (cbdata_t) cb);
145 TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
146 } else {
147 /* read interrupt */
148 cb = malloc(sizeof(struct gpio_cbdata));
149 if (cb == NULL) {
150 return ENOMEM;
152 memset(cb, 0, sizeof(*cb));
154 cb->type = GPIO_CB_INTR_READ;
155 cb->gpio = gpio;
157 snprintf(tmpname, 200, "%sIntr", name);
158 add_inode(get_root_inode(), tmpname, NO_INDEX,
159 &default_file_stat, 0, (cbdata_t) cb);
160 TAILQ_INSERT_HEAD(&gpio_cbdata_list, cb, next);
162 return OK;
165 static void
166 init_hook(void)
168 /* This hook will be called once, after VTreeFS has initialized. */
169 if (gpio_init()) {
170 log_warn(&log, "Failed to init gpio driver\n");
173 struct machine machine ;
174 sys_getmachine(&machine);
176 if (BOARD_IS_BBXM(machine.board_id)){
177 add_gpio_inode("USR0", 149, GPIO_MODE_OUTPUT);
178 add_gpio_inode("USR1", 150, GPIO_MODE_OUTPUT);
179 add_gpio_inode("Button", 4, GPIO_MODE_INPUT);
181 /* configure GPIO_144 to be exported */
182 sys_padconf(CONTROL_PADCONF_UART2_CTS, 0x0000ffff,
183 PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN |
184 PADCONF_INPUT_ENABLE(1));
185 sys_padconf(CONTROL_PADCONF_MMC2_DAT6, 0xffff0000,
186 (PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN |
187 PADCONF_INPUT_ENABLE(1)) << 16);
189 /* Added for demo purposes */
190 add_gpio_inode("BigRedButton", 144, GPIO_MODE_INPUT);
191 add_gpio_inode("BigRedButtonLed", 139, GPIO_MODE_OUTPUT);
192 } else if ( BOARD_IS_BB(machine.board_id)){
194 /* Export GPIO3_19 (P9-27 on BBB) output as LCD_EN */
196 sys_padconf(CONTROL_CONF_MCASP0_FSR, 0xffffffff,
197 (CONTROL_CONF_PUTYPESEL | CONTROL_CONF_MUXMODE(7)));
199 add_gpio_inode("LCD_EN", (32 * 3) + 19, GPIO_MODE_OUTPUT);
201 /* Export GPIO1_17 (P9-23 on BBB) input as RIGHT */
203 /* assumes external pull-up resistor (10K) */
204 sys_padconf(CONTROL_CONF_SPI0_D0, 0xffffffff, (CONTROL_CONF_RXACTIVE |
205 CONTROL_CONF_PUDEN | CONTROL_CONF_MUXMODE(7)));
207 add_gpio_inode("RIGHT", (32 * 1) + 17, GPIO_MODE_INPUT);
212 static ssize_t
213 read_hook
214 (struct inode *inode, char *ptr, size_t len, off_t offset, cbdata_t cbdata)
216 /* This hook will be called every time a regular file is read. We use
217 * it to dyanmically generate the contents of our file. */
218 int value;
219 struct gpio_cbdata *gpio_cbdata = (struct gpio_cbdata *) cbdata;
220 assert(gpio_cbdata->gpio != NULL);
222 if (gpio_cbdata->type == GPIO_CB_ON
223 || gpio_cbdata->type == GPIO_CB_OFF) {
224 /* turn on or off */
225 if (gpio_set(gpio_cbdata->gpio,
226 (gpio_cbdata->type == GPIO_CB_ON) ? 1 : 0))
227 return EIO;
228 return 0;
231 if (gpio_cbdata->type == GPIO_CB_INTR_READ) {
232 /* reading interrupt */
233 if (gpio_intr_read(gpio_cbdata->gpio, &value))
234 return EIO;
235 } else {
236 /* reading */
237 if (gpio_read(gpio_cbdata->gpio, &value))
238 return EIO;
240 snprintf(ptr, DATA_SIZE, "%d\n", value);
241 len = strlen(ptr);
243 /* If the offset is at or beyond the end of the string, return EOF. */
244 if (offset >= len)
245 return 0;
247 /* Otherwise, we may have to move the data to the start of ptr. */
248 if (offset > 0) {
249 len -= offset;
251 memmove(ptr, &ptr[offset], len);
254 /* Return the resulting length. */
255 return len;
258 static void
259 message_hook(message * m, int __unused ipc_status)
261 gpio_intr_message(m);
265 main(int argc, char **argv)
268 struct fs_hooks hooks;
269 struct inode_stat root_stat;
271 /* Set and apply the environment */
272 env_setargs(argc, argv);
274 /* fill in the hooks */
275 memset(&hooks, 0, sizeof(hooks));
276 hooks.init_hook = init_hook;
277 hooks.read_hook = read_hook;
278 hooks.message_hook = message_hook;
280 root_stat.mode = S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH;
281 root_stat.uid = 0;
282 root_stat.gid = 0;
283 root_stat.size = 0;
284 root_stat.dev = NO_DEV;
286 /* run VTreeFS */
287 run_vtreefs(&hooks, 30, 0, &root_stat, 0, DATA_SIZE);
289 return EXIT_SUCCESS;