linux/drivers/pinctrl/pinctrl-s3c64xx.c
<<
>>
Prefs
   1/*
   2 * S3C64xx specific support for pinctrl-samsung driver.
   3 *
   4 * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
   5 *
   6 * Based on pinctrl-exynos.c, please see the file for original copyrights.
   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 file contains the Samsung S3C64xx specific information required by the
  14 * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
  15 * external gpio and wakeup interrupt support.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/device.h>
  20#include <linux/interrupt.h>
  21#include <linux/irqdomain.h>
  22#include <linux/irq.h>
  23#include <linux/of_irq.h>
  24#include <linux/io.h>
  25#include <linux/irqchip/chained_irq.h>
  26#include <linux/slab.h>
  27#include <linux/err.h>
  28
  29#include "pinctrl-samsung.h"
  30
  31#define NUM_EINT0               28
  32#define NUM_EINT0_IRQ           4
  33#define EINT_MAX_PER_REG        16
  34#define EINT_MAX_PER_GROUP      16
  35
  36/* External GPIO and wakeup interrupt related definitions */
  37#define SVC_GROUP_SHIFT         4
  38#define SVC_GROUP_MASK          0xf
  39#define SVC_NUM_MASK            0xf
  40#define SVC_GROUP(x)            ((x >> SVC_GROUP_SHIFT) & \
  41                                                SVC_GROUP_MASK)
  42
  43#define EINT12CON_REG           0x200
  44#define EINT12MASK_REG          0x240
  45#define EINT12PEND_REG          0x260
  46
  47#define EINT_OFFS(i)            ((i) % (2 * EINT_MAX_PER_GROUP))
  48#define EINT_GROUP(i)           ((i) / EINT_MAX_PER_GROUP)
  49#define EINT_REG(g)             (4 * ((g) / 2))
  50
  51#define EINTCON_REG(i)          (EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
  52#define EINTMASK_REG(i)         (EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
  53#define EINTPEND_REG(i)         (EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
  54
  55#define SERVICE_REG             0x284
  56#define SERVICEPEND_REG         0x288
  57
  58#define EINT0CON0_REG           0x900
  59#define EINT0MASK_REG           0x920
  60#define EINT0PEND_REG           0x924
  61
  62/* S3C64xx specific external interrupt trigger types */
  63#define EINT_LEVEL_LOW          0
  64#define EINT_LEVEL_HIGH         1
  65#define EINT_EDGE_FALLING       2
  66#define EINT_EDGE_RISING        4
  67#define EINT_EDGE_BOTH          6
  68#define EINT_CON_MASK           0xF
  69#define EINT_CON_LEN            4
  70
  71static struct samsung_pin_bank_type bank_type_4bit_off = {
  72        .fld_width = { 4, 1, 2, 0, 2, 2, },
  73        .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
  74};
  75
  76static struct samsung_pin_bank_type bank_type_4bit_alive = {
  77        .fld_width = { 4, 1, 2, },
  78        .reg_offset = { 0x00, 0x04, 0x08, },
  79};
  80
  81static struct samsung_pin_bank_type bank_type_4bit2_off = {
  82        .fld_width = { 4, 1, 2, 0, 2, 2, },
  83        .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
  84};
  85
  86static struct samsung_pin_bank_type bank_type_4bit2_alive = {
  87        .fld_width = { 4, 1, 2, },
  88        .reg_offset = { 0x00, 0x08, 0x0c, },
  89};
  90
  91static struct samsung_pin_bank_type bank_type_2bit_off = {
  92        .fld_width = { 2, 1, 2, 0, 2, 2, },
  93        .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
  94};
  95
  96static struct samsung_pin_bank_type bank_type_2bit_alive = {
  97        .fld_width = { 2, 1, 2, },
  98        .reg_offset = { 0x00, 0x04, 0x08, },
  99};
 100
 101#define PIN_BANK_4BIT(pins, reg, id)                    \
 102        {                                               \
 103                .type           = &bank_type_4bit_off,  \
 104                .pctl_offset    = reg,                  \
 105                .nr_pins        = pins,                 \
 106                .eint_type      = EINT_TYPE_NONE,       \
 107                .name           = id                    \
 108        }
 109
 110#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)       \
 111        {                                               \
 112                .type           = &bank_type_4bit_off,  \
 113                .pctl_offset    = reg,                  \
 114                .nr_pins        = pins,                 \
 115                .eint_type      = EINT_TYPE_GPIO,       \
 116                .eint_func      = 7,                    \
 117                .eint_mask      = (1 << (pins)) - 1,    \
 118                .eint_offset    = eoffs,                \
 119                .name           = id                    \
 120        }
 121
 122#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
 123        {                                               \
 124                .type           = &bank_type_4bit_alive,\
 125                .pctl_offset    = reg,                  \
 126                .nr_pins        = pins,                 \
 127                .eint_type      = EINT_TYPE_WKUP,       \
 128                .eint_func      = 3,                    \
 129                .eint_mask      = emask,                \
 130                .eint_offset    = eoffs,                \
 131                .name           = id                    \
 132        }
 133
 134#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)      \
 135        {                                               \
 136                .type           = &bank_type_4bit2_off, \
 137                .pctl_offset    = reg,                  \
 138                .nr_pins        = pins,                 \
 139                .eint_type      = EINT_TYPE_GPIO,       \
 140                .eint_func      = 7,                    \
 141                .eint_mask      = (1 << (pins)) - 1,    \
 142                .eint_offset    = eoffs,                \
 143                .name           = id                    \
 144        }
 145
 146#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
 147        {                                               \
 148                .type           = &bank_type_4bit2_alive,\
 149                .pctl_offset    = reg,                  \
 150                .nr_pins        = pins,                 \
 151                .eint_type      = EINT_TYPE_WKUP,       \
 152                .eint_func      = 3,                    \
 153                .eint_mask      = emask,                \
 154                .eint_offset    = eoffs,                \
 155                .name           = id                    \
 156        }
 157
 158#define PIN_BANK_4BIT2_ALIVE(pins, reg, id)             \
 159        {                                               \
 160                .type           = &bank_type_4bit2_alive,\
 161                .pctl_offset    = reg,                  \
 162                .nr_pins        = pins,                 \
 163                .eint_type      = EINT_TYPE_NONE,       \
 164                .name           = id                    \
 165        }
 166
 167#define PIN_BANK_2BIT(pins, reg, id)                    \
 168        {                                               \
 169                .type           = &bank_type_2bit_off,  \
 170                .pctl_offset    = reg,                  \
 171                .nr_pins        = pins,                 \
 172                .eint_type      = EINT_TYPE_NONE,       \
 173                .name           = id                    \
 174        }
 175
 176#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
 177        {                                               \
 178                .type           = &bank_type_2bit_off,  \
 179                .pctl_offset    = reg,                  \
 180                .nr_pins        = pins,                 \
 181                .eint_type      = EINT_TYPE_GPIO,       \
 182                .eint_func      = 3,                    \
 183                .eint_mask      = emask,                \
 184                .eint_offset    = eoffs,                \
 185                .name           = id                    \
 186        }
 187
 188#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)       \
 189        {                                               \
 190                .type           = &bank_type_2bit_alive,\
 191                .pctl_offset    = reg,                  \
 192                .nr_pins        = pins,                 \
 193                .eint_type      = EINT_TYPE_WKUP,       \
 194                .eint_func      = 2,                    \
 195                .eint_mask      = (1 << (pins)) - 1,    \
 196                .eint_offset    = eoffs,                \
 197                .name           = id                    \
 198        }
 199
 200/**
 201 * struct s3c64xx_eint0_data: EINT0 common data
 202 * @drvdata: pin controller driver data
 203 * @domains: IRQ domains of particular EINT0 interrupts
 204 * @pins: pin offsets inside of banks of particular EINT0 interrupts
 205 */
 206struct s3c64xx_eint0_data {
 207        struct samsung_pinctrl_drv_data *drvdata;
 208        struct irq_domain *domains[NUM_EINT0];
 209        u8 pins[NUM_EINT0];
 210};
 211
 212/**
 213 * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
 214 * @bank: pin bank related to the domain
 215 * @eints: EINT0 interrupts related to the domain
 216 */
 217struct s3c64xx_eint0_domain_data {
 218        struct samsung_pin_bank *bank;
 219        u8 eints[];
 220};
 221
 222/**
 223 * struct s3c64xx_eint_gpio_data: GPIO EINT data
 224 * @drvdata: pin controller driver data
 225 * @domains: array of domains related to EINT interrupt groups
 226 */
 227struct s3c64xx_eint_gpio_data {
 228        struct samsung_pinctrl_drv_data *drvdata;
 229        struct irq_domain *domains[];
 230};
 231
 232/*
 233 * Common functions for S3C64xx EINT configuration
 234 */
 235
 236static int s3c64xx_irq_get_trigger(unsigned int type)
 237{
 238        int trigger;
 239
 240        switch (type) {
 241        case IRQ_TYPE_EDGE_RISING:
 242                trigger = EINT_EDGE_RISING;
 243                break;
 244        case IRQ_TYPE_EDGE_FALLING:
 245                trigger = EINT_EDGE_FALLING;
 246                break;
 247        case IRQ_TYPE_EDGE_BOTH:
 248                trigger = EINT_EDGE_BOTH;
 249                break;
 250        case IRQ_TYPE_LEVEL_HIGH:
 251                trigger = EINT_LEVEL_HIGH;
 252                break;
 253        case IRQ_TYPE_LEVEL_LOW:
 254                trigger = EINT_LEVEL_LOW;
 255                break;
 256        default:
 257                return -EINVAL;
 258        }
 259
 260        return trigger;
 261}
 262
 263static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
 264{
 265        /* Edge- and level-triggered interrupts need different handlers */
 266        if (type & IRQ_TYPE_EDGE_BOTH)
 267                __irq_set_handler_locked(irq, handle_edge_irq);
 268        else
 269                __irq_set_handler_locked(irq, handle_level_irq);
 270}
 271
 272static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
 273                                        struct samsung_pin_bank *bank, int pin)
 274{
 275        struct samsung_pin_bank_type *bank_type = bank->type;
 276        unsigned long flags;
 277        void __iomem *reg;
 278        u8 shift;
 279        u32 mask;
 280        u32 val;
 281
 282        /* Make sure that pin is configured as interrupt */
 283        reg = d->virt_base + bank->pctl_offset;
 284        shift = pin;
 285        if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
 286                /* 4-bit bank type with 2 con regs */
 287                reg += 4;
 288                shift -= 8;
 289        }
 290
 291        shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
 292        mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
 293
 294        spin_lock_irqsave(&bank->slock, flags);
 295
 296        val = readl(reg);
 297        val &= ~(mask << shift);
 298        val |= bank->eint_func << shift;
 299        writel(val, reg);
 300
 301        spin_unlock_irqrestore(&bank->slock, flags);
 302}
 303
 304/*
 305 * Functions for EINT GPIO configuration (EINT groups 1-9)
 306 */
 307
 308static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask)
 309{
 310        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
 311        struct samsung_pinctrl_drv_data *d = bank->drvdata;
 312        unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
 313        void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset);
 314        u32 val;
 315
 316        val = readl(reg);
 317        if (mask)
 318                val |= 1 << index;
 319        else
 320                val &= ~(1 << index);
 321        writel(val, reg);
 322}
 323
 324static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
 325{
 326        s3c64xx_gpio_irq_set_mask(irqd, false);
 327}
 328
 329static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
 330{
 331        s3c64xx_gpio_irq_set_mask(irqd, true);
 332}
 333
 334static void s3c64xx_gpio_irq_ack(struct irq_data *irqd)
 335{
 336        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
 337        struct samsung_pinctrl_drv_data *d = bank->drvdata;
 338        unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
 339        void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset);
 340
 341        writel(1 << index, reg);
 342}
 343
 344static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
 345{
 346        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
 347        struct samsung_pinctrl_drv_data *d = bank->drvdata;
 348        void __iomem *reg;
 349        int trigger;
 350        u8 shift;
 351        u32 val;
 352
 353        trigger = s3c64xx_irq_get_trigger(type);
 354        if (trigger < 0) {
 355                pr_err("unsupported external interrupt type\n");
 356                return -EINVAL;
 357        }
 358
 359        s3c64xx_irq_set_handler(irqd->irq, type);
 360
 361        /* Set up interrupt trigger */
 362        reg = d->virt_base + EINTCON_REG(bank->eint_offset);
 363        shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
 364        shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
 365
 366        val = readl(reg);
 367        val &= ~(EINT_CON_MASK << shift);
 368        val |= trigger << shift;
 369        writel(val, reg);
 370
 371        s3c64xx_irq_set_function(d, bank, irqd->hwirq);
 372
 373        return 0;
 374}
 375
 376/*
 377 * irq_chip for gpio interrupts.
 378 */
 379static struct irq_chip s3c64xx_gpio_irq_chip = {
 380        .name           = "GPIO",
 381        .irq_unmask     = s3c64xx_gpio_irq_unmask,
 382        .irq_mask       = s3c64xx_gpio_irq_mask,
 383        .irq_ack        = s3c64xx_gpio_irq_ack,
 384        .irq_set_type   = s3c64xx_gpio_irq_set_type,
 385};
 386
 387static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
 388                                        irq_hw_number_t hw)
 389{
 390        struct samsung_pin_bank *bank = h->host_data;
 391
 392        if (!(bank->eint_mask & (1 << hw)))
 393                return -EINVAL;
 394
 395        irq_set_chip_and_handler(virq,
 396                                &s3c64xx_gpio_irq_chip, handle_level_irq);
 397        irq_set_chip_data(virq, bank);
 398        set_irq_flags(virq, IRQF_VALID);
 399
 400        return 0;
 401}
 402
 403/*
 404 * irq domain callbacks for external gpio interrupt controller.
 405 */
 406static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
 407        .map    = s3c64xx_gpio_irq_map,
 408        .xlate  = irq_domain_xlate_twocell,
 409};
 410
 411static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc)
 412{
 413        struct irq_chip *chip = irq_get_chip(irq);
 414        struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq);
 415        struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
 416
 417        chained_irq_enter(chip, desc);
 418
 419        do {
 420                unsigned int svc;
 421                unsigned int group;
 422                unsigned int pin;
 423                unsigned int virq;
 424
 425                svc = readl(drvdata->virt_base + SERVICE_REG);
 426                group = SVC_GROUP(svc);
 427                pin = svc & SVC_NUM_MASK;
 428
 429                if (!group)
 430                        break;
 431
 432                /* Group 1 is used for two pin banks */
 433                if (group == 1) {
 434                        if (pin < 8)
 435                                group = 0;
 436                        else
 437                                pin -= 8;
 438                }
 439
 440                virq = irq_linear_revmap(data->domains[group], pin);
 441                /*
 442                 * Something must be really wrong if an unmapped EINT
 443                 * was unmasked...
 444                 */
 445                BUG_ON(!virq);
 446
 447                generic_handle_irq(virq);
 448        } while (1);
 449
 450        chained_irq_exit(chip, desc);
 451}
 452
 453/**
 454 * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
 455 * @d: driver data of samsung pinctrl driver.
 456 */
 457static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
 458{
 459        struct s3c64xx_eint_gpio_data *data;
 460        struct samsung_pin_bank *bank;
 461        struct device *dev = d->dev;
 462        unsigned int nr_domains;
 463        unsigned int i;
 464
 465        if (!d->irq) {
 466                dev_err(dev, "irq number not available\n");
 467                return -EINVAL;
 468        }
 469
 470        nr_domains = 0;
 471        bank = d->ctrl->pin_banks;
 472        for (BUG_ON(!BUG_class="sref">i;
        a>(d-> 472
ctrl->urn 0;
l-> 44}
 475
 392        if (!(irq_set_type 363         467 hrTYPE_ clasamsung_pinctrl_drv_data */*4/span>
->EINVA/span>
 */4/span>
ung_pinctrl_drv_data *d = banl->ctrung_pinctrl_drv_dafl"+code=ctrl" clafl"a>                 l->,
d = " class="sref">s3c64xx_gpio_irq_map(408        .s3c64xx_gpio_irq_mapoadd>virq                 *d = of_n> =a> * 4k,
ctr,ass="line" name="L396"> 396      lass="sref">irq_domain_ops virq, ,
 *d = " class="sref">s3c64xx_gpio_irq_mapsass="sref">d-> 466                dev_err( 4" class="add fs="ed">dev, "irq number not available\L385"> 384};
 467banl->/*486
 "sref">vi4q,
4w)
 462        unsigned int  349{
 ">host_da4a;
 491
s3c64xx_eint_gpio_datarr"m_kzallo                s3c64xx_ung_pinctrl_drv_data *hw4/a>)))
 470 *ssizeof(c64xx_eint_gpio_data" class="sref">s3c64xx_q_linear_revmap( 467virq, EINV4L;
s3c64xx_uass="sref">d-> 494
 466                dev_err(dev, "irq number not available\"sref">vi4q,
 467/*4);
4sref">ban4);
drvdata =  471        4);
 599
 471        bank = d->ctrl-> 470        nr5"L401"> 451}
 472        for (BUG_ON(!BUG_class="sref">i;
        a>(d-> 502
 392        if (!(irq_set_type 363         467 hrTYPE_ clasamsung_pinctrl_drv_data */*5/span>
-> */5/span>
irq_linear_revmap(data-> 470++]ung_pinctrl_drv_data *d = " class="sref">s3c64xx_gpio_irq_mapl-> */5//a>);
5pio_irq_m5p,
,
 395        " name=a>                 465        if (! 411static void "irq number not available5L409"> 405};
 397 > =  465        if (!s3c64xx_u class="string">"irq number not available5L      re510
de5c)
 4005"L412"> 452{
5"sref">ir5);
ir5);
 441                drvda5a;
 h0 wake-ine" name="Ls" name="L441"> 441                 */516
 456des5);
 518
irq_mask      "lin0ef="+codes="s"+codxx.c#L461" id="L461" cia> = s3c64xx_gpio_ir+code=s3c64xx_eint_gpio_>,  rl-s3c64xx.c#L418" id="L418" class="line" nam5     5  do {
d->s5c;
      "lin0erq_mapoL459"> 459        struct ss="sref"71s="sref">d->de5p;
 =  413s3c64xx_gpio_ir+cota 413, "irq number not available5="sref">p5n;
s3c64xx_eint_gpio_init(struct sams71"> 471        ata" class="sref">ss="sref"465"> 465       ta *d = data->vi5q;
 351        u32  524
);
 366        val     reg = d->"irq number not available5=7nt"> */5);
 rl-s3c64xx.c#L418" id="L418" class="line" nam5des5K;
ss="sref"465"> 465       t ctr>data->, bank, "irq number not available5="L418"> 528
 436           5sref">gro5p)
 367t;ss="sref"465"> 465       t ctr>data->, bank, "irq number not available5         5break;
 369        writel    reg = d->"irq number not available5="L431"> 531
5 banks */5/span>
5 sref">vi5= 1) {
irq_unmask     ="lin0 class="sre"+codxx.c#L461" id="L461" cia> = s3c64xx_gpio_ir+code=s3c64xx_eint_gpio_>, pin 5lt; 8)
d->group = 0;
irq_mask      "lin0ef="+codes="s"+cod64xx_eint_gpio_>, "irq number not available5=7nt"> */5  else
5 ref">des5 -= 8;
irq_mask      "lin0ef="+"sre"+codxx.c#L461" id="L461" cia> = s3c64xx_gpio_ir+code=s3c64xx_eint_gpio_>,  539
d->pi5);
irq_mask      "lin0ef="+codes="s"+cod64xx_eint_gpio_>, "irq number not available5mment">/*5/span>
5pped EINT5/span>
5masked...5/span>
irq_ack      "lin0 class=""+codxx.c#L461" id="L461" cia> = s3c64xx_gpio_ir+code=s3c64xx_eint_gpio_>,  5/span>
d->vir5);
      "lin0erq_mapoL459"> 459        struct ss="sref"71s="sref">d-> 546
 =  413s3c64xx_gpio_ir+cota 413, "irq number not available5sref">vir5);
s3c64xx_eint_gpio_init(struct sams71"> 471        ata" class="sref">ss="sref"465"> 465       ta *d = data-> 549
 t;ss="sref"465"> 465       t ctr>data->, bank, des5);
reg = d->"irq number not available5"L451"> 451}
5="L452"> 552
5ment">/**5/span>
irq_set_type   = <="li0ef="+coderef""+codxx.c#L461" id="L461" cia> = s3c64xx_gpio_ir+code=s3c64xx_eint_gpio_>, irq_set_type
d->
      "lin0erq_mapoL459"> 459        struct ss="sref"71s="sref">d-> */5/span>
 =  413s3c64xx_gpio_ir+cota 413, "irq number not available5ss="sref"5d)
 390        struct samsung_pin_bank  ata" class="sref">ss="sref"465"> 465       ta *"irq number not available5s   } whi58{
