raspi_gpio_driver

view 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 source
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/io.h>
4 #include <linux/fs.h>
5 #include <asm/uaccess.h>
7 /* raspberry pi 2 */
8 #define PERI_ADDR 0x3f000000
9 #define PERI_SIZE 0x1000000
11 #define REG_GPIO_BASE 0x200000
12 #define REG_GPFSEL_BASE 0x200000
13 #define REG_GPSET_BASE 0x20001c
14 #define REG_GPCLR_BASE 0x200028
15 #define REG_GPLEV_BASE 0x200034
16 #define REG_GPPUD 0x200094
17 #define REG_GPPUDCLK_BASE 0x200098
19 #define FSEL_BITS 3
20 #define FSEL_INPUT 0
21 #define FSEL_OUTPUT 1
23 #define FSEL_SHIFT(i) (((i) % 10) * 3)
24 #define FSEL_MASK(i) (3 << FSEL_SHIFT(i))
26 #define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r))
28 static int gpio_init(void);
29 static void gpio_exit(void);
30 static int gpio_open(struct inode *inode, struct file *file);
31 static int gpio_close(struct inode *inode, struct file *file);
32 static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset);
34 static inline void set_pin_func(int pin, int func);
35 static inline void set_pin_state(int pin, int s);
36 static inline int get_pin_state(int pin);
37 static inline void set_pullup(int pin, int en);
38 static inline void set_pulldown(int pin, int en);
40 MODULE_LICENSE("GPL");
41 MODULE_AUTHOR("John Tsiombikas");
42 MODULE_DESCRIPTION("gpio module");
44 module_init(gpio_init);
45 module_exit(gpio_exit);
47 static int major;
48 static void *iomem;
50 static struct file_operations ops = {
51 .open = gpio_open,
52 .release = gpio_close,
53 .write = gpio_write
54 };
56 static int gpio_init(void)
57 {
58 if((major = register_chrdev(0, "gpio", &ops)) < 0) {
59 printk("failed to register character device gpio (err: %d)\n", major);
60 return -1;
61 }
62 printk("gpio module registered (device: %d)\n", major);
63 return 0;
64 }
66 static void gpio_exit(void)
67 {
68 unregister_chrdev(major, "gpio");
69 printk("gpio exit\n");
70 }
72 static int gpio_open(struct inode *inode, struct file *file)
73 {
74 printk("gpio_open called\n");
75 if(iomem) {
76 return -EBUSY;
77 }
79 if(!(iomem = ioremap(PERI_ADDR, PERI_SIZE))) {
80 printk("gpio: failed to map peripherals\n");
81 return -EBUSY;
82 }
83 set_pin_func(4, FSEL_OUTPUT);
84 set_pin_state(4, 0);
86 try_module_get(THIS_MODULE);
87 return 0;
88 }
90 static int gpio_close(struct inode *inode, struct file *file)
91 {
92 if(!iomem) {
93 return -EBADF;
94 }
96 iounmap(iomem);
97 iomem = 0;
99 module_put(THIS_MODULE);
100 return 0;
101 }
103 static ssize_t gpio_write(struct file *file, const char *buf, size_t sz, loff_t *offset)
104 {
105 unsigned char val;
107 printk("gpio_write(%d) called\n", sz);
109 if(sz < 1) {
110 return 0;
111 }
112 if(copy_from_user(&val, (unsigned char*)buf + sz - 1, 1) != 0) {
113 return -EFAULT;
114 }
116 set_pin_state(4, val ? 1 : 0);
117 return sz;
118 }
121 static inline void set_pin_func(int pin, int func)
122 {
123 int reg_addr, val;
124 reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4;
125 val = *REG(reg_addr);
126 *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin));
127 }
129 static inline void set_pin_state(int pin, int s)
130 {
131 int reg_addr;
132 int regidx = pin / 32;
133 int bit = pin % 32;
135 if(s) {
136 reg_addr = REG_GPSET_BASE + regidx * 4;
137 *REG(reg_addr) |= 1 << bit;
138 } else {
139 reg_addr = REG_GPCLR_BASE + regidx * 4;
140 *REG(reg_addr) |= 1 << bit;
141 }
142 }
144 static inline int get_pin_state(int pin)
145 {
146 int reg_addr;
147 int regidx = pin / 32;
148 int bit = pin % 32;
150 reg_addr = REG_GPLEV_BASE + regidx * 4;
151 return (*REG(reg_addr) >> bit) & 1;
152 }
154 #define delay_cycles(x) \
155 __asm__ __volatile__ ( \
156 "1:\n\t" \
157 "subs %0, %0, #1\n\t" \
158 "bne 1b\n\t" \
159 :: "r"(x))
161 static inline void set_pull_updown(int pin, int updown)
162 {
163 int regidx = pin / 32;
164 int bit = pin % 32;
165 int clk_addr = REG_GPPUDCLK_BASE + regidx * 4;
167 *REG(REG_GPPUD) = updown;
168 delay_cycles(150);
169 *REG(clk_addr) = bit;
170 delay_cycles(150);
171 *REG(REG_GPPUD) = 0;
172 *REG(clk_addr) = 0;
173 }
175 static inline void set_pullup(int pin, int en)
176 {
177 set_pull_updown(pin, en ? 2 : 0);
178 }
180 static inline void set_pulldown(int pin, int en)
181 {
182 set_pull_updown(pin, en ? 1 : 0);
183 }