2 * GPIO driver. This driver acts as a file system to allow
3 * reading and toggling of GPIO's.
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>
19 #include <sys/queue.h>
20 #include <sys/queue.h>
33 /* used for logging */
34 static struct log log
= {
36 .log_level
= LEVEL_INFO
,
37 .log_func
= default_log
40 #define GPIO_CB_READ 0
41 #define GPIO_CB_INTR_READ 1
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
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 */
61 TAILQ_HEAD(gpio_cbdata_head
, gpio_cbdata
)
62 gpio_cbdata_list
= TAILQ_HEAD_INITIALIZER(gpio_cbdata_list
);
65 /* Sane file stats for a directory */
66 static struct inode_stat default_file_stat
= {
75 add_gpio_inode(char *name
, int nr
, int mode
)
77 /* Create 2 files nodes for "name" "nameon" and "nameoff" to read and
78 * set values as we don't support writing yet */
80 struct gpio_cbdata
*cb
;
83 /* claim and configure the gpio */
84 if (gpio_claim("gpiofs", nr
, &gpio
)) {
85 log_warn(&log
, "Failed to claim GPIO %d\n", nr
);
90 if (gpio_pin_mode(gpio
, mode
)) {
91 log_warn(&log
, "Failed to switch GPIO %d to mode %d\n", nr
,
97 cb
= malloc(sizeof(struct gpio_cbdata
));
101 memset(cb
, 0, sizeof(*cb
));
103 cb
->type
= GPIO_CB_READ
;
106 snprintf(tmpname
, 200, "%s", name
);
107 add_inode(get_root_inode(), tmpname
, NO_INDEX
, &default_file_stat
, 0,
109 TAILQ_INSERT_HEAD(&gpio_cbdata_list
, cb
, next
);
111 if (mode
== GPIO_MODE_OUTPUT
) {
112 /* if we configured the GPIO pin as output mode also create
113 * two additional files to turn on and off the GPIO. */
115 cb
= malloc(sizeof(struct gpio_cbdata
));
119 memset(cb
, 0, sizeof(*cb
));
121 cb
->type
= GPIO_CB_ON
;
124 snprintf(tmpname
, 200, "%sOn", name
);
125 add_inode(get_root_inode(), tmpname
, NO_INDEX
,
126 &default_file_stat
, 0, (cbdata_t
) cb
);
127 TAILQ_INSERT_HEAD(&gpio_cbdata_list
, cb
, next
);
130 cb
= malloc(sizeof(struct gpio_cbdata
));
134 memset(cb
, 0, sizeof(*cb
));
136 cb
->type
= GPIO_CB_OFF
;
139 snprintf(tmpname
, 200, "%sOff", name
);
140 add_inode(get_root_inode(), tmpname
, NO_INDEX
,
141 &default_file_stat
, 0, (cbdata_t
) cb
);
142 TAILQ_INSERT_HEAD(&gpio_cbdata_list
, cb
, next
);
145 cb
= malloc(sizeof(struct gpio_cbdata
));
149 memset(cb
, 0, sizeof(*cb
));
151 cb
->type
= GPIO_CB_INTR_READ
;
154 snprintf(tmpname
, 200, "%sIntr", name
);
155 add_inode(get_root_inode(), tmpname
, NO_INDEX
,
156 &default_file_stat
, 0, (cbdata_t
) cb
);
157 TAILQ_INSERT_HEAD(&gpio_cbdata_list
, cb
, next
);
165 /* This hook will be called once, after VTreeFS has initialized. */
167 log_warn(&log
, "Failed to init gpio driver\n");
170 struct machine machine
;
171 sys_getmachine(&machine
);
173 if (BOARD_IS_BBXM(machine
.board_id
)){
174 add_gpio_inode("USR0", 149, GPIO_MODE_OUTPUT
);
175 add_gpio_inode("USR1", 150, GPIO_MODE_OUTPUT
);
176 add_gpio_inode("Button", 4, GPIO_MODE_INPUT
);
178 /* configure GPIO_144 to be exported */
179 sys_padconf(CONTROL_PADCONF_UART2_CTS
, 0x0000ffff,
180 PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN
|
181 PADCONF_INPUT_ENABLE(1));
182 sys_padconf(CONTROL_PADCONF_MMC2_DAT6
, 0xffff0000,
183 (PADCONF_MUXMODE(4) | PADCONF_PULL_MODE_PD_EN
|
184 PADCONF_INPUT_ENABLE(1)) << 16);
186 /* Added for demo purposes */
187 add_gpio_inode("BigRedButton", 144, GPIO_MODE_INPUT
);
188 add_gpio_inode("BigRedButtonLed", 139, GPIO_MODE_OUTPUT
);
189 } else if ( BOARD_IS_BB(machine
.board_id
)){
191 /* Export GPIO3_19 (P9-27 on BBB) output as LCD_EN */
193 sys_padconf(CONTROL_CONF_MCASP0_FSR
, 0xffffffff,
194 (CONTROL_CONF_PUTYPESEL
| CONTROL_CONF_MUXMODE(7)));
196 add_gpio_inode("LCD_EN", (32 * 3) + 19, GPIO_MODE_OUTPUT
);
198 /* Export GPIO1_17 (P9-23 on BBB) input as RIGHT */
200 /* assumes external pull-up resistor (10K) */
201 sys_padconf(CONTROL_CONF_SPI0_D0
, 0xffffffff, (CONTROL_CONF_RXACTIVE
|
202 CONTROL_CONF_PUDEN
| CONTROL_CONF_MUXMODE(7)));
204 add_gpio_inode("RIGHT", (32 * 1) + 17, GPIO_MODE_INPUT
);
211 (struct inode
*inode
, off_t offset
, char **ptr
, size_t * len
,
214 /* This hook will be called every time a regular file is read. We use
215 * it to dyanmically generate the contents of our file. */
216 static char data
[26];
218 struct gpio_cbdata
*gpio_cbdata
= (struct gpio_cbdata
*) cbdata
;
219 assert(gpio_cbdata
->gpio
!= NULL
);
221 if (gpio_cbdata
->type
== GPIO_CB_ON
222 || gpio_cbdata
->type
== GPIO_CB_OFF
) {
224 if (gpio_set(gpio_cbdata
->gpio
,
225 (gpio_cbdata
->type
== GPIO_CB_ON
) ? 1 : 0)) {
233 if (gpio_cbdata
->type
== GPIO_CB_INTR_READ
) {
234 /* reading interrupt */
235 if (gpio_intr_read(gpio_cbdata
->gpio
, &value
)) {
241 if (gpio_read(gpio_cbdata
->gpio
, &value
)) {
246 snprintf(data
, 26, "%d\n", value
);
248 /* If the offset is beyond the end of the string, return EOF. */
249 if (offset
> strlen(data
)) {
255 /* Otherwise, return a pointer into 'data'. If necessary, bound the
256 * returned length to the length of the rest of the string. Note that
257 * 'data' has to be static, because it will be used after this
258 * function returns. */
259 *ptr
= data
+ offset
;
261 if (*len
> strlen(data
) - offset
)
262 *len
= strlen(data
) - offset
;
268 message_hook(message
* m
)
270 gpio_intr_message(m
);
275 main(int argc
, char **argv
)
278 struct fs_hooks hooks
;
279 struct inode_stat root_stat
;
281 /* Set and apply the environment */
282 env_setargs(argc
, argv
);
284 /* fill in the hooks */
285 memset(&hooks
, 0, sizeof(hooks
));
286 hooks
.init_hook
= init_hook
;
287 hooks
.read_hook
= read_hook
;
288 hooks
.message_hook
= message_hook
;
290 root_stat
.mode
= S_IFDIR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
294 root_stat
.dev
= NO_DEV
;
296 /* limit the number of indexed entries */
297 start_vtreefs(&hooks
, 30, &root_stat
, 0);