]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'gpio/next' of git://git.secretlab.ca/git/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Oct 2011 14:27:45 +0000 (07:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Oct 2011 14:27:45 +0000 (07:27 -0700)
* 'gpio/next' of git://git.secretlab.ca/git/linux-2.6:
  h8300: Move gpio.h to gpio-internal.h
  gpio: pl061: add DT binding support
  gpio: fix build error in include/asm-generic/gpio.h
  gpiolib: Ensure struct gpio is always defined
  irq: Add EXPORT_SYMBOL_GPL to function of irq generic-chip
  gpio-ml-ioh: Use NUMA_NO_NODE not GFP_KERNEL
  gpio-pch: Use NUMA_NO_NODE not GFP_KERNEL
  gpio: langwell: ensure alternate function is cleared
  gpio-pch: Support interrupt function
  gpio-pch: Save register value in suspend()
  gpio-pch: modify gpio_nums and mask
  gpio-pch: support ML7223 IOH n-Bus
  gpio-pch: add spinlock in suspend/resume processing
  gpio-pch: Delete invalid "restore" code in suspend()
  gpio-ml-ioh: Fix suspend/resume issue
  gpio-ml-ioh: Support interrupt function
  gpio-ml-ioh: Delete unnecessary code
  gpio/mxc: add chained_irq_enter/exit() to mx3_gpio_irq_handler()
  gpio/nomadik: use genirq core to track enablement
  gpio/nomadik: disable clocks when unused

15 files changed:
arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
arch/h8300/include/asm/gpio-internal.h [moved from arch/h8300/include/asm/gpio.h with 100% similarity]
arch/h8300/platform/h8300h/irq.c
arch/h8300/platform/h8s/irq.c
drivers/gpio/Kconfig
drivers/gpio/gpio-langwell.c
drivers/gpio/gpio-ml-ioh.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-nomadik.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-pl061.c
include/asm-generic/gpio.h
include/linux/amba/pl061.h
include/linux/gpio.h
kernel/irq/generic-chip.c

index 3ba4d8f8073baf10279e3c69122c822c87d8bb1c..9605bf227df9e9ebca2ccda718f8e4aa7a81c9f8 100644 (file)
@@ -67,6 +67,9 @@ extern int nmk_gpio_get_mode(int gpio);
 extern void nmk_gpio_wakeups_suspend(void);
 extern void nmk_gpio_wakeups_resume(void);
 
+extern void nmk_gpio_clocks_enable(void);
+extern void nmk_gpio_clocks_disable(void);
+
 extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
 
 /*
index e977345105d7d83707ad9d0557e5577368822885..bc4f51bceef5e3927682feba994c78dc16e98dc5 100644 (file)
@@ -11,7 +11,7 @@
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
+#include <asm/gpio-internal.h>
 #include <asm/regs306x.h>
 
 const int __initdata h8300_saved_vectors[] = {
index 8182f041f82956abb8be40d35a7fc5df0c952cfb..7b5f29febc0740a53d11ec410e892b813dee792a 100644 (file)
@@ -14,7 +14,7 @@
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
+#include <asm/gpio-internal.h>
 #include <asm/regs267x.h>
 
 /* saved vector list */
index 4caa3d37bbde5783164f47cc68e278bb4d243c0d..cb0bd078efc030887f31548b4c6f8d97abfa3eaf 100644 (file)
@@ -397,6 +397,7 @@ config GPIO_LANGWELL
 config GPIO_PCH
        tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO"
        depends on PCI && X86
+       select GENERIC_IRQ_CHIP
        help
          This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
          which is an IOH(Input/Output Hub) for x86 embedded processor.
@@ -411,6 +412,7 @@ config GPIO_PCH
 config GPIO_ML_IOH
        tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
        depends on PCI
+       select GENERIC_IRQ_CHIP
        help
          ML7213 is companion chip for Intel Atom E6xx series.
          This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
index d2eb57c60e0ed874c2e68790c14ac2d0d0531ada..00692e89ef878ac20834354df75f173d40fe68b8 100644 (file)
@@ -59,6 +59,7 @@ enum GPIO_REG {
        GRER,           /* rising edge detect */
        GFER,           /* falling edge detect */
        GEDR,           /* edge detect result */
+       GAFR,           /* alt function */
 };
 
 struct lnw_gpio {
@@ -81,6 +82,31 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
        return ptr;
 }
 
+static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
+                                  enum GPIO_REG reg_type)
+{
+       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       unsigned nreg = chip->ngpio / 32;
+       u8 reg = offset / 16;
+       void __iomem *ptr;
+
+       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
+       return ptr;
+}
+
+static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR);
+       u32 value = readl(gafr);
+       int shift = (offset % 16) << 1, af = (value >> shift) & 3;
+
+       if (af) {
+               value &= ~(3 << shift);
+               writel(value, gafr);
+       }
+       return 0;
+}
+
 static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        void __iomem *gplr = gpio_reg(chip, offset, GPLR);
@@ -321,6 +347,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        lnw->reg_base = base;
        lnw->irq_base = irq_base;
        lnw->chip.label = dev_name(&pdev->dev);
+       lnw->chip.request = lnw_gpio_request;
        lnw->chip.direction_input = lnw_gpio_direction_input;
        lnw->chip.direction_output = lnw_gpio_direction_output;
        lnw->chip.get = lnw_gpio_get;
