linux/drivers/gpio/gpio-vr41xx.c
<<
>>
Prefs
   1/*
   2 *  Driver for NEC VR4100 series General-purpose I/O Unit.
   3 *
   4 *  Copyright (C) 2002 MontaVista Software Inc.
   5 *      Author: Yoichi Yuasa <source@mvista.com>
   6 *  Copyright (C) 2003-2009  Yoichi Yuasa <yuasa@linux-mips.org>
   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/gpio.h>
  25#include <linux/init.h>
  26#include <linux/interrupt.h>
  27#include <linux/io.h>
  28#include <linux/irq.h>
  29#include <linux/kernel.h>
  30#include <linux/module.h>
  31#include <linux/platform_device.h>
  32#include <linux/spinlock.h>
  33#include <linux/types.h>
  34
  35#include <asm/vr41xx/giu.h>
  36#include <asm/vr41xx/irq.h>
  37#include <asm/vr41xx/vr41xx.h>
  38
  39MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
  40MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
  41MODULE_LICENSE("GPL");
  42
  43#define GIUIOSELL       0x00
  44#define GIUIOSELH       0x02
  45#define GIUPIODL        0x04
  46#define GIUPIODH        0x06
  47#define GIUINTSTATL     0x08
  48#define GIUINTSTATH     0x0a
  49#define GIUINTENL       0x0c
  50#define GIUINTENH       0x0e
  51#define GIUINTTYPL      0x10
  52#define GIUINTTYPH      0x12
  53#define GIUINTALSELL    0x14
  54#define GIUINTALSELH    0x16
  55#define GIUINTHTSELL    0x18
  56#define GIUINTHTSELH    0x1a
  57#define GIUPODATL       0x1c
  58#define GIUPODATEN      0x1c
  59#define GIUPODATH       0x1e
  60 #define PIOEN0         0x0100
  61 #define PIOEN1         0x0200
  62#define GIUPODAT        0x1e
  63#define GIUFEDGEINHL    0x20
  64#define GIUFEDGEINHH    0x22
  65#define GIUREDGEINHL    0x24
  66#define GIUREDGEINHH    0x26
  67
  68#define GIUUSEUPDN      0x1e0
  69#define GIUTERMUPDN     0x1e2
  70
  71#define GPIO_HAS_PULLUPDOWN_IO          0x0001
  72#define GPIO_HAS_OUTPUT_ENABLE          0x0002
  73#define GPIO_HAS_INTERRUPT_EDGE_SELECT  0x0100
  74
  75enum {
  76        GPIO_INPUT,
  77        GPIO_OUTPUT,
  78};
  79
  80static DEFINE_SPINLOCK(giu_lock);
  81static unsigned long giu_flags;
  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 u16 giu_set(u16 offset, u16 set)
  93{
  94        u16 data;
  95
  96        data = giu_read(offset);
  97        data |= set;
  98        giu_write(offset, data);
  99
 100        return data;
 101}
 102
 103static inline u16 giu_clear(u16 offset, u16 clear)
 104{
 105        u16 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(struct irq_data *d)
 115{
 116        giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 117}
 118
 119static void mask_giuint_low(struct irq_data *d)
 120{
 121        giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 122}
 123
 124static void mask_ack_giuint_low(struct irq_data *d)
 125{
 126        unsigned int pin;
 127
 128        pin = GPIO_PIN_OF_IRQ(d->irq);
 129        giu_clear(GIUINTENL, 1 << pin);
 130        giu_write(GIUINTSTATL, 1 << pin);
 131}
 132
 133static void unmask_giuint_low(struct irq_data *d)
 134{
 135        giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 136}
 137
 138static struct irq_chip giuint_low_irq_chip = {
 139        .name           = "GIUINTL",
 140        .irq_ack        = ack_giuint_low,
 141        .irq_mask       = mask_giuint_low,
 142        .irq_mask_ack   = mask_ack_giuint_low,
 143        .irq_unmask     = unmask_giuint_low,
 144};
 145
 146static void ack_giuint_high(struct irq_data *d)
 147{
 148        giu_write(GIUINTSTATH,
 149                  1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 150}
 151
 152static void mask_giuint_high(struct irq_data *d)
 153{
 154        giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 155}
 156
 157static void mask_ack_giuint_high(struct irq_data *d)
 158{
 159        unsigned int pin;
 160
 161        pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET;
 162        giu_clear(GIUINTENH, 1 << pin);
 163        giu_write(GIUINTSTATH, 1 << pin);
 164}
 165
 166static void unmask_giuint_high(struct irq_data *d)
 167{
 168        giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 169}
 170
 171static struct irq_chip giuint_high_irq_chip = {
 172        .name           = "GIUINTH",
 173        .irq_ack        = ack_giuint_high,
 174        .irq_mask       = mask_giuint_high,
 175        .irq_mask_ack   = mask_ack_giuint_high,
 176        .irq_unmask     = unmask_giuint_high,
 177};
 178
 179static int giu_get_irq(unsigned int irq)
 180{
 181        u16 pendl, pendh, maskl, maskh;
 182        int i;
 183
 184        pendl = giu_read(GIUINTSTATL);
 185        pendh = giu_read(GIUINTSTATH);
 186        maskl = giu_read(GIUINTENL);
 187        maskh = giu_read(GIUINTENH);
 188
 189        maskl &= pendl;
 190        maskh &= pendh;
 191
 192        if (maskl) {
 193                for (i = 0; i < 16; i++) {
 194                        if (maskl & (1 << i))
 195                                return GIU_IRQ(i);
 196                }
 197        } else if (maskh) {
 198                for (i = 0; i < 16; i++) {
 199                        if (maskh & (1 << i))
 200                                return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
 201                }
 202        }
 203
 204        printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
 205               maskl, pendl, maskh, pendh);
 206
 207        atomic_inc(&irq_err_count);
 208
 209        return -EINVAL;
 210}
 211
 212void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
 213                            irq_signal_t signal)
 214{
 215        u16 mask;
 216
 217        if (pin < GIUINT_HIGH_OFFSET) {
 218                mask = 1 << pin;
 219                if (trigger != IRQ_TRIGGER_LEVEL) {
 220                        giu_set(GIUINTTYPL, mask);
 221                        if (signal == IRQ_SIGNAL_HOLD)
 222                                giu_set(GIUINTHTSELL, mask);
 223                        else
 224                                giu_clear(GIUINTHTSELL, mask);
 225                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 226                                switch (trigger) {
 227                                case IRQ_TRIGGER_EDGE_FALLING:
 228                                        giu_set(GIUFEDGEINHL, mask);
 229                                        giu_clear(GIUREDGEINHL, mask);
 230                                        break;
 231                                case IRQ_TRIGGER_EDGE_RISING:
 232                                        giu_clear(GIUFEDGEINHL, mask);
 233                                        giu_set(GIUREDGEINHL, mask);
 234                                        break;
 235                                default:
 236                                        giu_set(GIUFEDGEINHL, mask);
 237                                        giu_set(GIUREDGEINHL, mask);
 238                                        break;
 239                                }
 240                        }
 241                        irq_set_chip_and_handler(GIU_IRQ(pin),
 242                                                 &giuint_low_irq_chip,
 243                                                 handle_edge_irq);
 244                } else {
 245                        giu_clear(GIUINTTYPL, mask);
 246                        giu_clear(GIUINTHTSELL, mask);
 247                        irq_set_chip_and_handler(GIU_IRQ(pin),
 248                                                 &giuint_low_irq_chip,
 249                                                 handle_level_irq);
 250                }
 251                giu_write(GIUINTSTATL, mask);
 252        } else if (pin < GIUINT_HIGH_MAX) {
 253                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 254                if (trigger != IRQ_TRIGGER_LEVEL) {
 255                        giu_set(GIUINTTYPH, mask);
 256                        if (signal == IRQ_SIGNAL_HOLD)
 257                                giu_set(GIUINTHTSELH, mask);
 258                        else
 259                                giu_clear(GIUINTHTSELH, mask);
 260                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 261                                switch (trigger) {
 262                                case IRQ_TRIGGER_EDGE_FALLING:
 263                                        giu_set(GIUFEDGEINHH, mask);
 264                                        giu_clear(GIUREDGEINHH, mask);
 265                                        break;
 266                                case IRQ_TRIGGER_EDGE_RISING:
 267                                        giu_clear(GIUFEDGEINHH, mask);
 268                                        giu_set(GIUREDGEINHH, mask);
 269                                        break;
 270                                default:
 271                                        giu_set(GIUFEDGEINHH, mask);
 272                                        giu_set(GIUREDGEINHH, mask);
 273                                        break;
 274                                }
 275                        }
 276                        irq_set_chip_and_handler(GIU_IRQ(pin),
 277                                                 &giuint_high_irq_chip,
 278                                                 handle_edge_irq);
 279                } else {
 280                        giu_clear(GIUINTTYPH, mask);
 281                        giu_clear(GIUINTHTSELH, mask);
 282                        irq_set_chip_and_handler(GIU_IRQ(pin),
 283                                                 &giuint_high_irq_chip,
 284                                                 handle_level_irq);
 285                }
 286                giu_write(GIUINTSTATH, mask);
 287        }
 288}
 289EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
 290
 291void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
 292{
 293        u16 mask;
 294
 295        if (pin < GIUINT_HIGH_OFFSET) {
 296                mask = 1 << pin;
 297                if (level == IRQ_LEVEL_HIGH)
 298                        giu_set(GIUINTALSELL, mask);
 299                else
 300                        giu_clear(GIUINTALSELL, mask);
 301                giu_write(GIUINTSTATL, mask);
 302        } else if (pin < GIUINT_HIGH_MAX) {
 303                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 304                if (level == IRQ_LEVEL_HIGH)
 305                        giu_set(GIUINTALSELH, mask);
 306                else
 307                        giu_clear(GIUINTALSELH, mask);
 308                giu_write(GIUINTSTATH, mask);
 309        }
 310}
 311EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
 312
 313static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
 314{
 315        u16 offset, mask, reg;
 316        unsigned long flags;
 317
 318        if (pin >= chip->ngpio)
 319                return -EINVAL;
 320
 321        if (pin < 16) {
 322                offset = GIUIOSELL;
 323                mask = 1 << pin;
 324        } else if (pin < 32) {
 325                offset = GIUIOSELH;
 326                mask = 1 << (pin - 16);
 327        } else {
 328                if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
 329                        offset = GIUPODATEN;
 330                        mask = 1 << (pin - 32);
 331                } else {
 332                        switch (pin) {
 333                        case 48:
 334                                offset = GIUPODATH;
 335                                mask = PIOEN0;
 336                                break;
 337                        case 49:
 338                                offset = GIUPODATH;
 339                                mask = PIOEN1;
 340                                break;
 341                        default:
 342                                return -EINVAL;
 343                        }
 344                }
 345        }
 346
 347        spin_lock_irqsave(&giu_lock, flags);
 348
 349        reg = giu_read(offset);
 350        if (dir == GPIO_OUTPUT)
 351                reg |= mask;
 352        else
 353                reg &= ~mask;
 354        giu_write(offset, reg);
 355
 356        spin_unlock_irqrestore(&giu_lock, flags);
 357
 358        return 0;
 359}
 360
 361int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
 362{
 363        u16 reg, mask;
 364        unsigned long flags;
 365
 366        if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
 367                return -EPERM;
 368
 369        if (pin >= 15)
 370                return -EINVAL;
 371
 372        mask = 1 << pin;
 373
 374        spin_lock_irqsave(&giu_lock, flags);
 375
 376        if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
 377                reg = giu_read(GIUTERMUPDN);
 378                if (pull == GPIO_PULL_UP)
 379                        reg |= mask;
 380                else
 381                        reg &= ~mask;
 382                giu_write(GIUTERMUPDN, reg);
 383
 384                reg = giu_read(GIUUSEUPDN);
 385                reg |= mask;
 386                giu_write(GIUUSEUPDN, reg);
 387        } else {
 388                reg = giu_read(GIUUSEUPDN);
 389                reg &= ~mask;
 390                giu_write(GIUUSEUPDN, reg);
 391        }
 392
 393        spin_unlock_irqrestore(&giu_lock, flags);
 394
 395        return 0;
 396}
 397EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
 398
 399static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
 400{
 401        u16 reg, mask;
 402
 403        if (pin >= chip->ngpio)
 404                return -EINVAL;
 405
 406        if (pin < 16) {
 407                reg = giu_read(GIUPIODL);
 408                mask = 1 << pin;
 409        } else if (pin < 32) {
 410                reg = giu_read(GIUPIODH);
 411                mask = 1 << (pin - 16);
 412        } else if (pin < 48) {
 413                reg = giu_read(GIUPODATL);
 414                mask = 1 << (pin - 32);
 415        } else {
 416                reg = giu_read(GIUPODATH);
 417                mask = 1 << (pin - 48);
 418        }
 419
 420        if (reg & mask)
 421                return 1;
 422
 423        return 0;
 424}
 425
 426static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
 427                            int value)
 428{
 429        u16 offset, mask, reg;
 430        unsigned long flags;
 431
 432        if (pin >= chip->ngpio)
 433                return;
 434
 435        if (pin < 16) {
 436                offset = GIUPIODL;
 437                mask = 1 << pin;
 438        } else if (pin < 32) {
 439                offset = GIUPIODH;
 440                mask = 1 << (pin - 16);
 441        } else if (pin < 48) {
 442                offset = GIUPODATL;
 443                mask = 1 << (pin - 32);
 444        } else {
 445                offset = GIUPODATH;
 446                mask = 1 << (pin - 48);
 447        }
 448
 449        spin_lock_irqsave(&giu_lock, flags);
 450
 451        reg = giu_read(offset);
 452        if (value)
 453                reg |= mask;
 454        else
 455                reg &= ~mask;
 456        giu_write(offset, reg);
 457
 458        spin_unlock_irqrestore(&giu_lock, flags);
 459}
 460
 461
 462static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 463{
 464        return giu_set_direction(chip, offset, GPIO_INPUT);
 465}
 466
 467static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 468                                int value)
 469{
 470        vr41xx_gpio_set(chip, offset, value);
 471
 472        return giu_set_direction(chip, offset, GPIO_OUTPUT);
 473}
 474
 475static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 476{
 477        if (offset >= chip->ngpio)
 478                return -EINVAL;
 479
 480        return GIU_IRQ_BASE + offset;
 481}
 482
 483static struct gpio_chip vr41xx_gpio_chip = {
 484        .label                  = "vr41xx",
 485        .owner                  = THIS_MODULE,
 486        .direction_input        = vr41xx_gpio_direction_input,
 487        .get                    = vr41xx_gpio_get,
 488        .direction_output       = vr41xx_gpio_direction_output,
 489        .set                    = vr41xx_gpio_set,
 490        .to_irq                 = vr41xx_gpio_to_irq,
 491};
 492
 493static int __devinit giu_probe(struct platform_device *pdev)
 494{
 495        struct resource *res;
 496        unsigned int trigger, i, pin;
 497        struct irq_chip *chip;
 498        int irq, retval;
 499
 500        switch (pdev->id) {
 501        case GPIO_50PINS_PULLUPDOWN:
 502                giu_flags = GPIO_HAS_PULLUPDOWN_IO;
 503                vr41xx_gpio_chip.ngpio = 50;
 504                break;
 505        case GPIO_36PINS:
 506                vr41xx_gpio_chip.ngpio = 36;
 507                break;
 508        case GPIO_48PINS_EDGE_SELECT:
 509                giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
 510                vr41xx_gpio_chip.ngpio = 48;
 511                break;
 512        default:
 513                dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
 514                return -ENODEV;
 515        }
 516
 517        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 518        if (!res)
 519                return -EBUSY;
 520
 521        giu_base = ioremap(res->start, resource_size(res));
 522        if (!giu_base)
 523                return -ENOMEM;
 524
 525        vr41xx_gpio_chip.dev = &pdev->dev;
 526
 527        retval = gpiochip_add(&vr41xx_gpio_chip);
 528
 529        giu_write(GIUINTENL, 0);
 530        giu_write(GIUINTENH, 0);
 531
 532        trigger = giu_read(GIUINTTYPH) << 16;
 533        trigger |= giu_read(GIUINTTYPL);
 534        for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
 535                pin = GPIO_PIN_OF_IRQ(i);
 536                if (pin < GIUINT_HIGH_OFFSET)
 537                        chip = &giuint_low_irq_chip;
 538                else
 539                        chip = &giuint_high_irq_chip;
 540
 541                if (trigger & (1 << pin))
 542                        irq_set_chip_and_handler(i, chip, handle_edge_irq);
 543                else
 544                        irq_set_chip_and_handler(i, chip, handle_level_irq);
 545
 546        }
 547
 548        irq = platform_get_irq(pdev, 0);
 549        if (irq < 0 || irq >= nr_irqs)
 550                return -EBUSY;
 551
 552        return cascade_irq(irq, giu_get_irq);
 553}
 554
 555static int __devexit giu_remove(struct platform_device *pdev)
 556{
 557        if (giu_base) {
 558                iounmap(giu_base);
 559                giu_base = NULL;
 560        }
 561
 562        return 0;
 563}
 564
 565static struct platform_driver giu_device_driver = {
 566        .probe          = giu_probe,
 567        .remove         = __devexit_p(giu_remove),
 568        .driver         = {
 569                .name   = "GIU",
 570                .owner  = THIS_MODULE,
 571        },
 572};
 573
 574module_platform_driver(giu_device_driver);
 575
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.