162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Pinctrl / GPIO driver for StarFive JH7100 SoC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Shanghai StarFive Technology Co., Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bits.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/reset.h> 1862306a36Sopenharmony_ci#include <linux/seq_file.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 2262306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2362306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2462306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <dt-bindings/pinctrl/pinctrl-starfive-jh7100.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "../core.h" 2962306a36Sopenharmony_ci#include "../pinctrl-utils.h" 3062306a36Sopenharmony_ci#include "../pinmux.h" 3162306a36Sopenharmony_ci#include "../pinconf.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define DRIVER_NAME "pinctrl-starfive" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Refer to Section 12. GPIO Registers in the JH7100 data sheet: 3762306a36Sopenharmony_ci * https://github.com/starfive-tech/JH7100_Docs 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#define NR_GPIOS 64 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Global enable for GPIO interrupts. If bit 0 is set to 1 the GPIO interrupts 4362306a36Sopenharmony_ci * are enabled. If set to 0 the GPIO interrupts are disabled. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci#define GPIOEN 0x000 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * The following 32-bit registers come in pairs, but only the offset of the 4962306a36Sopenharmony_ci * first register is defined. The first controls (interrupts for) GPIO 0-31 and 5062306a36Sopenharmony_ci * the second GPIO 32-63. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Interrupt Type. If set to 1 the interrupt is edge-triggered. If set to 0 the 5562306a36Sopenharmony_ci * interrupt is level-triggered. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define GPIOIS 0x010 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci * Edge-Trigger Interrupt Type. If set to 1 the interrupt gets triggered on 6162306a36Sopenharmony_ci * both positive and negative edges. If set to 0 the interrupt is triggered by a 6262306a36Sopenharmony_ci * single edge. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci#define GPIOIBE 0x018 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * Interrupt Trigger Polarity. If set to 1 the interrupt is triggered on a 6862306a36Sopenharmony_ci * rising edge (edge-triggered) or high level (level-triggered). If set to 0 the 6962306a36Sopenharmony_ci * interrupt is triggered on a falling edge (edge-triggered) or low level 7062306a36Sopenharmony_ci * (level-triggered). 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci#define GPIOIEV 0x020 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * Interrupt Mask. If set to 1 the interrupt is enabled (unmasked). If set to 0 7662306a36Sopenharmony_ci * the interrupt is disabled (masked). Note that the current documentation is 7762306a36Sopenharmony_ci * wrong and says the exct opposite of this. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci#define GPIOIE 0x028 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * Clear Edge-Triggered Interrupts. Write a 1 to clear the edge-triggered 8362306a36Sopenharmony_ci * interrupt. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci#define GPIOIC 0x030 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * Edge-Triggered Interrupt Status. A 1 means the configured edge was detected. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define GPIORIS 0x038 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Interrupt Status after Masking. A 1 means the configured edge or level was 9462306a36Sopenharmony_ci * detected and not masked. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci#define GPIOMIS 0x040 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * Data Value. Dynamically reflects the value of the GPIO pin. If 1 the pin is 10062306a36Sopenharmony_ci * a digital 1 and if 0 the pin is a digital 0. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci#define GPIODIN 0x048 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * From the data sheet section 12.2, there are 64 32-bit output data registers 10662306a36Sopenharmony_ci * and 64 output enable registers. Output data and output enable registers for 10762306a36Sopenharmony_ci * a given GPIO are contiguous. Eg. GPO0_DOUT_CFG is 0x50 and GPO0_DOEN_CFG is 10862306a36Sopenharmony_ci * 0x54 while GPO1_DOUT_CFG is 0x58 and GPO1_DOEN_CFG is 0x5c. The stride 10962306a36Sopenharmony_ci * between GPIO registers is effectively 8, thus: GPOn_DOUT_CFG is 0x50 + 8n 11062306a36Sopenharmony_ci * and GPOn_DOEN_CFG is 0x54 + 8n. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define GPON_DOUT_CFG 0x050 11362306a36Sopenharmony_ci#define GPON_DOEN_CFG 0x054 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * From Section 12.3, there are 75 input signal configuration registers which 11762306a36Sopenharmony_ci * are 4 bytes wide starting with GPI_CPU_JTAG_TCK_CFG at 0x250 and ending with 11862306a36Sopenharmony_ci * GPI_USB_OVER_CURRENT_CFG 0x378 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci#define GPI_CFG_OFFSET 0x250 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Pad Control Bits. There are 16 pad control bits for each pin located in 103 12462306a36Sopenharmony_ci * 32-bit registers controlling PAD_GPIO[0] to PAD_GPIO[63] followed by 12562306a36Sopenharmony_ci * PAD_FUNC_SHARE[0] to PAD_FUNC_SHARE[141]. Odd numbered pins use the upper 16 12662306a36Sopenharmony_ci * bit of each register. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci#define PAD_SLEW_RATE_MASK GENMASK(11, 9) 12962306a36Sopenharmony_ci#define PAD_SLEW_RATE_POS 9 13062306a36Sopenharmony_ci#define PAD_BIAS_STRONG_PULL_UP BIT(8) 13162306a36Sopenharmony_ci#define PAD_INPUT_ENABLE BIT(7) 13262306a36Sopenharmony_ci#define PAD_INPUT_SCHMITT_ENABLE BIT(6) 13362306a36Sopenharmony_ci#define PAD_BIAS_DISABLE BIT(5) 13462306a36Sopenharmony_ci#define PAD_BIAS_PULL_DOWN BIT(4) 13562306a36Sopenharmony_ci#define PAD_BIAS_MASK \ 13662306a36Sopenharmony_ci (PAD_BIAS_STRONG_PULL_UP | \ 13762306a36Sopenharmony_ci PAD_BIAS_DISABLE | \ 13862306a36Sopenharmony_ci PAD_BIAS_PULL_DOWN) 13962306a36Sopenharmony_ci#define PAD_DRIVE_STRENGTH_MASK GENMASK(3, 0) 14062306a36Sopenharmony_ci#define PAD_DRIVE_STRENGTH_POS 0 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * From Section 11, the IO_PADSHARE_SEL register can be programmed to select 14462306a36Sopenharmony_ci * one of seven pre-defined multiplexed signal groups on PAD_FUNC_SHARE and 14562306a36Sopenharmony_ci * PAD_GPIO pads. This is a global setting. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci#define IO_PADSHARE_SEL 0x1a0 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* 15062306a36Sopenharmony_ci * This just needs to be some number such that when 15162306a36Sopenharmony_ci * sfp->gpio.pin_base = PAD_INVALID_GPIO then 15262306a36Sopenharmony_ci * starfive_pin_to_gpio(sfp, validpin) is never a valid GPIO number. 15362306a36Sopenharmony_ci * That is it should underflow and return something >= NR_GPIOS. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci#define PAD_INVALID_GPIO 0x10000 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * The packed pinmux values from the device tree look like this: 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * | 31 - 24 | 23 - 16 | 15 - 8 | 7 | 6 | 5 - 0 | 16162306a36Sopenharmony_ci * | dout | doen | din | dout rev | doen rev | gpio nr | 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * ..but the GPOn_DOUT_CFG and GPOn_DOEN_CFG registers look like this: 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * | 31 | 30 - 8 | 7 - 0 | 16662306a36Sopenharmony_ci * | dout/doen rev | unused | dout/doen | 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic unsigned int starfive_pinmux_to_gpio(u32 v) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return v & (NR_GPIOS - 1); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic u32 starfive_pinmux_to_dout(u32 v) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci return ((v & BIT(7)) << (31 - 7)) | ((v >> 24) & GENMASK(7, 0)); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic u32 starfive_pinmux_to_doen(u32 v) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci return ((v & BIT(6)) << (31 - 6)) | ((v >> 16) & GENMASK(7, 0)); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic u32 starfive_pinmux_to_din(u32 v) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci return (v >> 8) & GENMASK(7, 0); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * The maximum GPIO output current depends on the chosen drive strength: 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * DS: 0 1 2 3 4 5 6 7 19262306a36Sopenharmony_ci * mA: 14.2 21.2 28.2 35.2 42.2 49.1 56.0 62.8 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * After rounding that is 7*DS + 14 mA 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic u32 starfive_drive_strength_to_max_mA(u16 ds) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci return 7 * ds + 14; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic u16 starfive_drive_strength_from_max_mA(u32 i) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci return (clamp(i, 14U, 63U) - 14) / 7; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistruct starfive_pinctrl { 20762306a36Sopenharmony_ci struct gpio_chip gc; 20862306a36Sopenharmony_ci struct pinctrl_gpio_range gpios; 20962306a36Sopenharmony_ci raw_spinlock_t lock; 21062306a36Sopenharmony_ci void __iomem *base; 21162306a36Sopenharmony_ci void __iomem *padctl; 21262306a36Sopenharmony_ci struct pinctrl_dev *pctl; 21362306a36Sopenharmony_ci struct mutex mutex; /* serialize adding groups and functions */ 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic inline unsigned int starfive_pin_to_gpio(const struct starfive_pinctrl *sfp, 21762306a36Sopenharmony_ci unsigned int pin) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci return pin - sfp->gpios.pin_base; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic inline unsigned int starfive_gpio_to_pin(const struct starfive_pinctrl *sfp, 22362306a36Sopenharmony_ci unsigned int gpio) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return sfp->gpios.pin_base + gpio; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic struct starfive_pinctrl *starfive_from_irq_data(struct irq_data *d) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return container_of(gc, struct starfive_pinctrl, gc); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic struct starfive_pinctrl *starfive_from_irq_desc(struct irq_desc *desc) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return container_of(gc, struct starfive_pinctrl, gc); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const struct pinctrl_pin_desc starfive_pins[] = { 24362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(0), "GPIO[0]"), 24462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(1), "GPIO[1]"), 24562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(2), "GPIO[2]"), 24662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(3), "GPIO[3]"), 24762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(4), "GPIO[4]"), 24862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(5), "GPIO[5]"), 24962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(6), "GPIO[6]"), 25062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(7), "GPIO[7]"), 25162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(8), "GPIO[8]"), 25262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(9), "GPIO[9]"), 25362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(10), "GPIO[10]"), 25462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(11), "GPIO[11]"), 25562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(12), "GPIO[12]"), 25662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(13), "GPIO[13]"), 25762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(14), "GPIO[14]"), 25862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(15), "GPIO[15]"), 25962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(16), "GPIO[16]"), 26062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(17), "GPIO[17]"), 26162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(18), "GPIO[18]"), 26262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(19), "GPIO[19]"), 26362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(20), "GPIO[20]"), 26462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(21), "GPIO[21]"), 26562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(22), "GPIO[22]"), 26662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(23), "GPIO[23]"), 26762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(24), "GPIO[24]"), 26862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(25), "GPIO[25]"), 26962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(26), "GPIO[26]"), 27062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(27), "GPIO[27]"), 27162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(28), "GPIO[28]"), 27262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(29), "GPIO[29]"), 27362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(30), "GPIO[30]"), 27462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(31), "GPIO[31]"), 27562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(32), "GPIO[32]"), 27662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(33), "GPIO[33]"), 27762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(34), "GPIO[34]"), 27862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(35), "GPIO[35]"), 27962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(36), "GPIO[36]"), 28062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(37), "GPIO[37]"), 28162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(38), "GPIO[38]"), 28262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(39), "GPIO[39]"), 28362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(40), "GPIO[40]"), 28462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(41), "GPIO[41]"), 28562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(42), "GPIO[42]"), 28662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(43), "GPIO[43]"), 28762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(44), "GPIO[44]"), 28862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(45), "GPIO[45]"), 28962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(46), "GPIO[46]"), 29062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(47), "GPIO[47]"), 29162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(48), "GPIO[48]"), 29262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(49), "GPIO[49]"), 29362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(50), "GPIO[50]"), 29462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(51), "GPIO[51]"), 29562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(52), "GPIO[52]"), 29662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(53), "GPIO[53]"), 29762306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(54), "GPIO[54]"), 29862306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(55), "GPIO[55]"), 29962306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(56), "GPIO[56]"), 30062306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(57), "GPIO[57]"), 30162306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(58), "GPIO[58]"), 30262306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(59), "GPIO[59]"), 30362306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(60), "GPIO[60]"), 30462306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(61), "GPIO[61]"), 30562306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(62), "GPIO[62]"), 30662306a36Sopenharmony_ci PINCTRL_PIN(PAD_GPIO(63), "GPIO[63]"), 30762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(0), "FUNC_SHARE[0]"), 30862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(1), "FUNC_SHARE[1]"), 30962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(2), "FUNC_SHARE[2]"), 31062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(3), "FUNC_SHARE[3]"), 31162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(4), "FUNC_SHARE[4]"), 31262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(5), "FUNC_SHARE[5]"), 31362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(6), "FUNC_SHARE[6]"), 31462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(7), "FUNC_SHARE[7]"), 31562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(8), "FUNC_SHARE[8]"), 31662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(9), "FUNC_SHARE[9]"), 31762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(10), "FUNC_SHARE[10]"), 31862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(11), "FUNC_SHARE[11]"), 31962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(12), "FUNC_SHARE[12]"), 32062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(13), "FUNC_SHARE[13]"), 32162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(14), "FUNC_SHARE[14]"), 32262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(15), "FUNC_SHARE[15]"), 32362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(16), "FUNC_SHARE[16]"), 32462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(17), "FUNC_SHARE[17]"), 32562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(18), "FUNC_SHARE[18]"), 32662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(19), "FUNC_SHARE[19]"), 32762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(20), "FUNC_SHARE[20]"), 32862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(21), "FUNC_SHARE[21]"), 32962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(22), "FUNC_SHARE[22]"), 33062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(23), "FUNC_SHARE[23]"), 33162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(24), "FUNC_SHARE[24]"), 33262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(25), "FUNC_SHARE[25]"), 33362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(26), "FUNC_SHARE[26]"), 33462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(27), "FUNC_SHARE[27]"), 33562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(28), "FUNC_SHARE[28]"), 33662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(29), "FUNC_SHARE[29]"), 33762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(30), "FUNC_SHARE[30]"), 33862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(31), "FUNC_SHARE[31]"), 33962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(32), "FUNC_SHARE[32]"), 34062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(33), "FUNC_SHARE[33]"), 34162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(34), "FUNC_SHARE[34]"), 34262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(35), "FUNC_SHARE[35]"), 34362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(36), "FUNC_SHARE[36]"), 34462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(37), "FUNC_SHARE[37]"), 34562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(38), "FUNC_SHARE[38]"), 34662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(39), "FUNC_SHARE[39]"), 34762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(40), "FUNC_SHARE[40]"), 34862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(41), "FUNC_SHARE[41]"), 34962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(42), "FUNC_SHARE[42]"), 35062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(43), "FUNC_SHARE[43]"), 35162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(44), "FUNC_SHARE[44]"), 35262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(45), "FUNC_SHARE[45]"), 35362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(46), "FUNC_SHARE[46]"), 35462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(47), "FUNC_SHARE[47]"), 35562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(48), "FUNC_SHARE[48]"), 35662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(49), "FUNC_SHARE[49]"), 35762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(50), "FUNC_SHARE[50]"), 35862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(51), "FUNC_SHARE[51]"), 35962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(52), "FUNC_SHARE[52]"), 36062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(53), "FUNC_SHARE[53]"), 36162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(54), "FUNC_SHARE[54]"), 36262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(55), "FUNC_SHARE[55]"), 36362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(56), "FUNC_SHARE[56]"), 36462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(57), "FUNC_SHARE[57]"), 36562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(58), "FUNC_SHARE[58]"), 36662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(59), "FUNC_SHARE[59]"), 36762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(60), "FUNC_SHARE[60]"), 36862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(61), "FUNC_SHARE[61]"), 36962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(62), "FUNC_SHARE[62]"), 37062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(63), "FUNC_SHARE[63]"), 37162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(64), "FUNC_SHARE[64]"), 37262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(65), "FUNC_SHARE[65]"), 37362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(66), "FUNC_SHARE[66]"), 37462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(67), "FUNC_SHARE[67]"), 37562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(68), "FUNC_SHARE[68]"), 37662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(69), "FUNC_SHARE[69]"), 37762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(70), "FUNC_SHARE[70]"), 37862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(71), "FUNC_SHARE[71]"), 37962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(72), "FUNC_SHARE[72]"), 38062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(73), "FUNC_SHARE[73]"), 38162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(74), "FUNC_SHARE[74]"), 38262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(75), "FUNC_SHARE[75]"), 38362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(76), "FUNC_SHARE[76]"), 38462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(77), "FUNC_SHARE[77]"), 38562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(78), "FUNC_SHARE[78]"), 38662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(79), "FUNC_SHARE[79]"), 38762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(80), "FUNC_SHARE[80]"), 38862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(81), "FUNC_SHARE[81]"), 38962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(82), "FUNC_SHARE[82]"), 39062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(83), "FUNC_SHARE[83]"), 39162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(84), "FUNC_SHARE[84]"), 39262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(85), "FUNC_SHARE[85]"), 39362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(86), "FUNC_SHARE[86]"), 39462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(87), "FUNC_SHARE[87]"), 39562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(88), "FUNC_SHARE[88]"), 39662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(89), "FUNC_SHARE[89]"), 39762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(90), "FUNC_SHARE[90]"), 39862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(91), "FUNC_SHARE[91]"), 39962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(92), "FUNC_SHARE[92]"), 40062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(93), "FUNC_SHARE[93]"), 40162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(94), "FUNC_SHARE[94]"), 40262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(95), "FUNC_SHARE[95]"), 40362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(96), "FUNC_SHARE[96]"), 40462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(97), "FUNC_SHARE[97]"), 40562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(98), "FUNC_SHARE[98]"), 40662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(99), "FUNC_SHARE[99]"), 40762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(100), "FUNC_SHARE[100]"), 40862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(101), "FUNC_SHARE[101]"), 40962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(102), "FUNC_SHARE[102]"), 41062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(103), "FUNC_SHARE[103]"), 41162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(104), "FUNC_SHARE[104]"), 41262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(105), "FUNC_SHARE[105]"), 41362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(106), "FUNC_SHARE[106]"), 41462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(107), "FUNC_SHARE[107]"), 41562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(108), "FUNC_SHARE[108]"), 41662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(109), "FUNC_SHARE[109]"), 41762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(110), "FUNC_SHARE[110]"), 41862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(111), "FUNC_SHARE[111]"), 41962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(112), "FUNC_SHARE[112]"), 42062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(113), "FUNC_SHARE[113]"), 42162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(114), "FUNC_SHARE[114]"), 42262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(115), "FUNC_SHARE[115]"), 42362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(116), "FUNC_SHARE[116]"), 42462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(117), "FUNC_SHARE[117]"), 42562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(118), "FUNC_SHARE[118]"), 42662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(119), "FUNC_SHARE[119]"), 42762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(120), "FUNC_SHARE[120]"), 42862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(121), "FUNC_SHARE[121]"), 42962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(122), "FUNC_SHARE[122]"), 43062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(123), "FUNC_SHARE[123]"), 43162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(124), "FUNC_SHARE[124]"), 43262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(125), "FUNC_SHARE[125]"), 43362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(126), "FUNC_SHARE[126]"), 43462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(127), "FUNC_SHARE[127]"), 43562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(128), "FUNC_SHARE[128]"), 43662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(129), "FUNC_SHARE[129]"), 43762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(130), "FUNC_SHARE[130]"), 43862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(131), "FUNC_SHARE[131]"), 43962306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(132), "FUNC_SHARE[132]"), 44062306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(133), "FUNC_SHARE[133]"), 44162306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(134), "FUNC_SHARE[134]"), 44262306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(135), "FUNC_SHARE[135]"), 44362306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(136), "FUNC_SHARE[136]"), 44462306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(137), "FUNC_SHARE[137]"), 44562306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(138), "FUNC_SHARE[138]"), 44662306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(139), "FUNC_SHARE[139]"), 44762306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(140), "FUNC_SHARE[140]"), 44862306a36Sopenharmony_ci PINCTRL_PIN(PAD_FUNC_SHARE(141), "FUNC_SHARE[141]"), 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 45262306a36Sopenharmony_cistatic void starfive_pin_dbg_show(struct pinctrl_dev *pctldev, 45362306a36Sopenharmony_ci struct seq_file *s, 45462306a36Sopenharmony_ci unsigned int pin) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 45762306a36Sopenharmony_ci unsigned int gpio = starfive_pin_to_gpio(sfp, pin); 45862306a36Sopenharmony_ci void __iomem *reg; 45962306a36Sopenharmony_ci u32 dout, doen; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (gpio >= NR_GPIOS) 46262306a36Sopenharmony_ci return; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci reg = sfp->base + GPON_DOUT_CFG + 8 * gpio; 46562306a36Sopenharmony_ci dout = readl_relaxed(reg + 0x000); 46662306a36Sopenharmony_ci doen = readl_relaxed(reg + 0x004); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci seq_printf(s, "dout=%lu%s doen=%lu%s", 46962306a36Sopenharmony_ci dout & GENMASK(7, 0), (dout & BIT(31)) ? "r" : "", 47062306a36Sopenharmony_ci doen & GENMASK(7, 0), (doen & BIT(31)) ? "r" : ""); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci#else 47362306a36Sopenharmony_ci#define starfive_pin_dbg_show NULL 47462306a36Sopenharmony_ci#endif 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, 47762306a36Sopenharmony_ci struct device_node *np, 47862306a36Sopenharmony_ci struct pinctrl_map **maps, 47962306a36Sopenharmony_ci unsigned int *num_maps) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 48262306a36Sopenharmony_ci struct device *dev = sfp->gc.parent; 48362306a36Sopenharmony_ci struct device_node *child; 48462306a36Sopenharmony_ci struct pinctrl_map *map; 48562306a36Sopenharmony_ci const char **pgnames; 48662306a36Sopenharmony_ci const char *grpname; 48762306a36Sopenharmony_ci u32 *pinmux; 48862306a36Sopenharmony_ci int ngroups; 48962306a36Sopenharmony_ci int *pins; 49062306a36Sopenharmony_ci int nmaps; 49162306a36Sopenharmony_ci int ret; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci nmaps = 0; 49462306a36Sopenharmony_ci ngroups = 0; 49562306a36Sopenharmony_ci for_each_available_child_of_node(np, child) { 49662306a36Sopenharmony_ci int npinmux = of_property_count_u32_elems(child, "pinmux"); 49762306a36Sopenharmony_ci int npins = of_property_count_u32_elems(child, "pins"); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (npinmux > 0 && npins > 0) { 50062306a36Sopenharmony_ci dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: both pinmux and pins set\n", 50162306a36Sopenharmony_ci np, child); 50262306a36Sopenharmony_ci of_node_put(child); 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci if (npinmux == 0 && npins == 0) { 50662306a36Sopenharmony_ci dev_err(dev, "invalid pinctrl group %pOFn.%pOFn: neither pinmux nor pins set\n", 50762306a36Sopenharmony_ci np, child); 50862306a36Sopenharmony_ci of_node_put(child); 50962306a36Sopenharmony_ci return -EINVAL; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (npinmux > 0) 51362306a36Sopenharmony_ci nmaps += 2; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci nmaps += 1; 51662306a36Sopenharmony_ci ngroups += 1; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL); 52062306a36Sopenharmony_ci if (!pgnames) 52162306a36Sopenharmony_ci return -ENOMEM; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL); 52462306a36Sopenharmony_ci if (!map) 52562306a36Sopenharmony_ci return -ENOMEM; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci nmaps = 0; 52862306a36Sopenharmony_ci ngroups = 0; 52962306a36Sopenharmony_ci mutex_lock(&sfp->mutex); 53062306a36Sopenharmony_ci for_each_available_child_of_node(np, child) { 53162306a36Sopenharmony_ci int npins; 53262306a36Sopenharmony_ci int i; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", np, child); 53562306a36Sopenharmony_ci if (!grpname) { 53662306a36Sopenharmony_ci ret = -ENOMEM; 53762306a36Sopenharmony_ci goto put_child; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci pgnames[ngroups++] = grpname; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if ((npins = of_property_count_u32_elems(child, "pinmux")) > 0) { 54362306a36Sopenharmony_ci pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); 54462306a36Sopenharmony_ci if (!pins) { 54562306a36Sopenharmony_ci ret = -ENOMEM; 54662306a36Sopenharmony_ci goto put_child; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci pinmux = devm_kcalloc(dev, npins, sizeof(*pinmux), GFP_KERNEL); 55062306a36Sopenharmony_ci if (!pinmux) { 55162306a36Sopenharmony_ci ret = -ENOMEM; 55262306a36Sopenharmony_ci goto put_child; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci ret = of_property_read_u32_array(child, "pinmux", pinmux, npins); 55662306a36Sopenharmony_ci if (ret) 55762306a36Sopenharmony_ci goto put_child; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 56062306a36Sopenharmony_ci unsigned int gpio = starfive_pinmux_to_gpio(pinmux[i]); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci pins[i] = starfive_gpio_to_pin(sfp, gpio); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; 56662306a36Sopenharmony_ci map[nmaps].data.mux.function = np->name; 56762306a36Sopenharmony_ci map[nmaps].data.mux.group = grpname; 56862306a36Sopenharmony_ci nmaps += 1; 56962306a36Sopenharmony_ci } else if ((npins = of_property_count_u32_elems(child, "pins")) > 0) { 57062306a36Sopenharmony_ci pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); 57162306a36Sopenharmony_ci if (!pins) { 57262306a36Sopenharmony_ci ret = -ENOMEM; 57362306a36Sopenharmony_ci goto put_child; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci pinmux = NULL; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 57962306a36Sopenharmony_ci u32 v; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci ret = of_property_read_u32_index(child, "pins", i, &v); 58262306a36Sopenharmony_ci if (ret) 58362306a36Sopenharmony_ci goto put_child; 58462306a36Sopenharmony_ci pins[i] = v; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } else { 58762306a36Sopenharmony_ci ret = -EINVAL; 58862306a36Sopenharmony_ci goto put_child; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = pinctrl_generic_add_group(pctldev, grpname, pins, npins, pinmux); 59262306a36Sopenharmony_ci if (ret < 0) { 59362306a36Sopenharmony_ci dev_err(dev, "error adding group %s: %d\n", grpname, ret); 59462306a36Sopenharmony_ci goto put_child; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci ret = pinconf_generic_parse_dt_config(child, pctldev, 59862306a36Sopenharmony_ci &map[nmaps].data.configs.configs, 59962306a36Sopenharmony_ci &map[nmaps].data.configs.num_configs); 60062306a36Sopenharmony_ci if (ret) { 60162306a36Sopenharmony_ci dev_err(dev, "error parsing pin config of group %s: %d\n", 60262306a36Sopenharmony_ci grpname, ret); 60362306a36Sopenharmony_ci goto put_child; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* don't create a map if there are no pinconf settings */ 60762306a36Sopenharmony_ci if (map[nmaps].data.configs.num_configs == 0) 60862306a36Sopenharmony_ci continue; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; 61162306a36Sopenharmony_ci map[nmaps].data.configs.group_or_pin = grpname; 61262306a36Sopenharmony_ci nmaps += 1; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ret = pinmux_generic_add_function(pctldev, np->name, pgnames, ngroups, NULL); 61662306a36Sopenharmony_ci if (ret < 0) { 61762306a36Sopenharmony_ci dev_err(dev, "error adding function %s: %d\n", np->name, ret); 61862306a36Sopenharmony_ci goto free_map; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci *maps = map; 62262306a36Sopenharmony_ci *num_maps = nmaps; 62362306a36Sopenharmony_ci mutex_unlock(&sfp->mutex); 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ciput_child: 62762306a36Sopenharmony_ci of_node_put(child); 62862306a36Sopenharmony_cifree_map: 62962306a36Sopenharmony_ci pinctrl_utils_free_map(pctldev, map, nmaps); 63062306a36Sopenharmony_ci mutex_unlock(&sfp->mutex); 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic const struct pinctrl_ops starfive_pinctrl_ops = { 63562306a36Sopenharmony_ci .get_groups_count = pinctrl_generic_get_group_count, 63662306a36Sopenharmony_ci .get_group_name = pinctrl_generic_get_group_name, 63762306a36Sopenharmony_ci .get_group_pins = pinctrl_generic_get_group_pins, 63862306a36Sopenharmony_ci .pin_dbg_show = starfive_pin_dbg_show, 63962306a36Sopenharmony_ci .dt_node_to_map = starfive_dt_node_to_map, 64062306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 64162306a36Sopenharmony_ci}; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int starfive_set_mux(struct pinctrl_dev *pctldev, 64462306a36Sopenharmony_ci unsigned int fsel, unsigned int gsel) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 64762306a36Sopenharmony_ci struct device *dev = sfp->gc.parent; 64862306a36Sopenharmony_ci const struct group_desc *group; 64962306a36Sopenharmony_ci const u32 *pinmux; 65062306a36Sopenharmony_ci unsigned int i; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci group = pinctrl_generic_get_group(pctldev, gsel); 65362306a36Sopenharmony_ci if (!group) 65462306a36Sopenharmony_ci return -EINVAL; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci pinmux = group->data; 65762306a36Sopenharmony_ci for (i = 0; i < group->num_pins; i++) { 65862306a36Sopenharmony_ci u32 v = pinmux[i]; 65962306a36Sopenharmony_ci unsigned int gpio = starfive_pinmux_to_gpio(v); 66062306a36Sopenharmony_ci u32 dout = starfive_pinmux_to_dout(v); 66162306a36Sopenharmony_ci u32 doen = starfive_pinmux_to_doen(v); 66262306a36Sopenharmony_ci u32 din = starfive_pinmux_to_din(v); 66362306a36Sopenharmony_ci void __iomem *reg_dout; 66462306a36Sopenharmony_ci void __iomem *reg_doen; 66562306a36Sopenharmony_ci void __iomem *reg_din; 66662306a36Sopenharmony_ci unsigned long flags; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci dev_dbg(dev, "GPIO%u: dout=0x%x doen=0x%x din=0x%x\n", 66962306a36Sopenharmony_ci gpio, dout, doen, din); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci reg_dout = sfp->base + GPON_DOUT_CFG + 8 * gpio; 67262306a36Sopenharmony_ci reg_doen = sfp->base + GPON_DOEN_CFG + 8 * gpio; 67362306a36Sopenharmony_ci if (din != GPI_NONE) 67462306a36Sopenharmony_ci reg_din = sfp->base + GPI_CFG_OFFSET + 4 * din; 67562306a36Sopenharmony_ci else 67662306a36Sopenharmony_ci reg_din = NULL; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 67962306a36Sopenharmony_ci writel_relaxed(dout, reg_dout); 68062306a36Sopenharmony_ci writel_relaxed(doen, reg_doen); 68162306a36Sopenharmony_ci if (reg_din) 68262306a36Sopenharmony_ci writel_relaxed(gpio + 2, reg_din); 68362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic const struct pinmux_ops starfive_pinmux_ops = { 69062306a36Sopenharmony_ci .get_functions_count = pinmux_generic_get_function_count, 69162306a36Sopenharmony_ci .get_function_name = pinmux_generic_get_function_name, 69262306a36Sopenharmony_ci .get_function_groups = pinmux_generic_get_function_groups, 69362306a36Sopenharmony_ci .set_mux = starfive_set_mux, 69462306a36Sopenharmony_ci .strict = true, 69562306a36Sopenharmony_ci}; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic u16 starfive_padctl_get(struct starfive_pinctrl *sfp, 69862306a36Sopenharmony_ci unsigned int pin) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci void __iomem *reg = sfp->padctl + 4 * (pin / 2); 70162306a36Sopenharmony_ci int shift = 16 * (pin % 2); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return readl_relaxed(reg) >> shift; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void starfive_padctl_rmw(struct starfive_pinctrl *sfp, 70762306a36Sopenharmony_ci unsigned int pin, 70862306a36Sopenharmony_ci u16 _mask, u16 _value) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci void __iomem *reg = sfp->padctl + 4 * (pin / 2); 71162306a36Sopenharmony_ci int shift = 16 * (pin % 2); 71262306a36Sopenharmony_ci u32 mask = (u32)_mask << shift; 71362306a36Sopenharmony_ci u32 value = (u32)_value << shift; 71462306a36Sopenharmony_ci unsigned long flags; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci dev_dbg(sfp->gc.parent, "padctl_rmw(%u, 0x%03x, 0x%03x)\n", pin, _mask, _value); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 71962306a36Sopenharmony_ci value |= readl_relaxed(reg) & ~mask; 72062306a36Sopenharmony_ci writel_relaxed(value, reg); 72162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci#define PIN_CONFIG_STARFIVE_STRONG_PULL_UP (PIN_CONFIG_END + 1) 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic const struct pinconf_generic_params starfive_pinconf_custom_params[] = { 72762306a36Sopenharmony_ci { "starfive,strong-pull-up", PIN_CONFIG_STARFIVE_STRONG_PULL_UP, 1 }, 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 73162306a36Sopenharmony_cistatic const struct pin_config_item starfive_pinconf_custom_conf_items[] = { 73262306a36Sopenharmony_ci PCONFDUMP(PIN_CONFIG_STARFIVE_STRONG_PULL_UP, "input bias strong pull-up", NULL, false), 73362306a36Sopenharmony_ci}; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(starfive_pinconf_custom_conf_items) == 73662306a36Sopenharmony_ci ARRAY_SIZE(starfive_pinconf_custom_params)); 73762306a36Sopenharmony_ci#else 73862306a36Sopenharmony_ci#define starfive_pinconf_custom_conf_items NULL 73962306a36Sopenharmony_ci#endif 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int starfive_pinconf_get(struct pinctrl_dev *pctldev, 74262306a36Sopenharmony_ci unsigned int pin, unsigned long *config) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 74562306a36Sopenharmony_ci int param = pinconf_to_config_param(*config); 74662306a36Sopenharmony_ci u16 value = starfive_padctl_get(sfp, pin); 74762306a36Sopenharmony_ci bool enabled; 74862306a36Sopenharmony_ci u32 arg; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci switch (param) { 75162306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 75262306a36Sopenharmony_ci enabled = value & PAD_BIAS_DISABLE; 75362306a36Sopenharmony_ci arg = 0; 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 75662306a36Sopenharmony_ci enabled = value & PAD_BIAS_PULL_DOWN; 75762306a36Sopenharmony_ci arg = 1; 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 76062306a36Sopenharmony_ci enabled = !(value & PAD_BIAS_MASK); 76162306a36Sopenharmony_ci arg = 1; 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 76462306a36Sopenharmony_ci enabled = value & PAD_DRIVE_STRENGTH_MASK; 76562306a36Sopenharmony_ci arg = starfive_drive_strength_to_max_mA(value & PAD_DRIVE_STRENGTH_MASK); 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 76862306a36Sopenharmony_ci enabled = value & PAD_INPUT_ENABLE; 76962306a36Sopenharmony_ci arg = enabled; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 77262306a36Sopenharmony_ci enabled = value & PAD_INPUT_SCHMITT_ENABLE; 77362306a36Sopenharmony_ci arg = enabled; 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 77662306a36Sopenharmony_ci enabled = value & PAD_SLEW_RATE_MASK; 77762306a36Sopenharmony_ci arg = (value & PAD_SLEW_RATE_MASK) >> PAD_SLEW_RATE_POS; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case PIN_CONFIG_STARFIVE_STRONG_PULL_UP: 78062306a36Sopenharmony_ci enabled = value & PAD_BIAS_STRONG_PULL_UP; 78162306a36Sopenharmony_ci arg = enabled; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci default: 78462306a36Sopenharmony_ci return -ENOTSUPP; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 78862306a36Sopenharmony_ci return enabled ? 0 : -EINVAL; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic int starfive_pinconf_group_get(struct pinctrl_dev *pctldev, 79262306a36Sopenharmony_ci unsigned int gsel, unsigned long *config) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci const struct group_desc *group; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci group = pinctrl_generic_get_group(pctldev, gsel); 79762306a36Sopenharmony_ci if (!group) 79862306a36Sopenharmony_ci return -EINVAL; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci return starfive_pinconf_get(pctldev, group->pins[0], config); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic int starfive_pinconf_group_set(struct pinctrl_dev *pctldev, 80462306a36Sopenharmony_ci unsigned int gsel, 80562306a36Sopenharmony_ci unsigned long *configs, 80662306a36Sopenharmony_ci unsigned int num_configs) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 80962306a36Sopenharmony_ci const struct group_desc *group; 81062306a36Sopenharmony_ci u16 mask, value; 81162306a36Sopenharmony_ci int i; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci group = pinctrl_generic_get_group(pctldev, gsel); 81462306a36Sopenharmony_ci if (!group) 81562306a36Sopenharmony_ci return -EINVAL; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci mask = 0; 81862306a36Sopenharmony_ci value = 0; 81962306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 82062306a36Sopenharmony_ci int param = pinconf_to_config_param(configs[i]); 82162306a36Sopenharmony_ci u32 arg = pinconf_to_config_argument(configs[i]); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci switch (param) { 82462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 82562306a36Sopenharmony_ci mask |= PAD_BIAS_MASK; 82662306a36Sopenharmony_ci value = (value & ~PAD_BIAS_MASK) | PAD_BIAS_DISABLE; 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 82962306a36Sopenharmony_ci if (arg == 0) 83062306a36Sopenharmony_ci return -ENOTSUPP; 83162306a36Sopenharmony_ci mask |= PAD_BIAS_MASK; 83262306a36Sopenharmony_ci value = (value & ~PAD_BIAS_MASK) | PAD_BIAS_PULL_DOWN; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 83562306a36Sopenharmony_ci if (arg == 0) 83662306a36Sopenharmony_ci return -ENOTSUPP; 83762306a36Sopenharmony_ci mask |= PAD_BIAS_MASK; 83862306a36Sopenharmony_ci value = value & ~PAD_BIAS_MASK; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 84162306a36Sopenharmony_ci mask |= PAD_DRIVE_STRENGTH_MASK; 84262306a36Sopenharmony_ci value = (value & ~PAD_DRIVE_STRENGTH_MASK) | 84362306a36Sopenharmony_ci starfive_drive_strength_from_max_mA(arg); 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 84662306a36Sopenharmony_ci mask |= PAD_INPUT_ENABLE; 84762306a36Sopenharmony_ci if (arg) 84862306a36Sopenharmony_ci value |= PAD_INPUT_ENABLE; 84962306a36Sopenharmony_ci else 85062306a36Sopenharmony_ci value &= ~PAD_INPUT_ENABLE; 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 85362306a36Sopenharmony_ci mask |= PAD_INPUT_SCHMITT_ENABLE; 85462306a36Sopenharmony_ci if (arg) 85562306a36Sopenharmony_ci value |= PAD_INPUT_SCHMITT_ENABLE; 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci value &= ~PAD_INPUT_SCHMITT_ENABLE; 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 86062306a36Sopenharmony_ci mask |= PAD_SLEW_RATE_MASK; 86162306a36Sopenharmony_ci value = (value & ~PAD_SLEW_RATE_MASK) | 86262306a36Sopenharmony_ci ((arg << PAD_SLEW_RATE_POS) & PAD_SLEW_RATE_MASK); 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci case PIN_CONFIG_STARFIVE_STRONG_PULL_UP: 86562306a36Sopenharmony_ci if (arg) { 86662306a36Sopenharmony_ci mask |= PAD_BIAS_MASK; 86762306a36Sopenharmony_ci value = (value & ~PAD_BIAS_MASK) | 86862306a36Sopenharmony_ci PAD_BIAS_STRONG_PULL_UP; 86962306a36Sopenharmony_ci } else { 87062306a36Sopenharmony_ci mask |= PAD_BIAS_STRONG_PULL_UP; 87162306a36Sopenharmony_ci value = value & ~PAD_BIAS_STRONG_PULL_UP; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci break; 87462306a36Sopenharmony_ci default: 87562306a36Sopenharmony_ci return -ENOTSUPP; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci for (i = 0; i < group->num_pins; i++) 88062306a36Sopenharmony_ci starfive_padctl_rmw(sfp, group->pins[i], mask, value); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 88662306a36Sopenharmony_cistatic void starfive_pinconf_dbg_show(struct pinctrl_dev *pctldev, 88762306a36Sopenharmony_ci struct seq_file *s, unsigned int pin) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct starfive_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); 89062306a36Sopenharmony_ci u16 value = starfive_padctl_get(sfp, pin); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci seq_printf(s, " (0x%03x)", value); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci#else 89562306a36Sopenharmony_ci#define starfive_pinconf_dbg_show NULL 89662306a36Sopenharmony_ci#endif 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct pinconf_ops starfive_pinconf_ops = { 89962306a36Sopenharmony_ci .pin_config_get = starfive_pinconf_get, 90062306a36Sopenharmony_ci .pin_config_group_get = starfive_pinconf_group_get, 90162306a36Sopenharmony_ci .pin_config_group_set = starfive_pinconf_group_set, 90262306a36Sopenharmony_ci .pin_config_dbg_show = starfive_pinconf_dbg_show, 90362306a36Sopenharmony_ci .is_generic = true, 90462306a36Sopenharmony_ci}; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_cistatic struct pinctrl_desc starfive_desc = { 90762306a36Sopenharmony_ci .name = DRIVER_NAME, 90862306a36Sopenharmony_ci .pins = starfive_pins, 90962306a36Sopenharmony_ci .npins = ARRAY_SIZE(starfive_pins), 91062306a36Sopenharmony_ci .pctlops = &starfive_pinctrl_ops, 91162306a36Sopenharmony_ci .pmxops = &starfive_pinmux_ops, 91262306a36Sopenharmony_ci .confops = &starfive_pinconf_ops, 91362306a36Sopenharmony_ci .owner = THIS_MODULE, 91462306a36Sopenharmony_ci .num_custom_params = ARRAY_SIZE(starfive_pinconf_custom_params), 91562306a36Sopenharmony_ci .custom_params = starfive_pinconf_custom_params, 91662306a36Sopenharmony_ci .custom_conf_items = starfive_pinconf_custom_conf_items, 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int starfive_gpio_request(struct gpio_chip *gc, unsigned int gpio) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci return pinctrl_gpio_request(gc->base + gpio); 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic void starfive_gpio_free(struct gpio_chip *gc, unsigned int gpio) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci pinctrl_gpio_free(gc->base + gpio); 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic int starfive_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 93262306a36Sopenharmony_ci void __iomem *doen = sfp->base + GPON_DOEN_CFG + 8 * gpio; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (readl_relaxed(doen) == GPO_ENABLE) 93562306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int starfive_gpio_direction_input(struct gpio_chip *gc, 94162306a36Sopenharmony_ci unsigned int gpio) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 94462306a36Sopenharmony_ci void __iomem *doen = sfp->base + GPON_DOEN_CFG + 8 * gpio; 94562306a36Sopenharmony_ci unsigned long flags; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* enable input and schmitt trigger */ 94862306a36Sopenharmony_ci starfive_padctl_rmw(sfp, starfive_gpio_to_pin(sfp, gpio), 94962306a36Sopenharmony_ci PAD_INPUT_ENABLE | PAD_INPUT_SCHMITT_ENABLE, 95062306a36Sopenharmony_ci PAD_INPUT_ENABLE | PAD_INPUT_SCHMITT_ENABLE); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 95362306a36Sopenharmony_ci writel_relaxed(GPO_DISABLE, doen); 95462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic int starfive_gpio_direction_output(struct gpio_chip *gc, 95962306a36Sopenharmony_ci unsigned int gpio, int value) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 96262306a36Sopenharmony_ci void __iomem *dout = sfp->base + GPON_DOUT_CFG + 8 * gpio; 96362306a36Sopenharmony_ci void __iomem *doen = sfp->base + GPON_DOEN_CFG + 8 * gpio; 96462306a36Sopenharmony_ci unsigned long flags; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 96762306a36Sopenharmony_ci writel_relaxed(value, dout); 96862306a36Sopenharmony_ci writel_relaxed(GPO_ENABLE, doen); 96962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* disable input, schmitt trigger and bias */ 97262306a36Sopenharmony_ci starfive_padctl_rmw(sfp, starfive_gpio_to_pin(sfp, gpio), 97362306a36Sopenharmony_ci PAD_BIAS_MASK | PAD_INPUT_ENABLE | PAD_INPUT_SCHMITT_ENABLE, 97462306a36Sopenharmony_ci PAD_BIAS_DISABLE); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic int starfive_gpio_get(struct gpio_chip *gc, unsigned int gpio) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 98262306a36Sopenharmony_ci void __iomem *din = sfp->base + GPIODIN + 4 * (gpio / 32); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return !!(readl_relaxed(din) & BIT(gpio % 32)); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic void starfive_gpio_set(struct gpio_chip *gc, unsigned int gpio, 98862306a36Sopenharmony_ci int value) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 99162306a36Sopenharmony_ci void __iomem *dout = sfp->base + GPON_DOUT_CFG + 8 * gpio; 99262306a36Sopenharmony_ci unsigned long flags; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 99562306a36Sopenharmony_ci writel_relaxed(value, dout); 99662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic int starfive_gpio_set_config(struct gpio_chip *gc, unsigned int gpio, 100062306a36Sopenharmony_ci unsigned long config) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 100362306a36Sopenharmony_ci u32 arg = pinconf_to_config_argument(config); 100462306a36Sopenharmony_ci u16 value; 100562306a36Sopenharmony_ci u16 mask; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci switch (pinconf_to_config_param(config)) { 100862306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 100962306a36Sopenharmony_ci mask = PAD_BIAS_MASK; 101062306a36Sopenharmony_ci value = PAD_BIAS_DISABLE; 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 101362306a36Sopenharmony_ci if (arg == 0) 101462306a36Sopenharmony_ci return -ENOTSUPP; 101562306a36Sopenharmony_ci mask = PAD_BIAS_MASK; 101662306a36Sopenharmony_ci value = PAD_BIAS_PULL_DOWN; 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 101962306a36Sopenharmony_ci if (arg == 0) 102062306a36Sopenharmony_ci return -ENOTSUPP; 102162306a36Sopenharmony_ci mask = PAD_BIAS_MASK; 102262306a36Sopenharmony_ci value = 0; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_PUSH_PULL: 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 102762306a36Sopenharmony_ci mask = PAD_INPUT_ENABLE; 102862306a36Sopenharmony_ci value = arg ? PAD_INPUT_ENABLE : 0; 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 103162306a36Sopenharmony_ci mask = PAD_INPUT_SCHMITT_ENABLE; 103262306a36Sopenharmony_ci value = arg ? PAD_INPUT_SCHMITT_ENABLE : 0; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci default: 103562306a36Sopenharmony_ci return -ENOTSUPP; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci starfive_padctl_rmw(sfp, starfive_gpio_to_pin(sfp, gpio), mask, value); 103962306a36Sopenharmony_ci return 0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int starfive_gpio_add_pin_ranges(struct gpio_chip *gc) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci sfp->gpios.name = sfp->gc.label; 104762306a36Sopenharmony_ci sfp->gpios.base = sfp->gc.base; 104862306a36Sopenharmony_ci /* 104962306a36Sopenharmony_ci * sfp->gpios.pin_base depends on the chosen signal group 105062306a36Sopenharmony_ci * and is set in starfive_probe() 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci sfp->gpios.npins = NR_GPIOS; 105362306a36Sopenharmony_ci sfp->gpios.gc = &sfp->gc; 105462306a36Sopenharmony_ci pinctrl_add_gpio_range(sfp->pctl, &sfp->gpios); 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic void starfive_irq_ack(struct irq_data *d) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_data(d); 106162306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 106262306a36Sopenharmony_ci void __iomem *ic = sfp->base + GPIOIC + 4 * (gpio / 32); 106362306a36Sopenharmony_ci u32 mask = BIT(gpio % 32); 106462306a36Sopenharmony_ci unsigned long flags; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 106762306a36Sopenharmony_ci writel_relaxed(mask, ic); 106862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic void starfive_irq_mask(struct irq_data *d) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_data(d); 107462306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 107562306a36Sopenharmony_ci void __iomem *ie = sfp->base + GPIOIE + 4 * (gpio / 32); 107662306a36Sopenharmony_ci u32 mask = BIT(gpio % 32); 107762306a36Sopenharmony_ci unsigned long flags; 107862306a36Sopenharmony_ci u32 value; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 108162306a36Sopenharmony_ci value = readl_relaxed(ie) & ~mask; 108262306a36Sopenharmony_ci writel_relaxed(value, ie); 108362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci gpiochip_disable_irq(&sfp->gc, gpio); 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic void starfive_irq_mask_ack(struct irq_data *d) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_data(d); 109162306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 109262306a36Sopenharmony_ci void __iomem *ie = sfp->base + GPIOIE + 4 * (gpio / 32); 109362306a36Sopenharmony_ci void __iomem *ic = sfp->base + GPIOIC + 4 * (gpio / 32); 109462306a36Sopenharmony_ci u32 mask = BIT(gpio % 32); 109562306a36Sopenharmony_ci unsigned long flags; 109662306a36Sopenharmony_ci u32 value; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 109962306a36Sopenharmony_ci value = readl_relaxed(ie) & ~mask; 110062306a36Sopenharmony_ci writel_relaxed(value, ie); 110162306a36Sopenharmony_ci writel_relaxed(mask, ic); 110262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic void starfive_irq_unmask(struct irq_data *d) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_data(d); 110862306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 110962306a36Sopenharmony_ci void __iomem *ie = sfp->base + GPIOIE + 4 * (gpio / 32); 111062306a36Sopenharmony_ci u32 mask = BIT(gpio % 32); 111162306a36Sopenharmony_ci unsigned long flags; 111262306a36Sopenharmony_ci u32 value; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci gpiochip_enable_irq(&sfp->gc, gpio); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 111762306a36Sopenharmony_ci value = readl_relaxed(ie) | mask; 111862306a36Sopenharmony_ci writel_relaxed(value, ie); 111962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int starfive_irq_set_type(struct irq_data *d, unsigned int trigger) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_data(d); 112562306a36Sopenharmony_ci irq_hw_number_t gpio = irqd_to_hwirq(d); 112662306a36Sopenharmony_ci void __iomem *base = sfp->base + 4 * (gpio / 32); 112762306a36Sopenharmony_ci u32 mask = BIT(gpio % 32); 112862306a36Sopenharmony_ci u32 irq_type, edge_both, polarity; 112962306a36Sopenharmony_ci unsigned long flags; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci switch (trigger) { 113262306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 113362306a36Sopenharmony_ci irq_type = mask; /* 1: edge triggered */ 113462306a36Sopenharmony_ci edge_both = 0; /* 0: single edge */ 113562306a36Sopenharmony_ci polarity = mask; /* 1: rising edge */ 113662306a36Sopenharmony_ci break; 113762306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 113862306a36Sopenharmony_ci irq_type = mask; /* 1: edge triggered */ 113962306a36Sopenharmony_ci edge_both = 0; /* 0: single edge */ 114062306a36Sopenharmony_ci polarity = 0; /* 0: falling edge */ 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 114362306a36Sopenharmony_ci irq_type = mask; /* 1: edge triggered */ 114462306a36Sopenharmony_ci edge_both = mask; /* 1: both edges */ 114562306a36Sopenharmony_ci polarity = 0; /* 0: ignored */ 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 114862306a36Sopenharmony_ci irq_type = 0; /* 0: level triggered */ 114962306a36Sopenharmony_ci edge_both = 0; /* 0: ignored */ 115062306a36Sopenharmony_ci polarity = mask; /* 1: high level */ 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 115362306a36Sopenharmony_ci irq_type = 0; /* 0: level triggered */ 115462306a36Sopenharmony_ci edge_both = 0; /* 0: ignored */ 115562306a36Sopenharmony_ci polarity = 0; /* 0: low level */ 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci default: 115862306a36Sopenharmony_ci return -EINVAL; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (trigger & IRQ_TYPE_EDGE_BOTH) 116262306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 116362306a36Sopenharmony_ci else 116462306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci raw_spin_lock_irqsave(&sfp->lock, flags); 116762306a36Sopenharmony_ci irq_type |= readl_relaxed(base + GPIOIS) & ~mask; 116862306a36Sopenharmony_ci writel_relaxed(irq_type, base + GPIOIS); 116962306a36Sopenharmony_ci edge_both |= readl_relaxed(base + GPIOIBE) & ~mask; 117062306a36Sopenharmony_ci writel_relaxed(edge_both, base + GPIOIBE); 117162306a36Sopenharmony_ci polarity |= readl_relaxed(base + GPIOIEV) & ~mask; 117262306a36Sopenharmony_ci writel_relaxed(polarity, base + GPIOIEV); 117362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sfp->lock, flags); 117462306a36Sopenharmony_ci return 0; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic const struct irq_chip starfive_irq_chip = { 117862306a36Sopenharmony_ci .name = "StarFive GPIO", 117962306a36Sopenharmony_ci .irq_ack = starfive_irq_ack, 118062306a36Sopenharmony_ci .irq_mask = starfive_irq_mask, 118162306a36Sopenharmony_ci .irq_mask_ack = starfive_irq_mask_ack, 118262306a36Sopenharmony_ci .irq_unmask = starfive_irq_unmask, 118362306a36Sopenharmony_ci .irq_set_type = starfive_irq_set_type, 118462306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED, 118562306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 118662306a36Sopenharmony_ci}; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic void starfive_gpio_irq_handler(struct irq_desc *desc) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci struct starfive_pinctrl *sfp = starfive_from_irq_desc(desc); 119162306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 119262306a36Sopenharmony_ci unsigned long mis; 119362306a36Sopenharmony_ci unsigned int pin; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci chained_irq_enter(chip, desc); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci mis = readl_relaxed(sfp->base + GPIOMIS + 0); 119862306a36Sopenharmony_ci for_each_set_bit(pin, &mis, 32) 119962306a36Sopenharmony_ci generic_handle_domain_irq(sfp->gc.irq.domain, pin); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci mis = readl_relaxed(sfp->base + GPIOMIS + 4); 120262306a36Sopenharmony_ci for_each_set_bit(pin, &mis, 32) 120362306a36Sopenharmony_ci generic_handle_domain_irq(sfp->gc.irq.domain, pin + 32); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci chained_irq_exit(chip, desc); 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic int starfive_gpio_init_hw(struct gpio_chip *gc) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* mask all GPIO interrupts */ 121362306a36Sopenharmony_ci writel(0, sfp->base + GPIOIE + 0); 121462306a36Sopenharmony_ci writel(0, sfp->base + GPIOIE + 4); 121562306a36Sopenharmony_ci /* clear edge interrupt flags */ 121662306a36Sopenharmony_ci writel(~0U, sfp->base + GPIOIC + 0); 121762306a36Sopenharmony_ci writel(~0U, sfp->base + GPIOIC + 4); 121862306a36Sopenharmony_ci /* enable GPIO interrupts */ 121962306a36Sopenharmony_ci writel(1, sfp->base + GPIOEN); 122062306a36Sopenharmony_ci return 0; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic void starfive_disable_clock(void *data) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci clk_disable_unprepare(data); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int starfive_probe(struct platform_device *pdev) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 123162306a36Sopenharmony_ci struct starfive_pinctrl *sfp; 123262306a36Sopenharmony_ci struct reset_control *rst; 123362306a36Sopenharmony_ci struct clk *clk; 123462306a36Sopenharmony_ci u32 value; 123562306a36Sopenharmony_ci int ret; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL); 123862306a36Sopenharmony_ci if (!sfp) 123962306a36Sopenharmony_ci return -ENOMEM; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci sfp->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); 124262306a36Sopenharmony_ci if (IS_ERR(sfp->base)) 124362306a36Sopenharmony_ci return PTR_ERR(sfp->base); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci sfp->padctl = devm_platform_ioremap_resource_byname(pdev, "padctl"); 124662306a36Sopenharmony_ci if (IS_ERR(sfp->padctl)) 124762306a36Sopenharmony_ci return PTR_ERR(sfp->padctl); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci clk = devm_clk_get(dev, NULL); 125062306a36Sopenharmony_ci if (IS_ERR(clk)) 125162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(clk), "could not get clock\n"); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci rst = devm_reset_control_get_exclusive(dev, NULL); 125462306a36Sopenharmony_ci if (IS_ERR(rst)) 125562306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(rst), "could not get reset\n"); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci ret = clk_prepare_enable(clk); 125862306a36Sopenharmony_ci if (ret) 125962306a36Sopenharmony_ci return dev_err_probe(dev, ret, "could not enable clock\n"); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, starfive_disable_clock, clk); 126262306a36Sopenharmony_ci if (ret) 126362306a36Sopenharmony_ci return ret; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* 126662306a36Sopenharmony_ci * We don't want to assert reset and risk undoing pin muxing for the 126762306a36Sopenharmony_ci * early boot serial console, but let's make sure the reset line is 126862306a36Sopenharmony_ci * deasserted in case someone runs a really minimal bootloader. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci ret = reset_control_deassert(rst); 127162306a36Sopenharmony_ci if (ret) 127262306a36Sopenharmony_ci return dev_err_probe(dev, ret, "could not deassert reset\n"); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci platform_set_drvdata(pdev, sfp); 127562306a36Sopenharmony_ci sfp->gc.parent = dev; 127662306a36Sopenharmony_ci raw_spin_lock_init(&sfp->lock); 127762306a36Sopenharmony_ci mutex_init(&sfp->mutex); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ret = devm_pinctrl_register_and_init(dev, &starfive_desc, sfp, &sfp->pctl); 128062306a36Sopenharmony_ci if (ret) 128162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "could not register pinctrl driver\n"); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci if (!of_property_read_u32(dev->of_node, "starfive,signal-group", &value)) { 128462306a36Sopenharmony_ci if (value > 6) 128562306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, "invalid signal group %u\n", value); 128662306a36Sopenharmony_ci writel(value, sfp->padctl + IO_PADSHARE_SEL); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci value = readl(sfp->padctl + IO_PADSHARE_SEL); 129062306a36Sopenharmony_ci switch (value) { 129162306a36Sopenharmony_ci case 0: 129262306a36Sopenharmony_ci sfp->gpios.pin_base = PAD_INVALID_GPIO; 129362306a36Sopenharmony_ci goto out_pinctrl_enable; 129462306a36Sopenharmony_ci case 1: 129562306a36Sopenharmony_ci sfp->gpios.pin_base = PAD_GPIO(0); 129662306a36Sopenharmony_ci break; 129762306a36Sopenharmony_ci case 2: 129862306a36Sopenharmony_ci sfp->gpios.pin_base = PAD_FUNC_SHARE(72); 129962306a36Sopenharmony_ci break; 130062306a36Sopenharmony_ci case 3: 130162306a36Sopenharmony_ci sfp->gpios.pin_base = PAD_FUNC_SHARE(70); 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci case 4: case 5: case 6: 130462306a36Sopenharmony_ci sfp->gpios.pin_base = PAD_FUNC_SHARE(0); 130562306a36Sopenharmony_ci break; 130662306a36Sopenharmony_ci default: 130762306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, "invalid signal group %u\n", value); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci sfp->gc.label = dev_name(dev); 131162306a36Sopenharmony_ci sfp->gc.owner = THIS_MODULE; 131262306a36Sopenharmony_ci sfp->gc.request = starfive_gpio_request; 131362306a36Sopenharmony_ci sfp->gc.free = starfive_gpio_free; 131462306a36Sopenharmony_ci sfp->gc.get_direction = starfive_gpio_get_direction; 131562306a36Sopenharmony_ci sfp->gc.direction_input = starfive_gpio_direction_input; 131662306a36Sopenharmony_ci sfp->gc.direction_output = starfive_gpio_direction_output; 131762306a36Sopenharmony_ci sfp->gc.get = starfive_gpio_get; 131862306a36Sopenharmony_ci sfp->gc.set = starfive_gpio_set; 131962306a36Sopenharmony_ci sfp->gc.set_config = starfive_gpio_set_config; 132062306a36Sopenharmony_ci sfp->gc.add_pin_ranges = starfive_gpio_add_pin_ranges; 132162306a36Sopenharmony_ci sfp->gc.base = -1; 132262306a36Sopenharmony_ci sfp->gc.ngpio = NR_GPIOS; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci gpio_irq_chip_set_chip(&sfp->gc.irq, &starfive_irq_chip); 132562306a36Sopenharmony_ci sfp->gc.irq.parent_handler = starfive_gpio_irq_handler; 132662306a36Sopenharmony_ci sfp->gc.irq.num_parents = 1; 132762306a36Sopenharmony_ci sfp->gc.irq.parents = devm_kcalloc(dev, sfp->gc.irq.num_parents, 132862306a36Sopenharmony_ci sizeof(*sfp->gc.irq.parents), GFP_KERNEL); 132962306a36Sopenharmony_ci if (!sfp->gc.irq.parents) 133062306a36Sopenharmony_ci return -ENOMEM; 133162306a36Sopenharmony_ci sfp->gc.irq.default_type = IRQ_TYPE_NONE; 133262306a36Sopenharmony_ci sfp->gc.irq.handler = handle_bad_irq; 133362306a36Sopenharmony_ci sfp->gc.irq.init_hw = starfive_gpio_init_hw; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 133662306a36Sopenharmony_ci if (ret < 0) 133762306a36Sopenharmony_ci return ret; 133862306a36Sopenharmony_ci sfp->gc.irq.parents[0] = ret; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, &sfp->gc, sfp); 134162306a36Sopenharmony_ci if (ret) 134262306a36Sopenharmony_ci return dev_err_probe(dev, ret, "could not register gpiochip\n"); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci irq_domain_set_pm_device(sfp->gc.irq.domain, dev); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ciout_pinctrl_enable: 134762306a36Sopenharmony_ci return pinctrl_enable(sfp->pctl); 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic const struct of_device_id starfive_of_match[] = { 135162306a36Sopenharmony_ci { .compatible = "starfive,jh7100-pinctrl" }, 135262306a36Sopenharmony_ci { /* sentinel */ } 135362306a36Sopenharmony_ci}; 135462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, starfive_of_match); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_cistatic struct platform_driver starfive_pinctrl_driver = { 135762306a36Sopenharmony_ci .probe = starfive_probe, 135862306a36Sopenharmony_ci .driver = { 135962306a36Sopenharmony_ci .name = DRIVER_NAME, 136062306a36Sopenharmony_ci .of_match_table = starfive_of_match, 136162306a36Sopenharmony_ci }, 136262306a36Sopenharmony_ci}; 136362306a36Sopenharmony_cimodule_platform_driver(starfive_pinctrl_driver); 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ciMODULE_DESCRIPTION("Pinctrl driver for StarFive SoCs"); 136662306a36Sopenharmony_ciMODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>"); 136762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1368