1
2
3
4
5
6
7
8#include <linux/config.h>
9#include <linux/module.h>
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <asm/uaccess.h>
14#include <asm/io.h>
15
16#include <linux/scx200_gpio.h>
17
18#define NAME "scx200_gpio"
19
20MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
21MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
22MODULE_LICENSE("GPL");
23
24static int major = 0;
25MODULE_PARM(major, "i");
26MODULE_PARM_DESC(major, "Major device number");
27
28static ssize_t scx200_gpio_write(struct file *file, const char *data,
29 size_t len, loff_t *ppos)
30{
31 unsigned m = minor(file->f_dentry->d_inode->i_rdev);
32 size_t i;
33
34 if (ppos != &file->f_pos)
35 return -ESPIPE;
36
37 for (i = 0; i < len; ++i) {
38 char c;
39 if (get_user(c, data+i))
40 return -EFAULT;
41 switch (c)
42 {
43 case '0':
44 scx200_gpio_set(m, 0);
45 break;
46 case '1':
47 scx200_gpio_set(m, 1);
48 break;
49 case 'O':
50 printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
51 scx200_gpio_configure(m, ~1, 1);
52 break;
53 case 'o':
54 printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
55 scx200_gpio_configure(m, ~1, 0);
56 break;
57 case 'T':
58 printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
59 scx200_gpio_configure(m, ~2, 2);
60 break;
61 case 't':
62 printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
63 scx200_gpio_configure(m, ~2, 0);
64 break;
65 case 'P':
66 printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
67 scx200_gpio_configure(m, ~4, 4);
68 break;
69 case 'p':
70 printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
71 scx200_gpio_configure(m, ~4, 0);
72 break;
73 }
74 }
75
76 return len;
77}
78
79static ssize_t scx200_gpio_read(struct file *file, char *buf,
80 size_t len, loff_t *ppos)
81{
82 unsigned m = minor(file->f_dentry->d_inode->i_rdev);
83 int value;
84
85 if (ppos != &file->f_pos)
86 return -ESPIPE;
87
88 value = scx200_gpio_get(m);
89 if (put_user(value ? '1' : '0', buf))
90 return -EFAULT;
91
92 return 1;
93}
94
95static int scx200_gpio_open(struct inode *inode, struct file *file)
96{
97 unsigned m = minor(inode->i_rdev);
98 if (m > 63)
99 return -EINVAL;
100 return 0;
101}
102
103static int scx200_gpio_release(struct inode *inode, struct file *file)
104{
105 return 0;
106}
107
108
109static struct file_operations scx200_gpio_fops = {
110 .owner = THIS_MODULE,
111 .write = scx200_gpio_write,
112 .read = scx200_gpio_read,
113 .open = scx200_gpio_open,
114 .release = scx200_gpio_release,
115};
116
117static int __init scx200_gpio_init(void)
118{
119 int r;
120
121 printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
122
123 if (!scx200_gpio_present()) {
124 printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
125 return -ENODEV;
126 }
127
128 r = register_chrdev(major, NAME, &scx200_gpio_fops);
129 if (r < 0) {
130 printk(KERN_ERR NAME ": unable to register character device\n");
131 return r;
132 }
133 if (!major) {
134 major = r;
135 printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
136 }
137
138 return 0;
139}
140
141static void __exit scx200_gpio_cleanup(void)
142{
143 unregister_chrdev(major, NAME);
144}
145
146module_init(scx200_gpio_init);
147module_exit(scx200_gpio_cleanup);
148
149
150
151
152
153
154
155