From: "Chang, Rebecca Swee Fun" <[email protected]>

The GPIO pins are divided into 3 clusters, namely SOUTH,SUS and NORTH.

Signed-off-by: Chang, Rebecca Swee Fun <[email protected]>
---
 ...upport-for-Intel-Baytrail-GPIO-controller.patch |  904 ++++++++++++++++++++
 1 file changed, 904 insertions(+)
 create mode 100644 
meta/cfg/kernel-cache/features/valleyisland-io/0002-gpio-add-support-for-Intel-Baytrail-GPIO-controller.patch

diff --git 
a/meta/cfg/kernel-cache/features/valleyisland-io/0002-gpio-add-support-for-Intel-Baytrail-GPIO-controller.patch
 
b/meta/cfg/kernel-cache/features/valleyisland-io/0002-gpio-add-support-for-Intel-Baytrail-GPIO-controller.patch
new file mode 100644
index 0000000..c6ae730
--- /dev/null
+++ 
b/meta/cfg/kernel-cache/features/valleyisland-io/0002-gpio-add-support-for-Intel-Baytrail-GPIO-controller.patch
@@ -0,0 +1,904 @@
+gpio: add support for Intel Baytrail GPIO controller
+
+The GPIO pins are divided into 3 clusters, namely SOUTH,SUS and NORTH.
+
+Signed-off-by: Chang, Rebecca Swee Fun <[email protected]>
+---
+ drivers/gpio/Kconfig           |   14 +-
+ drivers/gpio/Makefile          |    2 +
+ drivers/gpio/gpio-byt-device.c |  157 ++++++++++
+ drivers/gpio/gpio-byt.c        |  622 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/acpi_gpio.h      |    4 +
+ include/linux/gpio-byt.h       |   16 ++
+ 6 files changed, 814 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/gpio/gpio-byt-device.c
+ create mode 100644 drivers/gpio/gpio-byt.c
+ create mode 100644 include/linux/gpio-byt.h
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 682de75..061f91b 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -224,6 +224,19 @@ config GPIO_TS5500
+         blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
+         LCD port.
+
++config GPIO_BYT
++      bool "Intel BYT GPIO support"
++      select IRQ_DOMAIN
++      help
++        Driver for memory mapped GPIO functionality on Intel BYT chipset.
++        Requires ACPI5 framework or GPIO_BYT_DEVICE to setup GPIO devices.
++
++config GPIO_BYT_DEVICE
++      bool "Intel BYT GPIO Platform Device Emulation"
++      depends on GPIO_BYT
++      help
++        This is for generating BYT GPIO platform devices for Intel BYT where  
          ACPI5 framework is absent.