index a9016f56ed7e012f7f66fb08ce32e55a1301f4b7..3aa6beec8c1e71b1e08527b43c6dbbd9e3f8f037 100644 (file)
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#define IOH_EDGE_FALLING       0
+#define IOH_EDGE_RISING                BIT(0)
+#define IOH_LEVEL_L            BIT(1)
+#define IOH_LEVEL_H            (BIT(0) | BIT(1))
+#define IOH_EDGE_BOTH          BIT(2)
+#define IOH_IM_MASK            (BIT(0) | BIT(1) | BIT(2))
+
+#define IOH_IRQ_BASE           0
 
 #define PCI_VENDOR_ID_ROHM             0x10DB
 
@@ -46,12 +57,22 @@ struct ioh_regs {
 
 /**
  * struct ioh_gpio_reg_data - The register store data.
+ * @ien_reg    To store contents of interrupt enable register.
+ * @imask_reg: To store contents of interrupt mask regist
  * @po_reg:    To store contents of PO register.
  * @pm_reg:    To store contents of PM register.
+ * @im0_reg:   To store contents of interrupt mode regist0
+ * @im1_reg:   To store contents of interrupt mode regist1
+ * @use_sel_reg: To store contents of GPIO_USE_SEL0~3
  */
 struct ioh_gpio_reg_data {
+       u32 ien_reg;
+       u32 imask_reg;
        u32 po_reg;
        u32 pm_reg;
+       u32 im0_reg;
+       u32 im1_reg;
+       u32 use_sel_reg;
 };
 
 /**
@@ -62,7 +83,11 @@ struct ioh_gpio_reg_data {
  * @gpio:                      Data for GPIO infrastructure.
  * @ioh_gpio_reg:              Memory mapped Register data is saved here
  *                             when suspend.
+ * @gpio_use_sel:              Save GPIO_USE_SEL1~4 register for PM
  * @ch:                                Indicate GPIO channel
+ * @irq_base:          Save base of IRQ number for interrupt
+ * @spinlock:          Used for register access protection in
+ *                             interrupt context ioh_irq_type and PM;
  */
 struct ioh_gpio {
        void __iomem *base;
@@ -70,8 +95,11 @@ struct ioh_gpio {
        struct device *dev;
        struct gpio_chip gpio;
        struct ioh_gpio_reg_data ioh_gpio_reg;
+       u32 gpio_use_sel;
        struct mutex lock;
        int ch;
+       int irq_base;
+       spinlock_t spinlock;
 };
 
 static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@@ -145,8 +173,25 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
  */
 static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
 {
-       chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po);
-       chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm);
+       int i;
+
+       for (i = 0; i < 8; i ++, chip++) {
+               chip->ioh_gpio_reg.po_reg =
+                                       ioread32(&chip->reg->regs[chip->ch].po);
+               chip->ioh_gpio_reg.pm_reg =
+                                       ioread32(&chip->reg->regs[chip->ch].pm);
+               chip->ioh_gpio_reg.ien_reg =
+                                      ioread32(&chip->reg->regs[chip->ch].ien);
+               chip->ioh_gpio_reg.imask_reg =
+                                    ioread32(&chip->reg->regs[chip->ch].imask);
+               chip->ioh_gpio_reg.im0_reg =
+                                     ioread32(&chip->reg->regs[chip->ch].im_0);
+               chip->ioh_gpio_reg.im1_reg =
+                                     ioread32(&chip->reg->regs[chip->ch].im_1);
+               if (i < 4)
+                       chip->ioh_gpio_reg.use_sel_reg =
+                                          ioread32(&chip->reg->ioh_sel_reg[i]);
+       }
 }
 
 /*
@@ -154,13 +199,34 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
  */
 static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
 {
-       /* to store contents of PO register */
-       iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po);
-       /* to store contents of PM register */
-       iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
+       int i;
+
+       for (i = 0; i < 8; i ++, chip++) {
+               iowrite32(chip->ioh_gpio_reg.po_reg,
+                         &chip->reg->regs[chip->ch].po);
+               iowrite32(chip->ioh_gpio_reg.pm_reg,
+                         &chip->reg->regs[chip->ch].pm);
+               iowrite32(chip->ioh_gpio_reg.ien_reg,
+                         &chip->reg->regs[chip->ch].ien);
+               iowrite32(chip->ioh_gpio_reg.imask_reg,
+                         &chip->reg->regs[chip->ch].imask);
+               iowrite32(chip->ioh_gpio_reg.im0_reg,
+                         &chip->reg->regs[chip->ch].im_0);
+               iowrite32(chip->ioh_gpio_reg.im1_reg,
+                         &chip->reg->regs[chip->ch].im_1);
+               if (i < 4)
+                       iowrite32(chip->ioh_gpio_reg.use_sel_reg,
+                                 &chip->reg->ioh_sel_reg[i]);
+       }
 }
 #endif
 
