1eb83479eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 2eb83479eSAndy Shevchenko /* 3eb83479eSAndy Shevchenko * GPIO controller driver for Intel Lynxpoint PCH chipset> 4eb83479eSAndy Shevchenko * Copyright (c) 2012, Intel Corporation. 5eb83479eSAndy Shevchenko * 6eb83479eSAndy Shevchenko * Author: Mathias Nyman <mathias.nyman@linux.intel.com> 7eb83479eSAndy Shevchenko */ 8eb83479eSAndy Shevchenko 9eb83479eSAndy Shevchenko #include <linux/acpi.h> 10eb83479eSAndy Shevchenko #include <linux/bitops.h> 11eb83479eSAndy Shevchenko #include <linux/gpio/driver.h> 12eb83479eSAndy Shevchenko #include <linux/interrupt.h> 13eb83479eSAndy Shevchenko #include <linux/io.h> 14eb83479eSAndy Shevchenko #include <linux/kernel.h> 15eb83479eSAndy Shevchenko #include <linux/module.h> 16eb83479eSAndy Shevchenko #include <linux/platform_device.h> 17eb83479eSAndy Shevchenko #include <linux/pm_runtime.h> 18eb83479eSAndy Shevchenko #include <linux/slab.h> 19eb83479eSAndy Shevchenko #include <linux/types.h> 20eb83479eSAndy Shevchenko 217c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */ 22eb83479eSAndy Shevchenko 237c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO 95 24eb83479eSAndy Shevchenko 25eb83479eSAndy Shevchenko /* Bitmapped register offsets */ 26eb83479eSAndy Shevchenko #define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ 27eb83479eSAndy Shevchenko #define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ 28eb83479eSAndy Shevchenko #define LP_INT_STAT 0x80 29eb83479eSAndy Shevchenko #define LP_INT_ENABLE 0x90 30eb83479eSAndy Shevchenko 31eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */ 32eb83479eSAndy Shevchenko #define LP_CONFIG1 0x100 33eb83479eSAndy Shevchenko #define LP_CONFIG2 0x104 34eb83479eSAndy Shevchenko 35eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */ 36eb83479eSAndy Shevchenko #define OUT_LVL_BIT BIT(31) 37eb83479eSAndy Shevchenko #define IN_LVL_BIT BIT(30) 38eb83479eSAndy Shevchenko #define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ 39eb83479eSAndy Shevchenko #define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ 40eb83479eSAndy Shevchenko #define DIR_BIT BIT(2) /* 0: Output, 1: Input */ 4176347d7aSAndy Shevchenko #define USE_SEL_MASK GENMASK(1, 0) /* 0: Native, 1: GPIO, ... */ 4276347d7aSAndy Shevchenko #define USE_SEL_NATIVE (0 << 0) 4376347d7aSAndy Shevchenko #define USE_SEL_GPIO (1 << 0) 44eb83479eSAndy Shevchenko 45eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */ 46eb83479eSAndy Shevchenko #define GPINDIS_BIT BIT(2) /* disable input sensing */ 47eb83479eSAndy Shevchenko #define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ 48eb83479eSAndy Shevchenko 49eb83479eSAndy Shevchenko struct lp_gpio { 50eb83479eSAndy Shevchenko struct gpio_chip chip; 511e78ea71SAndy Shevchenko struct device *dev; 52b2e05d63SAndy Shevchenko raw_spinlock_t lock; 53e1940adeSAndy Shevchenko void __iomem *regs; 54eb83479eSAndy Shevchenko }; 55eb83479eSAndy Shevchenko 56eb83479eSAndy Shevchenko /* 57eb83479eSAndy Shevchenko * Lynxpoint gpios are controlled through both bitmapped registers and 58eb83479eSAndy Shevchenko * per gpio specific registers. The bitmapped registers are in chunks of 597c0bc7bbSAndy Shevchenko * 3 x 32bit registers to cover all 95 GPIOs 60eb83479eSAndy Shevchenko * 61eb83479eSAndy Shevchenko * per gpio specific registers consist of two 32bit registers per gpio 627c0bc7bbSAndy Shevchenko * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 637c0bc7bbSAndy Shevchenko * 190 config registers. 64eb83479eSAndy Shevchenko * 65eb83479eSAndy Shevchenko * A simplified view of the register layout look like this: 66eb83479eSAndy Shevchenko * 67eb83479eSAndy Shevchenko * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 68eb83479eSAndy Shevchenko * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 69eb83479eSAndy Shevchenko * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 70eb83479eSAndy Shevchenko * ... 71eb83479eSAndy Shevchenko * LP_INT_ENABLE[31:0] ... 727c0bc7bbSAndy Shevchenko * LP_INT_ENABLE[63:32] ... 73eb83479eSAndy Shevchenko * LP_INT_ENABLE[94:64] ... 74eb83479eSAndy Shevchenko * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 75eb83479eSAndy Shevchenko * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 76eb83479eSAndy Shevchenko * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 77eb83479eSAndy Shevchenko * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 78eb83479eSAndy Shevchenko * LP2_CONFIG1 (gpio 2) ... 79eb83479eSAndy Shevchenko * LP2_CONFIG2 (gpio 2) ... 80eb83479eSAndy Shevchenko * ... 81eb83479eSAndy Shevchenko * LP94_CONFIG1 (gpio 94) ... 82eb83479eSAndy Shevchenko * LP94_CONFIG2 (gpio 94) ... 83eb83479eSAndy Shevchenko */ 84eb83479eSAndy Shevchenko 85c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset, 86eb83479eSAndy Shevchenko int reg) 87eb83479eSAndy Shevchenko { 88eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 89eb83479eSAndy Shevchenko int reg_offset; 90eb83479eSAndy Shevchenko 91eb83479eSAndy Shevchenko if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 92eb83479eSAndy Shevchenko /* per gpio specific config registers */ 93eb83479eSAndy Shevchenko reg_offset = offset * 8; 94eb83479eSAndy Shevchenko else 95eb83479eSAndy Shevchenko /* bitmapped registers */ 96eb83479eSAndy Shevchenko reg_offset = (offset / 32) * 4; 97eb83479eSAndy Shevchenko 98e1940adeSAndy Shevchenko return lg->regs + reg + reg_offset; 99eb83479eSAndy Shevchenko } 100eb83479eSAndy Shevchenko 10121a06495SAndy Shevchenko static bool lp_gpio_acpi_use(struct lp_gpio *lg, unsigned int pin) 10221a06495SAndy Shevchenko { 10321a06495SAndy Shevchenko void __iomem *acpi_use; 10421a06495SAndy Shevchenko 10521a06495SAndy Shevchenko acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED); 10621a06495SAndy Shevchenko if (!acpi_use) 10721a06495SAndy Shevchenko return true; 10821a06495SAndy Shevchenko 10921a06495SAndy Shevchenko return !(ioread32(acpi_use) & BIT(pin % 32)); 11021a06495SAndy Shevchenko } 11121a06495SAndy Shevchenko 112c35f463aSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned int offset) 113eb83479eSAndy Shevchenko { 114eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 115e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 116e1940adeSAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 11703fb681bSAndy Shevchenko u32 value; 118eb83479eSAndy Shevchenko 1191e78ea71SAndy Shevchenko pm_runtime_get(lg->dev); /* should we put if failed */ 120eb83479eSAndy Shevchenko 121eb83479eSAndy Shevchenko /* Fail if BIOS reserved pin for ACPI use */ 12221a06495SAndy Shevchenko if (lp_gpio_acpi_use(lg, offset)) { 1231e78ea71SAndy Shevchenko dev_err(lg->dev, "gpio %d reserved for ACPI\n", offset); 124eb83479eSAndy Shevchenko return -EBUSY; 125eb83479eSAndy Shevchenko } 12603fb681bSAndy Shevchenko 12703fb681bSAndy Shevchenko /* 12803fb681bSAndy Shevchenko * Reconfigure pin to GPIO mode if needed and issue a warning, 12903fb681bSAndy Shevchenko * since we expect firmware to configure it properly. 13003fb681bSAndy Shevchenko */ 131e1940adeSAndy Shevchenko value = ioread32(reg); 13203fb681bSAndy Shevchenko if ((value & USE_SEL_MASK) != USE_SEL_GPIO) { 133e1940adeSAndy Shevchenko iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg); 1341e78ea71SAndy Shevchenko dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", offset); 13503fb681bSAndy Shevchenko } 136eb83479eSAndy Shevchenko 137eb83479eSAndy Shevchenko /* enable input sensing */ 138e1940adeSAndy Shevchenko iowrite32(ioread32(conf2) & ~GPINDIS_BIT, conf2); 139eb83479eSAndy Shevchenko 140eb83479eSAndy Shevchenko 141eb83479eSAndy Shevchenko return 0; 142eb83479eSAndy Shevchenko } 143eb83479eSAndy Shevchenko 144c35f463aSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned int offset) 145eb83479eSAndy Shevchenko { 146eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 147e1940adeSAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 148eb83479eSAndy Shevchenko 149eb83479eSAndy Shevchenko /* disable input sensing */ 150e1940adeSAndy Shevchenko iowrite32(ioread32(conf2) | GPINDIS_BIT, conf2); 151eb83479eSAndy Shevchenko 1521e78ea71SAndy Shevchenko pm_runtime_put(lg->dev); 153eb83479eSAndy Shevchenko } 154eb83479eSAndy Shevchenko 155c35f463aSAndy Shevchenko static int lp_irq_type(struct irq_data *d, unsigned int type) 156eb83479eSAndy Shevchenko { 157eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 158eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 159eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 160e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 161eb83479eSAndy Shevchenko unsigned long flags; 162eb83479eSAndy Shevchenko u32 value; 163eb83479eSAndy Shevchenko 164eb83479eSAndy Shevchenko if (hwirq >= lg->chip.ngpio) 165eb83479eSAndy Shevchenko return -EINVAL; 166eb83479eSAndy Shevchenko 167b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 168e1940adeSAndy Shevchenko value = ioread32(reg); 169eb83479eSAndy Shevchenko 170eb83479eSAndy Shevchenko /* set both TRIG_SEL and INV bits to 0 for rising edge */ 171eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_RISING) 172eb83479eSAndy Shevchenko value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 173eb83479eSAndy Shevchenko 174eb83479eSAndy Shevchenko /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 175eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_FALLING) 176eb83479eSAndy Shevchenko value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 177eb83479eSAndy Shevchenko 178eb83479eSAndy Shevchenko /* TRIG_SEL bit 1, INV bit 0 for level low */ 179eb83479eSAndy Shevchenko if (type & IRQ_TYPE_LEVEL_LOW) 180eb83479eSAndy Shevchenko value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 181eb83479eSAndy Shevchenko 182eb83479eSAndy Shevchenko /* TRIG_SEL bit 1, INV bit 1 for level high */ 183eb83479eSAndy Shevchenko if (type & IRQ_TYPE_LEVEL_HIGH) 184eb83479eSAndy Shevchenko value |= TRIG_SEL_BIT | INT_INV_BIT; 185eb83479eSAndy Shevchenko 186e1940adeSAndy Shevchenko iowrite32(value, reg); 187eb83479eSAndy Shevchenko 188eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_BOTH) 189eb83479eSAndy Shevchenko irq_set_handler_locked(d, handle_edge_irq); 190eb83479eSAndy Shevchenko else if (type & IRQ_TYPE_LEVEL_MASK) 191eb83479eSAndy Shevchenko irq_set_handler_locked(d, handle_level_irq); 192eb83479eSAndy Shevchenko 193b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 194eb83479eSAndy Shevchenko 195eb83479eSAndy Shevchenko return 0; 196eb83479eSAndy Shevchenko } 197eb83479eSAndy Shevchenko 198c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset) 199eb83479eSAndy Shevchenko { 200e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 201e1940adeSAndy Shevchenko return !!(ioread32(reg) & IN_LVL_BIT); 202eb83479eSAndy Shevchenko } 203eb83479eSAndy Shevchenko 204c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 205eb83479eSAndy Shevchenko { 206eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 207e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 208eb83479eSAndy Shevchenko unsigned long flags; 209eb83479eSAndy Shevchenko 210b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 211eb83479eSAndy Shevchenko 212eb83479eSAndy Shevchenko if (value) 213e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | OUT_LVL_BIT, reg); 214eb83479eSAndy Shevchenko else 215e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg); 216eb83479eSAndy Shevchenko 217b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 218eb83479eSAndy Shevchenko } 219eb83479eSAndy Shevchenko 220c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 221eb83479eSAndy Shevchenko { 222eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 223e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 224eb83479eSAndy Shevchenko unsigned long flags; 225eb83479eSAndy Shevchenko 226b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 227e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | DIR_BIT, reg); 228b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 229eb83479eSAndy Shevchenko 230eb83479eSAndy Shevchenko return 0; 231eb83479eSAndy Shevchenko } 232eb83479eSAndy Shevchenko 233c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 234c35f463aSAndy Shevchenko int value) 235eb83479eSAndy Shevchenko { 236eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 237e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 238eb83479eSAndy Shevchenko unsigned long flags; 239eb83479eSAndy Shevchenko 240eb83479eSAndy Shevchenko lp_gpio_set(chip, offset, value); 241eb83479eSAndy Shevchenko 242b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 243e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~DIR_BIT, reg); 244b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 245eb83479eSAndy Shevchenko 246eb83479eSAndy Shevchenko return 0; 247eb83479eSAndy Shevchenko } 248eb83479eSAndy Shevchenko 249eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc) 250eb83479eSAndy Shevchenko { 251eb83479eSAndy Shevchenko struct irq_data *data = irq_desc_get_irq_data(desc); 252eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_desc_get_handler_data(desc); 253eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 254eb83479eSAndy Shevchenko struct irq_chip *chip = irq_data_get_irq_chip(data); 255e1940adeSAndy Shevchenko void __iomem *reg, *ena; 256e1940adeSAndy Shevchenko unsigned long pending; 257eb83479eSAndy Shevchenko u32 base, pin; 258eb83479eSAndy Shevchenko 259eb83479eSAndy Shevchenko /* check from GPIO controller which pin triggered the interrupt */ 260eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 261eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 262eb83479eSAndy Shevchenko ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 263eb83479eSAndy Shevchenko 264eb83479eSAndy Shevchenko /* Only interrupts that are enabled */ 265e1940adeSAndy Shevchenko pending = ioread32(reg) & ioread32(ena); 266eb83479eSAndy Shevchenko 267eb83479eSAndy Shevchenko for_each_set_bit(pin, &pending, 32) { 268c35f463aSAndy Shevchenko unsigned int irq; 269eb83479eSAndy Shevchenko 270eb83479eSAndy Shevchenko /* Clear before handling so we don't lose an edge */ 271e1940adeSAndy Shevchenko iowrite32(BIT(pin), reg); 272eb83479eSAndy Shevchenko 273eb83479eSAndy Shevchenko irq = irq_find_mapping(lg->chip.irq.domain, base + pin); 274eb83479eSAndy Shevchenko generic_handle_irq(irq); 275eb83479eSAndy Shevchenko } 276eb83479eSAndy Shevchenko } 277eb83479eSAndy Shevchenko chip->irq_eoi(data); 278eb83479eSAndy Shevchenko } 279eb83479eSAndy Shevchenko 280eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d) 281eb83479eSAndy Shevchenko { 282eb83479eSAndy Shevchenko } 283eb83479eSAndy Shevchenko 284eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d) 285eb83479eSAndy Shevchenko { 286eb83479eSAndy Shevchenko } 287eb83479eSAndy Shevchenko 288eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d) 289eb83479eSAndy Shevchenko { 290eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 291eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 292eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 293e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 294eb83479eSAndy Shevchenko unsigned long flags; 295eb83479eSAndy Shevchenko 296b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 297e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | BIT(hwirq % 32), reg); 298b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 299eb83479eSAndy Shevchenko } 300eb83479eSAndy Shevchenko 301eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d) 302eb83479eSAndy Shevchenko { 303eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 304eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 305eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 306e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 307eb83479eSAndy Shevchenko unsigned long flags; 308eb83479eSAndy Shevchenko 309b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 310e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg); 311b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 312eb83479eSAndy Shevchenko } 313eb83479eSAndy Shevchenko 314eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = { 315eb83479eSAndy Shevchenko .name = "LP-GPIO", 316eb83479eSAndy Shevchenko .irq_mask = lp_irq_mask, 317eb83479eSAndy Shevchenko .irq_unmask = lp_irq_unmask, 318eb83479eSAndy Shevchenko .irq_enable = lp_irq_enable, 319eb83479eSAndy Shevchenko .irq_disable = lp_irq_disable, 320eb83479eSAndy Shevchenko .irq_set_type = lp_irq_type, 321eb83479eSAndy Shevchenko .flags = IRQCHIP_SKIP_SET_WAKE, 322eb83479eSAndy Shevchenko }; 323eb83479eSAndy Shevchenko 324eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip) 325eb83479eSAndy Shevchenko { 326eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 327e1940adeSAndy Shevchenko void __iomem *reg; 328c35f463aSAndy Shevchenko unsigned int base; 329eb83479eSAndy Shevchenko 330eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 331eb83479eSAndy Shevchenko /* disable gpio pin interrupts */ 332eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 333e1940adeSAndy Shevchenko iowrite32(0, reg); 334eb83479eSAndy Shevchenko /* Clear interrupt status register */ 335eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 336e1940adeSAndy Shevchenko iowrite32(0xffffffff, reg); 337eb83479eSAndy Shevchenko } 338eb83479eSAndy Shevchenko 339eb83479eSAndy Shevchenko return 0; 340eb83479eSAndy Shevchenko } 341eb83479eSAndy Shevchenko 342eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev) 343eb83479eSAndy Shevchenko { 344eb83479eSAndy Shevchenko struct lp_gpio *lg; 345eb83479eSAndy Shevchenko struct gpio_chip *gc; 346eb83479eSAndy Shevchenko struct resource *io_rc, *irq_rc; 347eb83479eSAndy Shevchenko struct device *dev = &pdev->dev; 348e1940adeSAndy Shevchenko void __iomem *regs; 3493b4c2d8eSAndy Shevchenko int ret; 350eb83479eSAndy Shevchenko 351a718e68eSAndy Shevchenko lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 352eb83479eSAndy Shevchenko if (!lg) 353eb83479eSAndy Shevchenko return -ENOMEM; 354eb83479eSAndy Shevchenko 3551e78ea71SAndy Shevchenko lg->dev = dev; 356eb83479eSAndy Shevchenko platform_set_drvdata(pdev, lg); 357eb83479eSAndy Shevchenko 358eb83479eSAndy Shevchenko io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 359eb83479eSAndy Shevchenko if (!io_rc) { 360eb83479eSAndy Shevchenko dev_err(dev, "missing IO resources\n"); 361eb83479eSAndy Shevchenko return -EINVAL; 362eb83479eSAndy Shevchenko } 363eb83479eSAndy Shevchenko 364e1940adeSAndy Shevchenko regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); 365e1940adeSAndy Shevchenko if (!regs) { 366e1940adeSAndy Shevchenko dev_err(dev, "failed mapping IO region %pR\n", &io_rc); 367eb83479eSAndy Shevchenko return -EBUSY; 368eb83479eSAndy Shevchenko } 369eb83479eSAndy Shevchenko 370e1940adeSAndy Shevchenko lg->regs = regs; 371e1940adeSAndy Shevchenko 372b2e05d63SAndy Shevchenko raw_spin_lock_init(&lg->lock); 373eb83479eSAndy Shevchenko 374eb83479eSAndy Shevchenko gc = &lg->chip; 375eb83479eSAndy Shevchenko gc->label = dev_name(dev); 376eb83479eSAndy Shevchenko gc->owner = THIS_MODULE; 377eb83479eSAndy Shevchenko gc->request = lp_gpio_request; 378eb83479eSAndy Shevchenko gc->free = lp_gpio_free; 379eb83479eSAndy Shevchenko gc->direction_input = lp_gpio_direction_input; 380eb83479eSAndy Shevchenko gc->direction_output = lp_gpio_direction_output; 381eb83479eSAndy Shevchenko gc->get = lp_gpio_get; 382eb83479eSAndy Shevchenko gc->set = lp_gpio_set; 383eb83479eSAndy Shevchenko gc->base = -1; 384eb83479eSAndy Shevchenko gc->ngpio = LP_NUM_GPIO; 385eb83479eSAndy Shevchenko gc->can_sleep = false; 386eb83479eSAndy Shevchenko gc->parent = dev; 387eb83479eSAndy Shevchenko 388eb83479eSAndy Shevchenko /* set up interrupts */ 389e1940adeSAndy Shevchenko irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 390eb83479eSAndy Shevchenko if (irq_rc && irq_rc->start) { 391eb83479eSAndy Shevchenko struct gpio_irq_chip *girq; 392eb83479eSAndy Shevchenko 393eb83479eSAndy Shevchenko girq = &gc->irq; 394eb83479eSAndy Shevchenko girq->chip = &lp_irqchip; 395eb83479eSAndy Shevchenko girq->init_hw = lp_gpio_irq_init_hw; 396eb83479eSAndy Shevchenko girq->parent_handler = lp_gpio_irq_handler; 397eb83479eSAndy Shevchenko girq->num_parents = 1; 3981e78ea71SAndy Shevchenko girq->parents = devm_kcalloc(dev, girq->num_parents, 399eb83479eSAndy Shevchenko sizeof(*girq->parents), 400eb83479eSAndy Shevchenko GFP_KERNEL); 401eb83479eSAndy Shevchenko if (!girq->parents) 402eb83479eSAndy Shevchenko return -ENOMEM; 403c35f463aSAndy Shevchenko girq->parents[0] = (unsigned int)irq_rc->start; 404eb83479eSAndy Shevchenko girq->default_type = IRQ_TYPE_NONE; 405eb83479eSAndy Shevchenko girq->handler = handle_bad_irq; 406eb83479eSAndy Shevchenko } 407eb83479eSAndy Shevchenko 408eb83479eSAndy Shevchenko ret = devm_gpiochip_add_data(dev, gc, lg); 409eb83479eSAndy Shevchenko if (ret) { 410eb83479eSAndy Shevchenko dev_err(dev, "failed adding lp-gpio chip\n"); 411eb83479eSAndy Shevchenko return ret; 412eb83479eSAndy Shevchenko } 413eb83479eSAndy Shevchenko 414eb83479eSAndy Shevchenko pm_runtime_enable(dev); 415eb83479eSAndy Shevchenko 416eb83479eSAndy Shevchenko return 0; 417eb83479eSAndy Shevchenko } 418eb83479eSAndy Shevchenko 419*d0f2df40SAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev) 420*d0f2df40SAndy Shevchenko { 421*d0f2df40SAndy Shevchenko pm_runtime_disable(&pdev->dev); 422*d0f2df40SAndy Shevchenko return 0; 423*d0f2df40SAndy Shevchenko } 424*d0f2df40SAndy Shevchenko 425eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev) 426eb83479eSAndy Shevchenko { 427eb83479eSAndy Shevchenko return 0; 428eb83479eSAndy Shevchenko } 429eb83479eSAndy Shevchenko 430eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev) 431eb83479eSAndy Shevchenko { 432eb83479eSAndy Shevchenko return 0; 433eb83479eSAndy Shevchenko } 434eb83479eSAndy Shevchenko 435eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev) 436eb83479eSAndy Shevchenko { 437eb83479eSAndy Shevchenko struct lp_gpio *lg = dev_get_drvdata(dev); 438e1940adeSAndy Shevchenko void __iomem *reg; 439eb83479eSAndy Shevchenko int i; 440eb83479eSAndy Shevchenko 441eb83479eSAndy Shevchenko /* on some hardware suspend clears input sensing, re-enable it here */ 442eb83479eSAndy Shevchenko for (i = 0; i < lg->chip.ngpio; i++) { 443eb83479eSAndy Shevchenko if (gpiochip_is_requested(&lg->chip, i) != NULL) { 444eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2); 445e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg); 446eb83479eSAndy Shevchenko } 447eb83479eSAndy Shevchenko } 448eb83479eSAndy Shevchenko return 0; 449eb83479eSAndy Shevchenko } 450eb83479eSAndy Shevchenko 451eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = { 452eb83479eSAndy Shevchenko .runtime_suspend = lp_gpio_runtime_suspend, 453eb83479eSAndy Shevchenko .runtime_resume = lp_gpio_runtime_resume, 454eb83479eSAndy Shevchenko .resume = lp_gpio_resume, 455eb83479eSAndy Shevchenko }; 456eb83479eSAndy Shevchenko 457eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 458eb83479eSAndy Shevchenko { "INT33C7", 0 }, 459eb83479eSAndy Shevchenko { "INT3437", 0 }, 460eb83479eSAndy Shevchenko { } 461eb83479eSAndy Shevchenko }; 462eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 463eb83479eSAndy Shevchenko 464eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = { 465eb83479eSAndy Shevchenko .probe = lp_gpio_probe, 466eb83479eSAndy Shevchenko .remove = lp_gpio_remove, 467eb83479eSAndy Shevchenko .driver = { 468eb83479eSAndy Shevchenko .name = "lp_gpio", 469eb83479eSAndy Shevchenko .pm = &lp_gpio_pm_ops, 470eb83479eSAndy Shevchenko .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), 471eb83479eSAndy Shevchenko }, 472eb83479eSAndy Shevchenko }; 473eb83479eSAndy Shevchenko 474eb83479eSAndy Shevchenko static int __init lp_gpio_init(void) 475eb83479eSAndy Shevchenko { 476eb83479eSAndy Shevchenko return platform_driver_register(&lp_gpio_driver); 477eb83479eSAndy Shevchenko } 478eb83479eSAndy Shevchenko 479eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void) 480eb83479eSAndy Shevchenko { 481eb83479eSAndy Shevchenko platform_driver_unregister(&lp_gpio_driver); 482eb83479eSAndy Shevchenko } 483eb83479eSAndy Shevchenko 484eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init); 485eb83479eSAndy Shevchenko module_exit(lp_gpio_exit); 486eb83479eSAndy Shevchenko 487eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)"); 488eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); 489eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2"); 490eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio"); 491