raspi_gpio_driver
changeset 0:fbab2b3e28da
gpio module first test
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 04 Mar 2016 05:20:55 +0000 |
parents | |
children | acfcd119e532 |
files | Makefile gpio.c |
diffstat | 2 files changed, 192 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/Makefile Fri Mar 04 05:20:55 2016 +0000 1.3 @@ -0,0 +1,9 @@ 1.4 +obj-m := gpio.o 1.5 + 1.6 +.PHONY: all 1.7 +all: 1.8 + make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules 1.9 + 1.10 +.PHONY: clean 1.11 +clean: 1.12 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/gpio.c Fri Mar 04 05:20:55 2016 +0000 2.3 @@ -0,0 +1,183 @@ 2.4 +#include <linux/module.h> 2.5 +#include <linux/kernel.h> 2.6 +#include <linux/io.h> 2.7 +#include <linux/fs.h> 2.8 +#include <asm/uaccess.h> 2.9 + 2.10 +/* raspberry pi 2 */ 2.11 +#define PERI_ADDR 0x3f000000 2.12 +#define PERI_SIZE 0x1000000 2.13 + 2.14 +#define REG_GPIO_BASE 0x200000 2.15 +#define REG_GPFSEL_BASE 0x200000 2.16 +#define REG_GPSET_BASE 0x20001c 2.17 +#define REG_GPCLR_BASE 0x200028 2.18 +#define REG_GPLEV_BASE 0x200034 2.19 +#define REG_GPPUD 0x200094 2.20 +#define REG_GPPUDCLK_BASE 0x200098 2.21 + 2.22 +#define FSEL_BITS 3 2.23 +#define FSEL_INPUT 0 2.24 +#define FSEL_OUTPUT 1 2.25 + 2.26 +#define FSEL_SHIFT(i) (((i) % 10) * 3) 2.27 +#define FSEL_MASK(i) (3 << FSEL_SHIFT(i)) 2.28 + 2.29 +#define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r)) 2.30 + 2.31 +static int gpio_init(void); 2.32 +static void gpio_exit(void); 2.33 +static int gpio_open(struct inode *inode, struct file *file); 2.34 +static int gpio_close(struct inode *inode, struct file *file); 2.35 +static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset); 2.36 + 2.37 +static inline void set_pin_func(int pin, int func); 2.38 +static inline void set_pin_state(int pin, int s); 2.39 +static inline int get_pin_state(int pin); 2.40 +static inline void set_pullup(int pin, int en); 2.41 +static inline void set_pulldown(int pin, int en); 2.42 + 2.43 +MODULE_LICENSE("GPL"); 2.44 +MODULE_AUTHOR("John Tsiombikas"); 2.45 +MODULE_DESCRIPTION("gpio module"); 2.46 + 2.47 +module_init(gpio_init); 2.48 +module_exit(gpio_exit); 2.49 + 2.50 +static int major; 2.51 +static void *iomem; 2.52 + 2.53 +static struct file_operations ops = { 2.54 + .open = gpio_open, 2.55 + .release = gpio_close, 2.56 + .write = gpio_write 2.57 +}; 2.58 + 2.59 +static int gpio_init(void) 2.60 +{ 2.61 + if((major = register_chrdev(0, "gpio", &ops)) < 0) { 2.62 + printk("failed to register character device gpio (err: %d)\n", major); 2.63 + return -1; 2.64 + } 2.65 + printk("gpio module registered (device: %d)\n", major); 2.66 + return 0; 2.67 +} 2.68 + 2.69 +static void gpio_exit(void) 2.70 +{ 2.71 + unregister_chrdev(major, "gpio"); 2.72 + printk("gpio exit\n"); 2.73 +} 2.74 + 2.75 +static int gpio_open(struct inode *inode, struct file *file) 2.76 +{ 2.77 + printk("gpio_open called\n"); 2.78 + if(iomem) { 2.79 + return -EBUSY; 2.80 + } 2.81 + 2.82 + if(!(iomem = ioremap(PERI_ADDR, PERI_SIZE))) { 2.83 + printk("gpio: failed to map peripherals\n"); 2.84 + return -EBUSY; 2.85 + } 2.86 + set_pin_func(4, FSEL_OUTPUT); 2.87 + set_pin_state(4, 0); 2.88 + 2.89 + try_module_get(THIS_MODULE); 2.90 + return 0; 2.91 +} 2.92 + 2.93 +static int gpio_close(struct inode *inode, struct file *file) 2.94 +{ 2.95 + if(!iomem) { 2.96 + return -EBADF; 2.97 + } 2.98 + 2.99 + iounmap(iomem); 2.100 + iomem = 0; 2.101 + 2.102 + module_put(THIS_MODULE); 2.103 + return 0; 2.104 +} 2.105 + 2.106 +static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset) 2.107 +{ 2.108 + unsigned char val; 2.109 + 2.110 + printk("gpio_write(%d) called\n", sz); 2.111 + 2.112 + if(sz < 1) { 2.113 + return 0; 2.114 + } 2.115 + if(copy_from_user(&val, (unsigned char*)buf + sz - 1, 1) != 0) { 2.116 + return -EFAULT; 2.117 + } 2.118 + 2.119 + set_pin_state(4, val ? 1 : 0); 2.120 + return sz; 2.121 +} 2.122 + 2.123 + 2.124 +static inline void set_pin_func(int pin, int func) 2.125 +{ 2.126 + int reg_addr, val; 2.127 + reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4; 2.128 + val = *REG(reg_addr); 2.129 + *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin)); 2.130 +} 2.131 + 2.132 +static inline void set_pin_state(int pin, int s) 2.133 +{ 2.134 + int reg_addr; 2.135 + int regidx = pin / 32; 2.136 + int bit = pin % 32; 2.137 + 2.138 + if(s) { 2.139 + reg_addr = REG_GPSET_BASE + regidx * 4; 2.140 + *REG(reg_addr) |= 1 << bit; 2.141 + } else { 2.142 + reg_addr = REG_GPCLR_BASE + regidx * 4; 2.143 + *REG(reg_addr) |= 1 << bit; 2.144 + } 2.145 +} 2.146 + 2.147 +static inline int get_pin_state(int pin) 2.148 +{ 2.149 + int reg_addr; 2.150 + int regidx = pin / 32; 2.151 + int bit = pin % 32; 2.152 + 2.153 + reg_addr = REG_GPLEV_BASE + regidx * 4; 2.154 + return (*REG(reg_addr) >> bit) & 1; 2.155 +} 2.156 + 2.157 +#define delay_cycles(x) \ 2.158 + __asm__ __volatile__ ( \ 2.159 + "1:\n\t" \ 2.160 + "subs %0, %0, #1\n\t" \ 2.161 + "bne 1b\n\t" \ 2.162 + :: "r"(x)) 2.163 + 2.164 +static inline void set_pull_updown(int pin, int updown) 2.165 +{ 2.166 + int regidx = pin / 32; 2.167 + int bit = pin % 32; 2.168 + int clk_addr = REG_GPPUDCLK_BASE + regidx * 4; 2.169 + 2.170 + *REG(REG_GPPUD) = updown; 2.171 + delay_cycles(150); 2.172 + *REG(clk_addr) = bit; 2.173 + delay_cycles(150); 2.174 + *REG(REG_GPPUD) = 0; 2.175 + *REG(clk_addr) = 0; 2.176 +} 2.177 + 2.178 +static inline void set_pullup(int pin, int en) 2.179 +{ 2.180 + set_pull_updown(pin, en ? 2 : 0); 2.181 +} 2.182 + 2.183 +static inline void set_pulldown(int pin, int en) 2.184 +{ 2.185 + set_pull_updown(pin, en ? 1 : 0); 2.186 +}