diff options
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 26 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 2 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx-mmio.c | 1 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx8ulp.c | 2 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imxrt.c | 1 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-vf610.c | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-sx150x.c | 902 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-th1520.c | 700 | ||||
-rw-r--r-- | drivers/pinctrl/qcom/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pinctrl/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/qcom/pinctrl-ipq5424.c | 322 |
11 files changed, 1964 insertions, 1 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 687fb339ea0..5e2808abc8a 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -263,6 +263,24 @@ config PINCTRL_ROCKCHIP_RV1108 both the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_SX150X + bool "Semtech SX150x I2C GPIO expander pinctrl driver" + depends on DM && PINCTRL_FULL + help + Say yes here to provide support for Semtech SX150x-series I2C + GPIO expanders as pinctrl module. + Compatible models include: + - 8 bits: sx1508q, sx1502q + - 16 bits: sx1509q, sx1506q + +config SPL_PINCTRL_SX150X + bool "Semtech SX150x I2C GPIO expander pinctrl driver in SPL" + depends on DM && SPL_PINCTRL_FULL + help + This option is an SPL-variant of the PINCTRL_SX150X option. + See the help of PINCTRL_SX150X for details. + + config PINCTRL_SANDBOX bool "Sandbox pinctrl driver" depends on SANDBOX @@ -323,6 +341,14 @@ config SPL_PINCTRL_STMFX This option is an SPL-variant of the SPL_PINCTRL_STMFX option. See the help of PINCTRL_STMFX for details. +config PINCTRL_TH1520 + bool "T-Head TH1520 pinctrl driver" + depends on DM && PINCTRL_FULL + select PINCONF + help + Support pin multiplexing and configuration control blocks on the + T-Head TH1520 SoC. + config ASPEED_AST2500_PINCTRL bool "Aspeed AST2500 pin control driver" depends on DM && PINCTRL_GENERIC && ASPEED_AST2500 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a8eba656843..33ff7b95ef2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -32,7 +32,9 @@ obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o +obj-$(CONFIG_$(PHASE_)PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_$(PHASE_)PINCTRL_STMFX) += pinctrl-stmfx.o +obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o obj-y += broadcom/ obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/nxp/pinctrl-imx-mmio.c b/drivers/pinctrl/nxp/pinctrl-imx-mmio.c index 6ee108a0120..2f4228a9fc5 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx-mmio.c +++ b/drivers/pinctrl/nxp/pinctrl-imx-mmio.c @@ -187,7 +187,6 @@ int imx_pinctrl_probe_mmio(struct udevice *dev) return -ENOMEM; priv->info = info; - info->mux_mask = ofnode_read_u32_default(node, "fsl,mux_mask", 0); /* * Refer to linux documentation for details: * Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt diff --git a/drivers/pinctrl/nxp/pinctrl-imx8ulp.c b/drivers/pinctrl/nxp/pinctrl-imx8ulp.c index 2df63625191..3e8c080d3fd 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx8ulp.c +++ b/drivers/pinctrl/nxp/pinctrl-imx8ulp.c @@ -11,10 +11,12 @@ static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info0 = { .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CFG_IBE_OBE, + .mux_mask = 0xf00, }; static struct imx_pinctrl_soc_info imx8ulp_pinctrl_soc_info1 = { .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CFG_IBE_OBE, + .mux_mask = 0xf00, }; static const struct udevice_id imx8ulp_pinctrl_match[] = { diff --git a/drivers/pinctrl/nxp/pinctrl-imxrt.c b/drivers/pinctrl/nxp/pinctrl-imxrt.c index 39000ceb923..7e55d596248 100644 --- a/drivers/pinctrl/nxp/pinctrl-imxrt.c +++ b/drivers/pinctrl/nxp/pinctrl-imxrt.c @@ -11,6 +11,7 @@ static struct imx_pinctrl_soc_info imxrt_pinctrl_soc_info = { .flags = ZERO_OFFSET_VALID, + .mux_mask = 0x7, }; static const struct udevice_id imxrt_pinctrl_match[] = { diff --git a/drivers/pinctrl/nxp/pinctrl-vf610.c b/drivers/pinctrl/nxp/pinctrl-vf610.c index cbff8dcefd8..7d1b95eaa05 100644 --- a/drivers/pinctrl/nxp/pinctrl-vf610.c +++ b/drivers/pinctrl/nxp/pinctrl-vf610.c @@ -11,6 +11,7 @@ static struct imx_pinctrl_soc_info vf610_pinctrl_soc_info = { .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID, + .mux_mask = 0x700000, }; static const struct udevice_id vf610_pinctrl_match[] = { diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c new file mode 100644 index 00000000000..324d7af8fcd --- /dev/null +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -0,0 +1,902 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024, Exfo Inc - All Rights Reserved + * + * Author: Anis CHALI <anis.chali@exfo.com> + * inspired and adapted from linux driver of sx150x written by Gregory Bean + * <gbean@codeaurora.org> + */ + +#include <asm/gpio.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> +#include <dt-bindings/gpio/gpio.h> +#include <i2c.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <power/regulator.h> +#include <regmap.h> + +#define err(format, arg...) printf("ERR:" format "\n", ##arg) +#define dbg(format, arg...) printf("DBG:" format "\n", ##arg) + +#define SX150X_PIN(_pin, _name) { .pin = _pin, .name = _name } + +/* The chip models of sx150x */ +enum { + SX150X_123 = 0, + SX150X_456, + SX150X_789, +}; + +enum { + SX150X_789_REG_MISC_AUTOCLEAR_OFF = 1 << 0, + SX150X_MAX_REGISTER = 0xad, + SX150X_IRQ_TYPE_EDGE_RISING = 0x1, + SX150X_IRQ_TYPE_EDGE_FALLING = 0x2, + SX150X_789_RESET_KEY1 = 0x12, + SX150X_789_RESET_KEY2 = 0x34, +}; + +struct sx150x_123_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advanced; +}; + +struct sx150x_456_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advanced; +}; + +struct sx150x_789_pri { + u8 reg_drain; + u8 reg_polarity; + u8 reg_clock; + u8 reg_misc; + u8 reg_reset; + u8 ngpios; +}; + +struct sx150x_pin_desc { + u32 pin; + u8 *name; +}; + +struct sx150x_device_data { + u8 model; + u8 reg_pullup; + u8 reg_pulldn; + u8 reg_dir; + u8 reg_data; + u8 reg_irq_mask; + u8 reg_irq_src; + u8 reg_sense; + u8 ngpios; + union { + struct sx150x_123_pri x123; + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; + const struct sx150x_pin_desc *pins; + unsigned int npins; +}; + +struct sx150x_pinctrl_priv { + char name[32]; + struct udevice *gpio; + struct udevice *i2c; + const struct sx150x_device_data *data; +}; + +static const struct sx150x_pin_desc sx150x_4_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), SX150X_PIN(2, "gpio2"), + SX150X_PIN(3, "gpio3"), SX150X_PIN(4, "oscio"), +}; + +static const struct sx150x_pin_desc sx150x_8_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), SX150X_PIN(2, "gpio2"), + SX150X_PIN(3, "gpio3"), SX150X_PIN(4, "gpio4"), SX150X_PIN(5, "gpio5"), + SX150X_PIN(6, "gpio6"), SX150X_PIN(7, "gpio7"), SX150X_PIN(8, "oscio"), +}; + +static const struct sx150x_pin_desc sx150x_16_pins[] = { + SX150X_PIN(0, "gpio0"), SX150X_PIN(1, "gpio1"), + SX150X_PIN(2, "gpio2"), SX150X_PIN(3, "gpio3"), + SX150X_PIN(4, "gpio4"), SX150X_PIN(5, "gpio5"), + SX150X_PIN(6, "gpio6"), SX150X_PIN(7, "gpio7"), + SX150X_PIN(8, "gpio8"), SX150X_PIN(9, "gpio9"), + SX150X_PIN(10, "gpio10"), SX150X_PIN(11, "gpio11"), + SX150X_PIN(12, "gpio12"), SX150X_PIN(13, "gpio13"), + SX150X_PIN(14, "gpio14"), SX150X_PIN(15, "gpio15"), + SX150X_PIN(16, "oscio"), +}; + +static const struct sx150x_device_data sx1501q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x07, + .pri.x123 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table2 = 0x13, + .reg_advanced = 0xad, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = 4, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1502q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x06, + .pri.x123 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table1 = 0x12, + .reg_pld_table2 = 0x13, + .reg_pld_table3 = 0x14, + .reg_pld_table4 = 0x15, + .reg_advanced = 0xad, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = 8, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1503q_device_data = { + .model = SX150X_123, + .reg_pullup = 0x04, + .reg_pulldn = 0x06, + .reg_dir = 0x02, + .reg_data = 0x00, + .reg_irq_mask = 0x08, + .reg_irq_src = 0x0e, + .reg_sense = 0x0a, + .pri.x123 = { + .reg_pld_mode = 0x20, + .reg_pld_table0 = 0x22, + .reg_pld_table1 = 0x24, + .reg_pld_table2 = 0x26, + .reg_pld_table3 = 0x28, + .reg_pld_table4 = 0x2a, + .reg_advanced = 0xad, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = 16, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1504q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x07, + .pri.x456 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table2 = 0x13, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = 4, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1505q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x02, + .reg_pulldn = 0x03, + .reg_dir = 0x01, + .reg_data = 0x00, + .reg_irq_mask = 0x05, + .reg_irq_src = 0x08, + .reg_sense = 0x06, + .pri.x456 = { + .reg_pld_mode = 0x10, + .reg_pld_table0 = 0x11, + .reg_pld_table1 = 0x12, + .reg_pld_table2 = 0x13, + .reg_pld_table3 = 0x14, + .reg_pld_table4 = 0x15, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = 8, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1506q_device_data = { + .model = SX150X_456, + .reg_pullup = 0x04, + .reg_pulldn = 0x06, + .reg_dir = 0x02, + .reg_data = 0x00, + .reg_irq_mask = 0x08, + .reg_irq_src = 0x0e, + .reg_sense = 0x0a, + .pri.x456 = { + .reg_pld_mode = 0x20, + .reg_pld_table0 = 0x22, + .reg_pld_table1 = 0x24, + .reg_pld_table2 = 0x26, + .reg_pld_table3 = 0x28, + .reg_pld_table4 = 0x2a, + .reg_advanced = 0xad, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = 16, /* oscio not available */ +}; + +static const struct sx150x_device_data sx1507q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0b, + .reg_sense = 0x0a, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0d, + .reg_misc = 0x0e, + .reg_reset = 0x7d, + }, + .ngpios = 4, + .pins = sx150x_4_pins, + .npins = ARRAY_SIZE(sx150x_4_pins), +}; + +static const struct sx150x_device_data sx1508q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0c, + .reg_sense = 0x0a, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0f, + .reg_misc = 0x10, + .reg_reset = 0x7d, + }, + .ngpios = 8, + .pins = sx150x_8_pins, + .npins = ARRAY_SIZE(sx150x_8_pins), +}; + +static const struct sx150x_device_data sx1509q_device_data = { + .model = SX150X_789, + .reg_pullup = 0x06, + .reg_pulldn = 0x08, + .reg_dir = 0x0e, + .reg_data = 0x10, + .reg_irq_mask = 0x12, + .reg_irq_src = 0x18, + .reg_sense = 0x14, + .pri.x789 = { + .reg_drain = 0x0a, + .reg_polarity = 0x0c, + .reg_clock = 0x1e, + .reg_misc = 0x1f, + .reg_reset = 0x7d, + }, + .ngpios = 16, + .pins = sx150x_16_pins, + .npins = ARRAY_SIZE(sx150x_16_pins), +}; + +static bool sx150x_pin_is_oscio(struct sx150x_pinctrl_priv *pctl, + unsigned int pin) +{ + if (pin >= pctl->data->npins) + return false; + + /* OSCIO pin is only present in 789 devices */ + if (pctl->data->model != SX150X_789) + return false; + + return !strcmp(pctl->data->pins[pin].name, "oscio"); +} + +static int sx150x_reg_width(struct sx150x_pinctrl_priv *pctl, unsigned int reg) +{ + const struct sx150x_device_data *data = pctl->data; + + if (reg == data->reg_sense) { + /* + * RegSense packs two bits of configuration per GPIO, + * so we'd need to read twice as many bits as there + * are GPIO in our chip + */ + return 2 * data->ngpios; + } else if ((data->model == SX150X_789 && + (reg == data->pri.x789.reg_misc || + reg == data->pri.x789.reg_clock || + reg == data->pri.x789.reg_reset)) || + (data->model == SX150X_123 && + reg == data->pri.x123.reg_advanced) || + (data->model == SX150X_456 && data->pri.x456.reg_advanced && + reg == data->pri.x456.reg_advanced)) { + return 8; + } else { + return data->ngpios; + } +} + +static unsigned int sx150x_maybe_swizzle(struct sx150x_pinctrl_priv *pctl, + unsigned int reg, unsigned int val) +{ + unsigned int a, b; + const struct sx150x_device_data *data = pctl->data; + + /* + * Whereas SX1509 presents RegSense in a simple layout as such: + * reg [ f f e e d d c c ] + * reg 1 [ b b a a 9 9 8 8 ] + * reg 2 [ 7 7 6 6 5 5 4 4 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + * + * SX1503 and SX1506 deviate from that data layout, instead storing + * their contents as follows: + * + * reg [ f f e e d d c c ] + * reg 1 [ 7 7 6 6 5 5 4 4 ] + * reg 2 [ b b a a 9 9 8 8 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + * + * so, taking that into account, we swap two + * inner bytes of a 4-byte result + */ + + if (reg == data->reg_sense && data->ngpios == 16 && + (data->model == SX150X_123 || data->model == SX150X_456)) { + a = val & 0x00ff0000; + b = val & 0x0000ff00; + + val &= 0xff0000ff; + val |= b << 8; + val |= a >> 8; + } + + return val; +} + +/* + * In order to mask the differences between 16 and 8 bit expander + * devices we set up a sligthly ficticious regmap that pretends to be + * a set of 32-bit (to accommodate RegSenseLow/RegSenseHigh + * pair/quartet) registers and transparently reconstructs those + * registers via multiple I2C/SMBus reads + * + * This way the rest of the driver code, interfacing with the chip via + * regmap API, can work assuming that each GPIO pin is represented by + * a group of bits at an offset proportional to GPIO number within a + * given register. + */ +static int sx150x_reg_read(struct sx150x_pinctrl_priv *pctl, unsigned int reg, + unsigned int *result) +{ + int ret, n; + const int width = sx150x_reg_width(pctl, reg); + unsigned int idx, val; + + /* + * There are four potential cases covered by this function: + * + * 1) 8-pin chip, single configuration bit register + * + * This is trivial the code below just needs to read: + * reg [ 7 6 5 4 3 2 1 0 ] + * + * 2) 8-pin chip, double configuration bit register (RegSense) + * + * The read will be done as follows: + * reg [ 7 7 6 6 5 5 4 4 ] + * reg 1 [ 3 3 2 2 1 1 0 0 ] + * + * 3) 16-pin chip, single configuration bit register + * + * The read will be done as follows: + * reg [ f e d c b a 9 8 ] + * reg 1 [ 7 6 5 4 3 2 1 0 ] + * + * 4) 16-pin chip, double configuration bit register (RegSense) + * + * The read will be done as follows: + * reg [ f f e e d d c c ] + * reg 1 [ b b a a 9 9 8 8 ] + * reg 2 [ 7 7 6 6 5 5 4 4 ] + * reg 3 [ 3 3 2 2 1 1 0 0 ] + */ + + for (n = width, val = 0, idx = reg; n > 0; n -= 8, idx) { + val <<= 8; + + ret = dm_i2c_reg_read(pctl->i2c, idx); + if (ret < 0) + return ret; + + val |= ret; + } + + *result = sx150x_maybe_swizzle(pctl, reg, val); + + return 0; +} + +static int sx150x_reg_write(struct sx150x_pinctrl_priv *pctl, unsigned int reg, + unsigned int val) +{ + int ret, n; + const int width = sx150x_reg_width(pctl, reg); + + val = sx150x_maybe_swizzle(pctl, reg, val); + + n = (width - 1) & ~7; + do { + const u8 byte = (val >> n) & 0xff; + + ret = dm_i2c_reg_write(pctl->i2c, reg, byte); + if (ret < 0) + return ret; + + reg; + n -= 8; + } while (n >= 0); + + return 0; +} + +static unsigned int sx150x_read(struct sx150x_pinctrl_priv *pctl, uint reg) +{ + int ret; + unsigned int res; + + ret = sx150x_reg_read(pctl, reg, &res); + if (ret) { + err("%s: failed to read reg(%x) with %d", pctl->name, reg, ret); + return ret; + } + + return res; +} + +static int sx150x_write(struct sx150x_pinctrl_priv *pctl, uint reg, uint val) +{ + return sx150x_reg_write(pctl, reg, val); +} + +static int sx150x_write_bits(struct sx150x_pinctrl_priv *pctl, uint reg, + uint mask, uint val) +{ + int orig, tmp; + + orig = sx150x_read(pctl, reg); + if (orig < 0) + return orig; + + tmp = orig & ~mask; + tmp |= val & mask; + + return sx150x_write(pctl, reg, tmp); +} + +static int sx150x_reset(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + int err; + + err = sx150x_write(pctl, pctl->data->pri.x789.reg_reset, + SX150X_789_RESET_KEY1); + if (err < 0) + return err; + + err = sx150x_write(pctl, pctl->data->pri.x789.reg_reset, + SX150X_789_RESET_KEY2); + return err; +} + +static int sx150x_init_misc(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + u8 reg, value; + + switch (pctl->data->model) { + case SX150X_789: + reg = pctl->data->pri.x789.reg_misc; + value = 0x0; + break; + case SX150X_456: + reg = pctl->data->pri.x456.reg_advanced; + value = 0x00; + + /* + * Only SX1506 has RegAdvanced, SX1504/5 are expected + * to initialize this offset to zero + */ + if (!reg) + return 0; + break; + case SX150X_123: + reg = pctl->data->pri.x123.reg_advanced; + value = 0x00; + break; + default: + WARN(1, "Unknown chip model %d\n", pctl->data->model); + return -EINVAL; + } + + return sx150x_write(pctl, reg, value); +} + +static int sx150x_init_hw(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + const u8 reg[] = { + [SX150X_789] = pctl->data->pri.x789.reg_polarity, + [SX150X_456] = pctl->data->pri.x456.reg_pld_mode, + [SX150X_123] = pctl->data->pri.x123.reg_pld_mode, + }; + int err; + + if (pctl->data->model == SX150X_789 && + dev_read_bool(dev, "semtech,probe-reset")) { + err = sx150x_reset(dev); + if (err < 0) + return err; + } + + err = sx150x_init_misc(dev); + if (err < 0) + return err; + + /* Set all pins to work in normal mode */ + return sx150x_write(pctl, reg[pctl->data->model], 0); +} + +static int sx150x_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + return -EINVAL; + + int val = sx150x_read(pctl, pctl->data->reg_data); + + return !!(val & BIT(offset)); +} + +static int sx150x_gpio_set(struct udevice *dev, unsigned int offset, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + return sx150x_write_bits(pctl, pctl->data->reg_data, BIT(offset), + value ? BIT(offset) : 0); +} + +static int sx150x_gpio_oscio_set(struct udevice *dev, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + return sx150x_write(pctl, pctl->data->pri.x789.reg_clock, + (value ? 0x1f : 0x10)); +} + +static int sx150x_gpio_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + sx150x_gpio_oscio_set(dev->parent, value); + else + sx150x_gpio_set(dev->parent, offset, value); + + return 0; +} + +static int sx150x_gpio_get_direction(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + int val; + + if (sx150x_pin_is_oscio(pctl, offset)) + return GPIOF_OUTPUT; + + val = sx150x_read(pctl, pctl->data->reg_data); + if (val < 0) + return val; + + if (val & BIT(offset)) + return GPIOF_INPUT; + + return GPIOF_OUTPUT; +} + +static int sx150x_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + + if (sx150x_pin_is_oscio(pctl, offset)) + return -EINVAL; + + return sx150x_write_bits(pctl, pctl->data->reg_dir, BIT(offset), + BIT(offset)); +} + +static int sx150x_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + int ret; + + if (sx150x_pin_is_oscio(pctl, offset)) + return sx150x_gpio_oscio_set(dev, value); + + ret = sx150x_write_bits(pctl, pctl->data->reg_dir, BIT(offset), 0); + if (ret < 0) + return ret; + + return sx150x_gpio_set(dev, offset, value); +} + +static int sx150x_gpio_probe(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = pctl->name; + uc_priv->gpio_count = pctl->data->ngpios; + + return 0; +} + +static struct dm_gpio_ops sx150x_gpio_ops = { + .get_value = sx150x_gpio_get_value, + .set_value = sx150x_gpio_set_value, + .get_function = sx150x_gpio_get_direction, + .direction_input = sx150x_gpio_direction_input, + .direction_output = sx150x_gpio_direction_output, +}; + +static struct driver sx150x_gpio_driver = { + .name = "sx150x-gpio", + .id = UCLASS_GPIO, + .probe = sx150x_gpio_probe, + .ops = &sx150x_gpio_ops, +}; + +static const struct udevice_id sx150x_pinctrl_of_match[] = { + { .compatible = "semtech,sx1501q", + .data = (ulong)&sx1501q_device_data }, + { .compatible = "semtech,sx1502q", + .data = (ulong)&sx1502q_device_data }, + { .compatible = "semtech,sx1503q", + .data = (ulong)&sx1503q_device_data }, + { .compatible = "semtech,sx1504q", + .data = (ulong)&sx1504q_device_data }, + { .compatible = "semtech,sx1505q", + .data = (ulong)&sx1505q_device_data }, + { .compatible = "semtech,sx1506q", + .data = (ulong)&sx1506q_device_data }, + { .compatible = "semtech,sx1507q", + .data = (ulong)&sx1507q_device_data }, + { .compatible = "semtech,sx1508q", + .data = (ulong)&sx1508q_device_data }, + { .compatible = "semtech,sx1509q", + .data = (ulong)&sx1509q_device_data }, + {}, +}; + +static const struct pinconf_param sx150x_conf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "output", PIN_CONFIG_OUTPUT, 0 }, +}; + +static int sx150x_pinctrl_get_pins_count(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + + return pctl->data->ngpios; +} + +static const char *sx150x_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + static char pin_name[PINNAME_SIZE]; + + snprintf(pin_name, PINNAME_SIZE, "%s", pctl->data->pins[selector].name); + return pin_name; +} + +static int sx150x_pinctrl_conf_set(struct udevice *dev, unsigned int pin, + unsigned int param, unsigned int arg) +{ + int ret; + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + + if (sx150x_pin_is_oscio(pctl, pin)) { + if (param == PIN_CONFIG_OUTPUT) { + ret = sx150x_gpio_direction_output(pctl->gpio, pin, + arg); + if (ret < 0) + return ret; + } else { + return -EOPNOTSUPP; + } + } + + switch (param) { + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + case PIN_CONFIG_BIAS_DISABLE: + ret = sx150x_write_bits(pctl, pctl->data->reg_pulldn, BIT(pin), + 0); + if (ret < 0) + return ret; + + ret = sx150x_write_bits(pctl, pctl->data->reg_pullup, BIT(pin), + 0); + if (ret < 0) + return ret; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + ret = sx150x_write_bits(pctl, pctl->data->reg_pullup, BIT(pin), + BIT(pin)); + if (ret < 0) + return ret; + + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = sx150x_write_bits(pctl, pctl->data->reg_pulldn, BIT(pin), + BIT(pin)); + if (ret < 0) + return ret; + break; + + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (pctl->data->model != SX150X_789 || + sx150x_pin_is_oscio(pctl, pin)) + return -EOPNOTSUPP; + + ret = sx150x_write_bits(pctl, pctl->data->pri.x789.reg_drain, + BIT(pin), BIT(pin)); + if (ret < 0) + return ret; + + break; + + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (pctl->data->model != SX150X_789 || + sx150x_pin_is_oscio(pctl, pin)) + return 0; + + ret = sx150x_write_bits(pctl, pctl->data->pri.x789.reg_drain, + BIT(pin), 0); + if (ret < 0) + return ret; + + break; + + case PIN_CONFIG_OUTPUT: + ret = sx150x_gpio_direction_output(pctl->gpio, pin, arg); + if (ret < 0) + return ret; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int sx150x_pinctrl_bind(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_plat(dev); + int ret, reg; + + if (!dev_read_bool(dev, "gpio-controller")) + return 0; + + reg = (int)dev_read_addr_ptr(dev); + + ret = device_bind(dev, &sx150x_gpio_driver, dev_read_name(dev), NULL, + dev_ofnode(dev), &pctl->gpio); + if (ret) + return ret; + + return 0; +} + +static int sx150x_pinctrl_probe(struct udevice *dev) +{ + struct sx150x_pinctrl_priv *pctl = dev_get_priv(dev); + const struct sx150x_device_data *drv_data = + (const struct sx150x_device_data *)dev_get_driver_data(dev); + int ret, reg; + + if (!drv_data) + return -ENOENT; + + pctl->data = drv_data; + + reg = (int)dev_read_addr_ptr(dev); + ret = dm_i2c_probe(dev->parent, reg, 0, &pctl->i2c); + if (ret) { + err("Cannot find I2C chip %02x (%d)", reg, ret); + return ret; + } + + ret = sx150x_init_hw(dev); + if (ret) { + err("Cannot initialize GPIO expander at %02x with %d", reg, + ret); + return ret; + } + + snprintf(pctl->name, 32, "gpio-ext@%x_", reg); + + return 0; +} + +static struct pinctrl_ops sx150x_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_pins_count = sx150x_pinctrl_get_pins_count, + .get_pin_name = sx150x_pinctrl_get_pin_name, +#if CONFIG_IS_ENABLED(PINCONF) + .pinconf_set = sx150x_pinctrl_conf_set, + .pinconf_num_params = ARRAY_SIZE(sx150x_conf_params), + .pinconf_params = sx150x_conf_params, +#endif +}; + +U_BOOT_DRIVER(sx150x_pinctrl) = { + .name = "sx150x-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = sx150x_pinctrl_of_match, + .priv_auto = sizeof(struct sx150x_pinctrl_priv), + .ops = &sx150x_pinctrl_ops, + .probe = sx150x_pinctrl_probe, + .bind = sx150x_pinctrl_bind, +}; diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c new file mode 100644 index 00000000000..be7e508f8a4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl driver for the T-Head TH1520 SoC + * + * Copyright (C) 2023 Emil Renner Berthing <emil.renner.berthing@canonical.com> + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/string.h> +#include <malloc.h> + +#define TH1520_PADCFG_IE BIT(9) +#define TH1520_PADCFG_SL BIT(8) +#define TH1520_PADCFG_ST BIT(7) +#define TH1520_PADCFG_SPU BIT(6) +#define TH1520_PADCFG_PS BIT(5) +#define TH1520_PADCFG_PE BIT(4) +#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) +#define TH1520_PADCFG_DS GENMASK(3, 0) + +#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ +#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ +#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ + +#define TH1520_PAD_NO_PADCFG BIT(0) + +enum th1520_muxtype { + TH1520_MUX_____, + TH1520_MUX_GPIO, + TH1520_MUX_PWM, + TH1520_MUX_UART, + TH1520_MUX_IR, + TH1520_MUX_I2C, + TH1520_MUX_SPI, + TH1520_MUX_QSPI, + TH1520_MUX_SDIO, + TH1520_MUX_AUD, + TH1520_MUX_I2S, + TH1520_MUX_MAC0, + TH1520_MUX_MAC1, + TH1520_MUX_DPU0, + TH1520_MUX_DPU1, + TH1520_MUX_ISP, + TH1520_MUX_HDMI, + TH1520_MUX_BSEL, + TH1520_MUX_DBG, + TH1520_MUX_CLK, + TH1520_MUX_JTAG, + TH1520_MUX_ISO, + TH1520_MUX_FUSE, + TH1520_MUX_RST, +}; + +static const char *const th1520_muxtype_string[] = { + [TH1520_MUX_GPIO] = "gpio", + [TH1520_MUX_PWM] = "pwm", + [TH1520_MUX_UART] = "uart", + [TH1520_MUX_IR] = "ir", + [TH1520_MUX_I2C] = "i2c", + [TH1520_MUX_SPI] = "spi", + [TH1520_MUX_QSPI] = "qspi", + [TH1520_MUX_SDIO] = "sdio", + [TH1520_MUX_AUD] = "audio", + [TH1520_MUX_I2S] = "i2s", + [TH1520_MUX_MAC0] = "gmac0", + [TH1520_MUX_MAC1] = "gmac1", + [TH1520_MUX_DPU0] = "dpu0", + [TH1520_MUX_DPU1] = "dpu1", + [TH1520_MUX_ISP] = "isp", + [TH1520_MUX_HDMI] = "hdmi", + [TH1520_MUX_BSEL] = "bootsel", + [TH1520_MUX_DBG] = "debug", + [TH1520_MUX_CLK] = "clock", + [TH1520_MUX_JTAG] = "jtag", + [TH1520_MUX_ISO] = "iso7816", + [TH1520_MUX_FUSE] = "efuse", + [TH1520_MUX_RST] = "reset", +}; + +struct th1520_pin_desc { + unsigned int number; + const char *name; + enum th1520_muxtype muxes[6]; + u8 flags; +}; + +struct th1520_pad_group { + unsigned int npins; + const struct th1520_pin_desc *pins; + const char *name; +}; + +struct th1520_pinctrl { + const struct th1520_pad_group *group; + void __iomem *base; + struct pinctrl_dev *pctl; +}; + +static enum th1520_muxtype th1520_muxtype_get(const char *str) +{ + enum th1520_muxtype mt; + + for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { + if (!strcmp(str, th1520_muxtype_string[mt])) + return mt; + } + return TH1520_MUX_____; +} + +#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ + { \ + .number = _nr, \ + .name = #_name, \ + .muxes = { \ + TH1520_MUX_##m0, TH1520_MUX_##m1, \ + TH1520_MUX_##m2, TH1520_MUX_##m3, \ + TH1520_MUX_##m4, TH1520_MUX_##m5 \ + }, \ + .flags = _flags, \ + } + +static bool th1520_pad_no_padcfg(const struct th1520_pin_desc *pin) +{ + return pin->flags & TH1520_PAD_NO_PADCFG; +} + +static const struct th1520_pin_desc th1520_group1_pins[] = { + TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + /* skip number 5 so we can calculate register offsets and shifts from the pin number */ + TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group2_pins[] = { + TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), + TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), + TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), + TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(38, GPIO1_6, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(53, GPIO1_21, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(54, GPIO1_22, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(55, GPIO1_23, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(56, GPIO1_24, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(57, GPIO1_25, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), +}; + +static const struct th1520_pin_desc th1520_group3_pins[] = { + TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), + TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pad_group th1520_group1 = { + .name = "th1520-group1", + .pins = th1520_group1_pins, + .npins = ARRAY_SIZE(th1520_group1_pins), +}; + +static const struct th1520_pad_group th1520_group2 = { + .name = "th1520-group2", + .pins = th1520_group2_pins, + .npins = ARRAY_SIZE(th1520_group2_pins), +}; + +static const struct th1520_pad_group th1520_group3 = { + .name = "th1520-group3", + .pins = th1520_group3_pins, + .npins = ARRAY_SIZE(th1520_group3_pins), +}; + +static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 4 * (pin / 2); +} + +static unsigned int th1520_padcfg_shift(unsigned int pin) +{ + return 16 * (pin & BIT(0)); +} + +static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 0x400 + 4 * (pin / 8); +} + +static unsigned int th1520_muxcfg_shift(unsigned int pin) +{ + return 4 * (pin & GENMASK(2, 0)); +} + +static const u8 th1520_drive_strength_in_ma[16] = { + 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, +}; + +static u16 th1520_drive_strength_from_ma(u32 arg) +{ + u16 ds; + + for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { + if (arg <= th1520_drive_strength_in_ma[ds]) + return ds; + } + return TH1520_PADCFG_DS; +} + +static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, + u32 mask, u32 value) +{ + void __iomem *padcfg = th1520_padcfg(thp, pin); + unsigned int shift = th1520_padcfg_shift(pin); + u32 tmp; + + mask <<= shift; + value <<= shift; + + tmp = readl_relaxed(padcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, padcfg); + + return 0; +} + +static int th1520_pinconf_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum pin_config_param param, u32 arg) + +{ + u16 mask = 0, value = 0; + + if (th1520_pad_no_padcfg(desc)) + return -EOPNOTSUPP; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + value |= TH1520_PADCFG_PE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (arg == 0) + return -EOPNOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + if (arg == TH1520_PULL_STRONG_OHM) + value |= TH1520_PADCFG_SPU; + else + value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + mask |= TH1520_PADCFG_DS; + value &= ~TH1520_PADCFG_DS; + value |= th1520_drive_strength_from_ma(arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + mask |= TH1520_PADCFG_IE; + if (arg) + value |= TH1520_PADCFG_IE; + else + value &= ~TH1520_PADCFG_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask |= TH1520_PADCFG_ST; + if (arg) + value |= TH1520_PADCFG_ST; + else + value &= ~TH1520_PADCFG_ST; + break; + case PIN_CONFIG_SLEW_RATE: + mask |= TH1520_PADCFG_SL; + if (arg) + value |= TH1520_PADCFG_SL; + else + value &= ~TH1520_PADCFG_SL; + break; + default: + return -EOPNOTSUPP; + } + + return th1520_padcfg_rmw(thp, desc->number, mask, value); +} + +static int th1520_pinmux_apply_one(struct th1520_pinctrl *thp, + const struct th1520_pin_desc *desc, + enum th1520_muxtype muxtype) +{ + void __iomem *muxcfg = th1520_muxcfg(thp, desc->number); + unsigned int shift = th1520_muxcfg_shift(desc->number); + u32 mask, value, tmp; + + for (value = 0; value < ARRAY_SIZE(desc->muxes); value++) { + if (desc->muxes[value] == muxtype) + break; + } + if (value == ARRAY_SIZE(desc->muxes)) { + pr_err("invalid mux %s for pin \"%s\"\n", + th1520_muxtype_string[muxtype], desc->name); + return -EINVAL; + } + + mask = GENMASK(3, 0) << shift; + value = value << shift; + + tmp = readl_relaxed(muxcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, muxcfg); + + return 0; +} + +const struct pinconf_param th1520_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, +}; + +static const struct th1520_pin_desc * +th1520_pinctrl_search_pin(struct th1520_pinctrl *thp, + const char *name) +{ + const struct th1520_pad_group *pg = thp->group; + int i; + + for (i = 0; i < pg->npins; i++) { + if (!strcmp(pg->pins[i].name, name)) + return &pg->pins[i]; + } + + return NULL; +} + +static int th1520_pinctrl_apply_group(struct th1520_pinctrl *thp, ofnode group) +{ + struct th1520_pin_desc const **pins; + enum th1520_muxtype muxtype; + int pin_count, ret, i, j; + const char *muxname; + + pin_count = ofnode_read_string_count(group, "pins"); + if (pin_count < 0) { + pr_err("missing property pins"); + return -EINVAL; + } + + pins = calloc(pin_count, sizeof(pins[0])); + if (!pins) + return -ENOMEM; + + for (i = 0; i < pin_count; i++) { + const char *pinname; + + ret = ofnode_read_string_index(group, "pins", i, &pinname); + if (ret) + goto out; + + pins[i] = th1520_pinctrl_search_pin(thp, pinname); + if (!pins[i]) { + pr_err("unknown pin name \"%s\"\n", pinname); + goto out; + } + } + + for (i = 0; i < ARRAY_SIZE(th1520_pinconf_params); i++) { + const struct pinconf_param *param = &th1520_pinconf_params[i]; + u32 val; + + ret = ofnode_read_u32(group, param->property, &val); + if (ret == -EINVAL) + continue; + else if (ret) + val = param->default_value; + + for (j = 0; j < pin_count; j++) { + ret = th1520_pinconf_apply_one(thp, pins[j], + param->param, val); + if (ret) { + pr_err("failed to apply pinconf for \"%s\": %d\n", + pins[j]->name, ret); + goto out; + } + } + } + + muxname = ofnode_read_string(group, "function"); + if (!muxname) + goto out; + + muxtype = th1520_muxtype_get(muxname); + if (!muxtype) { + pr_err("invalid mux type \"%s\"", muxname); + ret = -EINVAL; + goto out; + } + + for (i = 0; i < pin_count; i++) { + ret = th1520_pinmux_apply_one(thp, pins[i], muxtype); + if (ret) { + pr_err("failed to set pinmux function: %d\n", ret); + break; + } + } + +out: + free(pins); + + return ret; +} + +static int th1520_pinctrl_set_state(struct udevice *dev, struct udevice *pcfg) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + ofnode group; + int ret = 0; + + dev_for_each_subnode(group, pcfg) { + ret = th1520_pinctrl_apply_group(thp, group); + if (ret) { + pr_err("failed to apply pin group \"%s\": %d\n", + ofnode_get_name(group), ret); + break; + } + } + + return ret; +} + +static int th1520_pinctrl_get_pins_count(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + + return thp->group->npins; +} + +static const char *th1520_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct th1520_pinctrl *p = dev_get_priv(dev); + + if (selector >= p->group->npins) + return ERR_PTR(-EINVAL); + + return p->group->pins[selector].name; +} + +static int th1520_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + const struct th1520_pad_group *group = thp->group; + const struct th1520_pin_desc *desc; + void __iomem *muxcfg; + unsigned int shift; + u32 val; + + if (selector >= group->npins) + return -EINVAL; + + desc = &group->pins[selector]; + if (th1520_pad_no_padcfg(desc)) { + strlcpy(buf, "unsupported", size - 1); + return 0; + } + + muxcfg = th1520_muxcfg(thp, desc->number); + shift = th1520_muxcfg_shift(desc->number); + + val = (readl_relaxed(muxcfg) >> shift) & GENMASK(3, 0); + strlcpy(buf, th1520_muxtype_string[desc->muxes[val]], size); + + return 0; +} + +static const struct pinctrl_ops th1520_pinctrl_ops = { + .get_pins_count = th1520_pinctrl_get_pins_count, + .get_pin_name = th1520_pinctrl_get_pin_name, + .get_pin_muxing = th1520_pinctrl_get_pin_muxing, + .set_state = th1520_pinctrl_set_state, +}; + +static int th1520_pinctrl_probe(struct udevice *dev) +{ + struct th1520_pinctrl *thp = dev_get_priv(dev); + struct clk clk; + u32 pin_group; + int ret; + + thp->base = dev_read_addr_ptr(dev); + if (!thp->base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) { + pr_err("failed to enable pinctrl clock: %d\n", ret); + return ret; + } + + ret = dev_read_u32(dev, "thead,pad-group", &pin_group); + if (ret) { + pr_err("failed to read thead,pad-group property: %d\n", ret); + return ret; + } + + switch (pin_group) { + case 1: + thp->group = &th1520_group1; + break; + case 2: + thp->group = &th1520_group2; + break; + case 3: + thp->group = &th1520_group3; + break; + default: + pr_err("invalid thead,pad-group property: %u\n", pin_group); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id th1520_pinctrl_ids[] = { + { .compatible = "thead,th1520-pinctrl"}, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(th1520_pinctrl) = { + .name = "th1520-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = th1520_pinctrl_ids, + .probe = th1520_pinctrl_probe, + .priv_auto = sizeof(struct th1520_pinctrl), + .ops = &th1520_pinctrl_ops, +}; diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index e567cb113a3..21f81b66099 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -27,6 +27,13 @@ config PINCTRL_QCOM_IPQ4019 Say Y here to enable support for pinctrl on the IPQ4019 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_IPQ5424 + bool "Qualcomm IPQ5424 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the IPQ5424 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_IPQ9574 bool "Qualcomm IPQ9574 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 6ffc6d48c15..6cb53838e71 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PINCTRL_QCOM) += pinctrl-qcom.o obj-$(CONFIG_PINCTRL_QCOM_APQ8016) += pinctrl-apq8016.o obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o +obj-$(CONFIG_PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5424.c b/drivers/pinctrl/qcom/pinctrl-ipq5424.c new file mode 100644 index 00000000000..cde990a32ef --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq5424.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +enum ipq5424_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_tic, + msm_mux_audio_pri, + msm_mux_audio_pri0, + msm_mux_audio_pri1, + msm_mux_audio_sec, + msm_mux_audio_sec0, + msm_mux_audio_sec1, + msm_mux_core_voltage, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_cxc_clk, + msm_mux_cxc_data, + msm_mux_dbg_out, + msm_mux_gcc_plltest, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_i2c0_scl, + msm_mux_i2c0_sda, + msm_mux_i2c1_scl, + msm_mux_i2c1_sda, + msm_mux_i2c11, + msm_mux_mac0, + msm_mux_mac1, + msm_mux_mdc_mst, + msm_mux_mdc_slv, + msm_mux_mdio_mst, + msm_mux_mdio_slv, + msm_mux_pcie0_clk, + msm_mux_pcie0_wake, + msm_mux_pcie1_clk, + msm_mux_pcie1_wake, + msm_mux_pcie2_clk, + msm_mux_pcie2_wake, + msm_mux_pcie3_clk, + msm_mux_pcie3_wake, + msm_mux_pll_test, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_PTA0_0, + msm_mux_PTA0_1, + msm_mux_PTA0_2, + msm_mux_PTA10, + msm_mux_PTA11, + msm_mux_pwm0, + msm_mux_pwm1, + msm_mux_pwm2, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_qdss_traceclk_a, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracedata_a, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data, + msm_mux_resout, + msm_mux_rx0, + msm_mux_rx1, + msm_mux_rx2, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_data, + msm_mux_spi0_clk, + msm_mux_spi0_cs, + msm_mux_spi0_miso, + msm_mux_spi0_mosi, + msm_mux_spi1, + msm_mux_spi10, + msm_mux_spi11, + msm_mux_tsens_max, + msm_mux_uart0, + msm_mux_uart1, + msm_mux_wci_txd, + msm_mux_wci_rxd, + msm_mux_wsi_clk, + msm_mux_wsi_data, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function ipq5424_functions[] = { + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_tic), + MSM_PIN_FUNCTION(audio_pri), + MSM_PIN_FUNCTION(audio_pri0), + MSM_PIN_FUNCTION(audio_pri1), + MSM_PIN_FUNCTION(audio_sec), + MSM_PIN_FUNCTION(audio_sec0), + MSM_PIN_FUNCTION(audio_sec1), + MSM_PIN_FUNCTION(core_voltage), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(cri_trng2), + MSM_PIN_FUNCTION(cri_trng3), + MSM_PIN_FUNCTION(cxc_clk), + MSM_PIN_FUNCTION(cxc_data), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(gcc_plltest), + MSM_PIN_FUNCTION(gcc_tlmm), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(i2c0_scl), + MSM_PIN_FUNCTION(i2c0_sda), + MSM_PIN_FUNCTION(i2c1_scl), + MSM_PIN_FUNCTION(i2c1_sda), + MSM_PIN_FUNCTION(i2c11), + MSM_PIN_FUNCTION(mac0), + MSM_PIN_FUNCTION(mac1), + MSM_PIN_FUNCTION(mdc_mst), + MSM_PIN_FUNCTION(mdc_slv), + MSM_PIN_FUNCTION(mdio_mst), + MSM_PIN_FUNCTION(mdio_slv), + MSM_PIN_FUNCTION(pcie0_clk), + MSM_PIN_FUNCTION(pcie0_wake), + MSM_PIN_FUNCTION(pcie1_clk), + MSM_PIN_FUNCTION(pcie1_wake), + MSM_PIN_FUNCTION(pcie2_clk), + MSM_PIN_FUNCTION(pcie2_wake), + MSM_PIN_FUNCTION(pcie3_clk), + MSM_PIN_FUNCTION(pcie3_wake), + MSM_PIN_FUNCTION(pll_test), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(PTA0_0), + MSM_PIN_FUNCTION(PTA0_1), + MSM_PIN_FUNCTION(PTA0_2), + MSM_PIN_FUNCTION(PTA10), + MSM_PIN_FUNCTION(PTA11), + MSM_PIN_FUNCTION(pwm0), + MSM_PIN_FUNCTION(pwm1), + MSM_PIN_FUNCTION(pwm2), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), + MSM_PIN_FUNCTION(qdss_traceclk_a), + MSM_PIN_FUNCTION(qdss_tracectl_a), + MSM_PIN_FUNCTION(qdss_tracedata_a), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(resout), + MSM_PIN_FUNCTION(rx0), + MSM_PIN_FUNCTION(rx1), + MSM_PIN_FUNCTION(rx2), + MSM_PIN_FUNCTION(sdc_clk), + MSM_PIN_FUNCTION(sdc_cmd), + MSM_PIN_FUNCTION(sdc_data), + MSM_PIN_FUNCTION(spi0_clk), + MSM_PIN_FUNCTION(spi0_cs), + MSM_PIN_FUNCTION(spi0_miso), + MSM_PIN_FUNCTION(spi0_mosi), + MSM_PIN_FUNCTION(spi1), + MSM_PIN_FUNCTION(spi10), + MSM_PIN_FUNCTION(spi11), + MSM_PIN_FUNCTION(tsens_max), + MSM_PIN_FUNCTION(uart0), + MSM_PIN_FUNCTION(uart1), + MSM_PIN_FUNCTION(wci_txd), + MSM_PIN_FUNCTION(wci_rxd), + MSM_PIN_FUNCTION(wsi_clk), + MSM_PIN_FUNCTION(wsi_data), +}; + +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\ + [id] = { msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + } + +static const msm_pin_function ipq5424_pin_functions[] = { + PINGROUP(0, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs, _, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), + PINGROUP(6, spi0_clk, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _, _), + PINGROUP(7, spi0_cs, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _, _), + PINGROUP(8, spi0_miso, pwm1, wci_txd, wci_rxd, _, cri_trng2, qdss_tracedata_a, _, _), + PINGROUP(9, spi0_mosi, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _, _), + PINGROUP(10, uart0, pwm0, spi11, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(11, uart0, pwm0, spi1, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(12, uart0, pwm0, spi11, _, prng_rosc0, qdss_tracedata_a, _, _, _), + PINGROUP(13, uart0, pwm0, spi11, _, prng_rosc1, qdss_tracedata_a, _, _, _), + PINGROUP(14, i2c0_scl, tsens_max, _, prng_rosc2, qdss_tracedata_a, _, _, _, _), + PINGROUP(15, i2c0_sda, _, prng_rosc3, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(16, core_voltage, i2c1_scl, _, _, _, _, _, _, _), + PINGROUP(17, core_voltage, i2c1_sda, _, _, _, _, _, _, _), + PINGROUP(18, _, _, _, _, _, _, _, _, _), + PINGROUP(19, _, _, _, _, _, _, _, _, _), + PINGROUP(20, mdc_slv, atest_char0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(21, mdio_slv, atest_char1, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(22, mdc_mst, atest_char2, _, _, _, _, _, _, _), + PINGROUP(23, mdio_mst, atest_char3, _, _, _, _, _, _, _), + PINGROUP(24, pcie0_clk, PTA10, mac0, _, wsi_clk, _, atest_char, qdss_cti_trig_out_a0, _), + PINGROUP(25, _, _, _, _, _, _, _, _, _), + PINGROUP(26, pcie0_wake, PTA10, mac0, _, wsi_data, _, qdss_cti_trig_in_a0, _, _), + PINGROUP(27, pcie1_clk, i2c11, PTA10, wsi_clk, qdss_cti_trig_out_a1, _, _, _, _), + PINGROUP(28, _, _, _, _, _, _, _, _, _), + PINGROUP(29, pcie1_wake, i2c11, wsi_data, qdss_cti_trig_in_a1, _, _, _, _, _), + PINGROUP(30, pcie2_clk, PTA11, mac1, qdss_cti_trig_out_b0, _, _, _, _, _), + PINGROUP(31, _, _, _, _, _, _, _, _, _), + PINGROUP(32, pcie2_wake, PTA11, mac1, audio_pri0, audio_pri0, qdss_cti_trig_in_b0, _, _, _), + PINGROUP(33, pcie3_clk, PTA11, audio_pri1, audio_pri1, qdss_cti_trig_out_b1, _, _, _, _), + PINGROUP(34, _, _, _, _, _, _, _, _, _), + PINGROUP(35, pcie3_wake, audio_sec1, audio_sec1, qdss_cti_trig_in_b1, _, _, _, _, _), + PINGROUP(36, audio_pri, spi1, audio_sec0, audio_sec0, qdss_tracedata_a, _, _, _, _), + PINGROUP(37, audio_pri, spi1, rx2, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(38, audio_pri, spi1, pll_test, rx1, qdss_tracedata_a, _, _, _, _), + PINGROUP(39, audio_pri, rx0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(40, PTA0_0, wci_txd, wci_rxd, _, atest_tic, _, _, _, _), + PINGROUP(41, PTA0_1, wci_txd, wci_rxd, cxc_data, _, _, _, _, _), + PINGROUP(42, PTA0_2, cxc_clk, _, _, _, _, _, _, _), + PINGROUP(43, uart1, gcc_plltest, _, _, _, _, _, _, _), + PINGROUP(44, uart1, gcc_tlmm, _, _, _, _, _, _, _), + PINGROUP(45, spi10, rx2, audio_sec, gcc_plltest, _, qdss_traceclk_a, _, _, _), + PINGROUP(46, spi1, rx1, audio_sec, dbg_out, qdss_tracectl_a, _, _, _, _), + PINGROUP(47, spi10, rx0, audio_sec, _, _, _, _, _, _), + PINGROUP(48, spi10, audio_sec, _, _, _, _, _, _, _), + PINGROUP(49, resout, _, _, _, _, _, _, _, _), +}; + +static const char *ipq5424_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return ipq5424_functions[selector].name; +} + +static const char *ipq5424_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + return pin_name; +} + +static int ipq5424_get_function_mux(unsigned int pin, unsigned int selector) +{ + unsigned int i; + const msm_pin_function *func = ipq5424_pin_functions + pin; + + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + debug("Can't find requested function for pin:selector %u:%u\n", + pin, selector); + + return -EINVAL; +} + +static const struct msm_pinctrl_data ipq5424_data = { + .pin_data = { + .pin_count = 49, + }, + .functions_count = ARRAY_SIZE(ipq5424_functions), + .get_function_name = ipq5424_get_function_name, + .get_function_mux = ipq5424_get_function_mux, + .get_pin_name = ipq5424_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,ipq5424-tlmm", .data = (ulong)&ipq5424_data }, + { /* Sentinal */ } +}; + +U_BOOT_DRIVER(pinctrl_ipq5424) = { + .name = "pinctrl_ipq5424", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, + .flags = DM_FLAG_PRE_RELOC, +}; |