+static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
+{
+       struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+       return chip->irq_base + offset;
+}
+
 static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
 {
        struct gpio_chip *gpio = &chip->gpio;
@@ -175,16 +241,148 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
        gpio->base = -1;
        gpio->ngpio = num_port;
        gpio->can_sleep = 0;
+       gpio->to_irq = ioh_gpio_to_irq;
+}
+
+static int ioh_irq_type(struct irq_data *d, unsigned int type)
+{
+       u32 im;
+       u32 *im_reg;
+       u32 ien;
+       u32 im_pos;
+       int ch;
+       unsigned long flags;
+       u32 val;
+       int irq = d->irq;
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct ioh_gpio *chip = gc->private;
+
+       ch = irq - chip->irq_base;
+       if (irq <= chip->irq_base + 7) {
+               im_reg = &chip->reg->regs[chip->ch].im_0;
+               im_pos = ch;
+       } else {
+               im_reg = &chip->reg->regs[chip->ch].im_1;
+               im_pos = ch - 8;
+       }
+       dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
+               __func__, irq, type, ch, im_pos, type);
+
+       spin_lock_irqsave(&chip->spinlock, flags);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               val = IOH_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               val = IOH_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               val = IOH_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               val = IOH_LEVEL_H;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               val = IOH_LEVEL_L;
+               break;
+       case IRQ_TYPE_PROBE:
+               goto end;
+       default:
+               dev_warn(chip->dev, "%s: unknown type(%dd)",
+                       __func__, type);
+               goto end;
+       }
+
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(IOH_IM_MASK << (im_pos * 4));
+       iowrite32(im | (val << (im_pos * 4)), im_reg);
+
+       /* iclr */
+       iowrite32(BIT(ch), &chip->reg->regs[chip->ch].iclr);
+
+       /* IMASKCLR */
+       iowrite32(BIT(ch), &chip->reg->regs[chip->ch].imaskclr);
+
+       /* Enable interrupt */
+       ien = ioread32(&chip->reg->regs[chip->ch].ien);
+       iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
+end:
+       spin_unlock_irqrestore(&chip->spinlock, flags);
+
+       return 0;
+}
+
+static void ioh_irq_unmask(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct ioh_gpio *chip = gc->private;
+
+       iowrite32(1 << (d->irq - chip->irq_base),
+                 &chip->reg->regs[chip->ch].imaskclr);
+}
+
+static void ioh_irq_mask(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct ioh_gpio *chip = gc->private;
+
+       iowrite32(1 << (d->irq - chip->irq_base),
+                 &chip->reg->regs[chip->ch].imask);
+}
+
+static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
+{
+       struct ioh_gpio *chip = dev_id;
+       u32 reg_val;
+       int i, j;
+       int ret = IRQ_NONE;
+
+       for (i = 0; i < 8; i++) {
+               reg_val = ioread32(&chip->reg->regs[i].istatus);
+               for (j = 0; j < num_ports[i]; j++) {
+                       if (reg_val & BIT(j)) {
+                               dev_dbg(chip->dev,
+                                       "%s:[%d]:irq=%d status=0x%x\n",
+                                       __func__, j, irq, reg_val);
+                               iowrite32(BIT(j),
+                                         &chip->reg->regs[chip->ch].iclr);
+                               generic_handle_irq(chip->irq_base + j);
+                               ret = IRQ_HANDLED;
+                       }
+               }
+       }
+       return ret;
+}
+
+static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
+                               unsigned int irq_start, unsigned int num)
+{
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+
+       gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base,
+                                   handle_simple_irq);
+       gc->private = chip;
+       ct = gc->chip_types;
+
+       ct->chip.irq_mask = ioh_irq_mask;
+       ct->chip.irq_unmask = ioh_irq_unmask;
+       ct->chip.irq_set_type = ioh_irq_type;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
 static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
                                    const struct pci_device_id *id)
 {
        int ret;
-       int i;
+       int i, j;
        struct ioh_gpio *chip;
        void __iomem *base;
        void __iomem *chip_save;
+       int irq_base;
 
        ret = pci_enable_device(pdev);
        if (ret) {
@@ -228,10 +426,41 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
        }
 
        chip = chip_save;
+       for (j = 0; j < 8; j++, chip++) {
+               irq_base = irq_alloc_descs(-1, IOH_IRQ_BASE, num_ports[j],
+                                          NUMA_NO_NODE);
+               if (irq_base < 0) {
+                       dev_warn(&pdev->dev,
+                               "ml_ioh_gpio: Failed to get IRQ base num\n");
+                       chip->irq_base = -1;
+                       goto err_irq_alloc_descs;
+               }
+               chip->irq_base = irq_base;
+               ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]);
+       }
+
+       chip = chip_save;
+       ret = request_irq(pdev->irq, ioh_gpio_handler,
+                            IRQF_SHARED, KBUILD_MODNAME, chip);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "%s request_irq failed\n", __func__);
+               goto err_request_irq;
+       }
+
        pci_set_drvdata(pdev, chip);
 
        return 0;
 
+err_request_irq:
+       chip = chip_save;
+err_irq_alloc_descs:
+       while (--j >= 0) {
+               chip--;
+               irq_free_descs(chip->irq_base, num_ports[j]);
+       }
+
+       chip = chip_save;
 err_gpiochip_add:
        while (--i >= 0) {
                chip--;
@@ -264,7 +493,11 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
        void __iomem *chip_save;
 
        chip_save = chip;
+
+       free_irq(pdev->irq, chip);
+
        for (i = 0; i < 8; i++, chip++) {
+               irq_free_descs(chip->irq_base, num_ports[i]);
                err = gpiochip_remove(&chip->gpio);
                if (err)
                        dev_err(&pdev->dev, "Failed gpiochip_remove\n");
@@ -282,9 +515,11 @@ static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        s32 ret;
        struct ioh_gpio *chip = pci_get_drvdata(pdev);
+       unsigned long flags;
 
+       spin_lock_irqsave(&chip->spinlock, flags);
        ioh_gpio_save_reg_conf(chip);
-       ioh_gpio_restore_reg_conf(chip);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        ret = pci_save_state(pdev);
        if (ret) {
@@ -304,6 +539,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
 {
        s32 ret;
        struct ioh_gpio *chip = pci_get_drvdata(pdev);
+       unsigned long flags;
 
        ret = pci_enable_wake(pdev, PCI_D0, 0);
 
@@ -315,9 +551,11 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
        }
        pci_restore_state(pdev);
 
+       spin_lock_irqsave(&chip->spinlock, flags);
        iowrite32(0x01, &chip->reg->srst);
        iowrite32(0x00, &chip->reg->srst);
        ioh_gpio_restore_reg_conf(chip);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
index 4340acae3bd3791d713b61022c13d8ed13ed4718..82f7b65baf7216a337b44ba46af2a956cde6cdb8 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <asm-generic/bug.h>
+#include <asm/mach/irq.h>
 
 enum mxc_gpio_hwtype {
        IMX1_GPIO,      /* runs on i.mx1 */
@@ -232,10 +233,15 @@ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
 {
        u32 irq_stat;
        struct mxc_gpio_port *port = irq_get_handler_data(irq);
+       struct irq_chip *chip = irq_get_chip(irq);
+
+       chained_irq_enter(chip, desc);
 
        irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR);
 
        mxc_gpio_irq_handler(port, irq_stat);
+
+       chained_irq_exit(chip, desc);
 }
 
 /* MX2 has one interrupt *for all* gpio ports */
index 740caed2b278bc4defd03dccb5444885ec6804d2..1ebedfb6d46dba7cb7c30e2a9400f6400e8b9159 100644 (file)
@@ -59,7 +59,6 @@ struct nmk_gpio_chip {
        u32 rwimsc;
        u32 fwimsc;
        u32 slpm;
-       u32 enabled;
        u32 pull_up;
 };
 
@@ -277,6 +276,8 @@ static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
                if (!chip)
                        break;
 
+               clk_enable(chip->clk);
+
                slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
                writel(temp, chip->addr + NMK_GPIO_SLPC);
        }
@@ -293,6 +294,8 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
                        break;
 
                writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
+
+               clk_disable(chip->clk);
        }
 }
 