s3c64xx_eint_gpio_init(struct sams71"> 471      ta *d = data->da5a;
data->des5k;
 395rrigge=ref">data-> 45v;
 395u8me="L351"> 351  shif"L457"> 457sthif"ref">data-> 5s;
 351        u32 ;
 564
 395rrigge=ref""> 407        .data 395.datairq_set_typeu32 ) {
 395rrigge=ref""ref="0sass="sref">d->);
dev_err(dev, "irq number not available5ref">EINV5L;
 467                return -5="L469"> 569
 = 0;
 395.dat/a> > = ,  465        if (!irq_set_typeu32 pin_ban5s;
 572
 456 471        bank = d-> 54}
 457sthif"ref"msung_pin_bank  ata" class="sref">ss="sref"465"> 465       t ctr>data->, bank, "irq number not available5="L375"> 575
 457sthif"ref"ms="s> 363        d->/*5/span>
"irq number not available5=ef">EINV5/span>
 457sthif"ref"m-> 363        "irq number not available5=68  5/span>
5irq_chip<5a> = {
 457sthif"ref"msung_pin_bankref"rCON_LEline" name="L445ref"rCON_LElamsung id="L433" class=shif"L457"> 457sthif"ref"m/ 2  class="sref">u32 ,
,
 366        val rega href="+code=valgref"  class="sref">u32  5k,
 367ng_pin_bankref"rCON_"+code=svc" class="ref"rCON_"+coref""ref=ref="+code=eint_maskshif"L457"> 457sthif"ref"  class="sref">u32 ,
 395rrigge=ref""ref=ref="+code=eint_maskshif"L457"> 457sthif"ref" class="sref">u32  5e,
 369        writelrega href="+code=valgref"  class="sref">u32  5};
/*586
 395.dat/a> f+code=s69"> 369          , bank, u32 EINV5q,
5w)
 4005"L389"> 359{
5">host_da5a;
 591
 441                hw5/a>)))
 441                EINV5L;
 456 594
 ed_irq_exit" class=ia> ed_ime="L351"> 351  s>   = <="li0ef="+ed_irq_exit" class=s>   = <="li0ef="+ed_ime="L36ss="sref">d->vi5q,
 351  riverq_exit" class=riveinctrl-s3c64xx.=s="sref">dev_err(, /*5);
 351  class="sref">irq_unmask 351  s>   = <="li0ef="+s="sref">irq_unmask     ="lin0 class="sre"+co,rl-s3c64xx.c#L431" id="L431" class="line" nam5"ef">EINV5);
 351  clas"sref">irq_unmask 351  s>   = <="li0ef="+s="sref">irq_mask      "lin0ef="+"sre"+co,rl-s3c64xx.c#L431" id="L431" class="line" nam5"="sref">5);
 351  class="sref">irq_ack 351  s>   = <="li0ef="+s="sref">irq_ack      "lin0 class=""+co,rl-s3c64xx.c#L431" id="L431" class="line" nam6="L399"> 699
 351  clascoderef">irq_set_type 351  s>   = <="li0ef="+coderef">irq_set_type   = <="li0ef="+coderef""+co,rl-s3c64xx.c#L431" id="L431" class="line" nam6=1L399"> 69;
 4006"L401"> 461}
 602
 395.datremu <="li69"> xx.c#L463" id="L463" class="lif (! 60;
 =>( 351  rang="d! 604
d-> */6/span>
 ed_irq_exit" class=ia> ed_ime="Lg_pinctrl_drv_daed_irq_exit" class="sref">c(408        . g   ,  (!u32  */6//a>);
      "lin0er459"> 459        struct s3c64xx_(408        . 397,  (!u32  */6//a>);
s3c64xx_eint_gpio_init(struct  471       ef="+code=drvdata" class="sref">drvdata = u32  */6//a>);
l-> 406};

chained_irq_exit(chip, de6c)
 462{
 366        val  a href="+code=data" class="sref"g" class="sref">reg = d->"irq number not available6"sref">ir6);
ung_pinctrl_drv_da    val  a href="+code=data" class="sref"g" class="sref">reg = d->"irq number not available6"sref">ir6);
drvda6a;
 366    penL351"> 351  rang="d!L~set_chip_datal-> */616
ng_pinctrl_drv_da ang="d!-> */6);
 618
d->     6  do {
->s6c;
de6p;
                 46n;
ng67t;u32 vi6q;
 624
,  (!        . ref=ar_revmailass="sref">val  ar_revmap" class="sref">irq_linear_revmap(data->,  (!s3c64xx_ss="sref">d->data->,  (!u32 drvda6);
 441                 */6);
 441                 */6K;
 441                 628
 456gro6p)
,  (!u32  631
 411sgeneric ="+codme="69"> 369        <>,  (!u32  46/span>
6 sref">vi6= 1) {
pin 6lt; 8)
     xii"L395"> 395"s50     xii"+code=irq_get_handled_irq_exit" class="sref">chained_irq_exit(chip, group = 0;
6 7nt"> */6  else
6 8nt"> */6 -= 8;
 xx.c#L463" id="L463" class="lif (! =>(d-> 639
 395.datremu <="li69"> ="L463" class="lif (!(chip, pi6);
6mment">/*6/span>

 xx.c#L463" id="L463" class="lif (! =>(
d-> 6/span>
 395.datremu <="li69"> ="L463" class="lif (!(chip, group);
6="L446"> 646
6sref">vir6);
 xx.c#L463" id="L463" class="lif (! =>(d-> 649
 395.datremu <="li69"> ="L463" class="lif (!(chip, des6);
6"L451"> 461}
 652
 xx.c#L463" id="L463" class="lif (! =>(/**6/span>
d->
 395.datremu <="li69"> ="L463" class="lif (!(chip, group
6ment"> */6/span>
6ss="sref"6d)
 flow ="+code"i"L395"> 395ia> flow ="+code"iinctrxx.c#L395" id="s class=="li0_="+code"+code=ctrl" clas class=="li0_="+code"ref">data->d->{
qrl-s3c64xx.c#L452" id="L452" class="line" nam6"sref">da6a;

qrl-s3c64xx.c#L452" id="L452" class="line" nam6"ref">des6k;
qrl-s3c64xx.c#L452" id="L452" class="line" nam6"L451"> 46v;
qrl-s3c64xx.c#L452" id="L452" class="line" nam6""L452"> 6s;
 4006ss="sref"6i;
 664
 xx.c#L461" id="L461" cia> =ss="sref">s3c64xx_gpio_irq_mapng_pinctrl_drv_dahref">s3c64xx_gph claq_xx.c#L463" id="L463" class="v>,  (!group) {
 hw_numbde"i"L395"> 395ia> hw_numbde"iinctrxx.c#L395" id="hwref">s3c64xx_gphw cla rl-s3c64xx.c#L452" id="L452" class="line" nam6n");
d->EINV6L;
 459        struct ss="sref"71rxx.c#L395" id="href">s3c64xx_gph class="sref">bank,  459     -> 390        struct samsung_pin_bank  ata" class="sref">ss="sref"465"> 465       ta *"irq number not available6="L469"> 669
 = 0;
d = id  7t;s3c64xx_gphw cla ) rl-s3c64xx.c#L452" id="L452" class="line" nam6">pin_ban6s;
 467                return - 672
