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 21cecddda7SAndy Shevchenko #include <linux/pinctrl/pinctrl.h> 22cecddda7SAndy Shevchenko #include <linux/pinctrl/pinmux.h> 23cecddda7SAndy Shevchenko #include <linux/pinctrl/pinconf.h> 24cecddda7SAndy Shevchenko #include <linux/pinctrl/pinconf-generic.h> 25cecddda7SAndy Shevchenko 26cecddda7SAndy Shevchenko #include "pinctrl-intel.h" 27cecddda7SAndy Shevchenko 28cecddda7SAndy Shevchenko #define COMMUNITY(p, n) \ 29cecddda7SAndy Shevchenko { \ 30cecddda7SAndy Shevchenko .pin_base = (p), \ 31cecddda7SAndy Shevchenko .npins = (n), \ 32cecddda7SAndy Shevchenko } 33cecddda7SAndy Shevchenko 34cecddda7SAndy Shevchenko static const struct pinctrl_pin_desc lptlp_pins[] = { 35cecddda7SAndy Shevchenko PINCTRL_PIN(0, "GP0_UART1_RXD"), 36cecddda7SAndy Shevchenko PINCTRL_PIN(1, "GP1_UART1_TXD"), 37cecddda7SAndy Shevchenko PINCTRL_PIN(2, "GP2_UART1_RTSB"), 38cecddda7SAndy Shevchenko PINCTRL_PIN(3, "GP3_UART1_CTSB"), 39cecddda7SAndy Shevchenko PINCTRL_PIN(4, "GP4_I2C0_SDA"), 40cecddda7SAndy Shevchenko PINCTRL_PIN(5, "GP5_I2C0_SCL"), 41cecddda7SAndy Shevchenko PINCTRL_PIN(6, "GP6_I2C1_SDA"), 42cecddda7SAndy Shevchenko PINCTRL_PIN(7, "GP7_I2C1_SCL"), 43cecddda7SAndy Shevchenko PINCTRL_PIN(8, "GP8"), 44cecddda7SAndy Shevchenko PINCTRL_PIN(9, "GP9"), 45cecddda7SAndy Shevchenko PINCTRL_PIN(10, "GP10"), 46cecddda7SAndy Shevchenko PINCTRL_PIN(11, "GP11_SMBALERTB"), 47cecddda7SAndy Shevchenko PINCTRL_PIN(12, "GP12_LANPHYPC"), 48cecddda7SAndy Shevchenko PINCTRL_PIN(13, "GP13"), 49cecddda7SAndy Shevchenko PINCTRL_PIN(14, "GP14"), 50cecddda7SAndy Shevchenko PINCTRL_PIN(15, "GP15"), 51cecddda7SAndy Shevchenko PINCTRL_PIN(16, "GP16_MGPIO9"), 52cecddda7SAndy Shevchenko PINCTRL_PIN(17, "GP17_MGPIO10"), 53cecddda7SAndy Shevchenko PINCTRL_PIN(18, "GP18_SRC0CLKRQB"), 54cecddda7SAndy Shevchenko PINCTRL_PIN(19, "GP19_SRC1CLKRQB"), 55cecddda7SAndy Shevchenko PINCTRL_PIN(20, "GP20_SRC2CLKRQB"), 56cecddda7SAndy Shevchenko PINCTRL_PIN(21, "GP21_SRC3CLKRQB"), 57cecddda7SAndy Shevchenko PINCTRL_PIN(22, "GP22_SRC4CLKRQB_TRST2"), 58cecddda7SAndy Shevchenko PINCTRL_PIN(23, "GP23_SRC5CLKRQB_TDI2"), 59cecddda7SAndy Shevchenko PINCTRL_PIN(24, "GP24_MGPIO0"), 60cecddda7SAndy Shevchenko PINCTRL_PIN(25, "GP25_USBWAKEOUTB"), 61cecddda7SAndy Shevchenko PINCTRL_PIN(26, "GP26_MGPIO5"), 62cecddda7SAndy Shevchenko PINCTRL_PIN(27, "GP27_MGPIO6"), 63cecddda7SAndy Shevchenko PINCTRL_PIN(28, "GP28_MGPIO7"), 64cecddda7SAndy Shevchenko PINCTRL_PIN(29, "GP29_SLP_WLANB_MGPIO3"), 65cecddda7SAndy Shevchenko PINCTRL_PIN(30, "GP30_SUSWARNB_SUSPWRDNACK_MGPIO1"), 66cecddda7SAndy Shevchenko PINCTRL_PIN(31, "GP31_ACPRESENT_MGPIO2"), 67cecddda7SAndy Shevchenko PINCTRL_PIN(32, "GP32_CLKRUNB"), 68cecddda7SAndy Shevchenko PINCTRL_PIN(33, "GP33_DEVSLP0"), 69cecddda7SAndy Shevchenko PINCTRL_PIN(34, "GP34_SATA0XPCIE6L3B_SATA0GP"), 70cecddda7SAndy Shevchenko PINCTRL_PIN(35, "GP35_SATA1XPCIE6L2B_SATA1GP"), 71cecddda7SAndy Shevchenko PINCTRL_PIN(36, "GP36_SATA2XPCIE6L1B_SATA2GP"), 72cecddda7SAndy Shevchenko PINCTRL_PIN(37, "GP37_SATA3XPCIE6L0B_SATA3GP"), 73cecddda7SAndy Shevchenko PINCTRL_PIN(38, "GP38_DEVSLP1"), 74cecddda7SAndy Shevchenko PINCTRL_PIN(39, "GP39_DEVSLP2"), 75cecddda7SAndy Shevchenko PINCTRL_PIN(40, "GP40_OC0B"), 76cecddda7SAndy Shevchenko PINCTRL_PIN(41, "GP41_OC1B"), 77cecddda7SAndy Shevchenko PINCTRL_PIN(42, "GP42_OC2B"), 78cecddda7SAndy Shevchenko PINCTRL_PIN(43, "GP43_OC3B"), 79cecddda7SAndy Shevchenko PINCTRL_PIN(44, "GP44"), 80cecddda7SAndy Shevchenko PINCTRL_PIN(45, "GP45_TMS2"), 81cecddda7SAndy Shevchenko PINCTRL_PIN(46, "GP46_TDO2"), 82cecddda7SAndy Shevchenko PINCTRL_PIN(47, "GP47"), 83cecddda7SAndy Shevchenko PINCTRL_PIN(48, "GP48"), 84cecddda7SAndy Shevchenko PINCTRL_PIN(49, "GP49"), 85cecddda7SAndy Shevchenko PINCTRL_PIN(50, "GP50"), 86cecddda7SAndy Shevchenko PINCTRL_PIN(51, "GP51_GSXDOUT"), 87cecddda7SAndy Shevchenko PINCTRL_PIN(52, "GP52_GSXSLOAD"), 88cecddda7SAndy Shevchenko PINCTRL_PIN(53, "GP53_GSXDIN"), 89cecddda7SAndy Shevchenko PINCTRL_PIN(54, "GP54_GSXSRESETB"), 90cecddda7SAndy Shevchenko PINCTRL_PIN(55, "GP55_GSXCLK"), 91cecddda7SAndy Shevchenko PINCTRL_PIN(56, "GP56"), 92cecddda7SAndy Shevchenko PINCTRL_PIN(57, "GP57"), 93cecddda7SAndy Shevchenko PINCTRL_PIN(58, "GP58"), 94cecddda7SAndy Shevchenko PINCTRL_PIN(59, "GP59"), 95cecddda7SAndy Shevchenko PINCTRL_PIN(60, "GP60_SML0ALERTB_MGPIO4"), 96cecddda7SAndy Shevchenko PINCTRL_PIN(61, "GP61_SUS_STATB"), 97cecddda7SAndy Shevchenko PINCTRL_PIN(62, "GP62_SUSCLK"), 98cecddda7SAndy Shevchenko PINCTRL_PIN(63, "GP63_SLP_S5B"), 99cecddda7SAndy Shevchenko PINCTRL_PIN(64, "GP64_SDIO_CLK"), 100cecddda7SAndy Shevchenko PINCTRL_PIN(65, "GP65_SDIO_CMD"), 101cecddda7SAndy Shevchenko PINCTRL_PIN(66, "GP66_SDIO_D0"), 102cecddda7SAndy Shevchenko PINCTRL_PIN(67, "GP67_SDIO_D1"), 103cecddda7SAndy Shevchenko PINCTRL_PIN(68, "GP68_SDIO_D2"), 104cecddda7SAndy Shevchenko PINCTRL_PIN(69, "GP69_SDIO_D3"), 105cecddda7SAndy Shevchenko PINCTRL_PIN(70, "GP70_SDIO_POWER_EN"), 106cecddda7SAndy Shevchenko PINCTRL_PIN(71, "GP71_MPHYPC"), 107cecddda7SAndy Shevchenko PINCTRL_PIN(72, "GP72_BATLOWB"), 108cecddda7SAndy Shevchenko PINCTRL_PIN(73, "GP73_SML1ALERTB_PCHHOTB_MGPIO8"), 109cecddda7SAndy Shevchenko PINCTRL_PIN(74, "GP74_SML1DATA_MGPIO12"), 110cecddda7SAndy Shevchenko PINCTRL_PIN(75, "GP75_SML1CLK_MGPIO11"), 111cecddda7SAndy Shevchenko PINCTRL_PIN(76, "GP76_BMBUSYB"), 112cecddda7SAndy Shevchenko PINCTRL_PIN(77, "GP77_PIRQAB"), 113cecddda7SAndy Shevchenko PINCTRL_PIN(78, "GP78_PIRQBB"), 114cecddda7SAndy Shevchenko PINCTRL_PIN(79, "GP79_PIRQCB"), 115cecddda7SAndy Shevchenko PINCTRL_PIN(80, "GP80_PIRQDB"), 116cecddda7SAndy Shevchenko PINCTRL_PIN(81, "GP81_SPKR"), 117cecddda7SAndy Shevchenko PINCTRL_PIN(82, "GP82_RCINB"), 118cecddda7SAndy Shevchenko PINCTRL_PIN(83, "GP83_GSPI0_CSB"), 119cecddda7SAndy Shevchenko PINCTRL_PIN(84, "GP84_GSPI0_CLK"), 120cecddda7SAndy Shevchenko PINCTRL_PIN(85, "GP85_GSPI0_MISO"), 121cecddda7SAndy Shevchenko PINCTRL_PIN(86, "GP86_GSPI0_MOSI"), 122cecddda7SAndy Shevchenko PINCTRL_PIN(87, "GP87_GSPI1_CSB"), 123cecddda7SAndy Shevchenko PINCTRL_PIN(88, "GP88_GSPI1_CLK"), 124cecddda7SAndy Shevchenko PINCTRL_PIN(89, "GP89_GSPI1_MISO"), 125cecddda7SAndy Shevchenko PINCTRL_PIN(90, "GP90_GSPI1_MOSI"), 126cecddda7SAndy Shevchenko PINCTRL_PIN(91, "GP91_UART0_RXD"), 127cecddda7SAndy Shevchenko PINCTRL_PIN(92, "GP92_UART0_TXD"), 128cecddda7SAndy Shevchenko PINCTRL_PIN(93, "GP93_UART0_RTSB"), 129cecddda7SAndy Shevchenko PINCTRL_PIN(94, "GP94_UART0_CTSB"), 130cecddda7SAndy Shevchenko }; 131cecddda7SAndy Shevchenko 132cecddda7SAndy Shevchenko static const struct intel_community lptlp_communities[] = { 133cecddda7SAndy Shevchenko COMMUNITY(0, 95), 134cecddda7SAndy Shevchenko }; 135cecddda7SAndy Shevchenko 136cecddda7SAndy Shevchenko static const struct intel_pinctrl_soc_data lptlp_soc_data = { 137cecddda7SAndy Shevchenko .pins = lptlp_pins, 138cecddda7SAndy Shevchenko .npins = ARRAY_SIZE(lptlp_pins), 139cecddda7SAndy Shevchenko .communities = lptlp_communities, 140cecddda7SAndy Shevchenko .ncommunities = ARRAY_SIZE(lptlp_communities), 141cecddda7SAndy Shevchenko }; 142cecddda7SAndy Shevchenko 1437c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */ 144eb83479eSAndy Shevchenko 1457c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO 95 146eb83479eSAndy Shevchenko 147eb83479eSAndy Shevchenko /* Bitmapped register offsets */ 148eb83479eSAndy Shevchenko #define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ 149eb83479eSAndy Shevchenko #define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ 150eb83479eSAndy Shevchenko #define LP_INT_STAT 0x80 151eb83479eSAndy Shevchenko #define LP_INT_ENABLE 0x90 152eb83479eSAndy Shevchenko 153eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */ 154eb83479eSAndy Shevchenko #define LP_CONFIG1 0x100 155eb83479eSAndy Shevchenko #define LP_CONFIG2 0x104 156eb83479eSAndy Shevchenko 157eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */ 158eb83479eSAndy Shevchenko #define OUT_LVL_BIT BIT(31) 159eb83479eSAndy Shevchenko #define IN_LVL_BIT BIT(30) 160eb83479eSAndy Shevchenko #define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ 161eb83479eSAndy Shevchenko #define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ 162eb83479eSAndy Shevchenko #define DIR_BIT BIT(2) /* 0: Output, 1: Input */ 16376347d7aSAndy Shevchenko #define USE_SEL_MASK GENMASK(1, 0) /* 0: Native, 1: GPIO, ... */ 16476347d7aSAndy Shevchenko #define USE_SEL_NATIVE (0 << 0) 16576347d7aSAndy Shevchenko #define USE_SEL_GPIO (1 << 0) 166eb83479eSAndy Shevchenko 167eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */ 168eb83479eSAndy Shevchenko #define GPINDIS_BIT BIT(2) /* disable input sensing */ 169eb83479eSAndy Shevchenko #define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */ 170eb83479eSAndy Shevchenko 171eb83479eSAndy Shevchenko /* 172eb83479eSAndy Shevchenko * Lynxpoint gpios are controlled through both bitmapped registers and 173eb83479eSAndy Shevchenko * per gpio specific registers. The bitmapped registers are in chunks of 1747c0bc7bbSAndy Shevchenko * 3 x 32bit registers to cover all 95 GPIOs 175eb83479eSAndy Shevchenko * 176eb83479eSAndy Shevchenko * per gpio specific registers consist of two 32bit registers per gpio 1777c0bc7bbSAndy Shevchenko * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 1787c0bc7bbSAndy Shevchenko * 190 config registers. 179eb83479eSAndy Shevchenko * 180eb83479eSAndy Shevchenko * A simplified view of the register layout look like this: 181eb83479eSAndy Shevchenko * 182eb83479eSAndy Shevchenko * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 183eb83479eSAndy Shevchenko * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 184eb83479eSAndy Shevchenko * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 185eb83479eSAndy Shevchenko * ... 186eb83479eSAndy Shevchenko * LP_INT_ENABLE[31:0] ... 1877c0bc7bbSAndy Shevchenko * LP_INT_ENABLE[63:32] ... 188eb83479eSAndy Shevchenko * LP_INT_ENABLE[94:64] ... 189eb83479eSAndy Shevchenko * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 190eb83479eSAndy Shevchenko * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 191eb83479eSAndy Shevchenko * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 192eb83479eSAndy Shevchenko * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 193eb83479eSAndy Shevchenko * LP2_CONFIG1 (gpio 2) ... 194eb83479eSAndy Shevchenko * LP2_CONFIG2 (gpio 2) ... 195eb83479eSAndy Shevchenko * ... 196eb83479eSAndy Shevchenko * LP94_CONFIG1 (gpio 94) ... 197eb83479eSAndy Shevchenko * LP94_CONFIG2 (gpio 94) ... 198eb83479eSAndy Shevchenko */ 199eb83479eSAndy Shevchenko 200*18213ad4SAndy Shevchenko static struct intel_community *lp_get_community(struct intel_pinctrl *lg, 201*18213ad4SAndy Shevchenko unsigned int pin) 202*18213ad4SAndy Shevchenko { 203*18213ad4SAndy Shevchenko struct intel_community *comm; 204*18213ad4SAndy Shevchenko int i; 205*18213ad4SAndy Shevchenko 206*18213ad4SAndy Shevchenko for (i = 0; i < lg->ncommunities; i++) { 207*18213ad4SAndy Shevchenko comm = &lg->communities[i]; 208*18213ad4SAndy Shevchenko if (pin < comm->pin_base + comm->npins && pin >= comm->pin_base) 209*18213ad4SAndy Shevchenko return comm; 210*18213ad4SAndy Shevchenko } 211*18213ad4SAndy Shevchenko 212*18213ad4SAndy Shevchenko return NULL; 213*18213ad4SAndy Shevchenko } 214*18213ad4SAndy Shevchenko 215c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset, 216eb83479eSAndy Shevchenko int reg) 217eb83479eSAndy Shevchenko { 218*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 219*18213ad4SAndy Shevchenko struct intel_community *comm; 220eb83479eSAndy Shevchenko int reg_offset; 221eb83479eSAndy Shevchenko 222*18213ad4SAndy Shevchenko comm = lp_get_community(lg, offset); 223*18213ad4SAndy Shevchenko if (!comm) 224*18213ad4SAndy Shevchenko return NULL; 225*18213ad4SAndy Shevchenko 226*18213ad4SAndy Shevchenko offset -= comm->pin_base; 227*18213ad4SAndy Shevchenko 228eb83479eSAndy Shevchenko if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 229eb83479eSAndy Shevchenko /* per gpio specific config registers */ 230eb83479eSAndy Shevchenko reg_offset = offset * 8; 231eb83479eSAndy Shevchenko else 232eb83479eSAndy Shevchenko /* bitmapped registers */ 233eb83479eSAndy Shevchenko reg_offset = (offset / 32) * 4; 234eb83479eSAndy Shevchenko 235*18213ad4SAndy Shevchenko return comm->regs + reg_offset + reg; 236eb83479eSAndy Shevchenko } 237eb83479eSAndy Shevchenko 238*18213ad4SAndy Shevchenko static bool lp_gpio_acpi_use(struct intel_pinctrl *lg, unsigned int pin) 23921a06495SAndy Shevchenko { 24021a06495SAndy Shevchenko void __iomem *acpi_use; 24121a06495SAndy Shevchenko 24221a06495SAndy Shevchenko acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED); 24321a06495SAndy Shevchenko if (!acpi_use) 24421a06495SAndy Shevchenko return true; 24521a06495SAndy Shevchenko 24621a06495SAndy Shevchenko return !(ioread32(acpi_use) & BIT(pin % 32)); 24721a06495SAndy Shevchenko } 24821a06495SAndy Shevchenko 249c35f463aSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned int offset) 250eb83479eSAndy Shevchenko { 251*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 252e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 253e1940adeSAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 25403fb681bSAndy Shevchenko u32 value; 255eb83479eSAndy Shevchenko 2561e78ea71SAndy Shevchenko pm_runtime_get(lg->dev); /* should we put if failed */ 257eb83479eSAndy Shevchenko 25803fb681bSAndy Shevchenko /* 25903fb681bSAndy Shevchenko * Reconfigure pin to GPIO mode if needed and issue a warning, 26003fb681bSAndy Shevchenko * since we expect firmware to configure it properly. 26103fb681bSAndy Shevchenko */ 262e1940adeSAndy Shevchenko value = ioread32(reg); 26303fb681bSAndy Shevchenko if ((value & USE_SEL_MASK) != USE_SEL_GPIO) { 264e1940adeSAndy Shevchenko iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg); 2651e78ea71SAndy Shevchenko dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", offset); 26603fb681bSAndy Shevchenko } 267eb83479eSAndy Shevchenko 268eb83479eSAndy Shevchenko /* enable input sensing */ 269e1940adeSAndy Shevchenko iowrite32(ioread32(conf2) & ~GPINDIS_BIT, conf2); 270eb83479eSAndy Shevchenko 271eb83479eSAndy Shevchenko 272eb83479eSAndy Shevchenko return 0; 273eb83479eSAndy Shevchenko } 274eb83479eSAndy Shevchenko 275c35f463aSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned int offset) 276eb83479eSAndy Shevchenko { 277*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 278e1940adeSAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2); 279eb83479eSAndy Shevchenko 280eb83479eSAndy Shevchenko /* disable input sensing */ 281e1940adeSAndy Shevchenko iowrite32(ioread32(conf2) | GPINDIS_BIT, conf2); 282eb83479eSAndy Shevchenko 2831e78ea71SAndy Shevchenko pm_runtime_put(lg->dev); 284eb83479eSAndy Shevchenko } 285eb83479eSAndy Shevchenko 286c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset) 287eb83479eSAndy Shevchenko { 288e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 289e1940adeSAndy Shevchenko return !!(ioread32(reg) & IN_LVL_BIT); 290eb83479eSAndy Shevchenko } 291eb83479eSAndy Shevchenko 292c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 293eb83479eSAndy Shevchenko { 294*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 295e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 296eb83479eSAndy Shevchenko unsigned long flags; 297eb83479eSAndy Shevchenko 298b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 299eb83479eSAndy Shevchenko 300eb83479eSAndy Shevchenko if (value) 301e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | OUT_LVL_BIT, reg); 302eb83479eSAndy Shevchenko else 303e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg); 304eb83479eSAndy Shevchenko 305b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 306eb83479eSAndy Shevchenko } 307eb83479eSAndy Shevchenko 308c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 309eb83479eSAndy Shevchenko { 310*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 311e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 312eb83479eSAndy Shevchenko unsigned long flags; 313eb83479eSAndy Shevchenko 314b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 315e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | DIR_BIT, reg); 316b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 317eb83479eSAndy Shevchenko 318eb83479eSAndy Shevchenko return 0; 319eb83479eSAndy Shevchenko } 320eb83479eSAndy Shevchenko 321c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 322c35f463aSAndy Shevchenko int value) 323eb83479eSAndy Shevchenko { 324*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 325e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 326eb83479eSAndy Shevchenko unsigned long flags; 327eb83479eSAndy Shevchenko 328eb83479eSAndy Shevchenko lp_gpio_set(chip, offset, value); 329eb83479eSAndy Shevchenko 330b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 331e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~DIR_BIT, reg); 332b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 333eb83479eSAndy Shevchenko 334eb83479eSAndy Shevchenko return 0; 335eb83479eSAndy Shevchenko } 336eb83479eSAndy Shevchenko 33754d371cfSAndy Shevchenko static int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 33854d371cfSAndy Shevchenko { 33954d371cfSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 34054d371cfSAndy Shevchenko 34154d371cfSAndy Shevchenko if (ioread32(reg) & DIR_BIT) 34254d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_IN; 34354d371cfSAndy Shevchenko 34454d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_OUT; 34554d371cfSAndy Shevchenko } 34654d371cfSAndy Shevchenko 347eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc) 348eb83479eSAndy Shevchenko { 349eb83479eSAndy Shevchenko struct irq_data *data = irq_desc_get_irq_data(desc); 350eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_desc_get_handler_data(desc); 351*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 352eb83479eSAndy Shevchenko struct irq_chip *chip = irq_data_get_irq_chip(data); 353e1940adeSAndy Shevchenko void __iomem *reg, *ena; 354e1940adeSAndy Shevchenko unsigned long pending; 355eb83479eSAndy Shevchenko u32 base, pin; 356eb83479eSAndy Shevchenko 357eb83479eSAndy Shevchenko /* check from GPIO controller which pin triggered the interrupt */ 358eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 359eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 360eb83479eSAndy Shevchenko ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 361eb83479eSAndy Shevchenko 362eb83479eSAndy Shevchenko /* Only interrupts that are enabled */ 363e1940adeSAndy Shevchenko pending = ioread32(reg) & ioread32(ena); 364eb83479eSAndy Shevchenko 365eb83479eSAndy Shevchenko for_each_set_bit(pin, &pending, 32) { 366c35f463aSAndy Shevchenko unsigned int irq; 367eb83479eSAndy Shevchenko 368eb83479eSAndy Shevchenko irq = irq_find_mapping(lg->chip.irq.domain, base + pin); 369eb83479eSAndy Shevchenko generic_handle_irq(irq); 370eb83479eSAndy Shevchenko } 371eb83479eSAndy Shevchenko } 372eb83479eSAndy Shevchenko chip->irq_eoi(data); 373eb83479eSAndy Shevchenko } 374eb83479eSAndy Shevchenko 3755931e6edSAndy Shevchenko static void lp_irq_ack(struct irq_data *d) 3765931e6edSAndy Shevchenko { 3775931e6edSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 378*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 3795931e6edSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 3805931e6edSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT); 3815931e6edSAndy Shevchenko unsigned long flags; 3825931e6edSAndy Shevchenko 3835931e6edSAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 3845931e6edSAndy Shevchenko iowrite32(BIT(hwirq % 32), reg); 3855931e6edSAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 3865931e6edSAndy Shevchenko } 3875931e6edSAndy Shevchenko 388eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d) 389eb83479eSAndy Shevchenko { 390eb83479eSAndy Shevchenko } 391eb83479eSAndy Shevchenko 392eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d) 393eb83479eSAndy Shevchenko { 394eb83479eSAndy Shevchenko } 395eb83479eSAndy Shevchenko 396eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d) 397eb83479eSAndy Shevchenko { 398eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 399*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 400eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 401e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 402eb83479eSAndy Shevchenko unsigned long flags; 403eb83479eSAndy Shevchenko 404b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 405e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | BIT(hwirq % 32), reg); 406b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 407eb83479eSAndy Shevchenko } 408eb83479eSAndy Shevchenko 409eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d) 410eb83479eSAndy Shevchenko { 411eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 412*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 413eb83479eSAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 414e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 415eb83479eSAndy Shevchenko unsigned long flags; 416eb83479eSAndy Shevchenko 417b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 418e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg); 419b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 420eb83479eSAndy Shevchenko } 421eb83479eSAndy Shevchenko 422095f2a67SAndy Shevchenko static int lp_irq_set_type(struct irq_data *d, unsigned int type) 423095f2a67SAndy Shevchenko { 424095f2a67SAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 425*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 426095f2a67SAndy Shevchenko u32 hwirq = irqd_to_hwirq(d); 427095f2a67SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 428095f2a67SAndy Shevchenko unsigned long flags; 429095f2a67SAndy Shevchenko u32 value; 430095f2a67SAndy Shevchenko 431095f2a67SAndy Shevchenko if (hwirq >= lg->chip.ngpio) 432095f2a67SAndy Shevchenko return -EINVAL; 433095f2a67SAndy Shevchenko 434540bff18SAndy Shevchenko /* Fail if BIOS reserved pin for ACPI use */ 435540bff18SAndy Shevchenko if (lp_gpio_acpi_use(lg, hwirq)) { 436540bff18SAndy Shevchenko dev_err(lg->dev, "pin %u can't be used as IRQ\n", hwirq); 437540bff18SAndy Shevchenko return -EBUSY; 438540bff18SAndy Shevchenko } 439540bff18SAndy Shevchenko 440095f2a67SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 441095f2a67SAndy Shevchenko value = ioread32(reg); 442095f2a67SAndy Shevchenko 443095f2a67SAndy Shevchenko /* set both TRIG_SEL and INV bits to 0 for rising edge */ 444095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_RISING) 445095f2a67SAndy Shevchenko value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 446095f2a67SAndy Shevchenko 447095f2a67SAndy Shevchenko /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 448095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_FALLING) 449095f2a67SAndy Shevchenko value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 450095f2a67SAndy Shevchenko 451095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 0 for level low */ 452095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_LOW) 453095f2a67SAndy Shevchenko value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 454095f2a67SAndy Shevchenko 455095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 1 for level high */ 456095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_HIGH) 457095f2a67SAndy Shevchenko value |= TRIG_SEL_BIT | INT_INV_BIT; 458095f2a67SAndy Shevchenko 459095f2a67SAndy Shevchenko iowrite32(value, reg); 460095f2a67SAndy Shevchenko 461095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_BOTH) 462095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_edge_irq); 463095f2a67SAndy Shevchenko else if (type & IRQ_TYPE_LEVEL_MASK) 464095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_level_irq); 465095f2a67SAndy Shevchenko 466095f2a67SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 467095f2a67SAndy Shevchenko 468095f2a67SAndy Shevchenko return 0; 469095f2a67SAndy Shevchenko } 470095f2a67SAndy Shevchenko 471eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = { 472eb83479eSAndy Shevchenko .name = "LP-GPIO", 4735931e6edSAndy Shevchenko .irq_ack = lp_irq_ack, 474eb83479eSAndy Shevchenko .irq_mask = lp_irq_mask, 475eb83479eSAndy Shevchenko .irq_unmask = lp_irq_unmask, 476eb83479eSAndy Shevchenko .irq_enable = lp_irq_enable, 477eb83479eSAndy Shevchenko .irq_disable = lp_irq_disable, 478095f2a67SAndy Shevchenko .irq_set_type = lp_irq_set_type, 479eb83479eSAndy Shevchenko .flags = IRQCHIP_SKIP_SET_WAKE, 480eb83479eSAndy Shevchenko }; 481eb83479eSAndy Shevchenko 482eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip) 483eb83479eSAndy Shevchenko { 484*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 485e1940adeSAndy Shevchenko void __iomem *reg; 486c35f463aSAndy Shevchenko unsigned int base; 487eb83479eSAndy Shevchenko 488eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 489eb83479eSAndy Shevchenko /* disable gpio pin interrupts */ 490eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 491e1940adeSAndy Shevchenko iowrite32(0, reg); 492eb83479eSAndy Shevchenko /* Clear interrupt status register */ 493eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 494e1940adeSAndy Shevchenko iowrite32(0xffffffff, reg); 495eb83479eSAndy Shevchenko } 496eb83479eSAndy Shevchenko 497eb83479eSAndy Shevchenko return 0; 498eb83479eSAndy Shevchenko } 499eb83479eSAndy Shevchenko 500eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev) 501eb83479eSAndy Shevchenko { 502*18213ad4SAndy Shevchenko const struct intel_pinctrl_soc_data *soc; 503*18213ad4SAndy Shevchenko struct intel_pinctrl *lg; 504eb83479eSAndy Shevchenko struct gpio_chip *gc; 505eb83479eSAndy Shevchenko struct resource *io_rc, *irq_rc; 506eb83479eSAndy Shevchenko struct device *dev = &pdev->dev; 507e1940adeSAndy Shevchenko void __iomem *regs; 508*18213ad4SAndy Shevchenko unsigned int i; 5093b4c2d8eSAndy Shevchenko int ret; 510eb83479eSAndy Shevchenko 511*18213ad4SAndy Shevchenko soc = (const struct intel_pinctrl_soc_data *)device_get_match_data(dev); 512*18213ad4SAndy Shevchenko if (!soc) 513*18213ad4SAndy Shevchenko return -ENODEV; 514*18213ad4SAndy Shevchenko 515a718e68eSAndy Shevchenko lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 516eb83479eSAndy Shevchenko if (!lg) 517eb83479eSAndy Shevchenko return -ENOMEM; 518eb83479eSAndy Shevchenko 5191e78ea71SAndy Shevchenko lg->dev = dev; 520*18213ad4SAndy Shevchenko lg->soc = soc; 521*18213ad4SAndy Shevchenko 522*18213ad4SAndy Shevchenko lg->ncommunities = lg->soc->ncommunities; 523*18213ad4SAndy Shevchenko lg->communities = devm_kcalloc(dev, lg->ncommunities, 524*18213ad4SAndy Shevchenko sizeof(*lg->communities), GFP_KERNEL); 525*18213ad4SAndy Shevchenko if (!lg->communities) 526*18213ad4SAndy Shevchenko return -ENOMEM; 527*18213ad4SAndy Shevchenko 528eb83479eSAndy Shevchenko platform_set_drvdata(pdev, lg); 529eb83479eSAndy Shevchenko 530eb83479eSAndy Shevchenko io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 531eb83479eSAndy Shevchenko if (!io_rc) { 532eb83479eSAndy Shevchenko dev_err(dev, "missing IO resources\n"); 533eb83479eSAndy Shevchenko return -EINVAL; 534eb83479eSAndy Shevchenko } 535eb83479eSAndy Shevchenko 536e1940adeSAndy Shevchenko regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); 537e1940adeSAndy Shevchenko if (!regs) { 538e1940adeSAndy Shevchenko dev_err(dev, "failed mapping IO region %pR\n", &io_rc); 539eb83479eSAndy Shevchenko return -EBUSY; 540eb83479eSAndy Shevchenko } 541eb83479eSAndy Shevchenko 542*18213ad4SAndy Shevchenko for (i = 0; i < lg->soc->ncommunities; i++) { 543*18213ad4SAndy Shevchenko struct intel_community *comm = &lg->communities[i]; 544*18213ad4SAndy Shevchenko 545*18213ad4SAndy Shevchenko *comm = lg->soc->communities[i]; 546*18213ad4SAndy Shevchenko 547*18213ad4SAndy Shevchenko comm->regs = regs; 548*18213ad4SAndy Shevchenko comm->pad_regs = regs + 0x100; 549*18213ad4SAndy Shevchenko } 550e1940adeSAndy Shevchenko 551b2e05d63SAndy Shevchenko raw_spin_lock_init(&lg->lock); 552eb83479eSAndy Shevchenko 553eb83479eSAndy Shevchenko gc = &lg->chip; 554eb83479eSAndy Shevchenko gc->label = dev_name(dev); 555eb83479eSAndy Shevchenko gc->owner = THIS_MODULE; 556eb83479eSAndy Shevchenko gc->request = lp_gpio_request; 557eb83479eSAndy Shevchenko gc->free = lp_gpio_free; 558eb83479eSAndy Shevchenko gc->direction_input = lp_gpio_direction_input; 559eb83479eSAndy Shevchenko gc->direction_output = lp_gpio_direction_output; 560eb83479eSAndy Shevchenko gc->get = lp_gpio_get; 561eb83479eSAndy Shevchenko gc->set = lp_gpio_set; 56254d371cfSAndy Shevchenko gc->get_direction = lp_gpio_get_direction; 563eb83479eSAndy Shevchenko gc->base = -1; 564eb83479eSAndy Shevchenko gc->ngpio = LP_NUM_GPIO; 565eb83479eSAndy Shevchenko gc->can_sleep = false; 566eb83479eSAndy Shevchenko gc->parent = dev; 567eb83479eSAndy Shevchenko 568eb83479eSAndy Shevchenko /* set up interrupts */ 569e1940adeSAndy Shevchenko irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 570eb83479eSAndy Shevchenko if (irq_rc && irq_rc->start) { 571eb83479eSAndy Shevchenko struct gpio_irq_chip *girq; 572eb83479eSAndy Shevchenko 573eb83479eSAndy Shevchenko girq = &gc->irq; 574eb83479eSAndy Shevchenko girq->chip = &lp_irqchip; 575eb83479eSAndy Shevchenko girq->init_hw = lp_gpio_irq_init_hw; 576eb83479eSAndy Shevchenko girq->parent_handler = lp_gpio_irq_handler; 577eb83479eSAndy Shevchenko girq->num_parents = 1; 5781e78ea71SAndy Shevchenko girq->parents = devm_kcalloc(dev, girq->num_parents, 579eb83479eSAndy Shevchenko sizeof(*girq->parents), 580eb83479eSAndy Shevchenko GFP_KERNEL); 581eb83479eSAndy Shevchenko if (!girq->parents) 582eb83479eSAndy Shevchenko return -ENOMEM; 583c35f463aSAndy Shevchenko girq->parents[0] = (unsigned int)irq_rc->start; 584eb83479eSAndy Shevchenko girq->default_type = IRQ_TYPE_NONE; 585eb83479eSAndy Shevchenko girq->handler = handle_bad_irq; 586eb83479eSAndy Shevchenko } 587eb83479eSAndy Shevchenko 588eb83479eSAndy Shevchenko ret = devm_gpiochip_add_data(dev, gc, lg); 589eb83479eSAndy Shevchenko if (ret) { 590eb83479eSAndy Shevchenko dev_err(dev, "failed adding lp-gpio chip\n"); 591eb83479eSAndy Shevchenko return ret; 592eb83479eSAndy Shevchenko } 593eb83479eSAndy Shevchenko 594eb83479eSAndy Shevchenko pm_runtime_enable(dev); 595eb83479eSAndy Shevchenko 596eb83479eSAndy Shevchenko return 0; 597eb83479eSAndy Shevchenko } 598eb83479eSAndy Shevchenko 599d0f2df40SAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev) 600d0f2df40SAndy Shevchenko { 601d0f2df40SAndy Shevchenko pm_runtime_disable(&pdev->dev); 602d0f2df40SAndy Shevchenko return 0; 603d0f2df40SAndy Shevchenko } 604d0f2df40SAndy Shevchenko 605eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev) 606eb83479eSAndy Shevchenko { 607eb83479eSAndy Shevchenko return 0; 608eb83479eSAndy Shevchenko } 609eb83479eSAndy Shevchenko 610eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev) 611eb83479eSAndy Shevchenko { 612eb83479eSAndy Shevchenko return 0; 613eb83479eSAndy Shevchenko } 614eb83479eSAndy Shevchenko 615eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev) 616eb83479eSAndy Shevchenko { 617*18213ad4SAndy Shevchenko struct intel_pinctrl *lg = dev_get_drvdata(dev); 618e1940adeSAndy Shevchenko void __iomem *reg; 619eb83479eSAndy Shevchenko int i; 620eb83479eSAndy Shevchenko 621eb83479eSAndy Shevchenko /* on some hardware suspend clears input sensing, re-enable it here */ 622eb83479eSAndy Shevchenko for (i = 0; i < lg->chip.ngpio; i++) { 623eb83479eSAndy Shevchenko if (gpiochip_is_requested(&lg->chip, i) != NULL) { 624eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2); 625e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg); 626eb83479eSAndy Shevchenko } 627eb83479eSAndy Shevchenko } 628eb83479eSAndy Shevchenko return 0; 629eb83479eSAndy Shevchenko } 630eb83479eSAndy Shevchenko 631eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = { 632eb83479eSAndy Shevchenko .runtime_suspend = lp_gpio_runtime_suspend, 633eb83479eSAndy Shevchenko .runtime_resume = lp_gpio_runtime_resume, 634eb83479eSAndy Shevchenko .resume = lp_gpio_resume, 635eb83479eSAndy Shevchenko }; 636eb83479eSAndy Shevchenko 637eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 638cecddda7SAndy Shevchenko { "INT33C7", (kernel_ulong_t)&lptlp_soc_data }, 639cecddda7SAndy Shevchenko { "INT3437", (kernel_ulong_t)&lptlp_soc_data }, 640eb83479eSAndy Shevchenko { } 641eb83479eSAndy Shevchenko }; 642eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 643eb83479eSAndy Shevchenko 644eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = { 645eb83479eSAndy Shevchenko .probe = lp_gpio_probe, 646eb83479eSAndy Shevchenko .remove = lp_gpio_remove, 647eb83479eSAndy Shevchenko .driver = { 648eb83479eSAndy Shevchenko .name = "lp_gpio", 649eb83479eSAndy Shevchenko .pm = &lp_gpio_pm_ops, 650eb83479eSAndy Shevchenko .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match), 651eb83479eSAndy Shevchenko }, 652eb83479eSAndy Shevchenko }; 653eb83479eSAndy Shevchenko 654eb83479eSAndy Shevchenko static int __init lp_gpio_init(void) 655eb83479eSAndy Shevchenko { 656eb83479eSAndy Shevchenko return platform_driver_register(&lp_gpio_driver); 657eb83479eSAndy Shevchenko } 658eb83479eSAndy Shevchenko 659eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void) 660eb83479eSAndy Shevchenko { 661eb83479eSAndy Shevchenko platform_driver_unregister(&lp_gpio_driver); 662eb83479eSAndy Shevchenko } 663eb83479eSAndy Shevchenko 664eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init); 665eb83479eSAndy Shevchenko module_exit(lp_gpio_exit); 666eb83479eSAndy Shevchenko 667eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)"); 668eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint"); 669eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2"); 670eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio"); 671