@@ -337,10 +340,12 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
                        break;
                }
 
+               clk_enable(nmk_chip->clk);
                spin_lock(&nmk_chip->lock);
                __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
                                 cfgs[i], sleep, glitch ? slpm : NULL);
                spin_unlock(&nmk_chip->lock);
+               clk_disable(nmk_chip->clk);
        }
 
        if (glitch)
@@ -425,6 +430,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
        if (!nmk_chip)
                return -EINVAL;
 
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
        spin_lock(&nmk_chip->lock);
 
@@ -432,6 +438,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
 
        spin_unlock(&nmk_chip->lock);
        spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
@@ -458,9 +465,11 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
        if (!nmk_chip)
                return -EINVAL;
 
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_chip->lock, flags);
        __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
@@ -484,9 +493,11 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
        if (!nmk_chip)
                return -EINVAL;
 
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_chip->lock, flags);
        __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
@@ -503,9 +514,13 @@ int nmk_gpio_get_mode(int gpio)
 
        bit = 1 << (gpio - nmk_chip->chip.base);
 
+       clk_enable(nmk_chip->clk);
+
        afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
        bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
 
+       clk_disable(nmk_chip->clk);
+
        return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
 }
 EXPORT_SYMBOL(nmk_gpio_get_mode);
@@ -526,7 +541,10 @@ static void nmk_gpio_irq_ack(struct irq_data *d)
        nmk_chip = irq_data_get_irq_chip_data(d);
        if (!nmk_chip)
                return;
+
+       clk_enable(nmk_chip->clk);
        writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
+       clk_disable(nmk_chip->clk);
 }
 
 enum nmk_gpio_irq_type {
@@ -587,11 +605,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
        if (!nmk_chip)
                return -EINVAL;
 
-       if (enable)
-               nmk_chip->enabled |= bitmask;
-       else
-               nmk_chip->enabled &= ~bitmask;
-
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
        spin_lock(&nmk_chip->lock);
 
@@ -602,6 +616,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
 
        spin_unlock(&nmk_chip->lock);
        spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
@@ -629,10 +644,11 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
                return -EINVAL;
        bitmask = nmk_gpio_get_bitmask(gpio);
 
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
        spin_lock(&nmk_chip->lock);
 
-       if (!(nmk_chip->enabled & bitmask))
+       if (irqd_irq_disabled(d))
                __nmk_gpio_set_wake(nmk_chip, gpio, on);
 
        if (on)
@@ -642,13 +658,15 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
 
        spin_unlock(&nmk_chip->lock);
        spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
 
 static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       bool enabled, wake = irqd_is_wakeup_set(d);
+       bool enabled = !irqd_irq_disabled(d);
+       bool wake = irqd_is_wakeup_set(d);
        int gpio;
        struct nmk_gpio_chip *nmk_chip;
        unsigned long flags;
@@ -665,8 +683,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        if (type & IRQ_TYPE_LEVEL_LOW)
                return -EINVAL;
 
-       enabled = nmk_chip->enabled & bitmask;
-
+       clk_enable(nmk_chip->clk);
        spin_lock_irqsave(&nmk_chip->lock, flags);
 
        if (enabled)
@@ -690,10 +707,28 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
                __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
 
        spin_unlock_irqrestore(&nmk_chip->lock, flags);
+       clk_disable(nmk_chip->clk);
 
        return 0;
 }
 