6"s="sref"6urn 0;
" name="L395"> 395        " name=69"> 369        <>,  (! 64}
c#L457" id="L457" class="li0ef="+ed_irq_exit" class=s>   = <="li0ef="+ed_ime="qL_pinctrl_drv_da="+codmlevelme="L411"> 411s="+codmlevelme=" class="sref">chip,  675
 397 3,  (!  ata" class="sref">ss="sref"ss="sref">chip, 
 41flag""+code=irq_get_handl<>,  (!IRQF_   ID (!chip, EINV6/span>
  6/span>
 4006irq_chip<6a> = {
6iomains,
,
 441                 6k,
 441                ,
 456 6e,
 =q_mapoop"+code=ctrl" claia> =q_mapoop"inctrxx.c#L395" id="s class=="li0_ank"oop"+code=ctrl" clas class=="li0_ank"oop"">samsuss="sref">d-> 6};
 351  mairq_exit" class=mai69">3c64=s=51"> 351  s>   = <="li0ef="+s=irq_exit" class=7" class="li0ef="+mai69">qrl-s3c64xx.c#L452" id="L452" class="line" nam6iment">/*686
 351  xlat="d!qrl-s3c64xx.c#L452" id="L452" class="line" nam6ief">EINV6q,
 4006s="sref">6w)
 369{
 456host_da6a;
]L36ss="sref">d-> 691
 351  clap-s3bl="d!samsun"sref">dev_err(      ,irq" cl-wakein-="lidev, hw6/a>)))
6ref">EINV6L;
 4006="L394"> 694
vi6q,
 441                /*6);
 441                EINV6);
             ." name="L441"> 441                6);
 456 799
 xx.c#L461" id="L461" cllass="sref">s3c64xx_eint_gpio_init(struct sams rl-s3c64xx.c#L452" id="L452" class="line" nam7=1L399"> 79;
d-> 471}
samsung_pin_bank a" class="sref">samsq_linear_revmap(<>va href="+code=chiv">sa0" id="L400" class="line" name="L400"> 4007="L402"> 702
samsung_pin_bankNULme="L467"> 467sa0" id="L400" class="line" name="L400"> 4007=4L402"> 70;
sa0" id="L400" class="line" name="L400"> 4007=5L402"> 704
 390        struct sa0" id="L400" class="line" name="L400"> 4007=6L402"> 70,
 459        struct s3c64xx_0" id="L400" class="line" name="L400"> 4007=7L402"> 70/a>);
 4007=8L402"> 70/a>);
 */7//a>);
va href="+code=chiv">saq_linear_revmap(of_n1" a href="+code=cof_n1" "+coqung_pin_banknirq_exit" class=ni">sa ass="sref">d-> 407};
nirq_exit" class=ni">sa  ass="sref">d-> 710
samsung_pin_banknirq_exit" class=ni">sa0" id="L400" class="line" name="L400"> 4007"sref">de7c)
 4007""L402"> 72{
7"sref">ir7);
7"5L402"> 7);
sa rl-s3c64xx.c#L452" id="L452" class="line" nam7ef">drvda7a;
 467sa0" id="L400" class="line" name="L400"> 4007"7L402"> 716
7L8nt"> */7);
s3c64xx_(408        .va href="+code=chiv">sa, sizeof(c64xx_eint_gpio_data" class="sref">s3c64xx_)qung_pin_bankGFP_KERNEme="L467"> 467chip,  718
s3c64xx_)ass="sref">d->     7  do {
v="li"+code=irq_get_handl<>va href="+code=chiv">sa, n"sref">dev_err(dev, "irq number not available7="sref">s7c;
 467sa0" id="L400" class="line" name="L400"> 4007=sref">de7p;
7=L412"> 47n;
s3c64xx_sref">drvdata =  a" class="sref">sams0" id="L400" class="line" name="L400"> 4007=sref">ir7q;
 724
a href="+code=va4xx_mref="+code=eint_maskNUM_ref"0_IRQ+code=ctrl" claNUM_ref"0_IRQd" c; +++code=eint_mask>a href="+code=va4xx_)ass="sref">d->drvda7);
 4007=7L402"> 7);
7=8nt"> */7K;
mairq_exit" class=ia> of_parse "+c>mai"+code=irq_get_handl="li0_nirq_exit" class=="li0_ni">saq_set_chip_dataa href="+code=va4xx_)0" id="L400" class="line" name="L400"> 4007="L418"> 728
,  (!d->gro7p)
v="li"+code=irq_get_handl<>va href="+code=chiv">sa, n"sref">dev_err(dev, a href="+code=va4xx_)0" id="L400" class="line" name="L400"> 4007         7break;
 467 4007="L431"> 731
7 L412"> 47/span>
7 sref">vi7= 1) {
 395        " name="+code=irq_get_handllif (!data->a href="+code=va4xx_]  class="sref">u32 pin 7lt; 8)
 397<    ="+code"line"+code=irq_get_handllif (!s3c64xx_) class="sref">u32 f">drvda7> = 0;
7 7L402"> 7  else
7 8nt"> */7 -= 8;
samsung_pin_bank a" class="sref">samsq_linear_revmap(ne" "d!( struct "+code=ctrl" class=ruct "d" c0" id="L400" class="line" name="L400"> 4007="L418"> 7     }
a href="+code=va4xx_mref="+code=eint_mask a" class="sref">samsq_linear_revmap(ne" "d!(nrruct "+code=ctrl" clanrruct "d" c; +++code=eint_mask>a href="+code=va4xx_, +++code=eint_maskg_pin_bank" class="sref">sa ass="sref">d-> 739
 459        struct ss="sref"0" id="L400" class="line" name="L400"> 4007"sref">pi7);
 4007""L431"> 7/span>
l-> 4007masked...7/span>
s3c64xx_gppap0" id="L400" class="line" name="L400"> 4007mpin 7/span>
group);
 *d = id irq_set_typeref"rTYPE_WKUPe="L467"> 467sa rl-s3c64xx.c#L452" id="L452" class="line" nam7="L446"> 746
 4007m8nt"> */7);
msung_pin_bankta *d = id  4007="L449"> 749
                ) class="sref">u32 des7);
 471}
