162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic GPIO driver for logic cells found in the Nomadik SoC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008,2009 STMicroelectronics 662306a36Sopenharmony_ci * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> 762306a36Sopenharmony_ci * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> 862306a36Sopenharmony_ci * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/of_address.h> 2062306a36Sopenharmony_ci#include <linux/of_device.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/seq_file.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <linux/spinlock.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Since we request GPIOs from ourself */ 2762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2862306a36Sopenharmony_ci#include <linux/pinctrl/machine.h> 2962306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 3062306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 3162306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "../core.h" 3462306a36Sopenharmony_ci#include "../pinctrl-utils.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "pinctrl-nomadik.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * The GPIO module in the Nomadik family of Systems-on-Chip is an 4062306a36Sopenharmony_ci * AMBA device, managing 32 pins and alternate functions. The logic block 4162306a36Sopenharmony_ci * is currently used in the Nomadik and ux500. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Symbols in this file are called "nmk_gpio" for "nomadik gpio" 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * pin configurations are represented by 32-bit integers: 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * bit 0.. 8 - Pin Number (512 Pins Maximum) 5062306a36Sopenharmony_ci * bit 9..10 - Alternate Function Selection 5162306a36Sopenharmony_ci * bit 11..12 - Pull up/down state 5262306a36Sopenharmony_ci * bit 13 - Sleep mode behaviour 5362306a36Sopenharmony_ci * bit 14 - Direction 5462306a36Sopenharmony_ci * bit 15 - Value (if output) 5562306a36Sopenharmony_ci * bit 16..18 - SLPM pull up/down state 5662306a36Sopenharmony_ci * bit 19..20 - SLPM direction 5762306a36Sopenharmony_ci * bit 21..22 - SLPM Value (if output) 5862306a36Sopenharmony_ci * bit 23..25 - PDIS value (if input) 5962306a36Sopenharmony_ci * bit 26 - Gpio mode 6062306a36Sopenharmony_ci * bit 27 - Sleep mode 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * to facilitate the definition, the following macros are provided 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * PIN_CFG_DEFAULT - default config (0): 6562306a36Sopenharmony_ci * pull up/down = disabled 6662306a36Sopenharmony_ci * sleep mode = input/wakeup 6762306a36Sopenharmony_ci * direction = input 6862306a36Sopenharmony_ci * value = low 6962306a36Sopenharmony_ci * SLPM direction = same as normal 7062306a36Sopenharmony_ci * SLPM pull = same as normal 7162306a36Sopenharmony_ci * SLPM value = same as normal 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * PIN_CFG - default config with alternate function 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_citypedef unsigned long pin_cfg_t; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define PIN_NUM_MASK 0x1ff 7962306a36Sopenharmony_ci#define PIN_NUM(x) ((x) & PIN_NUM_MASK) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define PIN_ALT_SHIFT 9 8262306a36Sopenharmony_ci#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT) 8362306a36Sopenharmony_ci#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT) 8462306a36Sopenharmony_ci#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT) 8562306a36Sopenharmony_ci#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT) 8662306a36Sopenharmony_ci#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT) 8762306a36Sopenharmony_ci#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define PIN_PULL_SHIFT 11 9062306a36Sopenharmony_ci#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT) 9162306a36Sopenharmony_ci#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT) 9262306a36Sopenharmony_ci#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT) 9362306a36Sopenharmony_ci#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT) 9462306a36Sopenharmony_ci#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define PIN_SLPM_SHIFT 13 9762306a36Sopenharmony_ci#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT) 9862306a36Sopenharmony_ci#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT) 9962306a36Sopenharmony_ci#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT) 10062306a36Sopenharmony_ci#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT) 10162306a36Sopenharmony_ci/* These two replace the above in DB8500v2+ */ 10262306a36Sopenharmony_ci#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT) 10362306a36Sopenharmony_ci#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT) 10462306a36Sopenharmony_ci#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */ 10762306a36Sopenharmony_ci#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#define PIN_DIR_SHIFT 14 11062306a36Sopenharmony_ci#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT) 11162306a36Sopenharmony_ci#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT) 11262306a36Sopenharmony_ci#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT) 11362306a36Sopenharmony_ci#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define PIN_VAL_SHIFT 15 11662306a36Sopenharmony_ci#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT) 11762306a36Sopenharmony_ci#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT) 11862306a36Sopenharmony_ci#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) 11962306a36Sopenharmony_ci#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define PIN_SLPM_PULL_SHIFT 16 12262306a36Sopenharmony_ci#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) 12362306a36Sopenharmony_ci#define PIN_SLPM_PULL(x) \ 12462306a36Sopenharmony_ci (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) 12562306a36Sopenharmony_ci#define PIN_SLPM_PULL_NONE \ 12662306a36Sopenharmony_ci ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) 12762306a36Sopenharmony_ci#define PIN_SLPM_PULL_UP \ 12862306a36Sopenharmony_ci ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) 12962306a36Sopenharmony_ci#define PIN_SLPM_PULL_DOWN \ 13062306a36Sopenharmony_ci ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define PIN_SLPM_DIR_SHIFT 19 13362306a36Sopenharmony_ci#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) 13462306a36Sopenharmony_ci#define PIN_SLPM_DIR(x) \ 13562306a36Sopenharmony_ci (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) 13662306a36Sopenharmony_ci#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) 13762306a36Sopenharmony_ci#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define PIN_SLPM_VAL_SHIFT 21 14062306a36Sopenharmony_ci#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) 14162306a36Sopenharmony_ci#define PIN_SLPM_VAL(x) \ 14262306a36Sopenharmony_ci (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) 14362306a36Sopenharmony_ci#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) 14462306a36Sopenharmony_ci#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define PIN_SLPM_PDIS_SHIFT 23 14762306a36Sopenharmony_ci#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT) 14862306a36Sopenharmony_ci#define PIN_SLPM_PDIS(x) \ 14962306a36Sopenharmony_ci (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT) 15062306a36Sopenharmony_ci#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT) 15162306a36Sopenharmony_ci#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT) 15262306a36Sopenharmony_ci#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define PIN_LOWEMI_SHIFT 25 15562306a36Sopenharmony_ci#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT) 15662306a36Sopenharmony_ci#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT) 15762306a36Sopenharmony_ci#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) 15862306a36Sopenharmony_ci#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define PIN_GPIOMODE_SHIFT 26 16162306a36Sopenharmony_ci#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) 16262306a36Sopenharmony_ci#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) 16362306a36Sopenharmony_ci#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) 16462306a36Sopenharmony_ci#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define PIN_SLEEPMODE_SHIFT 27 16762306a36Sopenharmony_ci#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) 16862306a36Sopenharmony_ci#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) 16962306a36Sopenharmony_ci#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) 17062306a36Sopenharmony_ci#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ 17462306a36Sopenharmony_ci#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) 17562306a36Sopenharmony_ci#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) 17662306a36Sopenharmony_ci#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) 17762306a36Sopenharmony_ci#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) 17862306a36Sopenharmony_ci#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) 18162306a36Sopenharmony_ci#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) 18262306a36Sopenharmony_ci#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) 18362306a36Sopenharmony_ci#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) 18462306a36Sopenharmony_ci#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define PIN_CFG_DEFAULT (0) 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci#define PIN_CFG(num, alt) \ 18962306a36Sopenharmony_ci (PIN_CFG_DEFAULT |\ 19062306a36Sopenharmony_ci (PIN_NUM(num) | PIN_##alt)) 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define PIN_CFG_INPUT(num, alt, pull) \ 19362306a36Sopenharmony_ci (PIN_CFG_DEFAULT |\ 19462306a36Sopenharmony_ci (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define PIN_CFG_OUTPUT(num, alt, val) \ 19762306a36Sopenharmony_ci (PIN_CFG_DEFAULT |\ 19862306a36Sopenharmony_ci (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* 20162306a36Sopenharmony_ci * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving 20262306a36Sopenharmony_ci * the "gpio" namespace for generic and cross-machine functions 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#define GPIO_BLOCK_SHIFT 5 20662306a36Sopenharmony_ci#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) 20762306a36Sopenharmony_ci#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* Register in the logic block */ 21062306a36Sopenharmony_ci#define NMK_GPIO_DAT 0x00 21162306a36Sopenharmony_ci#define NMK_GPIO_DATS 0x04 21262306a36Sopenharmony_ci#define NMK_GPIO_DATC 0x08 21362306a36Sopenharmony_ci#define NMK_GPIO_PDIS 0x0c 21462306a36Sopenharmony_ci#define NMK_GPIO_DIR 0x10 21562306a36Sopenharmony_ci#define NMK_GPIO_DIRS 0x14 21662306a36Sopenharmony_ci#define NMK_GPIO_DIRC 0x18 21762306a36Sopenharmony_ci#define NMK_GPIO_SLPC 0x1c 21862306a36Sopenharmony_ci#define NMK_GPIO_AFSLA 0x20 21962306a36Sopenharmony_ci#define NMK_GPIO_AFSLB 0x24 22062306a36Sopenharmony_ci#define NMK_GPIO_LOWEMI 0x28 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci#define NMK_GPIO_RIMSC 0x40 22362306a36Sopenharmony_ci#define NMK_GPIO_FIMSC 0x44 22462306a36Sopenharmony_ci#define NMK_GPIO_IS 0x48 22562306a36Sopenharmony_ci#define NMK_GPIO_IC 0x4c 22662306a36Sopenharmony_ci#define NMK_GPIO_RWIMSC 0x50 22762306a36Sopenharmony_ci#define NMK_GPIO_FWIMSC 0x54 22862306a36Sopenharmony_ci#define NMK_GPIO_WKS 0x58 22962306a36Sopenharmony_ci/* These appear in DB8540 and later ASICs */ 23062306a36Sopenharmony_ci#define NMK_GPIO_EDGELEVEL 0x5C 23162306a36Sopenharmony_ci#define NMK_GPIO_LEVEL 0x60 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* Pull up/down values */ 23562306a36Sopenharmony_cienum nmk_gpio_pull { 23662306a36Sopenharmony_ci NMK_GPIO_PULL_NONE, 23762306a36Sopenharmony_ci NMK_GPIO_PULL_UP, 23862306a36Sopenharmony_ci NMK_GPIO_PULL_DOWN, 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* Sleep mode */ 24262306a36Sopenharmony_cienum nmk_gpio_slpm { 24362306a36Sopenharmony_ci NMK_GPIO_SLPM_INPUT, 24462306a36Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT, 24562306a36Sopenharmony_ci NMK_GPIO_SLPM_NOCHANGE, 24662306a36Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistruct nmk_gpio_chip { 25062306a36Sopenharmony_ci struct gpio_chip chip; 25162306a36Sopenharmony_ci void __iomem *addr; 25262306a36Sopenharmony_ci struct clk *clk; 25362306a36Sopenharmony_ci unsigned int bank; 25462306a36Sopenharmony_ci void (*set_ioforce)(bool enable); 25562306a36Sopenharmony_ci spinlock_t lock; 25662306a36Sopenharmony_ci bool sleepmode; 25762306a36Sopenharmony_ci /* Keep track of configured edges */ 25862306a36Sopenharmony_ci u32 edge_rising; 25962306a36Sopenharmony_ci u32 edge_falling; 26062306a36Sopenharmony_ci u32 real_wake; 26162306a36Sopenharmony_ci u32 rwimsc; 26262306a36Sopenharmony_ci u32 fwimsc; 26362306a36Sopenharmony_ci u32 rimsc; 26462306a36Sopenharmony_ci u32 fimsc; 26562306a36Sopenharmony_ci u32 pull_up; 26662306a36Sopenharmony_ci u32 lowemi; 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/** 27062306a36Sopenharmony_ci * struct nmk_pinctrl - state container for the Nomadik pin controller 27162306a36Sopenharmony_ci * @dev: containing device pointer 27262306a36Sopenharmony_ci * @pctl: corresponding pin controller device 27362306a36Sopenharmony_ci * @soc: SoC data for this specific chip 27462306a36Sopenharmony_ci * @prcm_base: PRCM register range virtual base 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_cistruct nmk_pinctrl { 27762306a36Sopenharmony_ci struct device *dev; 27862306a36Sopenharmony_ci struct pinctrl_dev *pctl; 27962306a36Sopenharmony_ci const struct nmk_pinctrl_soc_data *soc; 28062306a36Sopenharmony_ci void __iomem *prcm_base; 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(nmk_gpio_slpm_lock); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, 29062306a36Sopenharmony_ci unsigned offset, int gpio_mode) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci u32 afunc, bfunc; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~BIT(offset); 29562306a36Sopenharmony_ci bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~BIT(offset); 29662306a36Sopenharmony_ci if (gpio_mode & NMK_GPIO_ALT_A) 29762306a36Sopenharmony_ci afunc |= BIT(offset); 29862306a36Sopenharmony_ci if (gpio_mode & NMK_GPIO_ALT_B) 29962306a36Sopenharmony_ci bfunc |= BIT(offset); 30062306a36Sopenharmony_ci writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); 30162306a36Sopenharmony_ci writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, 30562306a36Sopenharmony_ci unsigned offset, enum nmk_gpio_slpm mode) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci u32 slpm; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); 31062306a36Sopenharmony_ci if (mode == NMK_GPIO_SLPM_NOCHANGE) 31162306a36Sopenharmony_ci slpm |= BIT(offset); 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci slpm &= ~BIT(offset); 31462306a36Sopenharmony_ci writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, 31862306a36Sopenharmony_ci unsigned offset, enum nmk_gpio_pull pull) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci u32 pdis; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); 32362306a36Sopenharmony_ci if (pull == NMK_GPIO_PULL_NONE) { 32462306a36Sopenharmony_ci pdis |= BIT(offset); 32562306a36Sopenharmony_ci nmk_chip->pull_up &= ~BIT(offset); 32662306a36Sopenharmony_ci } else { 32762306a36Sopenharmony_ci pdis &= ~BIT(offset); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (pull == NMK_GPIO_PULL_UP) { 33362306a36Sopenharmony_ci nmk_chip->pull_up |= BIT(offset); 33462306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); 33562306a36Sopenharmony_ci } else if (pull == NMK_GPIO_PULL_DOWN) { 33662306a36Sopenharmony_ci nmk_chip->pull_up &= ~BIT(offset); 33762306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip, 34262306a36Sopenharmony_ci unsigned offset, bool lowemi) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci bool enabled = nmk_chip->lowemi & BIT(offset); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (lowemi == enabled) 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (lowemi) 35062306a36Sopenharmony_ci nmk_chip->lowemi |= BIT(offset); 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci nmk_chip->lowemi &= ~BIT(offset); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci writel_relaxed(nmk_chip->lowemi, 35562306a36Sopenharmony_ci nmk_chip->addr + NMK_GPIO_LOWEMI); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, 35962306a36Sopenharmony_ci unsigned offset) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip, 36562306a36Sopenharmony_ci unsigned offset, int val) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci if (val) 36862306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); 36962306a36Sopenharmony_ci else 37062306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, 37462306a36Sopenharmony_ci unsigned offset, int val) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRS); 37762306a36Sopenharmony_ci __nmk_gpio_set_output(nmk_chip, offset, val); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, 38162306a36Sopenharmony_ci unsigned offset, int gpio_mode, 38262306a36Sopenharmony_ci bool glitch) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci u32 rwimsc = nmk_chip->rwimsc; 38562306a36Sopenharmony_ci u32 fwimsc = nmk_chip->fwimsc; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if (glitch && nmk_chip->set_ioforce) { 38862306a36Sopenharmony_ci u32 bit = BIT(offset); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Prevent spurious wakeups */ 39162306a36Sopenharmony_ci writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC); 39262306a36Sopenharmony_ci writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci nmk_chip->set_ioforce(true); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (glitch && nmk_chip->set_ioforce) { 40062306a36Sopenharmony_ci nmk_chip->set_ioforce(false); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC); 40362306a36Sopenharmony_ci writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void 40862306a36Sopenharmony_cinmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci u32 falling = nmk_chip->fimsc & BIT(offset); 41162306a36Sopenharmony_ci u32 rising = nmk_chip->rimsc & BIT(offset); 41262306a36Sopenharmony_ci int gpio = nmk_chip->chip.base + offset; 41362306a36Sopenharmony_ci int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset); 41462306a36Sopenharmony_ci struct irq_data *d = irq_get_irq_data(irq); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!rising && !falling) 41762306a36Sopenharmony_ci return; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!d || !irqd_irq_disabled(d)) 42062306a36Sopenharmony_ci return; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (rising) { 42362306a36Sopenharmony_ci nmk_chip->rimsc &= ~BIT(offset); 42462306a36Sopenharmony_ci writel_relaxed(nmk_chip->rimsc, 42562306a36Sopenharmony_ci nmk_chip->addr + NMK_GPIO_RIMSC); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (falling) { 42962306a36Sopenharmony_ci nmk_chip->fimsc &= ~BIT(offset); 43062306a36Sopenharmony_ci writel_relaxed(nmk_chip->fimsc, 43162306a36Sopenharmony_ci nmk_chip->addr + NMK_GPIO_FIMSC); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, "%d: clearing interrupt mask\n", gpio); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void nmk_write_masked(void __iomem *reg, u32 mask, u32 value) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci u32 val; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci val = readl(reg); 44262306a36Sopenharmony_ci val = ((val & ~mask) | (value & mask)); 44362306a36Sopenharmony_ci writel(val, reg); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, 44762306a36Sopenharmony_ci unsigned offset, unsigned alt_num) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int i; 45062306a36Sopenharmony_ci u16 reg; 45162306a36Sopenharmony_ci u8 bit; 45262306a36Sopenharmony_ci u8 alt_index; 45362306a36Sopenharmony_ci const struct prcm_gpiocr_altcx_pin_desc *pin_desc; 45462306a36Sopenharmony_ci const u16 *gpiocr_regs; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (!npct->prcm_base) 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { 46062306a36Sopenharmony_ci dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", 46162306a36Sopenharmony_ci alt_num); 46262306a36Sopenharmony_ci return; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci for (i = 0 ; i < npct->soc->npins_altcx ; i++) { 46662306a36Sopenharmony_ci if (npct->soc->altcx_pins[i].pin == offset) 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci if (i == npct->soc->npins_altcx) { 47062306a36Sopenharmony_ci dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", 47162306a36Sopenharmony_ci offset); 47262306a36Sopenharmony_ci return; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci pin_desc = npct->soc->altcx_pins + i; 47662306a36Sopenharmony_ci gpiocr_regs = npct->soc->prcm_gpiocr_registers; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * If alt_num is NULL, just clear current ALTCx selection 48062306a36Sopenharmony_ci * to make sure we come back to a pure ALTC selection 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci if (!alt_num) { 48362306a36Sopenharmony_ci for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { 48462306a36Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 48562306a36Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 48662306a36Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 48762306a36Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) { 48862306a36Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); 48962306a36Sopenharmony_ci dev_dbg(npct->dev, 49062306a36Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", 49162306a36Sopenharmony_ci offset, i+1); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci return; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci alt_index = alt_num - 1; 49962306a36Sopenharmony_ci if (pin_desc->altcx[alt_index].used == false) { 50062306a36Sopenharmony_ci dev_warn(npct->dev, 50162306a36Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", 50262306a36Sopenharmony_ci offset, alt_num); 50362306a36Sopenharmony_ci return; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * Check if any other ALTCx functions are activated on this pin 50862306a36Sopenharmony_ci * and disable it first. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { 51162306a36Sopenharmony_ci if (i == alt_index) 51262306a36Sopenharmony_ci continue; 51362306a36Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 51462306a36Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 51562306a36Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 51662306a36Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) { 51762306a36Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); 51862306a36Sopenharmony_ci dev_dbg(npct->dev, 51962306a36Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", 52062306a36Sopenharmony_ci offset, i+1); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; 52662306a36Sopenharmony_ci bit = pin_desc->altcx[alt_index].control_bit; 52762306a36Sopenharmony_ci dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", 52862306a36Sopenharmony_ci offset, alt_index+1); 52962306a36Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit)); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* 53362306a36Sopenharmony_ci * Safe sequence used to switch IOs between GPIO and Alternate-C mode: 53462306a36Sopenharmony_ci * - Save SLPM registers 53562306a36Sopenharmony_ci * - Set SLPM=0 for the IOs you want to switch and others to 1 53662306a36Sopenharmony_ci * - Configure the GPIO registers for the IOs that are being switched 53762306a36Sopenharmony_ci * - Set IOFORCE=1 53862306a36Sopenharmony_ci * - Modify the AFLSA/B registers for the IOs that are being switched 53962306a36Sopenharmony_ci * - Set IOFORCE=0 54062306a36Sopenharmony_ci * - Restore SLPM registers 54162306a36Sopenharmony_ci * - Any spurious wake up event during switch sequence to be ignored and 54262306a36Sopenharmony_ci * cleared 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic void nmk_gpio_glitch_slpm_init(unsigned int *slpm) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci int i; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci for (i = 0; i < NUM_BANKS; i++) { 54962306a36Sopenharmony_ci struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; 55062306a36Sopenharmony_ci unsigned int temp = slpm[i]; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (!chip) 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci clk_enable(chip->clk); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); 55862306a36Sopenharmony_ci writel(temp, chip->addr + NMK_GPIO_SLPC); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci int i; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci for (i = 0; i < NUM_BANKS; i++) { 56762306a36Sopenharmony_ci struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!chip) 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci writel(slpm[i], chip->addr + NMK_GPIO_SLPC); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci clk_disable(chip->clk); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci int i; 58162306a36Sopenharmony_ci u16 reg; 58262306a36Sopenharmony_ci u8 bit; 58362306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 58462306a36Sopenharmony_ci const struct prcm_gpiocr_altcx_pin_desc *pin_desc; 58562306a36Sopenharmony_ci const u16 *gpiocr_regs; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!npct->prcm_base) 58862306a36Sopenharmony_ci return NMK_GPIO_ALT_C; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci for (i = 0; i < npct->soc->npins_altcx; i++) { 59162306a36Sopenharmony_ci if (npct->soc->altcx_pins[i].pin == gpio) 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci if (i == npct->soc->npins_altcx) 59562306a36Sopenharmony_ci return NMK_GPIO_ALT_C; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci pin_desc = npct->soc->altcx_pins + i; 59862306a36Sopenharmony_ci gpiocr_regs = npct->soc->prcm_gpiocr_registers; 59962306a36Sopenharmony_ci for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) { 60062306a36Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 60162306a36Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 60262306a36Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 60362306a36Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) 60462306a36Sopenharmony_ci return NMK_GPIO_ALT_C+i+1; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci return NMK_GPIO_ALT_C; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci/* IRQ functions */ 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic void nmk_gpio_irq_ack(struct irq_data *d) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 61562306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 61862306a36Sopenharmony_ci writel(BIT(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); 61962306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cienum nmk_gpio_irq_type { 62362306a36Sopenharmony_ci NORMAL, 62462306a36Sopenharmony_ci WAKE, 62562306a36Sopenharmony_ci}; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, 62862306a36Sopenharmony_ci int offset, enum nmk_gpio_irq_type which, 62962306a36Sopenharmony_ci bool enable) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci u32 *rimscval; 63262306a36Sopenharmony_ci u32 *fimscval; 63362306a36Sopenharmony_ci u32 rimscreg; 63462306a36Sopenharmony_ci u32 fimscreg; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (which == NORMAL) { 63762306a36Sopenharmony_ci rimscreg = NMK_GPIO_RIMSC; 63862306a36Sopenharmony_ci fimscreg = NMK_GPIO_FIMSC; 63962306a36Sopenharmony_ci rimscval = &nmk_chip->rimsc; 64062306a36Sopenharmony_ci fimscval = &nmk_chip->fimsc; 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci rimscreg = NMK_GPIO_RWIMSC; 64362306a36Sopenharmony_ci fimscreg = NMK_GPIO_FWIMSC; 64462306a36Sopenharmony_ci rimscval = &nmk_chip->rwimsc; 64562306a36Sopenharmony_ci fimscval = &nmk_chip->fwimsc; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* we must individually set/clear the two edges */ 64962306a36Sopenharmony_ci if (nmk_chip->edge_rising & BIT(offset)) { 65062306a36Sopenharmony_ci if (enable) 65162306a36Sopenharmony_ci *rimscval |= BIT(offset); 65262306a36Sopenharmony_ci else 65362306a36Sopenharmony_ci *rimscval &= ~BIT(offset); 65462306a36Sopenharmony_ci writel(*rimscval, nmk_chip->addr + rimscreg); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci if (nmk_chip->edge_falling & BIT(offset)) { 65762306a36Sopenharmony_ci if (enable) 65862306a36Sopenharmony_ci *fimscval |= BIT(offset); 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci *fimscval &= ~BIT(offset); 66162306a36Sopenharmony_ci writel(*fimscval, nmk_chip->addr + fimscreg); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, 66662306a36Sopenharmony_ci int offset, bool on) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci /* 66962306a36Sopenharmony_ci * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is 67062306a36Sopenharmony_ci * disabled, since setting SLPM to 1 increases power consumption, and 67162306a36Sopenharmony_ci * wakeup is anyhow controlled by the RIMSC and FIMSC registers. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci if (nmk_chip->sleepmode && on) { 67462306a36Sopenharmony_ci __nmk_gpio_set_slpm(nmk_chip, offset, 67562306a36Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_ENABLE); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, offset, WAKE, on); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic void nmk_gpio_irq_maskunmask(struct nmk_gpio_chip *nmk_chip, 68262306a36Sopenharmony_ci struct irq_data *d, bool enable) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci unsigned long flags; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 68762306a36Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 68862306a36Sopenharmony_ci spin_lock(&nmk_chip->lock); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (!(nmk_chip->real_wake & BIT(d->hwirq))) 69362306a36Sopenharmony_ci __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci spin_unlock(&nmk_chip->lock); 69662306a36Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 69762306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic void nmk_gpio_irq_mask(struct irq_data *d) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 70362306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci nmk_gpio_irq_maskunmask(nmk_chip, d, false); 70662306a36Sopenharmony_ci gpiochip_disable_irq(gc, irqd_to_hwirq(d)); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void nmk_gpio_irq_unmask(struct irq_data *d) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 71262306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci gpiochip_enable_irq(gc, irqd_to_hwirq(d)); 71562306a36Sopenharmony_ci nmk_gpio_irq_maskunmask(nmk_chip, d, true); 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 72162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 72262306a36Sopenharmony_ci unsigned long flags; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 72562306a36Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 72662306a36Sopenharmony_ci spin_lock(&nmk_chip->lock); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (irqd_irq_disabled(d)) 72962306a36Sopenharmony_ci __nmk_gpio_set_wake(nmk_chip, d->hwirq, on); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (on) 73262306a36Sopenharmony_ci nmk_chip->real_wake |= BIT(d->hwirq); 73362306a36Sopenharmony_ci else 73462306a36Sopenharmony_ci nmk_chip->real_wake &= ~BIT(d->hwirq); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci spin_unlock(&nmk_chip->lock); 73762306a36Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 73862306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 74662306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 74762306a36Sopenharmony_ci bool enabled = !irqd_irq_disabled(d); 74862306a36Sopenharmony_ci bool wake = irqd_is_wakeup_set(d); 74962306a36Sopenharmony_ci unsigned long flags; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_HIGH) 75262306a36Sopenharmony_ci return -EINVAL; 75362306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 75462306a36Sopenharmony_ci return -EINVAL; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 75762306a36Sopenharmony_ci spin_lock_irqsave(&nmk_chip->lock, flags); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (enabled) 76062306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (enabled || wake) 76362306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci nmk_chip->edge_rising &= ~BIT(d->hwirq); 76662306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 76762306a36Sopenharmony_ci nmk_chip->edge_rising |= BIT(d->hwirq); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci nmk_chip->edge_falling &= ~BIT(d->hwirq); 77062306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 77162306a36Sopenharmony_ci nmk_chip->edge_falling |= BIT(d->hwirq); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (enabled) 77462306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (enabled || wake) 77762306a36Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci spin_unlock_irqrestore(&nmk_chip->lock, flags); 78062306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic unsigned int nmk_gpio_irq_startup(struct irq_data *d) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 78862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 79162306a36Sopenharmony_ci nmk_gpio_irq_unmask(d); 79262306a36Sopenharmony_ci return 0; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic void nmk_gpio_irq_shutdown(struct irq_data *d) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 79862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci nmk_gpio_irq_mask(d); 80162306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic void nmk_gpio_irq_handler(struct irq_desc *desc) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct irq_chip *host_chip = irq_desc_get_chip(desc); 80762306a36Sopenharmony_ci struct gpio_chip *chip = irq_desc_get_handler_data(desc); 80862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 80962306a36Sopenharmony_ci u32 status; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci chained_irq_enter(host_chip, desc); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 81462306a36Sopenharmony_ci status = readl(nmk_chip->addr + NMK_GPIO_IS); 81562306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci while (status) { 81862306a36Sopenharmony_ci int bit = __ffs(status); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci generic_handle_domain_irq(chip->irq.domain, bit); 82162306a36Sopenharmony_ci status &= ~BIT(bit); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci chained_irq_exit(host_chip, desc); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/* I/O Functions */ 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic int nmk_gpio_get_dir(struct gpio_chip *chip, unsigned offset) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 83262306a36Sopenharmony_ci int dir; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci dir = readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (dir) 84162306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 86262306a36Sopenharmony_ci int value; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci value = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci return value; 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, 87462306a36Sopenharmony_ci int val) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci __nmk_gpio_set_output(nmk_chip, offset, val); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, 88662306a36Sopenharmony_ci int val) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci __nmk_gpio_make_output(nmk_chip, offset, val); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return 0; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 90062306a36Sopenharmony_cistatic int nmk_gpio_get_mode(struct nmk_gpio_chip *nmk_chip, int offset) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci u32 afunc, bfunc; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & BIT(offset); 90762306a36Sopenharmony_ci bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & BIT(offset); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic void nmk_gpio_dbg_show_one(struct seq_file *s, 91562306a36Sopenharmony_ci struct pinctrl_dev *pctldev, struct gpio_chip *chip, 91662306a36Sopenharmony_ci unsigned offset, unsigned gpio) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci const char *label = gpiochip_is_requested(chip, offset); 91962306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 92062306a36Sopenharmony_ci int mode; 92162306a36Sopenharmony_ci bool is_out; 92262306a36Sopenharmony_ci bool data_out; 92362306a36Sopenharmony_ci bool pull; 92462306a36Sopenharmony_ci const char *modes[] = { 92562306a36Sopenharmony_ci [NMK_GPIO_ALT_GPIO] = "gpio", 92662306a36Sopenharmony_ci [NMK_GPIO_ALT_A] = "altA", 92762306a36Sopenharmony_ci [NMK_GPIO_ALT_B] = "altB", 92862306a36Sopenharmony_ci [NMK_GPIO_ALT_C] = "altC", 92962306a36Sopenharmony_ci [NMK_GPIO_ALT_C+1] = "altC1", 93062306a36Sopenharmony_ci [NMK_GPIO_ALT_C+2] = "altC2", 93162306a36Sopenharmony_ci [NMK_GPIO_ALT_C+3] = "altC3", 93262306a36Sopenharmony_ci [NMK_GPIO_ALT_C+4] = "altC4", 93362306a36Sopenharmony_ci }; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 93662306a36Sopenharmony_ci is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset)); 93762306a36Sopenharmony_ci pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & BIT(offset)); 93862306a36Sopenharmony_ci data_out = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); 93962306a36Sopenharmony_ci mode = nmk_gpio_get_mode(nmk_chip, offset); 94062306a36Sopenharmony_ci if ((mode == NMK_GPIO_ALT_C) && pctldev) 94162306a36Sopenharmony_ci mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if (is_out) { 94462306a36Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) out %s %s", 94562306a36Sopenharmony_ci gpio, 94662306a36Sopenharmony_ci label ?: "(none)", 94762306a36Sopenharmony_ci data_out ? "hi" : "lo", 94862306a36Sopenharmony_ci (mode < 0) ? "unknown" : modes[mode]); 94962306a36Sopenharmony_ci } else { 95062306a36Sopenharmony_ci int irq = chip->to_irq(chip, offset); 95162306a36Sopenharmony_ci const int pullidx = pull ? 1 : 0; 95262306a36Sopenharmony_ci int val; 95362306a36Sopenharmony_ci static const char * const pulls[] = { 95462306a36Sopenharmony_ci "none ", 95562306a36Sopenharmony_ci "pull enabled", 95662306a36Sopenharmony_ci }; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s", 95962306a36Sopenharmony_ci gpio, 96062306a36Sopenharmony_ci label ?: "(none)", 96162306a36Sopenharmony_ci pulls[pullidx], 96262306a36Sopenharmony_ci (mode < 0) ? "unknown" : modes[mode]); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci val = nmk_gpio_get_input(chip, offset); 96562306a36Sopenharmony_ci seq_printf(s, " VAL %d", val); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * This races with request_irq(), set_irq_type(), 96962306a36Sopenharmony_ci * and set_irq_wake() ... but those are "rare". 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci if (irq > 0 && irq_has_action(irq)) { 97262306a36Sopenharmony_ci char *trigger; 97362306a36Sopenharmony_ci bool wake; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (nmk_chip->edge_rising & BIT(offset)) 97662306a36Sopenharmony_ci trigger = "edge-rising"; 97762306a36Sopenharmony_ci else if (nmk_chip->edge_falling & BIT(offset)) 97862306a36Sopenharmony_ci trigger = "edge-falling"; 97962306a36Sopenharmony_ci else 98062306a36Sopenharmony_ci trigger = "edge-undefined"; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci wake = !!(nmk_chip->real_wake & BIT(offset)); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci seq_printf(s, " irq-%d %s%s", 98562306a36Sopenharmony_ci irq, trigger, wake ? " wakeup" : ""); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci unsigned i; 99462306a36Sopenharmony_ci unsigned gpio = chip->base; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci for (i = 0; i < chip->ngpio; i++, gpio++) { 99762306a36Sopenharmony_ci nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio); 99862306a36Sopenharmony_ci seq_printf(s, "\n"); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci#else 100362306a36Sopenharmony_cistatic inline void nmk_gpio_dbg_show_one(struct seq_file *s, 100462306a36Sopenharmony_ci struct pinctrl_dev *pctldev, 100562306a36Sopenharmony_ci struct gpio_chip *chip, 100662306a36Sopenharmony_ci unsigned offset, unsigned gpio) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci#define nmk_gpio_dbg_show NULL 101062306a36Sopenharmony_ci#endif 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* 101362306a36Sopenharmony_ci * We will allocate memory for the state container using devm* allocators 101462306a36Sopenharmony_ci * binding to the first device reaching this point, it doesn't matter if 101562306a36Sopenharmony_ci * it is the pin controller or GPIO driver. However we need to use the right 101662306a36Sopenharmony_ci * platform device when looking up resources so pay attention to pdev. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_cistatic struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, 101962306a36Sopenharmony_ci struct platform_device *pdev) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 102262306a36Sopenharmony_ci struct platform_device *gpio_pdev; 102362306a36Sopenharmony_ci struct gpio_chip *chip; 102462306a36Sopenharmony_ci struct resource *res; 102562306a36Sopenharmony_ci struct clk *clk; 102662306a36Sopenharmony_ci void __iomem *base; 102762306a36Sopenharmony_ci u32 id; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci gpio_pdev = of_find_device_by_node(np); 103062306a36Sopenharmony_ci if (!gpio_pdev) { 103162306a36Sopenharmony_ci pr_err("populate \"%pOFn\": device not found\n", np); 103262306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci if (of_property_read_u32(np, "gpio-bank", &id)) { 103562306a36Sopenharmony_ci dev_err(&pdev->dev, "populate: gpio-bank property not found\n"); 103662306a36Sopenharmony_ci platform_device_put(gpio_pdev); 103762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* Already populated? */ 104162306a36Sopenharmony_ci nmk_chip = nmk_gpio_chips[id]; 104262306a36Sopenharmony_ci if (nmk_chip) { 104362306a36Sopenharmony_ci platform_device_put(gpio_pdev); 104462306a36Sopenharmony_ci return nmk_chip; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci nmk_chip = devm_kzalloc(&pdev->dev, sizeof(*nmk_chip), GFP_KERNEL); 104862306a36Sopenharmony_ci if (!nmk_chip) { 104962306a36Sopenharmony_ci platform_device_put(gpio_pdev); 105062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci nmk_chip->bank = id; 105462306a36Sopenharmony_ci chip = &nmk_chip->chip; 105562306a36Sopenharmony_ci chip->base = id * NMK_GPIO_PER_CHIP; 105662306a36Sopenharmony_ci chip->ngpio = NMK_GPIO_PER_CHIP; 105762306a36Sopenharmony_ci chip->label = dev_name(&gpio_pdev->dev); 105862306a36Sopenharmony_ci chip->parent = &gpio_pdev->dev; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0); 106162306a36Sopenharmony_ci base = devm_ioremap_resource(&pdev->dev, res); 106262306a36Sopenharmony_ci if (IS_ERR(base)) { 106362306a36Sopenharmony_ci platform_device_put(gpio_pdev); 106462306a36Sopenharmony_ci return ERR_CAST(base); 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci nmk_chip->addr = base; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci clk = clk_get(&gpio_pdev->dev, NULL); 106962306a36Sopenharmony_ci if (IS_ERR(clk)) { 107062306a36Sopenharmony_ci platform_device_put(gpio_pdev); 107162306a36Sopenharmony_ci return (void *) clk; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci clk_prepare(clk); 107462306a36Sopenharmony_ci nmk_chip->clk = clk; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); 107762306a36Sopenharmony_ci nmk_gpio_chips[id] = nmk_chip; 107862306a36Sopenharmony_ci return nmk_chip; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic void nmk_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 108462306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(gc); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci seq_printf(p, "nmk%u-%u-%u", nmk_chip->bank, 108762306a36Sopenharmony_ci gc->base, gc->base + gc->ngpio - 1); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic const struct irq_chip nmk_irq_chip = { 109162306a36Sopenharmony_ci .irq_ack = nmk_gpio_irq_ack, 109262306a36Sopenharmony_ci .irq_mask = nmk_gpio_irq_mask, 109362306a36Sopenharmony_ci .irq_unmask = nmk_gpio_irq_unmask, 109462306a36Sopenharmony_ci .irq_set_type = nmk_gpio_irq_set_type, 109562306a36Sopenharmony_ci .irq_set_wake = nmk_gpio_irq_set_wake, 109662306a36Sopenharmony_ci .irq_startup = nmk_gpio_irq_startup, 109762306a36Sopenharmony_ci .irq_shutdown = nmk_gpio_irq_shutdown, 109862306a36Sopenharmony_ci .irq_print_chip = nmk_gpio_irq_print_chip, 109962306a36Sopenharmony_ci .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, 110062306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 110162306a36Sopenharmony_ci}; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int nmk_gpio_probe(struct platform_device *dev) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct device_node *np = dev->dev.of_node; 110662306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 110762306a36Sopenharmony_ci struct gpio_chip *chip; 110862306a36Sopenharmony_ci struct gpio_irq_chip *girq; 110962306a36Sopenharmony_ci bool supports_sleepmode; 111062306a36Sopenharmony_ci int irq; 111162306a36Sopenharmony_ci int ret; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci nmk_chip = nmk_gpio_populate_chip(np, dev); 111462306a36Sopenharmony_ci if (IS_ERR(nmk_chip)) { 111562306a36Sopenharmony_ci dev_err(&dev->dev, "could not populate nmk chip struct\n"); 111662306a36Sopenharmony_ci return PTR_ERR(nmk_chip); 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci supports_sleepmode = 112062306a36Sopenharmony_ci of_property_read_bool(np, "st,supports-sleepmode"); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci /* Correct platform device ID */ 112362306a36Sopenharmony_ci dev->id = nmk_chip->bank; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci irq = platform_get_irq(dev, 0); 112662306a36Sopenharmony_ci if (irq < 0) 112762306a36Sopenharmony_ci return irq; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci /* 113062306a36Sopenharmony_ci * The virt address in nmk_chip->addr is in the nomadik register space, 113162306a36Sopenharmony_ci * so we can simply convert the resource address, without remapping 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_ci nmk_chip->sleepmode = supports_sleepmode; 113462306a36Sopenharmony_ci spin_lock_init(&nmk_chip->lock); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci chip = &nmk_chip->chip; 113762306a36Sopenharmony_ci chip->parent = &dev->dev; 113862306a36Sopenharmony_ci chip->request = gpiochip_generic_request; 113962306a36Sopenharmony_ci chip->free = gpiochip_generic_free; 114062306a36Sopenharmony_ci chip->get_direction = nmk_gpio_get_dir; 114162306a36Sopenharmony_ci chip->direction_input = nmk_gpio_make_input; 114262306a36Sopenharmony_ci chip->get = nmk_gpio_get_input; 114362306a36Sopenharmony_ci chip->direction_output = nmk_gpio_make_output; 114462306a36Sopenharmony_ci chip->set = nmk_gpio_set_output; 114562306a36Sopenharmony_ci chip->dbg_show = nmk_gpio_dbg_show; 114662306a36Sopenharmony_ci chip->can_sleep = false; 114762306a36Sopenharmony_ci chip->owner = THIS_MODULE; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci girq = &chip->irq; 115062306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &nmk_irq_chip); 115162306a36Sopenharmony_ci girq->parent_handler = nmk_gpio_irq_handler; 115262306a36Sopenharmony_ci girq->num_parents = 1; 115362306a36Sopenharmony_ci girq->parents = devm_kcalloc(&dev->dev, 1, 115462306a36Sopenharmony_ci sizeof(*girq->parents), 115562306a36Sopenharmony_ci GFP_KERNEL); 115662306a36Sopenharmony_ci if (!girq->parents) 115762306a36Sopenharmony_ci return -ENOMEM; 115862306a36Sopenharmony_ci girq->parents[0] = irq; 115962306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 116062306a36Sopenharmony_ci girq->handler = handle_edge_irq; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 116362306a36Sopenharmony_ci nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI); 116462306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret = gpiochip_add_data(chip, nmk_chip); 116762306a36Sopenharmony_ci if (ret) 116862306a36Sopenharmony_ci return ret; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci platform_set_drvdata(dev, nmk_chip); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci dev_info(&dev->dev, "chip registered\n"); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic int nmk_get_groups_cnt(struct pinctrl_dev *pctldev) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return npct->soc->ngroups; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic const char *nmk_get_group_name(struct pinctrl_dev *pctldev, 118562306a36Sopenharmony_ci unsigned selector) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return npct->soc->groups[selector].grp.name; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 119362306a36Sopenharmony_ci const unsigned **pins, 119462306a36Sopenharmony_ci unsigned *npins) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci *pins = npct->soc->groups[selector].grp.pins; 119962306a36Sopenharmony_ci *npins = npct->soc->groups[selector].grp.npins; 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic struct nmk_gpio_chip *find_nmk_gpio_from_pin(unsigned pin) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci int i; 120662306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_gpio; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci for(i = 0; i < NMK_MAX_BANKS; i++) { 120962306a36Sopenharmony_ci nmk_gpio = nmk_gpio_chips[i]; 121062306a36Sopenharmony_ci if (!nmk_gpio) 121162306a36Sopenharmony_ci continue; 121262306a36Sopenharmony_ci if (pin >= nmk_gpio->chip.base && 121362306a36Sopenharmony_ci pin < nmk_gpio->chip.base + nmk_gpio->chip.ngpio) 121462306a36Sopenharmony_ci return nmk_gpio; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci return NULL; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic struct gpio_chip *find_gc_from_pin(unsigned pin) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_gpio = find_nmk_gpio_from_pin(pin); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (nmk_gpio) 122462306a36Sopenharmony_ci return &nmk_gpio->chip; 122562306a36Sopenharmony_ci return NULL; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 122962306a36Sopenharmony_ci unsigned offset) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct gpio_chip *chip = find_gc_from_pin(offset); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (!chip) { 123462306a36Sopenharmony_ci seq_printf(s, "invalid pin offset"); 123562306a36Sopenharmony_ci return; 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, 124162306a36Sopenharmony_ci unsigned *num_maps, const char *group, 124262306a36Sopenharmony_ci const char *function) 124362306a36Sopenharmony_ci{ 124462306a36Sopenharmony_ci if (*num_maps == *reserved_maps) 124562306a36Sopenharmony_ci return -ENOSPC; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 124862306a36Sopenharmony_ci (*map)[*num_maps].data.mux.group = group; 124962306a36Sopenharmony_ci (*map)[*num_maps].data.mux.function = function; 125062306a36Sopenharmony_ci (*num_maps)++; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int nmk_dt_add_map_configs(struct pinctrl_map **map, 125662306a36Sopenharmony_ci unsigned *reserved_maps, 125762306a36Sopenharmony_ci unsigned *num_maps, const char *group, 125862306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci unsigned long *dup_configs; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (*num_maps == *reserved_maps) 126362306a36Sopenharmony_ci return -ENOSPC; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), 126662306a36Sopenharmony_ci GFP_KERNEL); 126762306a36Sopenharmony_ci if (!dup_configs) 126862306a36Sopenharmony_ci return -ENOMEM; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci (*map)[*num_maps].data.configs.group_or_pin = group; 127362306a36Sopenharmony_ci (*map)[*num_maps].data.configs.configs = dup_configs; 127462306a36Sopenharmony_ci (*map)[*num_maps].data.configs.num_configs = num_configs; 127562306a36Sopenharmony_ci (*num_maps)++; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci return 0; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci#define NMK_CONFIG_PIN(x, y) { .property = x, .config = y, } 128162306a36Sopenharmony_ci#define NMK_CONFIG_PIN_ARRAY(x, y) { .property = x, .choice = y, \ 128262306a36Sopenharmony_ci .size = ARRAY_SIZE(y), } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic const unsigned long nmk_pin_input_modes[] = { 128562306a36Sopenharmony_ci PIN_INPUT_NOPULL, 128662306a36Sopenharmony_ci PIN_INPUT_PULLUP, 128762306a36Sopenharmony_ci PIN_INPUT_PULLDOWN, 128862306a36Sopenharmony_ci}; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic const unsigned long nmk_pin_output_modes[] = { 129162306a36Sopenharmony_ci PIN_OUTPUT_LOW, 129262306a36Sopenharmony_ci PIN_OUTPUT_HIGH, 129362306a36Sopenharmony_ci PIN_DIR_OUTPUT, 129462306a36Sopenharmony_ci}; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic const unsigned long nmk_pin_sleep_modes[] = { 129762306a36Sopenharmony_ci PIN_SLEEPMODE_DISABLED, 129862306a36Sopenharmony_ci PIN_SLEEPMODE_ENABLED, 129962306a36Sopenharmony_ci}; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic const unsigned long nmk_pin_sleep_input_modes[] = { 130262306a36Sopenharmony_ci PIN_SLPM_INPUT_NOPULL, 130362306a36Sopenharmony_ci PIN_SLPM_INPUT_PULLUP, 130462306a36Sopenharmony_ci PIN_SLPM_INPUT_PULLDOWN, 130562306a36Sopenharmony_ci PIN_SLPM_DIR_INPUT, 130662306a36Sopenharmony_ci}; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic const unsigned long nmk_pin_sleep_output_modes[] = { 130962306a36Sopenharmony_ci PIN_SLPM_OUTPUT_LOW, 131062306a36Sopenharmony_ci PIN_SLPM_OUTPUT_HIGH, 131162306a36Sopenharmony_ci PIN_SLPM_DIR_OUTPUT, 131262306a36Sopenharmony_ci}; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic const unsigned long nmk_pin_sleep_wakeup_modes[] = { 131562306a36Sopenharmony_ci PIN_SLPM_WAKEUP_DISABLE, 131662306a36Sopenharmony_ci PIN_SLPM_WAKEUP_ENABLE, 131762306a36Sopenharmony_ci}; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic const unsigned long nmk_pin_gpio_modes[] = { 132062306a36Sopenharmony_ci PIN_GPIOMODE_DISABLED, 132162306a36Sopenharmony_ci PIN_GPIOMODE_ENABLED, 132262306a36Sopenharmony_ci}; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic const unsigned long nmk_pin_sleep_pdis_modes[] = { 132562306a36Sopenharmony_ci PIN_SLPM_PDIS_DISABLED, 132662306a36Sopenharmony_ci PIN_SLPM_PDIS_ENABLED, 132762306a36Sopenharmony_ci}; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistruct nmk_cfg_param { 133062306a36Sopenharmony_ci const char *property; 133162306a36Sopenharmony_ci unsigned long config; 133262306a36Sopenharmony_ci const unsigned long *choice; 133362306a36Sopenharmony_ci int size; 133462306a36Sopenharmony_ci}; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic const struct nmk_cfg_param nmk_cfg_params[] = { 133762306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,input", nmk_pin_input_modes), 133862306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,output", nmk_pin_output_modes), 133962306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep", nmk_pin_sleep_modes), 134062306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-input", nmk_pin_sleep_input_modes), 134162306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-output", nmk_pin_sleep_output_modes), 134262306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-wakeup", nmk_pin_sleep_wakeup_modes), 134362306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,gpio", nmk_pin_gpio_modes), 134462306a36Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-pull-disable", nmk_pin_sleep_pdis_modes), 134562306a36Sopenharmony_ci}; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int nmk_dt_pin_config(int index, int val, unsigned long *config) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci if (nmk_cfg_params[index].choice == NULL) 135062306a36Sopenharmony_ci *config = nmk_cfg_params[index].config; 135162306a36Sopenharmony_ci else { 135262306a36Sopenharmony_ci /* test if out of range */ 135362306a36Sopenharmony_ci if (val < nmk_cfg_params[index].size) { 135462306a36Sopenharmony_ci *config = nmk_cfg_params[index].config | 135562306a36Sopenharmony_ci nmk_cfg_params[index].choice[val]; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci return 0; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pin_name) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci int i, pin_number; 136462306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1) 136762306a36Sopenharmony_ci for (i = 0; i < npct->soc->npins; i++) 136862306a36Sopenharmony_ci if (npct->soc->pins[i].number == pin_number) 136962306a36Sopenharmony_ci return npct->soc->pins[i].name; 137062306a36Sopenharmony_ci return NULL; 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_cistatic bool nmk_pinctrl_dt_get_config(struct device_node *np, 137462306a36Sopenharmony_ci unsigned long *configs) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci bool has_config = 0; 137762306a36Sopenharmony_ci unsigned long cfg = 0; 137862306a36Sopenharmony_ci int i, val, ret; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nmk_cfg_params); i++) { 138162306a36Sopenharmony_ci ret = of_property_read_u32(np, 138262306a36Sopenharmony_ci nmk_cfg_params[i].property, &val); 138362306a36Sopenharmony_ci if (ret != -EINVAL) { 138462306a36Sopenharmony_ci if (nmk_dt_pin_config(i, val, &cfg) == 0) { 138562306a36Sopenharmony_ci *configs |= cfg; 138662306a36Sopenharmony_ci has_config = 1; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci return has_config; 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cistatic int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 139562306a36Sopenharmony_ci struct device_node *np, 139662306a36Sopenharmony_ci struct pinctrl_map **map, 139762306a36Sopenharmony_ci unsigned *reserved_maps, 139862306a36Sopenharmony_ci unsigned *num_maps) 139962306a36Sopenharmony_ci{ 140062306a36Sopenharmony_ci int ret; 140162306a36Sopenharmony_ci const char *function = NULL; 140262306a36Sopenharmony_ci unsigned long configs = 0; 140362306a36Sopenharmony_ci bool has_config = 0; 140462306a36Sopenharmony_ci struct property *prop; 140562306a36Sopenharmony_ci struct device_node *np_config; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci ret = of_property_read_string(np, "function", &function); 140862306a36Sopenharmony_ci if (ret >= 0) { 140962306a36Sopenharmony_ci const char *group; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci ret = of_property_count_strings(np, "groups"); 141262306a36Sopenharmony_ci if (ret < 0) 141362306a36Sopenharmony_ci goto exit; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, 141662306a36Sopenharmony_ci reserved_maps, 141762306a36Sopenharmony_ci num_maps, ret); 141862306a36Sopenharmony_ci if (ret < 0) 141962306a36Sopenharmony_ci goto exit; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci of_property_for_each_string(np, "groups", prop, group) { 142262306a36Sopenharmony_ci ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps, 142362306a36Sopenharmony_ci group, function); 142462306a36Sopenharmony_ci if (ret < 0) 142562306a36Sopenharmony_ci goto exit; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci has_config = nmk_pinctrl_dt_get_config(np, &configs); 143062306a36Sopenharmony_ci np_config = of_parse_phandle(np, "ste,config", 0); 143162306a36Sopenharmony_ci if (np_config) { 143262306a36Sopenharmony_ci has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); 143362306a36Sopenharmony_ci of_node_put(np_config); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci if (has_config) { 143662306a36Sopenharmony_ci const char *gpio_name; 143762306a36Sopenharmony_ci const char *pin; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci ret = of_property_count_strings(np, "pins"); 144062306a36Sopenharmony_ci if (ret < 0) 144162306a36Sopenharmony_ci goto exit; 144262306a36Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, 144362306a36Sopenharmony_ci reserved_maps, 144462306a36Sopenharmony_ci num_maps, ret); 144562306a36Sopenharmony_ci if (ret < 0) 144662306a36Sopenharmony_ci goto exit; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci of_property_for_each_string(np, "pins", prop, pin) { 144962306a36Sopenharmony_ci gpio_name = nmk_find_pin_name(pctldev, pin); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ret = nmk_dt_add_map_configs(map, reserved_maps, 145262306a36Sopenharmony_ci num_maps, 145362306a36Sopenharmony_ci gpio_name, &configs, 1); 145462306a36Sopenharmony_ci if (ret < 0) 145562306a36Sopenharmony_ci goto exit; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ciexit: 146062306a36Sopenharmony_ci return ret; 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_cistatic int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 146462306a36Sopenharmony_ci struct device_node *np_config, 146562306a36Sopenharmony_ci struct pinctrl_map **map, unsigned *num_maps) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci unsigned reserved_maps; 146862306a36Sopenharmony_ci struct device_node *np; 146962306a36Sopenharmony_ci int ret; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci reserved_maps = 0; 147262306a36Sopenharmony_ci *map = NULL; 147362306a36Sopenharmony_ci *num_maps = 0; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci for_each_child_of_node(np_config, np) { 147662306a36Sopenharmony_ci ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map, 147762306a36Sopenharmony_ci &reserved_maps, num_maps); 147862306a36Sopenharmony_ci if (ret < 0) { 147962306a36Sopenharmony_ci pinctrl_utils_free_map(pctldev, *map, *num_maps); 148062306a36Sopenharmony_ci of_node_put(np); 148162306a36Sopenharmony_ci return ret; 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci return 0; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic const struct pinctrl_ops nmk_pinctrl_ops = { 148962306a36Sopenharmony_ci .get_groups_count = nmk_get_groups_cnt, 149062306a36Sopenharmony_ci .get_group_name = nmk_get_group_name, 149162306a36Sopenharmony_ci .get_group_pins = nmk_get_group_pins, 149262306a36Sopenharmony_ci .pin_dbg_show = nmk_pin_dbg_show, 149362306a36Sopenharmony_ci .dt_node_to_map = nmk_pinctrl_dt_node_to_map, 149462306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 149562306a36Sopenharmony_ci}; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return npct->soc->nfunctions; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev, 150562306a36Sopenharmony_ci unsigned function) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci return npct->soc->functions[function].name; 151062306a36Sopenharmony_ci} 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 151362306a36Sopenharmony_ci unsigned function, 151462306a36Sopenharmony_ci const char * const **groups, 151562306a36Sopenharmony_ci unsigned * const num_groups) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci *groups = npct->soc->functions[function].groups; 152062306a36Sopenharmony_ci *num_groups = npct->soc->functions[function].ngroups; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci return 0; 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_cistatic int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, 152662306a36Sopenharmony_ci unsigned group) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 152962306a36Sopenharmony_ci const struct nmk_pingroup *g; 153062306a36Sopenharmony_ci static unsigned int slpm[NUM_BANKS]; 153162306a36Sopenharmony_ci unsigned long flags = 0; 153262306a36Sopenharmony_ci bool glitch; 153362306a36Sopenharmony_ci int ret = -EINVAL; 153462306a36Sopenharmony_ci int i; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci g = &npct->soc->groups[group]; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (g->altsetting < 0) 153962306a36Sopenharmony_ci return -EINVAL; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci dev_dbg(npct->dev, "enable group %s, %u pins\n", g->grp.name, g->grp.npins); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci /* 154462306a36Sopenharmony_ci * If we're setting altfunc C by setting both AFSLA and AFSLB to 1, 154562306a36Sopenharmony_ci * we may pass through an undesired state. In this case we take 154662306a36Sopenharmony_ci * some extra care. 154762306a36Sopenharmony_ci * 154862306a36Sopenharmony_ci * Safe sequence used to switch IOs between GPIO and Alternate-C mode: 154962306a36Sopenharmony_ci * - Save SLPM registers (since we have a shadow register in the 155062306a36Sopenharmony_ci * nmk_chip we're using that as backup) 155162306a36Sopenharmony_ci * - Set SLPM=0 for the IOs you want to switch and others to 1 155262306a36Sopenharmony_ci * - Configure the GPIO registers for the IOs that are being switched 155362306a36Sopenharmony_ci * - Set IOFORCE=1 155462306a36Sopenharmony_ci * - Modify the AFLSA/B registers for the IOs that are being switched 155562306a36Sopenharmony_ci * - Set IOFORCE=0 155662306a36Sopenharmony_ci * - Restore SLPM registers 155762306a36Sopenharmony_ci * - Any spurious wake up event during switch sequence to be ignored 155862306a36Sopenharmony_ci * and cleared 155962306a36Sopenharmony_ci * 156062306a36Sopenharmony_ci * We REALLY need to save ALL slpm registers, because the external 156162306a36Sopenharmony_ci * IOFORCE will switch *all* ports to their sleepmode setting to as 156262306a36Sopenharmony_ci * to avoid glitches. (Not just one port!) 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_ci glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci if (glitch) { 156762306a36Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* Initially don't put any pins to sleep when switching */ 157062306a36Sopenharmony_ci memset(slpm, 0xff, sizeof(slpm)); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci /* 157362306a36Sopenharmony_ci * Then mask the pins that need to be sleeping now when we're 157462306a36Sopenharmony_ci * switching to the ALT C function. 157562306a36Sopenharmony_ci */ 157662306a36Sopenharmony_ci for (i = 0; i < g->grp.npins; i++) { 157762306a36Sopenharmony_ci unsigned int bit = g->grp.pins[i] % NMK_GPIO_PER_CHIP; 157862306a36Sopenharmony_ci slpm[g->grp.pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(bit); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci nmk_gpio_glitch_slpm_init(slpm); 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci for (i = 0; i < g->grp.npins; i++) { 158462306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 158562306a36Sopenharmony_ci unsigned bit; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci nmk_chip = find_nmk_gpio_from_pin(g->grp.pins[i]); 158862306a36Sopenharmony_ci if (!nmk_chip) { 158962306a36Sopenharmony_ci dev_err(npct->dev, 159062306a36Sopenharmony_ci "invalid pin offset %d in group %s at index %d\n", 159162306a36Sopenharmony_ci g->grp.pins[i], g->grp.name, i); 159262306a36Sopenharmony_ci goto out_glitch; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->grp.pins[i], g->altsetting); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 159762306a36Sopenharmony_ci bit = g->grp.pins[i] % NMK_GPIO_PER_CHIP; 159862306a36Sopenharmony_ci /* 159962306a36Sopenharmony_ci * If the pin is switching to altfunc, and there was an 160062306a36Sopenharmony_ci * interrupt installed on it which has been lazy disabled, 160162306a36Sopenharmony_ci * actually mask the interrupt to prevent spurious interrupts 160262306a36Sopenharmony_ci * that would occur while the pin is under control of the 160362306a36Sopenharmony_ci * peripheral. Only SKE does this. 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci nmk_gpio_disable_lazy_irq(nmk_chip, bit); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci __nmk_gpio_set_mode_safe(nmk_chip, bit, 160862306a36Sopenharmony_ci (g->altsetting & NMK_GPIO_ALT_C), glitch); 160962306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci /* 161262306a36Sopenharmony_ci * Call PRCM GPIOCR config function in case ALTC 161362306a36Sopenharmony_ci * has been selected: 161462306a36Sopenharmony_ci * - If selection is a ALTCx, some bits in PRCM GPIOCR registers 161562306a36Sopenharmony_ci * must be set. 161662306a36Sopenharmony_ci * - If selection is pure ALTC and previous selection was ALTCx, 161762306a36Sopenharmony_ci * then some bits in PRCM GPIOCR registers must be cleared. 161862306a36Sopenharmony_ci */ 161962306a36Sopenharmony_ci if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) 162062306a36Sopenharmony_ci nmk_prcm_altcx_set_mode(npct, g->grp.pins[i], 162162306a36Sopenharmony_ci g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* When all pins are successfully reconfigured we get here */ 162562306a36Sopenharmony_ci ret = 0; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ciout_glitch: 162862306a36Sopenharmony_ci if (glitch) { 162962306a36Sopenharmony_ci nmk_gpio_glitch_slpm_restore(slpm); 163062306a36Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci return ret; 163462306a36Sopenharmony_ci} 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_cistatic int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, 163762306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 163862306a36Sopenharmony_ci unsigned offset) 163962306a36Sopenharmony_ci{ 164062306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 164162306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 164262306a36Sopenharmony_ci struct gpio_chip *chip; 164362306a36Sopenharmony_ci unsigned bit; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (!range) { 164662306a36Sopenharmony_ci dev_err(npct->dev, "invalid range\n"); 164762306a36Sopenharmony_ci return -EINVAL; 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci if (!range->gc) { 165062306a36Sopenharmony_ci dev_err(npct->dev, "missing GPIO chip in range\n"); 165162306a36Sopenharmony_ci return -EINVAL; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci chip = range->gc; 165462306a36Sopenharmony_ci nmk_chip = gpiochip_get_data(chip); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 165962306a36Sopenharmony_ci bit = offset % NMK_GPIO_PER_CHIP; 166062306a36Sopenharmony_ci /* There is no glitch when converting any pin to GPIO */ 166162306a36Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); 166262306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci return 0; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, 166862306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 166962306a36Sopenharmony_ci unsigned offset) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); 167462306a36Sopenharmony_ci /* Set the pin to some default state, GPIO is usually default */ 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_cistatic const struct pinmux_ops nmk_pinmux_ops = { 167862306a36Sopenharmony_ci .get_functions_count = nmk_pmx_get_funcs_cnt, 167962306a36Sopenharmony_ci .get_function_name = nmk_pmx_get_func_name, 168062306a36Sopenharmony_ci .get_function_groups = nmk_pmx_get_func_groups, 168162306a36Sopenharmony_ci .set_mux = nmk_pmx_set, 168262306a36Sopenharmony_ci .gpio_request_enable = nmk_gpio_request_enable, 168362306a36Sopenharmony_ci .gpio_disable_free = nmk_gpio_disable_free, 168462306a36Sopenharmony_ci .strict = true, 168562306a36Sopenharmony_ci}; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_cistatic int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, 168862306a36Sopenharmony_ci unsigned long *config) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci /* Not implemented */ 169162306a36Sopenharmony_ci return -EINVAL; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, 169562306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci static const char *pullnames[] = { 169862306a36Sopenharmony_ci [NMK_GPIO_PULL_NONE] = "none", 169962306a36Sopenharmony_ci [NMK_GPIO_PULL_UP] = "up", 170062306a36Sopenharmony_ci [NMK_GPIO_PULL_DOWN] = "down", 170162306a36Sopenharmony_ci [3] /* illegal */ = "??" 170262306a36Sopenharmony_ci }; 170362306a36Sopenharmony_ci static const char *slpmnames[] = { 170462306a36Sopenharmony_ci [NMK_GPIO_SLPM_INPUT] = "input/wakeup", 170562306a36Sopenharmony_ci [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", 170662306a36Sopenharmony_ci }; 170762306a36Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 170862306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 170962306a36Sopenharmony_ci unsigned bit; 171062306a36Sopenharmony_ci pin_cfg_t cfg; 171162306a36Sopenharmony_ci int pull, slpm, output, val, i; 171262306a36Sopenharmony_ci bool lowemi, gpiomode, sleep; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci nmk_chip = find_nmk_gpio_from_pin(pin); 171562306a36Sopenharmony_ci if (!nmk_chip) { 171662306a36Sopenharmony_ci dev_err(npct->dev, 171762306a36Sopenharmony_ci "invalid pin offset %d\n", pin); 171862306a36Sopenharmony_ci return -EINVAL; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 172262306a36Sopenharmony_ci /* 172362306a36Sopenharmony_ci * The pin config contains pin number and altfunction fields, 172462306a36Sopenharmony_ci * here we just ignore that part. It's being handled by the 172562306a36Sopenharmony_ci * framework and pinmux callback respectively. 172662306a36Sopenharmony_ci */ 172762306a36Sopenharmony_ci cfg = (pin_cfg_t) configs[i]; 172862306a36Sopenharmony_ci pull = PIN_PULL(cfg); 172962306a36Sopenharmony_ci slpm = PIN_SLPM(cfg); 173062306a36Sopenharmony_ci output = PIN_DIR(cfg); 173162306a36Sopenharmony_ci val = PIN_VAL(cfg); 173262306a36Sopenharmony_ci lowemi = PIN_LOWEMI(cfg); 173362306a36Sopenharmony_ci gpiomode = PIN_GPIOMODE(cfg); 173462306a36Sopenharmony_ci sleep = PIN_SLEEPMODE(cfg); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (sleep) { 173762306a36Sopenharmony_ci int slpm_pull = PIN_SLPM_PULL(cfg); 173862306a36Sopenharmony_ci int slpm_output = PIN_SLPM_DIR(cfg); 173962306a36Sopenharmony_ci int slpm_val = PIN_SLPM_VAL(cfg); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci /* All pins go into GPIO mode at sleep */ 174262306a36Sopenharmony_ci gpiomode = true; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci /* 174562306a36Sopenharmony_ci * The SLPM_* values are normal values + 1 to allow zero 174662306a36Sopenharmony_ci * to mean "same as normal". 174762306a36Sopenharmony_ci */ 174862306a36Sopenharmony_ci if (slpm_pull) 174962306a36Sopenharmony_ci pull = slpm_pull - 1; 175062306a36Sopenharmony_ci if (slpm_output) 175162306a36Sopenharmony_ci output = slpm_output - 1; 175262306a36Sopenharmony_ci if (slpm_val) 175362306a36Sopenharmony_ci val = slpm_val - 1; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, 175662306a36Sopenharmony_ci "pin %d: sleep pull %s, dir %s, val %s\n", 175762306a36Sopenharmony_ci pin, 175862306a36Sopenharmony_ci slpm_pull ? pullnames[pull] : "same", 175962306a36Sopenharmony_ci slpm_output ? (output ? "output" : "input") 176062306a36Sopenharmony_ci : "same", 176162306a36Sopenharmony_ci slpm_val ? (val ? "high" : "low") : "same"); 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, 176562306a36Sopenharmony_ci "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", 176662306a36Sopenharmony_ci pin, cfg, pullnames[pull], slpmnames[slpm], 176762306a36Sopenharmony_ci output ? "output " : "input", 176862306a36Sopenharmony_ci output ? (val ? "high" : "low") : "", 176962306a36Sopenharmony_ci lowemi ? "on" : "off"); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci clk_enable(nmk_chip->clk); 177262306a36Sopenharmony_ci bit = pin % NMK_GPIO_PER_CHIP; 177362306a36Sopenharmony_ci if (gpiomode) 177462306a36Sopenharmony_ci /* No glitch when going to GPIO mode */ 177562306a36Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); 177662306a36Sopenharmony_ci if (output) 177762306a36Sopenharmony_ci __nmk_gpio_make_output(nmk_chip, bit, val); 177862306a36Sopenharmony_ci else { 177962306a36Sopenharmony_ci __nmk_gpio_make_input(nmk_chip, bit); 178062306a36Sopenharmony_ci __nmk_gpio_set_pull(nmk_chip, bit, pull); 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci /* TODO: isn't this only applicable on output pins? */ 178362306a36Sopenharmony_ci __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci __nmk_gpio_set_slpm(nmk_chip, bit, slpm); 178662306a36Sopenharmony_ci clk_disable(nmk_chip->clk); 178762306a36Sopenharmony_ci } /* for each config */ 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci return 0; 179062306a36Sopenharmony_ci} 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_cistatic const struct pinconf_ops nmk_pinconf_ops = { 179362306a36Sopenharmony_ci .pin_config_get = nmk_pin_config_get, 179462306a36Sopenharmony_ci .pin_config_set = nmk_pin_config_set, 179562306a36Sopenharmony_ci}; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic struct pinctrl_desc nmk_pinctrl_desc = { 179862306a36Sopenharmony_ci .name = "pinctrl-nomadik", 179962306a36Sopenharmony_ci .pctlops = &nmk_pinctrl_ops, 180062306a36Sopenharmony_ci .pmxops = &nmk_pinmux_ops, 180162306a36Sopenharmony_ci .confops = &nmk_pinconf_ops, 180262306a36Sopenharmony_ci .owner = THIS_MODULE, 180362306a36Sopenharmony_ci}; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_cistatic const struct of_device_id nmk_pinctrl_match[] = { 180662306a36Sopenharmony_ci { 180762306a36Sopenharmony_ci .compatible = "stericsson,stn8815-pinctrl", 180862306a36Sopenharmony_ci .data = (void *)PINCTRL_NMK_STN8815, 180962306a36Sopenharmony_ci }, 181062306a36Sopenharmony_ci { 181162306a36Sopenharmony_ci .compatible = "stericsson,db8500-pinctrl", 181262306a36Sopenharmony_ci .data = (void *)PINCTRL_NMK_DB8500, 181362306a36Sopenharmony_ci }, 181462306a36Sopenharmony_ci {}, 181562306a36Sopenharmony_ci}; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 181862306a36Sopenharmony_cistatic int nmk_pinctrl_suspend(struct device *dev) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci struct nmk_pinctrl *npct; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci npct = dev_get_drvdata(dev); 182362306a36Sopenharmony_ci if (!npct) 182462306a36Sopenharmony_ci return -EINVAL; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci return pinctrl_force_sleep(npct->pctl); 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic int nmk_pinctrl_resume(struct device *dev) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct nmk_pinctrl *npct; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci npct = dev_get_drvdata(dev); 183462306a36Sopenharmony_ci if (!npct) 183562306a36Sopenharmony_ci return -EINVAL; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci return pinctrl_force_default(npct->pctl); 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci#endif 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic int nmk_pinctrl_probe(struct platform_device *pdev) 184262306a36Sopenharmony_ci{ 184362306a36Sopenharmony_ci const struct of_device_id *match; 184462306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 184562306a36Sopenharmony_ci struct device_node *prcm_np; 184662306a36Sopenharmony_ci struct nmk_pinctrl *npct; 184762306a36Sopenharmony_ci unsigned int version = 0; 184862306a36Sopenharmony_ci int i; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); 185162306a36Sopenharmony_ci if (!npct) 185262306a36Sopenharmony_ci return -ENOMEM; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci match = of_match_device(nmk_pinctrl_match, &pdev->dev); 185562306a36Sopenharmony_ci if (!match) 185662306a36Sopenharmony_ci return -ENODEV; 185762306a36Sopenharmony_ci version = (unsigned int) match->data; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci /* Poke in other ASIC variants here */ 186062306a36Sopenharmony_ci if (version == PINCTRL_NMK_STN8815) 186162306a36Sopenharmony_ci nmk_pinctrl_stn8815_init(&npct->soc); 186262306a36Sopenharmony_ci if (version == PINCTRL_NMK_DB8500) 186362306a36Sopenharmony_ci nmk_pinctrl_db8500_init(&npct->soc); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci /* 186662306a36Sopenharmony_ci * Since we depend on the GPIO chips to provide clock and register base 186762306a36Sopenharmony_ci * for the pin control operations, make sure that we have these 186862306a36Sopenharmony_ci * populated before we continue. Follow the phandles to instantiate 186962306a36Sopenharmony_ci * them. The GPIO portion of the actual hardware may be probed before 187062306a36Sopenharmony_ci * or after this point: it shouldn't matter as the APIs are orthogonal. 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_ci for (i = 0; i < NMK_MAX_BANKS; i++) { 187362306a36Sopenharmony_ci struct device_node *gpio_np; 187462306a36Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); 187762306a36Sopenharmony_ci if (gpio_np) { 187862306a36Sopenharmony_ci dev_info(&pdev->dev, 187962306a36Sopenharmony_ci "populate NMK GPIO %d \"%pOFn\"\n", 188062306a36Sopenharmony_ci i, gpio_np); 188162306a36Sopenharmony_ci nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); 188262306a36Sopenharmony_ci if (IS_ERR(nmk_chip)) 188362306a36Sopenharmony_ci dev_err(&pdev->dev, 188462306a36Sopenharmony_ci "could not populate nmk chip struct " 188562306a36Sopenharmony_ci "- continue anyway\n"); 188662306a36Sopenharmony_ci of_node_put(gpio_np); 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci prcm_np = of_parse_phandle(np, "prcm", 0); 189162306a36Sopenharmony_ci if (prcm_np) { 189262306a36Sopenharmony_ci npct->prcm_base = of_iomap(prcm_np, 0); 189362306a36Sopenharmony_ci of_node_put(prcm_np); 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci if (!npct->prcm_base) { 189662306a36Sopenharmony_ci if (version == PINCTRL_NMK_STN8815) { 189762306a36Sopenharmony_ci dev_info(&pdev->dev, 189862306a36Sopenharmony_ci "No PRCM base, " 189962306a36Sopenharmony_ci "assuming no ALT-Cx control is available\n"); 190062306a36Sopenharmony_ci } else { 190162306a36Sopenharmony_ci dev_err(&pdev->dev, "missing PRCM base address\n"); 190262306a36Sopenharmony_ci return -EINVAL; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci nmk_pinctrl_desc.pins = npct->soc->pins; 190762306a36Sopenharmony_ci nmk_pinctrl_desc.npins = npct->soc->npins; 190862306a36Sopenharmony_ci npct->dev = &pdev->dev; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci npct->pctl = devm_pinctrl_register(&pdev->dev, &nmk_pinctrl_desc, npct); 191162306a36Sopenharmony_ci if (IS_ERR(npct->pctl)) { 191262306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); 191362306a36Sopenharmony_ci return PTR_ERR(npct->pctl); 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci platform_set_drvdata(pdev, npct); 191762306a36Sopenharmony_ci dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci return 0; 192062306a36Sopenharmony_ci} 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_cistatic const struct of_device_id nmk_gpio_match[] = { 192362306a36Sopenharmony_ci { .compatible = "st,nomadik-gpio", }, 192462306a36Sopenharmony_ci {} 192562306a36Sopenharmony_ci}; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cistatic struct platform_driver nmk_gpio_driver = { 192862306a36Sopenharmony_ci .driver = { 192962306a36Sopenharmony_ci .name = "gpio", 193062306a36Sopenharmony_ci .of_match_table = nmk_gpio_match, 193162306a36Sopenharmony_ci }, 193262306a36Sopenharmony_ci .probe = nmk_gpio_probe, 193362306a36Sopenharmony_ci}; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops, 193662306a36Sopenharmony_ci nmk_pinctrl_suspend, 193762306a36Sopenharmony_ci nmk_pinctrl_resume); 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_cistatic struct platform_driver nmk_pinctrl_driver = { 194062306a36Sopenharmony_ci .driver = { 194162306a36Sopenharmony_ci .name = "pinctrl-nomadik", 194262306a36Sopenharmony_ci .of_match_table = nmk_pinctrl_match, 194362306a36Sopenharmony_ci .pm = &nmk_pinctrl_pm_ops, 194462306a36Sopenharmony_ci }, 194562306a36Sopenharmony_ci .probe = nmk_pinctrl_probe, 194662306a36Sopenharmony_ci}; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_cistatic int __init nmk_gpio_init(void) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci return platform_driver_register(&nmk_gpio_driver); 195162306a36Sopenharmony_ci} 195262306a36Sopenharmony_cisubsys_initcall(nmk_gpio_init); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cistatic int __init nmk_pinctrl_init(void) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci return platform_driver_register(&nmk_pinctrl_driver); 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_cicore_initcall(nmk_pinctrl_init); 1959