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        atomic_inc(&irq_err_count);
 221
 222        return -EINVAL;
 223}
 224
 225void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
 226                            irq_signal_t signal)
 227{
 228        u16 mask;
 229
 230        if (pin < GIUINT_HIGH_OFFSET) {
 231                mask = 1 << pin;
 232                if (trigger != IRQ_TRIGGER_LEVEL) {
 233                        giu_set(GIUINTTYPL, mask);
 234                        if (signal == IRQ_SIGNAL_HOLD)
 235                                giu_set(GIUINTHTSELL, mask);
 236                        else
 237                                giu_clear(GIUINTHTSELL, mask);
 238                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 239                                switch (trigger) {
 240                                case IRQ_TRIGGER_EDGE_FALLING:
 241                                        giu_set(GIUFEDGEINHL, mask);
 242                                        giu_clear(GIUREDGEINHL, mask);
 243                                        break;
 244                                case IRQ_TRIGGER_EDGE_RISING:
 245                                        giu_clear(GIUFEDGEINHL, mask);
 246                                        giu_set(GIUREDGEINHL, mask);
 247                                        break;
 248                                default:
 249                                        giu_set(GIUFEDGEINHL, mask);
 250                                        giu_set(GIUREDGEINHL, mask);
 251                                        break;
 252                                }
 253                        }
 254                        irq_set_chip_and_handler(GIU_IRQ(pin),
 255                                                 &giuint_low_irq_chip,
 256                                                 handle_edge_irq);
 257                } else {
 258                        giu_clear(GIUINTTYPL, mask);
 259                        giu_clear(GIUINTHTSELL, mask);
 260                        irq_set_chip_and_handler(GIU_IRQ(pin),
 261                                                 &giuint_low_irq_chip,
 262                                                 handle_level_irq);
 263                }
 264                giu_write(GIUINTSTATL, mask);
 265        } else if (pin < GIUINT_HIGH_MAX) {
 266                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 267                if (trigger != IRQ_TRIGGER_LEVEL) {
 268                        giu_set(GIUINTTYPH, mask);
 269                        if (signal == IRQ_SIGNAL_HOLD)
 270                                giu_set(GIUINTHTSELH, mask);
 271                        else
 272                                giu_clear(GIUINTHTSELH, mask);
 273                        if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
 274                                switch (trigger) {
 275                                case IRQ_TRIGGER_EDGE_FALLING:
 276                                        giu_set(GIUFEDGEINHH, mask);
 277                                        giu_clear(GIUREDGEINHH, mask);
 278                                        break;
 279                                case IRQ_TRIGGER_EDGE_RISING:
 280                                        giu_clear(GIUFEDGEINHH, mask);
 281                                        giu_set(GIUREDGEINHH, mask);
 282                                        break;
 283                                default:
 284                                        giu_set(GIUFEDGEINHH, mask);
 285                                        giu_set(GIUREDGEINHH, mask);
 286                                        break;
 287                                }
 288                        }
 289                        irq_set_chip_and_handler(GIU_IRQ(pin),
 290                                                 &giuint_high_irq_chip,
 291                                                 handle_edge_irq);
 292                } else {
 293                        giu_clear(GIUINTTYPH, mask);
 294                        giu_clear(GIUINTHTSELH, mask);
 295                        irq_set_chip_and_handler(GIU_IRQ(pin),
 296                                                 &giuint_high_irq_chip,
 297                                                 handle_level_irq);
 298                }
 299                giu_write(GIUINTSTATH, mask);
 300        }
 301}
 302EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
 303
 304void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
 305{
 306        u16 mask;
 307
 308        if (pin < GIUINT_HIGH_OFFSET) {
 309                mask = 1 << pin;
 310                if (level == IRQ_LEVEL_HIGH)
 311                        giu_set(GIUINTALSELL, mask);
 312                else
 313                        giu_clear(GIUINTALSELL, mask);
 314                giu_write(GIUINTSTATL, mask);
 315        } else if (pin < GIUINT_HIGH_MAX) {
 316                mask = 1 << (pin - GIUINT_HIGH_OFFSET);
 317                if (level == IRQ_LEVEL_HIGH)
 318                        giu_set(GIUINTALSELH, mask);
 319                else
 320                        giu_clear(GIUINTALSELH, mask);
 321                giu_write(GIUINTSTATH, mask);
 322        }
 323}
 324EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
 325
 326static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
 327{
 328        u16 offset, mask, reg;
 329        unsigned long flags;
 330
 331        if (pin >= chip->ngpio)
 332                return -EINVAL;
 333
 334        if (pin < 16) {
 335                offset = GIUIOSELL;
 336                mask = 1 << pin;
 337        } else if (pin < 32) {
 338                offset = GIUIOSELH;
 339                mask = 1 << (pin - 16);
 340        } else {
 341                if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
 342                        offset = GIUPODATEN;
 343                        mask = 1 << (pin - 32);
 344                } else {
 345                        switch (pin) {
 346                        case 48:
 347                                offset = GIUPODATH;
 348                                mask = PIOEN0;
 349                                break;
 350                        case 49:
 351                                offset = GIUPODATH;
 352                                mask = PIOEN1;
 353                                break;
 354                        default:
 355                                return -EINVAL;
 356                        }
 357                }
 358        }
 359
 360        spin_lock_irqsave(&giu_lock, flags);
 361
 362        reg = giu_read(offset);
 363        if (dir == GPIO_OUTPUT)
 364                reg |= mask;
 365        else
 366                reg &= ~mask;
 367        giu_write(offset, reg);
 368
 369        spin_unlock_irqrestore(&giu_lock, flags);
 370
 371        return 0;
 372}
 373
 374static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
 375{
 376        u16 reg, mask;
 377
 378        if (pin >= chip->ngpio)
 379                return -EINVAL;
 380
 381        if (pin < 16) {
 382                reg = giu_read(GIUPIODL);
 383                mask = 1 << pin;
 384        } else if (pin < 32) {
 385                reg = giu_read(GIUPIODH);
 386                mask = 1 << (pin - 16);
 387        } else if (pin < 48) {
 388                reg = giu_read(GIUPODATL);
 389                mask = 1 << (pin - 32);
 390        } else {
 391                reg = giu_read(GIUPODATH);
 392                mask = 1 << (pin - 48);
 393        }
 394
 395        if (reg & mask)
 396                return 1;
 397
 398        return 0;
 399}
 400
 401static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
 402                            int value)
 403{
 404        u16 offset, mask, reg;
 405        unsigned long flags;
 406
 407        if (pin >= chip->ngpio)
 408                return;
 409
 410        if (pin < 16) {
 411                offset = GIUPIODL;
 412                mask = 1 << pin;
 413        } else if (pin < 32) {
 414                offset = GIUPIODH;
 415                mask = 1 << (pin - 16);
 416        } else if (pin < 48) {
 417                offset = GIUPODATL;
 418                mask = 1 << (pin - 32);
 419        } else {
 420                offset = GIUPODATH;
 421                mask = 1 << (pin - 48);
 422        }
 423
 424        spin_lock_irqsave(&giu_lock, flags);
 425
 426        reg = giu_read(offset);
 427        if (value)
 428                reg |= mask;
 429        else
 430                reg &= ~mask;
 431        giu_write(offset, reg);
 432
 433        spin_unlock_irqrestore(&giu_lock, flags);
 434}
 435
 436
 437static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 438{
 439        return giu_set_direction(chip, offset, GPIO_INPUT);
 440}
 441
 442static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 443                                int value)
 444{
 445        vr41xx_gpio_set(chip, offset, value);
 446
 447        return giu_set_direction(chip, offset, GPIO_OUTPUT);
 448}
 449
 450static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 451{
 452        if (offset >= chip->ngpio)
 453                return -EINVAL;
 454
 455        return GIU_IRQ_BASE + offset;
 456}
 457
 458static struct gpio_chip vr41xx_gpio_chip = {
 459        .label                  = "vr41xx",
 460        .owner                  = THIS_MODULE,
 461        .direction_input        = vr41xx_gpio_direction_input,
 462        .get                    = vr41xx_gpio_get,
 463        .direction_output       = vr41xx_gpio_direction_output,
 464        .set                    = vr41xx_gpio_set,
 465        .to_irq                 = vr41xx_gpio_to_irq,
 466};
 467
 468static int giu_probe(struct platform_device *pdev)
 469{
 470        unsigned int trigger, i, pin;
 471        struct irq_chip *chip;
 472        int irq;
 473
 474        switch (pdev->id) {
 475        case GPIO_50PINS_PULLUPDOWN:
 476                giu_flags = GPIO_HAS_PULLUPDOWN_IO;
 477                vr41xx_gpio_chip.ngpio = 50;
 478                break;
 479        case GPIO_36PINS:
 480                vr41xx_gpio_chip.ngpio = 36;
 481                break;
 482        case GPIO_48PINS_EDGE_SELECT:
 483                giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
 484                vr41xx_gpio_chip.ngpio = 48;
 485                break;
 486        default:
 487                dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
 488                return -ENODEV;
 489        }
 490
 491        giu_base = devm_platform_ioremap_resource(pdev, 0);
 492        if (IS_ERR(giu_base))
 493                return PTR_ERR(giu_base);
 494
 495        vr41xx_gpio_chip.parent = &pdev->dev;
 496
 497        if (gpiochip_add_data(&vr41xx_gpio_chip, NULL))
 498                return -ENODEV;
 499
 500        giu_write(GIUINTENL, 0);
 501        giu_write(GIUINTENH, 0);
 502
 503        trigger = giu_read(GIUINTTYPH) << 16;
 504        trigger |= giu_read(GIUINTTYPL);
 505        for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
 506                pin = GPIO_PIN_OF_IRQ(i);
 507                if (pin < GIUINT_HIGH_OFFSET)
 508                        chip = &giuint_low_irq_chip;
 509                else
 510                        chip = &giuint_high_irq_chip;
 511
 512                if (trigger & (1 << pin))
 513                        irq_set_chip_and_handler(i, chip, handle_edge_irq);
 514                else
 515                        irq_set_chip_and_handler(i, chip, handle_level_irq);
 516
 517        }
 518
 519        irq = platform_get_irq(pdev, 0);
 520        if (irq < 0 || irq >= nr_irqs)
 521                return -EBUSY;
 522
 523        return cascade_irq(irq, giu_get_irq);
 524}
 525
 526static int giu_remove(struct platform_device *pdev)
 527{
 528        if (giu_base) {
 529                giu_base = NULL;
 530        }
 531
 532        return 0;
 533}
 534
 535static struct platform_driver giu_device_driver = {
 536        .probe          = giu_probe,
 537        .remove         = giu_remove,
 538        .driver         = {
 539                .name   = "GIU",
 540        },
 541};
 542
 543module_platform_driver(giu_device_driver);
 544