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 -}