++
+ config GPIO_VT8500
+       bool "VIA/Wondermedia SoC GPIO Support"
+       depends on ARCH_VT8500
+@@ -685,7 +698,6 @@ config GPIO_MSIC
+         intel MID devices
+
+ comment "USB GPIO expanders:"
+-
+ config GPIO_VIPERBOARD
+       tristate "Viperboard GPIO a & b support"
+       depends on MFD_VIPERBOARD && USB
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index c5aebd0..338f7c4 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -76,6 +76,8 @@ obj-$(CONFIG_GPIO_TS5500)    += gpio-ts5500.o
+ obj-$(CONFIG_GPIO_TWL4030)    += gpio-twl4030.o
+ obj-$(CONFIG_GPIO_TWL6040)    += gpio-twl6040.o
+ obj-$(CONFIG_GPIO_UCB1400)    += gpio-ucb1400.o
++obj-$(CONFIG_GPIO_BYT)                += gpio-byt.o
++obj-$(CONFIG_GPIO_BYT_DEVICE) += gpio-byt-device.o
+ obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
+ obj-$(CONFIG_GPIO_VR41XX)     += gpio-vr41xx.o
+ obj-$(CONFIG_GPIO_VT8500)     += gpio-vt8500.o
+diff --git a/drivers/gpio/gpio-byt-device.c b/drivers/gpio/gpio-byt-device.c
+new file mode 100644
+index 0000000..4cc1459
+--- /dev/null
++++ b/drivers/gpio/gpio-byt-device.c
+@@ -0,0 +1,157 @@
++/*
++ * platform_byt_gpio.c: GPIO Platform Device
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author: Kean Ho, Chew ([email protected])
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; version 2
++ * of the License.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/seq_file.h>
++#include <linux/pci.h>
++#include <linux/gpio-byt.h>
++
++/* PCI Memory Base Access */
++#define PCI_DEVICE_ID_INTEL_BYT_PCU   0x0f1c
++#define NO_REGISTER_SETTINGS  (BIT(0) | BIT(1) | BIT(2))
++
++/* Offsets */
++#define SCORE_OFFSET          0x0
++#define NCORE_OFFSET          0x1000
++#define SUS_OFFSET            0x2000
++#define SCORE_END             0x72C
++#define NCORE_END             0x970
++#define SUS_END                       0x98C
++
++static struct byt_gpio_port byt_gpio_score_platform_data = {
++      .unique_id = "1",
++};
++
++static struct resource byt_gpio_score_resources[] = {
++      {
++              .start  = 0x0,
++              .end    = 0x0,
++              .flags  = IORESOURCE_MEM,
++              .name   = "io-memory",
++      },
++      {
++              .start  = 49,
++              .end    = 49,
++              .flags  = IORESOURCE_IRQ,
++              .name   = "irq",
++      }
++};
++
++static struct byt_gpio_port byt_gpio_ncore_platform_data = {
++      .unique_id = "2",
++};
++
++static struct resource byt_gpio_ncore_resources[] = {
++      {
++              .start  = 0x0,
++              .end    = 0x0,
++              .flags  = IORESOURCE_MEM,
++              .name   = "io-memory",
++      },
++      {
++              .start  = 48,
++              .end    = 48,
++              .flags  = IORESOURCE_IRQ,
++              .name   = "irq",
++      }
++};
++
++static struct byt_gpio_port byt_gpio_sus_platform_data = {
++      .unique_id = "3",
++};
++
++static struct resource byt_gpio_sus_resources[] = {
++      {
++              .start  = 0x0,
++              .end    = 0x0,
++              .flags  = IORESOURCE_MEM,
++              .name   = "io-memory",
++      },
++      {
++              .start  = 50,
++              .end    = 50,
++              .flags  = IORESOURCE_IRQ,
++              .name   = "irq",
++      }
++};
++
++static struct platform_device byt_gpio_score_device = {
++      .name                   = "byt_gpio",
++      .id                     = 0,
++      .num_resources          = ARRAY_SIZE(byt_gpio_score_resources),
++      .resource               = byt_gpio_score_resources,
++      .dev                    = {
++              .platform_data  = &byt_gpio_score_platform_data,
++      }
++};
++
++static struct platform_device byt_gpio_ncore_device = {
++      .name                   = "byt_gpio",
++      .id                     = 1,
++      .num_resources          = ARRAY_SIZE(byt_gpio_ncore_resources),
++      .resource               = byt_gpio_ncore_resources,
++      .dev                    = {
++              .platform_data  = &byt_gpio_ncore_platform_data,
++      }
++};
++
++static struct platform_device byt_gpio_sus_device = {
++      .name                   = "byt_gpio",
++      .id                     = 2,
++      .num_resources          = ARRAY_SIZE(byt_gpio_sus_resources),
++      .resource               = byt_gpio_sus_resources,
++      .dev                    = {
++              .platform_data  = &byt_gpio_sus_platform_data,
++      }
++};
++
++static struct platform_device *devices[] __initdata = {
++      &byt_gpio_score_device,
++      &byt_gpio_ncore_device,
++      &byt_gpio_sus_device,
++};
++
++static int __init get_pci_memory_init(void)
++{
++      u32 io_base_add;
++      struct pci_dev *pci_dev;
++      pci_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
++                              PCI_DEVICE_ID_INTEL_BYT_PCU,
++                              NULL);
++
++      if (pci_dev == NULL) {
++              return -EFAULT;
++      };
++      pci_read_config_dword(pci_dev, 0x4c, &io_base_add);
++      io_base_add &= ~NO_REGISTER_SETTINGS;
++      byt_gpio_score_resources[0].start = io_base_add + SCORE_OFFSET;
++      byt_gpio_score_resources[0].end = io_base_add + SCORE_OFFSET + 
SCORE_END;
++      byt_gpio_ncore_resources[0].start = io_base_add + NCORE_OFFSET;
++      byt_gpio_ncore_resources[0].end = io_base_add + NCORE_OFFSET + 
NCORE_END;
++      byt_gpio_sus_resources[0].start = io_base_add + SUS_OFFSET;
++      byt_gpio_sus_resources[0].end = io_base_add + SUS_OFFSET + SUS_END;
++      return 0;
++};
++rootfs_initcall(get_pci_memory_init);
++
++
++static int __init byt_gpio_device_init(void)
++{
++      return platform_add_devices(devices, ARRAY_SIZE(devices));
++};
++device_initcall(byt_gpio_device_init);
+diff --git a/drivers/gpio/gpio-byt.c b/drivers/gpio/gpio-byt.c
+new file mode 100644
+index 0000000..428c3eb
+--- /dev/null
++++ b/drivers/gpio/gpio-byt.c
+@@ -0,0 +1,622 @@
++/*
++ * GPIO driver for Intel BYT
++ * Copyright (c) 2012, Intel Corporation.
++ *
++ * Author: Mathias Nyman <[email protected]>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License along 
with
++ * this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/gpio.h>
++#include <linux/irqdomain.h>
++#include <linux/acpi.h>
++#include <linux/acpi_gpio.h>
++#include <linux/platform_device.h>
++#include <linux/seq_file.h>
++#include <linux/io.h>
++#include <linux/pm_runtime.h>
++#include <linux/gpio-byt.h>
++
++/* memory mapped register offsets */
++#define BYT_CONF0_REG         0x000
++#define BYT_CONF1_REG         0x004
++#define BYT_VAL_REG           0x008
++#define BYT_DFT_REG           0x00c
++#define BYT_INT_STAT_REG      0x800
++
++/* BYT_CONF0_REG register bits */
++#define BYT_TRIG_NEG          BIT(26)
++#define BYT_TRIG_POS          BIT(25)
++#define BYT_TRIG_LVL          BIT(24)
++#define BYT_PIN_MUX           0x07
++#define BYT_GPIO_FUNC         0x01
++
++/* BYT_VAL_REG register bits */
++#define BYT_INPUT_EN          BIT(2)  /*(active low)*/
++#define BYT_OUTPUT_EN         (BIT(1) | BIT(2))  /*(active low)*/
++#define BYT_LEVEL             BIT(0)
++
++#define BYT_DIR_MASK          (BIT(1) | BIT(2))
++#define BYT_TRIG_MASK         (BIT(26) | BIT(25) | BIT(24))
++
++#define BYT_NGPIO_SCORE               102
++#define BYT_NGPIO_NCORE               28
++#define BYT_NGPIO_SUS         44
++
++/*
++ * Baytrail gpio controller consist of three separate sub-controllers called
++ * SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
++ *
++ * GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace 
does
++ * _not_ correspond to the first gpio register at controller's gpio base.
++ * There is no logic or pattern in mapping gpio numbers to registers (pads) so
++ * each sub-controller needs to have its own mapping table
++ */
++
++static unsigned score_gpio_to_pad[BYT_NGPIO_SCORE] = {
++      85, 89, 93, 96, 99, 102, 98, 101, 34, 37,
++      36, 38, 39, 35, 40, 84, 62, 61, 64, 59,
++      54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
++      52, 49, 48, 43, 46, 41, 45, 42, 58, 44,
++      95, 105, 70, 68, 67, 66, 69, 71, 65, 72,
++      86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
++      80, 82, 13, 12, 15, 14, 17, 18, 19, 16,
++      2, 1, 0, 4, 6, 7, 9, 8, 33, 32,
++      31, 30, 29, 27, 25, 28, 26, 23, 21, 20,
++      24, 22, 5, 3, 10, 11, 106, 87, 91, 104,
++      97, 100,
++};
++
++static unsigned ncore_gpio_to_pad[BYT_NGPIO_NCORE] = {
++      19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
++      14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
++      3, 6, 10, 13, 2, 5, 9, 7,
++};
++
++static unsigned sus_gpio_to_pad[BYT_NGPIO_SUS] = {
++      29, 33, 30, 31, 32, 34, 36, 35, 38, 37,
++      18, 7, 11, 20, 17, 1, 8, 10, 19, 12,
++      0, 2, 23, 39, 28, 27, 22, 21, 24, 25,
++      26, 51, 56, 54, 49, 55, 48, 57, 50, 58,
++      52, 53, 59, 40,
++};
++
++struct gpio_bank {
++      char            *uid; /* acpi _UID */
++      int             ngpio;
++      unsigned        *to_pad;
++};
++
++static struct gpio_bank byt_banks[] = {
++      {
++              .uid = "1",
++              .ngpio = BYT_NGPIO_SCORE,
++              .to_pad = score_gpio_to_pad,
++      },
++      {
++              .uid = "2",
++              .ngpio = BYT_NGPIO_NCORE,
++              .to_pad = ncore_gpio_to_pad,
++      },
++      {
++              .uid = "3",
++              .ngpio = BYT_NGPIO_SUS,
++              .to_pad = sus_gpio_to_pad,
++      },
++      {
++      },
++};
++
++struct byt_gpio {
++      struct gpio_chip        chip;
++      struct irq_domain       *domain;
++      struct platform_device  *pdev;
++      spinlock_t              lock;
++      void __iomem            *reg_base;
++      unsigned                *gpio_to_pad;
++      unsigned                hwirq;
++};
++
++static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
++                               int reg)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      u32 reg_offset;
++      void __iomem *ptr;
++
++      if (reg == BYT_INT_STAT_REG)
++              reg_offset = (offset / 32) * 4;
++      else
++              reg_offset = vg->gpio_to_pad[offset] * 16;
++
++      ptr = (void __iomem *) (vg->reg_base + reg_offset + reg);
++      return ptr;
++}
++
++static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
++      u32 value;
++
++      value = readl(reg);
++      if (!strcmp(chip->label, "byt_gpio.2") && offset >= 11 && offset <= 21){
++              writel(value | BYT_GPIO_FUNC, reg);
++      } else {
++              writel(value & ~BYT_GPIO_FUNC, reg);
++      }
++
++      pm_runtime_get(&vg->pdev->dev);
++      return 0;
++/*
++ * Current Implemntation: Option 2
++ *
++ * Policy about what should be done when requesting a gpio is unclear.
++ * In most cases PIN MUX 000 means gpio function, with the exception of SUS
++ * core pins 11-21 where gpio is mux 001.
++ *
++ * Some pins are set by bios to a non-gpio mux, but still marked as gpio
++ * resource in acpi tables, and they work just as they should when not 
touching
++ * the pin muxing. (For example mmc card detect switch)
++ *
++ * option 1, check pin mux is "gpio", else fail (FIXME gpio SUS pins 11-21):
++ *    if (value)
++ *            return -EINVAL;
++ *
++ * option 2, force pin mux to gpio mode (FIXME gpio SUS pins 11-21):
++ *    writel(value & ~BYT_PIN_MUX, reg);
++ *
++ * option 3: don't touch the pinmuxing at all, let BIOS handle it
++ */
++}
++
++static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
++      u32 value;
++      unsigned int virq;
++
++      value = readl(reg);
++      value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
++
++      if (!strcmp(chip->label, "byt_gpio.2") && offset >= 11 && offset <= 21){
++                writel(value & ~BYT_GPIO_FUNC, reg);
++        } else {
++                writel(value | BYT_GPIO_FUNC, reg);
++        }
++      writel(value, reg);
++      virq = irq_find_mapping(vg->domain, offset);
++      irq_dispose_mapping(virq);
++      pm_runtime_put(&vg->pdev->dev);
++}
++
++static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
++      return readl(reg) & BYT_LEVEL;
++}
++
++static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
++      unsigned long flags;
++      u32 old_val;
++
++      spin_lock_irqsave(&vg->lock, flags);
++
++      old_val = readl(reg);
++
++      if (value)
++              writel(old_val | BYT_LEVEL, reg);
++      else
++              writel(old_val & ~BYT_LEVEL, reg);
++
++      spin_unlock_irqrestore(&vg->lock, flags);
++}
++
++static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
++      unsigned long flags;
++      u32 value;
++
++      spin_lock_irqsave(&vg->lock, flags);
++
++      value = readl(reg) | BYT_DIR_MASK;
++      value &= ~BYT_INPUT_EN; /* active low */
++      writel(value, reg);
++
++      spin_unlock_irqrestore(&vg->lock, flags);
++
++      return 0;
++}
++
++static int byt_gpio_direction_output(struct gpio_chip *chip,
++                                   unsigned gpio, int value)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
++      unsigned long flags;
++      u32 reg_val;
++
++      spin_lock_irqsave(&vg->lock, flags);
++
++      reg_val = readl(reg) | (BYT_DIR_MASK | !!value);
++      reg_val &= ~(BYT_OUTPUT_EN | !value);
++      writel(reg_val, reg);
++
++      spin_unlock_irqrestore(&vg->lock, flags);
++
++      return 0;
++}
++
++static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      int i;
++      unsigned long flags;
++      u32 conf0, val, offs;
++
++      spin_lock_irqsave(&vg->lock, flags);
++
++      for (i = 0; i < vg->chip.ngpio; i++) {
++              offs = vg->gpio_to_pad[i] * 16;
++              conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
++              val = readl(vg->reg_base + offs + BYT_VAL_REG);
++
++              seq_printf(s, " gpio-%-3d %s %s %s pad-%-3d offset:0x%03x "
++                         "mux:%d %s %s %s\n",
++                         i,
++                         val & BYT_INPUT_EN ? "  " : "in",
++                         val & BYT_OUTPUT_EN ? "   " : "out",
++                         val & BYT_LEVEL ? "hi" : "lo",
++                         vg->gpio_to_pad[i], offs,
++                         conf0 & 0x7,
++                         conf0 & BYT_TRIG_NEG ? "fall" : "",
++                         conf0 & BYT_TRIG_POS ? "rise" : "",
++                         conf0 & BYT_TRIG_LVL ? "lvl " : "");
++      }
++      spin_unlock_irqrestore(&vg->lock, flags);
++}
++
++static int byt_irq_type(struct irq_data *d, unsigned type)
++{
++      struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
++      u32 offset = irqd_to_hwirq(d);
++      u32 value;
++      unsigned long flags;
++      void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
++
++      if (offset >= vg->chip.ngpio)
++              return -EINVAL;
++
++      spin_lock_irqsave(&vg->lock, flags);
++
++      /* For level triggers, the BYT_TRIG_POS and BYT_TRIG_NEG bits
++       * are used to indicate high and low level triggering
++       */
++      value = readl(reg);
++      value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
++      switch(type){
++      case IRQ_TYPE_LEVEL_HIGH:
++              value |= BYT_TRIG_LVL;
++      case IRQ_TYPE_EDGE_RISING:
++              value |= BYT_TRIG_POS;
++              break;
++      case IRQ_TYPE_LEVEL_LOW:
++              value |= BYT_TRIG_LVL;
++      case IRQ_TYPE_EDGE_FALLING:
++              value |= BYT_TRIG_NEG;
++              break;
++      case IRQ_TYPE_EDGE_BOTH:
++              value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
++              break;
++      }
++      writel(value, reg);
++      spin_unlock_irqrestore(&vg->lock, flags);
++      return 0;
++}
++
++static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++      struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
++      return irq_create_mapping(vg->domain, offset);
++}
++
++static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
++{
++      struct irq_data *data = irq_desc_get_irq_data(desc);
++      struct byt_gpio *vg = irq_data_get_irq_handler_data(data);
++      struct irq_chip *chip = irq_data_get_irq_chip(data);
++      u32 base, pin, mask;
++      void __iomem *reg;
++      u32 pending;
++      unsigned virq;
++      int looplimit = 0;
++
++      /* check from GPIO controller which pin triggered the interrupt */
++      for (base = 0; base <  vg->chip.ngpio; base += 32) {
++              reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
++              while ((pending = readl(reg))) {
++                      pin = __ffs(pending);
++                      mask = BIT(pin);
++                      /* Clear before handling so we can't lose an edge */
++                      writel(mask, reg);
++                      virq = irq_find_mapping(vg->domain, base + pin);
++                      generic_handle_irq(virq);
++
++                      /* In case bios or user sets triggering incorrectly, a
++                       * pin might remain in "interrupt triggered" state.
++                       */
++                      if(looplimit++ > 32){
++                              dev_err(&vg->pdev->dev,
++                                      "GPIO %d interrupt flood, disabling\n",
++                                      base + pin);
++                              reg = byt_gpio_reg(&vg->chip, base + pin,
++                                              BYT_CONF0_REG);
++                              mask = readl(reg);
++                              mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
++                                        BYT_TRIG_LVL);
++                              writel(mask, reg);
++                              mask = readl(reg); /* flush */
++                              break;
++                      }
++              }
++      }
++      chip->irq_eoi(data);
++}
++
++static void byt_irq_unmask(struct irq_data *d)
++{
++}
++
++static void byt_irq_mask(struct irq_data *d)
++{
++}
++
++static struct irq_chip byt_irqchip = {
++      .name = "BYT-GPIO",
++      .irq_mask = byt_irq_mask,
++      .irq_unmask = byt_irq_unmask,
++      .irq_set_type = byt_irq_type,
++};
++
++static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
++{
++      void __iomem *reg;
++      u32 base, value;
++
++      /* clear interrupt status trigger registers */
++      for (base = 0; base < vg->chip.ngpio; base += 32) {
++              reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
++              writel(~0x0, reg);
++      }
++      /* Scan through any GPIO pin interrupt(s) which is/are still
++       * firing. Disable interrupt feature if any pin is found to prevent
++       * booting issue.
++       */
++      for (base = 0x0; base < 0xd; base += 0x04) {
++              reg = (void __iomem *) (vg->reg_base + BYT_INT_STAT_REG + base);
++              value = readl(reg);
++              if(value){
++                      dev_err(&vg->pdev->dev, "GPIO interrupts flood.  "
++                              "Pin misconfigured at BIOS/Bootloader. 
Offset:%xh"
++                              " Int Status:0x%x\n", BYT_INT_STAT_REG + base,
++                              value);
++              }
++      }
++}
++
++static int byt_gpio_irq_map(struct irq_domain *d, unsigned int virq,
++                          irq_hw_number_t hw)
++{
++      struct byt_gpio *vg = d->host_data;
++
++      irq_set_chip_and_handler_name(virq, &byt_irqchip, handle_simple_irq,
++                                    "demux");
++      irq_set_chip_data(virq, vg);
++      irq_set_irq_type(virq, IRQ_TYPE_NONE);
++      return 0;
++}
++
++static const struct irq_domain_ops byt_gpio_irq_ops = {
++      .map = byt_gpio_irq_map,
++};
++
++#ifdef CONFIG_GPIO_BYT_DEVICE
++static int byt_gpio_irq_enable(unsigned hwirq, struct platform_device *pdev)
++{
++      struct io_apic_irq_attr irq_attr;
++      struct device *dev = &pdev->dev;
++      /*
++       *  Since PCI BIOS is not able to provide IRQ mapping to
++       *  IRQ24 and onward, we need register to ioapic directly
++       *  and hardcode pci->irq= hwirq
++       */
++      irq_attr.ioapic = mp_find_ioapic(hwirq);
++      if(irq_attr.ioapic<0){
++              printk(KERN_ERR "ERROR: No IOAPIC for IRQ=%d DID=0x%x \n",
++                                              hwirq, (unsigned int) dev);
++              return irq_attr.ioapic;
++      }
++      irq_attr.ioapic_pin = hwirq;
++      irq_attr.trigger = 1;   /* level */
++      irq_attr.polarity = 1;  /* active low */
++      io_apic_set_pci_routing(dev, hwirq, &irq_attr);
++      return 0;
++
++}
++#endif
++
++static int byt_gpio_probe(struct platform_device *pdev)
++{
++      struct byt_gpio *vg;
++      struct gpio_chip *gc;
++      struct resource *mem_rc, *irq_rc;
++      struct device *dev = &pdev->dev;
++      struct gpio_bank *bank;
++      int ret;
++
++#ifdef CONFIG_GPIO_BYT_DEVICE
++      struct byt_gpio_port *platform_data = dev->platform_data;
++#else
++      struct acpi_device *acpi_dev;
++      acpi_handle handle = ACPI_HANDLE(dev);
++
++      if (acpi_bus_get_device(handle, &acpi_dev))
++              return -ENODEV;
++#endif
++      vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL);
++      if (!vg) {
++              dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n");
++              return -ENOMEM;
++      }
++      for (bank = byt_banks; bank->uid; bank++) {
++#ifdef CONFIG_GPIO_BYT_DEVICE
++              if (!strcmp(platform_data->unique_id, bank->uid)){
++#else
++              if (!strcmp(acpi_dev->pnp.unique_id, bank->uid)){
++#endif
++                      vg->chip.ngpio = bank->ngpio;
++                      vg->gpio_to_pad = bank->to_pad;
++                      break;
++              }
++      }
++      if (!vg->chip.ngpio || !vg->gpio_to_pad)
++              return -ENODEV;
++
++      vg->pdev = pdev;
++      platform_set_drvdata(pdev, vg);
++
++      mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      vg->reg_base = devm_request_and_ioremap(dev, mem_rc);
++      if (vg->reg_base == NULL) {
++              return -EFAULT;
++      }
++
++      spin_lock_init(&vg->lock);
++
++      gc = &vg->chip;
++      gc->label = dev_name(&pdev->dev);
++      gc->owner = THIS_MODULE;
++      gc->request = byt_gpio_request;
++      gc->free = byt_gpio_free;
++      gc->direction_input = byt_gpio_direction_input;
++      gc->direction_output = byt_gpio_direction_output;
++      gc->get = byt_gpio_get;
++      gc->set = byt_gpio_set;
++      gc->dbg_show = byt_gpio_dbg_show;
++      gc->base = -1;
++      gc->can_sleep = 0;
++      gc->dev = dev;
++
++      ret = gpiochip_add(gc);
++      if (ret) {
++              dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
++              return ret;
++      }
++
++      byt_gpio_irq_init_hw(vg);
++      /* set up interrupts  */
++      irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++      if (irq_rc && irq_rc->start) {
++              vg->hwirq = irq_rc->start;
++              gc->to_irq = byt_gpio_to_irq;
++#ifdef CONFIG_GPIO_BYT_DEVICE
++              ret = byt_gpio_irq_enable(vg->hwirq, pdev);
++              if (ret){
++                      dev_err(&pdev->dev, "failed to add GPIO to APIC\n");
++                      return ret;
++              }
++#endif
++              vg->domain = irq_domain_add_linear(NULL, gc->ngpio,
++                                                 &byt_gpio_irq_ops, vg);
++              if (!vg->domain)
++                      return -ENXIO;
++              irq_set_handler_data(vg->hwirq, vg);
++              irq_set_chained_handler(vg->hwirq, byt_gpio_irq_handler);
++#ifndef CONFIG_GPIO_BYT_DEVICE
++              /* Register interrupt handlers for gpio */
++              acpi_gpiochip_request_interrupts(gc);
++#endif
++      }
++      pm_runtime_enable(dev);
++      return 0;
++}
++
++static int byt_gpio_runtime_suspend(struct device *dev)
++{
++      return 0;
++}
++
++static int byt_gpio_runtime_resume(struct device *dev)
++{
++      return 0;
++}
++
++static const struct dev_pm_ops byt_gpio_pm_ops = {
++      .runtime_suspend = byt_gpio_runtime_suspend,
++      .runtime_resume = byt_gpio_runtime_resume,
++};
++
++#ifndef CONFIG_GPIO_BYT_DEVICE
++static const struct acpi_device_id byt_gpio_acpi_match[] = {
++      { "INT33B2", 0 },
++      { }
++};
++MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
++#endif
++
++static int byt_gpio_remove(struct platform_device *pdev)
++{
++      struct byt_gpio *vg = platform_get_drvdata(pdev);
++      int err;
++      err = gpiochip_remove(&vg->chip);
++      if (err)
++              dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
++      platform_set_drvdata(pdev, NULL);
++      return 0;
++}
++
++static struct platform_driver byt_gpio_driver = {
++      .probe          = byt_gpio_probe,
++      .remove         = byt_gpio_remove,
++      .driver         = {
++              .name   = "byt_gpio",
++              .owner  = THIS_MODULE,
++#ifndef CONFIG_GPIO_BYT_DEVICE
++              .pm     = &byt_gpio_pm_ops,
++              .acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
++#endif
++      },
++};
++
++static int __init byt_gpio_init(void)
++{
++      return platform_driver_register(&byt_gpio_driver);
++}
++
++subsys_initcall(byt_gpio_init);
+diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
+index 91615a3..b76ebd0 100644
+--- a/include/linux/acpi_gpio.h
++++ b/include/linux/acpi_gpio.h
+@@ -2,10 +2,12 @@
+ #define _LINUX_ACPI_GPIO_H_
+
+ #include <linux/errno.h>
++#include <linux/gpio.h>
+
+ #ifdef CONFIG_GPIO_ACPI
+
+ int acpi_get_gpio(char *path, int pin);
++void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
+
+ #else /* CONFIG_GPIO_ACPI */
+
+@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
+       return -ENODEV;
+ }
+
++static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { 
}
++
+ #endif /* CONFIG_GPIO_ACPI */
+
+ #endif /* _LINUX_ACPI_GPIO_H_ */
+diff --git a/include/linux/gpio-byt.h b/include/linux/gpio-byt.h
+new file mode 100644
+index 0000000..7ebf1f4
+--- /dev/null
++++ b/include/linux/gpio-byt.h
+@@ -0,0 +1,16 @@
++/*
++ * platform_byt_gpio.h: BYT GPIO header file
++ *
++ * (C) Copyright 2008 Intel Corporation
++ * Author:
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; version 2
++ * of the License.
++ */
++#ifdef CONFIG_GPIO_BYT_DEVICE
++struct byt_gpio_port {
++      char * unique_id;
++};
++#endif
+--
+1.7.10.4
+
-- 
1.7.10.4

_______________________________________________
linux-yocto mailing list
[email protected]
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to