Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.31-rc1 680 lines 16 kB view raw
1/* 2 * Driver for NEC VR4100 series General-purpose I/O Unit. 3 * 4 * Copyright (C) 2002 MontaVista Software Inc. 5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> 6 * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22#include <linux/errno.h> 23#include <linux/fs.h> 24#include <linux/init.h> 25#include <linux/interrupt.h> 26#include <linux/irq.h> 27#include <linux/kernel.h> 28#include <linux/module.h> 29#include <linux/platform_device.h> 30#include <linux/smp_lock.h> 31#include <linux/spinlock.h> 32#include <linux/types.h> 33 34#include <asm/io.h> 35#include <asm/vr41xx/giu.h> 36#include <asm/vr41xx/irq.h> 37#include <asm/vr41xx/vr41xx.h> 38 39MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); 40MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); 41MODULE_LICENSE("GPL"); 42 43static int major; /* default is dynamic major device number */ 44module_param(major, int, 0); 45MODULE_PARM_DESC(major, "Major device number"); 46 47#define GIUIOSELL 0x00 48#define GIUIOSELH 0x02 49#define GIUPIODL 0x04 50#define GIUPIODH 0x06 51#define GIUINTSTATL 0x08 52#define GIUINTSTATH 0x0a 53#define GIUINTENL 0x0c 54#define GIUINTENH 0x0e 55#define GIUINTTYPL 0x10 56#define GIUINTTYPH 0x12 57#define GIUINTALSELL 0x14 58#define GIUINTALSELH 0x16 59#define GIUINTHTSELL 0x18 60#define GIUINTHTSELH 0x1a 61#define GIUPODATL 0x1c 62#define GIUPODATEN 0x1c 63#define GIUPODATH 0x1e 64 #define PIOEN0 0x0100 65 #define PIOEN1 0x0200 66#define GIUPODAT 0x1e 67#define GIUFEDGEINHL 0x20 68#define GIUFEDGEINHH 0x22 69#define GIUREDGEINHL 0x24 70#define GIUREDGEINHH 0x26 71 72#define GIUUSEUPDN 0x1e0 73#define GIUTERMUPDN 0x1e2 74 75#define GPIO_HAS_PULLUPDOWN_IO 0x0001 76#define GPIO_HAS_OUTPUT_ENABLE 0x0002 77#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 78 79static spinlock_t giu_lock; 80static unsigned long giu_flags; 81static unsigned int giu_nr_pins; 82 83static void __iomem *giu_base; 84 85#define giu_read(offset) readw(giu_base + (offset)) 86#define giu_write(offset, value) writew((value), giu_base + (offset)) 87 88#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) 89#define GIUINT_HIGH_OFFSET 16 90#define GIUINT_HIGH_MAX 32 91 92static inline uint16_t giu_set(uint16_t offset, uint16_t set) 93{ 94 uint16_t data; 95 96 data = giu_read(offset); 97 data |= set; 98 giu_write(offset, data); 99 100 return data; 101} 102 103static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) 104{ 105 uint16_t data; 106 107 data = giu_read(offset); 108 data &= ~clear; 109 giu_write(offset, data); 110 111 return data; 112} 113 114static void ack_giuint_low(unsigned int irq) 115{ 116 giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); 117} 118 119static void mask_giuint_low(unsigned int irq) 120{ 121 giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); 122} 123 124static void mask_ack_giuint_low(unsigned int irq) 125{ 126 unsigned int pin; 127 128 pin = GPIO_PIN_OF_IRQ(irq); 129 giu_clear(GIUINTENL, 1 << pin); 130 giu_write(GIUINTSTATL, 1 << pin); 131} 132 133static void unmask_giuint_low(unsigned int irq) 134{ 135 giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); 136} 137 138static struct irq_chip giuint_low_irq_chip = { 139 .name = "GIUINTL", 140 .ack = ack_giuint_low, 141 .mask = mask_giuint_low, 142 .mask_ack = mask_ack_giuint_low, 143 .unmask = unmask_giuint_low, 144}; 145 146static void ack_giuint_high(unsigned int irq) 147{ 148 giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); 149} 150 151static void mask_giuint_high(unsigned int irq) 152{ 153 giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); 154} 155 156static void mask_ack_giuint_high(unsigned int irq) 157{ 158 unsigned int pin; 159 160 pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; 161 giu_clear(GIUINTENH, 1 << pin); 162 giu_write(GIUINTSTATH, 1 << pin); 163} 164 165static void unmask_giuint_high(unsigned int irq) 166{ 167 giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); 168} 169 170static struct irq_chip giuint_high_irq_chip = { 171 .name = "GIUINTH", 172 .ack = ack_giuint_high, 173 .mask = mask_giuint_high, 174 .mask_ack = mask_ack_giuint_high, 175 .unmask = unmask_giuint_high, 176}; 177 178static int giu_get_irq(unsigned int irq) 179{ 180 uint16_t pendl, pendh, maskl, maskh; 181 int i; 182 183 pendl = giu_read(GIUINTSTATL); 184 pendh = giu_read(GIUINTSTATH); 185 maskl = giu_read(GIUINTENL); 186 maskh = giu_read(GIUINTENH); 187 188 maskl &= pendl; 189 maskh &= pendh; 190 191 if (maskl) { 192 for (i = 0; i < 16; i++) { 193 if (maskl & (1 << i)) 194 return GIU_IRQ(i); 195 } 196 } else if (maskh) { 197 for (i = 0; i < 16; i++) { 198 if (maskh & (1 << i)) 199 return GIU_IRQ(i + GIUINT_HIGH_OFFSET); 200 } 201 } 202 203 printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", 204 maskl, pendl, maskh, pendh); 205 206 atomic_inc(&irq_err_count); 207 208 return -EINVAL; 209} 210 211void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) 212{ 213 uint16_t mask; 214 215 if (pin < GIUINT_HIGH_OFFSET) { 216 mask = 1 << pin; 217 if (trigger != IRQ_TRIGGER_LEVEL) { 218 giu_set(GIUINTTYPL, mask); 219 if (signal == IRQ_SIGNAL_HOLD) 220 giu_set(GIUINTHTSELL, mask); 221 else 222 giu_clear(GIUINTHTSELL, mask); 223 if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { 224 switch (trigger) { 225 case IRQ_TRIGGER_EDGE_FALLING: 226 giu_set(GIUFEDGEINHL, mask); 227 giu_clear(GIUREDGEINHL, mask); 228 break; 229 case IRQ_TRIGGER_EDGE_RISING: 230 giu_clear(GIUFEDGEINHL, mask); 231 giu_set(GIUREDGEINHL, mask); 232 break; 233 default: 234 giu_set(GIUFEDGEINHL, mask); 235 giu_set(GIUREDGEINHL, mask); 236 break; 237 } 238 } 239 set_irq_chip_and_handler(GIU_IRQ(pin), 240 &giuint_low_irq_chip, 241 handle_edge_irq); 242 } else { 243 giu_clear(GIUINTTYPL, mask); 244 giu_clear(GIUINTHTSELL, mask); 245 set_irq_chip_and_handler(GIU_IRQ(pin), 246 &giuint_low_irq_chip, 247 handle_level_irq); 248 } 249 giu_write(GIUINTSTATL, mask); 250 } else if (pin < GIUINT_HIGH_MAX) { 251 mask = 1 << (pin - GIUINT_HIGH_OFFSET); 252 if (trigger != IRQ_TRIGGER_LEVEL) { 253 giu_set(GIUINTTYPH, mask); 254 if (signal == IRQ_SIGNAL_HOLD) 255 giu_set(GIUINTHTSELH, mask); 256 else 257 giu_clear(GIUINTHTSELH, mask); 258 if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { 259 switch (trigger) { 260 case IRQ_TRIGGER_EDGE_FALLING: 261 giu_set(GIUFEDGEINHH, mask); 262 giu_clear(GIUREDGEINHH, mask); 263 break; 264 case IRQ_TRIGGER_EDGE_RISING: 265 giu_clear(GIUFEDGEINHH, mask); 266 giu_set(GIUREDGEINHH, mask); 267 break; 268 default: 269 giu_set(GIUFEDGEINHH, mask); 270 giu_set(GIUREDGEINHH, mask); 271 break; 272 } 273 } 274 set_irq_chip_and_handler(GIU_IRQ(pin), 275 &giuint_high_irq_chip, 276 handle_edge_irq); 277 } else { 278 giu_clear(GIUINTTYPH, mask); 279 giu_clear(GIUINTHTSELH, mask); 280 set_irq_chip_and_handler(GIU_IRQ(pin), 281 &giuint_high_irq_chip, 282 handle_level_irq); 283 } 284 giu_write(GIUINTSTATH, mask); 285 } 286} 287EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); 288 289void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) 290{ 291 uint16_t mask; 292 293 if (pin < GIUINT_HIGH_OFFSET) { 294 mask = 1 << pin; 295 if (level == IRQ_LEVEL_HIGH) 296 giu_set(GIUINTALSELL, mask); 297 else 298 giu_clear(GIUINTALSELL, mask); 299 giu_write(GIUINTSTATL, mask); 300 } else if (pin < GIUINT_HIGH_MAX) { 301 mask = 1 << (pin - GIUINT_HIGH_OFFSET); 302 if (level == IRQ_LEVEL_HIGH) 303 giu_set(GIUINTALSELH, mask); 304 else 305 giu_clear(GIUINTALSELH, mask); 306 giu_write(GIUINTSTATH, mask); 307 } 308} 309EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); 310 311gpio_data_t vr41xx_gpio_get_pin(unsigned int pin) 312{ 313 uint16_t reg, mask; 314 315 if (pin >= giu_nr_pins) 316 return GPIO_DATA_INVAL; 317 318 if (pin < 16) { 319 reg = giu_read(GIUPIODL); 320 mask = (uint16_t)1 << pin; 321 } else if (pin < 32) { 322 reg = giu_read(GIUPIODH); 323 mask = (uint16_t)1 << (pin - 16); 324 } else if (pin < 48) { 325 reg = giu_read(GIUPODATL); 326 mask = (uint16_t)1 << (pin - 32); 327 } else { 328 reg = giu_read(GIUPODATH); 329 mask = (uint16_t)1 << (pin - 48); 330 } 331 332 if (reg & mask) 333 return GPIO_DATA_HIGH; 334 335 return GPIO_DATA_LOW; 336} 337EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin); 338 339int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data) 340{ 341 uint16_t offset, mask, reg; 342 unsigned long flags; 343 344 if (pin >= giu_nr_pins) 345 return -EINVAL; 346 347 if (pin < 16) { 348 offset = GIUPIODL; 349 mask = (uint16_t)1 << pin; 350 } else if (pin < 32) { 351 offset = GIUPIODH; 352 mask = (uint16_t)1 << (pin - 16); 353 } else if (pin < 48) { 354 offset = GIUPODATL; 355 mask = (uint16_t)1 << (pin - 32); 356 } else { 357 offset = GIUPODATH; 358 mask = (uint16_t)1 << (pin - 48); 359 } 360 361 spin_lock_irqsave(&giu_lock, flags); 362 363 reg = giu_read(offset); 364 if (data == GPIO_DATA_HIGH) 365 reg |= mask; 366 else 367 reg &= ~mask; 368 giu_write(offset, reg); 369 370 spin_unlock_irqrestore(&giu_lock, flags); 371 372 return 0; 373} 374EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin); 375 376int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir) 377{ 378 uint16_t offset, mask, reg; 379 unsigned long flags; 380 381 if (pin >= giu_nr_pins) 382 return -EINVAL; 383 384 if (pin < 16) { 385 offset = GIUIOSELL; 386 mask = (uint16_t)1 << pin; 387 } else if (pin < 32) { 388 offset = GIUIOSELH; 389 mask = (uint16_t)1 << (pin - 16); 390 } else { 391 if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { 392 offset = GIUPODATEN; 393 mask = (uint16_t)1 << (pin - 32); 394 } else { 395 switch (pin) { 396 case 48: 397 offset = GIUPODATH; 398 mask = PIOEN0; 399 break; 400 case 49: 401 offset = GIUPODATH; 402 mask = PIOEN1; 403 break; 404 default: 405 return -EINVAL; 406 } 407 } 408 } 409 410 spin_lock_irqsave(&giu_lock, flags); 411 412 reg = giu_read(offset); 413 if (dir == GPIO_OUTPUT) 414 reg |= mask; 415 else 416 reg &= ~mask; 417 giu_write(offset, reg); 418 419 spin_unlock_irqrestore(&giu_lock, flags); 420 421 return 0; 422} 423EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction); 424 425int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) 426{ 427 uint16_t reg, mask; 428 unsigned long flags; 429 430 if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) 431 return -EPERM; 432 433 if (pin >= 15) 434 return -EINVAL; 435 436 mask = (uint16_t)1 << pin; 437 438 spin_lock_irqsave(&giu_lock, flags); 439 440 if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { 441 reg = giu_read(GIUTERMUPDN); 442 if (pull == GPIO_PULL_UP) 443 reg |= mask; 444 else 445 reg &= ~mask; 446 giu_write(GIUTERMUPDN, reg); 447 448 reg = giu_read(GIUUSEUPDN); 449 reg |= mask; 450 giu_write(GIUUSEUPDN, reg); 451 } else { 452 reg = giu_read(GIUUSEUPDN); 453 reg &= ~mask; 454 giu_write(GIUUSEUPDN, reg); 455 } 456 457 spin_unlock_irqrestore(&giu_lock, flags); 458 459 return 0; 460} 461EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); 462 463static ssize_t gpio_read(struct file *file, char __user *buf, size_t len, 464 loff_t *ppos) 465{ 466 unsigned int pin; 467 char value = '0'; 468 469 pin = iminor(file->f_path.dentry->d_inode); 470 if (pin >= giu_nr_pins) 471 return -EBADF; 472 473 if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH) 474 value = '1'; 475 476 if (len <= 0) 477 return -EFAULT; 478 479 if (put_user(value, buf)) 480 return -EFAULT; 481 482 return 1; 483} 484 485static ssize_t gpio_write(struct file *file, const char __user *data, 486 size_t len, loff_t *ppos) 487{ 488 unsigned int pin; 489 size_t i; 490 char c; 491 int retval = 0; 492 493 pin = iminor(file->f_path.dentry->d_inode); 494 if (pin >= giu_nr_pins) 495 return -EBADF; 496 497 for (i = 0; i < len; i++) { 498 if (get_user(c, data + i)) 499 return -EFAULT; 500 501 switch (c) { 502 case '0': 503 retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW); 504 break; 505 case '1': 506 retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH); 507 break; 508 case 'D': 509 printk(KERN_INFO "GPIO%d: pull down\n", pin); 510 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN); 511 break; 512 case 'd': 513 printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); 514 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); 515 break; 516 case 'I': 517 printk(KERN_INFO "GPIO%d: input\n", pin); 518 retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT); 519 break; 520 case 'O': 521 printk(KERN_INFO "GPIO%d: output\n", pin); 522 retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT); 523 break; 524 case 'o': 525 printk(KERN_INFO "GPIO%d: output disable\n", pin); 526 retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE); 527 break; 528 case 'P': 529 printk(KERN_INFO "GPIO%d: pull up\n", pin); 530 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP); 531 break; 532 case 'p': 533 printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); 534 retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); 535 break; 536 default: 537 break; 538 } 539 540 if (retval < 0) 541 break; 542 } 543 544 return i; 545} 546 547static int gpio_open(struct inode *inode, struct file *file) 548{ 549 unsigned int pin; 550 551 cycle_kernel_lock(); 552 pin = iminor(inode); 553 if (pin >= giu_nr_pins) 554 return -EBADF; 555 556 return nonseekable_open(inode, file); 557} 558 559static int gpio_release(struct inode *inode, struct file *file) 560{ 561 unsigned int pin; 562 563 pin = iminor(inode); 564 if (pin >= giu_nr_pins) 565 return -EBADF; 566 567 return 0; 568} 569 570static const struct file_operations gpio_fops = { 571 .owner = THIS_MODULE, 572 .read = gpio_read, 573 .write = gpio_write, 574 .open = gpio_open, 575 .release = gpio_release, 576}; 577 578static int __devinit giu_probe(struct platform_device *dev) 579{ 580 struct resource *res; 581 unsigned int trigger, i, pin; 582 struct irq_chip *chip; 583 int irq, retval; 584 585 switch (dev->id) { 586 case GPIO_50PINS_PULLUPDOWN: 587 giu_flags = GPIO_HAS_PULLUPDOWN_IO; 588 giu_nr_pins = 50; 589 break; 590 case GPIO_36PINS: 591 giu_nr_pins = 36; 592 break; 593 case GPIO_48PINS_EDGE_SELECT: 594 giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; 595 giu_nr_pins = 48; 596 break; 597 default: 598 printk(KERN_ERR "GIU: unknown ID %d\n", dev->id); 599 return -ENODEV; 600 } 601 602 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 603 if (!res) 604 return -EBUSY; 605 606 giu_base = ioremap(res->start, res->end - res->start + 1); 607 if (!giu_base) 608 return -ENOMEM; 609 610 retval = register_chrdev(major, "GIU", &gpio_fops); 611 if (retval < 0) { 612 iounmap(giu_base); 613 giu_base = NULL; 614 return retval; 615 } 616 617 if (major == 0) { 618 major = retval; 619 printk(KERN_INFO "GIU: major number %d\n", major); 620 } 621 622 spin_lock_init(&giu_lock); 623 624 giu_write(GIUINTENL, 0); 625 giu_write(GIUINTENH, 0); 626 627 trigger = giu_read(GIUINTTYPH) << 16; 628 trigger |= giu_read(GIUINTTYPL); 629 for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { 630 pin = GPIO_PIN_OF_IRQ(i); 631 if (pin < GIUINT_HIGH_OFFSET) 632 chip = &giuint_low_irq_chip; 633 else 634 chip = &giuint_high_irq_chip; 635 636 if (trigger & (1 << pin)) 637 set_irq_chip_and_handler(i, chip, handle_edge_irq); 638 else 639 set_irq_chip_and_handler(i, chip, handle_level_irq); 640 641 } 642 643 irq = platform_get_irq(dev, 0); 644 if (irq < 0 || irq >= nr_irqs) 645 return -EBUSY; 646 647 return cascade_irq(irq, giu_get_irq); 648} 649 650static int __devexit giu_remove(struct platform_device *dev) 651{ 652 if (giu_base) { 653 iounmap(giu_base); 654 giu_base = NULL; 655 } 656 657 return 0; 658} 659 660static struct platform_driver giu_device_driver = { 661 .probe = giu_probe, 662 .remove = __devexit_p(giu_remove), 663 .driver = { 664 .name = "GIU", 665 .owner = THIS_MODULE, 666 }, 667}; 668 669static int __init vr41xx_giu_init(void) 670{ 671 return platform_driver_register(&giu_device_driver); 672} 673 674static void __exit vr41xx_giu_exit(void) 675{ 676 platform_driver_unregister(&giu_device_driver); 677} 678 679module_init(vr41xx_giu_init); 680module_exit(vr41xx_giu_exit);