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> 13*9580ba25SAndy Shevchenko #include <linux/cleanup.h> 14eb83479eSAndy Shevchenko #include <linux/gpio/driver.h> 15eb83479eSAndy Shevchenko #include <linux/interrupt.h> 16eb83479eSAndy Shevchenko #include <linux/io.h> 17eb83479eSAndy Shevchenko #include <linux/module.h> 18eb83479eSAndy Shevchenko #include <linux/platform_device.h> 1967c9e830SRaag Jadav #include <linux/pm.h> 20c4168db7SAndy Shevchenko #include <linux/seq_file.h> 21eb83479eSAndy Shevchenko #include <linux/slab.h> 22eb83479eSAndy Shevchenko #include <linux/types.h> 23eb83479eSAndy Shevchenko 24c4168db7SAndy Shevchenko #include <linux/pinctrl/consumer.h> 25c4168db7SAndy Shevchenko #include <linux/pinctrl/pinconf-generic.h> 26c4168db7SAndy Shevchenko #include <linux/pinctrl/pinconf.h> 27cecddda7SAndy Shevchenko #include <linux/pinctrl/pinctrl.h> 28cecddda7SAndy Shevchenko #include <linux/pinctrl/pinmux.h> 29cecddda7SAndy Shevchenko 30cecddda7SAndy Shevchenko #include "pinctrl-intel.h" 31cecddda7SAndy Shevchenko 32cecddda7SAndy Shevchenko #define COMMUNITY(p, n) \ 33cecddda7SAndy Shevchenko { \ 34cecddda7SAndy Shevchenko .pin_base = (p), \ 35cecddda7SAndy Shevchenko .npins = (n), \ 36cecddda7SAndy Shevchenko } 37cecddda7SAndy Shevchenko 38cecddda7SAndy Shevchenko static const struct pinctrl_pin_desc lptlp_pins[] = { 39cecddda7SAndy Shevchenko PINCTRL_PIN(0, "GP0_UART1_RXD"), 40cecddda7SAndy Shevchenko PINCTRL_PIN(1, "GP1_UART1_TXD"), 41cecddda7SAndy Shevchenko PINCTRL_PIN(2, "GP2_UART1_RTSB"), 42cecddda7SAndy Shevchenko PINCTRL_PIN(3, "GP3_UART1_CTSB"), 43cecddda7SAndy Shevchenko PINCTRL_PIN(4, "GP4_I2C0_SDA"), 44cecddda7SAndy Shevchenko PINCTRL_PIN(5, "GP5_I2C0_SCL"), 45cecddda7SAndy Shevchenko PINCTRL_PIN(6, "GP6_I2C1_SDA"), 46cecddda7SAndy Shevchenko PINCTRL_PIN(7, "GP7_I2C1_SCL"), 47cecddda7SAndy Shevchenko PINCTRL_PIN(8, "GP8"), 48cecddda7SAndy Shevchenko PINCTRL_PIN(9, "GP9"), 49cecddda7SAndy Shevchenko PINCTRL_PIN(10, "GP10"), 50cecddda7SAndy Shevchenko PINCTRL_PIN(11, "GP11_SMBALERTB"), 51cecddda7SAndy Shevchenko PINCTRL_PIN(12, "GP12_LANPHYPC"), 52cecddda7SAndy Shevchenko PINCTRL_PIN(13, "GP13"), 53cecddda7SAndy Shevchenko PINCTRL_PIN(14, "GP14"), 54cecddda7SAndy Shevchenko PINCTRL_PIN(15, "GP15"), 55cecddda7SAndy Shevchenko PINCTRL_PIN(16, "GP16_MGPIO9"), 56cecddda7SAndy Shevchenko PINCTRL_PIN(17, "GP17_MGPIO10"), 57cecddda7SAndy Shevchenko PINCTRL_PIN(18, "GP18_SRC0CLKRQB"), 58cecddda7SAndy Shevchenko PINCTRL_PIN(19, "GP19_SRC1CLKRQB"), 59cecddda7SAndy Shevchenko PINCTRL_PIN(20, "GP20_SRC2CLKRQB"), 60cecddda7SAndy Shevchenko PINCTRL_PIN(21, "GP21_SRC3CLKRQB"), 61cecddda7SAndy Shevchenko PINCTRL_PIN(22, "GP22_SRC4CLKRQB_TRST2"), 62cecddda7SAndy Shevchenko PINCTRL_PIN(23, "GP23_SRC5CLKRQB_TDI2"), 63cecddda7SAndy Shevchenko PINCTRL_PIN(24, "GP24_MGPIO0"), 64cecddda7SAndy Shevchenko PINCTRL_PIN(25, "GP25_USBWAKEOUTB"), 65cecddda7SAndy Shevchenko PINCTRL_PIN(26, "GP26_MGPIO5"), 66cecddda7SAndy Shevchenko PINCTRL_PIN(27, "GP27_MGPIO6"), 67cecddda7SAndy Shevchenko PINCTRL_PIN(28, "GP28_MGPIO7"), 68cecddda7SAndy Shevchenko PINCTRL_PIN(29, "GP29_SLP_WLANB_MGPIO3"), 69cecddda7SAndy Shevchenko PINCTRL_PIN(30, "GP30_SUSWARNB_SUSPWRDNACK_MGPIO1"), 70cecddda7SAndy Shevchenko PINCTRL_PIN(31, "GP31_ACPRESENT_MGPIO2"), 71cecddda7SAndy Shevchenko PINCTRL_PIN(32, "GP32_CLKRUNB"), 72cecddda7SAndy Shevchenko PINCTRL_PIN(33, "GP33_DEVSLP0"), 73cecddda7SAndy Shevchenko PINCTRL_PIN(34, "GP34_SATA0XPCIE6L3B_SATA0GP"), 74cecddda7SAndy Shevchenko PINCTRL_PIN(35, "GP35_SATA1XPCIE6L2B_SATA1GP"), 75cecddda7SAndy Shevchenko PINCTRL_PIN(36, "GP36_SATA2XPCIE6L1B_SATA2GP"), 76cecddda7SAndy Shevchenko PINCTRL_PIN(37, "GP37_SATA3XPCIE6L0B_SATA3GP"), 77cecddda7SAndy Shevchenko PINCTRL_PIN(38, "GP38_DEVSLP1"), 78cecddda7SAndy Shevchenko PINCTRL_PIN(39, "GP39_DEVSLP2"), 79cecddda7SAndy Shevchenko PINCTRL_PIN(40, "GP40_OC0B"), 80cecddda7SAndy Shevchenko PINCTRL_PIN(41, "GP41_OC1B"), 81cecddda7SAndy Shevchenko PINCTRL_PIN(42, "GP42_OC2B"), 82cecddda7SAndy Shevchenko PINCTRL_PIN(43, "GP43_OC3B"), 83cecddda7SAndy Shevchenko PINCTRL_PIN(44, "GP44"), 84cecddda7SAndy Shevchenko PINCTRL_PIN(45, "GP45_TMS2"), 85cecddda7SAndy Shevchenko PINCTRL_PIN(46, "GP46_TDO2"), 86cecddda7SAndy Shevchenko PINCTRL_PIN(47, "GP47"), 87cecddda7SAndy Shevchenko PINCTRL_PIN(48, "GP48"), 88cecddda7SAndy Shevchenko PINCTRL_PIN(49, "GP49"), 89cecddda7SAndy Shevchenko PINCTRL_PIN(50, "GP50"), 90cecddda7SAndy Shevchenko PINCTRL_PIN(51, "GP51_GSXDOUT"), 91cecddda7SAndy Shevchenko PINCTRL_PIN(52, "GP52_GSXSLOAD"), 92cecddda7SAndy Shevchenko PINCTRL_PIN(53, "GP53_GSXDIN"), 93cecddda7SAndy Shevchenko PINCTRL_PIN(54, "GP54_GSXSRESETB"), 94cecddda7SAndy Shevchenko PINCTRL_PIN(55, "GP55_GSXCLK"), 95cecddda7SAndy Shevchenko PINCTRL_PIN(56, "GP56"), 96cecddda7SAndy Shevchenko PINCTRL_PIN(57, "GP57"), 97cecddda7SAndy Shevchenko PINCTRL_PIN(58, "GP58"), 98cecddda7SAndy Shevchenko PINCTRL_PIN(59, "GP59"), 99cecddda7SAndy Shevchenko PINCTRL_PIN(60, "GP60_SML0ALERTB_MGPIO4"), 100cecddda7SAndy Shevchenko PINCTRL_PIN(61, "GP61_SUS_STATB"), 101cecddda7SAndy Shevchenko PINCTRL_PIN(62, "GP62_SUSCLK"), 102cecddda7SAndy Shevchenko PINCTRL_PIN(63, "GP63_SLP_S5B"), 103cecddda7SAndy Shevchenko PINCTRL_PIN(64, "GP64_SDIO_CLK"), 104cecddda7SAndy Shevchenko PINCTRL_PIN(65, "GP65_SDIO_CMD"), 105cecddda7SAndy Shevchenko PINCTRL_PIN(66, "GP66_SDIO_D0"), 106cecddda7SAndy Shevchenko PINCTRL_PIN(67, "GP67_SDIO_D1"), 107cecddda7SAndy Shevchenko PINCTRL_PIN(68, "GP68_SDIO_D2"), 108cecddda7SAndy Shevchenko PINCTRL_PIN(69, "GP69_SDIO_D3"), 109cecddda7SAndy Shevchenko PINCTRL_PIN(70, "GP70_SDIO_POWER_EN"), 110cecddda7SAndy Shevchenko PINCTRL_PIN(71, "GP71_MPHYPC"), 111cecddda7SAndy Shevchenko PINCTRL_PIN(72, "GP72_BATLOWB"), 112cecddda7SAndy Shevchenko PINCTRL_PIN(73, "GP73_SML1ALERTB_PCHHOTB_MGPIO8"), 113cecddda7SAndy Shevchenko PINCTRL_PIN(74, "GP74_SML1DATA_MGPIO12"), 114cecddda7SAndy Shevchenko PINCTRL_PIN(75, "GP75_SML1CLK_MGPIO11"), 115cecddda7SAndy Shevchenko PINCTRL_PIN(76, "GP76_BMBUSYB"), 116cecddda7SAndy Shevchenko PINCTRL_PIN(77, "GP77_PIRQAB"), 117cecddda7SAndy Shevchenko PINCTRL_PIN(78, "GP78_PIRQBB"), 118cecddda7SAndy Shevchenko PINCTRL_PIN(79, "GP79_PIRQCB"), 119cecddda7SAndy Shevchenko PINCTRL_PIN(80, "GP80_PIRQDB"), 120cecddda7SAndy Shevchenko PINCTRL_PIN(81, "GP81_SPKR"), 121cecddda7SAndy Shevchenko PINCTRL_PIN(82, "GP82_RCINB"), 122cecddda7SAndy Shevchenko PINCTRL_PIN(83, "GP83_GSPI0_CSB"), 123cecddda7SAndy Shevchenko PINCTRL_PIN(84, "GP84_GSPI0_CLK"), 124cecddda7SAndy Shevchenko PINCTRL_PIN(85, "GP85_GSPI0_MISO"), 125cecddda7SAndy Shevchenko PINCTRL_PIN(86, "GP86_GSPI0_MOSI"), 126cecddda7SAndy Shevchenko PINCTRL_PIN(87, "GP87_GSPI1_CSB"), 127cecddda7SAndy Shevchenko PINCTRL_PIN(88, "GP88_GSPI1_CLK"), 128cecddda7SAndy Shevchenko PINCTRL_PIN(89, "GP89_GSPI1_MISO"), 129cecddda7SAndy Shevchenko PINCTRL_PIN(90, "GP90_GSPI1_MOSI"), 130cecddda7SAndy Shevchenko PINCTRL_PIN(91, "GP91_UART0_RXD"), 131cecddda7SAndy Shevchenko PINCTRL_PIN(92, "GP92_UART0_TXD"), 132cecddda7SAndy Shevchenko PINCTRL_PIN(93, "GP93_UART0_RTSB"), 133cecddda7SAndy Shevchenko PINCTRL_PIN(94, "GP94_UART0_CTSB"), 134cecddda7SAndy Shevchenko }; 135cecddda7SAndy Shevchenko 136cecddda7SAndy Shevchenko static const struct intel_community lptlp_communities[] = { 137cecddda7SAndy Shevchenko COMMUNITY(0, 95), 138cecddda7SAndy Shevchenko }; 139cecddda7SAndy Shevchenko 140cecddda7SAndy Shevchenko static const struct intel_pinctrl_soc_data lptlp_soc_data = { 141cecddda7SAndy Shevchenko .pins = lptlp_pins, 142cecddda7SAndy Shevchenko .npins = ARRAY_SIZE(lptlp_pins), 143cecddda7SAndy Shevchenko .communities = lptlp_communities, 144cecddda7SAndy Shevchenko .ncommunities = ARRAY_SIZE(lptlp_communities), 145cecddda7SAndy Shevchenko }; 146cecddda7SAndy Shevchenko 1477c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */ 148eb83479eSAndy Shevchenko 1497c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO 95 150eb83479eSAndy Shevchenko 151eb83479eSAndy Shevchenko /* Bitmapped register offsets */ 152eb83479eSAndy Shevchenko #define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ 1537f32d370SAndy Shevchenko #define LP_IRQ2IOXAPIC 0x10 /* Bitmap, set by bios, 1: pin routed to IOxAPIC */ 154eb83479eSAndy Shevchenko #define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ 155eb83479eSAndy Shevchenko #define LP_INT_STAT 0x80 156eb83479eSAndy Shevchenko #define LP_INT_ENABLE 0x90 157eb83479eSAndy Shevchenko 158eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */ 159eb83479eSAndy Shevchenko #define LP_CONFIG1 0x100 160eb83479eSAndy Shevchenko #define LP_CONFIG2 0x104 161eb83479eSAndy Shevchenko 162eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */ 163eb83479eSAndy Shevchenko #define OUT_LVL_BIT BIT(31) 164eb83479eSAndy Shevchenko #define IN_LVL_BIT BIT(30) 165eb83479eSAndy Shevchenko #define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ 166eb83479eSAndy Shevchenko #define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ 167eb83479eSAndy Shevchenko #define DIR_BIT BIT(2) /* 0: Output, 1: Input */ 16876347d7aSAndy Shevchenko #define USE_SEL_MASK GENMASK(1, 0) /* 0: Native, 1: GPIO, ... */ 16976347d7aSAndy Shevchenko #define USE_SEL_NATIVE (0 << 0) 17076347d7aSAndy Shevchenko #define USE_SEL_GPIO (1 << 0) 171eb83479eSAndy Shevchenko 172eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */ 173eb83479eSAndy Shevchenko #define GPINDIS_BIT BIT(2) /* disable input sensing */ 1747f32d370SAndy Shevchenko #define GPIWP_MASK GENMASK(1, 0) /* weak pull options */ 1757f32d370SAndy Shevchenko #define GPIWP_NONE 0 /* none */ 1767f32d370SAndy Shevchenko #define GPIWP_DOWN 1 /* weak pull down */ 1777f32d370SAndy Shevchenko #define GPIWP_UP 2 /* weak pull up */ 178eb83479eSAndy Shevchenko 179eb83479eSAndy Shevchenko /* 180eb83479eSAndy Shevchenko * Lynxpoint gpios are controlled through both bitmapped registers and 181eb83479eSAndy Shevchenko * per gpio specific registers. The bitmapped registers are in chunks of 1827c0bc7bbSAndy Shevchenko * 3 x 32bit registers to cover all 95 GPIOs 183eb83479eSAndy Shevchenko * 184eb83479eSAndy Shevchenko * per gpio specific registers consist of two 32bit registers per gpio 1857c0bc7bbSAndy Shevchenko * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 1867c0bc7bbSAndy Shevchenko * 190 config registers. 187eb83479eSAndy Shevchenko * 188eb83479eSAndy Shevchenko * A simplified view of the register layout look like this: 189eb83479eSAndy Shevchenko * 190eb83479eSAndy Shevchenko * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 191eb83479eSAndy Shevchenko * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 192eb83479eSAndy Shevchenko * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 193eb83479eSAndy Shevchenko * ... 194eb83479eSAndy Shevchenko * LP_INT_ENABLE[31:0] ... 1957c0bc7bbSAndy Shevchenko * LP_INT_ENABLE[63:32] ... 196eb83479eSAndy Shevchenko * LP_INT_ENABLE[94:64] ... 197eb83479eSAndy Shevchenko * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 198eb83479eSAndy Shevchenko * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 199eb83479eSAndy Shevchenko * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 200eb83479eSAndy Shevchenko * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 201eb83479eSAndy Shevchenko * LP2_CONFIG1 (gpio 2) ... 202eb83479eSAndy Shevchenko * LP2_CONFIG2 (gpio 2) ... 203eb83479eSAndy Shevchenko * ... 204eb83479eSAndy Shevchenko * LP94_CONFIG1 (gpio 94) ... 205eb83479eSAndy Shevchenko * LP94_CONFIG2 (gpio 94) ... 2067f32d370SAndy Shevchenko * 2077f32d370SAndy Shevchenko * IOxAPIC redirection map applies only for gpio 8-10, 13-14, 45-55. 208eb83479eSAndy Shevchenko */ 209eb83479eSAndy Shevchenko 210c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset, 211eb83479eSAndy Shevchenko int reg) 212eb83479eSAndy Shevchenko { 21318213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 21418213ad4SAndy Shevchenko struct intel_community *comm; 215eb83479eSAndy Shevchenko int reg_offset; 216eb83479eSAndy Shevchenko 217976cf4a6SRaag Jadav comm = intel_get_community(lg, offset); 21818213ad4SAndy Shevchenko if (!comm) 21918213ad4SAndy Shevchenko return NULL; 22018213ad4SAndy Shevchenko 22118213ad4SAndy Shevchenko offset -= comm->pin_base; 22218213ad4SAndy Shevchenko 223eb83479eSAndy Shevchenko if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 224eb83479eSAndy Shevchenko /* per gpio specific config registers */ 225eb83479eSAndy Shevchenko reg_offset = offset * 8; 226eb83479eSAndy Shevchenko else 227eb83479eSAndy Shevchenko /* bitmapped registers */ 228eb83479eSAndy Shevchenko reg_offset = (offset / 32) * 4; 229eb83479eSAndy Shevchenko 23018213ad4SAndy Shevchenko return comm->regs + reg_offset + reg; 231eb83479eSAndy Shevchenko } 232eb83479eSAndy Shevchenko 23318213ad4SAndy Shevchenko static bool lp_gpio_acpi_use(struct intel_pinctrl *lg, unsigned int pin) 23421a06495SAndy Shevchenko { 23521a06495SAndy Shevchenko void __iomem *acpi_use; 23621a06495SAndy Shevchenko 23721a06495SAndy Shevchenko acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED); 23821a06495SAndy Shevchenko if (!acpi_use) 23921a06495SAndy Shevchenko return true; 24021a06495SAndy Shevchenko 24121a06495SAndy Shevchenko return !(ioread32(acpi_use) & BIT(pin % 32)); 24221a06495SAndy Shevchenko } 24321a06495SAndy Shevchenko 2447f32d370SAndy Shevchenko static bool lp_gpio_ioxapic_use(struct gpio_chip *chip, unsigned int offset) 2457f32d370SAndy Shevchenko { 2467f32d370SAndy Shevchenko void __iomem *ioxapic_use = lp_gpio_reg(chip, offset, LP_IRQ2IOXAPIC); 2477f32d370SAndy Shevchenko u32 value; 2487f32d370SAndy Shevchenko 2497f32d370SAndy Shevchenko value = ioread32(ioxapic_use); 2507f32d370SAndy Shevchenko 2517f32d370SAndy Shevchenko if (offset >= 8 && offset <= 10) 2527f32d370SAndy Shevchenko return !!(value & BIT(offset - 8 + 0)); 2537f32d370SAndy Shevchenko if (offset >= 13 && offset <= 14) 2547f32d370SAndy Shevchenko return !!(value & BIT(offset - 13 + 3)); 2557f32d370SAndy Shevchenko if (offset >= 45 && offset <= 55) 2567f32d370SAndy Shevchenko return !!(value & BIT(offset - 45 + 5)); 2577f32d370SAndy Shevchenko 2587f32d370SAndy Shevchenko return false; 2597f32d370SAndy Shevchenko } 2607f32d370SAndy Shevchenko 26103d9eca7SAndy Shevchenko static void lp_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 26203d9eca7SAndy Shevchenko unsigned int pin) 26303d9eca7SAndy Shevchenko { 26403d9eca7SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 26503d9eca7SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 26603d9eca7SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 26703d9eca7SAndy Shevchenko u32 value, mode; 26803d9eca7SAndy Shevchenko 26903d9eca7SAndy Shevchenko value = ioread32(reg); 27003d9eca7SAndy Shevchenko 27103d9eca7SAndy Shevchenko mode = value & USE_SEL_MASK; 27203d9eca7SAndy Shevchenko if (mode == USE_SEL_GPIO) 27303d9eca7SAndy Shevchenko seq_puts(s, "GPIO "); 27403d9eca7SAndy Shevchenko else 27503d9eca7SAndy Shevchenko seq_printf(s, "mode %d ", mode); 27603d9eca7SAndy Shevchenko 27703d9eca7SAndy Shevchenko seq_printf(s, "0x%08x 0x%08x", value, ioread32(conf2)); 27803d9eca7SAndy Shevchenko 27903d9eca7SAndy Shevchenko if (lp_gpio_acpi_use(lg, pin)) 28003d9eca7SAndy Shevchenko seq_puts(s, " [ACPI]"); 28103d9eca7SAndy Shevchenko } 28203d9eca7SAndy Shevchenko 2837f32d370SAndy Shevchenko static const struct pinctrl_ops lptlp_pinctrl_ops = { 284976cf4a6SRaag Jadav .get_groups_count = intel_get_groups_count, 285976cf4a6SRaag Jadav .get_group_name = intel_get_group_name, 286976cf4a6SRaag Jadav .get_group_pins = intel_get_group_pins, 28703d9eca7SAndy Shevchenko .pin_dbg_show = lp_pin_dbg_show, 2887f32d370SAndy Shevchenko }; 2897f32d370SAndy Shevchenko 2907f32d370SAndy Shevchenko static int lp_pinmux_set_mux(struct pinctrl_dev *pctldev, 2917f32d370SAndy Shevchenko unsigned int function, unsigned int group) 2927f32d370SAndy Shevchenko { 2937f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 2947f32d370SAndy Shevchenko const struct intel_pingroup *grp = &lg->soc->groups[group]; 2957f32d370SAndy Shevchenko int i; 2967f32d370SAndy Shevchenko 297*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 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 return 0; 3167f32d370SAndy Shevchenko } 3177f32d370SAndy Shevchenko 3180472567bSAndy Shevchenko static void lp_gpio_enable_input(void __iomem *reg) 3190472567bSAndy Shevchenko { 3200472567bSAndy Shevchenko iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg); 3210472567bSAndy Shevchenko } 3220472567bSAndy Shevchenko 3230472567bSAndy Shevchenko static void lp_gpio_disable_input(void __iomem *reg) 3240472567bSAndy Shevchenko { 3250472567bSAndy Shevchenko iowrite32(ioread32(reg) | GPINDIS_BIT, reg); 3260472567bSAndy Shevchenko } 3270472567bSAndy Shevchenko 3287f32d370SAndy Shevchenko static int lp_gpio_request_enable(struct pinctrl_dev *pctldev, 3297f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3307f32d370SAndy Shevchenko unsigned int pin) 3317f32d370SAndy Shevchenko { 3327f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3337f32d370SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 3347f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 3357f32d370SAndy Shevchenko u32 value; 3367f32d370SAndy Shevchenko 337*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 3387f32d370SAndy Shevchenko 3397f32d370SAndy Shevchenko /* 3407f32d370SAndy Shevchenko * Reconfigure pin to GPIO mode if needed and issue a warning, 3417f32d370SAndy Shevchenko * since we expect firmware to configure it properly. 3427f32d370SAndy Shevchenko */ 3437f32d370SAndy Shevchenko value = ioread32(reg); 3447f32d370SAndy Shevchenko if ((value & USE_SEL_MASK) != USE_SEL_GPIO) { 3457f32d370SAndy Shevchenko iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg); 3467f32d370SAndy Shevchenko dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", pin); 3477f32d370SAndy Shevchenko } 3487f32d370SAndy Shevchenko 3497f32d370SAndy Shevchenko /* Enable input sensing */ 3500472567bSAndy Shevchenko lp_gpio_enable_input(conf2); 3517f32d370SAndy Shevchenko 3527f32d370SAndy Shevchenko return 0; 3537f32d370SAndy Shevchenko } 3547f32d370SAndy Shevchenko 3557f32d370SAndy Shevchenko static void lp_gpio_disable_free(struct pinctrl_dev *pctldev, 3567f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3577f32d370SAndy Shevchenko unsigned int pin) 3587f32d370SAndy Shevchenko { 3597f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3607f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 3617f32d370SAndy Shevchenko 362*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 3637f32d370SAndy Shevchenko 3647f32d370SAndy Shevchenko /* Disable input sensing */ 3650472567bSAndy Shevchenko lp_gpio_disable_input(conf2); 3667f32d370SAndy Shevchenko } 3677f32d370SAndy Shevchenko 3687f32d370SAndy Shevchenko static int lp_gpio_set_direction(struct pinctrl_dev *pctldev, 3697f32d370SAndy Shevchenko struct pinctrl_gpio_range *range, 3707f32d370SAndy Shevchenko unsigned int pin, bool input) 3717f32d370SAndy Shevchenko { 3727f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 3737f32d370SAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 3747f32d370SAndy Shevchenko u32 value; 3757f32d370SAndy Shevchenko 376*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 3777f32d370SAndy Shevchenko 3787f32d370SAndy Shevchenko value = ioread32(reg); 3797f32d370SAndy Shevchenko value &= ~DIR_BIT; 3807f32d370SAndy Shevchenko if (input) { 3817f32d370SAndy Shevchenko value |= DIR_BIT; 3827f32d370SAndy Shevchenko } else { 3837f32d370SAndy Shevchenko /* 3847f32d370SAndy Shevchenko * Before making any direction modifications, do a check if GPIO 3857f32d370SAndy Shevchenko * is set for direct IRQ. On Lynxpoint, setting GPIO to output 3867f32d370SAndy Shevchenko * does not make sense, so let's at least warn the caller before 3877f32d370SAndy Shevchenko * they shoot themselves in the foot. 3887f32d370SAndy Shevchenko */ 3897f32d370SAndy Shevchenko WARN(lp_gpio_ioxapic_use(&lg->chip, pin), 3907f32d370SAndy Shevchenko "Potential Error: Setting GPIO to output with IOxAPIC redirection"); 3917f32d370SAndy Shevchenko } 3927f32d370SAndy Shevchenko iowrite32(value, reg); 3937f32d370SAndy Shevchenko 3947f32d370SAndy Shevchenko return 0; 3957f32d370SAndy Shevchenko } 3967f32d370SAndy Shevchenko 3977f32d370SAndy Shevchenko static const struct pinmux_ops lptlp_pinmux_ops = { 398976cf4a6SRaag Jadav .get_functions_count = intel_get_functions_count, 399976cf4a6SRaag Jadav .get_function_name = intel_get_function_name, 400976cf4a6SRaag Jadav .get_function_groups = intel_get_function_groups, 4017f32d370SAndy Shevchenko .set_mux = lp_pinmux_set_mux, 4027f32d370SAndy Shevchenko .gpio_request_enable = lp_gpio_request_enable, 4037f32d370SAndy Shevchenko .gpio_disable_free = lp_gpio_disable_free, 4047f32d370SAndy Shevchenko .gpio_set_direction = lp_gpio_set_direction, 4057f32d370SAndy Shevchenko }; 4067f32d370SAndy Shevchenko 4077f32d370SAndy Shevchenko static int lp_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 4087f32d370SAndy Shevchenko unsigned long *config) 4097f32d370SAndy Shevchenko { 4107f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 4117f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 4127f32d370SAndy Shevchenko enum pin_config_param param = pinconf_to_config_param(*config); 4137f32d370SAndy Shevchenko u32 value, pull; 414d25dd66aSAndy Shevchenko u16 arg; 4157f32d370SAndy Shevchenko 416*9580ba25SAndy Shevchenko scoped_guard(raw_spinlock_irqsave, &lg->lock) 4177f32d370SAndy Shevchenko value = ioread32(conf2); 4187f32d370SAndy Shevchenko 4197f32d370SAndy Shevchenko pull = value & GPIWP_MASK; 4207f32d370SAndy Shevchenko 4217f32d370SAndy Shevchenko switch (param) { 4227f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_DISABLE: 423d25dd66aSAndy Shevchenko if (pull != GPIWP_NONE) 4247f32d370SAndy Shevchenko return -EINVAL; 425d25dd66aSAndy Shevchenko arg = 0; 4267f32d370SAndy Shevchenko break; 4277f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_DOWN: 4287f32d370SAndy Shevchenko if (pull != GPIWP_DOWN) 4297f32d370SAndy Shevchenko return -EINVAL; 4307f32d370SAndy Shevchenko 4317f32d370SAndy Shevchenko arg = 1; 4327f32d370SAndy Shevchenko break; 4337f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_UP: 4347f32d370SAndy Shevchenko if (pull != GPIWP_UP) 4357f32d370SAndy Shevchenko return -EINVAL; 4367f32d370SAndy Shevchenko 4377f32d370SAndy Shevchenko arg = 1; 4387f32d370SAndy Shevchenko break; 4397f32d370SAndy Shevchenko default: 4407f32d370SAndy Shevchenko return -ENOTSUPP; 4417f32d370SAndy Shevchenko } 4427f32d370SAndy Shevchenko 4437f32d370SAndy Shevchenko *config = pinconf_to_config_packed(param, arg); 4447f32d370SAndy Shevchenko 4457f32d370SAndy Shevchenko return 0; 4467f32d370SAndy Shevchenko } 4477f32d370SAndy Shevchenko 4487f32d370SAndy Shevchenko static int lp_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 4497f32d370SAndy Shevchenko unsigned long *configs, unsigned int num_configs) 4507f32d370SAndy Shevchenko { 4517f32d370SAndy Shevchenko struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 4527f32d370SAndy Shevchenko void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 4537f32d370SAndy Shevchenko enum pin_config_param param; 454*9580ba25SAndy Shevchenko unsigned int i; 4557f32d370SAndy Shevchenko u32 value; 4567f32d370SAndy Shevchenko 457*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 4587f32d370SAndy Shevchenko 4597f32d370SAndy Shevchenko value = ioread32(conf2); 4607f32d370SAndy Shevchenko 4617f32d370SAndy Shevchenko for (i = 0; i < num_configs; i++) { 4627f32d370SAndy Shevchenko param = pinconf_to_config_param(configs[i]); 4637f32d370SAndy Shevchenko 4647f32d370SAndy Shevchenko switch (param) { 4657f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_DISABLE: 4667f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 467d25dd66aSAndy Shevchenko value |= GPIWP_NONE; 4687f32d370SAndy Shevchenko break; 4697f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_DOWN: 4707f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 4717f32d370SAndy Shevchenko value |= GPIWP_DOWN; 4727f32d370SAndy Shevchenko break; 4737f32d370SAndy Shevchenko case PIN_CONFIG_BIAS_PULL_UP: 4747f32d370SAndy Shevchenko value &= ~GPIWP_MASK; 4757f32d370SAndy Shevchenko value |= GPIWP_UP; 4767f32d370SAndy Shevchenko break; 4777f32d370SAndy Shevchenko default: 478*9580ba25SAndy Shevchenko return -ENOTSUPP; 479*9580ba25SAndy Shevchenko } 4807f32d370SAndy Shevchenko } 4817f32d370SAndy Shevchenko 4827f32d370SAndy Shevchenko iowrite32(value, conf2); 4837f32d370SAndy Shevchenko 484*9580ba25SAndy Shevchenko return 0; 4857f32d370SAndy Shevchenko } 4867f32d370SAndy Shevchenko 4877f32d370SAndy Shevchenko static const struct pinconf_ops lptlp_pinconf_ops = { 4887f32d370SAndy Shevchenko .is_generic = true, 4897f32d370SAndy Shevchenko .pin_config_get = lp_pin_config_get, 4907f32d370SAndy Shevchenko .pin_config_set = lp_pin_config_set, 4917f32d370SAndy Shevchenko }; 4927f32d370SAndy Shevchenko 4937f32d370SAndy Shevchenko static const struct pinctrl_desc lptlp_pinctrl_desc = { 4947f32d370SAndy Shevchenko .pctlops = &lptlp_pinctrl_ops, 4957f32d370SAndy Shevchenko .pmxops = &lptlp_pinmux_ops, 4967f32d370SAndy Shevchenko .confops = &lptlp_pinconf_ops, 4977f32d370SAndy Shevchenko .owner = THIS_MODULE, 4987f32d370SAndy Shevchenko }; 4997f32d370SAndy Shevchenko 500c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset) 501eb83479eSAndy Shevchenko { 502e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 503e1940adeSAndy Shevchenko return !!(ioread32(reg) & IN_LVL_BIT); 504eb83479eSAndy Shevchenko } 505eb83479eSAndy Shevchenko 506c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 507eb83479eSAndy Shevchenko { 50818213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 509e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 510eb83479eSAndy Shevchenko 511*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 512eb83479eSAndy Shevchenko 513eb83479eSAndy Shevchenko if (value) 514e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | OUT_LVL_BIT, reg); 515eb83479eSAndy Shevchenko else 516e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg); 517eb83479eSAndy Shevchenko } 518eb83479eSAndy Shevchenko 519c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 520eb83479eSAndy Shevchenko { 521315c46f9SBartosz Golaszewski return pinctrl_gpio_direction_input(chip, offset); 522eb83479eSAndy Shevchenko } 523eb83479eSAndy Shevchenko 524c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 525c35f463aSAndy Shevchenko int value) 526eb83479eSAndy Shevchenko { 527eb83479eSAndy Shevchenko lp_gpio_set(chip, offset, value); 528eb83479eSAndy Shevchenko 529b679d6c0SBartosz Golaszewski return pinctrl_gpio_direction_output(chip, offset); 530eb83479eSAndy Shevchenko } 531eb83479eSAndy Shevchenko 53254d371cfSAndy Shevchenko static int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 53354d371cfSAndy Shevchenko { 53454d371cfSAndy Shevchenko void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 53554d371cfSAndy Shevchenko 53654d371cfSAndy Shevchenko if (ioread32(reg) & DIR_BIT) 53754d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_IN; 53854d371cfSAndy Shevchenko 53954d371cfSAndy Shevchenko return GPIO_LINE_DIRECTION_OUT; 54054d371cfSAndy Shevchenko } 54154d371cfSAndy Shevchenko 542eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc) 543eb83479eSAndy Shevchenko { 544eb83479eSAndy Shevchenko struct irq_data *data = irq_desc_get_irq_data(desc); 545eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_desc_get_handler_data(desc); 54618213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 547eb83479eSAndy Shevchenko struct irq_chip *chip = irq_data_get_irq_chip(data); 548e1940adeSAndy Shevchenko void __iomem *reg, *ena; 549e1940adeSAndy Shevchenko unsigned long pending; 550eb83479eSAndy Shevchenko u32 base, pin; 551eb83479eSAndy Shevchenko 552eb83479eSAndy Shevchenko /* check from GPIO controller which pin triggered the interrupt */ 553eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 554eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 555eb83479eSAndy Shevchenko ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 556eb83479eSAndy Shevchenko 557eb83479eSAndy Shevchenko /* Only interrupts that are enabled */ 558e1940adeSAndy Shevchenko pending = ioread32(reg) & ioread32(ena); 559eb83479eSAndy Shevchenko 560a9cb09b7SMarc Zyngier for_each_set_bit(pin, &pending, 32) 561a9cb09b7SMarc Zyngier generic_handle_domain_irq(lg->chip.irq.domain, base + pin); 562eb83479eSAndy Shevchenko } 563eb83479eSAndy Shevchenko chip->irq_eoi(data); 564eb83479eSAndy Shevchenko } 565eb83479eSAndy Shevchenko 5665931e6edSAndy Shevchenko static void lp_irq_ack(struct irq_data *d) 5675931e6edSAndy Shevchenko { 5685931e6edSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 56918213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 570180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 5715931e6edSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT); 5725931e6edSAndy Shevchenko 573*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 574*9580ba25SAndy Shevchenko 5755931e6edSAndy Shevchenko iowrite32(BIT(hwirq % 32), reg); 5765931e6edSAndy Shevchenko } 5775931e6edSAndy Shevchenko 578eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d) 579eb83479eSAndy Shevchenko { 580eb83479eSAndy Shevchenko } 581eb83479eSAndy Shevchenko 582eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d) 583eb83479eSAndy Shevchenko { 584eb83479eSAndy Shevchenko } 585eb83479eSAndy Shevchenko 586eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d) 587eb83479eSAndy Shevchenko { 588eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 58918213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 590180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 591e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 592eb83479eSAndy Shevchenko 593180f9db7SAndy Shevchenko gpiochip_enable_irq(gc, hwirq); 594180f9db7SAndy Shevchenko 595*9580ba25SAndy Shevchenko scoped_guard(raw_spinlock_irqsave, &lg->lock) 596e1940adeSAndy Shevchenko iowrite32(ioread32(reg) | BIT(hwirq % 32), reg); 597eb83479eSAndy Shevchenko } 598eb83479eSAndy Shevchenko 599eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d) 600eb83479eSAndy Shevchenko { 601eb83479eSAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 60218213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 603180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 604e1940adeSAndy Shevchenko void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 605eb83479eSAndy Shevchenko 606*9580ba25SAndy Shevchenko scoped_guard(raw_spinlock_irqsave, &lg->lock) 607e1940adeSAndy Shevchenko iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg); 608180f9db7SAndy Shevchenko 609180f9db7SAndy Shevchenko gpiochip_disable_irq(gc, hwirq); 610eb83479eSAndy Shevchenko } 611eb83479eSAndy Shevchenko 612095f2a67SAndy Shevchenko static int lp_irq_set_type(struct irq_data *d, unsigned int type) 613095f2a67SAndy Shevchenko { 614095f2a67SAndy Shevchenko struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 61518213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(gc); 616180f9db7SAndy Shevchenko irq_hw_number_t hwirq = irqd_to_hwirq(d); 617180f9db7SAndy Shevchenko void __iomem *reg; 618095f2a67SAndy Shevchenko u32 value; 619095f2a67SAndy Shevchenko 620180f9db7SAndy Shevchenko reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 621180f9db7SAndy Shevchenko if (!reg) 622095f2a67SAndy Shevchenko return -EINVAL; 623095f2a67SAndy Shevchenko 624540bff18SAndy Shevchenko /* Fail if BIOS reserved pin for ACPI use */ 625540bff18SAndy Shevchenko if (lp_gpio_acpi_use(lg, hwirq)) { 626180f9db7SAndy Shevchenko dev_err(lg->dev, "pin %lu can't be used as IRQ\n", hwirq); 627540bff18SAndy Shevchenko return -EBUSY; 628540bff18SAndy Shevchenko } 629540bff18SAndy Shevchenko 630*9580ba25SAndy Shevchenko guard(raw_spinlock_irqsave)(&lg->lock); 631*9580ba25SAndy Shevchenko 632095f2a67SAndy Shevchenko value = ioread32(reg); 633095f2a67SAndy Shevchenko 634095f2a67SAndy Shevchenko /* set both TRIG_SEL and INV bits to 0 for rising edge */ 635095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_RISING) 636095f2a67SAndy Shevchenko value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 637095f2a67SAndy Shevchenko 638095f2a67SAndy Shevchenko /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 639095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_FALLING) 640095f2a67SAndy Shevchenko value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 641095f2a67SAndy Shevchenko 642095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 0 for level low */ 643095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_LOW) 644095f2a67SAndy Shevchenko value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 645095f2a67SAndy Shevchenko 646095f2a67SAndy Shevchenko /* TRIG_SEL bit 1, INV bit 1 for level high */ 647095f2a67SAndy Shevchenko if (type & IRQ_TYPE_LEVEL_HIGH) 648095f2a67SAndy Shevchenko value |= TRIG_SEL_BIT | INT_INV_BIT; 649095f2a67SAndy Shevchenko 650095f2a67SAndy Shevchenko iowrite32(value, reg); 651095f2a67SAndy Shevchenko 652095f2a67SAndy Shevchenko if (type & IRQ_TYPE_EDGE_BOTH) 653095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_edge_irq); 654095f2a67SAndy Shevchenko else if (type & IRQ_TYPE_LEVEL_MASK) 655095f2a67SAndy Shevchenko irq_set_handler_locked(d, handle_level_irq); 656095f2a67SAndy Shevchenko 657095f2a67SAndy Shevchenko return 0; 658095f2a67SAndy Shevchenko } 659095f2a67SAndy Shevchenko 660180f9db7SAndy Shevchenko static const struct irq_chip lp_irqchip = { 661eb83479eSAndy Shevchenko .name = "LP-GPIO", 6625931e6edSAndy Shevchenko .irq_ack = lp_irq_ack, 663eb83479eSAndy Shevchenko .irq_mask = lp_irq_mask, 664eb83479eSAndy Shevchenko .irq_unmask = lp_irq_unmask, 665eb83479eSAndy Shevchenko .irq_enable = lp_irq_enable, 666eb83479eSAndy Shevchenko .irq_disable = lp_irq_disable, 667095f2a67SAndy Shevchenko .irq_set_type = lp_irq_set_type, 668180f9db7SAndy Shevchenko .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, 669180f9db7SAndy Shevchenko GPIOCHIP_IRQ_RESOURCE_HELPERS, 670eb83479eSAndy Shevchenko }; 671eb83479eSAndy Shevchenko 672eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip) 673eb83479eSAndy Shevchenko { 67418213ad4SAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 675e1940adeSAndy Shevchenko void __iomem *reg; 676c35f463aSAndy Shevchenko unsigned int base; 677eb83479eSAndy Shevchenko 678eb83479eSAndy Shevchenko for (base = 0; base < lg->chip.ngpio; base += 32) { 679eb83479eSAndy Shevchenko /* disable gpio pin interrupts */ 680eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 681e1940adeSAndy Shevchenko iowrite32(0, reg); 682eb83479eSAndy Shevchenko /* Clear interrupt status register */ 683eb83479eSAndy Shevchenko reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 684e1940adeSAndy Shevchenko iowrite32(0xffffffff, reg); 685eb83479eSAndy Shevchenko } 686eb83479eSAndy Shevchenko 687eb83479eSAndy Shevchenko return 0; 688eb83479eSAndy Shevchenko } 689eb83479eSAndy Shevchenko 6903683509cSAndy Shevchenko static int lp_gpio_add_pin_ranges(struct gpio_chip *chip) 6913683509cSAndy Shevchenko { 6923683509cSAndy Shevchenko struct intel_pinctrl *lg = gpiochip_get_data(chip); 6933683509cSAndy Shevchenko struct device *dev = lg->dev; 6943683509cSAndy Shevchenko int ret; 6953683509cSAndy Shevchenko 6963683509cSAndy Shevchenko ret = gpiochip_add_pin_range(chip, dev_name(dev), 0, 0, lg->soc->npins); 6973683509cSAndy Shevchenko if (ret) 6983683509cSAndy Shevchenko dev_err(dev, "failed to add GPIO pin range\n"); 6993683509cSAndy Shevchenko 7003683509cSAndy Shevchenko return ret; 7013683509cSAndy Shevchenko } 7023683509cSAndy Shevchenko 703eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev) 704eb83479eSAndy Shevchenko { 70518213ad4SAndy Shevchenko const struct intel_pinctrl_soc_data *soc; 70618213ad4SAndy Shevchenko struct intel_pinctrl *lg; 707eb83479eSAndy Shevchenko struct gpio_chip *gc; 708eb83479eSAndy Shevchenko struct device *dev = &pdev->dev; 7095f3b82a1SAndy Shevchenko struct resource *io_rc; 710e1940adeSAndy Shevchenko void __iomem *regs; 71118213ad4SAndy Shevchenko unsigned int i; 7125f3b82a1SAndy Shevchenko int irq, ret; 713eb83479eSAndy Shevchenko 71418213ad4SAndy Shevchenko soc = (const struct intel_pinctrl_soc_data *)device_get_match_data(dev); 71518213ad4SAndy Shevchenko if (!soc) 71618213ad4SAndy Shevchenko return -ENODEV; 71718213ad4SAndy Shevchenko 718a718e68eSAndy Shevchenko lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 719eb83479eSAndy Shevchenko if (!lg) 720eb83479eSAndy Shevchenko return -ENOMEM; 721eb83479eSAndy Shevchenko 7221e78ea71SAndy Shevchenko lg->dev = dev; 72318213ad4SAndy Shevchenko lg->soc = soc; 72418213ad4SAndy Shevchenko 72518213ad4SAndy Shevchenko lg->ncommunities = lg->soc->ncommunities; 72618213ad4SAndy Shevchenko lg->communities = devm_kcalloc(dev, lg->ncommunities, 72718213ad4SAndy Shevchenko sizeof(*lg->communities), GFP_KERNEL); 72818213ad4SAndy Shevchenko if (!lg->communities) 72918213ad4SAndy Shevchenko return -ENOMEM; 73018213ad4SAndy Shevchenko 7317f32d370SAndy Shevchenko lg->pctldesc = lptlp_pinctrl_desc; 7327f32d370SAndy Shevchenko lg->pctldesc.name = dev_name(dev); 7337f32d370SAndy Shevchenko lg->pctldesc.pins = lg->soc->pins; 7347f32d370SAndy Shevchenko lg->pctldesc.npins = lg->soc->npins; 7357f32d370SAndy Shevchenko 73664e14e90SAndy Shevchenko lg->pctldev = devm_pinctrl_register(dev, &lg->pctldesc, lg); 73764e14e90SAndy Shevchenko if (IS_ERR(lg->pctldev)) { 73864e14e90SAndy Shevchenko dev_err(dev, "failed to register pinctrl driver\n"); 73964e14e90SAndy Shevchenko return PTR_ERR(lg->pctldev); 74064e14e90SAndy Shevchenko } 74164e14e90SAndy Shevchenko 742eb83479eSAndy Shevchenko platform_set_drvdata(pdev, lg); 743eb83479eSAndy Shevchenko 744eb83479eSAndy Shevchenko io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 745eb83479eSAndy Shevchenko if (!io_rc) { 746eb83479eSAndy Shevchenko dev_err(dev, "missing IO resources\n"); 747eb83479eSAndy Shevchenko return -EINVAL; 748eb83479eSAndy Shevchenko } 749eb83479eSAndy Shevchenko 750e1940adeSAndy Shevchenko regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); 751e1940adeSAndy Shevchenko if (!regs) { 752e1940adeSAndy Shevchenko dev_err(dev, "failed mapping IO region %pR\n", &io_rc); 753eb83479eSAndy Shevchenko return -EBUSY; 754eb83479eSAndy Shevchenko } 755eb83479eSAndy Shevchenko 75618213ad4SAndy Shevchenko for (i = 0; i < lg->soc->ncommunities; i++) { 75718213ad4SAndy Shevchenko struct intel_community *comm = &lg->communities[i]; 75818213ad4SAndy Shevchenko 75918213ad4SAndy Shevchenko *comm = lg->soc->communities[i]; 76018213ad4SAndy Shevchenko 76118213ad4SAndy Shevchenko comm->regs = regs; 76218213ad4SAndy Shevchenko comm->pad_regs = regs + 0x100; 76318213ad4SAndy Shevchenko } 764e1940adeSAndy Shevchenko 765b2e05d63SAndy Shevchenko raw_spin_lock_init(&lg->lock); 766eb83479eSAndy Shevchenko 767eb83479eSAndy Shevchenko gc = &lg->chip; 768eb83479eSAndy Shevchenko gc->label = dev_name(dev); 769eb83479eSAndy Shevchenko gc->owner = THIS_MODULE; 77064e14e90SAndy Shevchenko gc->request = gpiochip_generic_request; 77164e14e90SAndy Shevchenko gc->free = gpiochip_generic_free; 772eb83479eSAndy Shevchenko gc->direction_input = lp_gpio_direction_input; 773eb83479eSAndy Shevchenko gc->direction_output = lp_gpio_direction_output; 774eb83479eSAndy Shevchenko gc->get = lp_gpio_get; 775eb83479eSAndy Shevchenko gc->set = lp_gpio_set; 7761d112baaSAndy Shevchenko gc->set_config = gpiochip_generic_config; 77754d371cfSAndy Shevchenko gc->get_direction = lp_gpio_get_direction; 778eb83479eSAndy Shevchenko gc->base = -1; 779eb83479eSAndy Shevchenko gc->ngpio = LP_NUM_GPIO; 780eb83479eSAndy Shevchenko gc->can_sleep = false; 7813683509cSAndy Shevchenko gc->add_pin_ranges = lp_gpio_add_pin_ranges; 782eb83479eSAndy Shevchenko gc->parent = dev; 783eb83479eSAndy Shevchenko 784eb83479eSAndy Shevchenko /* set up interrupts */ 7855f3b82a1SAndy Shevchenko irq = platform_get_irq_optional(pdev, 0); 7865f3b82a1SAndy Shevchenko if (irq > 0) { 787eb83479eSAndy Shevchenko struct gpio_irq_chip *girq; 788eb83479eSAndy Shevchenko 789eb83479eSAndy Shevchenko girq = &gc->irq; 790180f9db7SAndy Shevchenko gpio_irq_chip_set_chip(girq, &lp_irqchip); 791eb83479eSAndy Shevchenko girq->init_hw = lp_gpio_irq_init_hw; 792eb83479eSAndy Shevchenko girq->parent_handler = lp_gpio_irq_handler; 793eb83479eSAndy Shevchenko girq->num_parents = 1; 7941e78ea71SAndy Shevchenko girq->parents = devm_kcalloc(dev, girq->num_parents, 795eb83479eSAndy Shevchenko sizeof(*girq->parents), 796eb83479eSAndy Shevchenko GFP_KERNEL); 797eb83479eSAndy Shevchenko if (!girq->parents) 798eb83479eSAndy Shevchenko return -ENOMEM; 7995f3b82a1SAndy Shevchenko girq->parents[0] = irq; 800eb83479eSAndy Shevchenko girq->default_type = IRQ_TYPE_NONE; 801eb83479eSAndy Shevchenko girq->handler = handle_bad_irq; 802eb83479eSAndy Shevchenko } 803eb83479eSAndy Shevchenko 804eb83479eSAndy Shevchenko ret = devm_gpiochip_add_data(dev, gc, lg); 805eb83479eSAndy Shevchenko if (ret) { 806eb83479eSAndy Shevchenko dev_err(dev, "failed adding lp-gpio chip\n"); 807eb83479eSAndy Shevchenko return ret; 808eb83479eSAndy Shevchenko } 809eb83479eSAndy Shevchenko 810eb83479eSAndy Shevchenko return 0; 811eb83479eSAndy Shevchenko } 812eb83479eSAndy Shevchenko 813eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev) 814eb83479eSAndy Shevchenko { 81518213ad4SAndy Shevchenko struct intel_pinctrl *lg = dev_get_drvdata(dev); 816f3e7d281SAndy Shevchenko struct gpio_chip *chip = &lg->chip; 817f3e7d281SAndy Shevchenko const char *dummy; 818eb83479eSAndy Shevchenko int i; 819eb83479eSAndy Shevchenko 820eb83479eSAndy Shevchenko /* on some hardware suspend clears input sensing, re-enable it here */ 8210472567bSAndy Shevchenko for_each_requested_gpio(chip, i, dummy) 8220472567bSAndy Shevchenko lp_gpio_enable_input(lp_gpio_reg(chip, i, LP_CONFIG2)); 823f3e7d281SAndy Shevchenko 824eb83479eSAndy Shevchenko return 0; 825eb83479eSAndy Shevchenko } 826eb83479eSAndy Shevchenko 82767c9e830SRaag Jadav static DEFINE_SIMPLE_DEV_PM_OPS(lp_gpio_pm_ops, NULL, lp_gpio_resume); 828eb83479eSAndy Shevchenko 829eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 830cecddda7SAndy Shevchenko { "INT33C7", (kernel_ulong_t)&lptlp_soc_data }, 831cecddda7SAndy Shevchenko { "INT3437", (kernel_ulong_t)&lptlp_soc_data }, 832eb83479eSAndy Shevchenko { } 833eb83479eSAndy Shevchenko }; 834eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 835eb83479eSAndy Shevchenko 836eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = { 837eb83479eSAndy Shevchenko .probe = lp_gpio_probe, 838eb83479eSAndy Shevchenko .driver = { 839eb83479eSAndy Shevchenko .name = "lp_gpio", 84067c9e830SRaag Jadav .pm = pm_sleep_ptr(&lp_gpio_pm_ops), 841e359a6f0SAndy Shevchenko .acpi_match_table = lynxpoint_gpio_acpi_match, 842eb83479eSAndy Shevchenko }, 843eb83479eSAndy Shevchenko }; 844eb83479eSAndy Shevchenko 845eb83479eSAndy Shevchenko static int __init lp_gpio_init(void) 846eb83479eSAndy Shevchenko { 847eb83479eSAndy Shevchenko return platform_driver_register(&lp_gpio_driver); 848eb83479eSAndy Shevchenko } 8490ddebf85SAndy Shevchenko subsys_initcall(lp_gpio_init); 850eb83479eSAndy Shevchenko 851eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void) 852eb83479eSAndy Shevchenko { 853eb83479eSAndy Shevchenko platform_driver_unregister(&lp_gpio_driver); 854eb83479eSAndy Shevchenko } 855eb83479eSAndy Shevchenko module_exit(lp_gpio_exit); 856eb83479eSAndy Shevchenko 857eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)"); 8583a67fe38SAndy Shevchenko MODULE_AUTHOR("Andy Shevchenko (Intel)"); 8593a67fe38SAndy Shevchenko MODULE_DESCRIPTION("Intel Lynxpoint pinctrl driver"); 860eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2"); 861eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio"); 862976cf4a6SRaag Jadav MODULE_IMPORT_NS(PINCTRL_INTEL); 863