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