162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cherryview/Braswell pinctrl driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014, 2020 Intel Corporation 662306a36Sopenharmony_ci * Author: Mika Westerberg <mika.westerberg@linux.intel.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This driver is based on the original Cherryview GPIO driver by 962306a36Sopenharmony_ci * Ning Li <ning.li@intel.com> 1062306a36Sopenharmony_ci * Alan Cox <alan@linux.intel.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/acpi.h> 1462306a36Sopenharmony_ci#include <linux/dmi.h> 1562306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/seq_file.h> 2062306a36Sopenharmony_ci#include <linux/types.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2362306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2562306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2662306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "pinctrl-intel.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define CHV_INTSTAT 0x300 3162306a36Sopenharmony_ci#define CHV_INTMASK 0x380 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define FAMILY_PAD_REGS_OFF 0x4400 3462306a36Sopenharmony_ci#define FAMILY_PAD_REGS_SIZE 0x400 3562306a36Sopenharmony_ci#define MAX_FAMILY_PAD_GPIO_NO 15 3662306a36Sopenharmony_ci#define GPIO_REGS_SIZE 8 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define CHV_PADCTRL0 0x000 3962306a36Sopenharmony_ci#define CHV_PADCTRL0_INTSEL_SHIFT 28 4062306a36Sopenharmony_ci#define CHV_PADCTRL0_INTSEL_MASK GENMASK(31, 28) 4162306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_UP BIT(23) 4262306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_SHIFT 20 4362306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_MASK GENMASK(22, 20) 4462306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_20K 1 4562306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_5K 2 4662306a36Sopenharmony_ci#define CHV_PADCTRL0_TERM_1K 4 4762306a36Sopenharmony_ci#define CHV_PADCTRL0_PMODE_SHIFT 16 4862306a36Sopenharmony_ci#define CHV_PADCTRL0_PMODE_MASK GENMASK(19, 16) 4962306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOEN BIT(15) 5062306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_SHIFT 8 5162306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_MASK GENMASK(10, 8) 5262306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_GPIO 0 5362306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_GPO 1 5462306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_GPI 2 5562306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOCFG_HIZ 3 5662306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIOTXSTATE BIT(1) 5762306a36Sopenharmony_ci#define CHV_PADCTRL0_GPIORXSTATE BIT(0) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define CHV_PADCTRL1 0x004 6062306a36Sopenharmony_ci#define CHV_PADCTRL1_CFGLOCK BIT(31) 6162306a36Sopenharmony_ci#define CHV_PADCTRL1_INVRXTX_SHIFT 4 6262306a36Sopenharmony_ci#define CHV_PADCTRL1_INVRXTX_MASK GENMASK(7, 4) 6362306a36Sopenharmony_ci#define CHV_PADCTRL1_INVRXTX_TXDATA BIT(7) 6462306a36Sopenharmony_ci#define CHV_PADCTRL1_INVRXTX_RXDATA BIT(6) 6562306a36Sopenharmony_ci#define CHV_PADCTRL1_INVRXTX_TXENABLE BIT(5) 6662306a36Sopenharmony_ci#define CHV_PADCTRL1_ODEN BIT(3) 6762306a36Sopenharmony_ci#define CHV_PADCTRL1_INTWAKECFG_MASK GENMASK(2, 0) 6862306a36Sopenharmony_ci#define CHV_PADCTRL1_INTWAKECFG_FALLING 1 6962306a36Sopenharmony_ci#define CHV_PADCTRL1_INTWAKECFG_RISING 2 7062306a36Sopenharmony_ci#define CHV_PADCTRL1_INTWAKECFG_BOTH 3 7162306a36Sopenharmony_ci#define CHV_PADCTRL1_INTWAKECFG_LEVEL 4 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct intel_pad_context { 7462306a36Sopenharmony_ci u32 padctrl0; 7562306a36Sopenharmony_ci u32 padctrl1; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define CHV_INVALID_HWIRQ (~0U) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * struct intel_community_context - community context for Cherryview 8262306a36Sopenharmony_ci * @intr_lines: Mapping between 16 HW interrupt wires and GPIO offset (in GPIO number space) 8362306a36Sopenharmony_ci * @saved_intmask: Interrupt mask saved for system sleep 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_cistruct intel_community_context { 8662306a36Sopenharmony_ci unsigned int intr_lines[16]; 8762306a36Sopenharmony_ci u32 saved_intmask; 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define PINMODE_INVERT_OE BIT(15) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define PINMODE(m, i) ((m) | ((i) * PINMODE_INVERT_OE)) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define CHV_GPP(start, end) \ 9562306a36Sopenharmony_ci { \ 9662306a36Sopenharmony_ci .base = (start), \ 9762306a36Sopenharmony_ci .size = (end) - (start) + 1, \ 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define CHV_COMMUNITY(g, i, a) \ 10162306a36Sopenharmony_ci { \ 10262306a36Sopenharmony_ci .gpps = (g), \ 10362306a36Sopenharmony_ci .ngpps = ARRAY_SIZE(g), \ 10462306a36Sopenharmony_ci .nirqs = (i), \ 10562306a36Sopenharmony_ci .acpi_space_id = (a), \ 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const struct pinctrl_pin_desc southwest_pins[] = { 10962306a36Sopenharmony_ci PINCTRL_PIN(0, "FST_SPI_D2"), 11062306a36Sopenharmony_ci PINCTRL_PIN(1, "FST_SPI_D0"), 11162306a36Sopenharmony_ci PINCTRL_PIN(2, "FST_SPI_CLK"), 11262306a36Sopenharmony_ci PINCTRL_PIN(3, "FST_SPI_D3"), 11362306a36Sopenharmony_ci PINCTRL_PIN(4, "FST_SPI_CS1_B"), 11462306a36Sopenharmony_ci PINCTRL_PIN(5, "FST_SPI_D1"), 11562306a36Sopenharmony_ci PINCTRL_PIN(6, "FST_SPI_CS0_B"), 11662306a36Sopenharmony_ci PINCTRL_PIN(7, "FST_SPI_CS2_B"), 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci PINCTRL_PIN(15, "UART1_RTS_B"), 11962306a36Sopenharmony_ci PINCTRL_PIN(16, "UART1_RXD"), 12062306a36Sopenharmony_ci PINCTRL_PIN(17, "UART2_RXD"), 12162306a36Sopenharmony_ci PINCTRL_PIN(18, "UART1_CTS_B"), 12262306a36Sopenharmony_ci PINCTRL_PIN(19, "UART2_RTS_B"), 12362306a36Sopenharmony_ci PINCTRL_PIN(20, "UART1_TXD"), 12462306a36Sopenharmony_ci PINCTRL_PIN(21, "UART2_TXD"), 12562306a36Sopenharmony_ci PINCTRL_PIN(22, "UART2_CTS_B"), 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci PINCTRL_PIN(30, "MF_HDA_CLK"), 12862306a36Sopenharmony_ci PINCTRL_PIN(31, "MF_HDA_RSTB"), 12962306a36Sopenharmony_ci PINCTRL_PIN(32, "MF_HDA_SDIO"), 13062306a36Sopenharmony_ci PINCTRL_PIN(33, "MF_HDA_SDO"), 13162306a36Sopenharmony_ci PINCTRL_PIN(34, "MF_HDA_DOCKRSTB"), 13262306a36Sopenharmony_ci PINCTRL_PIN(35, "MF_HDA_SYNC"), 13362306a36Sopenharmony_ci PINCTRL_PIN(36, "MF_HDA_SDI1"), 13462306a36Sopenharmony_ci PINCTRL_PIN(37, "MF_HDA_DOCKENB"), 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci PINCTRL_PIN(45, "I2C5_SDA"), 13762306a36Sopenharmony_ci PINCTRL_PIN(46, "I2C4_SDA"), 13862306a36Sopenharmony_ci PINCTRL_PIN(47, "I2C6_SDA"), 13962306a36Sopenharmony_ci PINCTRL_PIN(48, "I2C5_SCL"), 14062306a36Sopenharmony_ci PINCTRL_PIN(49, "I2C_NFC_SDA"), 14162306a36Sopenharmony_ci PINCTRL_PIN(50, "I2C4_SCL"), 14262306a36Sopenharmony_ci PINCTRL_PIN(51, "I2C6_SCL"), 14362306a36Sopenharmony_ci PINCTRL_PIN(52, "I2C_NFC_SCL"), 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci PINCTRL_PIN(60, "I2C1_SDA"), 14662306a36Sopenharmony_ci PINCTRL_PIN(61, "I2C0_SDA"), 14762306a36Sopenharmony_ci PINCTRL_PIN(62, "I2C2_SDA"), 14862306a36Sopenharmony_ci PINCTRL_PIN(63, "I2C1_SCL"), 14962306a36Sopenharmony_ci PINCTRL_PIN(64, "I2C3_SDA"), 15062306a36Sopenharmony_ci PINCTRL_PIN(65, "I2C0_SCL"), 15162306a36Sopenharmony_ci PINCTRL_PIN(66, "I2C2_SCL"), 15262306a36Sopenharmony_ci PINCTRL_PIN(67, "I2C3_SCL"), 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci PINCTRL_PIN(75, "SATA_GP0"), 15562306a36Sopenharmony_ci PINCTRL_PIN(76, "SATA_GP1"), 15662306a36Sopenharmony_ci PINCTRL_PIN(77, "SATA_LEDN"), 15762306a36Sopenharmony_ci PINCTRL_PIN(78, "SATA_GP2"), 15862306a36Sopenharmony_ci PINCTRL_PIN(79, "MF_SMB_ALERTB"), 15962306a36Sopenharmony_ci PINCTRL_PIN(80, "SATA_GP3"), 16062306a36Sopenharmony_ci PINCTRL_PIN(81, "MF_SMB_CLK"), 16162306a36Sopenharmony_ci PINCTRL_PIN(82, "MF_SMB_DATA"), 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci PINCTRL_PIN(90, "PCIE_CLKREQ0B"), 16462306a36Sopenharmony_ci PINCTRL_PIN(91, "PCIE_CLKREQ1B"), 16562306a36Sopenharmony_ci PINCTRL_PIN(92, "GP_SSP_2_CLK"), 16662306a36Sopenharmony_ci PINCTRL_PIN(93, "PCIE_CLKREQ2B"), 16762306a36Sopenharmony_ci PINCTRL_PIN(94, "GP_SSP_2_RXD"), 16862306a36Sopenharmony_ci PINCTRL_PIN(95, "PCIE_CLKREQ3B"), 16962306a36Sopenharmony_ci PINCTRL_PIN(96, "GP_SSP_2_FS"), 17062306a36Sopenharmony_ci PINCTRL_PIN(97, "GP_SSP_2_TXD"), 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic const unsigned southwest_uart0_pins[] = { 16, 20 }; 17462306a36Sopenharmony_cistatic const unsigned southwest_uart1_pins[] = { 15, 16, 18, 20 }; 17562306a36Sopenharmony_cistatic const unsigned southwest_uart2_pins[] = { 17, 19, 21, 22 }; 17662306a36Sopenharmony_cistatic const unsigned southwest_i2c0_pins[] = { 61, 65 }; 17762306a36Sopenharmony_cistatic const unsigned southwest_hda_pins[] = { 30, 31, 32, 33, 34, 35, 36, 37 }; 17862306a36Sopenharmony_cistatic const unsigned southwest_lpe_pins[] = { 17962306a36Sopenharmony_ci 30, 31, 32, 33, 34, 35, 36, 37, 92, 94, 96, 97, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_cistatic const unsigned southwest_i2c1_pins[] = { 60, 63 }; 18262306a36Sopenharmony_cistatic const unsigned southwest_i2c2_pins[] = { 62, 66 }; 18362306a36Sopenharmony_cistatic const unsigned southwest_i2c3_pins[] = { 64, 67 }; 18462306a36Sopenharmony_cistatic const unsigned southwest_i2c4_pins[] = { 46, 50 }; 18562306a36Sopenharmony_cistatic const unsigned southwest_i2c5_pins[] = { 45, 48 }; 18662306a36Sopenharmony_cistatic const unsigned southwest_i2c6_pins[] = { 47, 51 }; 18762306a36Sopenharmony_cistatic const unsigned southwest_i2c_nfc_pins[] = { 49, 52 }; 18862306a36Sopenharmony_cistatic const unsigned southwest_spi3_pins[] = { 76, 79, 80, 81, 82 }; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* Some of LPE I2S TXD pins need to have OE inversion set */ 19162306a36Sopenharmony_cistatic const unsigned int southwest_lpe_altfuncs[] = { 19262306a36Sopenharmony_ci PINMODE(1, 1), PINMODE(1, 0), PINMODE(1, 0), PINMODE(1, 0), /* 30, 31, 32, 33 */ 19362306a36Sopenharmony_ci PINMODE(1, 1), PINMODE(1, 0), PINMODE(1, 0), PINMODE(1, 0), /* 34, 35, 36, 37 */ 19462306a36Sopenharmony_ci PINMODE(1, 0), PINMODE(1, 0), PINMODE(1, 0), PINMODE(1, 1), /* 92, 94, 96, 97 */ 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * Two spi3 chipselects are available in different mode than the main spi3 19962306a36Sopenharmony_ci * functionality, which is using mode 2. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic const unsigned int southwest_spi3_altfuncs[] = { 20262306a36Sopenharmony_ci PINMODE(3, 0), PINMODE(2, 0), PINMODE(3, 0), PINMODE(2, 0), /* 76, 79, 80, 81 */ 20362306a36Sopenharmony_ci PINMODE(2, 0), /* 82 */ 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic const struct intel_pingroup southwest_groups[] = { 20762306a36Sopenharmony_ci PIN_GROUP("uart0_grp", southwest_uart0_pins, PINMODE(2, 0)), 20862306a36Sopenharmony_ci PIN_GROUP("uart1_grp", southwest_uart1_pins, PINMODE(1, 0)), 20962306a36Sopenharmony_ci PIN_GROUP("uart2_grp", southwest_uart2_pins, PINMODE(1, 0)), 21062306a36Sopenharmony_ci PIN_GROUP("hda_grp", southwest_hda_pins, PINMODE(2, 0)), 21162306a36Sopenharmony_ci PIN_GROUP("i2c0_grp", southwest_i2c0_pins, PINMODE(1, 1)), 21262306a36Sopenharmony_ci PIN_GROUP("i2c1_grp", southwest_i2c1_pins, PINMODE(1, 1)), 21362306a36Sopenharmony_ci PIN_GROUP("i2c2_grp", southwest_i2c2_pins, PINMODE(1, 1)), 21462306a36Sopenharmony_ci PIN_GROUP("i2c3_grp", southwest_i2c3_pins, PINMODE(1, 1)), 21562306a36Sopenharmony_ci PIN_GROUP("i2c4_grp", southwest_i2c4_pins, PINMODE(1, 1)), 21662306a36Sopenharmony_ci PIN_GROUP("i2c5_grp", southwest_i2c5_pins, PINMODE(1, 1)), 21762306a36Sopenharmony_ci PIN_GROUP("i2c6_grp", southwest_i2c6_pins, PINMODE(1, 1)), 21862306a36Sopenharmony_ci PIN_GROUP("i2c_nfc_grp", southwest_i2c_nfc_pins, PINMODE(2, 1)), 21962306a36Sopenharmony_ci PIN_GROUP("lpe_grp", southwest_lpe_pins, southwest_lpe_altfuncs), 22062306a36Sopenharmony_ci PIN_GROUP("spi3_grp", southwest_spi3_pins, southwest_spi3_altfuncs), 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const char * const southwest_uart0_groups[] = { "uart0_grp" }; 22462306a36Sopenharmony_cistatic const char * const southwest_uart1_groups[] = { "uart1_grp" }; 22562306a36Sopenharmony_cistatic const char * const southwest_uart2_groups[] = { "uart2_grp" }; 22662306a36Sopenharmony_cistatic const char * const southwest_hda_groups[] = { "hda_grp" }; 22762306a36Sopenharmony_cistatic const char * const southwest_lpe_groups[] = { "lpe_grp" }; 22862306a36Sopenharmony_cistatic const char * const southwest_i2c0_groups[] = { "i2c0_grp" }; 22962306a36Sopenharmony_cistatic const char * const southwest_i2c1_groups[] = { "i2c1_grp" }; 23062306a36Sopenharmony_cistatic const char * const southwest_i2c2_groups[] = { "i2c2_grp" }; 23162306a36Sopenharmony_cistatic const char * const southwest_i2c3_groups[] = { "i2c3_grp" }; 23262306a36Sopenharmony_cistatic const char * const southwest_i2c4_groups[] = { "i2c4_grp" }; 23362306a36Sopenharmony_cistatic const char * const southwest_i2c5_groups[] = { "i2c5_grp" }; 23462306a36Sopenharmony_cistatic const char * const southwest_i2c6_groups[] = { "i2c6_grp" }; 23562306a36Sopenharmony_cistatic const char * const southwest_i2c_nfc_groups[] = { "i2c_nfc_grp" }; 23662306a36Sopenharmony_cistatic const char * const southwest_spi3_groups[] = { "spi3_grp" }; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* 23962306a36Sopenharmony_ci * Only do pinmuxing for certain LPSS devices for now. Rest of the pins are 24062306a36Sopenharmony_ci * enabled only as GPIOs. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistatic const struct intel_function southwest_functions[] = { 24362306a36Sopenharmony_ci FUNCTION("uart0", southwest_uart0_groups), 24462306a36Sopenharmony_ci FUNCTION("uart1", southwest_uart1_groups), 24562306a36Sopenharmony_ci FUNCTION("uart2", southwest_uart2_groups), 24662306a36Sopenharmony_ci FUNCTION("hda", southwest_hda_groups), 24762306a36Sopenharmony_ci FUNCTION("lpe", southwest_lpe_groups), 24862306a36Sopenharmony_ci FUNCTION("i2c0", southwest_i2c0_groups), 24962306a36Sopenharmony_ci FUNCTION("i2c1", southwest_i2c1_groups), 25062306a36Sopenharmony_ci FUNCTION("i2c2", southwest_i2c2_groups), 25162306a36Sopenharmony_ci FUNCTION("i2c3", southwest_i2c3_groups), 25262306a36Sopenharmony_ci FUNCTION("i2c4", southwest_i2c4_groups), 25362306a36Sopenharmony_ci FUNCTION("i2c5", southwest_i2c5_groups), 25462306a36Sopenharmony_ci FUNCTION("i2c6", southwest_i2c6_groups), 25562306a36Sopenharmony_ci FUNCTION("i2c_nfc", southwest_i2c_nfc_groups), 25662306a36Sopenharmony_ci FUNCTION("spi3", southwest_spi3_groups), 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic const struct intel_padgroup southwest_gpps[] = { 26062306a36Sopenharmony_ci CHV_GPP(0, 7), 26162306a36Sopenharmony_ci CHV_GPP(15, 22), 26262306a36Sopenharmony_ci CHV_GPP(30, 37), 26362306a36Sopenharmony_ci CHV_GPP(45, 52), 26462306a36Sopenharmony_ci CHV_GPP(60, 67), 26562306a36Sopenharmony_ci CHV_GPP(75, 82), 26662306a36Sopenharmony_ci CHV_GPP(90, 97), 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * Southwest community can generate GPIO interrupts only for the first 8 27162306a36Sopenharmony_ci * interrupts. The upper half (8-15) can only be used to trigger GPEs. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_cistatic const struct intel_community southwest_communities[] = { 27462306a36Sopenharmony_ci CHV_COMMUNITY(southwest_gpps, 8, 0x91), 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data southwest_soc_data = { 27862306a36Sopenharmony_ci .uid = "1", 27962306a36Sopenharmony_ci .pins = southwest_pins, 28062306a36Sopenharmony_ci .npins = ARRAY_SIZE(southwest_pins), 28162306a36Sopenharmony_ci .groups = southwest_groups, 28262306a36Sopenharmony_ci .ngroups = ARRAY_SIZE(southwest_groups), 28362306a36Sopenharmony_ci .functions = southwest_functions, 28462306a36Sopenharmony_ci .nfunctions = ARRAY_SIZE(southwest_functions), 28562306a36Sopenharmony_ci .communities = southwest_communities, 28662306a36Sopenharmony_ci .ncommunities = ARRAY_SIZE(southwest_communities), 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic const struct pinctrl_pin_desc north_pins[] = { 29062306a36Sopenharmony_ci PINCTRL_PIN(0, "GPIO_DFX_0"), 29162306a36Sopenharmony_ci PINCTRL_PIN(1, "GPIO_DFX_3"), 29262306a36Sopenharmony_ci PINCTRL_PIN(2, "GPIO_DFX_7"), 29362306a36Sopenharmony_ci PINCTRL_PIN(3, "GPIO_DFX_1"), 29462306a36Sopenharmony_ci PINCTRL_PIN(4, "GPIO_DFX_5"), 29562306a36Sopenharmony_ci PINCTRL_PIN(5, "GPIO_DFX_4"), 29662306a36Sopenharmony_ci PINCTRL_PIN(6, "GPIO_DFX_8"), 29762306a36Sopenharmony_ci PINCTRL_PIN(7, "GPIO_DFX_2"), 29862306a36Sopenharmony_ci PINCTRL_PIN(8, "GPIO_DFX_6"), 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci PINCTRL_PIN(15, "GPIO_SUS0"), 30162306a36Sopenharmony_ci PINCTRL_PIN(16, "SEC_GPIO_SUS10"), 30262306a36Sopenharmony_ci PINCTRL_PIN(17, "GPIO_SUS3"), 30362306a36Sopenharmony_ci PINCTRL_PIN(18, "GPIO_SUS7"), 30462306a36Sopenharmony_ci PINCTRL_PIN(19, "GPIO_SUS1"), 30562306a36Sopenharmony_ci PINCTRL_PIN(20, "GPIO_SUS5"), 30662306a36Sopenharmony_ci PINCTRL_PIN(21, "SEC_GPIO_SUS11"), 30762306a36Sopenharmony_ci PINCTRL_PIN(22, "GPIO_SUS4"), 30862306a36Sopenharmony_ci PINCTRL_PIN(23, "SEC_GPIO_SUS8"), 30962306a36Sopenharmony_ci PINCTRL_PIN(24, "GPIO_SUS2"), 31062306a36Sopenharmony_ci PINCTRL_PIN(25, "GPIO_SUS6"), 31162306a36Sopenharmony_ci PINCTRL_PIN(26, "CX_PREQ_B"), 31262306a36Sopenharmony_ci PINCTRL_PIN(27, "SEC_GPIO_SUS9"), 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci PINCTRL_PIN(30, "TRST_B"), 31562306a36Sopenharmony_ci PINCTRL_PIN(31, "TCK"), 31662306a36Sopenharmony_ci PINCTRL_PIN(32, "PROCHOT_B"), 31762306a36Sopenharmony_ci PINCTRL_PIN(33, "SVIDO_DATA"), 31862306a36Sopenharmony_ci PINCTRL_PIN(34, "TMS"), 31962306a36Sopenharmony_ci PINCTRL_PIN(35, "CX_PRDY_B_2"), 32062306a36Sopenharmony_ci PINCTRL_PIN(36, "TDO_2"), 32162306a36Sopenharmony_ci PINCTRL_PIN(37, "CX_PRDY_B"), 32262306a36Sopenharmony_ci PINCTRL_PIN(38, "SVIDO_ALERT_B"), 32362306a36Sopenharmony_ci PINCTRL_PIN(39, "TDO"), 32462306a36Sopenharmony_ci PINCTRL_PIN(40, "SVIDO_CLK"), 32562306a36Sopenharmony_ci PINCTRL_PIN(41, "TDI"), 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci PINCTRL_PIN(45, "GP_CAMERASB_05"), 32862306a36Sopenharmony_ci PINCTRL_PIN(46, "GP_CAMERASB_02"), 32962306a36Sopenharmony_ci PINCTRL_PIN(47, "GP_CAMERASB_08"), 33062306a36Sopenharmony_ci PINCTRL_PIN(48, "GP_CAMERASB_00"), 33162306a36Sopenharmony_ci PINCTRL_PIN(49, "GP_CAMERASB_06"), 33262306a36Sopenharmony_ci PINCTRL_PIN(50, "GP_CAMERASB_10"), 33362306a36Sopenharmony_ci PINCTRL_PIN(51, "GP_CAMERASB_03"), 33462306a36Sopenharmony_ci PINCTRL_PIN(52, "GP_CAMERASB_09"), 33562306a36Sopenharmony_ci PINCTRL_PIN(53, "GP_CAMERASB_01"), 33662306a36Sopenharmony_ci PINCTRL_PIN(54, "GP_CAMERASB_07"), 33762306a36Sopenharmony_ci PINCTRL_PIN(55, "GP_CAMERASB_11"), 33862306a36Sopenharmony_ci PINCTRL_PIN(56, "GP_CAMERASB_04"), 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci PINCTRL_PIN(60, "PANEL0_BKLTEN"), 34162306a36Sopenharmony_ci PINCTRL_PIN(61, "HV_DDI0_HPD"), 34262306a36Sopenharmony_ci PINCTRL_PIN(62, "HV_DDI2_DDC_SDA"), 34362306a36Sopenharmony_ci PINCTRL_PIN(63, "PANEL1_BKLTCTL"), 34462306a36Sopenharmony_ci PINCTRL_PIN(64, "HV_DDI1_HPD"), 34562306a36Sopenharmony_ci PINCTRL_PIN(65, "PANEL0_BKLTCTL"), 34662306a36Sopenharmony_ci PINCTRL_PIN(66, "HV_DDI0_DDC_SDA"), 34762306a36Sopenharmony_ci PINCTRL_PIN(67, "HV_DDI2_DDC_SCL"), 34862306a36Sopenharmony_ci PINCTRL_PIN(68, "HV_DDI2_HPD"), 34962306a36Sopenharmony_ci PINCTRL_PIN(69, "PANEL1_VDDEN"), 35062306a36Sopenharmony_ci PINCTRL_PIN(70, "PANEL1_BKLTEN"), 35162306a36Sopenharmony_ci PINCTRL_PIN(71, "HV_DDI0_DDC_SCL"), 35262306a36Sopenharmony_ci PINCTRL_PIN(72, "PANEL0_VDDEN"), 35362306a36Sopenharmony_ci}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic const struct intel_padgroup north_gpps[] = { 35662306a36Sopenharmony_ci CHV_GPP(0, 8), 35762306a36Sopenharmony_ci CHV_GPP(15, 27), 35862306a36Sopenharmony_ci CHV_GPP(30, 41), 35962306a36Sopenharmony_ci CHV_GPP(45, 56), 36062306a36Sopenharmony_ci CHV_GPP(60, 72), 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/* 36462306a36Sopenharmony_ci * North community can generate GPIO interrupts only for the first 8 36562306a36Sopenharmony_ci * interrupts. The upper half (8-15) can only be used to trigger GPEs. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_cistatic const struct intel_community north_communities[] = { 36862306a36Sopenharmony_ci CHV_COMMUNITY(north_gpps, 8, 0x92), 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data north_soc_data = { 37262306a36Sopenharmony_ci .uid = "2", 37362306a36Sopenharmony_ci .pins = north_pins, 37462306a36Sopenharmony_ci .npins = ARRAY_SIZE(north_pins), 37562306a36Sopenharmony_ci .communities = north_communities, 37662306a36Sopenharmony_ci .ncommunities = ARRAY_SIZE(north_communities), 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic const struct pinctrl_pin_desc east_pins[] = { 38062306a36Sopenharmony_ci PINCTRL_PIN(0, "PMU_SLP_S3_B"), 38162306a36Sopenharmony_ci PINCTRL_PIN(1, "PMU_BATLOW_B"), 38262306a36Sopenharmony_ci PINCTRL_PIN(2, "SUS_STAT_B"), 38362306a36Sopenharmony_ci PINCTRL_PIN(3, "PMU_SLP_S0IX_B"), 38462306a36Sopenharmony_ci PINCTRL_PIN(4, "PMU_AC_PRESENT"), 38562306a36Sopenharmony_ci PINCTRL_PIN(5, "PMU_PLTRST_B"), 38662306a36Sopenharmony_ci PINCTRL_PIN(6, "PMU_SUSCLK"), 38762306a36Sopenharmony_ci PINCTRL_PIN(7, "PMU_SLP_LAN_B"), 38862306a36Sopenharmony_ci PINCTRL_PIN(8, "PMU_PWRBTN_B"), 38962306a36Sopenharmony_ci PINCTRL_PIN(9, "PMU_SLP_S4_B"), 39062306a36Sopenharmony_ci PINCTRL_PIN(10, "PMU_WAKE_B"), 39162306a36Sopenharmony_ci PINCTRL_PIN(11, "PMU_WAKE_LAN_B"), 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci PINCTRL_PIN(15, "MF_ISH_GPIO_3"), 39462306a36Sopenharmony_ci PINCTRL_PIN(16, "MF_ISH_GPIO_7"), 39562306a36Sopenharmony_ci PINCTRL_PIN(17, "MF_ISH_I2C1_SCL"), 39662306a36Sopenharmony_ci PINCTRL_PIN(18, "MF_ISH_GPIO_1"), 39762306a36Sopenharmony_ci PINCTRL_PIN(19, "MF_ISH_GPIO_5"), 39862306a36Sopenharmony_ci PINCTRL_PIN(20, "MF_ISH_GPIO_9"), 39962306a36Sopenharmony_ci PINCTRL_PIN(21, "MF_ISH_GPIO_0"), 40062306a36Sopenharmony_ci PINCTRL_PIN(22, "MF_ISH_GPIO_4"), 40162306a36Sopenharmony_ci PINCTRL_PIN(23, "MF_ISH_GPIO_8"), 40262306a36Sopenharmony_ci PINCTRL_PIN(24, "MF_ISH_GPIO_2"), 40362306a36Sopenharmony_ci PINCTRL_PIN(25, "MF_ISH_GPIO_6"), 40462306a36Sopenharmony_ci PINCTRL_PIN(26, "MF_ISH_I2C1_SDA"), 40562306a36Sopenharmony_ci}; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic const struct intel_padgroup east_gpps[] = { 40862306a36Sopenharmony_ci CHV_GPP(0, 11), 40962306a36Sopenharmony_ci CHV_GPP(15, 26), 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic const struct intel_community east_communities[] = { 41362306a36Sopenharmony_ci CHV_COMMUNITY(east_gpps, 16, 0x93), 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data east_soc_data = { 41762306a36Sopenharmony_ci .uid = "3", 41862306a36Sopenharmony_ci .pins = east_pins, 41962306a36Sopenharmony_ci .npins = ARRAY_SIZE(east_pins), 42062306a36Sopenharmony_ci .communities = east_communities, 42162306a36Sopenharmony_ci .ncommunities = ARRAY_SIZE(east_communities), 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic const struct pinctrl_pin_desc southeast_pins[] = { 42562306a36Sopenharmony_ci PINCTRL_PIN(0, "MF_PLT_CLK0"), 42662306a36Sopenharmony_ci PINCTRL_PIN(1, "PWM1"), 42762306a36Sopenharmony_ci PINCTRL_PIN(2, "MF_PLT_CLK1"), 42862306a36Sopenharmony_ci PINCTRL_PIN(3, "MF_PLT_CLK4"), 42962306a36Sopenharmony_ci PINCTRL_PIN(4, "MF_PLT_CLK3"), 43062306a36Sopenharmony_ci PINCTRL_PIN(5, "PWM0"), 43162306a36Sopenharmony_ci PINCTRL_PIN(6, "MF_PLT_CLK5"), 43262306a36Sopenharmony_ci PINCTRL_PIN(7, "MF_PLT_CLK2"), 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci PINCTRL_PIN(15, "SDMMC2_D3_CD_B"), 43562306a36Sopenharmony_ci PINCTRL_PIN(16, "SDMMC1_CLK"), 43662306a36Sopenharmony_ci PINCTRL_PIN(17, "SDMMC1_D0"), 43762306a36Sopenharmony_ci PINCTRL_PIN(18, "SDMMC2_D1"), 43862306a36Sopenharmony_ci PINCTRL_PIN(19, "SDMMC2_CLK"), 43962306a36Sopenharmony_ci PINCTRL_PIN(20, "SDMMC1_D2"), 44062306a36Sopenharmony_ci PINCTRL_PIN(21, "SDMMC2_D2"), 44162306a36Sopenharmony_ci PINCTRL_PIN(22, "SDMMC2_CMD"), 44262306a36Sopenharmony_ci PINCTRL_PIN(23, "SDMMC1_CMD"), 44362306a36Sopenharmony_ci PINCTRL_PIN(24, "SDMMC1_D1"), 44462306a36Sopenharmony_ci PINCTRL_PIN(25, "SDMMC2_D0"), 44562306a36Sopenharmony_ci PINCTRL_PIN(26, "SDMMC1_D3_CD_B"), 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci PINCTRL_PIN(30, "SDMMC3_D1"), 44862306a36Sopenharmony_ci PINCTRL_PIN(31, "SDMMC3_CLK"), 44962306a36Sopenharmony_ci PINCTRL_PIN(32, "SDMMC3_D3"), 45062306a36Sopenharmony_ci PINCTRL_PIN(33, "SDMMC3_D2"), 45162306a36Sopenharmony_ci PINCTRL_PIN(34, "SDMMC3_CMD"), 45262306a36Sopenharmony_ci PINCTRL_PIN(35, "SDMMC3_D0"), 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci PINCTRL_PIN(45, "MF_LPC_AD2"), 45562306a36Sopenharmony_ci PINCTRL_PIN(46, "LPC_CLKRUNB"), 45662306a36Sopenharmony_ci PINCTRL_PIN(47, "MF_LPC_AD0"), 45762306a36Sopenharmony_ci PINCTRL_PIN(48, "LPC_FRAMEB"), 45862306a36Sopenharmony_ci PINCTRL_PIN(49, "MF_LPC_CLKOUT1"), 45962306a36Sopenharmony_ci PINCTRL_PIN(50, "MF_LPC_AD3"), 46062306a36Sopenharmony_ci PINCTRL_PIN(51, "MF_LPC_CLKOUT0"), 46162306a36Sopenharmony_ci PINCTRL_PIN(52, "MF_LPC_AD1"), 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci PINCTRL_PIN(60, "SPI1_MISO"), 46462306a36Sopenharmony_ci PINCTRL_PIN(61, "SPI1_CSO_B"), 46562306a36Sopenharmony_ci PINCTRL_PIN(62, "SPI1_CLK"), 46662306a36Sopenharmony_ci PINCTRL_PIN(63, "MMC1_D6"), 46762306a36Sopenharmony_ci PINCTRL_PIN(64, "SPI1_MOSI"), 46862306a36Sopenharmony_ci PINCTRL_PIN(65, "MMC1_D5"), 46962306a36Sopenharmony_ci PINCTRL_PIN(66, "SPI1_CS1_B"), 47062306a36Sopenharmony_ci PINCTRL_PIN(67, "MMC1_D4_SD_WE"), 47162306a36Sopenharmony_ci PINCTRL_PIN(68, "MMC1_D7"), 47262306a36Sopenharmony_ci PINCTRL_PIN(69, "MMC1_RCLK"), 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci PINCTRL_PIN(75, "USB_OC1_B"), 47562306a36Sopenharmony_ci PINCTRL_PIN(76, "PMU_RESETBUTTON_B"), 47662306a36Sopenharmony_ci PINCTRL_PIN(77, "GPIO_ALERT"), 47762306a36Sopenharmony_ci PINCTRL_PIN(78, "SDMMC3_PWR_EN_B"), 47862306a36Sopenharmony_ci PINCTRL_PIN(79, "ILB_SERIRQ"), 47962306a36Sopenharmony_ci PINCTRL_PIN(80, "USB_OC0_B"), 48062306a36Sopenharmony_ci PINCTRL_PIN(81, "SDMMC3_CD_B"), 48162306a36Sopenharmony_ci PINCTRL_PIN(82, "SPKR"), 48262306a36Sopenharmony_ci PINCTRL_PIN(83, "SUSPWRDNACK"), 48362306a36Sopenharmony_ci PINCTRL_PIN(84, "SPARE_PIN"), 48462306a36Sopenharmony_ci PINCTRL_PIN(85, "SDMMC3_1P8_EN"), 48562306a36Sopenharmony_ci}; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic const unsigned southeast_pwm0_pins[] = { 5 }; 48862306a36Sopenharmony_cistatic const unsigned southeast_pwm1_pins[] = { 1 }; 48962306a36Sopenharmony_cistatic const unsigned southeast_sdmmc1_pins[] = { 49062306a36Sopenharmony_ci 16, 17, 20, 23, 24, 26, 63, 65, 67, 68, 69, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_cistatic const unsigned southeast_sdmmc2_pins[] = { 15, 18, 19, 21, 22, 25 }; 49362306a36Sopenharmony_cistatic const unsigned southeast_sdmmc3_pins[] = { 49462306a36Sopenharmony_ci 30, 31, 32, 33, 34, 35, 78, 81, 85, 49562306a36Sopenharmony_ci}; 49662306a36Sopenharmony_cistatic const unsigned southeast_spi1_pins[] = { 60, 61, 62, 64, 66 }; 49762306a36Sopenharmony_cistatic const unsigned southeast_spi2_pins[] = { 2, 3, 4, 6, 7 }; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic const struct intel_pingroup southeast_groups[] = { 50062306a36Sopenharmony_ci PIN_GROUP("pwm0_grp", southeast_pwm0_pins, PINMODE(1, 0)), 50162306a36Sopenharmony_ci PIN_GROUP("pwm1_grp", southeast_pwm1_pins, PINMODE(1, 0)), 50262306a36Sopenharmony_ci PIN_GROUP("sdmmc1_grp", southeast_sdmmc1_pins, PINMODE(1, 0)), 50362306a36Sopenharmony_ci PIN_GROUP("sdmmc2_grp", southeast_sdmmc2_pins, PINMODE(1, 0)), 50462306a36Sopenharmony_ci PIN_GROUP("sdmmc3_grp", southeast_sdmmc3_pins, PINMODE(1, 0)), 50562306a36Sopenharmony_ci PIN_GROUP("spi1_grp", southeast_spi1_pins, PINMODE(1, 0)), 50662306a36Sopenharmony_ci PIN_GROUP("spi2_grp", southeast_spi2_pins, PINMODE(4, 0)), 50762306a36Sopenharmony_ci}; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic const char * const southeast_pwm0_groups[] = { "pwm0_grp" }; 51062306a36Sopenharmony_cistatic const char * const southeast_pwm1_groups[] = { "pwm1_grp" }; 51162306a36Sopenharmony_cistatic const char * const southeast_sdmmc1_groups[] = { "sdmmc1_grp" }; 51262306a36Sopenharmony_cistatic const char * const southeast_sdmmc2_groups[] = { "sdmmc2_grp" }; 51362306a36Sopenharmony_cistatic const char * const southeast_sdmmc3_groups[] = { "sdmmc3_grp" }; 51462306a36Sopenharmony_cistatic const char * const southeast_spi1_groups[] = { "spi1_grp" }; 51562306a36Sopenharmony_cistatic const char * const southeast_spi2_groups[] = { "spi2_grp" }; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct intel_function southeast_functions[] = { 51862306a36Sopenharmony_ci FUNCTION("pwm0", southeast_pwm0_groups), 51962306a36Sopenharmony_ci FUNCTION("pwm1", southeast_pwm1_groups), 52062306a36Sopenharmony_ci FUNCTION("sdmmc1", southeast_sdmmc1_groups), 52162306a36Sopenharmony_ci FUNCTION("sdmmc2", southeast_sdmmc2_groups), 52262306a36Sopenharmony_ci FUNCTION("sdmmc3", southeast_sdmmc3_groups), 52362306a36Sopenharmony_ci FUNCTION("spi1", southeast_spi1_groups), 52462306a36Sopenharmony_ci FUNCTION("spi2", southeast_spi2_groups), 52562306a36Sopenharmony_ci}; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic const struct intel_padgroup southeast_gpps[] = { 52862306a36Sopenharmony_ci CHV_GPP(0, 7), 52962306a36Sopenharmony_ci CHV_GPP(15, 26), 53062306a36Sopenharmony_ci CHV_GPP(30, 35), 53162306a36Sopenharmony_ci CHV_GPP(45, 52), 53262306a36Sopenharmony_ci CHV_GPP(60, 69), 53362306a36Sopenharmony_ci CHV_GPP(75, 85), 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic const struct intel_community southeast_communities[] = { 53762306a36Sopenharmony_ci CHV_COMMUNITY(southeast_gpps, 16, 0x94), 53862306a36Sopenharmony_ci}; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data southeast_soc_data = { 54162306a36Sopenharmony_ci .uid = "4", 54262306a36Sopenharmony_ci .pins = southeast_pins, 54362306a36Sopenharmony_ci .npins = ARRAY_SIZE(southeast_pins), 54462306a36Sopenharmony_ci .groups = southeast_groups, 54562306a36Sopenharmony_ci .ngroups = ARRAY_SIZE(southeast_groups), 54662306a36Sopenharmony_ci .functions = southeast_functions, 54762306a36Sopenharmony_ci .nfunctions = ARRAY_SIZE(southeast_functions), 54862306a36Sopenharmony_ci .communities = southeast_communities, 54962306a36Sopenharmony_ci .ncommunities = ARRAY_SIZE(southeast_communities), 55062306a36Sopenharmony_ci}; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic const struct intel_pinctrl_soc_data *chv_soc_data[] = { 55362306a36Sopenharmony_ci &southwest_soc_data, 55462306a36Sopenharmony_ci &north_soc_data, 55562306a36Sopenharmony_ci &east_soc_data, 55662306a36Sopenharmony_ci &southeast_soc_data, 55762306a36Sopenharmony_ci NULL 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* 56162306a36Sopenharmony_ci * Lock to serialize register accesses 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * Due to a silicon issue, a shared lock must be used to prevent 56462306a36Sopenharmony_ci * concurrent accesses across the 4 GPIO controllers. 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * See Intel Atom Z8000 Processor Series Specification Update (Rev. 005), 56762306a36Sopenharmony_ci * errata #CHT34, for further information. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(chv_lock); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic u32 chv_pctrl_readl(struct intel_pinctrl *pctrl, unsigned int offset) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return readl(community->regs + offset); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void chv_pctrl_writel(struct intel_pinctrl *pctrl, unsigned int offset, u32 value) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 58162306a36Sopenharmony_ci void __iomem *reg = community->regs + offset; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Write and simple read back to confirm the bus transferring done */ 58462306a36Sopenharmony_ci writel(value, reg); 58562306a36Sopenharmony_ci readl(reg); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic void __iomem *chv_padreg(struct intel_pinctrl *pctrl, unsigned int offset, 58962306a36Sopenharmony_ci unsigned int reg) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 59262306a36Sopenharmony_ci unsigned int family_no = offset / MAX_FAMILY_PAD_GPIO_NO; 59362306a36Sopenharmony_ci unsigned int pad_no = offset % MAX_FAMILY_PAD_GPIO_NO; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci offset = FAMILY_PAD_REGS_SIZE * family_no + GPIO_REGS_SIZE * pad_no; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return community->pad_regs + offset + reg; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic u32 chv_readl(struct intel_pinctrl *pctrl, unsigned int pin, unsigned int offset) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci return readl(chv_padreg(pctrl, pin, offset)); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void chv_writel(struct intel_pinctrl *pctrl, unsigned int pin, unsigned int offset, u32 value) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci void __iomem *reg = chv_padreg(pctrl, pin, offset); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Write and simple read back to confirm the bus transferring done */ 61062306a36Sopenharmony_ci writel(value, reg); 61162306a36Sopenharmony_ci readl(reg); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* When Pad Cfg is locked, driver can only change GPIOTXState or GPIORXState */ 61562306a36Sopenharmony_cistatic bool chv_pad_locked(struct intel_pinctrl *pctrl, unsigned int offset) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci return chv_readl(pctrl, offset, CHV_PADCTRL1) & CHV_PADCTRL1_CFGLOCK; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 62162306a36Sopenharmony_ci unsigned int offset) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 62462306a36Sopenharmony_ci unsigned long flags; 62562306a36Sopenharmony_ci u32 ctrl0, ctrl1; 62662306a36Sopenharmony_ci bool locked; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, offset, CHV_PADCTRL0); 63162306a36Sopenharmony_ci ctrl1 = chv_readl(pctrl, offset, CHV_PADCTRL1); 63262306a36Sopenharmony_ci locked = chv_pad_locked(pctrl, offset); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (ctrl0 & CHV_PADCTRL0_GPIOEN) { 63762306a36Sopenharmony_ci seq_puts(s, "GPIO "); 63862306a36Sopenharmony_ci } else { 63962306a36Sopenharmony_ci u32 mode; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mode = ctrl0 & CHV_PADCTRL0_PMODE_MASK; 64262306a36Sopenharmony_ci mode >>= CHV_PADCTRL0_PMODE_SHIFT; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci seq_printf(s, "mode %d ", mode); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci seq_printf(s, "0x%08x 0x%08x", ctrl0, ctrl1); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (locked) 65062306a36Sopenharmony_ci seq_puts(s, " [LOCKED]"); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct pinctrl_ops chv_pinctrl_ops = { 65462306a36Sopenharmony_ci .get_groups_count = intel_get_groups_count, 65562306a36Sopenharmony_ci .get_group_name = intel_get_group_name, 65662306a36Sopenharmony_ci .get_group_pins = intel_get_group_pins, 65762306a36Sopenharmony_ci .pin_dbg_show = chv_pin_dbg_show, 65862306a36Sopenharmony_ci}; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, 66162306a36Sopenharmony_ci unsigned int function, unsigned int group) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 66462306a36Sopenharmony_ci struct device *dev = pctrl->dev; 66562306a36Sopenharmony_ci const struct intel_pingroup *grp; 66662306a36Sopenharmony_ci unsigned long flags; 66762306a36Sopenharmony_ci int i; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci grp = &pctrl->soc->groups[group]; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* Check first that the pad is not locked */ 67462306a36Sopenharmony_ci for (i = 0; i < grp->grp.npins; i++) { 67562306a36Sopenharmony_ci if (chv_pad_locked(pctrl, grp->grp.pins[i])) { 67662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 67762306a36Sopenharmony_ci dev_warn(dev, "unable to set mode for locked pin %u\n", grp->grp.pins[i]); 67862306a36Sopenharmony_ci return -EBUSY; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci for (i = 0; i < grp->grp.npins; i++) { 68362306a36Sopenharmony_ci int pin = grp->grp.pins[i]; 68462306a36Sopenharmony_ci unsigned int mode; 68562306a36Sopenharmony_ci bool invert_oe; 68662306a36Sopenharmony_ci u32 value; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Check if there is pin-specific config */ 68962306a36Sopenharmony_ci if (grp->modes) 69062306a36Sopenharmony_ci mode = grp->modes[i]; 69162306a36Sopenharmony_ci else 69262306a36Sopenharmony_ci mode = grp->mode; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Extract OE inversion */ 69562306a36Sopenharmony_ci invert_oe = mode & PINMODE_INVERT_OE; 69662306a36Sopenharmony_ci mode &= ~PINMODE_INVERT_OE; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci value = chv_readl(pctrl, pin, CHV_PADCTRL0); 69962306a36Sopenharmony_ci /* Disable GPIO mode */ 70062306a36Sopenharmony_ci value &= ~CHV_PADCTRL0_GPIOEN; 70162306a36Sopenharmony_ci /* Set to desired mode */ 70262306a36Sopenharmony_ci value &= ~CHV_PADCTRL0_PMODE_MASK; 70362306a36Sopenharmony_ci value |= mode << CHV_PADCTRL0_PMODE_SHIFT; 70462306a36Sopenharmony_ci chv_writel(pctrl, pin, CHV_PADCTRL0, value); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Update for invert_oe */ 70762306a36Sopenharmony_ci value = chv_readl(pctrl, pin, CHV_PADCTRL1) & ~CHV_PADCTRL1_INVRXTX_MASK; 70862306a36Sopenharmony_ci if (invert_oe) 70962306a36Sopenharmony_ci value |= CHV_PADCTRL1_INVRXTX_TXENABLE; 71062306a36Sopenharmony_ci chv_writel(pctrl, pin, CHV_PADCTRL1, value); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dev_dbg(dev, "configured pin %u mode %u OE %sinverted\n", pin, mode, 71362306a36Sopenharmony_ci invert_oe ? "" : "not "); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void chv_gpio_clear_triggering(struct intel_pinctrl *pctrl, 72262306a36Sopenharmony_ci unsigned int offset) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci u32 invrxtx_mask = CHV_PADCTRL1_INVRXTX_MASK; 72562306a36Sopenharmony_ci u32 value; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* 72862306a36Sopenharmony_ci * One some devices the GPIO should output the inverted value from what 72962306a36Sopenharmony_ci * device-drivers / ACPI code expects (inverted external buffer?). The 73062306a36Sopenharmony_ci * BIOS makes this work by setting the CHV_PADCTRL1_INVRXTX_TXDATA flag, 73162306a36Sopenharmony_ci * preserve this flag if the pin is already setup as GPIO. 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci value = chv_readl(pctrl, offset, CHV_PADCTRL0); 73462306a36Sopenharmony_ci if (value & CHV_PADCTRL0_GPIOEN) 73562306a36Sopenharmony_ci invrxtx_mask &= ~CHV_PADCTRL1_INVRXTX_TXDATA; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci value = chv_readl(pctrl, offset, CHV_PADCTRL1); 73862306a36Sopenharmony_ci value &= ~CHV_PADCTRL1_INTWAKECFG_MASK; 73962306a36Sopenharmony_ci value &= ~invrxtx_mask; 74062306a36Sopenharmony_ci chv_writel(pctrl, offset, CHV_PADCTRL1, value); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int chv_gpio_request_enable(struct pinctrl_dev *pctldev, 74462306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 74562306a36Sopenharmony_ci unsigned int offset) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 74862306a36Sopenharmony_ci unsigned long flags; 74962306a36Sopenharmony_ci u32 value; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (chv_pad_locked(pctrl, offset)) { 75462306a36Sopenharmony_ci value = chv_readl(pctrl, offset, CHV_PADCTRL0); 75562306a36Sopenharmony_ci if (!(value & CHV_PADCTRL0_GPIOEN)) { 75662306a36Sopenharmony_ci /* Locked so cannot enable */ 75762306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 75862306a36Sopenharmony_ci return -EBUSY; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci } else { 76162306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 76262306a36Sopenharmony_ci int i; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci /* Reset the interrupt mapping */ 76562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++) { 76662306a36Sopenharmony_ci if (cctx->intr_lines[i] == offset) { 76762306a36Sopenharmony_ci cctx->intr_lines[i] = CHV_INVALID_HWIRQ; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Disable interrupt generation */ 77362306a36Sopenharmony_ci chv_gpio_clear_triggering(pctrl, offset); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci value = chv_readl(pctrl, offset, CHV_PADCTRL0); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* 77862306a36Sopenharmony_ci * If the pin is in HiZ mode (both TX and RX buffers are 77962306a36Sopenharmony_ci * disabled) we turn it to be input now. 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_ci if ((value & CHV_PADCTRL0_GPIOCFG_MASK) == 78262306a36Sopenharmony_ci (CHV_PADCTRL0_GPIOCFG_HIZ << CHV_PADCTRL0_GPIOCFG_SHIFT)) { 78362306a36Sopenharmony_ci value &= ~CHV_PADCTRL0_GPIOCFG_MASK; 78462306a36Sopenharmony_ci value |= CHV_PADCTRL0_GPIOCFG_GPI << CHV_PADCTRL0_GPIOCFG_SHIFT; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* Switch to a GPIO mode */ 78862306a36Sopenharmony_ci value |= CHV_PADCTRL0_GPIOEN; 78962306a36Sopenharmony_ci chv_writel(pctrl, offset, CHV_PADCTRL0, value); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic void chv_gpio_disable_free(struct pinctrl_dev *pctldev, 79862306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 79962306a36Sopenharmony_ci unsigned int offset) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 80262306a36Sopenharmony_ci unsigned long flags; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (!chv_pad_locked(pctrl, offset)) 80762306a36Sopenharmony_ci chv_gpio_clear_triggering(pctrl, offset); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int chv_gpio_set_direction(struct pinctrl_dev *pctldev, 81362306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 81462306a36Sopenharmony_ci unsigned int offset, bool input) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 81762306a36Sopenharmony_ci unsigned long flags; 81862306a36Sopenharmony_ci u32 ctrl0; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, offset, CHV_PADCTRL0) & ~CHV_PADCTRL0_GPIOCFG_MASK; 82362306a36Sopenharmony_ci if (input) 82462306a36Sopenharmony_ci ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPI << CHV_PADCTRL0_GPIOCFG_SHIFT; 82562306a36Sopenharmony_ci else 82662306a36Sopenharmony_ci ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT; 82762306a36Sopenharmony_ci chv_writel(pctrl, offset, CHV_PADCTRL0, ctrl0); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic const struct pinmux_ops chv_pinmux_ops = { 83562306a36Sopenharmony_ci .get_functions_count = intel_get_functions_count, 83662306a36Sopenharmony_ci .get_function_name = intel_get_function_name, 83762306a36Sopenharmony_ci .get_function_groups = intel_get_function_groups, 83862306a36Sopenharmony_ci .set_mux = chv_pinmux_set_mux, 83962306a36Sopenharmony_ci .gpio_request_enable = chv_gpio_request_enable, 84062306a36Sopenharmony_ci .gpio_disable_free = chv_gpio_disable_free, 84162306a36Sopenharmony_ci .gpio_set_direction = chv_gpio_set_direction, 84262306a36Sopenharmony_ci}; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic int chv_config_get(struct pinctrl_dev *pctldev, unsigned int pin, 84562306a36Sopenharmony_ci unsigned long *config) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 84862306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 84962306a36Sopenharmony_ci unsigned long flags; 85062306a36Sopenharmony_ci u32 ctrl0, ctrl1; 85162306a36Sopenharmony_ci u16 arg = 0; 85262306a36Sopenharmony_ci u32 term; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 85562306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, pin, CHV_PADCTRL0); 85662306a36Sopenharmony_ci ctrl1 = chv_readl(pctrl, pin, CHV_PADCTRL1); 85762306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci switch (param) { 86262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 86362306a36Sopenharmony_ci if (term) 86462306a36Sopenharmony_ci return -EINVAL; 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 86862306a36Sopenharmony_ci if (!(ctrl0 & CHV_PADCTRL0_TERM_UP)) 86962306a36Sopenharmony_ci return -EINVAL; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci switch (term) { 87262306a36Sopenharmony_ci case CHV_PADCTRL0_TERM_20K: 87362306a36Sopenharmony_ci arg = 20000; 87462306a36Sopenharmony_ci break; 87562306a36Sopenharmony_ci case CHV_PADCTRL0_TERM_5K: 87662306a36Sopenharmony_ci arg = 5000; 87762306a36Sopenharmony_ci break; 87862306a36Sopenharmony_ci case CHV_PADCTRL0_TERM_1K: 87962306a36Sopenharmony_ci arg = 1000; 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 88662306a36Sopenharmony_ci if (!term || (ctrl0 & CHV_PADCTRL0_TERM_UP)) 88762306a36Sopenharmony_ci return -EINVAL; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci switch (term) { 89062306a36Sopenharmony_ci case CHV_PADCTRL0_TERM_20K: 89162306a36Sopenharmony_ci arg = 20000; 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci case CHV_PADCTRL0_TERM_5K: 89462306a36Sopenharmony_ci arg = 5000; 89562306a36Sopenharmony_ci break; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: { 90162306a36Sopenharmony_ci u32 cfg; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; 90462306a36Sopenharmony_ci cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; 90562306a36Sopenharmony_ci if (cfg != CHV_PADCTRL0_GPIOCFG_HIZ) 90662306a36Sopenharmony_ci return -EINVAL; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 91162306a36Sopenharmony_ci if (ctrl1 & CHV_PADCTRL1_ODEN) 91262306a36Sopenharmony_ci return -EINVAL; 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 91662306a36Sopenharmony_ci if (!(ctrl1 & CHV_PADCTRL1_ODEN)) 91762306a36Sopenharmony_ci return -EINVAL; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci default: 92262306a36Sopenharmony_ci return -ENOTSUPP; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 92662306a36Sopenharmony_ci return 0; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic int chv_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin, 93062306a36Sopenharmony_ci enum pin_config_param param, u32 arg) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci unsigned long flags; 93362306a36Sopenharmony_ci u32 ctrl0, pull; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 93662306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, pin, CHV_PADCTRL0); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci switch (param) { 93962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 94062306a36Sopenharmony_ci ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 94462306a36Sopenharmony_ci ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci switch (arg) { 94762306a36Sopenharmony_ci case 1000: 94862306a36Sopenharmony_ci /* For 1k there is only pull up */ 94962306a36Sopenharmony_ci pull = CHV_PADCTRL0_TERM_1K << CHV_PADCTRL0_TERM_SHIFT; 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci case 5000: 95262306a36Sopenharmony_ci pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT; 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case 20000: 95562306a36Sopenharmony_ci pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci default: 95862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ctrl0 |= CHV_PADCTRL0_TERM_UP | pull; 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 96662306a36Sopenharmony_ci ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci switch (arg) { 96962306a36Sopenharmony_ci case 5000: 97062306a36Sopenharmony_ci pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT; 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci case 20000: 97362306a36Sopenharmony_ci pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci default: 97662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 97762306a36Sopenharmony_ci return -EINVAL; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci ctrl0 |= pull; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci default: 98462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 98562306a36Sopenharmony_ci return -EINVAL; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci chv_writel(pctrl, pin, CHV_PADCTRL0, ctrl0); 98962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci return 0; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic int chv_config_set_oden(struct intel_pinctrl *pctrl, unsigned int pin, 99562306a36Sopenharmony_ci bool enable) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci unsigned long flags; 99862306a36Sopenharmony_ci u32 ctrl1; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 100162306a36Sopenharmony_ci ctrl1 = chv_readl(pctrl, pin, CHV_PADCTRL1); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (enable) 100462306a36Sopenharmony_ci ctrl1 |= CHV_PADCTRL1_ODEN; 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci ctrl1 &= ~CHV_PADCTRL1_ODEN; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci chv_writel(pctrl, pin, CHV_PADCTRL1, ctrl1); 100962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int chv_config_set(struct pinctrl_dev *pctldev, unsigned int pin, 101562306a36Sopenharmony_ci unsigned long *configs, unsigned int nconfigs) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 101862306a36Sopenharmony_ci struct device *dev = pctrl->dev; 101962306a36Sopenharmony_ci enum pin_config_param param; 102062306a36Sopenharmony_ci int i, ret; 102162306a36Sopenharmony_ci u32 arg; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (chv_pad_locked(pctrl, pin)) 102462306a36Sopenharmony_ci return -EBUSY; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci for (i = 0; i < nconfigs; i++) { 102762306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 102862306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci switch (param) { 103162306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 103262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 103362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 103462306a36Sopenharmony_ci ret = chv_config_set_pull(pctrl, pin, param, arg); 103562306a36Sopenharmony_ci if (ret) 103662306a36Sopenharmony_ci return ret; 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 104062306a36Sopenharmony_ci ret = chv_config_set_oden(pctrl, pin, false); 104162306a36Sopenharmony_ci if (ret) 104262306a36Sopenharmony_ci return ret; 104362306a36Sopenharmony_ci break; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_OPEN_DRAIN: 104662306a36Sopenharmony_ci ret = chv_config_set_oden(pctrl, pin, true); 104762306a36Sopenharmony_ci if (ret) 104862306a36Sopenharmony_ci return ret; 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci default: 105262306a36Sopenharmony_ci return -ENOTSUPP; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci dev_dbg(dev, "pin %d set config %d arg %u\n", pin, param, arg); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int chv_config_group_get(struct pinctrl_dev *pctldev, 106262306a36Sopenharmony_ci unsigned int group, 106362306a36Sopenharmony_ci unsigned long *config) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci const unsigned int *pins; 106662306a36Sopenharmony_ci unsigned int npins; 106762306a36Sopenharmony_ci int ret; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ret = intel_get_group_pins(pctldev, group, &pins, &npins); 107062306a36Sopenharmony_ci if (ret) 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ret = chv_config_get(pctldev, pins[0], config); 107462306a36Sopenharmony_ci if (ret) 107562306a36Sopenharmony_ci return ret; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci return 0; 107862306a36Sopenharmony_ci} 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int chv_config_group_set(struct pinctrl_dev *pctldev, 108162306a36Sopenharmony_ci unsigned int group, unsigned long *configs, 108262306a36Sopenharmony_ci unsigned int num_configs) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci const unsigned int *pins; 108562306a36Sopenharmony_ci unsigned int npins; 108662306a36Sopenharmony_ci int i, ret; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ret = intel_get_group_pins(pctldev, group, &pins, &npins); 108962306a36Sopenharmony_ci if (ret) 109062306a36Sopenharmony_ci return ret; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 109362306a36Sopenharmony_ci ret = chv_config_set(pctldev, pins[i], configs, num_configs); 109462306a36Sopenharmony_ci if (ret) 109562306a36Sopenharmony_ci return ret; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci return 0; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cistatic const struct pinconf_ops chv_pinconf_ops = { 110262306a36Sopenharmony_ci .is_generic = true, 110362306a36Sopenharmony_ci .pin_config_set = chv_config_set, 110462306a36Sopenharmony_ci .pin_config_get = chv_config_get, 110562306a36Sopenharmony_ci .pin_config_group_get = chv_config_group_get, 110662306a36Sopenharmony_ci .pin_config_group_set = chv_config_group_set, 110762306a36Sopenharmony_ci}; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic struct pinctrl_desc chv_pinctrl_desc = { 111062306a36Sopenharmony_ci .pctlops = &chv_pinctrl_ops, 111162306a36Sopenharmony_ci .pmxops = &chv_pinmux_ops, 111262306a36Sopenharmony_ci .confops = &chv_pinconf_ops, 111362306a36Sopenharmony_ci .owner = THIS_MODULE, 111462306a36Sopenharmony_ci}; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int chv_gpio_get(struct gpio_chip *chip, unsigned int offset) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 111962306a36Sopenharmony_ci unsigned long flags; 112062306a36Sopenharmony_ci u32 ctrl0, cfg; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 112362306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, offset, CHV_PADCTRL0); 112462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; 112762306a36Sopenharmony_ci cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (cfg == CHV_PADCTRL0_GPIOCFG_GPO) 113062306a36Sopenharmony_ci return !!(ctrl0 & CHV_PADCTRL0_GPIOTXSTATE); 113162306a36Sopenharmony_ci return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 113762306a36Sopenharmony_ci unsigned long flags; 113862306a36Sopenharmony_ci u32 ctrl0; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, offset, CHV_PADCTRL0); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (value) 114562306a36Sopenharmony_ci ctrl0 |= CHV_PADCTRL0_GPIOTXSTATE; 114662306a36Sopenharmony_ci else 114762306a36Sopenharmony_ci ctrl0 &= ~CHV_PADCTRL0_GPIOTXSTATE; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci chv_writel(pctrl, offset, CHV_PADCTRL0, ctrl0); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 115562306a36Sopenharmony_ci{ 115662306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 115762306a36Sopenharmony_ci u32 ctrl0, direction; 115862306a36Sopenharmony_ci unsigned long flags; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 116162306a36Sopenharmony_ci ctrl0 = chv_readl(pctrl, offset, CHV_PADCTRL0); 116262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; 116562306a36Sopenharmony_ci direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (direction == CHV_PADCTRL0_GPIOCFG_GPO) 116862306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cistatic int chv_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + offset); 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic int chv_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, 117962306a36Sopenharmony_ci int value) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci chv_gpio_set(chip, offset, value); 118262306a36Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + offset); 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic const struct gpio_chip chv_gpio_chip = { 118662306a36Sopenharmony_ci .owner = THIS_MODULE, 118762306a36Sopenharmony_ci .request = gpiochip_generic_request, 118862306a36Sopenharmony_ci .free = gpiochip_generic_free, 118962306a36Sopenharmony_ci .get_direction = chv_gpio_get_direction, 119062306a36Sopenharmony_ci .direction_input = chv_gpio_direction_input, 119162306a36Sopenharmony_ci .direction_output = chv_gpio_direction_output, 119262306a36Sopenharmony_ci .get = chv_gpio_get, 119362306a36Sopenharmony_ci .set = chv_gpio_set, 119462306a36Sopenharmony_ci}; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic void chv_gpio_irq_ack(struct irq_data *d) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 119962306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 120062306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 120162306a36Sopenharmony_ci u32 intr_line; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci raw_spin_lock(&chv_lock); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci intr_line = chv_readl(pctrl, hwirq, CHV_PADCTRL0); 120662306a36Sopenharmony_ci intr_line &= CHV_PADCTRL0_INTSEL_MASK; 120762306a36Sopenharmony_ci intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; 120862306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTSTAT, BIT(intr_line)); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci raw_spin_unlock(&chv_lock); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic void chv_gpio_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t hwirq, bool mask) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 121662306a36Sopenharmony_ci u32 value, intr_line; 121762306a36Sopenharmony_ci unsigned long flags; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci intr_line = chv_readl(pctrl, hwirq, CHV_PADCTRL0); 122262306a36Sopenharmony_ci intr_line &= CHV_PADCTRL0_INTSEL_MASK; 122362306a36Sopenharmony_ci intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci value = chv_pctrl_readl(pctrl, CHV_INTMASK); 122662306a36Sopenharmony_ci if (mask) 122762306a36Sopenharmony_ci value &= ~BIT(intr_line); 122862306a36Sopenharmony_ci else 122962306a36Sopenharmony_ci value |= BIT(intr_line); 123062306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTMASK, value); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic void chv_gpio_irq_mask(struct irq_data *d) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 123862306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci chv_gpio_irq_mask_unmask(gc, hwirq, true); 124162306a36Sopenharmony_ci gpiochip_disable_irq(gc, hwirq); 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic void chv_gpio_irq_unmask(struct irq_data *d) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 124762306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci gpiochip_enable_irq(gc, hwirq); 125062306a36Sopenharmony_ci chv_gpio_irq_mask_unmask(gc, hwirq, false); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic unsigned chv_gpio_irq_startup(struct irq_data *d) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci /* 125662306a36Sopenharmony_ci * Check if the interrupt has been requested with 0 as triggering 125762306a36Sopenharmony_ci * type. In that case it is assumed that the current values 125862306a36Sopenharmony_ci * programmed to the hardware are used (e.g BIOS configured 125962306a36Sopenharmony_ci * defaults). 126062306a36Sopenharmony_ci * 126162306a36Sopenharmony_ci * In that case ->irq_set_type() will never be called so we need to 126262306a36Sopenharmony_ci * read back the values from hardware now, set correct flow handler 126362306a36Sopenharmony_ci * and update mappings before the interrupt is being used. 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci if (irqd_get_trigger_type(d) == IRQ_TYPE_NONE) { 126662306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 126762306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 126862306a36Sopenharmony_ci struct device *dev = pctrl->dev; 126962306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 127062306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 127162306a36Sopenharmony_ci irq_flow_handler_t handler; 127262306a36Sopenharmony_ci unsigned long flags; 127362306a36Sopenharmony_ci u32 intsel, value; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 127662306a36Sopenharmony_ci intsel = chv_readl(pctrl, hwirq, CHV_PADCTRL0); 127762306a36Sopenharmony_ci intsel &= CHV_PADCTRL0_INTSEL_MASK; 127862306a36Sopenharmony_ci intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci value = chv_readl(pctrl, hwirq, CHV_PADCTRL1); 128162306a36Sopenharmony_ci if (value & CHV_PADCTRL1_INTWAKECFG_LEVEL) 128262306a36Sopenharmony_ci handler = handle_level_irq; 128362306a36Sopenharmony_ci else 128462306a36Sopenharmony_ci handler = handle_edge_irq; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) { 128762306a36Sopenharmony_ci irq_set_handler_locked(d, handler); 128862306a36Sopenharmony_ci dev_dbg(dev, "using interrupt line %u for IRQ_TYPE_NONE on pin %lu\n", 128962306a36Sopenharmony_ci intsel, hwirq); 129062306a36Sopenharmony_ci cctx->intr_lines[intsel] = hwirq; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci chv_gpio_irq_unmask(d); 129662306a36Sopenharmony_ci return 0; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int chv_gpio_set_intr_line(struct intel_pinctrl *pctrl, unsigned int pin) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct device *dev = pctrl->dev; 130262306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 130362306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 130462306a36Sopenharmony_ci u32 value, intsel; 130562306a36Sopenharmony_ci int i; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci value = chv_readl(pctrl, pin, CHV_PADCTRL0); 130862306a36Sopenharmony_ci intsel = (value & CHV_PADCTRL0_INTSEL_MASK) >> CHV_PADCTRL0_INTSEL_SHIFT; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (cctx->intr_lines[intsel] == pin) 131162306a36Sopenharmony_ci return 0; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (cctx->intr_lines[intsel] == CHV_INVALID_HWIRQ) { 131462306a36Sopenharmony_ci dev_dbg(dev, "using interrupt line %u for pin %u\n", intsel, pin); 131562306a36Sopenharmony_ci cctx->intr_lines[intsel] = pin; 131662306a36Sopenharmony_ci return 0; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci /* 132062306a36Sopenharmony_ci * The interrupt line selected by the BIOS is already in use by 132162306a36Sopenharmony_ci * another pin, this is a known BIOS bug found on several models. 132262306a36Sopenharmony_ci * But this may also be caused by Linux deciding to use a pin as 132362306a36Sopenharmony_ci * IRQ which was not expected to be used as such by the BIOS authors, 132462306a36Sopenharmony_ci * so log this at info level only. 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ci dev_info(dev, "interrupt line %u is used by both pin %u and pin %u\n", intsel, 132762306a36Sopenharmony_ci cctx->intr_lines[intsel], pin); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (chv_pad_locked(pctrl, pin)) 133062306a36Sopenharmony_ci return -EBUSY; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* 133362306a36Sopenharmony_ci * The BIOS fills the interrupt lines from 0 counting up, start at 133462306a36Sopenharmony_ci * the other end to find a free interrupt line to workaround this. 133562306a36Sopenharmony_ci */ 133662306a36Sopenharmony_ci for (i = community->nirqs - 1; i >= 0; i--) { 133762306a36Sopenharmony_ci if (cctx->intr_lines[i] == CHV_INVALID_HWIRQ) 133862306a36Sopenharmony_ci break; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci if (i < 0) 134162306a36Sopenharmony_ci return -EBUSY; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci dev_info(dev, "changing the interrupt line for pin %u to %d\n", pin, i); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci value = (value & ~CHV_PADCTRL0_INTSEL_MASK) | (i << CHV_PADCTRL0_INTSEL_SHIFT); 134662306a36Sopenharmony_ci chv_writel(pctrl, pin, CHV_PADCTRL0, value); 134762306a36Sopenharmony_ci cctx->intr_lines[i] = pin; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci return 0; 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic int chv_gpio_irq_type(struct irq_data *d, unsigned int type) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 135562306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 135662306a36Sopenharmony_ci irq_hw_number_t hwirq = irqd_to_hwirq(d); 135762306a36Sopenharmony_ci unsigned long flags; 135862306a36Sopenharmony_ci u32 value; 135962306a36Sopenharmony_ci int ret; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ret = chv_gpio_set_intr_line(pctrl, hwirq); 136462306a36Sopenharmony_ci if (ret) { 136562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 136662306a36Sopenharmony_ci return ret; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci /* 137062306a36Sopenharmony_ci * Pins which can be used as shared interrupt are configured in 137162306a36Sopenharmony_ci * BIOS. Driver trusts BIOS configurations and assigns different 137262306a36Sopenharmony_ci * handler according to the irq type. 137362306a36Sopenharmony_ci * 137462306a36Sopenharmony_ci * Driver needs to save the mapping between each pin and 137562306a36Sopenharmony_ci * its interrupt line. 137662306a36Sopenharmony_ci * 1. If the pin cfg is locked in BIOS: 137762306a36Sopenharmony_ci * Trust BIOS has programmed IntWakeCfg bits correctly, 137862306a36Sopenharmony_ci * driver just needs to save the mapping. 137962306a36Sopenharmony_ci * 2. If the pin cfg is not locked in BIOS: 138062306a36Sopenharmony_ci * Driver programs the IntWakeCfg bits and save the mapping. 138162306a36Sopenharmony_ci */ 138262306a36Sopenharmony_ci if (!chv_pad_locked(pctrl, hwirq)) { 138362306a36Sopenharmony_ci value = chv_readl(pctrl, hwirq, CHV_PADCTRL1); 138462306a36Sopenharmony_ci value &= ~CHV_PADCTRL1_INTWAKECFG_MASK; 138562306a36Sopenharmony_ci value &= ~CHV_PADCTRL1_INVRXTX_MASK; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) { 138862306a36Sopenharmony_ci if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) 138962306a36Sopenharmony_ci value |= CHV_PADCTRL1_INTWAKECFG_BOTH; 139062306a36Sopenharmony_ci else if (type & IRQ_TYPE_EDGE_RISING) 139162306a36Sopenharmony_ci value |= CHV_PADCTRL1_INTWAKECFG_RISING; 139262306a36Sopenharmony_ci else if (type & IRQ_TYPE_EDGE_FALLING) 139362306a36Sopenharmony_ci value |= CHV_PADCTRL1_INTWAKECFG_FALLING; 139462306a36Sopenharmony_ci } else if (type & IRQ_TYPE_LEVEL_MASK) { 139562306a36Sopenharmony_ci value |= CHV_PADCTRL1_INTWAKECFG_LEVEL; 139662306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 139762306a36Sopenharmony_ci value |= CHV_PADCTRL1_INVRXTX_RXDATA; 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci chv_writel(pctrl, hwirq, CHV_PADCTRL1, value); 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) 140462306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 140562306a36Sopenharmony_ci else if (type & IRQ_TYPE_LEVEL_MASK) 140662306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci return 0; 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic const struct irq_chip chv_gpio_irq_chip = { 141462306a36Sopenharmony_ci .name = "chv-gpio", 141562306a36Sopenharmony_ci .irq_startup = chv_gpio_irq_startup, 141662306a36Sopenharmony_ci .irq_ack = chv_gpio_irq_ack, 141762306a36Sopenharmony_ci .irq_mask = chv_gpio_irq_mask, 141862306a36Sopenharmony_ci .irq_unmask = chv_gpio_irq_unmask, 141962306a36Sopenharmony_ci .irq_set_type = chv_gpio_irq_type, 142062306a36Sopenharmony_ci .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE, 142162306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 142262306a36Sopenharmony_ci}; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic void chv_gpio_irq_handler(struct irq_desc *desc) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 142762306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(gc); 142862306a36Sopenharmony_ci struct device *dev = pctrl->dev; 142962306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 143062306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 143162306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 143262306a36Sopenharmony_ci unsigned long pending; 143362306a36Sopenharmony_ci unsigned long flags; 143462306a36Sopenharmony_ci u32 intr_line; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci chained_irq_enter(chip, desc); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 143962306a36Sopenharmony_ci pending = chv_pctrl_readl(pctrl, CHV_INTSTAT); 144062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci for_each_set_bit(intr_line, &pending, community->nirqs) { 144362306a36Sopenharmony_ci unsigned int offset; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci offset = cctx->intr_lines[intr_line]; 144662306a36Sopenharmony_ci if (offset == CHV_INVALID_HWIRQ) { 144762306a36Sopenharmony_ci dev_warn_once(dev, "interrupt on unmapped interrupt line %u\n", intr_line); 144862306a36Sopenharmony_ci /* Some boards expect hwirq 0 to trigger in this case */ 144962306a36Sopenharmony_ci offset = 0; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci generic_handle_domain_irq(gc->irq.domain, offset); 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci chained_irq_exit(chip, desc); 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci/* 145962306a36Sopenharmony_ci * Certain machines seem to hardcode Linux IRQ numbers in their ACPI 146062306a36Sopenharmony_ci * tables. Since we leave GPIOs that are not capable of generating 146162306a36Sopenharmony_ci * interrupts out of the irqdomain the numbering will be different and 146262306a36Sopenharmony_ci * cause devices using the hardcoded IRQ numbers fail. In order not to 146362306a36Sopenharmony_ci * break such machines we will only mask pins from irqdomain if the machine 146462306a36Sopenharmony_ci * is not listed below. 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_cistatic const struct dmi_system_id chv_no_valid_mask[] = { 146762306a36Sopenharmony_ci /* See https://bugzilla.kernel.org/show_bug.cgi?id=194945 */ 146862306a36Sopenharmony_ci { 146962306a36Sopenharmony_ci .ident = "Intel_Strago based Chromebooks (All models)", 147062306a36Sopenharmony_ci .matches = { 147162306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 147262306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_Strago"), 147362306a36Sopenharmony_ci }, 147462306a36Sopenharmony_ci }, 147562306a36Sopenharmony_ci { 147662306a36Sopenharmony_ci .ident = "HP Chromebook 11 G5 (Setzer)", 147762306a36Sopenharmony_ci .matches = { 147862306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "HP"), 147962306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"), 148062306a36Sopenharmony_ci }, 148162306a36Sopenharmony_ci }, 148262306a36Sopenharmony_ci { 148362306a36Sopenharmony_ci .ident = "Acer Chromebook R11 (Cyan)", 148462306a36Sopenharmony_ci .matches = { 148562306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 148662306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"), 148762306a36Sopenharmony_ci }, 148862306a36Sopenharmony_ci }, 148962306a36Sopenharmony_ci { 149062306a36Sopenharmony_ci .ident = "Samsung Chromebook 3 (Celes)", 149162306a36Sopenharmony_ci .matches = { 149262306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), 149362306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), 149462306a36Sopenharmony_ci }, 149562306a36Sopenharmony_ci }, 149662306a36Sopenharmony_ci {} 149762306a36Sopenharmony_ci}; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic void chv_init_irq_valid_mask(struct gpio_chip *chip, 150062306a36Sopenharmony_ci unsigned long *valid_mask, 150162306a36Sopenharmony_ci unsigned int ngpios) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 150462306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 150562306a36Sopenharmony_ci int i; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci /* Do not add GPIOs that can only generate GPEs to the IRQ domain */ 150862306a36Sopenharmony_ci for (i = 0; i < pctrl->soc->npins; i++) { 150962306a36Sopenharmony_ci const struct pinctrl_pin_desc *desc; 151062306a36Sopenharmony_ci u32 intsel; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci desc = &pctrl->soc->pins[i]; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci intsel = chv_readl(pctrl, desc->number, CHV_PADCTRL0); 151562306a36Sopenharmony_ci intsel &= CHV_PADCTRL0_INTSEL_MASK; 151662306a36Sopenharmony_ci intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (intsel >= community->nirqs) 151962306a36Sopenharmony_ci clear_bit(desc->number, valid_mask); 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci} 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_cistatic int chv_gpio_irq_init_hw(struct gpio_chip *chip) 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 152662306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* 152962306a36Sopenharmony_ci * The same set of machines in chv_no_valid_mask[] have incorrectly 153062306a36Sopenharmony_ci * configured GPIOs that generate spurious interrupts so we use 153162306a36Sopenharmony_ci * this same list to apply another quirk for them. 153262306a36Sopenharmony_ci * 153362306a36Sopenharmony_ci * See also https://bugzilla.kernel.org/show_bug.cgi?id=197953. 153462306a36Sopenharmony_ci */ 153562306a36Sopenharmony_ci if (!pctrl->chip.irq.init_valid_mask) { 153662306a36Sopenharmony_ci /* 153762306a36Sopenharmony_ci * Mask all interrupts the community is able to generate 153862306a36Sopenharmony_ci * but leave the ones that can only generate GPEs unmasked. 153962306a36Sopenharmony_ci */ 154062306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTMASK, GENMASK(31, community->nirqs)); 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* Clear all interrupts */ 154462306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTSTAT, 0xffff); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic int chv_gpio_add_pin_ranges(struct gpio_chip *chip) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci struct intel_pinctrl *pctrl = gpiochip_get_data(chip); 155262306a36Sopenharmony_ci struct device *dev = pctrl->dev; 155362306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 155462306a36Sopenharmony_ci const struct intel_padgroup *gpp; 155562306a36Sopenharmony_ci int ret, i; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci for (i = 0; i < community->ngpps; i++) { 155862306a36Sopenharmony_ci gpp = &community->gpps[i]; 155962306a36Sopenharmony_ci ret = gpiochip_add_pin_range(chip, dev_name(dev), gpp->base, gpp->base, gpp->size); 156062306a36Sopenharmony_ci if (ret) { 156162306a36Sopenharmony_ci dev_err(dev, "failed to add GPIO pin range\n"); 156262306a36Sopenharmony_ci return ret; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci return 0; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int chv_gpio_probe(struct intel_pinctrl *pctrl, int irq) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 157262306a36Sopenharmony_ci const struct intel_padgroup *gpp; 157362306a36Sopenharmony_ci struct gpio_chip *chip = &pctrl->chip; 157462306a36Sopenharmony_ci struct device *dev = pctrl->dev; 157562306a36Sopenharmony_ci bool need_valid_mask = !dmi_check_system(chv_no_valid_mask); 157662306a36Sopenharmony_ci int ret, i, irq_base; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci *chip = chv_gpio_chip; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci chip->ngpio = pctrl->soc->pins[pctrl->soc->npins - 1].number + 1; 158162306a36Sopenharmony_ci chip->label = dev_name(dev); 158262306a36Sopenharmony_ci chip->add_pin_ranges = chv_gpio_add_pin_ranges; 158362306a36Sopenharmony_ci chip->parent = dev; 158462306a36Sopenharmony_ci chip->base = -1; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci pctrl->irq = irq; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci gpio_irq_chip_set_chip(&chip->irq, &chv_gpio_irq_chip); 158962306a36Sopenharmony_ci chip->irq.init_hw = chv_gpio_irq_init_hw; 159062306a36Sopenharmony_ci chip->irq.parent_handler = chv_gpio_irq_handler; 159162306a36Sopenharmony_ci chip->irq.num_parents = 1; 159262306a36Sopenharmony_ci chip->irq.parents = &pctrl->irq; 159362306a36Sopenharmony_ci chip->irq.default_type = IRQ_TYPE_NONE; 159462306a36Sopenharmony_ci chip->irq.handler = handle_bad_irq; 159562306a36Sopenharmony_ci if (need_valid_mask) { 159662306a36Sopenharmony_ci chip->irq.init_valid_mask = chv_init_irq_valid_mask; 159762306a36Sopenharmony_ci } else { 159862306a36Sopenharmony_ci irq_base = devm_irq_alloc_descs(dev, -1, 0, pctrl->soc->npins, NUMA_NO_NODE); 159962306a36Sopenharmony_ci if (irq_base < 0) { 160062306a36Sopenharmony_ci dev_err(dev, "Failed to allocate IRQ numbers\n"); 160162306a36Sopenharmony_ci return irq_base; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, chip, pctrl); 160662306a36Sopenharmony_ci if (ret) { 160762306a36Sopenharmony_ci dev_err(dev, "Failed to register gpiochip\n"); 160862306a36Sopenharmony_ci return ret; 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (!need_valid_mask) { 161262306a36Sopenharmony_ci for (i = 0; i < community->ngpps; i++) { 161362306a36Sopenharmony_ci gpp = &community->gpps[i]; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci irq_domain_associate_many(chip->irq.domain, irq_base, 161662306a36Sopenharmony_ci gpp->base, gpp->size); 161762306a36Sopenharmony_ci irq_base += gpp->size; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic acpi_status chv_pinctrl_mmio_access_handler(u32 function, 162562306a36Sopenharmony_ci acpi_physical_address address, u32 bits, u64 *value, 162662306a36Sopenharmony_ci void *handler_context, void *region_context) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct intel_pinctrl *pctrl = region_context; 162962306a36Sopenharmony_ci unsigned long flags; 163062306a36Sopenharmony_ci acpi_status ret = AE_OK; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (function == ACPI_WRITE) 163562306a36Sopenharmony_ci chv_pctrl_writel(pctrl, address, *value); 163662306a36Sopenharmony_ci else if (function == ACPI_READ) 163762306a36Sopenharmony_ci *value = chv_pctrl_readl(pctrl, address); 163862306a36Sopenharmony_ci else 163962306a36Sopenharmony_ci ret = AE_BAD_PARAMETER; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci return ret; 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cistatic int chv_pinctrl_probe(struct platform_device *pdev) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci const struct intel_pinctrl_soc_data *soc_data; 164962306a36Sopenharmony_ci struct intel_community_context *cctx; 165062306a36Sopenharmony_ci struct intel_community *community; 165162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 165262306a36Sopenharmony_ci struct intel_pinctrl *pctrl; 165362306a36Sopenharmony_ci acpi_status status; 165462306a36Sopenharmony_ci unsigned int i; 165562306a36Sopenharmony_ci int ret, irq; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci soc_data = intel_pinctrl_get_soc_data(pdev); 165862306a36Sopenharmony_ci if (IS_ERR(soc_data)) 165962306a36Sopenharmony_ci return PTR_ERR(soc_data); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); 166262306a36Sopenharmony_ci if (!pctrl) 166362306a36Sopenharmony_ci return -ENOMEM; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci pctrl->dev = dev; 166662306a36Sopenharmony_ci pctrl->soc = soc_data; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci pctrl->ncommunities = pctrl->soc->ncommunities; 166962306a36Sopenharmony_ci pctrl->communities = devm_kmemdup(dev, pctrl->soc->communities, 167062306a36Sopenharmony_ci pctrl->ncommunities * sizeof(*pctrl->communities), 167162306a36Sopenharmony_ci GFP_KERNEL); 167262306a36Sopenharmony_ci if (!pctrl->communities) 167362306a36Sopenharmony_ci return -ENOMEM; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci community = &pctrl->communities[0]; 167662306a36Sopenharmony_ci community->regs = devm_platform_ioremap_resource(pdev, 0); 167762306a36Sopenharmony_ci if (IS_ERR(community->regs)) 167862306a36Sopenharmony_ci return PTR_ERR(community->regs); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci community->pad_regs = community->regs + FAMILY_PAD_REGS_OFF; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 168362306a36Sopenharmony_ci pctrl->context.pads = devm_kcalloc(dev, pctrl->soc->npins, 168462306a36Sopenharmony_ci sizeof(*pctrl->context.pads), 168562306a36Sopenharmony_ci GFP_KERNEL); 168662306a36Sopenharmony_ci if (!pctrl->context.pads) 168762306a36Sopenharmony_ci return -ENOMEM; 168862306a36Sopenharmony_ci#endif 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci pctrl->context.communities = devm_kcalloc(dev, pctrl->soc->ncommunities, 169162306a36Sopenharmony_ci sizeof(*pctrl->context.communities), 169262306a36Sopenharmony_ci GFP_KERNEL); 169362306a36Sopenharmony_ci if (!pctrl->context.communities) 169462306a36Sopenharmony_ci return -ENOMEM; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci cctx = &pctrl->context.communities[0]; 169762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cctx->intr_lines); i++) 169862306a36Sopenharmony_ci cctx->intr_lines[i] = CHV_INVALID_HWIRQ; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 170162306a36Sopenharmony_ci if (irq < 0) 170262306a36Sopenharmony_ci return irq; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci pctrl->pctldesc = chv_pinctrl_desc; 170562306a36Sopenharmony_ci pctrl->pctldesc.name = dev_name(dev); 170662306a36Sopenharmony_ci pctrl->pctldesc.pins = pctrl->soc->pins; 170762306a36Sopenharmony_ci pctrl->pctldesc.npins = pctrl->soc->npins; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pctldesc, pctrl); 171062306a36Sopenharmony_ci if (IS_ERR(pctrl->pctldev)) { 171162306a36Sopenharmony_ci dev_err(dev, "failed to register pinctrl driver\n"); 171262306a36Sopenharmony_ci return PTR_ERR(pctrl->pctldev); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci ret = chv_gpio_probe(pctrl, irq); 171662306a36Sopenharmony_ci if (ret) 171762306a36Sopenharmony_ci return ret; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci status = acpi_install_address_space_handler(ACPI_HANDLE(dev), 172062306a36Sopenharmony_ci community->acpi_space_id, 172162306a36Sopenharmony_ci chv_pinctrl_mmio_access_handler, 172262306a36Sopenharmony_ci NULL, pctrl); 172362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) 172462306a36Sopenharmony_ci dev_err(dev, "failed to install ACPI addr space handler\n"); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci platform_set_drvdata(pdev, pctrl); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci return 0; 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cistatic int chv_pinctrl_remove(struct platform_device *pdev) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct intel_pinctrl *pctrl = platform_get_drvdata(pdev); 173462306a36Sopenharmony_ci const struct intel_community *community = &pctrl->communities[0]; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci acpi_remove_address_space_handler(ACPI_HANDLE(&pdev->dev), 173762306a36Sopenharmony_ci community->acpi_space_id, 173862306a36Sopenharmony_ci chv_pinctrl_mmio_access_handler); 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci return 0; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_cistatic int chv_pinctrl_suspend_noirq(struct device *dev) 174462306a36Sopenharmony_ci{ 174562306a36Sopenharmony_ci struct intel_pinctrl *pctrl = dev_get_drvdata(dev); 174662306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 174762306a36Sopenharmony_ci unsigned long flags; 174862306a36Sopenharmony_ci int i; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci cctx->saved_intmask = chv_pctrl_readl(pctrl, CHV_INTMASK); 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci for (i = 0; i < pctrl->soc->npins; i++) { 175562306a36Sopenharmony_ci const struct pinctrl_pin_desc *desc; 175662306a36Sopenharmony_ci struct intel_pad_context *ctx = &pctrl->context.pads[i]; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci desc = &pctrl->soc->pins[i]; 175962306a36Sopenharmony_ci if (chv_pad_locked(pctrl, desc->number)) 176062306a36Sopenharmony_ci continue; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci ctx->padctrl0 = chv_readl(pctrl, desc->number, CHV_PADCTRL0); 176362306a36Sopenharmony_ci ctx->padctrl0 &= ~CHV_PADCTRL0_GPIORXSTATE; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci ctx->padctrl1 = chv_readl(pctrl, desc->number, CHV_PADCTRL1); 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci return 0; 177162306a36Sopenharmony_ci} 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_cistatic int chv_pinctrl_resume_noirq(struct device *dev) 177462306a36Sopenharmony_ci{ 177562306a36Sopenharmony_ci struct intel_pinctrl *pctrl = dev_get_drvdata(dev); 177662306a36Sopenharmony_ci struct intel_community_context *cctx = &pctrl->context.communities[0]; 177762306a36Sopenharmony_ci unsigned long flags; 177862306a36Sopenharmony_ci int i; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chv_lock, flags); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* 178362306a36Sopenharmony_ci * Mask all interrupts before restoring per-pin configuration 178462306a36Sopenharmony_ci * registers because we don't know in which state BIOS left them 178562306a36Sopenharmony_ci * upon exiting suspend. 178662306a36Sopenharmony_ci */ 178762306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTMASK, 0x0000); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci for (i = 0; i < pctrl->soc->npins; i++) { 179062306a36Sopenharmony_ci const struct pinctrl_pin_desc *desc; 179162306a36Sopenharmony_ci struct intel_pad_context *ctx = &pctrl->context.pads[i]; 179262306a36Sopenharmony_ci u32 val; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci desc = &pctrl->soc->pins[i]; 179562306a36Sopenharmony_ci if (chv_pad_locked(pctrl, desc->number)) 179662306a36Sopenharmony_ci continue; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci /* Only restore if our saved state differs from the current */ 179962306a36Sopenharmony_ci val = chv_readl(pctrl, desc->number, CHV_PADCTRL0); 180062306a36Sopenharmony_ci val &= ~CHV_PADCTRL0_GPIORXSTATE; 180162306a36Sopenharmony_ci if (ctx->padctrl0 != val) { 180262306a36Sopenharmony_ci chv_writel(pctrl, desc->number, CHV_PADCTRL0, ctx->padctrl0); 180362306a36Sopenharmony_ci dev_dbg(dev, "restored pin %2u ctrl0 0x%08x\n", desc->number, 180462306a36Sopenharmony_ci chv_readl(pctrl, desc->number, CHV_PADCTRL0)); 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci val = chv_readl(pctrl, desc->number, CHV_PADCTRL1); 180862306a36Sopenharmony_ci if (ctx->padctrl1 != val) { 180962306a36Sopenharmony_ci chv_writel(pctrl, desc->number, CHV_PADCTRL1, ctx->padctrl1); 181062306a36Sopenharmony_ci dev_dbg(dev, "restored pin %2u ctrl1 0x%08x\n", desc->number, 181162306a36Sopenharmony_ci chv_readl(pctrl, desc->number, CHV_PADCTRL1)); 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci /* 181662306a36Sopenharmony_ci * Now that all pins are restored to known state, we can restore 181762306a36Sopenharmony_ci * the interrupt mask register as well. 181862306a36Sopenharmony_ci */ 181962306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTSTAT, 0xffff); 182062306a36Sopenharmony_ci chv_pctrl_writel(pctrl, CHV_INTMASK, cctx->saved_intmask); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chv_lock, flags); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return 0; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic DEFINE_NOIRQ_DEV_PM_OPS(chv_pinctrl_pm_ops, 182862306a36Sopenharmony_ci chv_pinctrl_suspend_noirq, chv_pinctrl_resume_noirq); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_cistatic const struct acpi_device_id chv_pinctrl_acpi_match[] = { 183162306a36Sopenharmony_ci { "INT33FF", (kernel_ulong_t)chv_soc_data }, 183262306a36Sopenharmony_ci { } 183362306a36Sopenharmony_ci}; 183462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_cistatic struct platform_driver chv_pinctrl_driver = { 183762306a36Sopenharmony_ci .probe = chv_pinctrl_probe, 183862306a36Sopenharmony_ci .remove = chv_pinctrl_remove, 183962306a36Sopenharmony_ci .driver = { 184062306a36Sopenharmony_ci .name = "cherryview-pinctrl", 184162306a36Sopenharmony_ci .pm = pm_sleep_ptr(&chv_pinctrl_pm_ops), 184262306a36Sopenharmony_ci .acpi_match_table = chv_pinctrl_acpi_match, 184362306a36Sopenharmony_ci }, 184462306a36Sopenharmony_ci}; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_cistatic int __init chv_pinctrl_init(void) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci return platform_driver_register(&chv_pinctrl_driver); 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_cisubsys_initcall(chv_pinctrl_init); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void __exit chv_pinctrl_exit(void) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci platform_driver_unregister(&chv_pinctrl_driver); 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_cimodule_exit(chv_pinctrl_exit); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ciMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 185962306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Cherryview/Braswell pinctrl driver"); 186062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 186162306a36Sopenharmony_ciMODULE_IMPORT_NS(PINCTRL_INTEL); 1862