+static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
+{
+       struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
+
+       clk_enable(nmk_chip->clk);
+       nmk_gpio_irq_unmask(d);
+       return 0;
+}
+
+static void nmk_gpio_irq_shutdown(struct irq_data *d)
+{
+       struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
+
+       nmk_gpio_irq_mask(d);
+       clk_disable(nmk_chip->clk);
+}
+
 static struct irq_chip nmk_gpio_irq_chip = {
        .name           = "Nomadik-GPIO",
        .irq_ack        = nmk_gpio_irq_ack,
@@ -701,6 +736,8 @@ static struct irq_chip nmk_gpio_irq_chip = {
        .irq_unmask     = nmk_gpio_irq_unmask,
        .irq_set_type   = nmk_gpio_irq_set_type,
        .irq_set_wake   = nmk_gpio_irq_set_wake,
+       .irq_startup    = nmk_gpio_irq_startup,
+       .irq_shutdown   = nmk_gpio_irq_shutdown,
 };
 
 static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
@@ -727,7 +764,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
 static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
-       u32 status = readl(nmk_chip->addr + NMK_GPIO_IS);
+       u32 status;
+
+       clk_enable(nmk_chip->clk);
+       status = readl(nmk_chip->addr + NMK_GPIO_IS);
+       clk_disable(nmk_chip->clk);
 
        __nmk_gpio_irq_handler(irq, desc, status);
 }
@@ -773,7 +814,12 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
 
+       clk_enable(nmk_chip->clk);
+
        writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
+
+       clk_disable(nmk_chip->clk);
+
        return 0;
 }
 
@@ -782,8 +828,15 @@ static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
        u32 bit = 1 << offset;
+       int value;
+
+       clk_enable(nmk_chip->clk);
 
-       return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+       value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
+
+       clk_disable(nmk_chip->clk);
+
+       return value;
 }
 
 static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
@@ -792,7 +845,11 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
 
+       clk_enable(nmk_chip->clk);
+
        __nmk_gpio_set_output(nmk_chip, offset, val);
+
+       clk_disable(nmk_chip->clk);
 }
 
 static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
@@ -801,8 +858,12 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
 
+       clk_enable(nmk_chip->clk);
+
        __nmk_gpio_make_output(nmk_chip, offset, val);
 
+       clk_disable(nmk_chip->clk);
+
        return 0;
 }
 
@@ -833,6 +894,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                [NMK_GPIO_ALT_C]        = "altC",
        };
 
+       clk_enable(nmk_chip->clk);
+
        for (i = 0; i < chip->ngpio; i++, gpio++) {
                const char *label = gpiochip_is_requested(chip, i);
                bool pull;
@@ -877,6 +940,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 
                seq_printf(s, "\n");
        }
+
+       clk_disable(nmk_chip->clk);
 }
 
 #else
@@ -894,6 +959,34 @@ static struct gpio_chip nmk_gpio_template = {
        .can_sleep              = 0,
 };
 
+void nmk_gpio_clocks_enable(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_BANKS; i++) {
+               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+               if (!chip)
+                       continue;
+
+               clk_enable(chip->clk);
+       }
+}
+
+void nmk_gpio_clocks_disable(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_BANKS; i++) {
+               struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
+
+               if (!chip)
+                       continue;
+
+               clk_disable(chip->clk);
+       }
+}
+
 /*
  * Called from the suspend/resume path to only keep the real wakeup interrupts
  * (those that have had set_irq_wake() called on them) as wakeup interrupts,
@@ -913,6 +1006,8 @@ void nmk_gpio_wakeups_suspend(void)
                if (!chip)
                        break;
 
+               clk_enable(chip->clk);
+
                chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
                chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
 
@@ -927,6 +1022,8 @@ void nmk_gpio_wakeups_suspend(void)
                        /* 0 -> wakeup enable */
                        writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
                }
+
+               clk_disable(chip->clk);
        }
 }
 
@@ -940,11 +1037,15 @@ void nmk_gpio_wakeups_resume(void)
                if (!chip)
                        break;
 
+               clk_enable(chip->clk);
+
                writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
                writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
 
                if (chip->sleepmode)
                        writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
+
+               clk_disable(chip->clk);
        }
 }
 
@@ -1011,8 +1112,6 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
                goto out_release;
        }
 