ss="sref"71rxx.c#L395" id="hivm_kzallova href="+code=chiv">sa,rl-s3c64xx.c#L431" id="L431" class="line" nam7"ped EINT752
ss="sref"sd->GFP_KERNEme="L467"> 467chip, /**7/span>
ss="sref"sdss="sref">d->
v="li"+code=irq_get_handl<>va href="+code=chiv">sa, n"sref">dev_err(dev, "irq number not available7s>group
 467sa0" id="L400" class="line" name="L400"> 4007ment"> */7/span>
7ss="sref"7d)
ss="sref"465"> 465       ta *ta * 4007m        78{
da7a;
d = ia> =ss="sref">s3c64xx_gpio_irq_mapn408        .s3c64xx_gpio_irq_mapoadd ref=ar"+code=irq_get_handlta *d = of_n1" a href="+code=cof_n1" "+coqrl-s3c64xx.c#L449" id="L449" class="line" nam7"ref">des7k;
c#L457" id="L457" class="li0ef=""oop"+code=ctrl" clas class=="li0_ank"oop"">saqung_pin_bank  ata" class="sref">ss="sref"ss="sref">chip,  47v;
 *d = ia> =ss="sref">s3c64xx_gpio_irq_mapsdss="sref">d-> 7s;
v="li"+code=irq_get_handl<>va href="+code=chiv">sa, n"sref">dev_err( 4 rq_map add fail46">dev, "irq number not available7ss="sref"7i;
 467 4007="L464"> 764
7">group) {
7"ent"> */7pan>);
 *d = id  4007=s="sref"7L;
