18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic GPIO driver for logic cells found in the Nomadik SoC 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008,2009 STMicroelectronics 68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> 78c2ecf20Sopenharmony_ci * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2011-2013 Linus Walleij <linus.walleij@linaro.org> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/of_device.h> 228c2ecf20Sopenharmony_ci#include <linux/of_address.h> 238c2ecf20Sopenharmony_ci#include <linux/bitops.h> 248c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 258c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 268c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 278c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 288c2ecf20Sopenharmony_ci/* Since we request GPIOs from ourself */ 298c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 308c2ecf20Sopenharmony_ci#include "pinctrl-nomadik.h" 318c2ecf20Sopenharmony_ci#include "../core.h" 328c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * The GPIO module in the Nomadik family of Systems-on-Chip is an 368c2ecf20Sopenharmony_ci * AMBA device, managing 32 pins and alternate functions. The logic block 378c2ecf20Sopenharmony_ci * is currently used in the Nomadik and ux500. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Symbols in this file are called "nmk_gpio" for "nomadik gpio" 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * pin configurations are represented by 32-bit integers: 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * bit 0.. 8 - Pin Number (512 Pins Maximum) 468c2ecf20Sopenharmony_ci * bit 9..10 - Alternate Function Selection 478c2ecf20Sopenharmony_ci * bit 11..12 - Pull up/down state 488c2ecf20Sopenharmony_ci * bit 13 - Sleep mode behaviour 498c2ecf20Sopenharmony_ci * bit 14 - Direction 508c2ecf20Sopenharmony_ci * bit 15 - Value (if output) 518c2ecf20Sopenharmony_ci * bit 16..18 - SLPM pull up/down state 528c2ecf20Sopenharmony_ci * bit 19..20 - SLPM direction 538c2ecf20Sopenharmony_ci * bit 21..22 - SLPM Value (if output) 548c2ecf20Sopenharmony_ci * bit 23..25 - PDIS value (if input) 558c2ecf20Sopenharmony_ci * bit 26 - Gpio mode 568c2ecf20Sopenharmony_ci * bit 27 - Sleep mode 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * to facilitate the definition, the following macros are provided 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * PIN_CFG_DEFAULT - default config (0): 618c2ecf20Sopenharmony_ci * pull up/down = disabled 628c2ecf20Sopenharmony_ci * sleep mode = input/wakeup 638c2ecf20Sopenharmony_ci * direction = input 648c2ecf20Sopenharmony_ci * value = low 658c2ecf20Sopenharmony_ci * SLPM direction = same as normal 668c2ecf20Sopenharmony_ci * SLPM pull = same as normal 678c2ecf20Sopenharmony_ci * SLPM value = same as normal 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * PIN_CFG - default config with alternate function 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_citypedef unsigned long pin_cfg_t; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define PIN_NUM_MASK 0x1ff 758c2ecf20Sopenharmony_ci#define PIN_NUM(x) ((x) & PIN_NUM_MASK) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define PIN_ALT_SHIFT 9 788c2ecf20Sopenharmony_ci#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT) 798c2ecf20Sopenharmony_ci#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT) 808c2ecf20Sopenharmony_ci#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT) 818c2ecf20Sopenharmony_ci#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT) 828c2ecf20Sopenharmony_ci#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT) 838c2ecf20Sopenharmony_ci#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define PIN_PULL_SHIFT 11 868c2ecf20Sopenharmony_ci#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT) 878c2ecf20Sopenharmony_ci#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT) 888c2ecf20Sopenharmony_ci#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT) 898c2ecf20Sopenharmony_ci#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT) 908c2ecf20Sopenharmony_ci#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define PIN_SLPM_SHIFT 13 938c2ecf20Sopenharmony_ci#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT) 948c2ecf20Sopenharmony_ci#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT) 958c2ecf20Sopenharmony_ci#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT) 968c2ecf20Sopenharmony_ci#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT) 978c2ecf20Sopenharmony_ci/* These two replace the above in DB8500v2+ */ 988c2ecf20Sopenharmony_ci#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT) 998c2ecf20Sopenharmony_ci#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT) 1008c2ecf20Sopenharmony_ci#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */ 1038c2ecf20Sopenharmony_ci#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define PIN_DIR_SHIFT 14 1068c2ecf20Sopenharmony_ci#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT) 1078c2ecf20Sopenharmony_ci#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT) 1088c2ecf20Sopenharmony_ci#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT) 1098c2ecf20Sopenharmony_ci#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define PIN_VAL_SHIFT 15 1128c2ecf20Sopenharmony_ci#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT) 1138c2ecf20Sopenharmony_ci#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT) 1148c2ecf20Sopenharmony_ci#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) 1158c2ecf20Sopenharmony_ci#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL_SHIFT 16 1188c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) 1198c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL(x) \ 1208c2ecf20Sopenharmony_ci (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) 1218c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL_NONE \ 1228c2ecf20Sopenharmony_ci ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) 1238c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL_UP \ 1248c2ecf20Sopenharmony_ci ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) 1258c2ecf20Sopenharmony_ci#define PIN_SLPM_PULL_DOWN \ 1268c2ecf20Sopenharmony_ci ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define PIN_SLPM_DIR_SHIFT 19 1298c2ecf20Sopenharmony_ci#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) 1308c2ecf20Sopenharmony_ci#define PIN_SLPM_DIR(x) \ 1318c2ecf20Sopenharmony_ci (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) 1328c2ecf20Sopenharmony_ci#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) 1338c2ecf20Sopenharmony_ci#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define PIN_SLPM_VAL_SHIFT 21 1368c2ecf20Sopenharmony_ci#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) 1378c2ecf20Sopenharmony_ci#define PIN_SLPM_VAL(x) \ 1388c2ecf20Sopenharmony_ci (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) 1398c2ecf20Sopenharmony_ci#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) 1408c2ecf20Sopenharmony_ci#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS_SHIFT 23 1438c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT) 1448c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS(x) \ 1458c2ecf20Sopenharmony_ci (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT) 1468c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT) 1478c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT) 1488c2ecf20Sopenharmony_ci#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define PIN_LOWEMI_SHIFT 25 1518c2ecf20Sopenharmony_ci#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT) 1528c2ecf20Sopenharmony_ci#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT) 1538c2ecf20Sopenharmony_ci#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) 1548c2ecf20Sopenharmony_ci#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define PIN_GPIOMODE_SHIFT 26 1578c2ecf20Sopenharmony_ci#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) 1588c2ecf20Sopenharmony_ci#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) 1598c2ecf20Sopenharmony_ci#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) 1608c2ecf20Sopenharmony_ci#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define PIN_SLEEPMODE_SHIFT 27 1638c2ecf20Sopenharmony_ci#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) 1648c2ecf20Sopenharmony_ci#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) 1658c2ecf20Sopenharmony_ci#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) 1668c2ecf20Sopenharmony_ci#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ 1708c2ecf20Sopenharmony_ci#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) 1718c2ecf20Sopenharmony_ci#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) 1728c2ecf20Sopenharmony_ci#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) 1738c2ecf20Sopenharmony_ci#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) 1748c2ecf20Sopenharmony_ci#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) 1778c2ecf20Sopenharmony_ci#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) 1788c2ecf20Sopenharmony_ci#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) 1798c2ecf20Sopenharmony_ci#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) 1808c2ecf20Sopenharmony_ci#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define PIN_CFG_DEFAULT (0) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define PIN_CFG(num, alt) \ 1858c2ecf20Sopenharmony_ci (PIN_CFG_DEFAULT |\ 1868c2ecf20Sopenharmony_ci (PIN_NUM(num) | PIN_##alt)) 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define PIN_CFG_INPUT(num, alt, pull) \ 1898c2ecf20Sopenharmony_ci (PIN_CFG_DEFAULT |\ 1908c2ecf20Sopenharmony_ci (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define PIN_CFG_OUTPUT(num, alt, val) \ 1938c2ecf20Sopenharmony_ci (PIN_CFG_DEFAULT |\ 1948c2ecf20Sopenharmony_ci (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving 1988c2ecf20Sopenharmony_ci * the "gpio" namespace for generic and cross-machine functions 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define GPIO_BLOCK_SHIFT 5 2028c2ecf20Sopenharmony_ci#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) 2038c2ecf20Sopenharmony_ci#define NMK_MAX_BANKS DIV_ROUND_UP(512, NMK_GPIO_PER_CHIP) 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* Register in the logic block */ 2068c2ecf20Sopenharmony_ci#define NMK_GPIO_DAT 0x00 2078c2ecf20Sopenharmony_ci#define NMK_GPIO_DATS 0x04 2088c2ecf20Sopenharmony_ci#define NMK_GPIO_DATC 0x08 2098c2ecf20Sopenharmony_ci#define NMK_GPIO_PDIS 0x0c 2108c2ecf20Sopenharmony_ci#define NMK_GPIO_DIR 0x10 2118c2ecf20Sopenharmony_ci#define NMK_GPIO_DIRS 0x14 2128c2ecf20Sopenharmony_ci#define NMK_GPIO_DIRC 0x18 2138c2ecf20Sopenharmony_ci#define NMK_GPIO_SLPC 0x1c 2148c2ecf20Sopenharmony_ci#define NMK_GPIO_AFSLA 0x20 2158c2ecf20Sopenharmony_ci#define NMK_GPIO_AFSLB 0x24 2168c2ecf20Sopenharmony_ci#define NMK_GPIO_LOWEMI 0x28 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#define NMK_GPIO_RIMSC 0x40 2198c2ecf20Sopenharmony_ci#define NMK_GPIO_FIMSC 0x44 2208c2ecf20Sopenharmony_ci#define NMK_GPIO_IS 0x48 2218c2ecf20Sopenharmony_ci#define NMK_GPIO_IC 0x4c 2228c2ecf20Sopenharmony_ci#define NMK_GPIO_RWIMSC 0x50 2238c2ecf20Sopenharmony_ci#define NMK_GPIO_FWIMSC 0x54 2248c2ecf20Sopenharmony_ci#define NMK_GPIO_WKS 0x58 2258c2ecf20Sopenharmony_ci/* These appear in DB8540 and later ASICs */ 2268c2ecf20Sopenharmony_ci#define NMK_GPIO_EDGELEVEL 0x5C 2278c2ecf20Sopenharmony_ci#define NMK_GPIO_LEVEL 0x60 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* Pull up/down values */ 2318c2ecf20Sopenharmony_cienum nmk_gpio_pull { 2328c2ecf20Sopenharmony_ci NMK_GPIO_PULL_NONE, 2338c2ecf20Sopenharmony_ci NMK_GPIO_PULL_UP, 2348c2ecf20Sopenharmony_ci NMK_GPIO_PULL_DOWN, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* Sleep mode */ 2388c2ecf20Sopenharmony_cienum nmk_gpio_slpm { 2398c2ecf20Sopenharmony_ci NMK_GPIO_SLPM_INPUT, 2408c2ecf20Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT, 2418c2ecf20Sopenharmony_ci NMK_GPIO_SLPM_NOCHANGE, 2428c2ecf20Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistruct nmk_gpio_chip { 2468c2ecf20Sopenharmony_ci struct gpio_chip chip; 2478c2ecf20Sopenharmony_ci struct irq_chip irqchip; 2488c2ecf20Sopenharmony_ci void __iomem *addr; 2498c2ecf20Sopenharmony_ci struct clk *clk; 2508c2ecf20Sopenharmony_ci unsigned int bank; 2518c2ecf20Sopenharmony_ci void (*set_ioforce)(bool enable); 2528c2ecf20Sopenharmony_ci spinlock_t lock; 2538c2ecf20Sopenharmony_ci bool sleepmode; 2548c2ecf20Sopenharmony_ci /* Keep track of configured edges */ 2558c2ecf20Sopenharmony_ci u32 edge_rising; 2568c2ecf20Sopenharmony_ci u32 edge_falling; 2578c2ecf20Sopenharmony_ci u32 real_wake; 2588c2ecf20Sopenharmony_ci u32 rwimsc; 2598c2ecf20Sopenharmony_ci u32 fwimsc; 2608c2ecf20Sopenharmony_ci u32 rimsc; 2618c2ecf20Sopenharmony_ci u32 fimsc; 2628c2ecf20Sopenharmony_ci u32 pull_up; 2638c2ecf20Sopenharmony_ci u32 lowemi; 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/** 2678c2ecf20Sopenharmony_ci * struct nmk_pinctrl - state container for the Nomadik pin controller 2688c2ecf20Sopenharmony_ci * @dev: containing device pointer 2698c2ecf20Sopenharmony_ci * @pctl: corresponding pin controller device 2708c2ecf20Sopenharmony_ci * @soc: SoC data for this specific chip 2718c2ecf20Sopenharmony_ci * @prcm_base: PRCM register range virtual base 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistruct nmk_pinctrl { 2748c2ecf20Sopenharmony_ci struct device *dev; 2758c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 2768c2ecf20Sopenharmony_ci const struct nmk_pinctrl_soc_data *soc; 2778c2ecf20Sopenharmony_ci void __iomem *prcm_base; 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(nmk_gpio_slpm_lock); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, 2878c2ecf20Sopenharmony_ci unsigned offset, int gpio_mode) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u32 afunc, bfunc; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~BIT(offset); 2928c2ecf20Sopenharmony_ci bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~BIT(offset); 2938c2ecf20Sopenharmony_ci if (gpio_mode & NMK_GPIO_ALT_A) 2948c2ecf20Sopenharmony_ci afunc |= BIT(offset); 2958c2ecf20Sopenharmony_ci if (gpio_mode & NMK_GPIO_ALT_B) 2968c2ecf20Sopenharmony_ci bfunc |= BIT(offset); 2978c2ecf20Sopenharmony_ci writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); 2988c2ecf20Sopenharmony_ci writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, 3028c2ecf20Sopenharmony_ci unsigned offset, enum nmk_gpio_slpm mode) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci u32 slpm; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); 3078c2ecf20Sopenharmony_ci if (mode == NMK_GPIO_SLPM_NOCHANGE) 3088c2ecf20Sopenharmony_ci slpm |= BIT(offset); 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci slpm &= ~BIT(offset); 3118c2ecf20Sopenharmony_ci writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, 3158c2ecf20Sopenharmony_ci unsigned offset, enum nmk_gpio_pull pull) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci u32 pdis; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); 3208c2ecf20Sopenharmony_ci if (pull == NMK_GPIO_PULL_NONE) { 3218c2ecf20Sopenharmony_ci pdis |= BIT(offset); 3228c2ecf20Sopenharmony_ci nmk_chip->pull_up &= ~BIT(offset); 3238c2ecf20Sopenharmony_ci } else { 3248c2ecf20Sopenharmony_ci pdis &= ~BIT(offset); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pull == NMK_GPIO_PULL_UP) { 3308c2ecf20Sopenharmony_ci nmk_chip->pull_up |= BIT(offset); 3318c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); 3328c2ecf20Sopenharmony_ci } else if (pull == NMK_GPIO_PULL_DOWN) { 3338c2ecf20Sopenharmony_ci nmk_chip->pull_up &= ~BIT(offset); 3348c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip, 3398c2ecf20Sopenharmony_ci unsigned offset, bool lowemi) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci bool enabled = nmk_chip->lowemi & BIT(offset); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (lowemi == enabled) 3448c2ecf20Sopenharmony_ci return; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (lowemi) 3478c2ecf20Sopenharmony_ci nmk_chip->lowemi |= BIT(offset); 3488c2ecf20Sopenharmony_ci else 3498c2ecf20Sopenharmony_ci nmk_chip->lowemi &= ~BIT(offset); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci writel_relaxed(nmk_chip->lowemi, 3528c2ecf20Sopenharmony_ci nmk_chip->addr + NMK_GPIO_LOWEMI); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, 3568c2ecf20Sopenharmony_ci unsigned offset) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip, 3628c2ecf20Sopenharmony_ci unsigned offset, int val) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci if (val) 3658c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATS); 3668c2ecf20Sopenharmony_ci else 3678c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DATC); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, 3718c2ecf20Sopenharmony_ci unsigned offset, int val) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRS); 3748c2ecf20Sopenharmony_ci __nmk_gpio_set_output(nmk_chip, offset, val); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, 3788c2ecf20Sopenharmony_ci unsigned offset, int gpio_mode, 3798c2ecf20Sopenharmony_ci bool glitch) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci u32 rwimsc = nmk_chip->rwimsc; 3828c2ecf20Sopenharmony_ci u32 fwimsc = nmk_chip->fwimsc; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (glitch && nmk_chip->set_ioforce) { 3858c2ecf20Sopenharmony_ci u32 bit = BIT(offset); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Prevent spurious wakeups */ 3888c2ecf20Sopenharmony_ci writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC); 3898c2ecf20Sopenharmony_ci writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci nmk_chip->set_ioforce(true); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (glitch && nmk_chip->set_ioforce) { 3978c2ecf20Sopenharmony_ci nmk_chip->set_ioforce(false); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC); 4008c2ecf20Sopenharmony_ci writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic void 4058c2ecf20Sopenharmony_cinmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci u32 falling = nmk_chip->fimsc & BIT(offset); 4088c2ecf20Sopenharmony_ci u32 rising = nmk_chip->rimsc & BIT(offset); 4098c2ecf20Sopenharmony_ci int gpio = nmk_chip->chip.base + offset; 4108c2ecf20Sopenharmony_ci int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset); 4118c2ecf20Sopenharmony_ci struct irq_data *d = irq_get_irq_data(irq); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (!rising && !falling) 4148c2ecf20Sopenharmony_ci return; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!d || !irqd_irq_disabled(d)) 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (rising) { 4208c2ecf20Sopenharmony_ci nmk_chip->rimsc &= ~BIT(offset); 4218c2ecf20Sopenharmony_ci writel_relaxed(nmk_chip->rimsc, 4228c2ecf20Sopenharmony_ci nmk_chip->addr + NMK_GPIO_RIMSC); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (falling) { 4268c2ecf20Sopenharmony_ci nmk_chip->fimsc &= ~BIT(offset); 4278c2ecf20Sopenharmony_ci writel_relaxed(nmk_chip->fimsc, 4288c2ecf20Sopenharmony_ci nmk_chip->addr + NMK_GPIO_FIMSC); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, "%d: clearing interrupt mask\n", gpio); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void nmk_write_masked(void __iomem *reg, u32 mask, u32 value) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci u32 val; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci val = readl(reg); 4398c2ecf20Sopenharmony_ci val = ((val & ~mask) | (value & mask)); 4408c2ecf20Sopenharmony_ci writel(val, reg); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, 4448c2ecf20Sopenharmony_ci unsigned offset, unsigned alt_num) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int i; 4478c2ecf20Sopenharmony_ci u16 reg; 4488c2ecf20Sopenharmony_ci u8 bit; 4498c2ecf20Sopenharmony_ci u8 alt_index; 4508c2ecf20Sopenharmony_ci const struct prcm_gpiocr_altcx_pin_desc *pin_desc; 4518c2ecf20Sopenharmony_ci const u16 *gpiocr_regs; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (!npct->prcm_base) 4548c2ecf20Sopenharmony_ci return; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { 4578c2ecf20Sopenharmony_ci dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", 4588c2ecf20Sopenharmony_ci alt_num); 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci for (i = 0 ; i < npct->soc->npins_altcx ; i++) { 4638c2ecf20Sopenharmony_ci if (npct->soc->altcx_pins[i].pin == offset) 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci if (i == npct->soc->npins_altcx) { 4678c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", 4688c2ecf20Sopenharmony_ci offset); 4698c2ecf20Sopenharmony_ci return; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci pin_desc = npct->soc->altcx_pins + i; 4738c2ecf20Sopenharmony_ci gpiocr_regs = npct->soc->prcm_gpiocr_registers; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* 4768c2ecf20Sopenharmony_ci * If alt_num is NULL, just clear current ALTCx selection 4778c2ecf20Sopenharmony_ci * to make sure we come back to a pure ALTC selection 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci if (!alt_num) { 4808c2ecf20Sopenharmony_ci for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { 4818c2ecf20Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 4828c2ecf20Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 4838c2ecf20Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 4848c2ecf20Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) { 4858c2ecf20Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); 4868c2ecf20Sopenharmony_ci dev_dbg(npct->dev, 4878c2ecf20Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", 4888c2ecf20Sopenharmony_ci offset, i+1); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci return; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci alt_index = alt_num - 1; 4968c2ecf20Sopenharmony_ci if (pin_desc->altcx[alt_index].used == false) { 4978c2ecf20Sopenharmony_ci dev_warn(npct->dev, 4988c2ecf20Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", 4998c2ecf20Sopenharmony_ci offset, alt_num); 5008c2ecf20Sopenharmony_ci return; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* 5048c2ecf20Sopenharmony_ci * Check if any other ALTCx functions are activated on this pin 5058c2ecf20Sopenharmony_ci * and disable it first. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { 5088c2ecf20Sopenharmony_ci if (i == alt_index) 5098c2ecf20Sopenharmony_ci continue; 5108c2ecf20Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 5118c2ecf20Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 5128c2ecf20Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 5138c2ecf20Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) { 5148c2ecf20Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); 5158c2ecf20Sopenharmony_ci dev_dbg(npct->dev, 5168c2ecf20Sopenharmony_ci "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", 5178c2ecf20Sopenharmony_ci offset, i+1); 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; 5238c2ecf20Sopenharmony_ci bit = pin_desc->altcx[alt_index].control_bit; 5248c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", 5258c2ecf20Sopenharmony_ci offset, alt_index+1); 5268c2ecf20Sopenharmony_ci nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit)); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/* 5308c2ecf20Sopenharmony_ci * Safe sequence used to switch IOs between GPIO and Alternate-C mode: 5318c2ecf20Sopenharmony_ci * - Save SLPM registers 5328c2ecf20Sopenharmony_ci * - Set SLPM=0 for the IOs you want to switch and others to 1 5338c2ecf20Sopenharmony_ci * - Configure the GPIO registers for the IOs that are being switched 5348c2ecf20Sopenharmony_ci * - Set IOFORCE=1 5358c2ecf20Sopenharmony_ci * - Modify the AFLSA/B registers for the IOs that are being switched 5368c2ecf20Sopenharmony_ci * - Set IOFORCE=0 5378c2ecf20Sopenharmony_ci * - Restore SLPM registers 5388c2ecf20Sopenharmony_ci * - Any spurious wake up event during switch sequence to be ignored and 5398c2ecf20Sopenharmony_ci * cleared 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic void nmk_gpio_glitch_slpm_init(unsigned int *slpm) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci int i; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci for (i = 0; i < NUM_BANKS; i++) { 5468c2ecf20Sopenharmony_ci struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; 5478c2ecf20Sopenharmony_ci unsigned int temp = slpm[i]; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!chip) 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci clk_enable(chip->clk); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); 5558c2ecf20Sopenharmony_ci writel(temp, chip->addr + NMK_GPIO_SLPC); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci int i; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci for (i = 0; i < NUM_BANKS; i++) { 5648c2ecf20Sopenharmony_ci struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (!chip) 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci writel(slpm[i], chip->addr + NMK_GPIO_SLPC); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci clk_disable(chip->clk); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci int i; 5788c2ecf20Sopenharmony_ci u16 reg; 5798c2ecf20Sopenharmony_ci u8 bit; 5808c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 5818c2ecf20Sopenharmony_ci const struct prcm_gpiocr_altcx_pin_desc *pin_desc; 5828c2ecf20Sopenharmony_ci const u16 *gpiocr_regs; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!npct->prcm_base) 5858c2ecf20Sopenharmony_ci return NMK_GPIO_ALT_C; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci for (i = 0; i < npct->soc->npins_altcx; i++) { 5888c2ecf20Sopenharmony_ci if (npct->soc->altcx_pins[i].pin == gpio) 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci if (i == npct->soc->npins_altcx) 5928c2ecf20Sopenharmony_ci return NMK_GPIO_ALT_C; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci pin_desc = npct->soc->altcx_pins + i; 5958c2ecf20Sopenharmony_ci gpiocr_regs = npct->soc->prcm_gpiocr_registers; 5968c2ecf20Sopenharmony_ci for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) { 5978c2ecf20Sopenharmony_ci if (pin_desc->altcx[i].used == true) { 5988c2ecf20Sopenharmony_ci reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; 5998c2ecf20Sopenharmony_ci bit = pin_desc->altcx[i].control_bit; 6008c2ecf20Sopenharmony_ci if (readl(npct->prcm_base + reg) & BIT(bit)) 6018c2ecf20Sopenharmony_ci return NMK_GPIO_ALT_C+i+1; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci return NMK_GPIO_ALT_C; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* IRQ functions */ 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void nmk_gpio_irq_ack(struct irq_data *d) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(d); 6128c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 6158c2ecf20Sopenharmony_ci writel(BIT(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); 6168c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cienum nmk_gpio_irq_type { 6208c2ecf20Sopenharmony_ci NORMAL, 6218c2ecf20Sopenharmony_ci WAKE, 6228c2ecf20Sopenharmony_ci}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, 6258c2ecf20Sopenharmony_ci int offset, enum nmk_gpio_irq_type which, 6268c2ecf20Sopenharmony_ci bool enable) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci u32 *rimscval; 6298c2ecf20Sopenharmony_ci u32 *fimscval; 6308c2ecf20Sopenharmony_ci u32 rimscreg; 6318c2ecf20Sopenharmony_ci u32 fimscreg; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (which == NORMAL) { 6348c2ecf20Sopenharmony_ci rimscreg = NMK_GPIO_RIMSC; 6358c2ecf20Sopenharmony_ci fimscreg = NMK_GPIO_FIMSC; 6368c2ecf20Sopenharmony_ci rimscval = &nmk_chip->rimsc; 6378c2ecf20Sopenharmony_ci fimscval = &nmk_chip->fimsc; 6388c2ecf20Sopenharmony_ci } else { 6398c2ecf20Sopenharmony_ci rimscreg = NMK_GPIO_RWIMSC; 6408c2ecf20Sopenharmony_ci fimscreg = NMK_GPIO_FWIMSC; 6418c2ecf20Sopenharmony_ci rimscval = &nmk_chip->rwimsc; 6428c2ecf20Sopenharmony_ci fimscval = &nmk_chip->fwimsc; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* we must individually set/clear the two edges */ 6468c2ecf20Sopenharmony_ci if (nmk_chip->edge_rising & BIT(offset)) { 6478c2ecf20Sopenharmony_ci if (enable) 6488c2ecf20Sopenharmony_ci *rimscval |= BIT(offset); 6498c2ecf20Sopenharmony_ci else 6508c2ecf20Sopenharmony_ci *rimscval &= ~BIT(offset); 6518c2ecf20Sopenharmony_ci writel(*rimscval, nmk_chip->addr + rimscreg); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci if (nmk_chip->edge_falling & BIT(offset)) { 6548c2ecf20Sopenharmony_ci if (enable) 6558c2ecf20Sopenharmony_ci *fimscval |= BIT(offset); 6568c2ecf20Sopenharmony_ci else 6578c2ecf20Sopenharmony_ci *fimscval &= ~BIT(offset); 6588c2ecf20Sopenharmony_ci writel(*fimscval, nmk_chip->addr + fimscreg); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, 6638c2ecf20Sopenharmony_ci int offset, bool on) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci /* 6668c2ecf20Sopenharmony_ci * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is 6678c2ecf20Sopenharmony_ci * disabled, since setting SLPM to 1 increases power consumption, and 6688c2ecf20Sopenharmony_ci * wakeup is anyhow controlled by the RIMSC and FIMSC registers. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci if (nmk_chip->sleepmode && on) { 6718c2ecf20Sopenharmony_ci __nmk_gpio_set_slpm(nmk_chip, offset, 6728c2ecf20Sopenharmony_ci NMK_GPIO_SLPM_WAKEUP_ENABLE); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, offset, WAKE, on); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 6818c2ecf20Sopenharmony_ci unsigned long flags; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci nmk_chip = irq_data_get_irq_chip_data(d); 6848c2ecf20Sopenharmony_ci if (!nmk_chip) 6858c2ecf20Sopenharmony_ci return -EINVAL; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 6888c2ecf20Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 6898c2ecf20Sopenharmony_ci spin_lock(&nmk_chip->lock); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (!(nmk_chip->real_wake & BIT(d->hwirq))) 6948c2ecf20Sopenharmony_ci __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci spin_unlock(&nmk_chip->lock); 6978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 6988c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic void nmk_gpio_irq_mask(struct irq_data *d) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci nmk_gpio_irq_maskunmask(d, false); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void nmk_gpio_irq_unmask(struct irq_data *d) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci nmk_gpio_irq_maskunmask(d, true); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 7168c2ecf20Sopenharmony_ci unsigned long flags; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci nmk_chip = irq_data_get_irq_chip_data(d); 7198c2ecf20Sopenharmony_ci if (!nmk_chip) 7208c2ecf20Sopenharmony_ci return -EINVAL; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 7238c2ecf20Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 7248c2ecf20Sopenharmony_ci spin_lock(&nmk_chip->lock); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (irqd_irq_disabled(d)) 7278c2ecf20Sopenharmony_ci __nmk_gpio_set_wake(nmk_chip, d->hwirq, on); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (on) 7308c2ecf20Sopenharmony_ci nmk_chip->real_wake |= BIT(d->hwirq); 7318c2ecf20Sopenharmony_ci else 7328c2ecf20Sopenharmony_ci nmk_chip->real_wake &= ~BIT(d->hwirq); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci spin_unlock(&nmk_chip->lock); 7358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 7368c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci bool enabled = !irqd_irq_disabled(d); 7448c2ecf20Sopenharmony_ci bool wake = irqd_is_wakeup_set(d); 7458c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 7468c2ecf20Sopenharmony_ci unsigned long flags; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci nmk_chip = irq_data_get_irq_chip_data(d); 7498c2ecf20Sopenharmony_ci if (!nmk_chip) 7508c2ecf20Sopenharmony_ci return -EINVAL; 7518c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_HIGH) 7528c2ecf20Sopenharmony_ci return -EINVAL; 7538c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_LOW) 7548c2ecf20Sopenharmony_ci return -EINVAL; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 7578c2ecf20Sopenharmony_ci spin_lock_irqsave(&nmk_chip->lock, flags); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (enabled) 7608c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (enabled || wake) 7638c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci nmk_chip->edge_rising &= ~BIT(d->hwirq); 7668c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 7678c2ecf20Sopenharmony_ci nmk_chip->edge_rising |= BIT(d->hwirq); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci nmk_chip->edge_falling &= ~BIT(d->hwirq); 7708c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 7718c2ecf20Sopenharmony_ci nmk_chip->edge_falling |= BIT(d->hwirq); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (enabled) 7748c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (enabled || wake) 7778c2ecf20Sopenharmony_ci __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nmk_chip->lock, flags); 7808c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic unsigned int nmk_gpio_irq_startup(struct irq_data *d) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 7908c2ecf20Sopenharmony_ci nmk_gpio_irq_unmask(d); 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void nmk_gpio_irq_shutdown(struct irq_data *d) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci nmk_gpio_irq_mask(d); 7998c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic void nmk_gpio_irq_handler(struct irq_desc *desc) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct irq_chip *host_chip = irq_desc_get_chip(desc); 8058c2ecf20Sopenharmony_ci struct gpio_chip *chip = irq_desc_get_handler_data(desc); 8068c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8078c2ecf20Sopenharmony_ci u32 status; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci chained_irq_enter(host_chip, desc); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8128c2ecf20Sopenharmony_ci status = readl(nmk_chip->addr + NMK_GPIO_IS); 8138c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci while (status) { 8168c2ecf20Sopenharmony_ci int bit = __ffs(status); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(chip->irq.domain, bit)); 8198c2ecf20Sopenharmony_ci status &= ~BIT(bit); 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci chained_irq_exit(host_chip, desc); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci/* I/O Functions */ 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int nmk_gpio_get_dir(struct gpio_chip *chip, unsigned offset) 8288c2ecf20Sopenharmony_ci{ 8298c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8308c2ecf20Sopenharmony_ci int dir; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci dir = readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (dir) 8398c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci writel(BIT(offset), nmk_chip->addr + NMK_GPIO_DIRC); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return 0; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8608c2ecf20Sopenharmony_ci int value; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci value = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return value; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, 8728c2ecf20Sopenharmony_ci int val) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci __nmk_gpio_set_output(nmk_chip, offset, val); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, 8848c2ecf20Sopenharmony_ci int val) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci __nmk_gpio_make_output(nmk_chip, offset, val); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 8988c2ecf20Sopenharmony_cistatic int nmk_gpio_get_mode(struct nmk_gpio_chip *nmk_chip, int offset) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci u32 afunc, bfunc; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & BIT(offset); 9058c2ecf20Sopenharmony_ci bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & BIT(offset); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void nmk_gpio_dbg_show_one(struct seq_file *s, 9158c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev, struct gpio_chip *chip, 9168c2ecf20Sopenharmony_ci unsigned offset, unsigned gpio) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci const char *label = gpiochip_is_requested(chip, offset); 9198c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip = gpiochip_get_data(chip); 9208c2ecf20Sopenharmony_ci int mode; 9218c2ecf20Sopenharmony_ci bool is_out; 9228c2ecf20Sopenharmony_ci bool data_out; 9238c2ecf20Sopenharmony_ci bool pull; 9248c2ecf20Sopenharmony_ci const char *modes[] = { 9258c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_GPIO] = "gpio", 9268c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_A] = "altA", 9278c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_B] = "altB", 9288c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_C] = "altC", 9298c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_C+1] = "altC1", 9308c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_C+2] = "altC2", 9318c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_C+3] = "altC3", 9328c2ecf20Sopenharmony_ci [NMK_GPIO_ALT_C+4] = "altC4", 9338c2ecf20Sopenharmony_ci }; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 9368c2ecf20Sopenharmony_ci is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & BIT(offset)); 9378c2ecf20Sopenharmony_ci pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & BIT(offset)); 9388c2ecf20Sopenharmony_ci data_out = !!(readl(nmk_chip->addr + NMK_GPIO_DAT) & BIT(offset)); 9398c2ecf20Sopenharmony_ci mode = nmk_gpio_get_mode(nmk_chip, offset); 9408c2ecf20Sopenharmony_ci if ((mode == NMK_GPIO_ALT_C) && pctldev) 9418c2ecf20Sopenharmony_ci mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci if (is_out) { 9448c2ecf20Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) out %s %s", 9458c2ecf20Sopenharmony_ci gpio, 9468c2ecf20Sopenharmony_ci label ?: "(none)", 9478c2ecf20Sopenharmony_ci data_out ? "hi" : "lo", 9488c2ecf20Sopenharmony_ci (mode < 0) ? "unknown" : modes[mode]); 9498c2ecf20Sopenharmony_ci } else { 9508c2ecf20Sopenharmony_ci int irq = chip->to_irq(chip, offset); 9518c2ecf20Sopenharmony_ci struct irq_desc *desc = irq_to_desc(irq); 9528c2ecf20Sopenharmony_ci const int pullidx = pull ? 1 : 0; 9538c2ecf20Sopenharmony_ci int val; 9548c2ecf20Sopenharmony_ci static const char * const pulls[] = { 9558c2ecf20Sopenharmony_ci "none ", 9568c2ecf20Sopenharmony_ci "pull enabled", 9578c2ecf20Sopenharmony_ci }; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s", 9608c2ecf20Sopenharmony_ci gpio, 9618c2ecf20Sopenharmony_ci label ?: "(none)", 9628c2ecf20Sopenharmony_ci pulls[pullidx], 9638c2ecf20Sopenharmony_ci (mode < 0) ? "unknown" : modes[mode]); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci val = nmk_gpio_get_input(chip, offset); 9668c2ecf20Sopenharmony_ci seq_printf(s, " VAL %d", val); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* 9698c2ecf20Sopenharmony_ci * This races with request_irq(), set_irq_type(), 9708c2ecf20Sopenharmony_ci * and set_irq_wake() ... but those are "rare". 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ci if (irq > 0 && desc && desc->action) { 9738c2ecf20Sopenharmony_ci char *trigger; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (nmk_chip->edge_rising & BIT(offset)) 9768c2ecf20Sopenharmony_ci trigger = "edge-rising"; 9778c2ecf20Sopenharmony_ci else if (nmk_chip->edge_falling & BIT(offset)) 9788c2ecf20Sopenharmony_ci trigger = "edge-falling"; 9798c2ecf20Sopenharmony_ci else 9808c2ecf20Sopenharmony_ci trigger = "edge-undefined"; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci seq_printf(s, " irq-%d %s%s", 9838c2ecf20Sopenharmony_ci irq, trigger, 9848c2ecf20Sopenharmony_ci irqd_is_wakeup_set(&desc->irq_data) 9858c2ecf20Sopenharmony_ci ? " wakeup" : ""); 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci unsigned i; 9948c2ecf20Sopenharmony_ci unsigned gpio = chip->base; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci for (i = 0; i < chip->ngpio; i++, gpio++) { 9978c2ecf20Sopenharmony_ci nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio); 9988c2ecf20Sopenharmony_ci seq_printf(s, "\n"); 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci#else 10038c2ecf20Sopenharmony_cistatic inline void nmk_gpio_dbg_show_one(struct seq_file *s, 10048c2ecf20Sopenharmony_ci struct pinctrl_dev *pctldev, 10058c2ecf20Sopenharmony_ci struct gpio_chip *chip, 10068c2ecf20Sopenharmony_ci unsigned offset, unsigned gpio) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci#define nmk_gpio_dbg_show NULL 10108c2ecf20Sopenharmony_ci#endif 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/* 10138c2ecf20Sopenharmony_ci * We will allocate memory for the state container using devm* allocators 10148c2ecf20Sopenharmony_ci * binding to the first device reaching this point, it doesn't matter if 10158c2ecf20Sopenharmony_ci * it is the pin controller or GPIO driver. However we need to use the right 10168c2ecf20Sopenharmony_ci * platform device when looking up resources so pay attention to pdev. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, 10198c2ecf20Sopenharmony_ci struct platform_device *pdev) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 10228c2ecf20Sopenharmony_ci struct platform_device *gpio_pdev; 10238c2ecf20Sopenharmony_ci struct gpio_chip *chip; 10248c2ecf20Sopenharmony_ci struct resource *res; 10258c2ecf20Sopenharmony_ci struct clk *clk; 10268c2ecf20Sopenharmony_ci void __iomem *base; 10278c2ecf20Sopenharmony_ci u32 id; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci gpio_pdev = of_find_device_by_node(np); 10308c2ecf20Sopenharmony_ci if (!gpio_pdev) { 10318c2ecf20Sopenharmony_ci pr_err("populate \"%pOFn\": device not found\n", np); 10328c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "gpio-bank", &id)) { 10358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "populate: gpio-bank property not found\n"); 10368c2ecf20Sopenharmony_ci platform_device_put(gpio_pdev); 10378c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* Already populated? */ 10418c2ecf20Sopenharmony_ci nmk_chip = nmk_gpio_chips[id]; 10428c2ecf20Sopenharmony_ci if (nmk_chip) { 10438c2ecf20Sopenharmony_ci platform_device_put(gpio_pdev); 10448c2ecf20Sopenharmony_ci return nmk_chip; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci nmk_chip = devm_kzalloc(&pdev->dev, sizeof(*nmk_chip), GFP_KERNEL); 10488c2ecf20Sopenharmony_ci if (!nmk_chip) { 10498c2ecf20Sopenharmony_ci platform_device_put(gpio_pdev); 10508c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci nmk_chip->bank = id; 10548c2ecf20Sopenharmony_ci chip = &nmk_chip->chip; 10558c2ecf20Sopenharmony_ci chip->base = id * NMK_GPIO_PER_CHIP; 10568c2ecf20Sopenharmony_ci chip->ngpio = NMK_GPIO_PER_CHIP; 10578c2ecf20Sopenharmony_ci chip->label = dev_name(&gpio_pdev->dev); 10588c2ecf20Sopenharmony_ci chip->parent = &gpio_pdev->dev; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0); 10618c2ecf20Sopenharmony_ci base = devm_ioremap_resource(&pdev->dev, res); 10628c2ecf20Sopenharmony_ci if (IS_ERR(base)) { 10638c2ecf20Sopenharmony_ci platform_device_put(gpio_pdev); 10648c2ecf20Sopenharmony_ci return ERR_CAST(base); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci nmk_chip->addr = base; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci clk = clk_get(&gpio_pdev->dev, NULL); 10698c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 10708c2ecf20Sopenharmony_ci platform_device_put(gpio_pdev); 10718c2ecf20Sopenharmony_ci return (void *) clk; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci clk_prepare(clk); 10748c2ecf20Sopenharmony_ci nmk_chip->clk = clk; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); 10778c2ecf20Sopenharmony_ci nmk_gpio_chips[id] = nmk_chip; 10788c2ecf20Sopenharmony_ci return nmk_chip; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_cistatic int nmk_gpio_probe(struct platform_device *dev) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci struct device_node *np = dev->dev.of_node; 10848c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 10858c2ecf20Sopenharmony_ci struct gpio_chip *chip; 10868c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 10878c2ecf20Sopenharmony_ci struct irq_chip *irqchip; 10888c2ecf20Sopenharmony_ci bool supports_sleepmode; 10898c2ecf20Sopenharmony_ci int irq; 10908c2ecf20Sopenharmony_ci int ret; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci nmk_chip = nmk_gpio_populate_chip(np, dev); 10938c2ecf20Sopenharmony_ci if (IS_ERR(nmk_chip)) { 10948c2ecf20Sopenharmony_ci dev_err(&dev->dev, "could not populate nmk chip struct\n"); 10958c2ecf20Sopenharmony_ci return PTR_ERR(nmk_chip); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci supports_sleepmode = 10998c2ecf20Sopenharmony_ci of_property_read_bool(np, "st,supports-sleepmode"); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Correct platform device ID */ 11028c2ecf20Sopenharmony_ci dev->id = nmk_chip->bank; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci irq = platform_get_irq(dev, 0); 11058c2ecf20Sopenharmony_ci if (irq < 0) 11068c2ecf20Sopenharmony_ci return irq; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* 11098c2ecf20Sopenharmony_ci * The virt address in nmk_chip->addr is in the nomadik register space, 11108c2ecf20Sopenharmony_ci * so we can simply convert the resource address, without remapping 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_ci nmk_chip->sleepmode = supports_sleepmode; 11138c2ecf20Sopenharmony_ci spin_lock_init(&nmk_chip->lock); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci chip = &nmk_chip->chip; 11168c2ecf20Sopenharmony_ci chip->request = gpiochip_generic_request; 11178c2ecf20Sopenharmony_ci chip->free = gpiochip_generic_free; 11188c2ecf20Sopenharmony_ci chip->get_direction = nmk_gpio_get_dir; 11198c2ecf20Sopenharmony_ci chip->direction_input = nmk_gpio_make_input; 11208c2ecf20Sopenharmony_ci chip->get = nmk_gpio_get_input; 11218c2ecf20Sopenharmony_ci chip->direction_output = nmk_gpio_make_output; 11228c2ecf20Sopenharmony_ci chip->set = nmk_gpio_set_output; 11238c2ecf20Sopenharmony_ci chip->dbg_show = nmk_gpio_dbg_show; 11248c2ecf20Sopenharmony_ci chip->can_sleep = false; 11258c2ecf20Sopenharmony_ci chip->owner = THIS_MODULE; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci irqchip = &nmk_chip->irqchip; 11288c2ecf20Sopenharmony_ci irqchip->irq_ack = nmk_gpio_irq_ack; 11298c2ecf20Sopenharmony_ci irqchip->irq_mask = nmk_gpio_irq_mask; 11308c2ecf20Sopenharmony_ci irqchip->irq_unmask = nmk_gpio_irq_unmask; 11318c2ecf20Sopenharmony_ci irqchip->irq_set_type = nmk_gpio_irq_set_type; 11328c2ecf20Sopenharmony_ci irqchip->irq_set_wake = nmk_gpio_irq_set_wake; 11338c2ecf20Sopenharmony_ci irqchip->irq_startup = nmk_gpio_irq_startup; 11348c2ecf20Sopenharmony_ci irqchip->irq_shutdown = nmk_gpio_irq_shutdown; 11358c2ecf20Sopenharmony_ci irqchip->flags = IRQCHIP_MASK_ON_SUSPEND; 11368c2ecf20Sopenharmony_ci irqchip->name = kasprintf(GFP_KERNEL, "nmk%u-%u-%u", 11378c2ecf20Sopenharmony_ci dev->id, 11388c2ecf20Sopenharmony_ci chip->base, 11398c2ecf20Sopenharmony_ci chip->base + chip->ngpio - 1); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci girq = &chip->irq; 11428c2ecf20Sopenharmony_ci girq->chip = irqchip; 11438c2ecf20Sopenharmony_ci girq->parent_handler = nmk_gpio_irq_handler; 11448c2ecf20Sopenharmony_ci girq->num_parents = 1; 11458c2ecf20Sopenharmony_ci girq->parents = devm_kcalloc(&dev->dev, 1, 11468c2ecf20Sopenharmony_ci sizeof(*girq->parents), 11478c2ecf20Sopenharmony_ci GFP_KERNEL); 11488c2ecf20Sopenharmony_ci if (!girq->parents) 11498c2ecf20Sopenharmony_ci return -ENOMEM; 11508c2ecf20Sopenharmony_ci girq->parents[0] = irq; 11518c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 11528c2ecf20Sopenharmony_ci girq->handler = handle_edge_irq; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 11558c2ecf20Sopenharmony_ci nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI); 11568c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 11578c2ecf20Sopenharmony_ci chip->of_node = np; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci ret = gpiochip_add_data(chip, nmk_chip); 11608c2ecf20Sopenharmony_ci if (ret) 11618c2ecf20Sopenharmony_ci return ret; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci platform_set_drvdata(dev, nmk_chip); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci dev_info(&dev->dev, "chip registered\n"); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return 0; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int nmk_get_groups_cnt(struct pinctrl_dev *pctldev) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return npct->soc->ngroups; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic const char *nmk_get_group_name(struct pinctrl_dev *pctldev, 11788c2ecf20Sopenharmony_ci unsigned selector) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return npct->soc->groups[selector].name; 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 11868c2ecf20Sopenharmony_ci const unsigned **pins, 11878c2ecf20Sopenharmony_ci unsigned *num_pins) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci *pins = npct->soc->groups[selector].pins; 11928c2ecf20Sopenharmony_ci *num_pins = npct->soc->groups[selector].npins; 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic struct nmk_gpio_chip *find_nmk_gpio_from_pin(unsigned pin) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci int i; 11998c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_gpio; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci for(i = 0; i < NMK_MAX_BANKS; i++) { 12028c2ecf20Sopenharmony_ci nmk_gpio = nmk_gpio_chips[i]; 12038c2ecf20Sopenharmony_ci if (!nmk_gpio) 12048c2ecf20Sopenharmony_ci continue; 12058c2ecf20Sopenharmony_ci if (pin >= nmk_gpio->chip.base && 12068c2ecf20Sopenharmony_ci pin < nmk_gpio->chip.base + nmk_gpio->chip.ngpio) 12078c2ecf20Sopenharmony_ci return nmk_gpio; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci return NULL; 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic struct gpio_chip *find_gc_from_pin(unsigned pin) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_gpio = find_nmk_gpio_from_pin(pin); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (nmk_gpio) 12178c2ecf20Sopenharmony_ci return &nmk_gpio->chip; 12188c2ecf20Sopenharmony_ci return NULL; 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 12228c2ecf20Sopenharmony_ci unsigned offset) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct gpio_chip *chip = find_gc_from_pin(offset); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (!chip) { 12278c2ecf20Sopenharmony_ci seq_printf(s, "invalid pin offset"); 12288c2ecf20Sopenharmony_ci return; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic int nmk_dt_add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, 12348c2ecf20Sopenharmony_ci unsigned *num_maps, const char *group, 12358c2ecf20Sopenharmony_ci const char *function) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci if (*num_maps == *reserved_maps) 12388c2ecf20Sopenharmony_ci return -ENOSPC; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 12418c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.group = group; 12428c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.function = function; 12438c2ecf20Sopenharmony_ci (*num_maps)++; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return 0; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int nmk_dt_add_map_configs(struct pinctrl_map **map, 12498c2ecf20Sopenharmony_ci unsigned *reserved_maps, 12508c2ecf20Sopenharmony_ci unsigned *num_maps, const char *group, 12518c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci unsigned long *dup_configs; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (*num_maps == *reserved_maps) 12568c2ecf20Sopenharmony_ci return -ENOSPC; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), 12598c2ecf20Sopenharmony_ci GFP_KERNEL); 12608c2ecf20Sopenharmony_ci if (!dup_configs) 12618c2ecf20Sopenharmony_ci return -ENOMEM; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci (*map)[*num_maps].data.configs.group_or_pin = group; 12668c2ecf20Sopenharmony_ci (*map)[*num_maps].data.configs.configs = dup_configs; 12678c2ecf20Sopenharmony_ci (*map)[*num_maps].data.configs.num_configs = num_configs; 12688c2ecf20Sopenharmony_ci (*num_maps)++; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci#define NMK_CONFIG_PIN(x, y) { .property = x, .config = y, } 12748c2ecf20Sopenharmony_ci#define NMK_CONFIG_PIN_ARRAY(x, y) { .property = x, .choice = y, \ 12758c2ecf20Sopenharmony_ci .size = ARRAY_SIZE(y), } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_input_modes[] = { 12788c2ecf20Sopenharmony_ci PIN_INPUT_NOPULL, 12798c2ecf20Sopenharmony_ci PIN_INPUT_PULLUP, 12808c2ecf20Sopenharmony_ci PIN_INPUT_PULLDOWN, 12818c2ecf20Sopenharmony_ci}; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_output_modes[] = { 12848c2ecf20Sopenharmony_ci PIN_OUTPUT_LOW, 12858c2ecf20Sopenharmony_ci PIN_OUTPUT_HIGH, 12868c2ecf20Sopenharmony_ci PIN_DIR_OUTPUT, 12878c2ecf20Sopenharmony_ci}; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_sleep_modes[] = { 12908c2ecf20Sopenharmony_ci PIN_SLEEPMODE_DISABLED, 12918c2ecf20Sopenharmony_ci PIN_SLEEPMODE_ENABLED, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_sleep_input_modes[] = { 12958c2ecf20Sopenharmony_ci PIN_SLPM_INPUT_NOPULL, 12968c2ecf20Sopenharmony_ci PIN_SLPM_INPUT_PULLUP, 12978c2ecf20Sopenharmony_ci PIN_SLPM_INPUT_PULLDOWN, 12988c2ecf20Sopenharmony_ci PIN_SLPM_DIR_INPUT, 12998c2ecf20Sopenharmony_ci}; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_sleep_output_modes[] = { 13028c2ecf20Sopenharmony_ci PIN_SLPM_OUTPUT_LOW, 13038c2ecf20Sopenharmony_ci PIN_SLPM_OUTPUT_HIGH, 13048c2ecf20Sopenharmony_ci PIN_SLPM_DIR_OUTPUT, 13058c2ecf20Sopenharmony_ci}; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_sleep_wakeup_modes[] = { 13088c2ecf20Sopenharmony_ci PIN_SLPM_WAKEUP_DISABLE, 13098c2ecf20Sopenharmony_ci PIN_SLPM_WAKEUP_ENABLE, 13108c2ecf20Sopenharmony_ci}; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_gpio_modes[] = { 13138c2ecf20Sopenharmony_ci PIN_GPIOMODE_DISABLED, 13148c2ecf20Sopenharmony_ci PIN_GPIOMODE_ENABLED, 13158c2ecf20Sopenharmony_ci}; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic const unsigned long nmk_pin_sleep_pdis_modes[] = { 13188c2ecf20Sopenharmony_ci PIN_SLPM_PDIS_DISABLED, 13198c2ecf20Sopenharmony_ci PIN_SLPM_PDIS_ENABLED, 13208c2ecf20Sopenharmony_ci}; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistruct nmk_cfg_param { 13238c2ecf20Sopenharmony_ci const char *property; 13248c2ecf20Sopenharmony_ci unsigned long config; 13258c2ecf20Sopenharmony_ci const unsigned long *choice; 13268c2ecf20Sopenharmony_ci int size; 13278c2ecf20Sopenharmony_ci}; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic const struct nmk_cfg_param nmk_cfg_params[] = { 13308c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,input", nmk_pin_input_modes), 13318c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,output", nmk_pin_output_modes), 13328c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep", nmk_pin_sleep_modes), 13338c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-input", nmk_pin_sleep_input_modes), 13348c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-output", nmk_pin_sleep_output_modes), 13358c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-wakeup", nmk_pin_sleep_wakeup_modes), 13368c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,gpio", nmk_pin_gpio_modes), 13378c2ecf20Sopenharmony_ci NMK_CONFIG_PIN_ARRAY("ste,sleep-pull-disable", nmk_pin_sleep_pdis_modes), 13388c2ecf20Sopenharmony_ci}; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int nmk_dt_pin_config(int index, int val, unsigned long *config) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci if (nmk_cfg_params[index].choice == NULL) 13438c2ecf20Sopenharmony_ci *config = nmk_cfg_params[index].config; 13448c2ecf20Sopenharmony_ci else { 13458c2ecf20Sopenharmony_ci /* test if out of range */ 13468c2ecf20Sopenharmony_ci if (val < nmk_cfg_params[index].size) { 13478c2ecf20Sopenharmony_ci *config = nmk_cfg_params[index].config | 13488c2ecf20Sopenharmony_ci nmk_cfg_params[index].choice[val]; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci return 0; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_cistatic const char *nmk_find_pin_name(struct pinctrl_dev *pctldev, const char *pin_name) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci int i, pin_number; 13578c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1) 13608c2ecf20Sopenharmony_ci for (i = 0; i < npct->soc->npins; i++) 13618c2ecf20Sopenharmony_ci if (npct->soc->pins[i].number == pin_number) 13628c2ecf20Sopenharmony_ci return npct->soc->pins[i].name; 13638c2ecf20Sopenharmony_ci return NULL; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic bool nmk_pinctrl_dt_get_config(struct device_node *np, 13678c2ecf20Sopenharmony_ci unsigned long *configs) 13688c2ecf20Sopenharmony_ci{ 13698c2ecf20Sopenharmony_ci bool has_config = 0; 13708c2ecf20Sopenharmony_ci unsigned long cfg = 0; 13718c2ecf20Sopenharmony_ci int i, val, ret; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(nmk_cfg_params); i++) { 13748c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, 13758c2ecf20Sopenharmony_ci nmk_cfg_params[i].property, &val); 13768c2ecf20Sopenharmony_ci if (ret != -EINVAL) { 13778c2ecf20Sopenharmony_ci if (nmk_dt_pin_config(i, val, &cfg) == 0) { 13788c2ecf20Sopenharmony_ci *configs |= cfg; 13798c2ecf20Sopenharmony_ci has_config = 1; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci return has_config; 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 13888c2ecf20Sopenharmony_ci struct device_node *np, 13898c2ecf20Sopenharmony_ci struct pinctrl_map **map, 13908c2ecf20Sopenharmony_ci unsigned *reserved_maps, 13918c2ecf20Sopenharmony_ci unsigned *num_maps) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci int ret; 13948c2ecf20Sopenharmony_ci const char *function = NULL; 13958c2ecf20Sopenharmony_ci unsigned long configs = 0; 13968c2ecf20Sopenharmony_ci bool has_config = 0; 13978c2ecf20Sopenharmony_ci struct property *prop; 13988c2ecf20Sopenharmony_ci struct device_node *np_config; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "function", &function); 14018c2ecf20Sopenharmony_ci if (ret >= 0) { 14028c2ecf20Sopenharmony_ci const char *group; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci ret = of_property_count_strings(np, "groups"); 14058c2ecf20Sopenharmony_ci if (ret < 0) 14068c2ecf20Sopenharmony_ci goto exit; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, 14098c2ecf20Sopenharmony_ci reserved_maps, 14108c2ecf20Sopenharmony_ci num_maps, ret); 14118c2ecf20Sopenharmony_ci if (ret < 0) 14128c2ecf20Sopenharmony_ci goto exit; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci of_property_for_each_string(np, "groups", prop, group) { 14158c2ecf20Sopenharmony_ci ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps, 14168c2ecf20Sopenharmony_ci group, function); 14178c2ecf20Sopenharmony_ci if (ret < 0) 14188c2ecf20Sopenharmony_ci goto exit; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci has_config = nmk_pinctrl_dt_get_config(np, &configs); 14238c2ecf20Sopenharmony_ci np_config = of_parse_phandle(np, "ste,config", 0); 14248c2ecf20Sopenharmony_ci if (np_config) { 14258c2ecf20Sopenharmony_ci has_config |= nmk_pinctrl_dt_get_config(np_config, &configs); 14268c2ecf20Sopenharmony_ci of_node_put(np_config); 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci if (has_config) { 14298c2ecf20Sopenharmony_ci const char *gpio_name; 14308c2ecf20Sopenharmony_ci const char *pin; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci ret = of_property_count_strings(np, "pins"); 14338c2ecf20Sopenharmony_ci if (ret < 0) 14348c2ecf20Sopenharmony_ci goto exit; 14358c2ecf20Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, 14368c2ecf20Sopenharmony_ci reserved_maps, 14378c2ecf20Sopenharmony_ci num_maps, ret); 14388c2ecf20Sopenharmony_ci if (ret < 0) 14398c2ecf20Sopenharmony_ci goto exit; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci of_property_for_each_string(np, "pins", prop, pin) { 14428c2ecf20Sopenharmony_ci gpio_name = nmk_find_pin_name(pctldev, pin); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci ret = nmk_dt_add_map_configs(map, reserved_maps, 14458c2ecf20Sopenharmony_ci num_maps, 14468c2ecf20Sopenharmony_ci gpio_name, &configs, 1); 14478c2ecf20Sopenharmony_ci if (ret < 0) 14488c2ecf20Sopenharmony_ci goto exit; 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ciexit: 14538c2ecf20Sopenharmony_ci return ret; 14548c2ecf20Sopenharmony_ci} 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cistatic int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 14578c2ecf20Sopenharmony_ci struct device_node *np_config, 14588c2ecf20Sopenharmony_ci struct pinctrl_map **map, unsigned *num_maps) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci unsigned reserved_maps; 14618c2ecf20Sopenharmony_ci struct device_node *np; 14628c2ecf20Sopenharmony_ci int ret; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci reserved_maps = 0; 14658c2ecf20Sopenharmony_ci *map = NULL; 14668c2ecf20Sopenharmony_ci *num_maps = 0; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci for_each_child_of_node(np_config, np) { 14698c2ecf20Sopenharmony_ci ret = nmk_pinctrl_dt_subnode_to_map(pctldev, np, map, 14708c2ecf20Sopenharmony_ci &reserved_maps, num_maps); 14718c2ecf20Sopenharmony_ci if (ret < 0) { 14728c2ecf20Sopenharmony_ci pinctrl_utils_free_map(pctldev, *map, *num_maps); 14738c2ecf20Sopenharmony_ci of_node_put(np); 14748c2ecf20Sopenharmony_ci return ret; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci return 0; 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_cistatic const struct pinctrl_ops nmk_pinctrl_ops = { 14828c2ecf20Sopenharmony_ci .get_groups_count = nmk_get_groups_cnt, 14838c2ecf20Sopenharmony_ci .get_group_name = nmk_get_group_name, 14848c2ecf20Sopenharmony_ci .get_group_pins = nmk_get_group_pins, 14858c2ecf20Sopenharmony_ci .pin_dbg_show = nmk_pin_dbg_show, 14868c2ecf20Sopenharmony_ci .dt_node_to_map = nmk_pinctrl_dt_node_to_map, 14878c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 14888c2ecf20Sopenharmony_ci}; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci return npct->soc->nfunctions; 14958c2ecf20Sopenharmony_ci} 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_cistatic const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev, 14988c2ecf20Sopenharmony_ci unsigned function) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci return npct->soc->functions[function].name; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 15068c2ecf20Sopenharmony_ci unsigned function, 15078c2ecf20Sopenharmony_ci const char * const **groups, 15088c2ecf20Sopenharmony_ci unsigned * const num_groups) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci *groups = npct->soc->functions[function].groups; 15138c2ecf20Sopenharmony_ci *num_groups = npct->soc->functions[function].ngroups; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci return 0; 15168c2ecf20Sopenharmony_ci} 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_cistatic int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, 15198c2ecf20Sopenharmony_ci unsigned group) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 15228c2ecf20Sopenharmony_ci const struct nmk_pingroup *g; 15238c2ecf20Sopenharmony_ci static unsigned int slpm[NUM_BANKS]; 15248c2ecf20Sopenharmony_ci unsigned long flags = 0; 15258c2ecf20Sopenharmony_ci bool glitch; 15268c2ecf20Sopenharmony_ci int ret = -EINVAL; 15278c2ecf20Sopenharmony_ci int i; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci g = &npct->soc->groups[group]; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (g->altsetting < 0) 15328c2ecf20Sopenharmony_ci return -EINVAL; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* 15378c2ecf20Sopenharmony_ci * If we're setting altfunc C by setting both AFSLA and AFSLB to 1, 15388c2ecf20Sopenharmony_ci * we may pass through an undesired state. In this case we take 15398c2ecf20Sopenharmony_ci * some extra care. 15408c2ecf20Sopenharmony_ci * 15418c2ecf20Sopenharmony_ci * Safe sequence used to switch IOs between GPIO and Alternate-C mode: 15428c2ecf20Sopenharmony_ci * - Save SLPM registers (since we have a shadow register in the 15438c2ecf20Sopenharmony_ci * nmk_chip we're using that as backup) 15448c2ecf20Sopenharmony_ci * - Set SLPM=0 for the IOs you want to switch and others to 1 15458c2ecf20Sopenharmony_ci * - Configure the GPIO registers for the IOs that are being switched 15468c2ecf20Sopenharmony_ci * - Set IOFORCE=1 15478c2ecf20Sopenharmony_ci * - Modify the AFLSA/B registers for the IOs that are being switched 15488c2ecf20Sopenharmony_ci * - Set IOFORCE=0 15498c2ecf20Sopenharmony_ci * - Restore SLPM registers 15508c2ecf20Sopenharmony_ci * - Any spurious wake up event during switch sequence to be ignored 15518c2ecf20Sopenharmony_ci * and cleared 15528c2ecf20Sopenharmony_ci * 15538c2ecf20Sopenharmony_ci * We REALLY need to save ALL slpm registers, because the external 15548c2ecf20Sopenharmony_ci * IOFORCE will switch *all* ports to their sleepmode setting to as 15558c2ecf20Sopenharmony_ci * to avoid glitches. (Not just one port!) 15568c2ecf20Sopenharmony_ci */ 15578c2ecf20Sopenharmony_ci glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (glitch) { 15608c2ecf20Sopenharmony_ci spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* Initially don't put any pins to sleep when switching */ 15638c2ecf20Sopenharmony_ci memset(slpm, 0xff, sizeof(slpm)); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* 15668c2ecf20Sopenharmony_ci * Then mask the pins that need to be sleeping now when we're 15678c2ecf20Sopenharmony_ci * switching to the ALT C function. 15688c2ecf20Sopenharmony_ci */ 15698c2ecf20Sopenharmony_ci for (i = 0; i < g->npins; i++) 15708c2ecf20Sopenharmony_ci slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]); 15718c2ecf20Sopenharmony_ci nmk_gpio_glitch_slpm_init(slpm); 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci for (i = 0; i < g->npins; i++) { 15758c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 15768c2ecf20Sopenharmony_ci unsigned bit; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci nmk_chip = find_nmk_gpio_from_pin(g->pins[i]); 15798c2ecf20Sopenharmony_ci if (!nmk_chip) { 15808c2ecf20Sopenharmony_ci dev_err(npct->dev, 15818c2ecf20Sopenharmony_ci "invalid pin offset %d in group %s at index %d\n", 15828c2ecf20Sopenharmony_ci g->pins[i], g->name, i); 15838c2ecf20Sopenharmony_ci goto out_glitch; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 15888c2ecf20Sopenharmony_ci bit = g->pins[i] % NMK_GPIO_PER_CHIP; 15898c2ecf20Sopenharmony_ci /* 15908c2ecf20Sopenharmony_ci * If the pin is switching to altfunc, and there was an 15918c2ecf20Sopenharmony_ci * interrupt installed on it which has been lazy disabled, 15928c2ecf20Sopenharmony_ci * actually mask the interrupt to prevent spurious interrupts 15938c2ecf20Sopenharmony_ci * that would occur while the pin is under control of the 15948c2ecf20Sopenharmony_ci * peripheral. Only SKE does this. 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci nmk_gpio_disable_lazy_irq(nmk_chip, bit); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci __nmk_gpio_set_mode_safe(nmk_chip, bit, 15998c2ecf20Sopenharmony_ci (g->altsetting & NMK_GPIO_ALT_C), glitch); 16008c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci /* 16038c2ecf20Sopenharmony_ci * Call PRCM GPIOCR config function in case ALTC 16048c2ecf20Sopenharmony_ci * has been selected: 16058c2ecf20Sopenharmony_ci * - If selection is a ALTCx, some bits in PRCM GPIOCR registers 16068c2ecf20Sopenharmony_ci * must be set. 16078c2ecf20Sopenharmony_ci * - If selection is pure ALTC and previous selection was ALTCx, 16088c2ecf20Sopenharmony_ci * then some bits in PRCM GPIOCR registers must be cleared. 16098c2ecf20Sopenharmony_ci */ 16108c2ecf20Sopenharmony_ci if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) 16118c2ecf20Sopenharmony_ci nmk_prcm_altcx_set_mode(npct, g->pins[i], 16128c2ecf20Sopenharmony_ci g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci /* When all pins are successfully reconfigured we get here */ 16168c2ecf20Sopenharmony_ci ret = 0; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ciout_glitch: 16198c2ecf20Sopenharmony_ci if (glitch) { 16208c2ecf20Sopenharmony_ci nmk_gpio_glitch_slpm_restore(slpm); 16218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return ret; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_cistatic int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, 16288c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 16298c2ecf20Sopenharmony_ci unsigned offset) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 16328c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 16338c2ecf20Sopenharmony_ci struct gpio_chip *chip; 16348c2ecf20Sopenharmony_ci unsigned bit; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (!range) { 16378c2ecf20Sopenharmony_ci dev_err(npct->dev, "invalid range\n"); 16388c2ecf20Sopenharmony_ci return -EINVAL; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci if (!range->gc) { 16418c2ecf20Sopenharmony_ci dev_err(npct->dev, "missing GPIO chip in range\n"); 16428c2ecf20Sopenharmony_ci return -EINVAL; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci chip = range->gc; 16458c2ecf20Sopenharmony_ci nmk_chip = gpiochip_get_data(chip); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 16508c2ecf20Sopenharmony_ci bit = offset % NMK_GPIO_PER_CHIP; 16518c2ecf20Sopenharmony_ci /* There is no glitch when converting any pin to GPIO */ 16528c2ecf20Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); 16538c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci return 0; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, 16598c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 16608c2ecf20Sopenharmony_ci unsigned offset) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); 16658c2ecf20Sopenharmony_ci /* Set the pin to some default state, GPIO is usually default */ 16668c2ecf20Sopenharmony_ci} 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_cistatic const struct pinmux_ops nmk_pinmux_ops = { 16698c2ecf20Sopenharmony_ci .get_functions_count = nmk_pmx_get_funcs_cnt, 16708c2ecf20Sopenharmony_ci .get_function_name = nmk_pmx_get_func_name, 16718c2ecf20Sopenharmony_ci .get_function_groups = nmk_pmx_get_func_groups, 16728c2ecf20Sopenharmony_ci .set_mux = nmk_pmx_set, 16738c2ecf20Sopenharmony_ci .gpio_request_enable = nmk_gpio_request_enable, 16748c2ecf20Sopenharmony_ci .gpio_disable_free = nmk_gpio_disable_free, 16758c2ecf20Sopenharmony_ci .strict = true, 16768c2ecf20Sopenharmony_ci}; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_cistatic int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, 16798c2ecf20Sopenharmony_ci unsigned long *config) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci /* Not implemented */ 16828c2ecf20Sopenharmony_ci return -EINVAL; 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_cistatic int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, 16868c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci static const char *pullnames[] = { 16898c2ecf20Sopenharmony_ci [NMK_GPIO_PULL_NONE] = "none", 16908c2ecf20Sopenharmony_ci [NMK_GPIO_PULL_UP] = "up", 16918c2ecf20Sopenharmony_ci [NMK_GPIO_PULL_DOWN] = "down", 16928c2ecf20Sopenharmony_ci [3] /* illegal */ = "??" 16938c2ecf20Sopenharmony_ci }; 16948c2ecf20Sopenharmony_ci static const char *slpmnames[] = { 16958c2ecf20Sopenharmony_ci [NMK_GPIO_SLPM_INPUT] = "input/wakeup", 16968c2ecf20Sopenharmony_ci [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", 16978c2ecf20Sopenharmony_ci }; 16988c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); 16998c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 17008c2ecf20Sopenharmony_ci unsigned bit; 17018c2ecf20Sopenharmony_ci pin_cfg_t cfg; 17028c2ecf20Sopenharmony_ci int pull, slpm, output, val, i; 17038c2ecf20Sopenharmony_ci bool lowemi, gpiomode, sleep; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci nmk_chip = find_nmk_gpio_from_pin(pin); 17068c2ecf20Sopenharmony_ci if (!nmk_chip) { 17078c2ecf20Sopenharmony_ci dev_err(npct->dev, 17088c2ecf20Sopenharmony_ci "invalid pin offset %d\n", pin); 17098c2ecf20Sopenharmony_ci return -EINVAL; 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 17138c2ecf20Sopenharmony_ci /* 17148c2ecf20Sopenharmony_ci * The pin config contains pin number and altfunction fields, 17158c2ecf20Sopenharmony_ci * here we just ignore that part. It's being handled by the 17168c2ecf20Sopenharmony_ci * framework and pinmux callback respectively. 17178c2ecf20Sopenharmony_ci */ 17188c2ecf20Sopenharmony_ci cfg = (pin_cfg_t) configs[i]; 17198c2ecf20Sopenharmony_ci pull = PIN_PULL(cfg); 17208c2ecf20Sopenharmony_ci slpm = PIN_SLPM(cfg); 17218c2ecf20Sopenharmony_ci output = PIN_DIR(cfg); 17228c2ecf20Sopenharmony_ci val = PIN_VAL(cfg); 17238c2ecf20Sopenharmony_ci lowemi = PIN_LOWEMI(cfg); 17248c2ecf20Sopenharmony_ci gpiomode = PIN_GPIOMODE(cfg); 17258c2ecf20Sopenharmony_ci sleep = PIN_SLEEPMODE(cfg); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (sleep) { 17288c2ecf20Sopenharmony_ci int slpm_pull = PIN_SLPM_PULL(cfg); 17298c2ecf20Sopenharmony_ci int slpm_output = PIN_SLPM_DIR(cfg); 17308c2ecf20Sopenharmony_ci int slpm_val = PIN_SLPM_VAL(cfg); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* All pins go into GPIO mode at sleep */ 17338c2ecf20Sopenharmony_ci gpiomode = true; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci /* 17368c2ecf20Sopenharmony_ci * The SLPM_* values are normal values + 1 to allow zero 17378c2ecf20Sopenharmony_ci * to mean "same as normal". 17388c2ecf20Sopenharmony_ci */ 17398c2ecf20Sopenharmony_ci if (slpm_pull) 17408c2ecf20Sopenharmony_ci pull = slpm_pull - 1; 17418c2ecf20Sopenharmony_ci if (slpm_output) 17428c2ecf20Sopenharmony_ci output = slpm_output - 1; 17438c2ecf20Sopenharmony_ci if (slpm_val) 17448c2ecf20Sopenharmony_ci val = slpm_val - 1; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, 17478c2ecf20Sopenharmony_ci "pin %d: sleep pull %s, dir %s, val %s\n", 17488c2ecf20Sopenharmony_ci pin, 17498c2ecf20Sopenharmony_ci slpm_pull ? pullnames[pull] : "same", 17508c2ecf20Sopenharmony_ci slpm_output ? (output ? "output" : "input") 17518c2ecf20Sopenharmony_ci : "same", 17528c2ecf20Sopenharmony_ci slpm_val ? (val ? "high" : "low") : "same"); 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci dev_dbg(nmk_chip->chip.parent, 17568c2ecf20Sopenharmony_ci "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", 17578c2ecf20Sopenharmony_ci pin, cfg, pullnames[pull], slpmnames[slpm], 17588c2ecf20Sopenharmony_ci output ? "output " : "input", 17598c2ecf20Sopenharmony_ci output ? (val ? "high" : "low") : "", 17608c2ecf20Sopenharmony_ci lowemi ? "on" : "off"); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci clk_enable(nmk_chip->clk); 17638c2ecf20Sopenharmony_ci bit = pin % NMK_GPIO_PER_CHIP; 17648c2ecf20Sopenharmony_ci if (gpiomode) 17658c2ecf20Sopenharmony_ci /* No glitch when going to GPIO mode */ 17668c2ecf20Sopenharmony_ci __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); 17678c2ecf20Sopenharmony_ci if (output) 17688c2ecf20Sopenharmony_ci __nmk_gpio_make_output(nmk_chip, bit, val); 17698c2ecf20Sopenharmony_ci else { 17708c2ecf20Sopenharmony_ci __nmk_gpio_make_input(nmk_chip, bit); 17718c2ecf20Sopenharmony_ci __nmk_gpio_set_pull(nmk_chip, bit, pull); 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci /* TODO: isn't this only applicable on output pins? */ 17748c2ecf20Sopenharmony_ci __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci __nmk_gpio_set_slpm(nmk_chip, bit, slpm); 17778c2ecf20Sopenharmony_ci clk_disable(nmk_chip->clk); 17788c2ecf20Sopenharmony_ci } /* for each config */ 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return 0; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic const struct pinconf_ops nmk_pinconf_ops = { 17848c2ecf20Sopenharmony_ci .pin_config_get = nmk_pin_config_get, 17858c2ecf20Sopenharmony_ci .pin_config_set = nmk_pin_config_set, 17868c2ecf20Sopenharmony_ci}; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic struct pinctrl_desc nmk_pinctrl_desc = { 17898c2ecf20Sopenharmony_ci .name = "pinctrl-nomadik", 17908c2ecf20Sopenharmony_ci .pctlops = &nmk_pinctrl_ops, 17918c2ecf20Sopenharmony_ci .pmxops = &nmk_pinmux_ops, 17928c2ecf20Sopenharmony_ci .confops = &nmk_pinconf_ops, 17938c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 17948c2ecf20Sopenharmony_ci}; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic const struct of_device_id nmk_pinctrl_match[] = { 17978c2ecf20Sopenharmony_ci { 17988c2ecf20Sopenharmony_ci .compatible = "stericsson,stn8815-pinctrl", 17998c2ecf20Sopenharmony_ci .data = (void *)PINCTRL_NMK_STN8815, 18008c2ecf20Sopenharmony_ci }, 18018c2ecf20Sopenharmony_ci { 18028c2ecf20Sopenharmony_ci .compatible = "stericsson,db8500-pinctrl", 18038c2ecf20Sopenharmony_ci .data = (void *)PINCTRL_NMK_DB8500, 18048c2ecf20Sopenharmony_ci }, 18058c2ecf20Sopenharmony_ci { 18068c2ecf20Sopenharmony_ci .compatible = "stericsson,db8540-pinctrl", 18078c2ecf20Sopenharmony_ci .data = (void *)PINCTRL_NMK_DB8540, 18088c2ecf20Sopenharmony_ci }, 18098c2ecf20Sopenharmony_ci {}, 18108c2ecf20Sopenharmony_ci}; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 18138c2ecf20Sopenharmony_cistatic int nmk_pinctrl_suspend(struct device *dev) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci npct = dev_get_drvdata(dev); 18188c2ecf20Sopenharmony_ci if (!npct) 18198c2ecf20Sopenharmony_ci return -EINVAL; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci return pinctrl_force_sleep(npct->pctl); 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic int nmk_pinctrl_resume(struct device *dev) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci npct = dev_get_drvdata(dev); 18298c2ecf20Sopenharmony_ci if (!npct) 18308c2ecf20Sopenharmony_ci return -EINVAL; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci return pinctrl_force_default(npct->pctl); 18338c2ecf20Sopenharmony_ci} 18348c2ecf20Sopenharmony_ci#endif 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_cistatic int nmk_pinctrl_probe(struct platform_device *pdev) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci const struct of_device_id *match; 18398c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 18408c2ecf20Sopenharmony_ci struct device_node *prcm_np; 18418c2ecf20Sopenharmony_ci struct nmk_pinctrl *npct; 18428c2ecf20Sopenharmony_ci unsigned int version = 0; 18438c2ecf20Sopenharmony_ci int i; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); 18468c2ecf20Sopenharmony_ci if (!npct) 18478c2ecf20Sopenharmony_ci return -ENOMEM; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci match = of_match_device(nmk_pinctrl_match, &pdev->dev); 18508c2ecf20Sopenharmony_ci if (!match) 18518c2ecf20Sopenharmony_ci return -ENODEV; 18528c2ecf20Sopenharmony_ci version = (unsigned int) match->data; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* Poke in other ASIC variants here */ 18558c2ecf20Sopenharmony_ci if (version == PINCTRL_NMK_STN8815) 18568c2ecf20Sopenharmony_ci nmk_pinctrl_stn8815_init(&npct->soc); 18578c2ecf20Sopenharmony_ci if (version == PINCTRL_NMK_DB8500) 18588c2ecf20Sopenharmony_ci nmk_pinctrl_db8500_init(&npct->soc); 18598c2ecf20Sopenharmony_ci if (version == PINCTRL_NMK_DB8540) 18608c2ecf20Sopenharmony_ci nmk_pinctrl_db8540_init(&npct->soc); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci /* 18638c2ecf20Sopenharmony_ci * Since we depend on the GPIO chips to provide clock and register base 18648c2ecf20Sopenharmony_ci * for the pin control operations, make sure that we have these 18658c2ecf20Sopenharmony_ci * populated before we continue. Follow the phandles to instantiate 18668c2ecf20Sopenharmony_ci * them. The GPIO portion of the actual hardware may be probed before 18678c2ecf20Sopenharmony_ci * or after this point: it shouldn't matter as the APIs are orthogonal. 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_ci for (i = 0; i < NMK_MAX_BANKS; i++) { 18708c2ecf20Sopenharmony_ci struct device_node *gpio_np; 18718c2ecf20Sopenharmony_ci struct nmk_gpio_chip *nmk_chip; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); 18748c2ecf20Sopenharmony_ci if (gpio_np) { 18758c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 18768c2ecf20Sopenharmony_ci "populate NMK GPIO %d \"%pOFn\"\n", 18778c2ecf20Sopenharmony_ci i, gpio_np); 18788c2ecf20Sopenharmony_ci nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); 18798c2ecf20Sopenharmony_ci if (IS_ERR(nmk_chip)) 18808c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 18818c2ecf20Sopenharmony_ci "could not populate nmk chip struct " 18828c2ecf20Sopenharmony_ci "- continue anyway\n"); 18838c2ecf20Sopenharmony_ci of_node_put(gpio_np); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci prcm_np = of_parse_phandle(np, "prcm", 0); 18888c2ecf20Sopenharmony_ci if (prcm_np) { 18898c2ecf20Sopenharmony_ci npct->prcm_base = of_iomap(prcm_np, 0); 18908c2ecf20Sopenharmony_ci of_node_put(prcm_np); 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci if (!npct->prcm_base) { 18938c2ecf20Sopenharmony_ci if (version == PINCTRL_NMK_STN8815) { 18948c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 18958c2ecf20Sopenharmony_ci "No PRCM base, " 18968c2ecf20Sopenharmony_ci "assuming no ALT-Cx control is available\n"); 18978c2ecf20Sopenharmony_ci } else { 18988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing PRCM base address\n"); 18998c2ecf20Sopenharmony_ci return -EINVAL; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci nmk_pinctrl_desc.pins = npct->soc->pins; 19048c2ecf20Sopenharmony_ci nmk_pinctrl_desc.npins = npct->soc->npins; 19058c2ecf20Sopenharmony_ci npct->dev = &pdev->dev; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci npct->pctl = devm_pinctrl_register(&pdev->dev, &nmk_pinctrl_desc, npct); 19088c2ecf20Sopenharmony_ci if (IS_ERR(npct->pctl)) { 19098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); 19108c2ecf20Sopenharmony_ci return PTR_ERR(npct->pctl); 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, npct); 19148c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci return 0; 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic const struct of_device_id nmk_gpio_match[] = { 19208c2ecf20Sopenharmony_ci { .compatible = "st,nomadik-gpio", }, 19218c2ecf20Sopenharmony_ci {} 19228c2ecf20Sopenharmony_ci}; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic struct platform_driver nmk_gpio_driver = { 19258c2ecf20Sopenharmony_ci .driver = { 19268c2ecf20Sopenharmony_ci .name = "gpio", 19278c2ecf20Sopenharmony_ci .of_match_table = nmk_gpio_match, 19288c2ecf20Sopenharmony_ci }, 19298c2ecf20Sopenharmony_ci .probe = nmk_gpio_probe, 19308c2ecf20Sopenharmony_ci}; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(nmk_pinctrl_pm_ops, 19338c2ecf20Sopenharmony_ci nmk_pinctrl_suspend, 19348c2ecf20Sopenharmony_ci nmk_pinctrl_resume); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic struct platform_driver nmk_pinctrl_driver = { 19378c2ecf20Sopenharmony_ci .driver = { 19388c2ecf20Sopenharmony_ci .name = "pinctrl-nomadik", 19398c2ecf20Sopenharmony_ci .of_match_table = nmk_pinctrl_match, 19408c2ecf20Sopenharmony_ci .pm = &nmk_pinctrl_pm_ops, 19418c2ecf20Sopenharmony_ci }, 19428c2ecf20Sopenharmony_ci .probe = nmk_pinctrl_probe, 19438c2ecf20Sopenharmony_ci}; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_cistatic int __init nmk_gpio_init(void) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci return platform_driver_register(&nmk_gpio_driver); 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_cisubsys_initcall(nmk_gpio_init); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic int __init nmk_pinctrl_init(void) 19528c2ecf20Sopenharmony_ci{ 19538c2ecf20Sopenharmony_ci return platform_driver_register(&nmk_pinctrl_driver); 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_cicore_initcall(nmk_pinctrl_init); 1956