]> err.no Git - linux-2.6/blob - drivers/char/scx200_gpio.c
f9994ed01816b92dcb5c6493d364430b8893f412
[linux-2.6] / drivers / char / scx200_gpio.c
1 /* linux/drivers/char/scx200_gpio.c
2
3    National Semiconductor SCx200 GPIO driver.  Allows a user space
4    process to play with the GPIO pins.
5
6    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
7
8 #include <linux/config.h>
9 #include <linux/device.h>
10 #include <linux/fs.h>
11 #include <linux/module.h>
12 #include <linux/errno.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <asm/uaccess.h>
17 #include <asm/io.h>
18
19 #include <linux/types.h>
20 #include <linux/cdev.h>
21
22 #include <linux/scx200_gpio.h>
23 #include <linux/nsc_gpio.h>
24
25 #define NAME "scx200_gpio"
26 #define DEVNAME NAME
27
28 static struct platform_device *pdev;
29
30 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
31 MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
32 MODULE_LICENSE("GPL");
33
34 static int major = 0;           /* default to dynamic major */
35 module_param(major, int, 0);
36 MODULE_PARM_DESC(major, "Major device number");
37
38 extern void scx200_gpio_dump(unsigned index);
39
40 struct nsc_gpio_ops scx200_access = {
41         .owner          = THIS_MODULE,
42         .gpio_config    = scx200_gpio_configure,
43         .gpio_dump      = scx200_gpio_dump,
44         .gpio_get       = scx200_gpio_get,
45         .gpio_set       = scx200_gpio_set,
46         .gpio_set_high  = scx200_gpio_set_high,
47         .gpio_set_low   = scx200_gpio_set_low,
48         .gpio_change    = scx200_gpio_change,
49         .gpio_current   = scx200_gpio_current
50 };
51
52 static ssize_t scx200_gpio_write(struct file *file, const char __user *data,
53                                  size_t len, loff_t *ppos)
54 {
55         unsigned m = iminor(file->f_dentry->d_inode);
56         size_t i;
57         int err = 0;
58
59         for (i = 0; i < len; ++i) {
60                 char c;
61                 if (get_user(c, data + i))
62                         return -EFAULT;
63                 switch (c) {
64                 case '0':
65                         scx200_gpio_set(m, 0);
66                         break;
67                 case '1':
68                         scx200_gpio_set(m, 1);
69                         break;
70                 case 'O':
71                         printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
72                         scx200_gpio_configure(m, ~1, 1);
73                         break;
74                 case 'o':
75                         printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
76                         scx200_gpio_configure(m, ~1, 0);
77                         break;
78                 case 'T':
79                         printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
80                         scx200_gpio_configure(m, ~2, 2);
81                         break;
82                 case 't':
83                         printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
84                         scx200_gpio_configure(m, ~2, 0);
85                         break;
86                 case 'P':
87                         printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
88                         scx200_gpio_configure(m, ~4, 4);
89                         break;
90                 case 'p':
91                         printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
92                         scx200_gpio_configure(m, ~4, 0);
93                         break;
94
95                 case 'v':
96                         /* View Current pin settings */
97                         scx200_gpio_dump(m);
98                         break;
99                 case '\n':
100                         /* end of settings string, do nothing */
101                         break;
102                 default:
103                         printk(KERN_ERR NAME
104                                ": GPIO-%2d bad setting: chr<0x%2x>\n", m,
105                                (int)c);
106                         err++;
107                 }
108         }
109         if (err)
110                 return -EINVAL; /* full string handled, report error */
111
112         return len;
113 }
114
115 static ssize_t scx200_gpio_read(struct file *file, char __user *buf,
116                                 size_t len, loff_t *ppos)
117 {
118         unsigned m = iminor(file->f_dentry->d_inode);
119         int value;
120
121         value = scx200_gpio_get(m);
122         if (put_user(value ? '1' : '0', buf))
123                 return -EFAULT;
124
125         return 1;
126 }
127
128 static int scx200_gpio_open(struct inode *inode, struct file *file)
129 {
130         unsigned m = iminor(inode);
131         if (m > 63)
132                 return -EINVAL;
133         return nonseekable_open(inode, file);
134 }
135
136 static int scx200_gpio_release(struct inode *inode, struct file *file)
137 {
138         return 0;
139 }
140
141
142 static struct file_operations scx200_gpio_fops = {
143         .owner   = THIS_MODULE,
144         .write   = scx200_gpio_write,
145         .read    = scx200_gpio_read,
146         .open    = scx200_gpio_open,
147         .release = scx200_gpio_release,
148 };
149
150 struct cdev *scx200_devices;
151 static int num_pins = 32;
152
153 static int __init scx200_gpio_init(void)
154 {
155         int rc, i;
156         dev_t dev = MKDEV(major, 0);
157
158         if (!scx200_gpio_present()) {
159                 printk(KERN_ERR NAME ": no SCx200 gpio present\n");
160                 return -ENODEV;
161         }
162
163         /* support dev_dbg() with pdev->dev */
164         pdev = platform_device_alloc(DEVNAME, 0);
165         if (!pdev)
166                 return -ENOMEM;
167
168         rc = platform_device_add(pdev);
169         if (rc)
170                 goto undo_malloc;
171
172         if (major)
173                 rc = register_chrdev_region(dev, num_pins, "scx200_gpio");
174         else {
175                 rc = alloc_chrdev_region(&dev, 0, num_pins, "scx200_gpio");
176                 major = MAJOR(dev);
177         }
178         if (rc < 0) {
179                 dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
180                 goto undo_platform_device_add;
181         }
182         scx200_devices = kzalloc(num_pins * sizeof(struct cdev), GFP_KERNEL);
183         if (!scx200_devices) {
184                 rc = -ENOMEM;
185                 goto undo_chrdev_region;
186         }
187         for (i = 0; i < num_pins; i++) {
188                 struct cdev *cdev = &scx200_devices[i];
189                 cdev_init(cdev, &scx200_gpio_fops);
190                 cdev->owner = THIS_MODULE;
191                 rc = cdev_add(cdev, MKDEV(major, i), 1);
192                 /* tolerate 'minor' errors */
193                 if (rc)
194                         dev_err(&pdev->dev, "Error %d on minor %d", rc, i);
195         }
196
197         return 0; /* succeed */
198
199 undo_chrdev_region:
200         unregister_chrdev_region(dev, num_pins);
201 undo_platform_device_add:
202         platform_device_put(pdev);
203 undo_malloc:
204         kfree(pdev);
205         return rc;
206 }
207
208 static void __exit scx200_gpio_cleanup(void)
209 {
210         kfree(scx200_devices);
211         unregister_chrdev_region(MKDEV(major, 0), num_pins);
212         platform_device_put(pdev);
213         platform_device_unregister(pdev);
214         /* kfree(pdev); */
215 }
216
217 module_init(scx200_gpio_init);
218 module_exit(scx200_gpio_cleanup);