msung_pin_bankta *d = id  4007468  7     }
s3c64xx_gppapmsu0="+code=eint_mask" class="line" name="L317">l +++code=eint_maskp"sref">s3c64xx_gppapq_set_chip_data ass=ass== 1sdss="sref">d-> 769
 a67"> 1) rl-s3c64xx.c#L452" id="L452" class="line" nam7domains = 0;
 4007">pin_ban7s;
irq_linear_revmap(data->,  (!ta *d = ia> =ss="sref">s3c64xx_gpio_irq_map0" id="L400" class="line" name="L400"> 4007""L452"> 772
s3c64xx_ss="sref">d->data->,  (! 366    p"sref">s3c64xx_gppap0" id="L400" class="line" name="L400"> 4007"s="sref"7urn 0;
ss="sref"465"> 465       t data->s3c64xx_gppap]L366"> 366    lif (! 4007""L464"> 74}
 4007">group
7="
7=s="sref"7/span>
  7/span>
 4007irq_chip<7a> = {
7iomains,
,
"line"    -controlme= 0"L456" class="line" name="L456"> 456 7k,
 390        struct  390" classss=ruct "0ref">]L36ss="sref">d->,
dev_err(,  7e,
dev_err(, group};
dev_err(, 
dev_err(, ,
dev_err(,   7w)
dev_err(,  379{
dev_err(, ;
dev_err(,  791
dev_err(, hw7/a>)))
dev_err(, ;
dev_err(,  794
dev_err(, group,
dev_err(, );
dev_err(dev, );
dev_err(,   7);
dev_err(,  899
dev_err(,  89;
 4008"L401"> 481}
 802
 441                 80;
 441                 804
 441                 80,
 456 80/a>);
 390        str> 390" classss=r>]L36ss="sref">d-> 80/a>);
d-> 80/a>);
 456 408};
 351  pstruct "+code=ctrl" class=ruct "d" c.c#L43=s=51"> 351  s>   =  390" classss=ruct "0ref"qrl-s3c64xx.c#L449" id="L449" class="line" nam8L1L399"> 810
 351  nrruct "+code=ctrl" clanrruct "d" c .c#L43=s=51"> 351  ARRAY_SIZE_base" class="sARRAY_SIZE"+code=irq_get_handls>   =  390" classss=ruct "0ref"nqrl-s3c64xx.c#L449" id="L449" class="line" nam8"sref">de8c)
 351  id msung_pin_banks class=="liagpio_anit+code=ctrl" clas class=="liagpio_anitref"qrl-s3c64xx.c#L449" id="L449" class="line" nam8L"L402"> 82{
 351  id msung_pin_banks class=="lia="li0_anit+code=ctrl" clas class=="li=="li0_anit69">qrl-s3c64xx.c#L449" id="L449" class="line" nam8L4L402"> 8);
 351  labep="L390"> 390dev_err(,  8);
drvda8a;
 4008"7L402"> 816

The origicommLXR software by the  id="L400http://source="Lge.net/projects/lxr">LXR L442unityq_this experi2" iommlassion by  id="L400mailto:lxr@refux.no/alxr@refux.no.
lxr.refux.no kindly