-       clk_enable(clk);
-
        nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
        if (!nmk_chip) {
                ret = -ENOMEM;
index 36919e77c495cb97c3ae3a5896a6d7dabdce38df..1e8a4a5388108b756e132203d11115401d7f58c8 100644 (file)
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 
-#define PCH_GPIO_ALL_PINS      0xfff /* Mask for GPIO pins 0 to 11 */
-#define GPIO_NUM_PINS  12      /* Specifies number of GPIO PINS GPIO0-GPIO11 */
+#define PCH_EDGE_FALLING       0
+#define PCH_EDGE_RISING                BIT(0)
+#define PCH_LEVEL_L            BIT(1)
+#define PCH_LEVEL_H            (BIT(0) | BIT(1))
+#define PCH_EDGE_BOTH          BIT(2)
+#define PCH_IM_MASK            (BIT(0) | BIT(1) | BIT(2))
+
+#define PCH_IRQ_BASE           24
 
 struct pch_regs {
        u32     ien;
@@ -33,18 +41,43 @@ struct pch_regs {
        u32     pm;
        u32     im0;
        u32     im1;
-       u32     reserved[4];
+       u32     reserved[3];
+       u32     gpio_use_sel;
        u32     reset;
 };
 
+enum pch_type_t {
+       INTEL_EG20T_PCH,
+       OKISEMI_ML7223m_IOH, /* OKISEMI ML7223 IOH PCIe Bus-m */
+       OKISEMI_ML7223n_IOH  /* OKISEMI ML7223 IOH PCIe Bus-n */
+};
+
+/* Specifies number of GPIO PINS */
+static int gpio_pins[] = {
+       [INTEL_EG20T_PCH] = 12,
+       [OKISEMI_ML7223m_IOH] = 8,
+       [OKISEMI_ML7223n_IOH] = 8,
+};
+
 /**
  * struct pch_gpio_reg_data - The register store data.
+ * @ien_reg:   To store contents of IEN register.
+ * @imask_reg: To store contents of IMASK register.
  * @po_reg:    To store contents of PO register.
  * @pm_reg:    To store contents of PM register.
+ * @im0_reg:   To store contents of IM0 register.
+ * @im1_reg:   To store contents of IM1 register.
+ * @gpio_use_sel_reg : To store contents of GPIO_USE_SEL register.
+ *                    (Only ML7223 Bus-n)
  */
 struct pch_gpio_reg_data {
+       u32 ien_reg;
+       u32 imask_reg;
        u32 po_reg;
        u32 pm_reg;
+       u32 im0_reg;
+       u32 im1_reg;
+       u32 gpio_use_sel_reg;
 };
 
 /**
@@ -55,6 +88,12 @@ struct pch_gpio_reg_data {
  * @gpio:                      Data for GPIO infrastructure.
  * @pch_gpio_reg:              Memory mapped Register data is saved here
  *                             when suspend.
+ * @lock:                      Used for register access protection
+ * @irq_base:          Save base of IRQ number for interrupt
+ * @ioh:               IOH ID
+ * @spinlock:          Used for register access protection in
+ *                             interrupt context pch_irq_mask,
+ *                             pch_irq_unmask and pch_irq_type;
  */
 struct pch_gpio {
        void __iomem *base;
@@ -63,6 +102,9 @@ struct pch_gpio {
        struct gpio_chip gpio;
        struct pch_gpio_reg_data pch_gpio_reg;
        struct mutex lock;
+       int irq_base;
+       enum pch_type_t ioh;
+       spinlock_t spinlock;
 };
 
 static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
@@ -96,7 +138,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
        u32 reg_val;
 
        mutex_lock(&chip->lock);
-       pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS;
+       pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
        pm |= (1 << nr);
        iowrite32(pm, &chip->reg->pm);
 
@@ -118,7 +160,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
        u32 pm;
 
        mutex_lock(&chip->lock);
-       pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/
+       pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
        pm &= ~(1 << nr);
        iowrite32(pm, &chip->reg->pm);
        mutex_unlock(&chip->lock);
@@ -131,8 +173,16 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
  */
 static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
 {
+       chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien);
+       chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask);
        chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po);
        chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm);
+       chip->pch_gpio_reg.im0_reg = ioread32(&chip->reg->im0);
+       if (chip->ioh == INTEL_EG20T_PCH)
+               chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1);
+       if (chip->ioh == OKISEMI_ML7223n_IOH)
+               chip->pch_gpio_reg.gpio_use_sel_reg =\
+                                           ioread32(&chip->reg->gpio_use_sel);
 }
 
 /*
@@ -140,10 +190,24 @@ static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
  */
 static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
 {
+       iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien);
+       iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask);
        /* to store contents of PO register */
        iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po);
        /* to store contents of PM register */
        iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm);
+       iowrite32(chip->pch_gpio_reg.im0_reg, &chip->reg->im0);
+       if (chip->ioh == INTEL_EG20T_PCH)
+               iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1);
+       if (chip->ioh == OKISEMI_ML7223n_IOH)
+               iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
+                         &chip->reg->gpio_use_sel);
+}
+
+static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
+{
+       struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+       return chip->irq_base + offset;
 }
 
 static void pch_gpio_setup(struct pch_gpio *chip)
@@ -158,8 +222,132 @@ static void pch_gpio_setup(struct pch_gpio *chip)
        gpio->set = pch_gpio_set;
        gpio->dbg_show = NULL;
        gpio->base = -1;
-       gpio->ngpio = GPIO_NUM_PINS;
+       gpio->ngpio = gpio_pins[chip->ioh];
        gpio->can_sleep = 0;
+       gpio->to_irq = pch_gpio_to_irq;
+}
+
+static int pch_irq_type(struct irq_data *d, unsigned int type)
+{
+       u32 im;
+       u32 *im_reg;
+       u32 ien;
+       u32 im_pos;
+       int ch;
+       unsigned long flags;
+       u32 val;
+       int irq = d->irq;
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct pch_gpio *chip = gc->private;
+
+       ch = irq - chip->irq_base;
+       if (irq <= chip->irq_base + 7) {
+               im_reg = &chip->reg->im0;
+               im_pos = ch;
+       } else {
+               im_reg = &chip->reg->im1;
+               im_pos = ch - 8;
+       }
+       dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d\n",
+               __func__, irq, type, ch, im_pos);
+
+       spin_lock_irqsave(&chip->spinlock, flags);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               val = PCH_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               val = PCH_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               val = PCH_EDGE_BOTH;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               val = PCH_LEVEL_H;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               val = PCH_LEVEL_L;
+               break;
+       case IRQ_TYPE_PROBE:
+               goto end;
+       default:
+               dev_warn(chip->dev, "%s: unknown type(%dd)",
+                       __func__, type);
+               goto end;
+       }
+
+       /* Set interrupt mode */
+       im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
+       iowrite32(im | (val << (im_pos * 4)), im_reg);
+
+       /* iclr */
+       iowrite32(BIT(ch), &chip->reg->iclr);
+
+       /* IMASKCLR */
+       iowrite32(BIT(ch), &chip->reg->imaskclr);
+
+       /* Enable interrupt */
+       ien = ioread32(&chip->reg->ien);
+       iowrite32(ien | BIT(ch), &chip->reg->ien);
+end:
+       spin_unlock_irqrestore(&chip->spinlock, flags);
+
+       return 0;
+}
+
+static void pch_irq_unmask(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct pch_gpio *chip = gc->private;
+
+       iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imaskclr);
+}
+
+static void pch_irq_mask(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct pch_gpio *chip = gc->private;
+
+       iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask);
+}
+
+static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
+{
+       struct pch_gpio *chip = dev_id;
+       u32 reg_val = ioread32(&chip->reg->istatus);
+       int i;
+       int ret = IRQ_NONE;
+
+       for (i = 0; i < gpio_pins[chip->ioh]; i++) {
+               if (reg_val & BIT(i)) {
+                       dev_dbg(chip->dev, "%s:[%d]:irq=%d  status=0x%x\n",
+                               __func__, i, irq, reg_val);
+                       iowrite32(BIT(i), &chip->reg->iclr);
+                       generic_handle_irq(chip->irq_base + i);
+                       ret = IRQ_HANDLED;
+               }
+       }
+       return ret;
+}
+
+static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
+                               unsigned int irq_start, unsigned int num)
+{
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+
+       gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base,
+                                   handle_simple_irq);
+       gc->private = chip;
+       ct = gc->chip_types;
+
+       ct->chip.irq_mask = pch_irq_mask;
+       ct->chip.irq_unmask = pch_irq_unmask;
+       ct->chip.irq_set_type = pch_irq_type;
+
+       irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+                              IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
 static int __devinit pch_gpio_probe(struct pci_dev *pdev,
@@ -167,6 +355,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
 {
        s32 ret;
        struct pch_gpio *chip;
+       int irq_base;
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (chip == NULL)
@@ -192,6 +381,13 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
                goto err_iomap;
        }
 
+       if (pdev->device == 0x8803)
+               chip->ioh = INTEL_EG20T_PCH;
+       else if (pdev->device == 0x8014)
+               chip->ioh = OKISEMI_ML7223m_IOH;
+       else if (pdev->device == 0x8043)
+               chip->ioh = OKISEMI_ML7223n_IOH;
+
        chip->reg = chip->base;
        pci_set_drvdata(pdev, chip);
        mutex_init(&chip->lock);
@@ -202,8 +398,36 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
                goto err_gpiochip_add;
        }
 
