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;
  84static struct gpio_chip vr41xx_gpio_chip;
  85
  86#define giu_read(offset)                readw(giu_base + (offset))
  87#define giu_write(offset, value)        writew((value), giu_base + (offset))
  88
  89#define GPIO_PIN_OF_IRQ(irq)    ((irq) - GIU_IRQ_BASE)
  90#define GIUINT_HIGH_OFFSET      16
  91#define GIUINT_HIGH_MAX         32
  92
  93static inline u16 giu_set(u16 offset, u16 set)
  94{
  95        u16 data;
  96
  97        data = giu_read(offset);
  98        data |= set;
  99        giu_write(offset, data);
 100
 101        return data;
 102}
 103
 104static inline u16 giu_clear(u16 offset, u16 clear)
 105{
 106        u16 data;
 107
 108        data = giu_read(offset);
 109        data &= ~clear;
 110        giu_write(offset, data);
 111
 112        return data;
 113}
 114
 115static void ack_giuint_low(struct irq_data *d)
 116{
 117        giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 118}
 119
 120static void mask_giuint_low(struct irq_data *d)
 121{
 122        giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 123}
 124
 125static void mask_ack_giuint_low(struct irq_data *d)
 126{
 127        unsigned int pin;
 128
 129        pin = GPIO_PIN_OF_IRQ(d->irq);
 130        giu_clear(GIUINTENL, 1 << pin);
 131        giu_write(GIUINTSTATL, 1 << pin);
 132}
 133
 134static void unmask_giuint_low(struct irq_data *d)
 135{
 136        giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
 137}
 138
 139static unsigned int startup_giuint(struct irq_data *data)
 140{
 141        if (gpiochip_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
 142                dev_err(vr41xx_gpio_chip.parent,
 143                        "unable to lock HW IRQ %lu for IRQ\n",
 144                        data->hwirq);
 145        /* Satisfy the .enable semantics by unmasking the line */
 146        unmask_giuint_low(data);
 147        return 0;
 148}
 149
 150static void shutdown_giuint(struct irq_data *data)
 151{
 152        mask_giuint_low(data);
 153        gpiochip_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
 154}
 155
 156static struct irq_chip giuint_low_irq_chip = {
 157        .name           = "GIUINTL",
 158        .irq_ack        = ack_giuint_low,
 159        .irq_mask       = mask_giuint_low,
 160        .irq_mask_ack   = mask_ack_giuint_low,
 161        .irq_unmask     = unmask_giuint_low,
 162        .irq_startup    = startup_giuint,
 163        .irq_shutdown   = shutdown_giuint,
 164};
 165
 166static void ack_giuint_high(struct irq_data *d)
 167{
 168        giu_write(GIUINTSTATH,
 169                  1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 170}
 171
 172static void mask_giuint_high(struct irq_data *d)
 173{
 174        giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 175}
 176
 177static void mask_ack_giuint_high(struct irq_data *d)
 178{
 179        unsigned int pin;
 180
 181        pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET;
 182        giu_clear(GIUINTENH, 1 << pin);
 183        giu_write(GIUINTSTATH, 1 << pin);
 184}
 185
 186static void unmask_giuint_high(struct irq_data *d)
 187{
 188        giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
 189}
 190
 191static struct irq_chip giuint_high_irq_chip = {
 192        .name           = "GIUINTH",
 193        .irq_ack        = ack_giuint_high,
 194        .irq_mask       = mask_giuint_high,
 195        .irq_mask_ack   = mask_ack_giuint_high,
 196        .irq_unmask     = unmask_giuint_high,
 197};
 198
 199static int giu_get_irq(unsigned int irq)
 200{
 201        u16 pendl, pendh, maskl, maskh;
 202        int i;
 203
 204        pendl = giu_read(GIUINTSTATL);
 205        pendh = giu_read(GIUINTSTATH);
 206        maskl = giu_read(GIUINTENL);
 207        maskh = giu_read(GIUINTENH);
 208
 209        maskl &= pendl;
 210        maskh &= pendh;
 211
 212        if (maskl) {
 213                for (i = 0; i < 16; i++) {
 214                        if (maskl & (1 << i))
 215                                return GIU_IRQ(i);
 216                }
 217        } else if (maskh) {
 218                for (i = 0; i < 16; i++) {
 219                        if (maskh & (1 << i))
 220                                return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
 221                }
 222        }
 223
 224        printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
 225               maskl, pendl, maskh, pendh);
 226
 227        atomic_inc(&irq_err_count);
 228
 229        return -EINVAL;
 230}
 231
 232void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
 233                            irq_signal_t signal)
 234{
 235        u16 mask;
 236
 237        if (pin < GIUINT_HIGH_OFFSET) {
 238                mask = 1 << pin;
 239                if (trigger != IRQ_TRIGGER_LEVEL) {
 240                        giu_set(GIUINTTYPL, mask);
 241                        if (signal == IRQ_SIGNAL_HOLD)
 242                                giu_set(GIUINTHTSELL, mask);
 243                        else
 244                                giu_clear(GIUINTHTSELL, mask);
 245                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 246                                switch (trigger) {
 247                                case IRQ_TRIGGER_EDGE_FALLING:
 248                                        giu_set(GIUFEDGEINHL, mask);
 249                                        giu_clear(GIUREDGEINHL, mask);
 250                                        break;
 251                                case IRQ_TRIGGER_EDGE_RISING:
 252                                        giu_clear(GIUFEDGEINHL, mask);
 253                                        giu_set(GIUREDGEINHL, mask);
 254                                        break;
 255                                default:
 256                                        giu_set(GIUFEDGEINHL, mask);
 257                                        giu_set(GIUREDGEINHL, mask);
 258                                        break;
 259                                }
 260                        }
 261                        irq_set_chip_and_handler(GIU_IRQ(pin),
 262                                                 &giuint_low_irq_chip,
 263                                                 handle_edge_irq);
 264                } else {
 265                        giu_clear(GIUINTTYPL, mask);
 266                        giu_clear(GIUINTHTSELL, mask);
 267                        irq_set_chip_and_handler(GIU_IRQ(pin),
 268                                                 &giuint_low_irq_chip,
 269                                                 handle_level_irq);
 270                }
 271                giu_write(GIUINTSTATL, mask);
 272        } else if (pin < GIUINT_HIGH_MAX) {
 273                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 274                if (trigger != IRQ_TRIGGER_LEVEL) {
 275                        giu_set(GIUINTTYPH, mask);
 276                        if (signal == IRQ_SIGNAL_HOLD)
 277                                giu_set(GIUINTHTSELH, mask);
 278                        else
 279                                giu_clear(GIUINTHTSELH, mask);
 280                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 281                                switch (trigger) {
 282                                case IRQ_TRIGGER_EDGE_FALLING:
 283                                        giu_set(GIUFEDGEINHH, mask);
 284                                        giu_clear(GIUREDGEINHH, mask);
 285                                        break;
 286                                case IRQ_TRIGGER_EDGE_RISING:
 287                                        giu_clear(GIUFEDGEINHH, mask);
 288                                        giu_set(GIUREDGEINHH, mask);
 289                                        break;
 290                                default:
 291                                        giu_set(GIUFEDGEINHH, mask);
 292                                        giu_set(GIUREDGEINHH, mask);
 293                                        break;
 294                                }
 295                        }
 296                        irq_set_chip_and_handler(GIU_IRQ(pin),
 297                                                 &giuint_high_irq_chip,
 298                                                 handle_edge_irq);
 299                } else {
 300                        giu_clear(GIUINTTYPH, mask);
 301                        giu_clear(GIUINTHTSELH, mask);
 302                        irq_set_chip_and_handler(GIU_IRQ(pin),
 303                                                 &giuint_high_irq_chip,
 304                                                 handle_level_irq);
 305                }
 306                giu_write(GIUINTSTATH, mask);
 307        }
 308}
 309EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
 310
 311void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
 312{
 313        u16 mask;
 314
 315        if (pin < GIUINT_HIGH_OFFSET) {
 316                mask = 1 << pin;
 317                if (level == IRQ_LEVEL_HIGH)
 318                        giu_set(GIUINTALSELL, mask);
 319                else
 320                        giu_clear(GIUINTALSELL, mask);
 321                giu_write(GIUINTSTATL, mask);
 322        } else if (pin < GIUINT_HIGH_MAX) {
 323                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 324                if (level == IRQ_LEVEL_HIGH)
 325                        giu_set(GIUINTALSELH, mask);
 326                else
 327                        giu_clear(GIUINTALSELH, mask);
 328                giu_write(GIUINTSTATH, mask);
 329        }
 330}
 331EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
 332
 333static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
 334{
 335        u16 offset, mask, reg;
 336        unsigned long flags;
 337
 338        if (pin >= chip->ngpio)
 339                return -EINVAL;
 340
 341        if (pin < 16) {
 342                offset = GIUIOSELL;
 343                mask = 1 << pin;
 344        } else if (pin < 32) {
 345                offset = GIUIOSELH;
 346                mask = 1 << (pin - 16);
 347        } else {
 348                if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
 349                        offset = GIUPODATEN;
 350                        mask = 1 << (pin - 32);
 351                } else {
 352                        switch (pin) {
 353                        case 48:
 354                                offset = GIUPODATH;
 355                                mask = PIOEN0;
 356                                break;
 357                        case 49:
 358                                offset = GIUPODATH;
 359                                mask = PIOEN1;
 360                                break;
 361                        default:
 362                                return -EINVAL;
 363                        }
 364                }
 365        }
 366
 367        spin_lock_irqsave(&giu_lock, flags);
 368
 369        reg = giu_read(offset);
 370        if (dir == GPIO_OUTPUT)
 371                reg |= mask;
 372        else
 373                reg &= ~mask;
 374        giu_write(offset, reg);
 375
 376        spin_unlock_irqrestore(&giu_lock, flags);
 377
 378        return 0;
 379}
 380
 381int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
 382{
 383        u16 reg, mask;
 384        unsigned long flags;
 385
 386        if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
 387                return -EPERM;
 388
 389        if (pin >= 15)
 390                return -EINVAL;
 391
 392        mask = 1 << pin;
 393
 394        spin_lock_irqsave(&giu_lock, flags);
 395
 396        if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
 397                reg = giu_read(GIUTERMUPDN);
 398                if (pull == GPIO_PULL_UP)
 399                        reg |= mask;
 400                else
 401                        reg &= ~mask;
 402                giu_write(GIUTERMUPDN, reg);
 403
 404                reg = giu_read(GIUUSEUPDN);
 405                reg |= mask;
 406                giu_write(GIUUSEUPDN, reg);
 407        } else {
 408                reg = giu_read(GIUUSEUPDN);
 409                reg &= ~mask;
 410                giu_write(GIUUSEUPDN, reg);
 411        }
 412
 413        spin_unlock_irqrestore(&giu_lock, flags);
 414
 415        return 0;
 416}
 417EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
 418
 419static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
 420{
 421        u16 reg, mask;
 422
 423        if (pin >= chip->ngpio)
 424                return -EINVAL;
 425
 426        if (pin < 16) {
 427                reg = giu_read(GIUPIODL);
 428                mask = 1 << pin;
 429        } else if (pin < 32) {
 430                reg = giu_read(GIUPIODH);
 431                mask = 1 << (pin - 16);
 432        } else if (pin < 48) {
 433                reg = giu_read(GIUPODATL);
 434                mask = 1 << (pin - 32);
 435        } else {
 436                reg = giu_read(GIUPODATH);
 437                mask = 1 << (pin - 48);
 438        }
 439
 440        if (reg & mask)
 441                return 1;
 442
 443        return 0;
 444}
 445
 446static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
 447                            int value)
 448{
 449        u16 offset, mask, reg;
 450        unsigned long flags;
 451
 452        if (pin >= chip->ngpio)
 453                return;
 454
 455        if (pin < 16) {
 456                offset = GIUPIODL;
 457                mask = 1 << pin;
 458        } else if (pin < 32) {
 459                offset = GIUPIODH;
 460                mask = 1 << (pin - 16);
 461        } else if (pin < 48) {
 462                offset = GIUPODATL;
 463                mask = 1 << (pin - 32);
 464        } else {
 465                offset = GIUPODATH;
 466                mask = 1 << (pin - 48);
 467        }
 468
 469        spin_lock_irqsave(&giu_lock, flags);
 470
 471        reg = giu_read(offset);
 472        if (value)
 473                reg |= mask;
 474        else
 475                reg &= ~mask;
 476        giu_write(offset, reg);
 477
 478        spin_unlock_irqrestore(&giu_lock, flags);
 479}
 480
 481
 482static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 483{
 484        return giu_set_direction(chip, offset, GPIO_INPUT);
 485}
 486
 487static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 488                                int value)
 489{
 490        vr41xx_gpio_set(chip, offset, value);
 491
 492        return giu_set_direction(chip, offset, GPIO_OUTPUT);
 493}
 494
 495static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 496{
 497        if (offset >= chip->ngpio)
 498                return -EINVAL;
 499
 500        return GIU_IRQ_BASE + offset;
 501}
 502
 503static struct gpio_chip vr41xx_gpio_chip = {
 504        .label                  = "vr41xx",
 505        .owner                  = THIS_MODULE,
 506        .direction_input        = vr41xx_gpio_direction_input,
 507        .get                    = vr41xx_gpio_get,
 508        .direction_output       = vr41xx_gpio_direction_output,
 509        .set                    = vr41xx_gpio_set,
 510        .to_irq                 = vr41xx_gpio_to_irq,
 511};
 512
 513static int giu_probe(struct platform_device *pdev)
 514{
 515        struct resource *res;
 516        unsigned int trigger, i, pin;
 517        struct irq_chip *chip;
 518        int irq, ret;
 519
 520        switch (pdev->id) {
 521        case GPIO_50PINS_PULLUPDOWN:
 522                giu_flags = GPIO_HAS_PULLUPDOWN_IO;
 523                vr41xx_gpio_chip.ngpio = 50;
 524                break;
 525        case GPIO_36PINS:
 526                vr41xx_gpio_chip.ngpio = 36;
 527                break;
 528        case GPIO_48PINS_EDGE_SELECT:
 529                giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
 530                vr41xx_gpio_chip.ngpio = 48;
 531                break;
 532        default:
 533                dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
 534                return -ENODEV;
 535        }
 536
 537        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 538        if (!res)
 539                return -EBUSY;
 540
 541        giu_base = ioremap(res->start, resource_size(res));
 542        if (!giu_base)
 543                return -ENOMEM;
 544
 545        vr41xx_gpio_chip.parent = &pdev->dev;
 546
 547        ret = gpiochip_add_data(&vr41xx_gpio_chip, NULL);
 548        if (!ret) {
 549                iounmap(giu_base);
 550                return -ENODEV;
 551        }
 552
 553        giu_write(GIUINTENL, 0);
 554        giu_write(GIUINTENH, 0);
 555
 556        trigger = giu_read(GIUINTTYPH) << 16;
 557        trigger |= giu_read(GIUINTTYPL);
 558        for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
 559                pin = GPIO_PIN_OF_IRQ(i);
 560                if (pin < GIUINT_HIGH_OFFSET)
 561                        chip = &giuint_low_irq_chip;
 562                else
 563                        chip = &giuint_high_irq_chip;
 564
 565                if (trigger & (1 << pin))
 566                        irq_set_chip_and_handler(i, chip, handle_edge_irq);
 567                else
 568                        irq_set_chip_and_handler(i, chip, handle_level_irq);
 569
 570        }
 571
 572        irq = platform_get_irq(pdev, 0);
 573        if (irq < 0 || irq >= nr_irqs)
 574                return -EBUSY;
 575
 576        return cascade_irq(irq, giu_get_irq);
 577}
 578
 579static int giu_remove(struct platform_device *pdev)
 580{
 581        if (giu_base) {
 582                iounmap(giu_base);
 583                giu_base = NULL;
 584        }
 585
 586        return 0;
 587}
 588
 589static struct platform_driver giu_device_driver = {
 590        .probe          = giu_probe,
 591        .remove         = giu_remove,
 592        .driver         = {
 593                .name   = "GIU",
 594        },
 595};
 596
 597module_platform_driver(giu_device_driver);
 598