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 */ 41eb83479eSAndy Shevchenko #define USE_SEL_BIT BIT(0) /* 0: Native, 1: GPIO */ 42eb83479eSAndy Shevchenko 43eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */ 44eb83479eSAndy Shevchenko #define GPINDIS_BIT BIT(2) /* disable input sensing */ 45eb83479eSAndy Shevchenko #define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ 46eb83479eSAndy Shevchenko 47eb83479eSAndy Shevchenko struct lp_gpio { 48eb83479eSAndy Shevchenko struct gpio_chip chip; 49eb83479eSAndy Shevchenko struct platform_device *pdev; 50b2e05d63SAndy Shevchenko raw_spinlock_t lock; 51eb83479eSAndy Shevchenko unsigned long reg_base; 52eb83479eSAndy Shevchenko }; 53eb83479eSAndy Shevchenko 54eb83479eSAndy Shevchenko /* 55eb83479eSAndy Shevchenko * Lynxpoint gpios are controlled through both bitmapped registers and 56eb83479eSAndy Shevchenko * per gpio specific registers. The bitmapped registers are in chunks of 577c0bc7bbSAndy Shevchenko * 3 x 32bit registers to cover all 95 GPIOs 58eb83479eSAndy Shevchenko * 59eb83479eSAndy Shevchenko * per gpio specific registers consist of two 32bit registers per gpio 607c0bc7bbSAndy Shevchenko * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 617c0bc7bbSAndy Shevchenko * 190 config registers. 62eb83479eSAndy Shevchenko * 63eb83479eSAndy Shevchenko * A simplified view of the register layout look like this: 64eb83479eSAndy Shevchenko * 65eb83479eSAndy Shevchenko * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 66eb83479eSAndy Shevchenko * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 67eb83479eSAndy Shevchenko * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 68eb83479eSAndy Shevchenko * ... 69eb83479eSAndy Shevchenko * LP_INT_ENABLE[31:0] ... 707c0bc7bbSAndy Shevchenko * LP_INT_ENABLE[63:32] ... 71eb83479eSAndy Shevchenko * LP_INT_ENABLE[94:64] ... 72eb83479eSAndy Shevchenko * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 73eb83479eSAndy Shevchenko * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 74eb83479eSAndy Shevchenko * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 75eb83479eSAndy Shevchenko * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 76eb83479eSAndy Shevchenko * LP2_CONFIG1 (gpio 2) ... 77eb83479eSAndy Shevchenko * LP2_CONFIG2 (gpio 2) ... 78eb83479eSAndy Shevchenko * ... 79eb83479eSAndy Shevchenko * LP94_CONFIG1 (gpio 94) ... 80eb83479eSAndy Shevchenko * LP94_CONFIG2 (gpio 94) ... 81eb83479eSAndy Shevchenko */ 82eb83479eSAndy Shevchenko 83eb83479eSAndy Shevchenko static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset, 84eb83479eSAndy Shevchenko int reg) 85eb83479eSAndy Shevchenko { 86eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 87eb83479eSAndy Shevchenko int reg_offset; 88eb83479eSAndy Shevchenko 89eb83479eSAndy Shevchenko if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 90eb83479eSAndy Shevchenko /* per gpio specific config registers */ 91eb83479eSAndy Shevchenko reg_offset = offset * 8; 92eb83479eSAndy Shevchenko else 93eb83479eSAndy Shevchenko /* bitmapped registers */ 94eb83479eSAndy Shevchenko reg_offset = (offset / 32) * 4; 95eb83479eSAndy Shevchenko 96eb83479eSAndy Shevchenko return lg->reg_base + reg + reg_offset; 97eb83479eSAndy Shevchenko } 98eb83479eSAndy Shevchenko 99eb83479eSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned offset) 100eb83479eSAndy Shevchenko { 101eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 102eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 103eb83479eSAndy Shevchenko unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 104eb83479eSAndy Shevchenko unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED); 105eb83479eSAndy Shevchenko 106eb83479eSAndy Shevchenko pm_runtime_get(&lg->pdev->dev); /* should we put if failed */ 107eb83479eSAndy Shevchenko 108eb83479eSAndy Shevchenko /* Fail if BIOS reserved pin for ACPI use */ 109eb83479eSAndy Shevchenko if (!(inl(acpi_use) & BIT(offset % 32))) { 110eb83479eSAndy Shevchenko dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset); 111eb83479eSAndy Shevchenko return -EBUSY; 112eb83479eSAndy Shevchenko } 113eb83479eSAndy Shevchenko /* Fail if pin is in alternate function mode (not GPIO mode) */ 114eb83479eSAndy Shevchenko if (!(inl(reg) & USE_SEL_BIT)) 115eb83479eSAndy Shevchenko return -ENODEV; 116eb83479eSAndy Shevchenko 117eb83479eSAndy Shevchenko /* enable input sensing */ 118eb83479eSAndy Shevchenko outl(inl(conf2) & ~GPINDIS_BIT, conf2); 119eb83479eSAndy Shevchenko 120eb83479eSAndy Shevchenko 121eb83479eSAndy Shevchenko return 0; 122eb83479eSAndy Shevchenko } 123eb83479eSAndy Shevchenko 124eb83479eSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned offset) 125eb83479eSAndy Shevchenko { 126eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 127eb83479eSAndy Shevchenko unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 128eb83479eSAndy Shevchenko 129eb83479eSAndy Shevchenko /* disable input sensing */ 130eb83479eSAndy Shevchenko outl(inl(conf2) | GPINDIS_BIT, conf2); 131eb83479eSAndy Shevchenko 132eb83479eSAndy Shevchenko pm_runtime_put(&lg->pdev->dev); 133eb83479eSAndy Shevchenko } 134eb83479eSAndy Shevchenko 135eb83479eSAndy Shevchenko static int lp_irq_type(struct irq_data *d, unsigned type) 136eb83479eSAndy Shevchenko { 137eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 138eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 139eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 140eb83479eSAndy Shevchenko unsigned long flags; 141eb83479eSAndy Shevchenko u32 value; 142eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 143eb83479eSAndy Shevchenko 144eb83479eSAndy Shevchenko if (hwirq >= lg->chip.ngpio) 145eb83479eSAndy Shevchenko return -EINVAL; 146eb83479eSAndy Shevchenko 147b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 148eb83479eSAndy Shevchenko value = inl(reg); 149eb83479eSAndy Shevchenko 150eb83479eSAndy Shevchenko /* set both TRIG_SEL and INV bits to 0 for rising edge */ 151eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_RISING) 152eb83479eSAndy Shevchenko value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 153eb83479eSAndy Shevchenko 154eb83479eSAndy Shevchenko /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 155eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_FALLING) 156eb83479eSAndy Shevchenko value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 157eb83479eSAndy Shevchenko 158eb83479eSAndy Shevchenko /* TRIG_SEL bit 1, INV bit 0 for level low */ 159eb83479eSAndy Shevchenko if (type & IRQ_TYPE_LEVEL_LOW) 160eb83479eSAndy Shevchenko value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 161eb83479eSAndy Shevchenko 162eb83479eSAndy Shevchenko /* TRIG_SEL bit 1, INV bit 1 for level high */ 163eb83479eSAndy Shevchenko if (type & IRQ_TYPE_LEVEL_HIGH) 164eb83479eSAndy Shevchenko value |= TRIG_SEL_BIT | INT_INV_BIT; 165eb83479eSAndy Shevchenko 166eb83479eSAndy Shevchenko outl(value, reg); 167eb83479eSAndy Shevchenko 168eb83479eSAndy Shevchenko if (type & IRQ_TYPE_EDGE_BOTH) 169eb83479eSAndy Shevchenko irq_set_handler_locked(d, handle_edge_irq); 170eb83479eSAndy Shevchenko else if (type & IRQ_TYPE_LEVEL_MASK) 171eb83479eSAndy Shevchenko irq_set_handler_locked(d, handle_level_irq); 172eb83479eSAndy Shevchenko 173b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 174eb83479eSAndy Shevchenko 175eb83479eSAndy Shevchenko return 0; 176eb83479eSAndy Shevchenko } 177eb83479eSAndy Shevchenko 178eb83479eSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) 179eb83479eSAndy Shevchenko { 180eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 181eb83479eSAndy Shevchenko return !!(inl(reg) & IN_LVL_BIT); 182eb83479eSAndy Shevchenko } 183eb83479eSAndy Shevchenko 184eb83479eSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 185eb83479eSAndy Shevchenko { 186eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 187eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 188eb83479eSAndy Shevchenko unsigned long flags; 189eb83479eSAndy Shevchenko 190b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 191eb83479eSAndy Shevchenko 192eb83479eSAndy Shevchenko if (value) 193eb83479eSAndy Shevchenko outl(inl(reg) | OUT_LVL_BIT, reg); 194eb83479eSAndy Shevchenko else 195eb83479eSAndy Shevchenko outl(inl(reg) & ~OUT_LVL_BIT, reg); 196eb83479eSAndy Shevchenko 197b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 198eb83479eSAndy Shevchenko } 199eb83479eSAndy Shevchenko 200eb83479eSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 201eb83479eSAndy Shevchenko { 202eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 203eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 204eb83479eSAndy Shevchenko unsigned long flags; 205eb83479eSAndy Shevchenko 206b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 207eb83479eSAndy Shevchenko outl(inl(reg) | DIR_BIT, reg); 208b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 209eb83479eSAndy Shevchenko 210eb83479eSAndy Shevchenko return 0; 211eb83479eSAndy Shevchenko } 212eb83479eSAndy Shevchenko 213eb83479eSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, 214eb83479eSAndy Shevchenko unsigned offset, int value) 215eb83479eSAndy Shevchenko { 216eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 217eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 218eb83479eSAndy Shevchenko unsigned long flags; 219eb83479eSAndy Shevchenko 220eb83479eSAndy Shevchenko lp_gpio_set(chip, offset, value); 221eb83479eSAndy Shevchenko 222b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 223eb83479eSAndy Shevchenko outl(inl(reg) & ~DIR_BIT, reg); 224b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 225eb83479eSAndy Shevchenko 226eb83479eSAndy Shevchenko return 0; 227eb83479eSAndy Shevchenko } 228eb83479eSAndy Shevchenko 229eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc) 230eb83479eSAndy Shevchenko { 231eb83479eSAndy Shevchenko struct irq_data *data = irq_desc_get_irq_data(desc); 232eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_desc_get_handler_data(desc); 233eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 234eb83479eSAndy Shevchenko struct irq_chip *chip = irq_data_get_irq_chip(data); 235eb83479eSAndy Shevchenko unsigned long reg, ena, pending; 236eb83479eSAndy Shevchenko u32 base, pin; 237eb83479eSAndy Shevchenko 238eb83479eSAndy Shevchenko /* check from GPIO controller which pin triggered the interrupt */ 239eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 240eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 241eb83479eSAndy Shevchenko ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 242eb83479eSAndy Shevchenko 243eb83479eSAndy Shevchenko /* Only interrupts that are enabled */ 244eb83479eSAndy Shevchenko pending = inl(reg) & inl(ena); 245eb83479eSAndy Shevchenko 246eb83479eSAndy Shevchenko for_each_set_bit(pin, &pending, 32) { 247eb83479eSAndy Shevchenko unsigned irq; 248eb83479eSAndy Shevchenko 249eb83479eSAndy Shevchenko /* Clear before handling so we don't lose an edge */ 250eb83479eSAndy Shevchenko outl(BIT(pin), reg); 251eb83479eSAndy Shevchenko 252eb83479eSAndy Shevchenko irq = irq_find_mapping(lg->chip.irq.domain, base + pin); 253eb83479eSAndy Shevchenko generic_handle_irq(irq); 254eb83479eSAndy Shevchenko } 255eb83479eSAndy Shevchenko } 256eb83479eSAndy Shevchenko chip->irq_eoi(data); 257eb83479eSAndy Shevchenko } 258eb83479eSAndy Shevchenko 259eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d) 260eb83479eSAndy Shevchenko { 261eb83479eSAndy Shevchenko } 262eb83479eSAndy Shevchenko 263eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d) 264eb83479eSAndy Shevchenko { 265eb83479eSAndy Shevchenko } 266eb83479eSAndy Shevchenko 267eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d) 268eb83479eSAndy Shevchenko { 269eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 270eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 271eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 272eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 273eb83479eSAndy Shevchenko unsigned long flags; 274eb83479eSAndy Shevchenko 275b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 276eb83479eSAndy Shevchenko outl(inl(reg) | BIT(hwirq % 32), reg); 277b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 278eb83479eSAndy Shevchenko } 279eb83479eSAndy Shevchenko 280eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d) 281eb83479eSAndy Shevchenko { 282eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 283eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(gc); 284eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 285eb83479eSAndy Shevchenko unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 286eb83479eSAndy Shevchenko unsigned long flags; 287eb83479eSAndy Shevchenko 288b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 289eb83479eSAndy Shevchenko outl(inl(reg) & ~BIT(hwirq % 32), reg); 290b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 291eb83479eSAndy Shevchenko } 292eb83479eSAndy Shevchenko 293eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = { 294eb83479eSAndy Shevchenko .name = "LP-GPIO", 295eb83479eSAndy Shevchenko .irq_mask = lp_irq_mask, 296eb83479eSAndy Shevchenko .irq_unmask = lp_irq_unmask, 297eb83479eSAndy Shevchenko .irq_enable = lp_irq_enable, 298eb83479eSAndy Shevchenko .irq_disable = lp_irq_disable, 299eb83479eSAndy Shevchenko .irq_set_type = lp_irq_type, 300eb83479eSAndy Shevchenko .flags = IRQCHIP_SKIP_SET_WAKE, 301eb83479eSAndy Shevchenko }; 302eb83479eSAndy Shevchenko 303eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip) 304eb83479eSAndy Shevchenko { 305eb83479eSAndy Shevchenko struct lp_gpio *lg = gpiochip_get_data(chip); 306eb83479eSAndy Shevchenko unsigned long reg; 307eb83479eSAndy Shevchenko unsigned base; 308eb83479eSAndy Shevchenko 309eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 310eb83479eSAndy Shevchenko /* disable gpio pin interrupts */ 311eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 312eb83479eSAndy Shevchenko outl(0, reg); 313eb83479eSAndy Shevchenko /* Clear interrupt status register */ 314eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 315eb83479eSAndy Shevchenko outl(0xffffffff, reg); 316eb83479eSAndy Shevchenko } 317eb83479eSAndy Shevchenko 318eb83479eSAndy Shevchenko return 0; 319eb83479eSAndy Shevchenko } 320eb83479eSAndy Shevchenko 321eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev) 322eb83479eSAndy Shevchenko { 323eb83479eSAndy Shevchenko struct lp_gpio *lg; 324eb83479eSAndy Shevchenko struct gpio_chip *gc; 325eb83479eSAndy Shevchenko struct resource *io_rc, *irq_rc; 326eb83479eSAndy Shevchenko struct device *dev = &pdev->dev; 327eb83479eSAndy Shevchenko unsigned long reg_len; 3283b4c2d8eSAndy Shevchenko int ret; 329eb83479eSAndy Shevchenko 330*a718e68eSAndy Shevchenko lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 331eb83479eSAndy Shevchenko if (!lg) 332eb83479eSAndy Shevchenko return -ENOMEM; 333eb83479eSAndy Shevchenko 334eb83479eSAndy Shevchenko lg->pdev = pdev; 335eb83479eSAndy Shevchenko platform_set_drvdata(pdev, lg); 336eb83479eSAndy Shevchenko 337eb83479eSAndy Shevchenko io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 338eb83479eSAndy Shevchenko irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 339eb83479eSAndy Shevchenko 340eb83479eSAndy Shevchenko if (!io_rc) { 341eb83479eSAndy Shevchenko dev_err(dev, "missing IO resources\n"); 342eb83479eSAndy Shevchenko return -EINVAL; 343eb83479eSAndy Shevchenko } 344eb83479eSAndy Shevchenko 345eb83479eSAndy Shevchenko lg->reg_base = io_rc->start; 346eb83479eSAndy Shevchenko reg_len = resource_size(io_rc); 347eb83479eSAndy Shevchenko 348eb83479eSAndy Shevchenko if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) { 349caedcbd0SAndy Shevchenko dev_err(dev, "failed requesting IO region %pR\n", &io_rc); 350eb83479eSAndy Shevchenko return -EBUSY; 351eb83479eSAndy Shevchenko } 352eb83479eSAndy Shevchenko 353b2e05d63SAndy Shevchenko raw_spin_lock_init(&lg->lock); 354eb83479eSAndy Shevchenko 355eb83479eSAndy Shevchenko gc = &lg->chip; 356eb83479eSAndy Shevchenko gc->label = dev_name(dev); 357eb83479eSAndy Shevchenko gc->owner = THIS_MODULE; 358eb83479eSAndy Shevchenko gc->request = lp_gpio_request; 359eb83479eSAndy Shevchenko gc->free = lp_gpio_free; 360eb83479eSAndy Shevchenko gc->direction_input = lp_gpio_direction_input; 361eb83479eSAndy Shevchenko gc->direction_output = lp_gpio_direction_output; 362eb83479eSAndy Shevchenko gc->get = lp_gpio_get; 363eb83479eSAndy Shevchenko gc->set = lp_gpio_set; 364eb83479eSAndy Shevchenko gc->base = -1; 365eb83479eSAndy Shevchenko gc->ngpio = LP_NUM_GPIO; 366eb83479eSAndy Shevchenko gc->can_sleep = false; 367eb83479eSAndy Shevchenko gc->parent = dev; 368eb83479eSAndy Shevchenko 369eb83479eSAndy Shevchenko /* set up interrupts */ 370eb83479eSAndy Shevchenko if (irq_rc && irq_rc->start) { 371eb83479eSAndy Shevchenko struct gpio_irq_chip *girq; 372eb83479eSAndy Shevchenko 373eb83479eSAndy Shevchenko girq = &gc->irq; 374eb83479eSAndy Shevchenko girq->chip = &lp_irqchip; 375eb83479eSAndy Shevchenko girq->init_hw = lp_gpio_irq_init_hw; 376eb83479eSAndy Shevchenko girq->parent_handler = lp_gpio_irq_handler; 377eb83479eSAndy Shevchenko girq->num_parents = 1; 378eb83479eSAndy Shevchenko girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, 379eb83479eSAndy Shevchenko sizeof(*girq->parents), 380eb83479eSAndy Shevchenko GFP_KERNEL); 381eb83479eSAndy Shevchenko if (!girq->parents) 382eb83479eSAndy Shevchenko return -ENOMEM; 383eb83479eSAndy Shevchenko girq->parents[0] = (unsigned)irq_rc->start; 384eb83479eSAndy Shevchenko girq->default_type = IRQ_TYPE_NONE; 385eb83479eSAndy Shevchenko girq->handler = handle_bad_irq; 386eb83479eSAndy Shevchenko } 387eb83479eSAndy Shevchenko 388eb83479eSAndy Shevchenko ret = devm_gpiochip_add_data(dev, gc, lg); 389eb83479eSAndy Shevchenko if (ret) { 390eb83479eSAndy Shevchenko dev_err(dev, "failed adding lp-gpio chip\n"); 391eb83479eSAndy Shevchenko return ret; 392eb83479eSAndy Shevchenko } 393eb83479eSAndy Shevchenko 394eb83479eSAndy Shevchenko pm_runtime_enable(dev); 395eb83479eSAndy Shevchenko 396eb83479eSAndy Shevchenko return 0; 397eb83479eSAndy Shevchenko } 398eb83479eSAndy Shevchenko 399eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev) 400eb83479eSAndy Shevchenko { 401eb83479eSAndy Shevchenko return 0; 402eb83479eSAndy Shevchenko } 403eb83479eSAndy Shevchenko 404eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev) 405eb83479eSAndy Shevchenko { 406eb83479eSAndy Shevchenko return 0; 407eb83479eSAndy Shevchenko } 408eb83479eSAndy Shevchenko 409eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev) 410eb83479eSAndy Shevchenko { 411eb83479eSAndy Shevchenko struct lp_gpio *lg = dev_get_drvdata(dev); 412eb83479eSAndy Shevchenko unsigned long reg; 413eb83479eSAndy Shevchenko int i; 414eb83479eSAndy Shevchenko 415eb83479eSAndy Shevchenko /* on some hardware suspend clears input sensing, re-enable it here */ 416eb83479eSAndy Shevchenko for (i = 0; i < lg->chip.ngpio; i++) { 417eb83479eSAndy Shevchenko if (gpiochip_is_requested(&lg->chip, i) != NULL) { 418eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2); 419eb83479eSAndy Shevchenko outl(inl(reg) & ~GPINDIS_BIT, reg); 420eb83479eSAndy Shevchenko } 421eb83479eSAndy Shevchenko } 422eb83479eSAndy Shevchenko return 0; 423eb83479eSAndy Shevchenko } 424eb83479eSAndy Shevchenko 425eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = { 426eb83479eSAndy Shevchenko .runtime_suspend = lp_gpio_runtime_suspend, 427eb83479eSAndy Shevchenko .runtime_resume = lp_gpio_runtime_resume, 428eb83479eSAndy Shevchenko .resume = lp_gpio_resume, 429eb83479eSAndy Shevchenko }; 430eb83479eSAndy Shevchenko 431eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 432eb83479eSAndy Shevchenko { "INT33C7", 0 }, 433eb83479eSAndy Shevchenko { "INT3437", 0 }, 434eb83479eSAndy Shevchenko { } 435eb83479eSAndy Shevchenko }; 436eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 437eb83479eSAndy Shevchenko 438eb83479eSAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev) 439eb83479eSAndy Shevchenko { 440eb83479eSAndy Shevchenko pm_runtime_disable(&pdev->dev); 441eb83479eSAndy Shevchenko return 0; 442eb83479eSAndy Shevchenko } 443eb83479eSAndy Shevchenko 444eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = { 445eb83479eSAndy Shevchenko .probe = lp_gpio_probe, 446eb83479eSAndy Shevchenko .remove = lp_gpio_remove, 447eb83479eSAndy Shevchenko .driver = { 448eb83479eSAndy Shevchenko .name = "lp_gpio", 449eb83479eSAndy Shevchenko .pm = &lp_gpio_pm_ops, 450eb83479eSAndy Shevchenko .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), 451eb83479eSAndy Shevchenko }, 452eb83479eSAndy Shevchenko }; 453eb83479eSAndy Shevchenko 454eb83479eSAndy Shevchenko static int __init lp_gpio_init(void) 455eb83479eSAndy Shevchenko { 456eb83479eSAndy Shevchenko return platform_driver_register(&lp_gpio_driver); 457eb83479eSAndy Shevchenko } 458eb83479eSAndy Shevchenko 459eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void) 460eb83479eSAndy Shevchenko { 461eb83479eSAndy Shevchenko platform_driver_unregister(&lp_gpio_driver); 462eb83479eSAndy Shevchenko } 463eb83479eSAndy Shevchenko 464eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init); 465eb83479eSAndy Shevchenko module_exit(lp_gpio_exit); 466eb83479eSAndy Shevchenko 467eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)"); 468eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); 469eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2"); 470eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio"); 471