162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel Lynxpoint PCH pinctrl/GPIO driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012, 2019, Intel Corporation 662306a36Sopenharmony_ci * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> 762306a36Sopenharmony_ci * Andy Shevchenko <andriy.shevchenko@linux.intel.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/acpi.h> 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <linux/seq_file.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2562306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2662306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2762306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "pinctrl-intel.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define COMMUNITY(p, n) \ 3262306a36Sopenharmony_ci { \ 3362306a36Sopenharmony_ci .pin_base = (p), \ 3462306a36Sopenharmony_ci .npins = (n), \ 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const struct pinctrl_pin_desc lptlp_pins[] = { 3862306a36Sopenharmony_ci PINCTRL_PIN(0, "GP0_UART1_RXD"), 3962306a36Sopenharmony_ci PINCTRL_PIN(1, "GP1_UART1_TXD"), 4062306a36Sopenharmony_ci PINCTRL_PIN(2, "GP2_UART1_RTSB"), 4162306a36Sopenharmony_ci PINCTRL_PIN(3, "GP3_UART1_CTSB"), 4262306a36Sopenharmony_ci PINCTRL_PIN(4, "GP4_I2C0_SDA"), 4362306a36Sopenharmony_ci PINCTRL_PIN(5, "GP5_I2C0_SCL"), 4462306a36Sopenharmony_ci PINCTRL_PIN(6, "GP6_I2C1_SDA"), 4562306a36Sopenharmony_ci PINCTRL_PIN(7, "GP7_I2C1_SCL"), 4662306a36Sopenharmony_ci PINCTRL_PIN(8, "GP8"), 4762306a36Sopenharmony_ci PINCTRL_PIN(9, "GP9"), 4862306a36Sopenharmony_ci PINCTRL_PIN(10, "GP10"), 4962306a36Sopenharmony_ci PINCTRL_PIN(11, "GP11_SMBALERTB"), 5062306a36Sopenharmony_ci PINCTRL_PIN(12, "GP12_LANPHYPC"), 5162306a36Sopenharmony_ci PINCTRL_PIN(13, "GP13"), 5262306a36Sopenharmony_ci PINCTRL_PIN(14, "GP14"), 5362306a36Sopenharmony_ci PINCTRL_PIN(15, "GP15"), 5462306a36Sopenharmony_ci PINCTRL_PIN(16, "GP16_MGPIO9"), 5562306a36Sopenharmony_ci PINCTRL_PIN(17, "GP17_MGPIO10"), 5662306a36Sopenharmony_ci PINCTRL_PIN(18, "GP18_SRC0CLKRQB"), 5762306a36Sopenharmony_ci PINCTRL_PIN(19, "GP19_SRC1CLKRQB"), 5862306a36Sopenharmony_ci PINCTRL_PIN(20, "GP20_SRC2CLKRQB"), 5962306a36Sopenharmony_ci PINCTRL_PIN(21, "GP21_SRC3CLKRQB"), 6062306a36Sopenharmony_ci PINCTRL_PIN(22, "GP22_SRC4CLKRQB_TRST2"), 6162306a36Sopenharmony_ci PINCTRL_PIN(23, "GP23_SRC5CLKRQB_TDI2"), 6262306a36Sopenharmony_ci PINCTRL_PIN(24, "GP24_MGPIO0"), 6362306a36Sopenharmony_ci PINCTRL_PIN(25, "GP25_USBWAKEOUTB"), 6462306a36Sopenharmony_ci PINCTRL_PIN(26, "GP26_MGPIO5"), 6562306a36Sopenharmony_ci PINCTRL_PIN(27, "GP27_MGPIO6"), 6662306a36Sopenharmony_ci PINCTRL_PIN(28, "GP28_MGPIO7"), 6762306a36Sopenharmony_ci PINCTRL_PIN(29, "GP29_SLP_WLANB_MGPIO3"), 6862306a36Sopenharmony_ci PINCTRL_PIN(30, "GP30_SUSWARNB_SUSPWRDNACK_MGPIO1"), 6962306a36Sopenharmony_ci PINCTRL_PIN(31, "GP31_ACPRESENT_MGPIO2"), 7062306a36Sopenharmony_ci PINCTRL_PIN(32, "GP32_CLKRUNB"), 7162306a36Sopenharmony_ci PINCTRL_PIN(33, "GP33_DEVSLP0"), 7262306a36Sopenharmony_ci PINCTRL_PIN(34, "GP34_SATA0XPCIE6L3B_SATA0GP"), 7362306a36Sopenharmony_ci PINCTRL_PIN(35, "GP35_SATA1XPCIE6L2B_SATA1GP"), 7462306a36Sopenharmony_ci PINCTRL_PIN(36, "GP36_SATA2XPCIE6L1B_SATA2GP"), 7562306a36Sopenharmony_ci PINCTRL_PIN(37, "GP37_SATA3XPCIE6L0B_SATA3GP"), 7662306a36Sopenharmony_ci PINCTRL_PIN(38, "GP38_DEVSLP1"), 7762306a36Sopenharmony_ci PINCTRL_PIN(39, "GP39_DEVSLP2"), 7862306a36Sopenharmony_ci PINCTRL_PIN(40, "GP40_OC0B"), 7962306a36Sopenharmony_ci PINCTRL_PIN(41, "GP41_OC1B"), 8062306a36Sopenharmony_ci PINCTRL_PIN(42, "GP42_OC2B"), 8162306a36Sopenharmony_ci PINCTRL_PIN(43, "GP43_OC3B"), 8262306a36Sopenharmony_ci PINCTRL_PIN(44, "GP44"), 8362306a36Sopenharmony_ci PINCTRL_PIN(45, "GP45_TMS2"), 8462306a36Sopenharmony_ci PINCTRL_PIN(46, "GP46_TDO2"), 8562306a36Sopenharmony_ci PINCTRL_PIN(47, "GP47"), 8662306a36Sopenharmony_ci PINCTRL_PIN(48, "GP48"), 8762306a36Sopenharmony_ci PINCTRL_PIN(49, "GP49"), 8862306a36Sopenharmony_ci PINCTRL_PIN(50, "GP50"), 8962306a36Sopenharmony_ci PINCTRL_PIN(51, "GP51_GSXDOUT"), 9062306a36Sopenharmony_ci PINCTRL_PIN(52, "GP52_GSXSLOAD"), 9162306a36Sopenharmony_ci PINCTRL_PIN(53, "GP53_GSXDIN"), 9262306a36Sopenharmony_ci PINCTRL_PIN(54, "GP54_GSXSRESETB"), 9362306a36Sopenharmony_ci PINCTRL_PIN(55, "GP55_GSXCLK"), 9462306a36Sopenharmony_ci PINCTRL_PIN(56, "GP56"), 9562306a36Sopenharmony_ci PINCTRL_PIN(57, "GP57"), 9662306a36Sopenharmony_ci PINCTRL_PIN(58, "GP58"), 9762306a36Sopenharmony_ci PINCTRL_PIN(59, "GP59"), 9862306a36Sopenharmony_ci PINCTRL_PIN(60, "GP60_SML0ALERTB_MGPIO4"), 9962306a36Sopenharmony_ci PINCTRL_PIN(61, "GP61_SUS_STATB"), 10062306a36Sopenharmony_ci PINCTRL_PIN(62, "GP62_SUSCLK"), 10162306a36Sopenharmony_ci PINCTRL_PIN(63, "GP63_SLP_S5B"), 10262306a36Sopenharmony_ci PINCTRL_PIN(64, "GP64_SDIO_CLK"), 10362306a36Sopenharmony_ci PINCTRL_PIN(65, "GP65_SDIO_CMD"), 10462306a36Sopenharmony_ci PINCTRL_PIN(66, "GP66_SDIO_D0"), 10562306a36Sopenharmony_ci PINCTRL_PIN(67, "GP67_SDIO_D1"), 10662306a36Sopenharmony_ci PINCTRL_PIN(68, "GP68_SDIO_D2"), 10762306a36Sopenharmony_ci PINCTRL_PIN(69, "GP69_SDIO_D3"), 10862306a36Sopenharmony_ci PINCTRL_PIN(70, "GP70_SDIO_POWER_EN"), 10962306a36Sopenharmony_ci PINCTRL_PIN(71, "GP71_MPHYPC"), 11062306a36Sopenharmony_ci PINCTRL_PIN(72, "GP72_BATLOWB"), 11162306a36Sopenharmony_ci PINCTRL_PIN(73, "GP73_SML1ALERTB_PCHHOTB_MGPIO8"), 11262306a36Sopenharmony_ci PINCTRL_PIN(74, "GP74_SML1DATA_MGPIO12"), 11362306a36Sopenharmony_ci PINCTRL_PIN(75, "GP75_SML1CLK_MGPIO11"), 11462306a36Sopenharmony_ci PINCTRL_PIN(76, "GP76_BMBUSYB"), 11562306a36Sopenharmony_ci PINCTRL_PIN(77, "GP77_PIRQAB"), 11662306a36Sopenharmony_ci PINCTRL_PIN(78, "GP78_PIRQBB"), 11762306a36Sopenharmony_ci PINCTRL_PIN(79, "GP79_PIRQCB"), 11862306a36Sopenharmony_ci PINCTRL_PIN(80, "GP80_PIRQDB"), 11962306a36Sopenharmony_ci PINCTRL_PIN(81, "GP81_SPKR"), 12062306a36Sopenharmony_ci PINCTRL_PIN(82, "GP82_RCINB"), 12162306a36Sopenharmony_ci PINCTRL_PIN(83, "GP83_GSPI0_CSB"), 12262306a36Sopenharmony_ci PINCTRL_PIN(84, "GP84_GSPI0_CLK"), 12362306a36Sopenharmony_ci PINCTRL_PIN(85, "GP85_GSPI0_MISO"), 12462306a36Sopenharmony_ci PINCTRL_PIN(86, "GP86_GSPI0_MOSI"), 12562306a36Sopenharmony_ci PINCTRL_PIN(87, "GP87_GSPI1_CSB"), 12662306a36Sopenharmony_ci PINCTRL_PIN(88, "GP88_GSPI1_CLK"), 12762306a36Sopenharmony_ci PINCTRL_PIN(89, "GP89_GSPI1_MISO"), 12862306a36Sopenharmony_ci PINCTRL_PIN(90, "GP90_GSPI1_MOSI"), 12962306a36Sopenharmony_ci PINCTRL_PIN(91, "GP91_UART0_RXD"), 13062306a36Sopenharmony_ci PINCTRL_PIN(92, "GP92_UART0_TXD"), 13162306a36Sopenharmony_ci PINCTRL_PIN(93, "GP93_UART0_RTSB"), 13262306a36Sopenharmony_ci PINCTRL_PIN(94, "GP94_UART0_CTSB"), 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const struct intel_community lptlp_communities[] = { 13662306a36Sopenharmony_ci COMMUNITY(0, 95), 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data lptlp_soc_data = { 14062306a36Sopenharmony_ci .pins = lptlp_pins, 14162306a36Sopenharmony_ci .npins = ARRAY_SIZE(lptlp_pins), 14262306a36Sopenharmony_ci .communities = lptlp_communities, 14362306a36Sopenharmony_ci .ncommunities = ARRAY_SIZE(lptlp_communities), 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* LynxPoint chipset has support for 95 GPIO pins */ 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define LP_NUM_GPIO 95 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Bitmapped register offsets */ 15162306a36Sopenharmony_ci#define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */ 15262306a36Sopenharmony_ci#define LP_IRQ2IOXAPIC 0x10 /* Bitmap, set by bios, 1: pin routed to IOxAPIC */ 15362306a36Sopenharmony_ci#define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */ 15462306a36Sopenharmony_ci#define LP_INT_STAT 0x80 15562306a36Sopenharmony_ci#define LP_INT_ENABLE 0x90 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* Each pin has two 32 bit config registers, starting at 0x100 */ 15862306a36Sopenharmony_ci#define LP_CONFIG1 0x100 15962306a36Sopenharmony_ci#define LP_CONFIG2 0x104 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* LP_CONFIG1 reg bits */ 16262306a36Sopenharmony_ci#define OUT_LVL_BIT BIT(31) 16362306a36Sopenharmony_ci#define IN_LVL_BIT BIT(30) 16462306a36Sopenharmony_ci#define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */ 16562306a36Sopenharmony_ci#define INT_INV_BIT BIT(3) /* Invert interrupt triggering */ 16662306a36Sopenharmony_ci#define DIR_BIT BIT(2) /* 0: Output, 1: Input */ 16762306a36Sopenharmony_ci#define USE_SEL_MASK GENMASK(1, 0) /* 0: Native, 1: GPIO, ... */ 16862306a36Sopenharmony_ci#define USE_SEL_NATIVE (0 << 0) 16962306a36Sopenharmony_ci#define USE_SEL_GPIO (1 << 0) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* LP_CONFIG2 reg bits */ 17262306a36Sopenharmony_ci#define GPINDIS_BIT BIT(2) /* disable input sensing */ 17362306a36Sopenharmony_ci#define GPIWP_MASK GENMASK(1, 0) /* weak pull options */ 17462306a36Sopenharmony_ci#define GPIWP_NONE 0 /* none */ 17562306a36Sopenharmony_ci#define GPIWP_DOWN 1 /* weak pull down */ 17662306a36Sopenharmony_ci#define GPIWP_UP 2 /* weak pull up */ 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * Lynxpoint gpios are controlled through both bitmapped registers and 18062306a36Sopenharmony_ci * per gpio specific registers. The bitmapped registers are in chunks of 18162306a36Sopenharmony_ci * 3 x 32bit registers to cover all 95 GPIOs 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * per gpio specific registers consist of two 32bit registers per gpio 18462306a36Sopenharmony_ci * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of 18562306a36Sopenharmony_ci * 190 config registers. 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * A simplified view of the register layout look like this: 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers) 19062306a36Sopenharmony_ci * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63 19162306a36Sopenharmony_ci * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94 19262306a36Sopenharmony_ci * ... 19362306a36Sopenharmony_ci * LP_INT_ENABLE[31:0] ... 19462306a36Sopenharmony_ci * LP_INT_ENABLE[63:32] ... 19562306a36Sopenharmony_ci * LP_INT_ENABLE[94:64] ... 19662306a36Sopenharmony_ci * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers) 19762306a36Sopenharmony_ci * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0 19862306a36Sopenharmony_ci * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1 19962306a36Sopenharmony_ci * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1 20062306a36Sopenharmony_ci * LP2_CONFIG1 (gpio 2) ... 20162306a36Sopenharmony_ci * LP2_CONFIG2 (gpio 2) ... 20262306a36Sopenharmony_ci * ... 20362306a36Sopenharmony_ci * LP94_CONFIG1 (gpio 94) ... 20462306a36Sopenharmony_ci * LP94_CONFIG2 (gpio 94) ... 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * IOxAPIC redirection map applies only for gpio 8-10, 13-14, 45-55. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset, 21062306a36Sopenharmony_ci int reg) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(chip); 21362306a36Sopenharmony_ci struct intel_community *comm; 21462306a36Sopenharmony_ci int reg_offset; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci comm = intel_get_community(lg, offset); 21762306a36Sopenharmony_ci if (!comm) 21862306a36Sopenharmony_ci return NULL; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci offset -= comm->pin_base; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (reg == LP_CONFIG1 || reg == LP_CONFIG2) 22362306a36Sopenharmony_ci /* per gpio specific config registers */ 22462306a36Sopenharmony_ci reg_offset = offset * 8; 22562306a36Sopenharmony_ci else 22662306a36Sopenharmony_ci /* bitmapped registers */ 22762306a36Sopenharmony_ci reg_offset = (offset / 32) * 4; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return comm->regs + reg_offset + reg; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic bool lp_gpio_acpi_use(struct intel_pinctrl *lg, unsigned int pin) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci void __iomem *acpi_use; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED); 23762306a36Sopenharmony_ci if (!acpi_use) 23862306a36Sopenharmony_ci return true; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci return !(ioread32(acpi_use) & BIT(pin % 32)); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic bool lp_gpio_ioxapic_use(struct gpio_chip *chip, unsigned int offset) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci void __iomem *ioxapic_use = lp_gpio_reg(chip, offset, LP_IRQ2IOXAPIC); 24662306a36Sopenharmony_ci u32 value; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci value = ioread32(ioxapic_use); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (offset >= 8 && offset <= 10) 25162306a36Sopenharmony_ci return !!(value & BIT(offset - 8 + 0)); 25262306a36Sopenharmony_ci if (offset >= 13 && offset <= 14) 25362306a36Sopenharmony_ci return !!(value & BIT(offset - 13 + 3)); 25462306a36Sopenharmony_ci if (offset >= 45 && offset <= 55) 25562306a36Sopenharmony_ci return !!(value & BIT(offset - 45 + 5)); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return false; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void lp_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 26162306a36Sopenharmony_ci unsigned int pin) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 26462306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 26562306a36Sopenharmony_ci void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 26662306a36Sopenharmony_ci u32 value, mode; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci value = ioread32(reg); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci mode = value & USE_SEL_MASK; 27162306a36Sopenharmony_ci if (mode == USE_SEL_GPIO) 27262306a36Sopenharmony_ci seq_puts(s, "GPIO "); 27362306a36Sopenharmony_ci else 27462306a36Sopenharmony_ci seq_printf(s, "mode %d ", mode); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci seq_printf(s, "0x%08x 0x%08x", value, ioread32(conf2)); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (lp_gpio_acpi_use(lg, pin)) 27962306a36Sopenharmony_ci seq_puts(s, " [ACPI]"); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic const struct pinctrl_ops lptlp_pinctrl_ops = { 28362306a36Sopenharmony_ci .get_groups_count = intel_get_groups_count, 28462306a36Sopenharmony_ci .get_group_name = intel_get_group_name, 28562306a36Sopenharmony_ci .get_group_pins = intel_get_group_pins, 28662306a36Sopenharmony_ci .pin_dbg_show = lp_pin_dbg_show, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int lp_pinmux_set_mux(struct pinctrl_dev *pctldev, 29062306a36Sopenharmony_ci unsigned int function, unsigned int group) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 29362306a36Sopenharmony_ci const struct intel_pingroup *grp = &lg->soc->groups[group]; 29462306a36Sopenharmony_ci unsigned long flags; 29562306a36Sopenharmony_ci int i; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Now enable the mux setting for each pin in the group */ 30062306a36Sopenharmony_ci for (i = 0; i < grp->grp.npins; i++) { 30162306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, grp->grp.pins[i], LP_CONFIG1); 30262306a36Sopenharmony_ci u32 value; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci value = ioread32(reg); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci value &= ~USE_SEL_MASK; 30762306a36Sopenharmony_ci if (grp->modes) 30862306a36Sopenharmony_ci value |= grp->modes[i]; 30962306a36Sopenharmony_ci else 31062306a36Sopenharmony_ci value |= grp->mode; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci iowrite32(value, reg); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic void lp_gpio_enable_input(void __iomem *reg) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void lp_gpio_disable_input(void __iomem *reg) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci iowrite32(ioread32(reg) | GPINDIS_BIT, reg); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic int lp_gpio_request_enable(struct pinctrl_dev *pctldev, 33162306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 33262306a36Sopenharmony_ci unsigned int pin) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 33562306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 33662306a36Sopenharmony_ci void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 33762306a36Sopenharmony_ci unsigned long flags; 33862306a36Sopenharmony_ci u32 value; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci pm_runtime_get(lg->dev); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * Reconfigure pin to GPIO mode if needed and issue a warning, 34662306a36Sopenharmony_ci * since we expect firmware to configure it properly. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci value = ioread32(reg); 34962306a36Sopenharmony_ci if ((value & USE_SEL_MASK) != USE_SEL_GPIO) { 35062306a36Sopenharmony_ci iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg); 35162306a36Sopenharmony_ci dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", pin); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Enable input sensing */ 35562306a36Sopenharmony_ci lp_gpio_enable_input(conf2); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void lp_gpio_disable_free(struct pinctrl_dev *pctldev, 36362306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 36462306a36Sopenharmony_ci unsigned int pin) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 36762306a36Sopenharmony_ci void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 36862306a36Sopenharmony_ci unsigned long flags; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Disable input sensing */ 37362306a36Sopenharmony_ci lp_gpio_disable_input(conf2); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci pm_runtime_put(lg->dev); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int lp_gpio_set_direction(struct pinctrl_dev *pctldev, 38162306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 38262306a36Sopenharmony_ci unsigned int pin, bool input) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 38562306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1); 38662306a36Sopenharmony_ci unsigned long flags; 38762306a36Sopenharmony_ci u32 value; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci value = ioread32(reg); 39262306a36Sopenharmony_ci value &= ~DIR_BIT; 39362306a36Sopenharmony_ci if (input) { 39462306a36Sopenharmony_ci value |= DIR_BIT; 39562306a36Sopenharmony_ci } else { 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * Before making any direction modifications, do a check if GPIO 39862306a36Sopenharmony_ci * is set for direct IRQ. On Lynxpoint, setting GPIO to output 39962306a36Sopenharmony_ci * does not make sense, so let's at least warn the caller before 40062306a36Sopenharmony_ci * they shoot themselves in the foot. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci WARN(lp_gpio_ioxapic_use(&lg->chip, pin), 40362306a36Sopenharmony_ci "Potential Error: Setting GPIO to output with IOxAPIC redirection"); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci iowrite32(value, reg); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic const struct pinmux_ops lptlp_pinmux_ops = { 41362306a36Sopenharmony_ci .get_functions_count = intel_get_functions_count, 41462306a36Sopenharmony_ci .get_function_name = intel_get_function_name, 41562306a36Sopenharmony_ci .get_function_groups = intel_get_function_groups, 41662306a36Sopenharmony_ci .set_mux = lp_pinmux_set_mux, 41762306a36Sopenharmony_ci .gpio_request_enable = lp_gpio_request_enable, 41862306a36Sopenharmony_ci .gpio_disable_free = lp_gpio_disable_free, 41962306a36Sopenharmony_ci .gpio_set_direction = lp_gpio_set_direction, 42062306a36Sopenharmony_ci}; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int lp_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 42362306a36Sopenharmony_ci unsigned long *config) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 42662306a36Sopenharmony_ci void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 42762306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 42862306a36Sopenharmony_ci unsigned long flags; 42962306a36Sopenharmony_ci u32 value, pull; 43062306a36Sopenharmony_ci u16 arg; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 43362306a36Sopenharmony_ci value = ioread32(conf2); 43462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci pull = value & GPIWP_MASK; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci switch (param) { 43962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 44062306a36Sopenharmony_ci if (pull != GPIWP_NONE) 44162306a36Sopenharmony_ci return -EINVAL; 44262306a36Sopenharmony_ci arg = 0; 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 44562306a36Sopenharmony_ci if (pull != GPIWP_DOWN) 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci arg = 1; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 45162306a36Sopenharmony_ci if (pull != GPIWP_UP) 45262306a36Sopenharmony_ci return -EINVAL; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci arg = 1; 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci default: 45762306a36Sopenharmony_ci return -ENOTSUPP; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int lp_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 46662306a36Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev); 46962306a36Sopenharmony_ci void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2); 47062306a36Sopenharmony_ci enum pin_config_param param; 47162306a36Sopenharmony_ci unsigned long flags; 47262306a36Sopenharmony_ci int i, ret = 0; 47362306a36Sopenharmony_ci u32 value; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci value = ioread32(conf2); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 48062306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci switch (param) { 48362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 48462306a36Sopenharmony_ci value &= ~GPIWP_MASK; 48562306a36Sopenharmony_ci value |= GPIWP_NONE; 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 48862306a36Sopenharmony_ci value &= ~GPIWP_MASK; 48962306a36Sopenharmony_ci value |= GPIWP_DOWN; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 49262306a36Sopenharmony_ci value &= ~GPIWP_MASK; 49362306a36Sopenharmony_ci value |= GPIWP_UP; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci default: 49662306a36Sopenharmony_ci ret = -ENOTSUPP; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (ret) 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!ret) 50462306a36Sopenharmony_ci iowrite32(value, conf2); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return ret; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic const struct pinconf_ops lptlp_pinconf_ops = { 51262306a36Sopenharmony_ci .is_generic = true, 51362306a36Sopenharmony_ci .pin_config_get = lp_pin_config_get, 51462306a36Sopenharmony_ci .pin_config_set = lp_pin_config_set, 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct pinctrl_desc lptlp_pinctrl_desc = { 51862306a36Sopenharmony_ci .pctlops = &lptlp_pinctrl_ops, 51962306a36Sopenharmony_ci .pmxops = &lptlp_pinmux_ops, 52062306a36Sopenharmony_ci .confops = &lptlp_pinconf_ops, 52162306a36Sopenharmony_ci .owner = THIS_MODULE, 52262306a36Sopenharmony_ci}; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int lp_gpio_get(struct gpio_chip *chip, unsigned int offset) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 52762306a36Sopenharmony_ci return !!(ioread32(reg) & IN_LVL_BIT); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(chip); 53362306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 53462306a36Sopenharmony_ci unsigned long flags; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (value) 53962306a36Sopenharmony_ci iowrite32(ioread32(reg) | OUT_LVL_BIT, reg); 54062306a36Sopenharmony_ci else 54162306a36Sopenharmony_ci iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 55262306a36Sopenharmony_ci int value) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci lp_gpio_set(chip, offset, value); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + offset); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (ioread32(reg) & DIR_BIT) 56462306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic void lp_gpio_irq_handler(struct irq_desc *desc) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct irq_data *data = irq_desc_get_irq_data(desc); 57262306a36Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 57362306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(gc); 57462306a36Sopenharmony_ci struct irq_chip *chip = irq_data_get_irq_chip(data); 57562306a36Sopenharmony_ci void __iomem *reg, *ena; 57662306a36Sopenharmony_ci unsigned long pending; 57762306a36Sopenharmony_ci u32 base, pin; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* check from GPIO controller which pin triggered the interrupt */ 58062306a36Sopenharmony_ci for (base = 0; base < lg->chip.ngpio; base += 32) { 58162306a36Sopenharmony_ci reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 58262306a36Sopenharmony_ci ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Only interrupts that are enabled */ 58562306a36Sopenharmony_ci pending = ioread32(reg) & ioread32(ena); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci for_each_set_bit(pin, &pending, 32) 58862306a36Sopenharmony_ci generic_handle_domain_irq(lg->chip.irq.domain, base + pin); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci chip->irq_eoi(data); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void lp_irq_ack(struct irq_data *d) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 59662306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(gc); 59762306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 59862306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT); 59962306a36Sopenharmony_ci unsigned long flags; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 60262306a36Sopenharmony_ci iowrite32(BIT(hwirq % 32), reg); 60362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void lp_irq_unmask(struct irq_data *d) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void lp_irq_mask(struct irq_data *d) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic void lp_irq_enable(struct irq_data *d) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 61762306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(gc); 61862306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 61962306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 62062306a36Sopenharmony_ci unsigned long flags; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci gpiochip_enable_irq(gc, hwirq); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 62562306a36Sopenharmony_ci iowrite32(ioread32(reg) | BIT(hwirq % 32), reg); 62662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic void lp_irq_disable(struct irq_data *d) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 63262306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(gc); 63362306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 63462306a36Sopenharmony_ci void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE); 63562306a36Sopenharmony_ci unsigned long flags; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 63862306a36Sopenharmony_ci iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg); 63962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci gpiochip_disable_irq(gc, hwirq); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int lp_irq_set_type(struct irq_data *d, unsigned int type) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 64762306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(gc); 64862306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 64962306a36Sopenharmony_ci unsigned long flags; 65062306a36Sopenharmony_ci void __iomem *reg; 65162306a36Sopenharmony_ci u32 value; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1); 65462306a36Sopenharmony_ci if (!reg) 65562306a36Sopenharmony_ci return -EINVAL; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Fail if BIOS reserved pin for ACPI use */ 65862306a36Sopenharmony_ci if (lp_gpio_acpi_use(lg, hwirq)) { 65962306a36Sopenharmony_ci dev_err(lg->dev, "pin %lu can't be used as IRQ\n", hwirq); 66062306a36Sopenharmony_ci return -EBUSY; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci raw_spin_lock_irqsave(&lg->lock, flags); 66462306a36Sopenharmony_ci value = ioread32(reg); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* set both TRIG_SEL and INV bits to 0 for rising edge */ 66762306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 66862306a36Sopenharmony_ci value &= ~(TRIG_SEL_BIT | INT_INV_BIT); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* TRIG_SEL bit 0, INV bit 1 for falling edge */ 67162306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 67262306a36Sopenharmony_ci value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* TRIG_SEL bit 1, INV bit 0 for level low */ 67562306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 67662306a36Sopenharmony_ci value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* TRIG_SEL bit 1, INV bit 1 for level high */ 67962306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_HIGH) 68062306a36Sopenharmony_ci value |= TRIG_SEL_BIT | INT_INV_BIT; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci iowrite32(value, reg); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) 68562306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 68662306a36Sopenharmony_ci else if (type & IRQ_TYPE_LEVEL_MASK) 68762306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&lg->lock, flags); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic const struct irq_chip lp_irqchip = { 69562306a36Sopenharmony_ci .name = "LP-GPIO", 69662306a36Sopenharmony_ci .irq_ack = lp_irq_ack, 69762306a36Sopenharmony_ci .irq_mask = lp_irq_mask, 69862306a36Sopenharmony_ci .irq_unmask = lp_irq_unmask, 69962306a36Sopenharmony_ci .irq_enable = lp_irq_enable, 70062306a36Sopenharmony_ci .irq_disable = lp_irq_disable, 70162306a36Sopenharmony_ci .irq_set_type = lp_irq_set_type, 70262306a36Sopenharmony_ci .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, 70362306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 70462306a36Sopenharmony_ci}; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int lp_gpio_irq_init_hw(struct gpio_chip *chip) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(chip); 70962306a36Sopenharmony_ci void __iomem *reg; 71062306a36Sopenharmony_ci unsigned int base; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci for (base = 0; base < lg->chip.ngpio; base += 32) { 71362306a36Sopenharmony_ci /* disable gpio pin interrupts */ 71462306a36Sopenharmony_ci reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); 71562306a36Sopenharmony_ci iowrite32(0, reg); 71662306a36Sopenharmony_ci /* Clear interrupt status register */ 71762306a36Sopenharmony_ci reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT); 71862306a36Sopenharmony_ci iowrite32(0xffffffff, reg); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int lp_gpio_add_pin_ranges(struct gpio_chip *chip) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct intel_pinctrl *lg = gpiochip_get_data(chip); 72762306a36Sopenharmony_ci struct device *dev = lg->dev; 72862306a36Sopenharmony_ci int ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = gpiochip_add_pin_range(chip, dev_name(dev), 0, 0, lg->soc->npins); 73162306a36Sopenharmony_ci if (ret) 73262306a36Sopenharmony_ci dev_err(dev, "failed to add GPIO pin range\n"); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return ret; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int lp_gpio_probe(struct platform_device *pdev) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci const struct intel_pinctrl_soc_data *soc; 74062306a36Sopenharmony_ci struct intel_pinctrl *lg; 74162306a36Sopenharmony_ci struct gpio_chip *gc; 74262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 74362306a36Sopenharmony_ci struct resource *io_rc; 74462306a36Sopenharmony_ci void __iomem *regs; 74562306a36Sopenharmony_ci unsigned int i; 74662306a36Sopenharmony_ci int irq, ret; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci soc = (const struct intel_pinctrl_soc_data *)device_get_match_data(dev); 74962306a36Sopenharmony_ci if (!soc) 75062306a36Sopenharmony_ci return -ENODEV; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL); 75362306a36Sopenharmony_ci if (!lg) 75462306a36Sopenharmony_ci return -ENOMEM; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci lg->dev = dev; 75762306a36Sopenharmony_ci lg->soc = soc; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci lg->ncommunities = lg->soc->ncommunities; 76062306a36Sopenharmony_ci lg->communities = devm_kcalloc(dev, lg->ncommunities, 76162306a36Sopenharmony_ci sizeof(*lg->communities), GFP_KERNEL); 76262306a36Sopenharmony_ci if (!lg->communities) 76362306a36Sopenharmony_ci return -ENOMEM; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci lg->pctldesc = lptlp_pinctrl_desc; 76662306a36Sopenharmony_ci lg->pctldesc.name = dev_name(dev); 76762306a36Sopenharmony_ci lg->pctldesc.pins = lg->soc->pins; 76862306a36Sopenharmony_ci lg->pctldesc.npins = lg->soc->npins; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci lg->pctldev = devm_pinctrl_register(dev, &lg->pctldesc, lg); 77162306a36Sopenharmony_ci if (IS_ERR(lg->pctldev)) { 77262306a36Sopenharmony_ci dev_err(dev, "failed to register pinctrl driver\n"); 77362306a36Sopenharmony_ci return PTR_ERR(lg->pctldev); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci platform_set_drvdata(pdev, lg); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); 77962306a36Sopenharmony_ci if (!io_rc) { 78062306a36Sopenharmony_ci dev_err(dev, "missing IO resources\n"); 78162306a36Sopenharmony_ci return -EINVAL; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc)); 78562306a36Sopenharmony_ci if (!regs) { 78662306a36Sopenharmony_ci dev_err(dev, "failed mapping IO region %pR\n", &io_rc); 78762306a36Sopenharmony_ci return -EBUSY; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci for (i = 0; i < lg->soc->ncommunities; i++) { 79162306a36Sopenharmony_ci struct intel_community *comm = &lg->communities[i]; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci *comm = lg->soc->communities[i]; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci comm->regs = regs; 79662306a36Sopenharmony_ci comm->pad_regs = regs + 0x100; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci raw_spin_lock_init(&lg->lock); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci gc = &lg->chip; 80262306a36Sopenharmony_ci gc->label = dev_name(dev); 80362306a36Sopenharmony_ci gc->owner = THIS_MODULE; 80462306a36Sopenharmony_ci gc->request = gpiochip_generic_request; 80562306a36Sopenharmony_ci gc->free = gpiochip_generic_free; 80662306a36Sopenharmony_ci gc->direction_input = lp_gpio_direction_input; 80762306a36Sopenharmony_ci gc->direction_output = lp_gpio_direction_output; 80862306a36Sopenharmony_ci gc->get = lp_gpio_get; 80962306a36Sopenharmony_ci gc->set = lp_gpio_set; 81062306a36Sopenharmony_ci gc->set_config = gpiochip_generic_config; 81162306a36Sopenharmony_ci gc->get_direction = lp_gpio_get_direction; 81262306a36Sopenharmony_ci gc->base = -1; 81362306a36Sopenharmony_ci gc->ngpio = LP_NUM_GPIO; 81462306a36Sopenharmony_ci gc->can_sleep = false; 81562306a36Sopenharmony_ci gc->add_pin_ranges = lp_gpio_add_pin_ranges; 81662306a36Sopenharmony_ci gc->parent = dev; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* set up interrupts */ 81962306a36Sopenharmony_ci irq = platform_get_irq_optional(pdev, 0); 82062306a36Sopenharmony_ci if (irq > 0) { 82162306a36Sopenharmony_ci struct gpio_irq_chip *girq; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci girq = &gc->irq; 82462306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &lp_irqchip); 82562306a36Sopenharmony_ci girq->init_hw = lp_gpio_irq_init_hw; 82662306a36Sopenharmony_ci girq->parent_handler = lp_gpio_irq_handler; 82762306a36Sopenharmony_ci girq->num_parents = 1; 82862306a36Sopenharmony_ci girq->parents = devm_kcalloc(dev, girq->num_parents, 82962306a36Sopenharmony_ci sizeof(*girq->parents), 83062306a36Sopenharmony_ci GFP_KERNEL); 83162306a36Sopenharmony_ci if (!girq->parents) 83262306a36Sopenharmony_ci return -ENOMEM; 83362306a36Sopenharmony_ci girq->parents[0] = irq; 83462306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 83562306a36Sopenharmony_ci girq->handler = handle_bad_irq; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, gc, lg); 83962306a36Sopenharmony_ci if (ret) { 84062306a36Sopenharmony_ci dev_err(dev, "failed adding lp-gpio chip\n"); 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci pm_runtime_enable(dev); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int lp_gpio_remove(struct platform_device *pdev) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int lp_gpio_runtime_suspend(struct device *dev) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic int lp_gpio_runtime_resume(struct device *dev) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci return 0; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int lp_gpio_resume(struct device *dev) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct intel_pinctrl *lg = dev_get_drvdata(dev); 86862306a36Sopenharmony_ci struct gpio_chip *chip = &lg->chip; 86962306a36Sopenharmony_ci const char *dummy; 87062306a36Sopenharmony_ci int i; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* on some hardware suspend clears input sensing, re-enable it here */ 87362306a36Sopenharmony_ci for_each_requested_gpio(chip, i, dummy) 87462306a36Sopenharmony_ci lp_gpio_enable_input(lp_gpio_reg(chip, i, LP_CONFIG2)); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic const struct dev_pm_ops lp_gpio_pm_ops = { 88062306a36Sopenharmony_ci SYSTEM_SLEEP_PM_OPS(NULL, lp_gpio_resume) 88162306a36Sopenharmony_ci RUNTIME_PM_OPS(lp_gpio_runtime_suspend, lp_gpio_runtime_resume, NULL) 88262306a36Sopenharmony_ci}; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic const struct acpi_device_id lynxpoint_gpio_acpi_match[] = { 88562306a36Sopenharmony_ci { "INT33C7", (kernel_ulong_t)&lptlp_soc_data }, 88662306a36Sopenharmony_ci { "INT3437", (kernel_ulong_t)&lptlp_soc_data }, 88762306a36Sopenharmony_ci { } 88862306a36Sopenharmony_ci}; 88962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic struct platform_driver lp_gpio_driver = { 89262306a36Sopenharmony_ci .probe = lp_gpio_probe, 89362306a36Sopenharmony_ci .remove = lp_gpio_remove, 89462306a36Sopenharmony_ci .driver = { 89562306a36Sopenharmony_ci .name = "lp_gpio", 89662306a36Sopenharmony_ci .pm = pm_ptr(&lp_gpio_pm_ops), 89762306a36Sopenharmony_ci .acpi_match_table = lynxpoint_gpio_acpi_match, 89862306a36Sopenharmony_ci }, 89962306a36Sopenharmony_ci}; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int __init lp_gpio_init(void) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci return platform_driver_register(&lp_gpio_driver); 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_cisubsys_initcall(lp_gpio_init); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic void __exit lp_gpio_exit(void) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci platform_driver_unregister(&lp_gpio_driver); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_cimodule_exit(lp_gpio_exit); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ciMODULE_AUTHOR("Mathias Nyman (Intel)"); 91462306a36Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko (Intel)"); 91562306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Lynxpoint pinctrl driver"); 91662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 91762306a36Sopenharmony_ciMODULE_ALIAS("platform:lp_gpio"); 91862306a36Sopenharmony_ciMODULE_IMPORT_NS(PINCTRL_INTEL); 919