2  *  Driver for TANBAC TB0219 base board.
 
   4  *  Copyright (C) 2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
 
   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.
 
  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.
 
  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
 
  20 #include <linux/platform_device.h>
 
  22 #include <linux/init.h>
 
  23 #include <linux/module.h>
 
  26 #include <asm/reboot.h>
 
  27 #include <asm/vr41xx/giu.h>
 
  28 #include <asm/vr41xx/tb0219.h>
 
  30 MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
 
  31 MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
 
  32 MODULE_LICENSE("GPL");
 
  34 static int major;       /* default is dynamic major device number */
 
  35 module_param(major, int, 0);
 
  36 MODULE_PARM_DESC(major, "Major device number");
 
  38 static void (*old_machine_restart)(char *command);
 
  39 static void __iomem *tb0219_base;
 
  40 static spinlock_t tb0219_lock;
 
  42 #define tb0219_read(offset)             readw(tb0219_base + (offset))
 
  43 #define tb0219_write(offset, value)     writew((value), tb0219_base + (offset))
 
  45 #define TB0219_START    0x0a000000UL
 
  46 #define TB0219_SIZE     0x20UL
 
  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
 
  95 static inline char get_led(void)
 
  97         return (char)tb0219_read(TB0219_LED);
 
 100 static inline char get_gpio_input_pin(unsigned int pin)
 
 104         values = tb0219_read(TB0219_GPIO_INPUT);
 
 105         if (values & (1 << pin))
 
 111 static inline char get_gpio_output_pin(unsigned int pin)
 
 115         values = tb0219_read(TB0219_GPIO_OUTPUT);
 
 116         if (values & (1 << pin))
 
 122 static inline char get_dip_switch(unsigned int pin)
 
 126         values = tb0219_read(TB0219_DIP_SWITCH);
 
 127         if (values & (1 << pin))
 
 133 static inline int set_led(char command)
 
 135         tb0219_write(TB0219_LED, command);
 
 140 static inline int set_gpio_output_pin(unsigned int pin, char command)
 
 145         if (command != '0' && command != '1')
 
 148         spin_lock_irqsave(&tb0219_lock, flags);
 
 149         value = tb0219_read(TB0219_GPIO_OUTPUT);
 
 151                 value &= ~(1 << pin);
 
 154         tb0219_write(TB0219_GPIO_OUTPUT, value);
 
 155         spin_unlock_irqrestore(&tb0219_lock, flags);
 
 161 static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len,
 
 167         minor = iminor(file->f_dentry->d_inode);
 
 173                 value = get_gpio_input_pin(minor - 16);
 
 176                 value = get_gpio_output_pin(minor - 32);
 
 179                 value = get_dip_switch(minor - 48);
 
 188         if (put_user(value, buf))
 
 194 static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
 
 195                                    size_t len, loff_t *ppos)
 
 203         minor = iminor(file->f_dentry->d_inode);
 
 209                 type = TYPE_GPIO_OUTPUT;
 
 215         for (i = 0; i < len; i++) {
 
 216                 if (get_user(c, data + i))
 
 223                 case TYPE_GPIO_OUTPUT:
 
 224                         retval = set_gpio_output_pin(minor - 32, c);
 
 235 static int tanbac_tb0219_open(struct inode *inode, struct file *file)
 
 239         minor = iminor(inode);
 
 245                 return nonseekable_open(inode, file);
 
 253 static int tanbac_tb0219_release(struct inode *inode, struct file *file)
 
 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,
 
 266 static void tb0219_restart(char *command)
 
 268         tb0219_write(TB0219_RESET, 0);
 
 271 static void tb0219_pci_irq_init(void)
 
 274         vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 
 275         vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW);
 
 278         vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 
 279         vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW);
 
 282         vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 
 283         vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
 
 286 static int __devinit tb0219_probe(struct platform_device *dev)
 
 290         if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL)
 
 293         tb0219_base = ioremap(TB0219_START, TB0219_SIZE);
 
 294         if (tb0219_base == NULL) {
 
 295                 release_mem_region(TB0219_START, TB0219_SIZE);
 
 299         retval = register_chrdev(major, "TB0219", &tb0219_fops);
 
 301                 iounmap(tb0219_base);
 
 303                 release_mem_region(TB0219_START, TB0219_SIZE);
 
 307         spin_lock_init(&tb0219_lock);
 
 309         old_machine_restart = _machine_restart;
 
 310         _machine_restart = tb0219_restart;
 
 312         tb0219_pci_irq_init();
 
 316                 printk(KERN_INFO "TB0219: major number %d\n", major);
 
 322 static int __devexit tb0219_remove(struct platform_device *dev)
 
 324         _machine_restart = old_machine_restart;
 
 326         iounmap(tb0219_base);
 
 329         release_mem_region(TB0219_START, TB0219_SIZE);
 
 334 static struct platform_device *tb0219_platform_device;
 
 336 static struct platform_driver tb0219_device_driver = {
 
 337         .probe          = tb0219_probe,
 
 338         .remove         = __devexit_p(tb0219_remove),
 
 341                 .owner  = THIS_MODULE,
 
 345 static int __init tanbac_tb0219_init(void)
 
 349         tb0219_platform_device = platform_device_alloc("TB0219", -1);
 
 350         if (!tb0219_platform_device)
 
 353         retval = platform_device_add(tb0219_platform_device);
 
 355                 platform_device_put(tb0219_platform_device);
 
 359         retval = platform_driver_register(&tb0219_device_driver);
 
 361                 platform_device_unregister(tb0219_platform_device);
 
 366 static void __exit tanbac_tb0219_exit(void)
 
 368         platform_driver_unregister(&tb0219_device_driver);
 
 369         platform_device_unregister(tb0219_platform_device);
 
 372 module_init(tanbac_tb0219_init);
 
 373 module_exit(tanbac_tb0219_exit);