root/drivers/char/tb0219.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_led
  2. get_gpio_input_pin
  3. get_gpio_output_pin
  4. get_dip_switch
  5. set_led
  6. set_gpio_output_pin
  7. tanbac_tb0219_read
  8. tanbac_tb0219_write
  9. tanbac_tb0219_open
  10. tanbac_tb0219_release
  11. tb0219_restart
  12. tb0219_pci_irq_init
  13. tb0219_probe
  14. tb0219_remove
  15. tanbac_tb0219_init
  16. tanbac_tb0219_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Driver for TANBAC TB0219 base board.
   4  *
   5  *  Copyright (C) 2005  Yoichi Yuasa <yuasa@linux-mips.org>
   6  */
   7 #include <linux/platform_device.h>
   8 #include <linux/fs.h>
   9 #include <linux/init.h>
  10 #include <linux/module.h>
  11 #include <linux/uaccess.h>
  12 
  13 #include <asm/io.h>
  14 #include <asm/reboot.h>
  15 #include <asm/vr41xx/giu.h>
  16 #include <asm/vr41xx/tb0219.h>
  17 
  18 MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
  19 MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
  20 MODULE_LICENSE("GPL");
  21 
  22 static int major;       /* default is dynamic major device number */
  23 module_param(major, int, 0);
  24 MODULE_PARM_DESC(major, "Major device number");
  25 
  26 static void (*old_machine_restart)(char *command);
  27 static void __iomem *tb0219_base;
  28 static DEFINE_SPINLOCK(tb0219_lock);
  29 
  30 #define tb0219_read(offset)             readw(tb0219_base + (offset))
  31 #define tb0219_write(offset, value)     writew((value), tb0219_base + (offset))
  32 
  33 #define TB0219_START    0x0a000000UL
  34 #define TB0219_SIZE     0x20UL
  35 
  36 #define TB0219_LED                      0x00
  37 #define TB0219_GPIO_INPUT               0x02
  38 #define TB0219_GPIO_OUTPUT              0x04
  39 #define TB0219_DIP_SWITCH               0x06
  40 #define TB0219_MISC                     0x08
  41 #define TB0219_RESET                    0x0e
  42 #define TB0219_PCI_SLOT1_IRQ_STATUS     0x10
  43 #define TB0219_PCI_SLOT2_IRQ_STATUS     0x12
  44 #define TB0219_PCI_SLOT3_IRQ_STATUS     0x14
  45 
  46 typedef enum {
  47         TYPE_LED,
  48         TYPE_GPIO_OUTPUT,
  49 } tb0219_type_t;
  50 
  51 /*
  52  * Minor device number
  53  *       0 = 7 segment LED
  54  *
  55  *      16 = GPIO IN 0
  56  *      17 = GPIO IN 1
  57  *      18 = GPIO IN 2
  58  *      19 = GPIO IN 3
  59  *      20 = GPIO IN 4
  60  *      21 = GPIO IN 5
  61  *      22 = GPIO IN 6
  62  *      23 = GPIO IN 7
  63  *
  64  *      32 = GPIO OUT 0
  65  *      33 = GPIO OUT 1
  66  *      34 = GPIO OUT 2
  67  *      35 = GPIO OUT 3
  68  *      36 = GPIO OUT 4
  69  *      37 = GPIO OUT 5
  70  *      38 = GPIO OUT 6
  71  *      39 = GPIO OUT 7
  72  *
  73  *      48 = DIP switch 1
  74  *      49 = DIP switch 2
  75  *      50 = DIP switch 3
  76  *      51 = DIP switch 4
  77  *      52 = DIP switch 5
  78  *      53 = DIP switch 6
  79  *      54 = DIP switch 7
  80  *      55 = DIP switch 8
  81  */
  82 
  83 static inline char get_led(void)
  84 {
  85         return (char)tb0219_read(TB0219_LED);
  86 }
  87 
  88 static inline char get_gpio_input_pin(unsigned int pin)
  89 {
  90         uint16_t values;
  91 
  92         values = tb0219_read(TB0219_GPIO_INPUT);
  93         if (values & (1 << pin))
  94                 return '1';
  95 
  96         return '0';
  97 }
  98 
  99 static inline char get_gpio_output_pin(unsigned int pin)
 100 {
 101         uint16_t values;
 102 
 103         values = tb0219_read(TB0219_GPIO_OUTPUT);
 104         if (values & (1 << pin))
 105                 return '1';
 106 
 107         return '0';
 108 }
 109 
 110 static inline char get_dip_switch(unsigned int pin)
 111 {
 112         uint16_t values;
 113 
 114         values = tb0219_read(TB0219_DIP_SWITCH);
 115         if (values & (1 << pin))
 116                 return '1';
 117 
 118         return '0';
 119 }
 120 
 121 static inline int set_led(char command)
 122 {
 123         tb0219_write(TB0219_LED, command);
 124 
 125         return 0;
 126 }
 127 
 128 static inline int set_gpio_output_pin(unsigned int pin, char command)
 129 {
 130         unsigned long flags;
 131         uint16_t value;
 132 
 133         if (command != '0' && command != '1')
 134                 return -EINVAL;
 135 
 136         spin_lock_irqsave(&tb0219_lock, flags);
 137         value = tb0219_read(TB0219_GPIO_OUTPUT);
 138         if (command == '0')
 139                 value &= ~(1 << pin);
 140         else
 141                 value |= 1 << pin;
 142         tb0219_write(TB0219_GPIO_OUTPUT, value);
 143         spin_unlock_irqrestore(&tb0219_lock, flags);
 144 
 145         return 0;
 146 
 147 }
 148 
 149 static ssize_t tanbac_tb0219_read(struct file *file, char __user *buf, size_t len,
 150                                   loff_t *ppos)
 151 {
 152         unsigned int minor;
 153         char value;
 154 
 155         minor = iminor(file_inode(file));
 156         switch (minor) {
 157         case 0:
 158                 value = get_led();
 159                 break;
 160         case 16 ... 23:
 161                 value = get_gpio_input_pin(minor - 16);
 162                 break;
 163         case 32 ... 39:
 164                 value = get_gpio_output_pin(minor - 32);
 165                 break;
 166         case 48 ... 55:
 167                 value = get_dip_switch(minor - 48);
 168                 break;
 169         default:
 170                 return -EBADF;
 171         }
 172 
 173         if (len <= 0)
 174                 return -EFAULT;
 175 
 176         if (put_user(value, buf))
 177                 return -EFAULT;
 178 
 179         return 1;
 180 }
 181 
 182 static ssize_t tanbac_tb0219_write(struct file *file, const char __user *data,
 183                                    size_t len, loff_t *ppos)
 184 {
 185         unsigned int minor;
 186         tb0219_type_t type;
 187         size_t i;
 188         int retval = 0;
 189         char c;
 190 
 191         minor = iminor(file_inode(file));
 192         switch (minor) {
 193         case 0:
 194                 type = TYPE_LED;
 195                 break;
 196         case 32 ... 39:
 197                 type = TYPE_GPIO_OUTPUT;
 198                 break;
 199         default:
 200                 return -EBADF;
 201         }
 202 
 203         for (i = 0; i < len; i++) {
 204                 if (get_user(c, data + i))
 205                         return -EFAULT;
 206 
 207                 switch (type) {
 208                 case TYPE_LED:
 209                         retval = set_led(c);
 210                         break;
 211                 case TYPE_GPIO_OUTPUT:
 212                         retval = set_gpio_output_pin(minor - 32, c);
 213                         break;
 214                 }
 215 
 216                 if (retval < 0)
 217                         break;
 218         }
 219 
 220         return i;
 221 }
 222 
 223 static int tanbac_tb0219_open(struct inode *inode, struct file *file)
 224 {
 225         unsigned int minor;
 226 
 227         minor = iminor(inode);
 228         switch (minor) {
 229         case 0:
 230         case 16 ... 23:
 231         case 32 ... 39:
 232         case 48 ... 55:
 233                 return stream_open(inode, file);
 234         default:
 235                 break;
 236         }
 237 
 238         return -EBADF;
 239 }
 240 
 241 static int tanbac_tb0219_release(struct inode *inode, struct file *file)
 242 {
 243         return 0;
 244 }
 245 
 246 static const struct file_operations tb0219_fops = {
 247         .owner          = THIS_MODULE,
 248         .read           = tanbac_tb0219_read,
 249         .write          = tanbac_tb0219_write,
 250         .open           = tanbac_tb0219_open,
 251         .release        = tanbac_tb0219_release,
 252         .llseek         = no_llseek,
 253 };
 254 
 255 static void tb0219_restart(char *command)
 256 {
 257         tb0219_write(TB0219_RESET, 0);
 258 }
 259 
 260 static void tb0219_pci_irq_init(void)
 261 {
 262         /* PCI Slot 1 */
 263         vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 264         vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW);
 265 
 266         /* PCI Slot 2 */
 267         vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 268         vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW);
 269 
 270         /* PCI Slot 3 */
 271         vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
 272         vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
 273 }
 274 
 275 static int tb0219_probe(struct platform_device *dev)
 276 {
 277         int retval;
 278 
 279         if (request_mem_region(TB0219_START, TB0219_SIZE, "TB0219") == NULL)
 280                 return -EBUSY;
 281 
 282         tb0219_base = ioremap(TB0219_START, TB0219_SIZE);
 283         if (tb0219_base == NULL) {
 284                 release_mem_region(TB0219_START, TB0219_SIZE);
 285                 return -ENOMEM;
 286         }
 287 
 288         retval = register_chrdev(major, "TB0219", &tb0219_fops);
 289         if (retval < 0) {
 290                 iounmap(tb0219_base);
 291                 tb0219_base = NULL;
 292                 release_mem_region(TB0219_START, TB0219_SIZE);
 293                 return retval;
 294         }
 295 
 296         old_machine_restart = _machine_restart;
 297         _machine_restart = tb0219_restart;
 298 
 299         tb0219_pci_irq_init();
 300 
 301         if (major == 0) {
 302                 major = retval;
 303                 printk(KERN_INFO "TB0219: major number %d\n", major);
 304         }
 305 
 306         return 0;
 307 }
 308 
 309 static int tb0219_remove(struct platform_device *dev)
 310 {
 311         _machine_restart = old_machine_restart;
 312 
 313         iounmap(tb0219_base);
 314         tb0219_base = NULL;
 315 
 316         release_mem_region(TB0219_START, TB0219_SIZE);
 317 
 318         return 0;
 319 }
 320 
 321 static struct platform_device *tb0219_platform_device;
 322 
 323 static struct platform_driver tb0219_device_driver = {
 324         .probe          = tb0219_probe,
 325         .remove         = tb0219_remove,
 326         .driver         = {
 327                 .name   = "TB0219",
 328         },
 329 };
 330 
 331 static int __init tanbac_tb0219_init(void)
 332 {
 333         int retval;
 334 
 335         tb0219_platform_device = platform_device_alloc("TB0219", -1);
 336         if (!tb0219_platform_device)
 337                 return -ENOMEM;
 338 
 339         retval = platform_device_add(tb0219_platform_device);
 340         if (retval < 0) {
 341                 platform_device_put(tb0219_platform_device);
 342                 return retval;
 343         }
 344 
 345         retval = platform_driver_register(&tb0219_device_driver);
 346         if (retval < 0)
 347                 platform_device_unregister(tb0219_platform_device);
 348 
 349         return retval;
 350 }
 351 
 352 static void __exit tanbac_tb0219_exit(void)
 353 {
 354         platform_driver_unregister(&tb0219_device_driver);
 355         platform_device_unregister(tb0219_platform_device);
 356 }
 357 
 358 module_init(tanbac_tb0219_init);
 359 module_exit(tanbac_tb0219_exit);

/* [<][>][^][v][top][bottom][index][help] */