Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tb0219.c
Go to the documentation of this file.
1 /*
2  * Driver for TANBAC TB0219 base board.
3  *
4  * Copyright (C) 2005 Yoichi Yuasa <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 #include <linux/platform_device.h>
21 #include <linux/fs.h>
22 #include <linux/init.h>
23 #include <linux/module.h>
24 
25 #include <asm/io.h>
26 #include <asm/reboot.h>
27 #include <asm/vr41xx/giu.h>
28 #include <asm/vr41xx/tb0219.h>
29 
30 MODULE_AUTHOR("Yoichi Yuasa <[email protected]>");
31 MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
32 MODULE_LICENSE("GPL");
33 
34 static int major; /* default is dynamic major device number */
35 module_param(major, int, 0);
36 MODULE_PARM_DESC(major, "Major device number");
37 
38 static void (*old_machine_restart)(char *command);
39 static void __iomem *tb0219_base;
40 static DEFINE_SPINLOCK(tb0219_lock);
41 
42 #define tb0219_read(offset) readw(tb0219_base + (offset))
43 #define tb0219_write(offset, value) writew((value), tb0219_base + (offset))
44 
45 #define TB0219_START 0x0a000000UL
46 #define TB0219_SIZE 0x20UL
47 
48 #define TB0219_LED 0x00
49 #define TB0219_GPIO_INPUT 0x02
50 #define TB0219_GPIO_OUTPUT 0x04
51 #define TB0219_DIP_SWITCH 0x06
52 #define TB0219_MISC 0x08
53 #define TB0219_RESET 0x0e
54 #define TB0219_PCI_SLOT1_IRQ_STATUS 0x10
55 #define TB0219_PCI_SLOT2_IRQ_STATUS 0x12
56 #define TB0219_PCI_SLOT3_IRQ_STATUS 0x14
57 
58 typedef enum {
62 
63 /*
64  * Minor device number
65  * 0 = 7 segment LED
66  *
67  * 16 = GPIO IN 0
68  * 17 = GPIO IN 1
69  * 18 = GPIO IN 2
70  * 19 = GPIO IN 3
71  * 20 = GPIO IN 4
72  * 21 = GPIO IN 5
73  * 22 = GPIO IN 6
74  * 23 = GPIO IN 7
75  *
76  * 32 = GPIO OUT 0
77  * 33 = GPIO OUT 1
78  * 34 = GPIO OUT 2
79  * 35 = GPIO OUT 3
80  * 36 = GPIO OUT 4
81  * 37 = GPIO OUT 5
82  * 38 = GPIO OUT 6
83  * 39 = GPIO OUT 7
84  *
85  * 48 = DIP switch 1
86  * 49 = DIP switch 2
87  * 50 = DIP switch 3
88  * 51 = DIP switch 4
89  * 52 = DIP switch 5
90  * 53 = DIP switch 6
91  * 54 = DIP switch 7
92  * 55 = DIP switch 8
93  */
94 
95 static inline char get_led(void)
96 {
97  return (char)tb0219_read(TB0219_LED);
98 }
99 
100 static inline char get_gpio_input_pin(unsigned int pin)
101 {
103 
104  values = tb0219_read(TB0219_GPIO_INPUT);
105  if (values & (1 << pin))
106  return '1';
107 
108  return '0';
109 }
110 
111 static inline char get_gpio_output_pin(unsigned int pin)
112 {
114 
116  if (values & (1 << pin))
117  return '1';
118 
119  return '0';
120 }
121 
122 static inline char get_dip_switch(unsigned int pin)
123 {
125 
126  values = tb0219_read(TB0219_DIP_SWITCH);
127  if (values & (1 << pin))
128  return '1';
129 
130  return '0';
131 }
132 
133 static inline int set_led(char command)
134 {
135  tb0219_write(TB0219_LED, command);
136 
137  return 0;
138 }
139 
140 static inline int set_gpio_output_pin(unsigned int pin, char command)
141 {
142  unsigned long flags;
143  uint16_t value;
144 
145  if (command != '0' && command != '1')
146  return -EINVAL;
147 
148  spin_lock_irqsave(&tb0219_lock, flags);
150  if (command == '0')
151  value &= ~(1 << pin);
152  else
153  value |= 1 << pin;
155  spin_unlock_irqrestore(&tb0219_lock, flags);
156 
157  return 0;
158 
159 }
160 
161 static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len,
162  loff_t *ppos)
163 {
164  unsigned int minor;
165  char value;
166 
167  minor = iminor(file->f_path.dentry->d_inode);
168  switch (minor) {
169  case 0:
170  value = get_led();
171  break;
172  case 16 ... 23:
173  value = get_gpio_input_pin(minor - 16);
174  break;
175  case 32 ... 39:
176  value = get_gpio_output_pin(minor - 32);
177  break;
178  case 48 ... 55:
179  value = get_dip_switch(minor - 48);
180  break;
181  default:
182  return -EBADF;
183  }
184 
185  if (len <= 0)
186  return -EFAULT;
187 
188  if (put_user(value, buf))
189  return -EFAULT;
190 
191  return 1;
192 }
193 
194 static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
195  size_t len, loff_t *ppos)
196 {
197  unsigned int minor;
199  size_t i;
200  int retval = 0;
201  char c;
202 
203  minor = iminor(file->f_path.dentry->d_inode);
204  switch (minor) {
205  case 0:
206  type = TYPE_LED;
207  break;
208  case 32 ... 39:
209  type = TYPE_GPIO_OUTPUT;
210  break;
211  default:
212  return -EBADF;
213  }
214 
215  for (i = 0; i < len; i++) {
216  if (get_user(c, data + i))
217  return -EFAULT;
218 
219  switch (type) {
220  case TYPE_LED:
221  retval = set_led(c);
222  break;
223  case TYPE_GPIO_OUTPUT:
224  retval = set_gpio_output_pin(minor - 32, c);
225  break;
226  }
227 
228  if (retval < 0)
229  break;
230  }
231 
232  return i;
233 }
234 
235 static int tanbac_tb0219_open(struct inode *inode, struct file *file)
236 {
237  unsigned int minor;
238 
239  minor = iminor(inode);
240  switch (minor) {
241  case 0:
242  case 16 ... 23:
243  case 32 ... 39:
244  case 48 ... 55:
245  return nonseekable_open(inode, file);
246  default:
247  break;
248  }
249 
250  return -EBADF;
251 }
252 
253 static int tanbac_tb0219_release(struct inode *inode, struct file *file)
254 {
255  return 0;
256 }
257 
258 static const struct file_operations tb0219_fops = {
259  .owner = THIS_MODULE,
260  .read = tanbac_tb0219_read,
261  .write = tanbac_tb0219_write,
262  .open = tanbac_tb0219_open,
263  .release = tanbac_tb0219_release,
264  .llseek = no_llseek,
265 };
266 
267 static void tb0219_restart(char *command)
268 {
270 }
271 
272 static void tb0219_pci_irq_init(void)
273 {
274  /* PCI Slot 1 */
277 
278  /* PCI Slot 2 */
281 
282  /* PCI Slot 3 */
285 }
286 
287 static int __devinit tb0219_probe(struct platform_device *dev)
288 {
289  int retval;
290 
291  if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL)
292  return -EBUSY;
293 
294  tb0219_base = ioremap(TB0219_START, TB0219_SIZE);
295  if (tb0219_base == NULL) {
297  return -ENOMEM;
298  }
299 
300  retval = register_chrdev(major, "TB0219", &tb0219_fops);
301  if (retval < 0) {
302  iounmap(tb0219_base);
303  tb0219_base = NULL;
305  return retval;
306  }
307 
308  old_machine_restart = _machine_restart;
309  _machine_restart = tb0219_restart;
310 
311  tb0219_pci_irq_init();
312 
313  if (major == 0) {
314  major = retval;
315  printk(KERN_INFO "TB0219: major number %d\n", major);
316  }
317 
318  return 0;
319 }
320 
321 static int __devexit tb0219_remove(struct platform_device *dev)
322 {
323  _machine_restart = old_machine_restart;
324 
325  iounmap(tb0219_base);
326  tb0219_base = NULL;
327 
329 
330  return 0;
331 }
332 
333 static struct platform_device *tb0219_platform_device;
334 
335 static struct platform_driver tb0219_device_driver = {
336  .probe = tb0219_probe,
337  .remove = __devexit_p(tb0219_remove),
338  .driver = {
339  .name = "TB0219",
340  .owner = THIS_MODULE,
341  },
342 };
343 
344 static int __init tanbac_tb0219_init(void)
345 {
346  int retval;
347 
348  tb0219_platform_device = platform_device_alloc("TB0219", -1);
349  if (!tb0219_platform_device)
350  return -ENOMEM;
351 
352  retval = platform_device_add(tb0219_platform_device);
353  if (retval < 0) {
354  platform_device_put(tb0219_platform_device);
355  return retval;
356  }
357 
358  retval = platform_driver_register(&tb0219_device_driver);
359  if (retval < 0)
360  platform_device_unregister(tb0219_platform_device);
361 
362  return retval;
363 }
364 
365 static void __exit tanbac_tb0219_exit(void)
366 {
367  platform_driver_unregister(&tb0219_device_driver);
368  platform_device_unregister(tb0219_platform_device);
369 }
370 
371 module_init(tanbac_tb0219_init);
372 module_exit(tanbac_tb0219_exit);