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