import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / char / xilinx_gpio / adapter.c
1 /*
2  * adapter.c
3  *
4  * Xilinx GPIO Adapter component to interface GPIO component to Linux
5  *
6  * Author: MontaVista Software, Inc.
7  *         source@mvista.com
8  *
9  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
10  * of the GNU General Public License version 2.1.  This program is licensed
11  * "as is" without any warranty of any kind, whether express or implied.
12  */
13
14 /*
15  * This driver is a bit unusual in that it is composed of two logical
16  * parts where one part is the OS independent code and the other part is
17  * the OS dependent code.  Xilinx provides their drivers split in this
18  * fashion.  This file represents the Linux OS dependent part known as
19  * the Linux adapter.  The other files in this directory are the OS
20  * independent files as provided by Xilinx with no changes made to them.
21  * The names exported by those files begin with XGpio_.  All functions
22  * in this file that are called by Linux have names that begin with
23  * xgpio_.  Any other functions are static helper functions.
24  */
25
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/miscdevice.h>
30 #include <asm/io.h>
31 #include <asm/irq.h>
32 #include <asm/uaccess.h>
33
34 /* Use the IBM OCP definitions for compatibility. */
35 #include <linux/ibm_ocp_gpio.h>
36
37 #include <xbasic_types.h>
38 #include "xgpio.h"
39 #include "xgpio_i.h"
40
41 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
42 MODULE_DESCRIPTION("Xilinx GPIO driver");
43 MODULE_LICENSE("GPL");
44
45 /* Our private per interface data. */
46 struct xgpio_instance {
47         struct xgpio_instance *next_inst;       /* The next instance in inst_list */
48         int index;              /* Which interface is this */
49         u32 save_BaseAddress;   /* Saved physical base address */
50         /*
51          * The underlying OS independent code needs space as well.  A
52          * pointer to the following XGpio structure will be passed to
53          * any XGpio_ function that requires it.  However, we treat the
54          * data as an opaque object in this file (meaning that we never
55          * reference any of the fields inside of the structure).
56          */
57         XGpio Gpio;
58 };
59 /* List of instances we're handling. */
60 static struct xgpio_instance *inst_list = NULL;
61
62 /* SAATODO: This function will be moved into the Xilinx code. */
63 /*****************************************************************************/
64 /**
65 *
66 * Lookup the device configuration based on the GPIO instance.  The table
67 * XGpio_ConfigTable contains the configuration info for each device in the system.
68 *
69 * @param Instance is the index of the interface being looked up.
70 *
71 * @return
72 *
73 * A pointer to the configuration table entry corresponding to the given
74 * device ID, or NULL if no match is found.
75 *
76 * @note
77 *
78 * None.
79 *
80 ******************************************************************************/
81 XGpio_Config *XGpio_GetConfig(int Instance)
82 {
83         if (Instance < 0 || Instance >= XPAR_XGPIO_NUM_INSTANCES)
84         {
85                 return NULL;
86         }
87
88         return &XGpio_ConfigTable[Instance];
89 }
90
91 /* SAATODO: This function will be moved into the Xilinx code. */
92 /****************************************************************************/
93 /**
94 * Get the input/output direction of all discrete signals.
95 *
96 * @param InstancePtr is a pointer to an XGpio instance to be worked on.
97 *
98 * @return Current copy of the tristate (direction) register.
99 *
100 * @note
101 *
102 * None
103 *
104 *****************************************************************************/
105 u32
106 XGpio_GetDataDirection(XGpio * InstancePtr)
107 {
108         XASSERT_NONVOID(InstancePtr != NULL);
109         XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);
110         return XGpio_mReadReg(InstancePtr->BaseAddress, XGPIO_TRI_OFFSET);
111 }
112
113 static int
114 xgpio_open(struct inode *inode, struct file *file)
115 {
116         MOD_INC_USE_COUNT;
117
118         return 0;
119 }
120
121 static int
122 xgpio_release(struct inode *inode, struct file *file)
123 {
124         MOD_DEC_USE_COUNT;
125
126         return 0;
127 }
128
129 static int
130 ioctl_setup(unsigned long arg,
131             struct ibm_gpio_ioctl_data *ioctl_data,
132             struct xgpio_instance **match)
133 {
134         struct xgpio_instance *inst;
135
136         if (copy_from_user(ioctl_data, (void *) arg, sizeof (*ioctl_data)))
137                 return -EFAULT;
138
139         inst = inst_list;
140         while (inst && inst->index != ioctl_data->device)
141                 inst = inst->next_inst;
142
143         *match = inst;
144         return inst ? 0 : -ENODEV;
145 }
146
147 static int
148 xgpio_ioctl(struct inode *inode, struct file *file,
149             unsigned int cmd, unsigned long arg)
150 {
151         struct ibm_gpio_ioctl_data ioctl_data;
152         struct xgpio_instance *inst;
153         int status;
154         u32 r;
155
156         switch (cmd) {
157         case IBMGPIO_IN:
158                 status = ioctl_setup(arg, &ioctl_data, &inst);
159                 if (status < 0)
160                         return status;
161
162                 /* Ensure that the GPIO bits in the mask are tristated. */
163                 r = XGpio_GetDataDirection(&inst->Gpio);
164                 XGpio_SetDataDirection(&inst->Gpio, r & ~ioctl_data.mask);
165
166                 ioctl_data.data = (XGpio_DiscreteRead(&inst->Gpio)
167                                    & ioctl_data.mask);
168                 if (copy_to_user((struct ibm_gpio_ioctl_data *) arg,
169                                  &ioctl_data, sizeof (ioctl_data))) {
170                         return -EFAULT;
171                 }
172                 break;
173
174         case IBMGPIO_OUT:
175                 status = ioctl_setup(arg, &ioctl_data, &inst);
176                 if (status < 0)
177                         return status;
178
179                 /* Get the prior value. */
180                 r = XGpio_DiscreteRead(&inst->Gpio);
181                 /* Clear the bits that we're going to put in. */
182                 r &= ~ioctl_data.mask;
183                 /* Set the bits that were provided. */
184                 r |= (ioctl_data.mask & ioctl_data.data);
185
186                 XGpio_DiscreteWrite(&inst->Gpio, r);
187
188                 /* Ensure that the GPIO bits in the mask are not tristated. */
189                 r = XGpio_GetDataDirection(&inst->Gpio);
190                 XGpio_SetDataDirection(&inst->Gpio, r | ioctl_data.mask);
191
192                 break;
193
194         case IBMGPIO_TRISTATE:
195                 status = ioctl_setup(arg, &ioctl_data, &inst);
196                 if (status < 0)
197                         return status;
198
199                 /* Get the prior value. */
200                 r = XGpio_GetDataDirection(&inst->Gpio);
201                 /* Clear the bits that we're going to put in. */
202                 r &= ~ioctl_data.mask;
203                 /* Set the bits that were provided. */
204                 r |= (ioctl_data.mask & ioctl_data.data);
205
206                 XGpio_SetDataDirection(&inst->Gpio, r);
207                 break;
208
209         default:
210                 return -ENOIOCTLCMD;
211
212         }
213         return 0;
214 }
215
216 static void
217 remove_head_inst(void)
218 {
219         struct xgpio_instance *inst;
220         XGpio_Config *cfg;
221
222         /* Pull the head off of inst_list. */
223         inst = inst_list;
224         inst_list = inst->next_inst;
225
226         cfg = XGpio_GetConfig(inst->index);
227         iounmap((void *) cfg->BaseAddress);
228         cfg->BaseAddress = inst->save_BaseAddress;
229 }
230
231 static struct file_operations xfops = {
232         owner:THIS_MODULE,
233         ioctl:xgpio_ioctl,
234         open:xgpio_open,
235         release:xgpio_release,
236 };
237 /*
238  * We get to all of the GPIOs through one minor number.  Here's the
239  * miscdevice that gets registered for that minor number.
240  */
241 static struct miscdevice miscdev = {
242         minor:GPIO_MINOR,
243         name:"xgpio",
244         fops:&xfops
245 };
246
247 static int __init
248 probe(int index)
249 {
250         static const unsigned long remap_size
251             = XPAR_GPIO_0_HIGHADDR - XPAR_GPIO_0_BASEADDR + 1;
252         struct xgpio_instance *inst;
253         XGpio_Config *cfg;
254
255         /* Find the config for our instance. */
256         cfg = XGpio_GetConfig(index);
257         if (!cfg)
258                 return -ENODEV;
259
260         /* Allocate the inst and zero it out. */
261         inst = (struct xgpio_instance *) kmalloc(sizeof (struct xgpio_instance),
262                                                  GFP_KERNEL);
263         if (!inst) {
264                 printk(KERN_ERR "%s #%d: Could not allocate instance.\n",
265                        miscdev.name, index);
266                 return -ENOMEM;
267         }
268         memset(inst, 0, sizeof (struct xgpio_instance));
269
270         /* Make it the head of inst_list. */
271         inst->next_inst = inst_list;
272         inst_list = inst;
273
274         /* Change the addresses to be virtual; save the old ones to restore. */
275         inst->save_BaseAddress = cfg->BaseAddress;
276         cfg->BaseAddress = (u32) ioremap(inst->save_BaseAddress, remap_size);
277
278         /* Tell the Xilinx code to bring this GPIO interface up. */
279         if (XGpio_Initialize(&inst->Gpio, cfg->DeviceId) != XST_SUCCESS) {
280                 printk(KERN_ERR "%s #%d: Could not initialize instance.\n",
281                        miscdev.name, inst->index);
282                 remove_head_inst();
283                 return -ENODEV;
284         }
285
286         printk(KERN_INFO "%s #%d at 0x%08X mapped to 0x%08X\n",
287                miscdev.name, inst->index,
288                inst->save_BaseAddress, cfg->BaseAddress);
289
290         return 0;
291 }
292
293 static int __init
294 xgpio_init(void)
295 {
296         int rtn, index = 0;
297
298         while (probe(index++) == 0) ;
299
300         if (index > 1) {
301                 /* We found at least one instance. */
302
303                 /* Register the driver with misc and report success. */
304                 rtn = misc_register(&miscdev);
305                 if (rtn) {
306                         printk(KERN_ERR "%s: Could not register driver.\n",
307                                miscdev.name);
308                         while (inst_list)
309                                 remove_head_inst();
310                         return rtn;
311                 }
312
313                 /* Report success. */
314                 return 0;
315         } else {
316                 /* No instances found. */
317                 return -ENODEV;
318         }
319
320 }
321
322 static void __exit
323 xgpio_cleanup(void)
324 {
325         while (inst_list)
326                 remove_head_inst();
327
328         misc_deregister(&miscdev);
329 }
330
331 EXPORT_NO_SYMBOLS;
332
333 module_init(xgpio_init);
334 module_exit(xgpio_cleanup);