+       irq_base = irq_alloc_descs(-1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE);
+       if (irq_base < 0) {
+               dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n");
+               chip->irq_base = -1;
+               goto end;
+       }
+       chip->irq_base = irq_base;
+
+       ret = request_irq(pdev->irq, pch_gpio_handler,
+                            IRQF_SHARED, KBUILD_MODNAME, chip);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "%s request_irq failed\n", __func__);
+               goto err_request_irq;
+       }
+
+       pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
+
+       /* Initialize interrupt ien register */
+       iowrite32(0, &chip->reg->ien);
+end:
        return 0;
 
+err_request_irq:
+       irq_free_descs(irq_base, gpio_pins[chip->ioh]);
+
+       ret = gpiochip_remove(&chip->gpio);
+       if (ret)
+               dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
+
 err_gpiochip_add:
        pci_iounmap(pdev, chip->base);
 
@@ -224,6 +448,12 @@ static void __devexit pch_gpio_remove(struct pci_dev *pdev)
        int err;
        struct pch_gpio *chip = pci_get_drvdata(pdev);
 
+       if (chip->irq_base != -1) {
+               free_irq(pdev->irq, chip);
+
+               irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]);
+       }
+
        err = gpiochip_remove(&chip->gpio);
        if (err)
                dev_err(&pdev->dev, "Failed gpiochip_remove\n");
@@ -239,9 +469,11 @@ static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        s32 ret;
        struct pch_gpio *chip = pci_get_drvdata(pdev);
+       unsigned long flags;
 
+       spin_lock_irqsave(&chip->spinlock, flags);
        pch_gpio_save_reg_conf(chip);
