[PATCH 02/14] pinctrl: add Microchip LAN969x driver
Robert Marko
robert.marko at sartura.hr
Thu Mar 26 12:26:43 CET 2026
Add pinctrl, pinconf and GPIO driver for Microchip LAN969x.
This is updated version of the vendor U-Boot driver to include all
pinmux functions supported in Linux as well as printing the current
pinmux as set in the SoC.
Signed-off-by: Robert Marko <robert.marko at sartura.hr>
---
drivers/pinctrl/Kconfig | 8 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-lan969x.c | 582 ++++++++++++++++++++++++++++++
3 files changed, 591 insertions(+)
create mode 100644 drivers/pinctrl/pinctrl-lan969x.c
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ea90713ec6c..b962c61c8ea 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -227,6 +227,14 @@ config PINCTRL_INTEL
driver which must be separately enabled. The driver supports setting
pins on start-up and changing the GPIO attributes.
+config PINCTRL_LAN969X
+ bool "Microchip LAN969X pinctrl driver"
+ depends on DM && TARGET_LAN969X
+ select PINCONF
+ select REGMAP
+ help
+ This option is to enable the LAN969X pinctrl driver.
+
config PINCTRL_PIC32
bool "Microchip PIC32 pin-control and pin-mux driver"
depends on DM && MACH_PIC32
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 33ff7b95ef2..d0c46268673 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_$(PHASE_)PINCTRL_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_ARCH_ATH79) += ath79/
obj-$(CONFIG_PINCTRL_INTEL) += intel/
+obj-$(CONFIG_PINCTRL_LAN969X) += pinctrl-lan969x.o
obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
obj-$(CONFIG_ARCH_NPCM) += nuvoton/
obj-$(CONFIG_PINCTRL_QCOM) += qcom/
diff --git a/drivers/pinctrl/pinctrl-lan969x.c b/drivers/pinctrl/pinctrl-lan969x.c
new file mode 100644
index 00000000000..70e66193ddd
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-lan969x.c
@@ -0,0 +1,582 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+#include <asm/gpio.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/device-internal.h>
+#include <dm/pinctrl.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <regmap.h>
+
+/* GPIO standard registers */
+#define LAN969X_FUNC_PER_PIN 8
+
+/* GPIO standard registers */
+#define LAN969X_GPIO_OUT_SET 0x0
+#define LAN969X_GPIO_OUT_CLR 0x4
+#define LAN969X_GPIO_OUT 0x8
+#define LAN969X_GPIO_IN 0xc
+#define LAN969X_GPIO_OE 0x10
+#define LAN969X_GPIO_INTR 0x14
+#define LAN969X_GPIO_INTR_ENA 0x18
+#define LAN969X_GPIO_INTR_IDENT 0x1c
+#define LAN969X_GPIO_ALT0 0x20
+#define LAN969X_GPIO_ALT1 0x24
+#define LAN969X_GPIO_ALT2 0x28
+#define LAN969X_GPIO_SD_MAP 0x2c
+
+enum {
+ FUNC_CAN0_a,
+ FUNC_CAN0_b,
+ FUNC_CAN1,
+ FUNC_CLKMON,
+ FUNC_NONE,
+ FUNC_FAN,
+ FUNC_FC,
+ FUNC_FC_SHRD,
+ FUNC_FUSA,
+ FUNC_GPIO,
+ FUNC_IRQ0,
+ FUNC_IRQ1,
+ FUNC_IRQ3,
+ FUNC_IRQ4,
+ FUNC_MIIM,
+ FUNC_MIIM_Sa,
+ FUNC_MIIM_IRQ,
+ FUNC_PCIE_PERST,
+ FUNC_PTPSYNC_0,
+ FUNC_PTPSYNC_1,
+ FUNC_PTPSYNC_2,
+ FUNC_PTPSYNC_3,
+ FUNC_PTPSYNC_4,
+ FUNC_PTPSYNC_5,
+ FUNC_PTPSYNC_6,
+ FUNC_PTPSYNC_7,
+ FUNC_QSPI1,
+ FUNC_R,
+ FUNC_SD,
+ FUNC_SFP_SD,
+ FUNC_SGPIO_a,
+ FUNC_SYNCE,
+ FUNC_TWI,
+ FUNC_USB_POWER,
+ FUNC_USB2PHY_RST,
+ FUNC_USB_OVER_DETECT,
+ FUNC_USB_ULPI,
+ FUNC_EMMC_SD,
+ FUNC_MAX
+};
+
+static const char *const lan969x_function_names[FUNC_MAX] = {
+ [FUNC_CAN0_a] = "can0_a",
+ [FUNC_CAN0_b] = "can0_b",
+ [FUNC_CAN1] = "can1",
+ [FUNC_CLKMON] = "clkmon",
+ [FUNC_NONE] = "none",
+ [FUNC_FAN] = "fan",
+ [FUNC_FC] = "fc",
+ [FUNC_FC_SHRD] = "fc_shrd",
+ [FUNC_FUSA] = "fusa",
+ [FUNC_GPIO] = "gpio",
+ [FUNC_IRQ0] = "irq0",
+ [FUNC_IRQ1] = "irq1",
+ [FUNC_IRQ3] = "irq3",
+ [FUNC_IRQ4] = "irq4",
+ [FUNC_MIIM] = "miim",
+ [FUNC_MIIM_Sa] = "miim_slave_a",
+ [FUNC_MIIM_IRQ] = "miim_irq",
+ [FUNC_PCIE_PERST] = "pcie_perst",
+ [FUNC_PTPSYNC_0] = "ptpsync_0",
+ [FUNC_PTPSYNC_1] = "ptpsync_1",
+ [FUNC_PTPSYNC_2] = "ptpsync_2",
+ [FUNC_PTPSYNC_3] = "ptpsync_3",
+ [FUNC_PTPSYNC_4] = "ptpsync_4",
+ [FUNC_PTPSYNC_5] = "ptpsync_5",
+ [FUNC_PTPSYNC_6] = "ptpsync_6",
+ [FUNC_PTPSYNC_7] = "ptpsync_7",
+ [FUNC_QSPI1] = "qspi1",
+ [FUNC_R] = "reserved",
+ [FUNC_SD] = "sd",
+ [FUNC_SFP_SD] = "sfp_sd",
+ [FUNC_SGPIO_a] = "sgpio_a",
+ [FUNC_SYNCE] = "synce",
+ [FUNC_TWI] = "twi",
+ [FUNC_USB_POWER] = "usb_power",
+ [FUNC_USB2PHY_RST] = "usb2phy_rst",
+ [FUNC_USB_OVER_DETECT] = "usb_over_detect",
+ [FUNC_USB_ULPI] = "usb_ulpi",
+ [FUNC_EMMC_SD] = "emmc_sd",
+};
+
+struct lan969x_pin_caps {
+ unsigned int pin;
+ unsigned char functions[LAN969X_FUNC_PER_PIN];
+};
+
+struct lan969x_pin_data {
+ const char *name;
+ struct lan969x_pin_caps *drv_data;
+};
+
+#define LAN969X_P(p, f0, f1, f2, f3, f4, f5, f6, f7) \
+static struct lan969x_pin_caps lan969x_pin_##p = { \
+ .pin = p, \
+ .functions = { \
+ FUNC_##f0, FUNC_##f1, FUNC_##f2, \
+ FUNC_##f3, FUNC_##f4, FUNC_##f5, \
+ FUNC_##f6, FUNC_##f7 \
+ }, \
+}
+
+#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+
+struct lan969x_pmx_func {
+ const char **groups;
+ unsigned int ngroups;
+};
+
+struct lan969x_pinctrl {
+ struct udevice *dev;
+ struct pinctrl_dev *pctl;
+ struct regmap *map;
+ void __iomem *pincfg;
+ struct lan969x_pmx_func *func;
+ int num_func;
+ const struct lan969x_pin_data *lan969x_pins;
+ int num_pins;
+ const char * const *function_names;
+ const unsigned long *lan969x_gpios;
+ u8 stride;
+};
+
+/* Pinmuxing table taken from data sheet */
+/* Pin FUNC0 FUNC1 FUNC2 FUNC3 FUNC4 FUNC5 FUNC6 FUNC7 */
+LAN969X_P(0, GPIO, IRQ0, FC_SHRD, PCIE_PERST, NONE, NONE, NONE, R);
+LAN969X_P(1, GPIO, IRQ1, FC_SHRD, USB_POWER, NONE, NONE, NONE, R);
+LAN969X_P(2, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(3, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(4, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(5, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(6, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(7, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(8, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(9, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(10, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(11, GPIO, MIIM_IRQ, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(12, GPIO, IRQ3, FC_SHRD, USB2PHY_RST, NONE, NONE, NONE, R);
+LAN969X_P(13, GPIO, IRQ4, FC_SHRD, USB_OVER_DETECT, NONE, NONE, NONE, R);
+LAN969X_P(14, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(15, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(16, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(17, GPIO, EMMC_SD, QSPI1, PTPSYNC_0, USB_POWER, NONE, NONE, R);
+LAN969X_P(18, GPIO, EMMC_SD, QSPI1, PTPSYNC_1, USB2PHY_RST, NONE, NONE, R);
+LAN969X_P(19, GPIO, EMMC_SD, QSPI1, PTPSYNC_2, USB_OVER_DETECT, NONE, NONE, R);
+LAN969X_P(20, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(21, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(22, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(23, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(24, GPIO, EMMC_SD, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(25, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R);
+LAN969X_P(26, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R);
+LAN969X_P(27, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R);
+LAN969X_P(28, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R);
+LAN969X_P(29, GPIO, SYNCE, FC, MIIM_IRQ, QSPI1, NONE, NONE, R);
+LAN969X_P(30, GPIO, PTPSYNC_0, USB_ULPI, FC_SHRD, QSPI1, NONE, NONE, R);
+LAN969X_P(31, GPIO, PTPSYNC_1, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(32, GPIO, PTPSYNC_2, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(33, GPIO, SD, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(34, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R);
+LAN969X_P(35, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R);
+LAN969X_P(36, GPIO, SD, USB_ULPI, PCIE_PERST, FC_SHRD, NONE, NONE, R);
+LAN969X_P(37, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R);
+LAN969X_P(38, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R);
+LAN969X_P(39, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R);
+LAN969X_P(40, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R);
+LAN969X_P(41, GPIO, SD, USB_ULPI, MIIM_IRQ, NONE, NONE, NONE, R);
+LAN969X_P(42, GPIO, PTPSYNC_3, CAN1, NONE, NONE, NONE, NONE, R);
+LAN969X_P(43, GPIO, PTPSYNC_4, CAN1, NONE, NONE, NONE, NONE, R);
+LAN969X_P(44, GPIO, PTPSYNC_5, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(45, GPIO, PTPSYNC_6, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(46, GPIO, PTPSYNC_7, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(47, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(48, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(49, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(50, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(51, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(52, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(53, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(54, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(55, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(56, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(57, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_3, NONE, NONE, R);
+LAN969X_P(58, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_4, NONE, NONE, R);
+LAN969X_P(59, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_5, NONE, NONE, R);
+LAN969X_P(60, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_6, NONE, NONE, R);
+LAN969X_P(61, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(62, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(63, GPIO, MIIM_IRQ, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(64, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(65, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(66, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+
+#define LAN969X_PIN(n) { \
+ .name = "GPIO_"#n, \
+ .drv_data = &lan969x_pin_##n \
+}
+
+static const struct lan969x_pin_data lan969x_pins[] = {
+ LAN969X_PIN(0),
+ LAN969X_PIN(1),
+ LAN969X_PIN(2),
+ LAN969X_PIN(3),
+ LAN969X_PIN(4),
+ LAN969X_PIN(5),
+ LAN969X_PIN(6),
+ LAN969X_PIN(7),
+ LAN969X_PIN(8),
+ LAN969X_PIN(9),
+ LAN969X_PIN(10),
+ LAN969X_PIN(11),
+ LAN969X_PIN(12),
+ LAN969X_PIN(13),
+ LAN969X_PIN(14),
+ LAN969X_PIN(15),
+ LAN969X_PIN(16),
+ LAN969X_PIN(17),
+ LAN969X_PIN(18),
+ LAN969X_PIN(19),
+ LAN969X_PIN(20),
+ LAN969X_PIN(21),
+ LAN969X_PIN(22),
+ LAN969X_PIN(23),
+ LAN969X_PIN(24),
+ LAN969X_PIN(25),
+ LAN969X_PIN(26),
+ LAN969X_PIN(27),
+ LAN969X_PIN(28),
+ LAN969X_PIN(29),
+ LAN969X_PIN(30),
+ LAN969X_PIN(31),
+ LAN969X_PIN(32),
+ LAN969X_PIN(33),
+ LAN969X_PIN(34),
+ LAN969X_PIN(35),
+ LAN969X_PIN(36),
+ LAN969X_PIN(37),
+ LAN969X_PIN(38),
+ LAN969X_PIN(39),
+ LAN969X_PIN(40),
+ LAN969X_PIN(41),
+ LAN969X_PIN(42),
+ LAN969X_PIN(43),
+ LAN969X_PIN(44),
+ LAN969X_PIN(45),
+ LAN969X_PIN(46),
+ LAN969X_PIN(47),
+ LAN969X_PIN(48),
+ LAN969X_PIN(49),
+ LAN969X_PIN(50),
+ LAN969X_PIN(51),
+ LAN969X_PIN(52),
+ LAN969X_PIN(53),
+ LAN969X_PIN(54),
+ LAN969X_PIN(55),
+ LAN969X_PIN(56),
+ LAN969X_PIN(57),
+ LAN969X_PIN(58),
+ LAN969X_PIN(59),
+ LAN969X_PIN(60),
+ LAN969X_PIN(61),
+ LAN969X_PIN(62),
+ LAN969X_PIN(63),
+ LAN969X_PIN(64),
+ LAN969X_PIN(65),
+ LAN969X_PIN(66),
+};
+
+static int lan969x_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ uc_priv->bank_name = "lan969x-gpio";
+ uc_priv->gpio_count = ARRAY_SIZE(lan969x_pins);
+
+ return 0;
+}
+
+static int lan969x_gpio_get(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+ unsigned int val;
+
+ regmap_read(info->map, REG(LAN969X_GPIO_IN, info, offset), &val);
+
+ return !!(val & BIT(offset % 32));
+}
+
+static int lan969x_gpio_set(struct udevice *dev, unsigned int offset, int value)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ if (value)
+ regmap_write(info->map, REG(LAN969X_GPIO_OUT_SET, info, offset),
+ BIT(offset % 32));
+ else
+ regmap_write(info->map, REG(LAN969X_GPIO_OUT_CLR, info, offset),
+ BIT(offset % 32));
+
+ return 0;
+}
+
+static int lan969x_gpio_get_direction(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+ unsigned int val;
+
+ regmap_read(info->map, REG(LAN969X_GPIO_OE, info, offset), &val);
+
+ if (val & BIT(offset % 32))
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static int lan969x_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ regmap_write(info->map, REG(LAN969X_GPIO_OE, info, offset),
+ ~BIT(offset % 32));
+
+ return 0;
+}
+
+static int lan969x_gpio_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ regmap_write(info->map, REG(LAN969X_GPIO_OE, info, offset),
+ BIT(offset % 32));
+
+ return lan969x_gpio_set(dev, offset, value);
+}
+
+const struct dm_gpio_ops lan969x_gpio_ops = {
+ .set_value = lan969x_gpio_set,
+ .get_value = lan969x_gpio_get,
+ .get_function = lan969x_gpio_get_direction,
+ .direction_input = lan969x_gpio_direction_input,
+ .direction_output = lan969x_gpio_direction_output,
+};
+
+static int lan969x_pctl_get_groups_count(struct udevice *dev)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->num_pins;
+}
+
+static const char *lan969x_pctl_get_group_name(struct udevice *dev,
+ unsigned int group)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->lan969x_pins[group].name;
+}
+
+static int lan969x_get_functions_count(struct udevice *dev)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->num_func;
+}
+
+static const char *lan969x_get_function_name(struct udevice *dev,
+ unsigned int function)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->function_names[function];
+}
+
+static int lan969x_pin_function_idx(unsigned int pin, unsigned int function,
+ const struct lan969x_pin_data *lan969x_pins)
+{
+ struct lan969x_pin_caps *p = lan969x_pins[pin].drv_data;
+ int i;
+
+ for (i = 0; i < LAN969X_FUNC_PER_PIN; i++) {
+ if (function == p->functions[i])
+ return i;
+ }
+
+ return -1;
+}
+
+#define REG_ALT(msb, info, p) (LAN969X_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
+
+static int lan969x_pinmux_set_mux(struct udevice *dev,
+ unsigned int pin_selector, unsigned int selector)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ struct lan969x_pin_caps *pin = info->lan969x_pins[pin_selector].drv_data;
+ unsigned int p = pin->pin % 32;
+ int f;
+
+ f = lan969x_pin_function_idx(pin_selector, selector, info->lan969x_pins);
+ if (f < 0)
+ return -EINVAL;
+
+ /*
+ * f is encoded on two bits.
+ * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of
+ * ALT[1], bit 2 of f goes in BIT(pin) of ALT[2]
+ * This is racy because both registers can't be updated at the same time
+ * but it doesn't matter much for now.
+ * Note: ALT0/ALT1/ALT2 are organized specially for 78 gpio targets
+ */
+ regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
+ BIT(p), f << p);
+ regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
+ BIT(p), (f >> 1) << p);
+ regmap_update_bits(info->map, REG_ALT(2, info, pin->pin),
+ BIT(p), (f >> 2) << p);
+
+ return 0;
+}
+
+/* Non-constant mask variant of FIELD_GET */
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+
+static int lan969x_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ struct lan969x_pin_caps *pin = info->lan969x_pins[selector].drv_data;
+ unsigned int alt0, alt1, alt2, function = 0;
+
+ regmap_read(info->map, REG_ALT(0, info, pin->pin), &alt0);
+ regmap_read(info->map, REG_ALT(1, info, pin->pin), &alt1);
+ regmap_read(info->map, REG_ALT(2, info, pin->pin), &alt2);
+
+ function |= FIELD_PREP(BIT(0), field_get(BIT(pin->pin), alt0));
+ function |= FIELD_PREP(BIT(1), field_get(BIT(pin->pin), alt1));
+ function |= FIELD_PREP(BIT(2), field_get(BIT(pin->pin), alt2));
+
+ snprintf(buf, size, "%s", lan969x_get_function_name(dev, pin->functions[function]));
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(PINCONF)
+static const struct pinconf_param lan969x_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, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+};
+
+static int lan969x_pinconf_set(struct udevice *dev, unsigned int pin,
+ unsigned int param, unsigned int arg)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ unsigned int val;
+ int err = 0;
+
+ if (info->pincfg == NULL)
+ return err;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = readl(info->pincfg + (pin * 4));
+ val &= ~(BIT(3) | BIT(2));
+ val |= (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
+ (param == PIN_CONFIG_BIAS_PULL_UP) ? BIT(3) : BIT(2);
+ writel(val, info->pincfg + (pin * 4));
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (arg <= 3) {
+ val = readl(info->pincfg + (pin * 4));
+ val &= ~GENMASK(1, 0);
+ val |= arg;
+ writel(val, info->pincfg + (pin * 4));
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -ENOTSUPP;
+ }
+
+ return err;
+}
+#endif
+
+const struct pinctrl_ops lan969x_pinctrl_ops = {
+ .get_pins_count = lan969x_pctl_get_groups_count,
+ .get_pin_name = lan969x_pctl_get_group_name,
+ .get_pin_muxing = lan969x_get_pin_muxing,
+ .get_functions_count = lan969x_get_functions_count,
+ .get_function_name = lan969x_get_function_name,
+ .pinmux_set = lan969x_pinmux_set_mux,
+ .set_state = pinctrl_generic_set_state,
+#if CONFIG_IS_ENABLED(PINCONF)
+ .pinconf_num_params = ARRAY_SIZE(lan969x_pinconf_params),
+ .pinconf_params = lan969x_pinconf_params,
+ .pinconf_set = lan969x_pinconf_set,
+#endif
+};
+
+static struct driver lan969x_gpio_driver = {
+ .name = "lan969x-gpio",
+ .id = UCLASS_GPIO,
+ .probe = lan969x_gpio_probe,
+ .ops = &lan969x_gpio_ops,
+};
+
+int lan969x_pinctrl_probe(struct udevice *dev)
+{
+ struct lan969x_pinctrl *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
+ if (ret)
+ return -EINVAL;
+
+ priv->pincfg = dev_remap_addr_index(dev, 1);
+
+ priv->func = devm_kzalloc(dev, FUNC_MAX * sizeof(struct lan969x_pmx_func), GFP_KERNEL);
+ priv->num_func = FUNC_MAX;
+ priv->function_names = lan969x_function_names;
+
+ priv->lan969x_pins = lan969x_pins;
+ priv->num_pins = ARRAY_SIZE(lan969x_pins);
+ priv->stride = 1 + (priv->num_pins - 1) / 32;
+
+ ret = device_bind(dev, &lan969x_gpio_driver, "lan969x-gpio", NULL,
+ dev_ofnode(dev), NULL);
+
+ return ret;
+}
+
+static const struct udevice_id lan969x_pinctrl_of_match[] = {
+ {.compatible = "microchip,lan9691-pinctrl"},
+ {},
+};
+
+U_BOOT_DRIVER(lan969x_pinctrl) = {
+ .name = "lan969x-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(lan969x_pinctrl_of_match),
+ .probe = lan969x_pinctrl_probe,
+ .priv_auto = sizeof(struct lan969x_pinctrl),
+ .ops = &lan969x_pinctrl_ops,
+};
--
2.53.0
More information about the U-Boot
mailing list