# HG changeset patch # User John Tsiombikas # Date 1457151933 0 # Node ID acfcd119e53248bb582a9a2862f652b502534be2 # Parent fbab2b3e28da89e0242f62ad99860b21e8b3bfc7 - 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 diff -r fbab2b3e28da -r acfcd119e532 gpio.c --- a/gpio.c Fri Mar 04 05:20:55 2016 +0000 +++ b/gpio.c Sat Mar 05 04:25:33 2016 +0000 @@ -2,109 +2,94 @@ #include #include #include +#include #include +#include -/* raspberry pi 2 */ -#define PERI_ADDR 0x3f000000 -#define PERI_SIZE 0x1000000 +#define TEST_OUTPUT_PIN 4 +#define TEST_INPUT_PIN 22 -#define REG_GPIO_BASE 0x200000 -#define REG_GPFSEL_BASE 0x200000 -#define REG_GPSET_BASE 0x20001c -#define REG_GPCLR_BASE 0x200028 -#define REG_GPLEV_BASE 0x200034 -#define REG_GPPUD 0x200094 -#define REG_GPPUDCLK_BASE 0x200098 +static int dev_init(void); +static void dev_exit(void); +static int dev_open(struct inode *inode, struct file *file); +static int dev_close(struct inode *inode, struct file *file); +static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset); -#define FSEL_BITS 3 -#define FSEL_INPUT 0 -#define FSEL_OUTPUT 1 - -#define FSEL_SHIFT(i) (((i) % 10) * 3) -#define FSEL_MASK(i) (3 << FSEL_SHIFT(i)) - -#define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r)) - -static int gpio_init(void); -static void gpio_exit(void); -static int gpio_open(struct inode *inode, struct file *file); -static int gpio_close(struct inode *inode, struct file *file); -static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset); - -static inline void set_pin_func(int pin, int func); -static inline void set_pin_state(int pin, int s); -static inline int get_pin_state(int pin); -static inline void set_pullup(int pin, int en); -static inline void set_pulldown(int pin, int en); +static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Tsiombikas"); MODULE_DESCRIPTION("gpio module"); -module_init(gpio_init); -module_exit(gpio_exit); +module_init(dev_init); +module_exit(dev_exit); static int major; -static void *iomem; +static int intr_num = -1; +static int num_presses; static struct file_operations ops = { - .open = gpio_open, - .release = gpio_close, - .write = gpio_write + .open = dev_open, + .release = dev_close, + .write = dev_write }; -static int gpio_init(void) +static int dev_init(void) { if((major = register_chrdev(0, "gpio", &ops)) < 0) { printk("failed to register character device gpio (err: %d)\n", major); return -1; } printk("gpio module registered (device: %d)\n", major); + + gpio_direction_output(TEST_OUTPUT_PIN, 0); + gpio_direction_input(TEST_INPUT_PIN); + + if(gpio_request(TEST_INPUT_PIN, "test_input") != 0) { + printk("gpio: failed to get input gpio pin\n"); + return -1; + } + if((intr_num = gpio_to_irq(TEST_INPUT_PIN)) < 0) { + printk("gpio: failed to get interrupt line for gpio pin\n"); + return -1; + } + if(request_irq(intr_num, (irq_handler_t)intr_handler, IRQF_TRIGGER_RISING, + "gpio_intr", "gpio") != 0) { + printk("gpio: failed to setup interrupt handler\n"); + return -1; + } + return 0; } -static void gpio_exit(void) +static void dev_exit(void) { + printk("gpio exit\n"); unregister_chrdev(major, "gpio"); - printk("gpio exit\n"); + + if(intr_num != -1) { + free_irq(intr_num, "gpio"); + } + gpio_free(TEST_INPUT_PIN); } -static int gpio_open(struct inode *inode, struct file *file) +static int dev_open(struct inode *inode, struct file *file) { - printk("gpio_open called\n"); - if(iomem) { - return -EBUSY; - } - - if(!(iomem = ioremap(PERI_ADDR, PERI_SIZE))) { - printk("gpio: failed to map peripherals\n"); - return -EBUSY; - } - set_pin_func(4, FSEL_OUTPUT); - set_pin_state(4, 0); - try_module_get(THIS_MODULE); return 0; } -static int gpio_close(struct inode *inode, struct file *file) +static int dev_close(struct inode *inode, struct file *file) { - if(!iomem) { - return -EBADF; - } - - iounmap(iomem); - iomem = 0; - module_put(THIS_MODULE); return 0; } -static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset) +static ssize_t dev_write(struct file *file, const char *buf, size_t sz, loff_t *offset) { unsigned char val; - printk("gpio_write(%d) called\n", sz); + printk("dev_write(%d) called\n", sz); if(sz < 1) { return 0; @@ -113,71 +98,12 @@ return -EFAULT; } - set_pin_state(4, val ? 1 : 0); + gpio_set_value(TEST_OUTPUT_PIN, val == '0' ? 0 : 1); return sz; } - -static inline void set_pin_func(int pin, int func) +static irqreturn_t intr_handler(int inum, void *devid, struct pt_regs *regs) { - int reg_addr, val; - reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4; - val = *REG(reg_addr); - *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin)); + printk("presses: %d\n", num_presses++); + return IRQ_HANDLED; } - -static inline void set_pin_state(int pin, int s) -{ - int reg_addr; - int regidx = pin / 32; - int bit = pin % 32; - - if(s) { - reg_addr = REG_GPSET_BASE + regidx * 4; - *REG(reg_addr) |= 1 << bit; - } else { - reg_addr = REG_GPCLR_BASE + regidx * 4; - *REG(reg_addr) |= 1 << bit; - } -} - -static inline int get_pin_state(int pin) -{ - int reg_addr; - int regidx = pin / 32; - int bit = pin % 32; - - reg_addr = REG_GPLEV_BASE + regidx * 4; - return (*REG(reg_addr) >> bit) & 1; -} - -#define delay_cycles(x) \ - __asm__ __volatile__ ( \ - "1:\n\t" \ - "subs %0, %0, #1\n\t" \ - "bne 1b\n\t" \ - :: "r"(x)) - -static inline void set_pull_updown(int pin, int updown) -{ - int regidx = pin / 32; - int bit = pin % 32; - int clk_addr = REG_GPPUDCLK_BASE + regidx * 4; - - *REG(REG_GPPUD) = updown; - delay_cycles(150); - *REG(clk_addr) = bit; - delay_cycles(150); - *REG(REG_GPPUD) = 0; - *REG(clk_addr) = 0; -} - -static inline void set_pullup(int pin, int en) -{ - set_pull_updown(pin, en ? 2 : 0); -} - -static inline void set_pulldown(int pin, int en) -{ - set_pull_updown(pin, en ? 1 : 0); -}