-       pch_gpio_restore_reg_conf(chip);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        ret = pci_save_state(pdev);
        if (ret) {
@@ -261,6 +493,7 @@ static int pch_gpio_resume(struct pci_dev *pdev)
 {
        s32 ret;
        struct pch_gpio *chip = pci_get_drvdata(pdev);
+       unsigned long flags;
 
        ret = pci_enable_wake(pdev, PCI_D0, 0);
 
@@ -272,9 +505,11 @@ static int pch_gpio_resume(struct pci_dev *pdev)
        }
        pci_restore_state(pdev);
 
+       spin_lock_irqsave(&chip->spinlock, flags);
        iowrite32(0x01, &chip->reg->reset);
        iowrite32(0x00, &chip->reg->reset);
        pch_gpio_restore_reg_conf(chip);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
@@ -287,6 +522,7 @@ static int pch_gpio_resume(struct pci_dev *pdev)
 static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
        { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
index 2c5a18f32bf30f8dcd6b351f05196ce6e40f26ca..093c90bd3c1d1b1d888ce2465831c95d125e0036 100644 (file)
@@ -118,7 +118,7 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
 {
        struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
 
-       if (chip->irq_base == (unsigned) -1)
+       if (chip->irq_base == NO_IRQ)
                return -EINVAL;
 
        return chip->irq_base + offset;
@@ -246,6 +246,18 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
        if (chip == NULL)
                return -ENOMEM;
 
+       pdata = dev->dev.platform_data;
+       if (pdata) {
+               chip->gc.base = pdata->gpio_base;
+               chip->irq_base = pdata->irq_base;
+       } else if (dev->dev.of_node) {
+               chip->gc.base = -1;
+               chip->irq_base = NO_IRQ;
+       } else {
+               ret = -ENODEV;
+               goto free_mem;
+       }
+
        if (!request_mem_region(dev->res.start,
                                resource_size(&dev->res), "pl061")) {
                ret = -EBUSY;
@@ -267,14 +279,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
        chip->gc.get = pl061_get_value;
        chip->gc.set = pl061_set_value;
        chip->gc.to_irq = pl061_to_irq;
-       chip->gc.base = pdata->gpio_base;
        chip->gc.ngpio = PL061_GPIO_NR;
        chip->gc.label = dev_name(&dev->dev);
        chip->gc.dev = &dev->dev;
        chip->gc.owner = THIS_MODULE;
 
-       chip->irq_base = pdata->irq_base;
-
        ret = gpiochip_add(&chip->gc);
        if (ret)
                goto iounmap;
@@ -283,7 +292,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
         * irq_chip support
         */
 
-       if (chip->irq_base == (unsigned) -1)
+       if (chip->irq_base == NO_IRQ)
                return 0;
 
        writeb(0, chip->base + GPIOIE); /* disable irqs */
@@ -307,11 +316,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
        list_add(&chip->list, chip_list);
 
        for (i = 0; i < PL061_GPIO_NR; i++) {
-               if (pdata->directions & (1 << i))
-                       pl061_direction_output(&chip->gc, i,
-                                       pdata->values & (1 << i));
-               else
-                       pl061_direction_input(&chip->gc, i);
+               if (pdata) {
+                       if (pdata->directions & (1 << i))
+                               pl061_direction_output(&chip->gc, i,
+                                               pdata->values & (1 << i));
+                       else
+                               pl061_direction_input(&chip->gc, i);
+               }
 
                irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip,
                                         handle_simple_irq);
index d494001b12260a2f56b9337e01226f17dcee3634..8c8621097fa0916f770e18eeffa08a410ecf43dd 100644 (file)
@@ -41,6 +41,7 @@ static inline bool gpio_is_valid(int number)
 }
 
 struct device;
+struct gpio;
 struct seq_file;
 struct module;
 struct device_node;
@@ -170,18 +171,6 @@ extern int __gpio_cansleep(unsigned gpio);
 
 extern int __gpio_to_irq(unsigned gpio);
 
-/**
- * struct gpio - a structure describing a GPIO with configuration
- * @gpio:      the GPIO number
- * @flags:     GPIO configuration as specified by GPIOF_*
- * @label:     a literal description string of this GPIO
- */
-struct gpio {
-       unsigned        gpio;
-       unsigned long   flags;
-       const char      *label;
-};
-
 extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
 extern int gpio_request_array(const struct gpio *array, size_t num);
 extern void gpio_free_array(const struct gpio *array, size_t num);
@@ -220,13 +209,13 @@ static inline int gpio_cansleep(unsigned gpio)
 static inline int gpio_get_value_cansleep(unsigned gpio)
 {
        might_sleep();
-       return gpio_get_value(gpio);
+       return __gpio_get_value(gpio);
 }
 
 static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 {
        might_sleep();
-       gpio_set_value(gpio, value);
+       __gpio_set_value(gpio, value);
 }
 
 #endif /* !CONFIG_GPIOLIB */
index 5ddd9ad4b19c9c381d77ab5c24a01031b4127ba3..2412af944f1f584dcc611e17b910e8f55eb79cfc 100644 (file)
@@ -7,8 +7,7 @@ struct pl061_platform_data {
        unsigned        gpio_base;
 
        /* number of the first IRQ.
-        * If the IRQ functionality in not desired this must be set to
-        * (unsigned) -1.
+        * If the IRQ functionality in not desired this must be set to NO_IRQ.
         */
        unsigned        irq_base;
 
index 17b5a0d80e4239cc10fceb670be29dbf4e49a0f0..38ac48b7d3a8db90bf0ff7630df25c2d8880ecb9 100644 (file)
 #define GPIOF_OUT_INIT_LOW     (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
 #define GPIOF_OUT_INIT_HIGH    (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
 
+/**
+ * struct gpio - a structure describing a GPIO with configuration
+ * @gpio:      the GPIO number
+ * @flags:     GPIO configuration as specified by GPIOF_*
+ * @label:     a literal description string of this GPIO
+ */
+struct gpio {
+       unsigned        gpio;
+       unsigned long   flags;
+       const char      *label;
+};
+
 #ifdef CONFIG_GENERIC_GPIO
 #include <asm/gpio.h>
 
 #include <linux/errno.h>
 
 struct device;
-struct gpio;
 struct gpio_chip;
 
-/*
- * Some platforms don't support the GPIO programming interface.
- *
- * In case some driver uses it anyway (it should normally have
- * depended on GENERIC_GPIO), these routines help the compiler
- * optimize out much GPIO-related code ... or trigger a runtime
- * warning when something is wrongly called.
- */
-
 static inline bool gpio_is_valid(int number)
 {
        return false;
index e38544dddb18a143e2a63f2827a56e45f8b1aa53..6cb7613e4bf4250e57ad05c54f0a0a62668676a4 100644 (file)
@@ -211,6 +211,7 @@ irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
        }
        return gc;
 }
+EXPORT_SYMBOL_GPL(irq_alloc_generic_chip);
 
 /*
  * Separate lockdep class for interrupt chip which can nest irq_desc
@@ -258,6 +259,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
        }
        gc->irq_cnt = i - gc->irq_base;
 }
+EXPORT_SYMBOL_GPL(irq_setup_generic_chip);
 
 /**
  * irq_setup_alt_chip - Switch to alternative chip
@@ -281,6 +283,7 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
        }
        return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(irq_setup_alt_chip);
 
 /**
  * irq_remove_generic_chip - Remove a chip
@@ -311,6 +314,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
                irq_modify_status(i, clr, set);
        }
 }
+EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
 
 #ifdef CONFIG_PM
 static int irq_gc_suspend(void)