raspi_gpio_driver
changeset 1:acfcd119e532
- dropped all my custom i/o register fiddling in favor of the kernel gpio
functions which are already implemented by broadcom.
- added a test interrupt handler
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 05 Mar 2016 04:25:33 +0000 |
parents | fbab2b3e28da |
children | a7543d592206 |
files | gpio.c |
diffstat | 1 files changed, 51 insertions(+), 125 deletions(-) [+] |
line diff
1.1 --- a/gpio.c Fri Mar 04 05:20:55 2016 +0000 1.2 +++ b/gpio.c Sat Mar 05 04:25:33 2016 +0000 1.3 @@ -2,109 +2,94 @@ 1.4 #include <linux/kernel.h> 1.5 #include <linux/io.h> 1.6 #include <linux/fs.h> 1.7 +#include <linux/interrupt.h> 1.8 #include <asm/uaccess.h> 1.9 +#include <linux/gpio.h> 1.10 1.11 -/* raspberry pi 2 */ 1.12 -#define PERI_ADDR 0x3f000000 1.13 -#define PERI_SIZE 0x1000000 1.14 +#define TEST_OUTPUT_PIN 4 1.15 +#define TEST_INPUT_PIN 22 1.16 1.17 -#define REG_GPIO_BASE 0x200000 1.18 -#define REG_GPFSEL_BASE 0x200000 1.19 -#define REG_GPSET_BASE 0x20001c 1.20 -#define REG_GPCLR_BASE 0x200028 1.21 -#define REG_GPLEV_BASE 0x200034 1.22 -#define REG_GPPUD 0x200094 1.23 -#define REG_GPPUDCLK_BASE 0x200098 1.24 +static int dev_init(void); 1.25 +static void dev_exit(void); 1.26 +static int dev_open(struct inode *inode, struct file *file); 1.27 +static int dev_close(struct inode *inode, struct file *file); 1.28 +static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset); 1.29 1.30 -#define FSEL_BITS 3 1.31 -#define FSEL_INPUT 0 1.32 -#define FSEL_OUTPUT 1 1.33 - 1.34 -#define FSEL_SHIFT(i) (((i) % 10) * 3) 1.35 -#define FSEL_MASK(i) (3 << FSEL_SHIFT(i)) 1.36 - 1.37 -#define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r)) 1.38 - 1.39 -static int gpio_init(void); 1.40 -static void gpio_exit(void); 1.41 -static int gpio_open(struct inode *inode, struct file *file); 1.42 -static int gpio_close(struct inode *inode, struct file *file); 1.43 -static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset); 1.44 - 1.45 -static inline void set_pin_func(int pin, int func); 1.46 -static inline void set_pin_state(int pin, int s); 1.47 -static inline int get_pin_state(int pin); 1.48 -static inline void set_pullup(int pin, int en); 1.49 -static inline void set_pulldown(int pin, int en); 1.50 +static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs); 1.51 1.52 MODULE_LICENSE("GPL"); 1.53 MODULE_AUTHOR("John Tsiombikas"); 1.54 MODULE_DESCRIPTION("gpio module"); 1.55 1.56 -module_init(gpio_init); 1.57 -module_exit(gpio_exit); 1.58 +module_init(dev_init); 1.59 +module_exit(dev_exit); 1.60 1.61 static int major; 1.62 -static void *iomem; 1.63 +static int intr_num = -1; 1.64 +static int num_presses; 1.65 1.66 static struct file_operations ops = { 1.67 - .open = gpio_open, 1.68 - .release = gpio_close, 1.69 - .write = gpio_write 1.70 + .open = dev_open, 1.71 + .release = dev_close, 1.72 + .write = dev_write 1.73 }; 1.74 1.75 -static int gpio_init(void) 1.76 +static int dev_init(void) 1.77 { 1.78 if((major = register_chrdev(0, "gpio", &ops)) < 0) { 1.79 printk("failed to register character device gpio (err: %d)\n", major); 1.80 return -1; 1.81 } 1.82 printk("gpio module registered (device: %d)\n", major); 1.83 + 1.84 + gpio_direction_output(TEST_OUTPUT_PIN, 0); 1.85 + gpio_direction_input(TEST_INPUT_PIN); 1.86 + 1.87 + if(gpio_request(TEST_INPUT_PIN, "test_input") != 0) { 1.88 + printk("gpio: failed to get input gpio pin\n"); 1.89 + return -1; 1.90 + } 1.91 + if((intr_num = gpio_to_irq(TEST_INPUT_PIN)) < 0) { 1.92 + printk("gpio: failed to get interrupt line for gpio pin\n"); 1.93 + return -1; 1.94 + } 1.95 + if(request_irq(intr_num, (irq_handler_t)intr_handler, IRQF_TRIGGER_RISING, 1.96 + "gpio_intr", "gpio") != 0) { 1.97 + printk("gpio: failed to setup interrupt handler\n"); 1.98 + return -1; 1.99 + } 1.100 + 1.101 return 0; 1.102 } 1.103 1.104 -static void gpio_exit(void) 1.105 +static void dev_exit(void) 1.106 { 1.107 + printk("gpio exit\n"); 1.108 unregister_chrdev(major, "gpio"); 1.109 - printk("gpio exit\n"); 1.110 + 1.111 + if(intr_num != -1) { 1.112 + free_irq(intr_num, "gpio"); 1.113 + } 1.114 + gpio_free(TEST_INPUT_PIN); 1.115 } 1.116 1.117 -static int gpio_open(struct inode *inode, struct file *file) 1.118 +static int dev_open(struct inode *inode, struct file *file) 1.119 { 1.120 - printk("gpio_open called\n"); 1.121 - if(iomem) { 1.122 - return -EBUSY; 1.123 - } 1.124 - 1.125 - if(!(iomem = ioremap(PERI_ADDR, PERI_SIZE))) { 1.126 - printk("gpio: failed to map peripherals\n"); 1.127 - return -EBUSY; 1.128 - } 1.129 - set_pin_func(4, FSEL_OUTPUT); 1.130 - set_pin_state(4, 0); 1.131 - 1.132 try_module_get(THIS_MODULE); 1.133 return 0; 1.134 } 1.135 1.136 -static int gpio_close(struct inode *inode, struct file *file) 1.137 +static int dev_close(struct inode *inode, struct file *file) 1.138 { 1.139 - if(!iomem) { 1.140 - return -EBADF; 1.141 - } 1.142 - 1.143 - iounmap(iomem); 1.144 - iomem = 0; 1.145 - 1.146 module_put(THIS_MODULE); 1.147 return 0; 1.148 } 1.149 1.150 -static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset) 1.151 +static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset) 1.152 { 1.153 unsigned char val; 1.154 1.155 - printk("gpio_write(%d) called\n", sz); 1.156 + printk("dev_write(%d) called\n", sz); 1.157 1.158 if(sz < 1) { 1.159 return 0; 1.160 @@ -113,71 +98,12 @@ 1.161 return -EFAULT; 1.162 } 1.163 1.164 - set_pin_state(4, val ? 1 : 0); 1.165 + gpio_set_value(TEST_OUTPUT_PIN, val == '0' ? 0 : 1); 1.166 return sz; 1.167 } 1.168 1.169 - 1.170 -static inline void set_pin_func(int pin, int func) 1.171 +static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs) 1.172 { 1.173 - int reg_addr, val; 1.174 - reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4; 1.175 - val = *REG(reg_addr); 1.176 - *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin)); 1.177 + printk("presses: %d\n", num_presses++); 1.178 + return IRQ_HANDLED; 1.179 } 1.180 - 1.181 -static inline void set_pin_state(int pin, int s) 1.182 -{ 1.183 - int reg_addr; 1.184 - int regidx = pin / 32; 1.185 - int bit = pin % 32; 1.186 - 1.187 - if(s) { 1.188 - reg_addr = REG_GPSET_BASE + regidx * 4; 1.189 - *REG(reg_addr) |= 1 << bit; 1.190 - } else { 1.191 - reg_addr = REG_GPCLR_BASE + regidx * 4; 1.192 - *REG(reg_addr) |= 1 << bit; 1.193 - } 1.194 -} 1.195 - 1.196 -static inline int get_pin_state(int pin) 1.197 -{ 1.198 - int reg_addr; 1.199 - int regidx = pin / 32; 1.200 - int bit = pin % 32; 1.201 - 1.202 - reg_addr = REG_GPLEV_BASE + regidx * 4; 1.203 - return (*REG(reg_addr) >> bit) & 1; 1.204 -} 1.205 - 1.206 -#define delay_cycles(x) \ 1.207 - __asm__ __volatile__ ( \ 1.208 - "1:\n\t" \ 1.209 - "subs %0, %0, #1\n\t" \ 1.210 - "bne 1b\n\t" \ 1.211 - :: "r"(x)) 1.212 - 1.213 -static inline void set_pull_updown(int pin, int updown) 1.214 -{ 1.215 - int regidx = pin / 32; 1.216 - int bit = pin % 32; 1.217 - int clk_addr = REG_GPPUDCLK_BASE + regidx * 4; 1.218 - 1.219 - *REG(REG_GPPUD) = updown; 1.220 - delay_cycles(150); 1.221 - *REG(clk_addr) = bit; 1.222 - delay_cycles(150); 1.223 - *REG(REG_GPPUD) = 0; 1.224 - *REG(clk_addr) = 0; 1.225 -} 1.226 - 1.227 -static inline void set_pullup(int pin, int en) 1.228 -{ 1.229 - set_pull_updown(pin, en ? 2 : 0); 1.230 -} 1.231 - 1.232 -static inline void set_pulldown(int pin, int en) 1.233 -{ 1.234 - set_pull_updown(pin, en ? 1 : 0); 1.235 -}