Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / sh / boards / landisk / landisk_pwb.c
1 /*
2  * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
3  *
4  * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  *
10  * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
11  *
12  * LED control drive function added by kogiidena
13  */
14 #include <linux/module.h>
15 #include <linux/errno.h>
16 #include <linux/signal.h>
17 #include <linux/major.h>
18 #include <linux/poll.h>
19 #include <linux/init.h>
20 #include <linux/delay.h>
21 #include <linux/sched.h>
22 #include <linux/timer.h>
23 #include <linux/interrupt.h>
24
25 #include <asm/system.h>
26 #include <asm/io.h>
27 #include <asm/irq.h>
28 #include <asm/uaccess.h>
29 #include <asm/landisk/iodata_landisk.h>
30
31 #define SHUTDOWN_BTN_MINOR      1       /* Shutdown button device minor no. */
32 #define LED_MINOR              21       /* LED minor no. */
33 #define BTN_MINOR              22       /* BUTTON minor no. */
34 #define GIO_MINOR              40       /* GIO minor no. */
35
36 static int openCnt;
37 static int openCntLED;
38 static int openCntGio;
39 static int openCntBtn;
40 static int landisk_btn;
41 static int landisk_btnctrlpid;
42 /*
43  * Functions prototypes
44  */
45
46 static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
47                      unsigned long arg);
48
49 static int swdrv_open(struct inode *inode, struct file *filp)
50 {
51         int minor;
52
53         minor = MINOR(inode->i_rdev);
54         filp->private_data = (void *)minor;
55
56         if (minor == SHUTDOWN_BTN_MINOR) {
57                 if (openCnt > 0) {
58                         return -EALREADY;
59                 } else {
60                         openCnt++;
61                         return 0;
62                 }
63         } else if (minor == LED_MINOR) {
64                 if (openCntLED > 0) {
65                         return -EALREADY;
66                 } else {
67                         openCntLED++;
68                         return 0;
69                 }
70         } else if (minor == BTN_MINOR) {
71                 if (openCntBtn > 0) {
72                         return -EALREADY;
73                 } else {
74                         openCntBtn++;
75                         return 0;
76                 }
77         } else if (minor == GIO_MINOR) {
78                 if (openCntGio > 0) {
79                         return -EALREADY;
80                 } else {
81                         openCntGio++;
82                         return 0;
83                 }
84         }
85         return -ENOENT;
86
87 }
88
89 static int swdrv_close(struct inode *inode, struct file *filp)
90 {
91         int minor;
92
93         minor = MINOR(inode->i_rdev);
94         if (minor == SHUTDOWN_BTN_MINOR) {
95                 openCnt--;
96         } else if (minor == LED_MINOR) {
97                 openCntLED--;
98         } else if (minor == BTN_MINOR) {
99                 openCntBtn--;
100         } else if (minor == GIO_MINOR) {
101                 openCntGio--;
102         }
103         return 0;
104 }
105
106 static int swdrv_read(struct file *filp, char *buff, size_t count,
107                       loff_t * ppos)
108 {
109         int minor;
110         minor = (int)(filp->private_data);
111
112         if (!access_ok(VERIFY_WRITE, (void *)buff, count))
113                 return -EFAULT;
114
115         if (minor == SHUTDOWN_BTN_MINOR) {
116                 if (landisk_btn & 0x10) {
117                         put_user(1, buff);
118                         return 1;
119                 } else {
120                         return 0;
121                 }
122         }
123         return 0;
124 }
125
126 static int swdrv_write(struct file *filp, const char *buff, size_t count,
127                        loff_t * ppos)
128 {
129         int minor;
130         minor = (int)(filp->private_data);
131
132         if (minor == SHUTDOWN_BTN_MINOR) {
133                 return count;
134         }
135         return count;
136 }
137
138 static irqreturn_t sw_interrupt(int irq, void *dev_id)
139 {
140         landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
141         disable_irq(IRQ_BUTTON);
142         disable_irq(IRQ_POWER);
143         ctrl_outb(0x00, PA_PWRINT_CLR);
144
145         if (landisk_btnctrlpid != 0) {
146                 kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
147                 landisk_btnctrlpid = 0;
148         }
149
150         return IRQ_HANDLED;
151 }
152
153 static struct file_operations swdrv_fops = {
154         .read = swdrv_read,     /* read */
155         .write = swdrv_write,   /* write */
156         .open = swdrv_open,     /* open */
157         .release = swdrv_close, /* release */
158         .ioctl = gio_ioctl,     /* ioctl */
159
160 };
161
162 static char banner[] __initdata =
163     KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";
164
165 int __init swdrv_init(void)
166 {
167         int error;
168
169         printk("%s", banner);
170
171         openCnt = 0;
172         openCntLED = 0;
173         openCntBtn = 0;
174         openCntGio = 0;
175         landisk_btn = 0;
176         landisk_btnctrlpid = 0;
177
178         if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
179                 printk(KERN_ERR
180                        "Button, LED and GIO driver:Couldn't register driver, error=%d\n",
181                        error);
182                 return 1;
183         }
184
185         if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
186                 printk(KERN_ERR "Unable to get IRQ 11.\n");
187                 return 1;
188         }
189         if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
190                 printk(KERN_ERR "Unable to get IRQ 12.\n");
191                 return 1;
192         }
193         ctrl_outb(0x00, PA_PWRINT_CLR);
194
195         return 0;
196 }
197
198 module_init(swdrv_init);
199
200 /*
201  * gio driver
202  *
203  */
204
205 #include <asm/landisk/gio.h>
206
207 static int gio_ioctl(struct inode *inode, struct file *filp,
208                      unsigned int cmd, unsigned long arg)
209 {
210         int minor;
211         unsigned int data, mask;
212         static unsigned int addr = 0;
213
214         minor = (int)(filp->private_data);
215
216         /* access control */
217         if (minor == GIO_MINOR) {
218                 ;
219         } else if (minor == LED_MINOR) {
220                 if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
221                         ;
222                 } else {
223                         return -EINVAL;
224                 }
225         } else if (minor == BTN_MINOR) {
226                 if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
227                         ;
228                 } else {
229                         return -EINVAL;
230                 }
231         } else {
232                 return -EINVAL;
233         }
234
235         if (cmd & 0x01) {       /* write */
236                 if (copy_from_user(&data, (int *)arg, sizeof(int))) {
237                         return -EFAULT;
238                 }
239         }
240
241         switch (cmd) {
242         case GIODRV_IOCSGIOSETADDR:     /* addres set */
243                 addr = data;
244                 break;
245
246         case GIODRV_IOCSGIODATA1:       /* write byte */
247                 ctrl_outb((unsigned char)(0x0ff & data), addr);
248                 break;
249
250         case GIODRV_IOCSGIODATA2:       /* write word */
251                 if (addr & 0x01) {
252                         return -EFAULT;
253                 }
254                 ctrl_outw((unsigned short int)(0x0ffff & data), addr);
255                 break;
256
257         case GIODRV_IOCSGIODATA4:       /* write long */
258                 if (addr & 0x03) {
259                         return -EFAULT;
260                 }
261                 ctrl_outl(data, addr);
262                 break;
263
264         case GIODRV_IOCGGIODATA1:       /* read byte */
265                 data = ctrl_inb(addr);
266                 break;
267
268         case GIODRV_IOCGGIODATA2:       /* read word */
269                 if (addr & 0x01) {
270                         return -EFAULT;
271                 }
272                 data = ctrl_inw(addr);
273                 break;
274
275         case GIODRV_IOCGGIODATA4:       /* read long */
276                 if (addr & 0x03) {
277                         return -EFAULT;
278                 }
279                 data = ctrl_inl(addr);
280                 break;
281         case GIODRV_IOCSGIO_LED:        /* write */
282                 mask = ((data & 0x00ffffff) << 8)
283                     | ((data & 0x0000ffff) << 16)
284                     | ((data & 0x000000ff) << 24);
285                 landisk_ledparam = data & (~mask);
286                 if (landisk_arch == 0) {        /* arch == landisk */
287                         landisk_ledparam &= 0x03030303;
288                         mask = (~(landisk_ledparam >> 22)) & 0x000c;
289                         landisk_ledparam |= mask;
290                 } else {                        /* arch == usl-5p */
291                         mask = (landisk_ledparam >> 24) & 0x0001;
292                         landisk_ledparam |= mask;
293                         landisk_ledparam &= 0x007f7f7f;
294                 }
295                 landisk_ledparam |= 0x80;
296                 break;
297         case GIODRV_IOCGGIO_LED:        /* read */
298                 data = landisk_ledparam;
299                 if (landisk_arch == 0) {        /* arch == landisk */
300                         data &= 0x03030303;
301                 } else {                        /* arch == usl-5p */
302                         ;
303                 }
304                 data &= (~0x080);
305                 break;
306         case GIODRV_IOCSGIO_BUZZER:     /* write */
307                 landisk_buzzerparam = data;
308                 landisk_ledparam |= 0x80;
309                 break;
310         case GIODRV_IOCGGIO_LANDISK:    /* read */
311                 data = landisk_arch & 0x01;
312                 break;
313         case GIODRV_IOCGGIO_BTN:        /* read */
314                 data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
315                 data <<= 8;
316                 data |= (0x0ff & ctrl_inb(PA_IMASK));
317                 data <<= 8;
318                 data |= (0x0ff & landisk_btn);
319                 data <<= 8;
320                 data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
321                 break;
322         case GIODRV_IOCSGIO_BTNPID:     /* write */
323                 landisk_btnctrlpid = data;
324                 landisk_btn = 0;
325                 if (irq_desc[IRQ_BUTTON].depth) {
326                         enable_irq(IRQ_BUTTON);
327                 }
328                 if (irq_desc[IRQ_POWER].depth) {
329                         enable_irq(IRQ_POWER);
330                 }
331                 break;
332         case GIODRV_IOCGGIO_BTNPID:     /* read */
333                 data = landisk_btnctrlpid;
334                 break;
335         default:
336                 return -EFAULT;
337                 break;
338         }
339
340         if ((cmd & 0x01) == 0) {        /* read */
341                 if (copy_to_user((int *)arg, &data, sizeof(int))) {
342                         return -EFAULT;
343                 }
344         }
345         return 0;
346 }