1eb83479eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0 2eb83479eSAndy Shevchenko /* 33a67fe38SAndy Shevchenko * Intel Lynxpoint PCH pinctrl/GPIO driver 4eb83479eSAndy Shevchenko * 53a67fe38SAndy Shevchenko * Copyright (c) 2012, 2019, Intel Corporation 63a67fe38SAndy Shevchenko * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> 73a67fe38SAndy Shevchenko * Andy Shevchenko <andriy.shevchenko@linux.intel.com> 8eb83479eSAndy Shevchenko */ 9eb83479eSAndy Shevchenko 10eb83479eSAndy Shevchenko #include <linux/acpi.h> 111cb71a63SAndy Shevchenko #include <linux/array_size.h> 12eb83479eSAndy Shevchenko #include <linux/bitops.h> 13eb83479eSAndy Shevchenko #include <linux/gpio/driver.h> 14eb83479eSAndy Shevchenko #include <linux/interrupt.h> 15eb83479eSAndy Shevchenko #include <linux/io.h> 16eb83479eSAndy Shevchenko #include <linux/module.h> 17eb83479eSAndy Shevchenko #include <linux/platform_device.h> 1867c9e830SRaag Jadav #include <linux/pm.h> 19c4168db7SAndy Shevchenko #include <linux/seq_file.h> 20eb83479eSAndy Shevchenko #include <linux/slab.h> 21eb83479eSAndy Shevchenko #include <linux/types.h> 22eb83479eSAndy Shevchenko 23c4168db7SAndy Shevchenko #include <linux/pinctrl/consumer.h> 24c4168db7SAndy Shevchenko #include <linux/pinctrl/pinconf-generic.h> 25c4168db7SAndy Shevchenko #include <linux/pinctrl/pinconf.h> 26cecddda7SAndy Shevchenko #include <linux/pinctrl/pinctrl.h> 27cecddda7SAndy Shevchenko #include <linux/pinctrl/pinmux.h> 28cecddda7SAndy Shevchenko 29cecddda7SAndy Shevchenko #include "pinctrl-intel.h" 30cecddda7SAndy Shevchenko 31cecddda7SAndy Shevchenko #define COMMUNITY(p, n) \ 32cecddda7SAndy Shevchenko { \ 33cecddda7SAndy Shevchenko .pin_base = (p), \ 34cecddda7SAndy Shevchenko .npins = (n), \ 35cecddda7SAndy Shevchenko } 36cecddda7SAndy Shevchenko 37cecddda7SAndy Shevchenko static const struct pinctrl_pin_desc lptlp_pins[] = { 38cecddda7SAndy Shevchenko PINCTRL_PIN(0, "GP0_UART1_RXD"), 39cecddda7SAndy Shevchenko PINCTRL_PIN(1, "GP1_UART1_TXD"), 40cecddda7SAndy Shevchenko PINCTRL_PIN(2, "GP2_UART1_RTSB"), 41cecddda7SAndy Shevchenko PINCTRL_PIN(3, "GP3_UART1_CTSB"), 42cecddda7SAndy Shevchenko PINCTRL_PIN(4, "GP4_I2C0_SDA"), 43cecddda7SAndy Shevchenko PINCTRL_PIN(5, "GP5_I2C0_SCL"), 44cecddda7SAndy Shevchenko PINCTRL_PIN(6, "GP6_I2C1_SDA"), 45cecddda7SAndy Shevchenko PINCTRL_PIN(7, "GP7_I2C1_SCL"), 46cecddda7SAndy Shevchenko PINCTRL_PIN(8, "GP8"), 47cecddda7SAndy Shevchenko PINCTRL_PIN(9, "GP9"), 48cecddda7SAndy Shevchenko PINCTRL_PIN(10, "GP10"), 49cecddda7SAndy Shevchenko PINCTRL_PIN(11, "GP11_SMBALERTB"), 50cecddda7SAndy Shevchenko PINCTRL_PIN(12, "GP12_LANPHYPC"), 51cecddda7SAndy Shevchenko PINCTRL_PIN(13, "GP13"), 52cecddda7SAndy Shevchenko PINCTRL_PIN(14, "GP14"), 53cecddda7SAndy Shevchenko PINCTRL_PIN(15, "GP15"), 54cecddda7SAndy Shevchenko PINCTRL_PIN(16, "GP16_MGPIO9"), 55cecddda7SAndy Shevchenko PINCTRL_PIN(17, "GP17_MGPIO10"), 56cecddda7SAndy Shevchenko PINCTRL_PIN(18, "GP18_SRC0CLKRQB"), 57cecddda7SAndy Shevchenko PINCTRL_PIN(19, "GP19_SRC1CLKRQB"), 58cecddda7SAndy Shevchenko PINCTRL_PIN(20, "GP20_SRC2CLKRQB"), 59cecddda7SAndy Shevchenko PINCTRL_PIN(21, "GP21_SRC3CLKRQB"), 60cecddda7SAndy Shevchenko PINCTRL_PIN(22, "GP22_SRC4CLKRQB_TRST2"), 61cecddda7SAndy Shevchenko PINCTRL_PIN(23, "GP23_SRC5CLKRQB_TDI2"), 62cecddda7SAndy Shevchenko PINCTRL_PIN(24, "GP24_MGPIO0"), 63cecddda7SAndy Shevchenko PINCTRL_PIN(25, "GP25_USBWAKEOUTB"), 64cecddda7SAndy Shevchenko PINCTRL_PIN(26, "GP26_MGPIO5"), 65cecddda7SAndy Shevchenko PINCTRL_PIN(27, "GP27_MGPIO6"), 66cecddda7SAndy Shevchenko PINCTRL_PIN(28, "GP28_MGPIO7"), 67cecddda7SAndy Shevchenko PINCTRL_PIN(29, "GP29_SLP_WLANB_MGPIO3"), 68cecddda7SAndy Shevchenko PINCTRL_PIN(30, "GP30_SUSWARNB_SUSPWRDNACK_MGPIO1"), 69cecddda7SAndy Shevchenko PINCTRL_PIN(31, "GP31_ACPRESENT_MGPIO2"), 70cecddda7SAndy Shevchenko PINCTRL_PIN(32, "GP32_CLKRUNB"), 71cecddda7SAndy Shevchenko PINCTRL_PIN(33, "GP33_DEVSLP0"), 72cecddda7SAndy Shevchenko PINCTRL_PIN(34, "GP34_SATA0XPCIE6L3B_SATA0GP"), 73cecddda7SAndy Shevchenko PINCTRL_PIN(35, "GP35_SATA1XPCIE6L2B_SATA1GP"), 74cecddda7SAndy Shevchenko PINCTRL_PIN(36, "GP36_SATA2XPCIE6L1B_SATA2GP"), 75cecddda7SAndy Shevchenko PINCTRL_PIN(37, "GP37_SATA3XPCIE6L0B_SATA3GP"), 76cecddda7SAndy Shevchenko PINCTRL_PIN(38, "GP38_DEVSLP1"), 77cecddda7SAndy Shevchenko PINCTRL_PIN(39, "GP39_DEVSLP2"), 78cecddda7SAndy Shevchenko PINCTRL_PIN(40, "GP40_OC0B"), 79cecddda7SAndy Shevchenko PINCTRL_PIN(41, "GP41_OC1B"), 80cecddda7SAndy Shevchenko PINCTRL_PIN(42, "GP42_OC2B"), 81cecddda7SAndy Shevchenko PINCTRL_PIN(43, "GP43_OC3B"), 82cecddda7SAndy Shevchenko PINCTRL_PIN(44, "GP44"), 83cecddda7SAndy Shevchenko PINCTRL_PIN(45, "GP45_TMS2"), 84cecddda7SAndy Shevchenko PINCTRL_PIN(46, "GP46_TDO2"), 85cecddda7SAndy Shevchenko PINCTRL_PIN(47, "GP47"), 86cecddda7SAndy Shevchenko PINCTRL_PIN(48, "GP48"), 87cecddda7SAndy Shevchenko PINCTRL_PIN(49, "GP49"), 88cecddda7SAndy Shevchenko PINCTRL_PIN(50, "GP50"), 89cecddda7SAndy Shevchenko PINCTRL_PIN(51, "GP51_GSXDOUT"), 90cecddda7SAndy Shevchenko PINCTRL_PIN(52, "GP52_GSXSLOAD"), 91cecddda7SAndy Shevchenko PINCTRL_PIN(53, "GP53_GSXDIN"), 92cecddda7SAndy Shevchenko PINCTRL_PIN(54, "GP54_GSXSRESETB"), 93cecddda7SAndy Shevchenko PINCTRL_PIN(55, "GP55_GSXCLK"), 94cecddda7SAndy Shevchenko PINCTRL_PIN(56, "GP56"), 95cecddda7SAndy Shevchenko PINCTRL_PIN(57, "GP57"), 96cecddda7SAndy Shevchenko PINCTRL_PIN(58, "GP58"), 97cecddda7SAndy Shevchenko PINCTRL_PIN(59, "GP59"), 98cecddda7SAndy Shevchenko PINCTRL_PIN(60, "GP60_SML0ALERTB_MGPIO4"), 99cecddda7SAndy Shevchenko PINCTRL_PIN(61, "GP61_SUS_STATB"), 100cecddda7SAndy Shevchenko PINCTRL_PIN(62, "GP62_SUSCLK"), 101cecddda7SAndy Shevchenko PINCTRL_PIN(63, "GP63_SLP_S5B"), 102cecddda7SAndy Shevchenko PINCTRL_PIN(64, "GP64_SDIO_CLK"), 103cecddda7SAndy Shevchenko PINCTRL_PIN(65, "GP65_SDIO_CMD"), 104cecddda7SAndy Shevchenko PINCTRL_PIN(66, "GP66_SDIO_D0"), 105cecddda7SAndy Shevchenko PINCTRL_PIN(67, "GP67_SDIO_D1"), 106cecddda7SAndy Shevchenko PINCTRL_PIN(68, "GP68_SDIO_D2"), 107cecddda7SAndy Shevchenko PINCTRL_PIN(69, "GP69_SDIO_D3"), 108cecddda7SAndy Shevchenko PINCTRL_PIN(70, "GP70_SDIO_POWER_EN"), 109cecddda7SAndy Shevchenko PINCTRL_PIN(71, "GP71_MPHYPC"), 110cecddda7SAndy Shevchenko PINCTRL_PIN(72, "GP72_BATLOWB"), 111cecddda7SAndy Shevchenko PINCTRL_PIN(73, "GP73_SML1ALERTB_PCHHOTB_MGPIO8"), 112cecddda7SAndy Shevchenko PINCTRL_PIN(74, "GP74_SML1DATA_MGPIO12"), 113cecddda7SAndy Shevchenko PINCTRL_PIN(75, "GP75_SML1CLK_MGPIO11"), 114cecddda7SAndy Shevchenko PINCTRL_PIN(76, "GP76_BMBUSYB"), 115cecddda7SAndy Shevchenko PINCTRL_PIN(77, "GP77_PIRQAB"), 116cecddda7SAndy Shevchenko PINCTRL_PIN(78, "GP78_PIRQBB"), 117cecddda7SAndy Shevchenko PINCTRL_PIN(79, "GP79_PIRQCB"), 118cecddda7SAndy Shevchenko PINCTRL_PIN(80, "GP80_PIRQDB"), 119cecddda7SAndy Shevchenko PINCTRL_PIN(81, "GP81_SPKR"), 120cecddda7SAndy Shevchenko PINCTRL_PIN(82, "GP82_RCINB"), 121cecddda7SAndy Shevchenko PINCTRL_PIN(83, "GP83_GSPI0_CSB"), 122cecddda7SAndy Shevchenko PINCTRL_PIN(84, "GP84_GSPI0_CLK"), 123cecddda7SAndy Shevchenko PINCTRL_PIN(85, "GP85_GSPI0_MISO"), 124cecddda7SAndy Shevchenko PINCTRL_PIN(86, "GP86_GSPI0_MOSI"), 125cecddda7SAndy Shevchenko PINCTRL_PIN(87, "GP87_GSPI1_CSB"), 126cecddda7SAndy Shevchenko PINCTRL_PIN(88, "GP88_GSPI1_CLK"), 127cecddda7SAndy Shevchenko PINCTRL_PIN(89, "GP89_GSPI1_MISO"), 128cecddda7SAndy Shevchenko PINCTRL_PIN(90, "GP90_GSPI1_MOSI"), 129cecddda7SAndy Shevchenko PINCTRL_PIN(91, "GP91_UART0_RXD"), 130cecddda7SAndy Shevchenko PINCTRL_PIN(92, "GP92_UART0_TXD"), 131cecddda7SAndy Shevchenko PINCTRL_PIN(93, "GP93_UART0_RTSB"), 132cecddda7SAndy Shevchenko PINCTRL_PIN(94, "GP94_UART0_CTSB"), 133cecddda7SAndy Shevchenko }; 134cecddda7SAndy Shevchenko 135cecddda7SAndy Shevchenko static const struct intel_community lptlp_communities[] = { 136cecddda7SAndy Shevchenko COMMUNITY(0, 95), 137cecddda7SAndy Shevchenko }; 138cecddda7SAndy Shevchenko 139cecddda7SAndy Shevchenko static const struct intel_pinctrl_soc_data lptlp_soc_data = { 140cecddda7SAndy Shevchenko .pins = lptlp_pins, 141cecddda7SAndy Shevchenko .npins = ARRAY_SIZE(lptlp_pins), 142cecddda7SAndy Shevchenko .communities = lptlp_communities, 143cecddda7SAndy Shevchenko .ncommunities = ARRAY_SIZE(lptlp_communities), 144cecddda7SAndy Shevchenko }; 145cecddda7SAndy Shevchenko 1467c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */ 147eb83479eSAndy Shevchenko 1487c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO 95 149eb83479eSAndy Shevchenko 150eb83479eSAndy Shevchenko /* Bitmapped register offsets */ 151eb83479eSAndy Shevchenko #define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ 1527f32d370SAndy Shevchenko #define LP_IRQ2IOXAPIC 0x10 /* Bitmap, set by bios, 1: pin routed to IOxAPIC */ 153eb83479eSAndy Shevchenko #define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ 154eb83479eSAndy Shevchenko #define LP_INT_STAT 0x80 155eb83479eSAndy Shevchenko #define LP_INT_ENABLE 0x90 156eb83479eSAndy Shevchenko 157eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */ 158eb83479eSAndy Shevchenko #define LP_CONFIG1 0x100 159eb83479eSAndy Shevchenko #define LP_CONFIG2 0x104 160eb83479eSAndy Shevchenko 161eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */ 162eb83479eSAndy Shevchenko #define OUT_LVL_BIT BIT(31) 163eb83479eSAndy Shevchenko #define IN_LVL_BIT BIT(30) 164eb83479eSAndy Shevchenko #define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ 165eb83479eSAndy Shevchenko #define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ 166eb83479eSAndy Shevchenko #define DIR_BIT BIT(2) /* 0: Output, 1: Input */ 16776347d7aSAndy Shevchenko #define USE_SEL_MASK GENMASK(1, 0) /* 0: Native, 1: GPIO, ... */ 16876347d7aSAndy Shevchenko #define USE_SEL_NATIVE (0 << 0) 16976347d7aSAndy Shevchenko #define USE_SEL_GPIO (1 << 0) 170eb83479eSAndy Shevchenko 171eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */ 172eb83479eSAndy Shevchenko #define GPINDIS_BIT BIT(2) /* disable input sensing */ 1737f32d370SAndy Shevchenko #define GPIWP_MASK GENMASK(1, 0) /* weak pull options */ 1747f32d370SAndy Shevchenko #define GPIWP_NONE 0 /* none */ 1757f32d370SAndy Shevchenko #define GPIWP_DOWN 1 /* weak pull down */ 1767f32d370SAndy Shevchenko #define GPIWP_UP 2 /* weak pull up */ 177eb83479eSAndy Shevchenko 178eb83479eSAndy Shevchenko /* 179eb83479eSAndy Shevchenko * Lynxpoint gpios are controlled through both bitmapped registers and 180eb83479eSAndy Shevchenko * per gpio specific registers. The bitmapped registers are in chunks of 1817c0bc7bbSAndy Shevchenko * 3 x 32bit registers to cover all 95 GPIOs 182eb83479eSAndy Shevchenko * 183eb83479eSAndy Shevchenko * per gpio specific registers consist of two 32bit registers per gpio 1847c0bc7bbSAndy Shevchenko * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 1857c0bc7bbSAndy Shevchenko * 190 config registers. 186eb83479eSAndy Shevchenko * 187eb83479eSAndy Shevchenko * A simplified view of the register layout look like this: 188eb83479eSAndy Shevchenko * 189eb83479eSAndy Shevchenko * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 190eb83479eSAndy Shevchenko * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 191eb83479eSAndy Shevchenko * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 192eb83479eSAndy Shevchenko * ... 193eb83479eSAndy Shevchenko * LP_INT_ENABLE[31:0] ... 1947c0bc7bbSAndy Shevchenko * LP_INT_ENABLE[63:32] ... 195eb83479eSAndy Shevchenko * LP_INT_ENABLE[94:64] ... 196eb83479eSAndy Shevchenko * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 197eb83479eSAndy Shevchenko * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 198eb83479eSAndy Shevchenko * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 199eb83479eSAndy Shevchenko * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 200eb83479eSAndy Shevchenko * LP2_CONFIG1 (gpio 2) ... 201eb83479eSAndy Shevchenko * LP2_CONFIG2 (gpio 2) ... 202eb83479eSAndy Shevchenko * ... 203eb83479eSAndy Shevchenko * LP94_CONFIG1 (gpio 94) ... 204eb83479eSAndy Shevchenko * LP94_CONFIG2 (gpio 94) ... 2057f32d370SAndy Shevchenko * 2067f32d370SAndy Shevchenko * IOxAPIC redirection map applies only for gpio 8-10, 13-14, 45-55. 207eb83479eSAndy Shevchenko */ 208eb83479eSAndy Shevchenko 209c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset, 210eb83479eSAndy Shevchenko int reg) 211eb83479eSAndy Shevchenko { 21218213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 21318213ad4SAndy Shevchenko struct intel_community *comm; 214eb83479eSAndy Shevchenko int reg_offset; 215eb83479eSAndy Shevchenko 216976cf4a6SRaag Jadav comm = intel_get_community(lg, offset); 21718213ad4SAndy Shevchenko if (!comm) 21818213ad4SAndy Shevchenko return NULL; 21918213ad4SAndy Shevchenko 22018213ad4SAndy Shevchenko offset -= comm->pin_base; 22118213ad4SAndy Shevchenko 222eb83479eSAndy Shevchenko if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 223eb83479eSAndy Shevchenko /* per gpio specific config registers */ 224eb83479eSAndy Shevchenko reg_offset = offset * 8; 225eb83479eSAndy Shevchenko else 226eb83479eSAndy Shevchenko /* bitmapped registers */ 227eb83479eSAndy Shevchenko reg_offset = (offset / 32) * 4; 228eb83479eSAndy Shevchenko 22918213ad4SAndy Shevchenko return comm->regs + reg_offset + reg; 230eb83479eSAndy Shevchenko } 231eb83479eSAndy Shevchenko 23218213ad4SAndy Shevchenko static bool lp_gpio_acpi_use(struct intel_pinctrl *lg, unsigned int pin) 23321a06495SAndy Shevchenko { 23421a06495SAndy Shevchenko void __iomem *acpi_use; 23521a06495SAndy Shevchenko 23621a06495SAndy Shevchenko acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED); 23721a06495SAndy Shevchenko if (!acpi_use) 23821a06495SAndy Shevchenko return true; 23921a06495SAndy Shevchenko 24021a06495SAndy Shevchenko return !(ioread32(acpi_use) & BIT(pin % 32)); 24121a06495SAndy Shevchenko } 24221a06495SAndy Shevchenko 2437f32d370SAndy Shevchenko static bool lp_gpio_ioxapic_use(struct gpio_chip *chip, unsigned int offset) 2447f32d370SAndy Shevchenko { 2457f32d370SAndy Shevchenko void __iomem *ioxapic_use = lp_gpio_reg(chip, offset, LP_IRQ2IOXAPIC); 2467f32d370SAndy Shevchenko u32 value; 2477f32d370SAndy Shevchenko 2487f32d370SAndy Shevchenko value = ioread32(ioxapic_use); 2497f32d370SAndy Shevchenko 2507f32d370SAndy Shevchenko if (offset >= 8 && offset <= 10) 2517f32d370SAndy Shevchenko return !!(value & BIT(offset - 8 + 0)); 2527f32d370SAndy Shevchenko if (offset >= 13 && offset <= 14) 2537f32d370SAndy Shevchenko return !!(value & BIT(offset - 13 + 3)); 2547f32d370SAndy Shevchenko if (offset >= 45 && offset <= 55) 2557f32d370SAndy Shevchenko return !!(value & BIT(offset - 45 + 5)); 2567f32d370SAndy Shevchenko 2577f32d370SAndy Shevchenko return false; 2587f32d370SAndy Shevchenko } 2597f32d370SAndy Shevchenko 26003d9eca7SAndy Shevchenko static void lp_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 26103d9eca7SAndy Shevchenko unsigned int pin) 26203d9eca7SAndy Shevchenko { 26303d9eca7SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 26403d9eca7SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 26503d9eca7SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 26603d9eca7SAndy Shevchenko u32 value, mode; 26703d9eca7SAndy Shevchenko 26803d9eca7SAndy Shevchenko value = ioread32(reg); 26903d9eca7SAndy Shevchenko 27003d9eca7SAndy Shevchenko mode = value & USE_SEL_MASK; 27103d9eca7SAndy Shevchenko if (mode == USE_SEL_GPIO) 27203d9eca7SAndy Shevchenko seq_puts(s, "GPIO "); 27303d9eca7SAndy Shevchenko else 27403d9eca7SAndy Shevchenko seq_printf(s, "mode %d ", mode); 27503d9eca7SAndy Shevchenko 27603d9eca7SAndy Shevchenko seq_printf(s, "0x%08x 0x%08x", value, ioread32(conf2)); 27703d9eca7SAndy Shevchenko 27803d9eca7SAndy Shevchenko if (lp_gpio_acpi_use(lg, pin)) 27903d9eca7SAndy Shevchenko seq_puts(s, " [ACPI]"); 28003d9eca7SAndy Shevchenko } 28103d9eca7SAndy Shevchenko 2827f32d370SAndy Shevchenko static const struct pinctrl_ops lptlp_pinctrl_ops = { 283976cf4a6SRaag Jadav .get_groups_count = intel_get_groups_count, 284976cf4a6SRaag Jadav .get_group_name = intel_get_group_name, 285976cf4a6SRaag Jadav .get_group_pins = intel_get_group_pins, 28603d9eca7SAndy Shevchenko .pin_dbg_show = lp_pin_dbg_show, 2877f32d370SAndy Shevchenko }; 2887f32d370SAndy Shevchenko 2897f32d370SAndy Shevchenko static int lp_pinmux_set_mux(struct pinctrl_dev *pctldev, 2907f32d370SAndy Shevchenko unsigned int function, unsigned int group) 2917f32d370SAndy Shevchenko { 2927f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 2937f32d370SAndy Shevchenko const struct intel_pingroup *grp = &lg->soc->groups[group]; 2947f32d370SAndy Shevchenko unsigned long flags; 2957f32d370SAndy Shevchenko int i; 2967f32d370SAndy Shevchenko 2977f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 2987f32d370SAndy Shevchenko 2997f32d370SAndy Shevchenko /* Now enable the mux setting for each pin in the group */ 300a7f9757cSAndy Shevchenko for (i = 0; i < grp->grp.npins; i++) { 301a7f9757cSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, grp->grp.pins[i], LP_CONFIG1); 3027f32d370SAndy Shevchenko u32 value; 3037f32d370SAndy Shevchenko 3047f32d370SAndy Shevchenko value = ioread32(reg); 3057f32d370SAndy Shevchenko 3067f32d370SAndy Shevchenko value &= ~USE_SEL_MASK; 3077f32d370SAndy Shevchenko if (grp->modes) 3087f32d370SAndy Shevchenko value |= grp->modes[i]; 3097f32d370SAndy Shevchenko else 3107f32d370SAndy Shevchenko value |= grp->mode; 3117f32d370SAndy Shevchenko 3127f32d370SAndy Shevchenko iowrite32(value, reg); 3137f32d370SAndy Shevchenko } 3147f32d370SAndy Shevchenko 3157f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 3167f32d370SAndy Shevchenko 3177f32d370SAndy Shevchenko return 0; 3187f32d370SAndy Shevchenko } 3197f32d370SAndy Shevchenko 3200472567bSAndy Shevchenko static void lp_gpio_enable_input(void __iomem *reg) 3210472567bSAndy Shevchenko { 3220472567bSAndy Shevchenko iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg); 3230472567bSAndy Shevchenko } 3240472567bSAndy Shevchenko 3250472567bSAndy Shevchenko static void lp_gpio_disable_input(void __iomem *reg) 3260472567bSAndy Shevchenko { 3270472567bSAndy Shevchenko iowrite32(ioread32(reg) | GPINDIS_BIT, reg); 3280472567bSAndy Shevchenko } 3290472567bSAndy Shevchenko 3307f32d370SAndy Shevchenko static int lp_gpio_request_enable(struct pinctrl_dev *pctldev, 3317f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3327f32d370SAndy Shevchenko unsigned int pin) 3337f32d370SAndy Shevchenko { 3347f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3357f32d370SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 3367f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 3377f32d370SAndy Shevchenko unsigned long flags; 3387f32d370SAndy Shevchenko u32 value; 3397f32d370SAndy Shevchenko 3407f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 3417f32d370SAndy Shevchenko 3427f32d370SAndy Shevchenko /* 3437f32d370SAndy Shevchenko * Reconfigure pin to GPIO mode if needed and issue a warning, 3447f32d370SAndy Shevchenko * since we expect firmware to configure it properly. 3457f32d370SAndy Shevchenko */ 3467f32d370SAndy Shevchenko value = ioread32(reg); 3477f32d370SAndy Shevchenko if ((value & USE_SEL_MASK) != USE_SEL_GPIO) { 3487f32d370SAndy Shevchenko iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg); 3497f32d370SAndy Shevchenko dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", pin); 3507f32d370SAndy Shevchenko } 3517f32d370SAndy Shevchenko 3527f32d370SAndy Shevchenko /* Enable input sensing */ 3530472567bSAndy Shevchenko lp_gpio_enable_input(conf2); 3547f32d370SAndy Shevchenko 3557f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 3567f32d370SAndy Shevchenko 3577f32d370SAndy Shevchenko return 0; 3587f32d370SAndy Shevchenko } 3597f32d370SAndy Shevchenko 3607f32d370SAndy Shevchenko static void lp_gpio_disable_free(struct pinctrl_dev *pctldev, 3617f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3627f32d370SAndy Shevchenko unsigned int pin) 3637f32d370SAndy Shevchenko { 3647f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3657f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 3667f32d370SAndy Shevchenko unsigned long flags; 3677f32d370SAndy Shevchenko 3687f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 3697f32d370SAndy Shevchenko 3707f32d370SAndy Shevchenko /* Disable input sensing */ 3710472567bSAndy Shevchenko lp_gpio_disable_input(conf2); 3727f32d370SAndy Shevchenko 3737f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 3747f32d370SAndy Shevchenko } 3757f32d370SAndy Shevchenko 3767f32d370SAndy Shevchenko static int lp_gpio_set_direction(struct pinctrl_dev *pctldev, 3777f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3787f32d370SAndy Shevchenko unsigned int pin, bool input) 3797f32d370SAndy Shevchenko { 3807f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3817f32d370SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 3827f32d370SAndy Shevchenko unsigned long flags; 3837f32d370SAndy Shevchenko u32 value; 3847f32d370SAndy Shevchenko 3857f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 3867f32d370SAndy Shevchenko 3877f32d370SAndy Shevchenko value = ioread32(reg); 3887f32d370SAndy Shevchenko value &= ~DIR_BIT; 3897f32d370SAndy Shevchenko if (input) { 3907f32d370SAndy Shevchenko value |= DIR_BIT; 3917f32d370SAndy Shevchenko } else { 3927f32d370SAndy Shevchenko /* 3937f32d370SAndy Shevchenko * Before making any direction modifications, do a check if GPIO 3947f32d370SAndy Shevchenko * is set for direct IRQ. On Lynxpoint, setting GPIO to output 3957f32d370SAndy Shevchenko * does not make sense, so let's at least warn the caller before 3967f32d370SAndy Shevchenko * they shoot themselves in the foot. 3977f32d370SAndy Shevchenko */ 3987f32d370SAndy Shevchenko WARN(lp_gpio_ioxapic_use(&lg->chip, pin), 3997f32d370SAndy Shevchenko "Potential Error: Setting GPIO to output with IOxAPIC redirection"); 4007f32d370SAndy Shevchenko } 4017f32d370SAndy Shevchenko iowrite32(value, reg); 4027f32d370SAndy Shevchenko 4037f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 4047f32d370SAndy Shevchenko 4057f32d370SAndy Shevchenko return 0; 4067f32d370SAndy Shevchenko } 4077f32d370SAndy Shevchenko 4087f32d370SAndy Shevchenko static const struct pinmux_ops lptlp_pinmux_ops = { 409976cf4a6SRaag Jadav .get_functions_count = intel_get_functions_count, 410976cf4a6SRaag Jadav .get_function_name = intel_get_function_name, 411976cf4a6SRaag Jadav .get_function_groups = intel_get_function_groups, 4127f32d370SAndy Shevchenko .set_mux = lp_pinmux_set_mux, 4137f32d370SAndy Shevchenko .gpio_request_enable = lp_gpio_request_enable, 4147f32d370SAndy Shevchenko .gpio_disable_free = lp_gpio_disable_free, 4157f32d370SAndy Shevchenko .gpio_set_direction = lp_gpio_set_direction, 4167f32d370SAndy Shevchenko }; 4177f32d370SAndy Shevchenko 4187f32d370SAndy Shevchenko static int lp_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 4197f32d370SAndy Shevchenko unsigned long *config) 4207f32d370SAndy Shevchenko { 4217f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 4227f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 4237f32d370SAndy Shevchenko enum pin_config_param param = pinconf_to_config_param(*config); 4247f32d370SAndy Shevchenko unsigned long flags; 4257f32d370SAndy Shevchenko u32 value, pull; 426d25dd66aSAndy Shevchenko u16 arg; 4277f32d370SAndy Shevchenko 4287f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 4297f32d370SAndy Shevchenko value = ioread32(conf2); 4307f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 4317f32d370SAndy Shevchenko 4327f32d370SAndy Shevchenko pull = value & GPIWP_MASK; 4337f32d370SAndy Shevchenko 4347f32d370SAndy Shevchenko switch (param) { 4357f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_DISABLE: 436d25dd66aSAndy Shevchenko if (pull != GPIWP_NONE) 4377f32d370SAndy Shevchenko return -EINVAL; 438d25dd66aSAndy Shevchenko arg = 0; 4397f32d370SAndy Shevchenko break; 4407f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_DOWN: 4417f32d370SAndy Shevchenko if (pull != GPIWP_DOWN) 4427f32d370SAndy Shevchenko return -EINVAL; 4437f32d370SAndy Shevchenko 4447f32d370SAndy Shevchenko arg = 1; 4457f32d370SAndy Shevchenko break; 4467f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_UP: 4477f32d370SAndy Shevchenko if (pull != GPIWP_UP) 4487f32d370SAndy Shevchenko return -EINVAL; 4497f32d370SAndy Shevchenko 4507f32d370SAndy Shevchenko arg = 1; 4517f32d370SAndy Shevchenko break; 4527f32d370SAndy Shevchenko default: 4537f32d370SAndy Shevchenko return -ENOTSUPP; 4547f32d370SAndy Shevchenko } 4557f32d370SAndy Shevchenko 4567f32d370SAndy Shevchenko *config = pinconf_to_config_packed(param, arg); 4577f32d370SAndy Shevchenko 4587f32d370SAndy Shevchenko return 0; 4597f32d370SAndy Shevchenko } 4607f32d370SAndy Shevchenko 4617f32d370SAndy Shevchenko static int lp_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 4627f32d370SAndy Shevchenko unsigned long *configs, unsigned int num_configs) 4637f32d370SAndy Shevchenko { 4647f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 4657f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 4667f32d370SAndy Shevchenko enum pin_config_param param; 4677f32d370SAndy Shevchenko unsigned long flags; 4687f32d370SAndy Shevchenko int i, ret = 0; 4697f32d370SAndy Shevchenko u32 value; 4707f32d370SAndy Shevchenko 4717f32d370SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 4727f32d370SAndy Shevchenko 4737f32d370SAndy Shevchenko value = ioread32(conf2); 4747f32d370SAndy Shevchenko 4757f32d370SAndy Shevchenko for (i = 0; i < num_configs; i++) { 4767f32d370SAndy Shevchenko param = pinconf_to_config_param(configs[i]); 4777f32d370SAndy Shevchenko 4787f32d370SAndy Shevchenko switch (param) { 4797f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_DISABLE: 4807f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 481d25dd66aSAndy Shevchenko value |= GPIWP_NONE; 4827f32d370SAndy Shevchenko break; 4837f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_DOWN: 4847f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 4857f32d370SAndy Shevchenko value |= GPIWP_DOWN; 4867f32d370SAndy Shevchenko break; 4877f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_UP: 4887f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 4897f32d370SAndy Shevchenko value |= GPIWP_UP; 4907f32d370SAndy Shevchenko break; 4917f32d370SAndy Shevchenko default: 4927f32d370SAndy Shevchenko ret = -ENOTSUPP; 4937f32d370SAndy Shevchenko } 4947f32d370SAndy Shevchenko 4957f32d370SAndy Shevchenko if (ret) 4967f32d370SAndy Shevchenko break; 4977f32d370SAndy Shevchenko } 4987f32d370SAndy Shevchenko 4997f32d370SAndy Shevchenko if (!ret) 5007f32d370SAndy Shevchenko iowrite32(value, conf2); 5017f32d370SAndy Shevchenko 5027f32d370SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 5037f32d370SAndy Shevchenko 5047f32d370SAndy Shevchenko return ret; 5057f32d370SAndy Shevchenko } 5067f32d370SAndy Shevchenko 5077f32d370SAndy Shevchenko static const struct pinconf_ops lptlp_pinconf_ops = { 5087f32d370SAndy Shevchenko .is_generic = true, 5097f32d370SAndy Shevchenko .pin_config_get = lp_pin_config_get, 5107f32d370SAndy Shevchenko .pin_config_set = lp_pin_config_set, 5117f32d370SAndy Shevchenko }; 5127f32d370SAndy Shevchenko 5137f32d370SAndy Shevchenko static const struct pinctrl_desc lptlp_pinctrl_desc = { 5147f32d370SAndy Shevchenko .pctlops = &lptlp_pinctrl_ops, 5157f32d370SAndy Shevchenko .pmxops = &lptlp_pinmux_ops, 5167f32d370SAndy Shevchenko .confops = &lptlp_pinconf_ops, 5177f32d370SAndy Shevchenko .owner = THIS_MODULE, 5187f32d370SAndy Shevchenko }; 5197f32d370SAndy Shevchenko 520c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset) 521eb83479eSAndy Shevchenko { 522e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 523e1940adeSAndy Shevchenko return !!(ioread32(reg) & IN_LVL_BIT); 524eb83479eSAndy Shevchenko } 525eb83479eSAndy Shevchenko 526c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 527eb83479eSAndy Shevchenko { 52818213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 529e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 530eb83479eSAndy Shevchenko unsigned long flags; 531eb83479eSAndy Shevchenko 532b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 533eb83479eSAndy Shevchenko 534eb83479eSAndy Shevchenko if (value) 535e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | OUT_LVL_BIT, reg); 536eb83479eSAndy Shevchenko else 537e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg); 538eb83479eSAndy Shevchenko 539b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 540eb83479eSAndy Shevchenko } 541eb83479eSAndy Shevchenko 542c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 543eb83479eSAndy Shevchenko { 544*315c46f9SBartosz Golaszewski return pinctrl_gpio_direction_input(chip, offset); 545eb83479eSAndy Shevchenko } 546eb83479eSAndy Shevchenko 547c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 548c35f463aSAndy Shevchenko int value) 549eb83479eSAndy Shevchenko { 550eb83479eSAndy Shevchenko lp_gpio_set(chip, offset, value); 551eb83479eSAndy Shevchenko 552578d009bSBartosz Golaszewski return pinctrl_gpio_direction_output_new(chip, offset); 553eb83479eSAndy Shevchenko } 554eb83479eSAndy Shevchenko 55554d371cfSAndy Shevchenko static int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 55654d371cfSAndy Shevchenko { 55754d371cfSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 55854d371cfSAndy Shevchenko 55954d371cfSAndy Shevchenko if (ioread32(reg) & DIR_BIT) 56054d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_IN; 56154d371cfSAndy Shevchenko 56254d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_OUT; 56354d371cfSAndy Shevchenko } 56454d371cfSAndy Shevchenko 565eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc) 566eb83479eSAndy Shevchenko { 567eb83479eSAndy Shevchenko struct irq_data *data = irq_desc_get_irq_data(desc); 568eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_desc_get_handler_data(desc); 56918213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 570eb83479eSAndy Shevchenko struct irq_chip *chip = irq_data_get_irq_chip(data); 571e1940adeSAndy Shevchenko void __iomem *reg, *ena; 572e1940adeSAndy Shevchenko unsigned long pending; 573eb83479eSAndy Shevchenko u32 base, pin; 574eb83479eSAndy Shevchenko 575eb83479eSAndy Shevchenko /* check from GPIO controller which pin triggered the interrupt */ 576eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 577eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 578eb83479eSAndy Shevchenko ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 579eb83479eSAndy Shevchenko 580eb83479eSAndy Shevchenko /* Only interrupts that are enabled */ 581e1940adeSAndy Shevchenko pending = ioread32(reg) & ioread32(ena); 582eb83479eSAndy Shevchenko 583a9cb09b7SMarc Zyngier for_each_set_bit(pin, &pending, 32) 584a9cb09b7SMarc Zyngier generic_handle_domain_irq(lg->chip.irq.domain, base + pin); 585eb83479eSAndy Shevchenko } 586eb83479eSAndy Shevchenko chip->irq_eoi(data); 587eb83479eSAndy Shevchenko } 588eb83479eSAndy Shevchenko 5895931e6edSAndy Shevchenko static void lp_irq_ack(struct irq_data *d) 5905931e6edSAndy Shevchenko { 5915931e6edSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 59218213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 593180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 5945931e6edSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT); 5955931e6edSAndy Shevchenko unsigned long flags; 5965931e6edSAndy Shevchenko 5975931e6edSAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 5985931e6edSAndy Shevchenko iowrite32(BIT(hwirq % 32), reg); 5995931e6edSAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 6005931e6edSAndy Shevchenko } 6015931e6edSAndy Shevchenko 602eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d) 603eb83479eSAndy Shevchenko { 604eb83479eSAndy Shevchenko } 605eb83479eSAndy Shevchenko 606eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d) 607eb83479eSAndy Shevchenko { 608eb83479eSAndy Shevchenko } 609eb83479eSAndy Shevchenko 610eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d) 611eb83479eSAndy Shevchenko { 612eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 61318213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 614180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 615e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 616eb83479eSAndy Shevchenko unsigned long flags; 617eb83479eSAndy Shevchenko 618180f9db7SAndy Shevchenko gpiochip_enable_irq(gc, hwirq); 619180f9db7SAndy Shevchenko 620b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 621e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | BIT(hwirq % 32), reg); 622b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 623eb83479eSAndy Shevchenko } 624eb83479eSAndy Shevchenko 625eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d) 626eb83479eSAndy Shevchenko { 627eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 62818213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 629180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 630e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 631eb83479eSAndy Shevchenko unsigned long flags; 632eb83479eSAndy Shevchenko 633b2e05d63SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 634e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg); 635b2e05d63SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 636180f9db7SAndy Shevchenko 637180f9db7SAndy Shevchenko gpiochip_disable_irq(gc, hwirq); 638eb83479eSAndy Shevchenko } 639eb83479eSAndy Shevchenko 640095f2a67SAndy Shevchenko static int lp_irq_set_type(struct irq_data *d, unsigned int type) 641095f2a67SAndy Shevchenko { 642095f2a67SAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 64318213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 644180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 645095f2a67SAndy Shevchenko unsigned long flags; 646180f9db7SAndy Shevchenko void __iomem *reg; 647095f2a67SAndy Shevchenko u32 value; 648095f2a67SAndy Shevchenko 649180f9db7SAndy Shevchenko reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 650180f9db7SAndy Shevchenko if (!reg) 651095f2a67SAndy Shevchenko return -EINVAL; 652095f2a67SAndy Shevchenko 653540bff18SAndy Shevchenko /* Fail if BIOS reserved pin for ACPI use */ 654540bff18SAndy Shevchenko if (lp_gpio_acpi_use(lg, hwirq)) { 655180f9db7SAndy Shevchenko dev_err(lg->dev, "pin %lu can't be used as IRQ\n", hwirq); 656540bff18SAndy Shevchenko return -EBUSY; 657540bff18SAndy Shevchenko } 658540bff18SAndy Shevchenko 659095f2a67SAndy Shevchenko raw_spin_lock_irqsave(&lg->lock, flags); 660095f2a67SAndy Shevchenko value = ioread32(reg); 661095f2a67SAndy Shevchenko 662095f2a67SAndy Shevchenko /* set both TRIG_SEL and INV bits to 0 for rising edge */ 663095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_RISING) 664095f2a67SAndy Shevchenko value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 665095f2a67SAndy Shevchenko 666095f2a67SAndy Shevchenko /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 667095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_FALLING) 668095f2a67SAndy Shevchenko value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 669095f2a67SAndy Shevchenko 670095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 0 for level low */ 671095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_LOW) 672095f2a67SAndy Shevchenko value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 673095f2a67SAndy Shevchenko 674095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 1 for level high */ 675095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_HIGH) 676095f2a67SAndy Shevchenko value |= TRIG_SEL_BIT | INT_INV_BIT; 677095f2a67SAndy Shevchenko 678095f2a67SAndy Shevchenko iowrite32(value, reg); 679095f2a67SAndy Shevchenko 680095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_BOTH) 681095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_edge_irq); 682095f2a67SAndy Shevchenko else if (type & IRQ_TYPE_LEVEL_MASK) 683095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_level_irq); 684095f2a67SAndy Shevchenko 685095f2a67SAndy Shevchenko raw_spin_unlock_irqrestore(&lg->lock, flags); 686095f2a67SAndy Shevchenko 687095f2a67SAndy Shevchenko return 0; 688095f2a67SAndy Shevchenko } 689095f2a67SAndy Shevchenko 690180f9db7SAndy Shevchenko static const struct irq_chip lp_irqchip = { 691eb83479eSAndy Shevchenko .name = "LP-GPIO", 6925931e6edSAndy Shevchenko .irq_ack = lp_irq_ack, 693eb83479eSAndy Shevchenko .irq_mask = lp_irq_mask, 694eb83479eSAndy Shevchenko .irq_unmask = lp_irq_unmask, 695eb83479eSAndy Shevchenko .irq_enable = lp_irq_enable, 696eb83479eSAndy Shevchenko .irq_disable = lp_irq_disable, 697095f2a67SAndy Shevchenko .irq_set_type = lp_irq_set_type, 698180f9db7SAndy Shevchenko .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, 699180f9db7SAndy Shevchenko GPIOCHIP_IRQ_RESOURCE_HELPERS, 700eb83479eSAndy Shevchenko }; 701eb83479eSAndy Shevchenko 702eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip) 703eb83479eSAndy Shevchenko { 70418213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 705e1940adeSAndy Shevchenko void __iomem *reg; 706c35f463aSAndy Shevchenko unsigned int base; 707eb83479eSAndy Shevchenko 708eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 709eb83479eSAndy Shevchenko /* disable gpio pin interrupts */ 710eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 711e1940adeSAndy Shevchenko iowrite32(0, reg); 712eb83479eSAndy Shevchenko /* Clear interrupt status register */ 713eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 714e1940adeSAndy Shevchenko iowrite32(0xffffffff, reg); 715eb83479eSAndy Shevchenko } 716eb83479eSAndy Shevchenko 717eb83479eSAndy Shevchenko return 0; 718eb83479eSAndy Shevchenko } 719eb83479eSAndy Shevchenko 7203683509cSAndy Shevchenko static int lp_gpio_add_pin_ranges(struct gpio_chip *chip) 7213683509cSAndy Shevchenko { 7223683509cSAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 7233683509cSAndy Shevchenko struct device *dev = lg->dev; 7243683509cSAndy Shevchenko int ret; 7253683509cSAndy Shevchenko 7263683509cSAndy Shevchenko ret = gpiochip_add_pin_range(chip, dev_name(dev), 0, 0, lg->soc->npins); 7273683509cSAndy Shevchenko if (ret) 7283683509cSAndy Shevchenko dev_err(dev, "failed to add GPIO pin range\n"); 7293683509cSAndy Shevchenko 7303683509cSAndy Shevchenko return ret; 7313683509cSAndy Shevchenko } 7323683509cSAndy Shevchenko 733eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev) 734eb83479eSAndy Shevchenko { 73518213ad4SAndy Shevchenko const struct intel_pinctrl_soc_data *soc; 73618213ad4SAndy Shevchenko struct intel_pinctrl *lg; 737eb83479eSAndy Shevchenko struct gpio_chip *gc; 738eb83479eSAndy Shevchenko struct device *dev = &pdev->dev; 7395f3b82a1SAndy Shevchenko struct resource *io_rc; 740e1940adeSAndy Shevchenko void __iomem *regs; 74118213ad4SAndy Shevchenko unsigned int i; 7425f3b82a1SAndy Shevchenko int irq, ret; 743eb83479eSAndy Shevchenko 74418213ad4SAndy Shevchenko soc = (const struct intel_pinctrl_soc_data *)device_get_match_data(dev); 74518213ad4SAndy Shevchenko if (!soc) 74618213ad4SAndy Shevchenko return -ENODEV; 74718213ad4SAndy Shevchenko 748a718e68eSAndy Shevchenko lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 749eb83479eSAndy Shevchenko if (!lg) 750eb83479eSAndy Shevchenko return -ENOMEM; 751eb83479eSAndy Shevchenko 7521e78ea71SAndy Shevchenko lg->dev = dev; 75318213ad4SAndy Shevchenko lg->soc = soc; 75418213ad4SAndy Shevchenko 75518213ad4SAndy Shevchenko lg->ncommunities = lg->soc->ncommunities; 75618213ad4SAndy Shevchenko lg->communities = devm_kcalloc(dev, lg->ncommunities, 75718213ad4SAndy Shevchenko sizeof(*lg->communities), GFP_KERNEL); 75818213ad4SAndy Shevchenko if (!lg->communities) 75918213ad4SAndy Shevchenko return -ENOMEM; 76018213ad4SAndy Shevchenko 7617f32d370SAndy Shevchenko lg->pctldesc = lptlp_pinctrl_desc; 7627f32d370SAndy Shevchenko lg->pctldesc.name = dev_name(dev); 7637f32d370SAndy Shevchenko lg->pctldesc.pins = lg->soc->pins; 7647f32d370SAndy Shevchenko lg->pctldesc.npins = lg->soc->npins; 7657f32d370SAndy Shevchenko 76664e14e90SAndy Shevchenko lg->pctldev = devm_pinctrl_register(dev, &lg->pctldesc, lg); 76764e14e90SAndy Shevchenko if (IS_ERR(lg->pctldev)) { 76864e14e90SAndy Shevchenko dev_err(dev, "failed to register pinctrl driver\n"); 76964e14e90SAndy Shevchenko return PTR_ERR(lg->pctldev); 77064e14e90SAndy Shevchenko } 77164e14e90SAndy Shevchenko 772eb83479eSAndy Shevchenko platform_set_drvdata(pdev, lg); 773eb83479eSAndy Shevchenko 774eb83479eSAndy Shevchenko io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 775eb83479eSAndy Shevchenko if (!io_rc) { 776eb83479eSAndy Shevchenko dev_err(dev, "missing IO resources\n"); 777eb83479eSAndy Shevchenko return -EINVAL; 778eb83479eSAndy Shevchenko } 779eb83479eSAndy Shevchenko 780e1940adeSAndy Shevchenko regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); 781e1940adeSAndy Shevchenko if (!regs) { 782e1940adeSAndy Shevchenko dev_err(dev, "failed mapping IO region %pR\n", &io_rc); 783eb83479eSAndy Shevchenko return -EBUSY; 784eb83479eSAndy Shevchenko } 785eb83479eSAndy Shevchenko 78618213ad4SAndy Shevchenko for (i = 0; i < lg->soc->ncommunities; i++) { 78718213ad4SAndy Shevchenko struct intel_community *comm = &lg->communities[i]; 78818213ad4SAndy Shevchenko 78918213ad4SAndy Shevchenko *comm = lg->soc->communities[i]; 79018213ad4SAndy Shevchenko 79118213ad4SAndy Shevchenko comm->regs = regs; 79218213ad4SAndy Shevchenko comm->pad_regs = regs + 0x100; 79318213ad4SAndy Shevchenko } 794e1940adeSAndy Shevchenko 795b2e05d63SAndy Shevchenko raw_spin_lock_init(&lg->lock); 796eb83479eSAndy Shevchenko 797eb83479eSAndy Shevchenko gc = &lg->chip; 798eb83479eSAndy Shevchenko gc->label = dev_name(dev); 799eb83479eSAndy Shevchenko gc->owner = THIS_MODULE; 80064e14e90SAndy Shevchenko gc->request = gpiochip_generic_request; 80164e14e90SAndy Shevchenko gc->free = gpiochip_generic_free; 802eb83479eSAndy Shevchenko gc->direction_input = lp_gpio_direction_input; 803eb83479eSAndy Shevchenko gc->direction_output = lp_gpio_direction_output; 804eb83479eSAndy Shevchenko gc->get = lp_gpio_get; 805eb83479eSAndy Shevchenko gc->set = lp_gpio_set; 8061d112baaSAndy Shevchenko gc->set_config = gpiochip_generic_config; 80754d371cfSAndy Shevchenko gc->get_direction = lp_gpio_get_direction; 808eb83479eSAndy Shevchenko gc->base = -1; 809eb83479eSAndy Shevchenko gc->ngpio = LP_NUM_GPIO; 810eb83479eSAndy Shevchenko gc->can_sleep = false; 8113683509cSAndy Shevchenko gc->add_pin_ranges = lp_gpio_add_pin_ranges; 812eb83479eSAndy Shevchenko gc->parent = dev; 813eb83479eSAndy Shevchenko 814eb83479eSAndy Shevchenko /* set up interrupts */ 8155f3b82a1SAndy Shevchenko irq = platform_get_irq_optional(pdev, 0); 8165f3b82a1SAndy Shevchenko if (irq > 0) { 817eb83479eSAndy Shevchenko struct gpio_irq_chip *girq; 818eb83479eSAndy Shevchenko 819eb83479eSAndy Shevchenko girq = &gc->irq; 820180f9db7SAndy Shevchenko gpio_irq_chip_set_chip(girq, &lp_irqchip); 821eb83479eSAndy Shevchenko girq->init_hw = lp_gpio_irq_init_hw; 822eb83479eSAndy Shevchenko girq->parent_handler = lp_gpio_irq_handler; 823eb83479eSAndy Shevchenko girq->num_parents = 1; 8241e78ea71SAndy Shevchenko girq->parents = devm_kcalloc(dev, girq->num_parents, 825eb83479eSAndy Shevchenko sizeof(*girq->parents), 826eb83479eSAndy Shevchenko GFP_KERNEL); 827eb83479eSAndy Shevchenko if (!girq->parents) 828eb83479eSAndy Shevchenko return -ENOMEM; 8295f3b82a1SAndy Shevchenko girq->parents[0] = irq; 830eb83479eSAndy Shevchenko girq->default_type = IRQ_TYPE_NONE; 831eb83479eSAndy Shevchenko girq->handler = handle_bad_irq; 832eb83479eSAndy Shevchenko } 833eb83479eSAndy Shevchenko 834eb83479eSAndy Shevchenko ret = devm_gpiochip_add_data(dev, gc, lg); 835eb83479eSAndy Shevchenko if (ret) { 836eb83479eSAndy Shevchenko dev_err(dev, "failed adding lp-gpio chip\n"); 837eb83479eSAndy Shevchenko return ret; 838eb83479eSAndy Shevchenko } 839eb83479eSAndy Shevchenko 840eb83479eSAndy Shevchenko return 0; 841eb83479eSAndy Shevchenko } 842eb83479eSAndy Shevchenko 843eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev) 844eb83479eSAndy Shevchenko { 84518213ad4SAndy Shevchenko struct intel_pinctrl *lg = dev_get_drvdata(dev); 846f3e7d281SAndy Shevchenko struct gpio_chip *chip = &lg->chip; 847f3e7d281SAndy Shevchenko const char *dummy; 848eb83479eSAndy Shevchenko int i; 849eb83479eSAndy Shevchenko 850eb83479eSAndy Shevchenko /* on some hardware suspend clears input sensing, re-enable it here */ 8510472567bSAndy Shevchenko for_each_requested_gpio(chip, i, dummy) 8520472567bSAndy Shevchenko lp_gpio_enable_input(lp_gpio_reg(chip, i, LP_CONFIG2)); 853f3e7d281SAndy Shevchenko 854eb83479eSAndy Shevchenko return 0; 855eb83479eSAndy Shevchenko } 856eb83479eSAndy Shevchenko 85767c9e830SRaag Jadav static DEFINE_SIMPLE_DEV_PM_OPS(lp_gpio_pm_ops, NULL, lp_gpio_resume); 858eb83479eSAndy Shevchenko 859eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 860cecddda7SAndy Shevchenko { "INT33C7", (kernel_ulong_t)&lptlp_soc_data }, 861cecddda7SAndy Shevchenko { "INT3437", (kernel_ulong_t)&lptlp_soc_data }, 862eb83479eSAndy Shevchenko { } 863eb83479eSAndy Shevchenko }; 864eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 865eb83479eSAndy Shevchenko 866eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = { 867eb83479eSAndy Shevchenko .probe = lp_gpio_probe, 868eb83479eSAndy Shevchenko .driver = { 869eb83479eSAndy Shevchenko .name = "lp_gpio", 87067c9e830SRaag Jadav .pm = pm_sleep_ptr(&lp_gpio_pm_ops), 871e359a6f0SAndy Shevchenko .acpi_match_table = lynxpoint_gpio_acpi_match, 872eb83479eSAndy Shevchenko }, 873eb83479eSAndy Shevchenko }; 874eb83479eSAndy Shevchenko 875eb83479eSAndy Shevchenko static int __init lp_gpio_init(void) 876eb83479eSAndy Shevchenko { 877eb83479eSAndy Shevchenko return platform_driver_register(&lp_gpio_driver); 878eb83479eSAndy Shevchenko } 8790ddebf85SAndy Shevchenko subsys_initcall(lp_gpio_init); 880eb83479eSAndy Shevchenko 881eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void) 882eb83479eSAndy Shevchenko { 883eb83479eSAndy Shevchenko platform_driver_unregister(&lp_gpio_driver); 884eb83479eSAndy Shevchenko } 885eb83479eSAndy Shevchenko module_exit(lp_gpio_exit); 886eb83479eSAndy Shevchenko 887eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)"); 8883a67fe38SAndy Shevchenko MODULE_AUTHOR("Andy Shevchenko (Intel)"); 8893a67fe38SAndy Shevchenko MODULE_DESCRIPTION("Intel Lynxpoint pinctrl driver"); 890eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2"); 891eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio"); 892976cf4a6SRaag Jadav MODULE_IMPORT_NS(PINCTRL_INTEL); 893