raspi_gpio_driver
diff gpio.c @ 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gpio.c Fri Mar 04 05:20:55 2016 +0000 1.3 @@ -0,0 +1,183 @@ 1.4 +#include <linux/module.h> 1.5 +#include <linux/kernel.h> 1.6 +#include <linux/io.h> 1.7 +#include <linux/fs.h> 1.8 +#include <asm/uaccess.h> 1.9 + 1.10 +/* raspberry pi 2 */ 1.11 +#define PERI_ADDR 0x3f000000 1.12 +#define PERI_SIZE 0x1000000 1.13 + 1.14 +#define REG_GPIO_BASE 0x200000 1.15 +#define REG_GPFSEL_BASE 0x200000 1.16 +#define REG_GPSET_BASE 0x20001c 1.17 +#define REG_GPCLR_BASE 0x200028 1.18 +#define REG_GPLEV_BASE 0x200034 1.19 +#define REG_GPPUD 0x200094 1.20 +#define REG_GPPUDCLK_BASE 0x200098 1.21 + 1.22 +#define FSEL_BITS 3 1.23 +#define FSEL_INPUT 0 1.24 +#define FSEL_OUTPUT 1 1.25 + 1.26 +#define FSEL_SHIFT(i) (((i) % 10) * 3) 1.27 +#define FSEL_MASK(i) (3 << FSEL_SHIFT(i)) 1.28 + 1.29 +#define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r)) 1.30 + 1.31 +static int gpio_init(void); 1.32 +static void gpio_exit(void); 1.33 +static int gpio_open(struct inode *inode, struct file *file); 1.34 +static int gpio_close(struct inode *inode, struct file *file); 1.35 +static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset); 1.36 + 1.37 +static inline void set_pin_func(int pin, int func); 1.38 +static inline void set_pin_state(int pin, int s); 1.39 +static inline int get_pin_state(int pin); 1.40 +static inline void set_pullup(int pin, int en); 1.41 +static inline void set_pulldown(int pin, int en); 1.42 + 1.43 +MODULE_LICENSE("GPL"); 1.44 +MODULE_AUTHOR("John Tsiombikas"); 1.45 +MODULE_DESCRIPTION("gpio module"); 1.46 + 1.47 +module_init(gpio_init); 1.48 +module_exit(gpio_exit); 1.49 + 1.50 +static int major; 1.51 +static void *iomem; 1.52 + 1.53 +static struct file_operations ops = { 1.54 + .open = gpio_open, 1.55 + .release = gpio_close, 1.56 + .write = gpio_write 1.57 +}; 1.58 + 1.59 +static int gpio_init(void) 1.60 +{ 1.61 + if((major = register_chrdev(0, "gpio", &ops)) < 0) { 1.62 + printk("failed to register character device gpio (err: %d)\n", major); 1.63 + return -1; 1.64 + } 1.65 + printk("gpio module registered (device: %d)\n", major); 1.66 + return 0; 1.67 +} 1.68 + 1.69 +static void gpio_exit(void) 1.70 +{ 1.71 + unregister_chrdev(major, "gpio"); 1.72 + printk("gpio exit\n"); 1.73 +} 1.74 + 1.75 +static int gpio_open(struct inode *inode, struct file *file) 1.76 +{ 1.77 + printk("gpio_open called\n"); 1.78 + if(iomem) { 1.79 + return -EBUSY; 1.80 + } 1.81 + 1.82 + if(!(iomem = ioremap(PERI_ADDR, PERI_SIZE))) { 1.83 + printk("gpio: failed to map peripherals\n"); 1.84 + return -EBUSY; 1.85 + } 1.86 + set_pin_func(4, FSEL_OUTPUT); 1.87 + set_pin_state(4, 0); 1.88 + 1.89 + try_module_get(THIS_MODULE); 1.90 + return 0; 1.91 +} 1.92 + 1.93 +static int gpio_close(struct inode *inode, struct file *file) 1.94 +{ 1.95 + if(!iomem) { 1.96 + return -EBADF; 1.97 + } 1.98 + 1.99 + iounmap(iomem); 1.100 + iomem = 0; 1.101 + 1.102 + module_put(THIS_MODULE); 1.103 + return 0; 1.104 +} 1.105 + 1.106 +static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset) 1.107 +{ 1.108 + unsigned char val; 1.109 + 1.110 + printk("gpio_write(%d) called\n", sz); 1.111 + 1.112 + if(sz < 1) { 1.113 + return 0; 1.114 + } 1.115 + if(copy_from_user(&val, (unsigned char*)buf + sz - 1, 1) != 0) { 1.116 + return -EFAULT; 1.117 + } 1.118 + 1.119 + set_pin_state(4, val ? 1 : 0); 1.120 + return sz; 1.121 +} 1.122 + 1.123 + 1.124 +static inline void set_pin_func(int pin, int func) 1.125 +{ 1.126 + int reg_addr, val; 1.127 + reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4; 1.128 + val = *REG(reg_addr); 1.129 + *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin)); 1.130 +} 1.131 + 1.132 +static inline void set_pin_state(int pin, int s) 1.133 +{ 1.134 + int reg_addr; 1.135 + int regidx = pin / 32; 1.136 + int bit = pin % 32; 1.137 + 1.138 + if(s) { 1.139 + reg_addr = REG_GPSET_BASE + regidx * 4; 1.140 + *REG(reg_addr) |= 1 << bit; 1.141 + } else { 1.142 + reg_addr = REG_GPCLR_BASE + regidx * 4; 1.143 + *REG(reg_addr) |= 1 << bit; 1.144 + } 1.145 +} 1.146 + 1.147 +static inline int get_pin_state(int pin) 1.148 +{ 1.149 + int reg_addr; 1.150 + int regidx = pin / 32; 1.151 + int bit = pin % 32; 1.152 + 1.153 + reg_addr = REG_GPLEV_BASE + regidx * 4; 1.154 + return (*REG(reg_addr) >> bit) & 1; 1.155 +} 1.156 + 1.157 +#define delay_cycles(x) \ 1.158 + __asm__ __volatile__ ( \ 1.159 + "1:\n\t" \ 1.160 + "subs %0, %0, #1\n\t" \ 1.161 + "bne 1b\n\t" \ 1.162 + :: "r"(x)) 1.163 + 1.164 +static inline void set_pull_updown(int pin, int updown) 1.165 +{ 1.166 + int regidx = pin / 32; 1.167 + int bit = pin % 32; 1.168 + int clk_addr = REG_GPPUDCLK_BASE + regidx * 4; 1.169 + 1.170 + *REG(REG_GPPUD) = updown; 1.171 + delay_cycles(150); 1.172 + *REG(clk_addr) = bit; 1.173 + delay_cycles(150); 1.174 + *REG(REG_GPPUD) = 0; 1.175 + *REG(clk_addr) = 0; 1.176 +} 1.177 + 1.178 +static inline void set_pullup(int pin, int en) 1.179 +{ 1.180 + set_pull_updown(pin, en ? 2 : 0); 1.181 +} 1.182 + 1.183 +static inline void set_pulldown(int pin, int en) 1.184 +{ 1.185 + set_pull_updown(pin, en ? 1 : 0); 1.186 +}