root/drivers/pinctrl/aspeed/pinctrl-aspeed-g7-soc1.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Pinctrl driver for Aspeed G7 SoC1
 *
 * Copyright (C) 2026 Aspeed Technology Inc.
 */

#include <linux/errno.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>

#include "../core.h"
#include "../pinconf.h"
#include "../pinctrl-utils.h"
#include "../pinmux.h"

#define ASPEED_G7_SOC1_NR_PINS 220
#define ASPEED_G7_SOC1_REG_WIDTH 32
#define ASPEED_G7_SOC1_REG_STRIDE 4

#define ASPEED_G7_SOC1_MUX_BASE          0x400
#define ASPEED_G7_SOC1_BIAS_BASE         0x480
#define ASPEED_G7_SOC1_DRV_BASE          0x4C0
#define ASPEED_G7_SOC1_PCIE_REG          0x908
#define ASPEED_G7_SOC1_USB_MODE_REG      0x3B0
#define ASPEED_G7_SOC1_SGMII_REG         0x47C

/*
 * Each pin occupies a 4-bit slot in the MUX registers (MUX_BITS_PER_PIN),
 * but only bits [2:0] select the mux function; bit 3 is reserved read-only
 * and must not be written.  MUX_FUNC_MASK therefore covers 3 bits, not 4.
 */
#define ASPEED_G7_SOC1_MUX_FUNC_MASK 0x7
#define ASPEED_G7_SOC1_MUX_BITS_PER_PIN 4
#define ASPEED_G7_SOC1_MUX_PINS_PER_REG \
        (ASPEED_G7_SOC1_REG_WIDTH / ASPEED_G7_SOC1_MUX_BITS_PER_PIN)

#define ASPEED_G7_SOC1_BIAS_FUNC_MASK 0x1
#define ASPEED_G7_SOC1_BIAS_BITS_PER_PIN 1
#define ASPEED_G7_SOC1_BIAS_PINS_PER_REG \
        (ASPEED_G7_SOC1_REG_WIDTH / ASPEED_G7_SOC1_BIAS_BITS_PER_PIN)

#define ASPEED_G7_SOC1_DRV_FUNC_MASK 0x3
#define ASPEED_G7_SOC1_DRV_BITS_PER_PIN 2
#define ASPEED_G7_SOC1_DRV_PINS_PER_REG \
        (ASPEED_G7_SOC1_REG_WIDTH / ASPEED_G7_SOC1_DRV_BITS_PER_PIN)

#define ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA 4
#define ASPEED_G7_SOC1_DRV_STRENGTH_HW_BASE 1
#define ASPEED_G7_SOC1_DRV_STRENGTH_MIN_MA \
        (ASPEED_G7_SOC1_DRV_STRENGTH_HW_BASE * ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA)
#define ASPEED_G7_SOC1_DRV_STRENGTH_MAX_MA \
        ((ASPEED_G7_SOC1_DRV_FUNC_MASK + ASPEED_G7_SOC1_DRV_STRENGTH_HW_BASE) * \
         ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA)

/*
 * NOTE: The numeric values of these enum entries are significant.
 * They must match the SoC GPIO numbering / ball-to-GPIO ID mapping.
 * Do not reorder alphabetically.
 */
enum {
        C16,
        C14,
        C11,
        D9,
        F14,
        D10,
        C12,
        C13,
        AC26,
        AA25,
        AB23,
        U22,
        V21,
        N26,
        P25,
        N25,
        V23,
        W22,
        AB26,
        AD26,
        P26,
        AE26,
        AF26,
        AF25,
        AE25,
        AD25,
        AF23,
        AF20,
        AF21,
        AE21,
        AE23,
        AD22,
        AF17,
        AA16,
        Y16,
        V17,
        J13,
        AB16,
        AC16,
        AF16,
        AA15,
        AB15,
        AC15,
        AD15,
        Y15,
        AA14,
        W16,
        V16,
        AB18,
        AC18,
        K13,
        AA17,
        AB17,
        AD16,
        AC17,
        AD17,
        AE16,
        AE17,
        AB24,
        W26,
        HOLE0,
        HOLE1,
        HOLE2,
        HOLE3,
        W25,
        Y23,
        Y24,
        W21,
        AA23,
        AC22,
        AB22,
        Y21,
        AE20,
        AF19,
        Y22,
        AA20,
        AA22,
        AB20,
        AF18,
        AE19,
        AD20,
        AC20,
        AA21,
        AB21,
        AC19,
        AE18,
        AD19,
        AD18,
        U25,
        U26,
        Y26,
        AA24,
        R25,
        AA26,
        R26,
        Y25,
        B16,
        D14,
        B15,
        B14,
        C17,
        B13,
        E14,
        C15,
        D24,
        B23,
        B22,
        C23,
        B18,
        B21,
        M15,
        B19,
        B26,
        A25,
        A24,
        B24,
        E26,
        A21,
        A19,
        A18,
        D26,
        C26,
        A23,
        A22,
        B25,
        F26,
        A26,
        A14,
        E10,
        E13,
        D12,
        F10,
        E11,
        F11,
        F13,
        N15,
        C20,
        C19,
        A8,
        R14,
        A7,
        P14,
        D20,
        A6,
        B6,
        N14,
        B7,
        B8,
        B9,
        M14,
        J11,
        E7,
        D19,
        B11,
        D15,
        B12,
        B10,
        P13,
        C18,
        C6,
        C7,
        D7,
        N13,
        C8,
        C9,
        C10,
        M16,
        A15,
        G11,
        H7,
        H8,
        H9,
        H10,
        H11,
        J9,
        J10,
        E9,
        F9,
        F8,
        M13,
        F7,
        D8,
        E8,
        L12,
        F12,
        E12,
        J12,
        G7,
        G8,
        G9,
        G10,
        K12,
        W17,
        V18,
        W18,
        Y17,
        AA18,
        AA13,
        Y18,
        AA12,
        W20,
        V20,
        Y11,
        V14,
        V19,
        W14,
        Y20,
        AB19,
        U21,
        T24,
        V24,
        V22,
        T23,
        AC25,
        AB25,
        AC24,
        PCIERC2_PERST,
        PORTC_MODE,
        PORTD_MODE,
        SGMII0,
};

struct aspeed_g7_soc1_pinctrl {
        struct device *dev;
        struct regmap *regmap;
        struct pinctrl_dev *pctl;
};

struct aspeed_g7_field {
        unsigned int reg;
        unsigned int shift;
        unsigned int mask;
};

static struct aspeed_g7_field
aspeed_g7_soc1_pinmux_field_from_pin(unsigned int pin)
{
        return (struct aspeed_g7_field){
                .reg = ASPEED_G7_SOC1_MUX_BASE +
                       (pin / ASPEED_G7_SOC1_MUX_PINS_PER_REG) *
                               ASPEED_G7_SOC1_REG_STRIDE,
                .shift = (pin % ASPEED_G7_SOC1_MUX_PINS_PER_REG) *
                         ASPEED_G7_SOC1_MUX_BITS_PER_PIN,
                .mask = ASPEED_G7_SOC1_MUX_FUNC_MASK,
        };
}

static struct aspeed_g7_field
aspeed_g7_soc1_bias_field_from_pin(unsigned int pin)
{
        return (struct aspeed_g7_field){
                .reg = ASPEED_G7_SOC1_BIAS_BASE +
                       (pin / ASPEED_G7_SOC1_BIAS_PINS_PER_REG) *
                               ASPEED_G7_SOC1_REG_STRIDE,
                .shift = pin % ASPEED_G7_SOC1_BIAS_PINS_PER_REG,
                .mask = ASPEED_G7_SOC1_BIAS_FUNC_MASK,
        };
}

static struct aspeed_g7_field
aspeed_g7_soc1_drv_field_from_idx(unsigned int idx)
{
        return (struct aspeed_g7_field){
                .reg = ASPEED_G7_SOC1_DRV_BASE +
                       (idx / ASPEED_G7_SOC1_DRV_PINS_PER_REG) *
                               ASPEED_G7_SOC1_REG_STRIDE,
                .shift = (idx % ASPEED_G7_SOC1_DRV_PINS_PER_REG) *
                         ASPEED_G7_SOC1_DRV_BITS_PER_PIN,
                .mask = ASPEED_G7_SOC1_DRV_FUNC_MASK,
        };
}

#define PIN(n) PINCTRL_PIN(n, #n)

static const struct pinctrl_pin_desc aspeed_g7_soc1_pins[] = {
        PIN(C16),
        PIN(C14),
        PIN(C11),
        PIN(D9),
        PIN(F14),
        PIN(D10),
        PIN(C12),
        PIN(C13),
        PIN(AC26),
        PIN(AA25),
        PIN(AB23),
        PIN(U22),
        PIN(V21),
        PIN(N26),
        PIN(P25),
        PIN(N25),
        PIN(V23),
        PIN(W22),
        PIN(AB26),
        PIN(AD26),
        PIN(P26),
        PIN(AE26),
        PIN(AF26),
        PIN(AF25),
        PIN(AE25),
        PIN(AD25),
        PIN(AF23),
        PIN(AF20),
        PIN(AF21),
        PIN(AE21),
        PIN(AE23),
        PIN(AD22),
        PIN(AF17),
        PIN(AA16),
        PIN(Y16),
        PIN(V17),
        PIN(J13),
        PIN(AB16),
        PIN(AC16),
        PIN(AF16),
        PIN(AA15),
        PIN(AB15),
        PIN(AC15),
        PIN(AD15),
        PIN(Y15),
        PIN(AA14),
        PIN(W16),
        PIN(V16),
        PIN(AB18),
        PIN(AC18),
        PIN(K13),
        PIN(AA17),
        PIN(AB17),
        PIN(AD16),
        PIN(AC17),
        PIN(AD17),
        PIN(AE16),
        PIN(AE17),
        PIN(AB24),
        PIN(W26),
        PIN(HOLE0),
        PIN(HOLE1),
        PIN(HOLE2),
        PIN(HOLE3),
        PIN(W25),
        PIN(Y23),
        PIN(Y24),
        PIN(W21),
        PIN(AA23),
        PIN(AC22),
        PIN(AB22),
        PIN(Y21),
        PIN(AE20),
        PIN(AF19),
        PIN(Y22),
        PIN(AA20),
        PIN(AA22),
        PIN(AB20),
        PIN(AF18),
        PIN(AE19),
        PIN(AD20),
        PIN(AC20),
        PIN(AA21),
        PIN(AB21),
        PIN(AC19),
        PIN(AE18),
        PIN(AD19),
        PIN(AD18),
        PIN(U25),
        PIN(U26),
        PIN(Y26),
        PIN(AA24),
        PIN(R25),
        PIN(AA26),
        PIN(R26),
        PIN(Y25),
        PIN(B16),
        PIN(D14),
        PIN(B15),
        PIN(B14),
        PIN(C17),
        PIN(B13),
        PIN(E14),
        PIN(C15),
        PIN(D24),
        PIN(B23),
        PIN(B22),
        PIN(C23),
        PIN(B18),
        PIN(B21),
        PIN(M15),
        PIN(B19),
        PIN(B26),
        PIN(A25),
        PIN(A24),
        PIN(B24),
        PIN(E26),
        PIN(A21),
        PIN(A19),
        PIN(A18),
        PIN(D26),
        PIN(C26),
        PIN(A23),
        PIN(A22),
        PIN(B25),
        PIN(F26),
        PIN(A26),
        PIN(A14),
        PIN(E10),
        PIN(E13),
        PIN(D12),
        PIN(F10),
        PIN(E11),
        PIN(F11),
        PIN(F13),
        PIN(N15),
        PIN(C20),
        PIN(C19),
        PIN(A8),
        PIN(R14),
        PIN(A7),
        PIN(P14),
        PIN(D20),
        PIN(A6),
        PIN(B6),
        PIN(N14),
        PIN(B7),
        PIN(B8),
        PIN(B9),
        PIN(M14),
        PIN(J11),
        PIN(E7),
        PIN(D19),
        PIN(B11),
        PIN(D15),
        PIN(B12),
        PIN(B10),
        PIN(P13),
        PIN(C18),
        PIN(C6),
        PIN(C7),
        PIN(D7),
        PIN(N13),
        PIN(C8),
        PIN(C9),
        PIN(C10),
        PIN(M16),
        PIN(A15),
        PIN(G11),
        PIN(H7),
        PIN(H8),
        PIN(H9),
        PIN(H10),
        PIN(H11),
        PIN(J9),
        PIN(J10),
        PIN(E9),
        PIN(F9),
        PIN(F8),
        PIN(M13),
        PIN(F7),
        PIN(D8),
        PIN(E8),
        PIN(L12),
        PIN(F12),
        PIN(E12),
        PIN(J12),
        PIN(G7),
        PIN(G8),
        PIN(G9),
        PIN(G10),
        PIN(K12),
        PIN(W17),
        PIN(V18),
        PIN(W18),
        PIN(Y17),
        PIN(AA18),
        PIN(AA13),
        PIN(Y18),
        PIN(AA12),
        PIN(W20),
        PIN(V20),
        PIN(Y11),
        PIN(V14),
        PIN(V19),
        PIN(W14),
        PIN(Y20),
        PIN(AB19),
        PIN(U21),
        PIN(T24),
        PIN(V24),
        PIN(V22),
        PIN(T23),
        PIN(AC25),
        PIN(AB25),
        PIN(AC24),
        PIN(PCIERC2_PERST),
        PIN(PORTC_MODE),
        PIN(PORTD_MODE),
        PIN(SGMII0),
};

static const struct pinctrl_ops aspeed_g7_soc1_pctl_ops = {
        .get_groups_count = pinctrl_generic_get_group_count,
        .get_group_name = pinctrl_generic_get_group_name,
        .get_group_pins = pinctrl_generic_get_group_pins,
        .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
        .dt_free_map = pinctrl_utils_free_map,
};

struct aspeed_g7_soc1_function {
        struct pinfunction pinfunction;
        const u8 *muxvals;
};

static int aspeed_g7_soc1_drive_strength_to_hw(u32 strength,
                                               unsigned int *val)
{
        if (strength < ASPEED_G7_SOC1_DRV_STRENGTH_MIN_MA ||
            strength > ASPEED_G7_SOC1_DRV_STRENGTH_MAX_MA ||
            strength % ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA)
                return -EINVAL;

        *val = (strength / ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA) -
               ASPEED_G7_SOC1_DRV_STRENGTH_HW_BASE;

        return 0;
}

static int aspeed_g7_soc1_set_mux(struct pinctrl_dev *pctldev,
                                  unsigned int fselector, unsigned int group)
{
        struct aspeed_g7_soc1_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        const struct aspeed_g7_soc1_function *soc1_func;
        const struct function_desc *fd;
        const struct pinfunction *func;
        const struct pingroup *grp;
        struct group_desc *gd;
        const char *gname;
        int i, g_idx = -1, ret;

        gd = pinctrl_generic_get_group(pctldev, group);
        if (!gd)
                return -EINVAL;

        grp = &gd->grp;

        fd = pinmux_generic_get_function(pctldev, fselector);
        if (!fd)
                return -EINVAL;

        soc1_func = fd->data;
        if (!soc1_func)
                return -EINVAL;

        func = &soc1_func->pinfunction;
        gname = grp->name;

        for (i = 0; i < func->ngroups; i++) {
                if (!strcmp(gname, func->groups[i])) {
                        g_idx = i;
                        break;
                }
        }

        if (g_idx < 0)
                return -EINVAL;

        for (i = 0; i < grp->npins; i++) {
                unsigned int val = soc1_func->muxvals[g_idx];
                unsigned int pin = grp->pins[i];
                struct aspeed_g7_field field;

                if (pin == PCIERC2_PERST) {
                        /*
                         * PCIERC2_PERST is a special case: it is managed by a
                         * dedicated control register (0x908) instead of the
                         * standard 4-bit multi-function field.
                         */
                        field.reg = ASPEED_G7_SOC1_PCIE_REG;
                        field.shift = 0;
                        field.mask = 0x1;
                        val = 1;
                } else if (pin == PORTC_MODE || pin == PORTD_MODE) {
                        /*
                         * PORTC_MODE and PORTD_MODE are virtual "pins" that
                         * control the USB 2.0 controller mode settings.
                         * These reside in a specific control register (0x3B0)
                         * with non-standard bit widths.
                         */
                        field.reg = ASPEED_G7_SOC1_USB_MODE_REG;
                        field.mask = 0x3;
                        field.shift = pin == PORTC_MODE ? 0 : 2;
                } else if (pin == SGMII0) {
                        /*
                         * SGMII0 is a virtual pin whose mux control resides at
                         * SCU47C bit 0, outside the contiguous pin-indexed MUX
                         * register range starting at MUX_BASE.  The field is
                         * 1 bit wide; use a 1-bit mask to avoid clobbering
                         * adjacent bits in SCU47C.
                         */
                        field.reg = ASPEED_G7_SOC1_SGMII_REG;
                        field.shift = 0;
                        field.mask = 0x1;
                } else {
                        /* Standard 4-bit-per-pin multi-function configuration */
                        field = aspeed_g7_soc1_pinmux_field_from_pin(pin);
                }

                dev_dbg(pctl->dev,
                        "Setting pin %u reg 0x%x shift %u to function %s (muxval=0x%x)\n",
                        pin, field.reg, field.shift, func->name, val);

                ret = regmap_update_bits(pctl->regmap, field.reg,
                                         field.mask << field.shift,
                                         val << field.shift);
                if (ret)
                        return ret;
        }

        return 0;
}

static int aspeed_g7_soc1_gpio_request_enable(struct pinctrl_dev *pctldev,
                                              struct pinctrl_gpio_range *range,
                                              unsigned int pin)
{
        struct aspeed_g7_soc1_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        struct aspeed_g7_field field;
        unsigned int val = 0;
        int ret = -ENOTSUPP;

        if (pin <= AC24) {
                /*
                 * Balls W17 through AB19 are the ADC-capable pins: mux
                 * function 0 selects the ADC input and function 1 selects
                 * GPIO, unlike all other pins where function 0 is GPIO.
                 */
                if (pin >= W17 && pin <= AB19)
                        val = 1;
                field = aspeed_g7_soc1_pinmux_field_from_pin(pin);
                ret = regmap_update_bits(pctl->regmap, field.reg,
                                         field.mask << field.shift,
                                         val << field.shift);
        }

        return ret;
}

static const struct pinmux_ops aspeed_g7_soc1_pmx_ops = {
        .get_functions_count = pinmux_generic_get_function_count,
        .get_function_name = pinmux_generic_get_function_name,
        .get_function_groups = pinmux_generic_get_function_groups,
        .set_mux = aspeed_g7_soc1_set_mux,
        .gpio_request_enable = aspeed_g7_soc1_gpio_request_enable,
        .strict = true,
};

/*
 * aspeed_g7_soc1_drv_map - Mapping table for pin drive strength control.
 *
 * In AST2700 SOC1, drive strength configuration is architecturally decoupled
 * from the main pin mux registers (0x400 range). It is managed by a separate
 * set of registers starting at 0x4C0.
 *
 * This table is required because:
 * 1. The mapping between physical pin IDs and drive strength control slots
 *    is non-linear and sparse.
 *    For example, W25 maps to field index 8 (stored as 9),
 *    meaning it occupies bits [17:16] of the first 0x4C0 register.
 * 2. Only a subset of physical pins supports drive strength configuration.
 *
 * The table stores (drive strength field index + 1).
 * The field index refers to the 2-bit drive strength field position within the
 * 0x4C0 register range. A value of 0 indicates that the pin does not support
 * drive strength configuration (returning -ENOTSUPP).
 * This +1 offset allows us to rely on C's default zero-initialization for
 * unsupported pins while avoiding compiler warnings regarding overridden
 * initializers.
 */
static const int aspeed_g7_soc1_drv_map[ASPEED_G7_SOC1_NR_PINS] = {
        [C16] = 1,   [C14] = 2,   [C11] = 3,   [D9] = 4,    [F14] = 5,   [D10] = 6,   [C12] = 7,
        [C13] = 8,   [W25] = 9,   [Y23] = 10,  [Y24] = 11,  [W21] = 12,  [AA23] = 13, [AC22] = 14,
        [AB22] = 15, [Y21] = 16,  [AE20] = 17, [AF19] = 18, [Y22] = 19,  [AA20] = 20, [AA22] = 21,
        [AB20] = 22, [AF18] = 23, [AE19] = 24, [AD20] = 25, [AC20] = 26, [AA21] = 27, [AB21] = 28,
        [AC19] = 29, [AE18] = 30, [AD19] = 31, [AD18] = 32, [U25] = 33,  [U26] = 34,  [Y26] = 35,
        [AA24] = 36, [R25] = 37,  [AA26] = 38, [R26] = 39,  [Y25] = 40,  [B16] = 41,  [D14] = 42,
        [B15] = 43,  [B14] = 44,  [C17] = 45,  [B13] = 46,  [E14] = 47,  [C15] = 48,  [D24] = 49,
        [B23] = 50,  [B22] = 51,  [C23] = 52,  [B18] = 53,  [B21] = 54,  [M15] = 55,  [B19] = 56,
        [B26] = 57,  [A25] = 58,  [A24] = 59,  [B24] = 60,  [E26] = 61,  [A21] = 62,  [A19] = 63,
        [A18] = 64,  [D26] = 65,  [C26] = 66,  [A23] = 67,  [A22] = 68,  [B25] = 69,  [F26] = 70,
        [A26] = 71,  [A14] = 72,  [E10] = 73,  [E13] = 74,  [D12] = 75,  [F10] = 76,  [E11] = 77,
        [F11] = 78,  [F13] = 79,  [N15] = 80,  [C20] = 81,  [C19] = 82,  [A8] = 83,   [R14] = 84,
        [A7] = 85,   [P14] = 86,  [D20] = 87,  [A6] = 88,   [B6] = 89,   [N14] = 90,  [B7] = 91,
        [B8] = 92,   [B9] = 93,   [M14] = 94,  [J11] = 95,  [E7] = 96,   [D19] = 97,  [B11] = 98,
        [D15] = 99,  [B12] = 100, [B10] = 101, [P13] = 102, [C18] = 103, [C6] = 104,  [C7] = 105,
        [D7] = 106,  [N13] = 107, [C8] = 108,  [C9] = 109,  [C10] = 110, [M16] = 111, [A15] = 112,
        [E9] = 113,  [F9] = 114,  [F8] = 115,  [M13] = 116, [F7] = 117,  [D8] = 118,  [E8] = 119,
        [L12] = 120,
};

static int aspeed_g7_soc1_pin_config_get(struct pinctrl_dev *pctldev,
                                         unsigned int pin,
                                         unsigned long *config)
{
        struct aspeed_g7_soc1_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param = pinconf_to_config_param(*config);
        struct aspeed_g7_field field;
        unsigned int val, val_raw;
        int ret, ds_idx;

        if (pin > AC24)
                return -EINVAL;

        switch (param) {
        case PIN_CONFIG_BIAS_DISABLE:
                field = aspeed_g7_soc1_bias_field_from_pin(pin);
                break;
        case PIN_CONFIG_BIAS_PULL_DOWN:
        case PIN_CONFIG_BIAS_PULL_UP:
                /*
                 * The hardware has a single 1-bit enable/disable field per
                 * pin; pull direction is fixed in silicon and cannot be read
                 * back from the register.  Reject readback requests for a
                 * specific pull direction.
                 */
                return -ENOTSUPP;
        case PIN_CONFIG_DRIVE_STRENGTH:
                ds_idx = aspeed_g7_soc1_drv_map[pin];
                if (!ds_idx)
                        return -ENOTSUPP;
                ds_idx--; /* Adjust back to 0-based hardware index */
                field = aspeed_g7_soc1_drv_field_from_idx(ds_idx);
                break;
        default:
                return -ENOTSUPP;
        }

        ret = regmap_read(pctl->regmap, field.reg, &val_raw);
        if (ret)
                return ret;

        val = (val_raw & (field.mask << field.shift)) >> field.shift;
        if (param == PIN_CONFIG_DRIVE_STRENGTH)
                val = (val + ASPEED_G7_SOC1_DRV_STRENGTH_HW_BASE) *
                      ASPEED_G7_SOC1_DRV_STRENGTH_STEP_MA;

        if (!val)
                return -EINVAL;

        *config = pinconf_to_config_packed(param, val);

        return 0;
}

static int aspeed_g7_soc1_pin_config_set(struct pinctrl_dev *pctldev,
                                         unsigned int pin,
                                         unsigned long *configs,
                                         unsigned int num_configs)
{
        struct aspeed_g7_soc1_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        struct aspeed_g7_field field;
        enum pin_config_param param;
        int i, ret, ds_idx;
        unsigned int val;
        u32 arg;

        if (pin > AC24)
                return -EINVAL;

        for (i = 0; i < num_configs; i++) {
                param = pinconf_to_config_param(configs[i]);
                arg = pinconf_to_config_argument(configs[i]);

                switch (param) {
                case PIN_CONFIG_BIAS_PULL_DOWN:
                case PIN_CONFIG_BIAS_PULL_UP:
                        /*
                         * The hardware has one enable/disable bit per pin;
                         * pull direction is fixed in silicon.  Both PULL_UP
                         * and PULL_DOWN map to "enable bias"; the caller must
                         * request the direction that the hardware provides.
                         */
                case PIN_CONFIG_BIAS_DISABLE:
                        field = aspeed_g7_soc1_bias_field_from_pin(pin);
                        val = (param == PIN_CONFIG_BIAS_DISABLE) ? 1 : 0;
                        break;
                case PIN_CONFIG_DRIVE_STRENGTH:
                        ds_idx = aspeed_g7_soc1_drv_map[pin];
                        if (!ds_idx)
                                return -ENOTSUPP;
                        ds_idx--; /* Adjust back to 0-based hardware index */
                        field = aspeed_g7_soc1_drv_field_from_idx(ds_idx);
                        ret = aspeed_g7_soc1_drive_strength_to_hw(arg, &val);
                        if (ret)
                                return ret;
                        break;
                default:
                        return -ENOTSUPP;
                }

                dev_dbg(pctl->dev,
                        "Configuring pin %u reg 0x%x shift %u param %d arg %u val 0x%x\n",
                        pin, field.reg, field.shift, param, arg, val);

                ret = regmap_update_bits(pctl->regmap, field.reg,
                                         field.mask << field.shift,
                                         val << field.shift);

                if (ret)
                        return ret;
        }

        return 0;
}

static int aspeed_g7_soc1_pin_config_group_get(struct pinctrl_dev *pctldev,
                                               unsigned int selector,
                                               unsigned long *config)
{
        const unsigned int *pins;
        unsigned int npins;
        int ret;

        ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
        if (ret)
                return ret;
        if (!npins)
                return -ENODEV;

        return aspeed_g7_soc1_pin_config_get(pctldev, pins[0], config);
}

static int aspeed_g7_soc1_pin_config_group_set(struct pinctrl_dev *pctldev,
                                               unsigned int selector,
                                               unsigned long *configs,
                                               unsigned int num_configs)
{
        const unsigned int *pins;
        unsigned int npins;
        int ret;
        int i;

        ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
        if (ret)
                return ret;

        for (i = 0; i < npins; i++) {
                ret = aspeed_g7_soc1_pin_config_set(pctldev, pins[i], configs,
                                                    num_configs);
                if (ret)
                        return ret;
        }

        return 0;
}

static const struct pinconf_ops aspeed_g7_soc1_conf_ops = {
        .is_generic = true,
        .pin_config_get = aspeed_g7_soc1_pin_config_get,
        .pin_config_set = aspeed_g7_soc1_pin_config_set,
        .pin_config_group_get = aspeed_g7_soc1_pin_config_group_get,
        .pin_config_group_set = aspeed_g7_soc1_pin_config_group_set,
        .pin_config_config_dbg_show = pinconf_generic_dump_config,
};

static const struct pinctrl_desc aspeed_g7_soc1_desc = {
        .name = "aspeed-g7-soc1-pinctrl",
        .pins = aspeed_g7_soc1_pins,
        .npins = ARRAY_SIZE(aspeed_g7_soc1_pins),
        .pctlops = &aspeed_g7_soc1_pctl_ops,
        .pmxops = &aspeed_g7_soc1_pmx_ops,
        .confops = &aspeed_g7_soc1_conf_ops,
        .owner = THIS_MODULE,
};

 #define PIN_GROUP(name, ...) static const unsigned int name ## _pins[] = { __VA_ARGS__ }

/* Pin Groups and Functions */
PIN_GROUP(ADC0, W17);
PIN_GROUP(ADC1, V18);
PIN_GROUP(ADC10, Y11);
PIN_GROUP(ADC11, V14);
PIN_GROUP(ADC12, V19);
PIN_GROUP(ADC13, W14);
PIN_GROUP(ADC14, Y20);
PIN_GROUP(ADC15, AB19);
PIN_GROUP(ADC2, W18);
PIN_GROUP(ADC3, Y17);
PIN_GROUP(ADC4, AA18);
PIN_GROUP(ADC5, AA13);
PIN_GROUP(ADC6, Y18);
PIN_GROUP(ADC7, AA12);
PIN_GROUP(ADC8, W20);
PIN_GROUP(ADC9, V20);
PIN_GROUP(AUXPWRGOOD0, W14);
PIN_GROUP(AUXPWRGOOD1, Y20);
PIN_GROUP(CANBUS, G7, G8, G9);
PIN_GROUP(DI2C0, C16, D9);
PIN_GROUP(DI2C1, C14, F14);
PIN_GROUP(DI2C10, R25, AA26);
PIN_GROUP(DI2C11, R26, Y25);
PIN_GROUP(DI2C12, W25, Y23);
PIN_GROUP(DI2C13, Y24, W21);
PIN_GROUP(DI2C14, AA23, AC22);
PIN_GROUP(DI2C15, AB22, Y21);
PIN_GROUP(DI2C2, D10, C12);
PIN_GROUP(DI2C3, C11, C13);
PIN_GROUP(DI2C8, U25, U26);
PIN_GROUP(DI2C9, Y26, AA24);
PIN_GROUP(DSGPM0, D19, B10, C7, D7);
PIN_GROUP(ESPI0, B16, D14, B15, B14, C17, B13, E14, C15);
PIN_GROUP(ESPI1, C16, C14, C11, D9, F14, D10, C12, C13);
PIN_GROUP(FSI0, AD20, AC20);
PIN_GROUP(FSI1, AA21, AB21);
PIN_GROUP(FSI2, AC19, AE18);
PIN_GROUP(FSI3, AD19, AD18);
PIN_GROUP(FWQSPI, M16, A15);
PIN_GROUP(FWSPIABR, A14);
PIN_GROUP(FWWPN, N15);
PIN_GROUP(HBLED, V24);
PIN_GROUP(HVI3C0, U25, U26);
PIN_GROUP(HVI3C1, Y26, AA24);
PIN_GROUP(HVI3C12, W25, Y23);
PIN_GROUP(HVI3C13, Y24, W21);
PIN_GROUP(HVI3C14, AA23, AC22);
PIN_GROUP(HVI3C15, AB22, Y21);
PIN_GROUP(HVI3C2, R25, AA26);
PIN_GROUP(HVI3C3, R26, Y25);
PIN_GROUP(I2C0, G11, H7);
PIN_GROUP(I2C1, H8, H9);
PIN_GROUP(I2C10, G8, G9);
PIN_GROUP(I2C11, G10, K12);
PIN_GROUP(I2C12, AC18, AA17);
PIN_GROUP(I2C13, AB17, AD16);
PIN_GROUP(I2C14, AC17, AD17);
PIN_GROUP(I2C15, AE16, AE17);
PIN_GROUP(I2C2, H10, H11);
PIN_GROUP(I2C3, J9, J10);
PIN_GROUP(I2C4, E9, F9);
PIN_GROUP(I2C5, F8, M13);
PIN_GROUP(I2C6, F7, D8);
PIN_GROUP(I2C7, E8, L12);
PIN_GROUP(I2C8, F12, E12);
PIN_GROUP(I2C9, J12, G7);
PIN_GROUP(I2CF0, F12, E12, J12, G7);
PIN_GROUP(I2CF1, E9, F9, F8, M13);
PIN_GROUP(I2CF2, F7, D8, E8, L12);
PIN_GROUP(I3C10, AC19, AE18);
PIN_GROUP(I3C11, AD19, AD18);
PIN_GROUP(I3C4, AE20, AF19);
PIN_GROUP(I3C5, Y22, AA20);
PIN_GROUP(I3C6, AA22, AB20);
PIN_GROUP(I3C7, AF18, AE19);
PIN_GROUP(I3C8, AD20, AC20);
PIN_GROUP(I3C9, AA21, AB21);
PIN_GROUP(JTAGM1, D12, F10, E11, F11, F13);
PIN_GROUP(LPC0, AF26, AF25, B16, D14, B15, B14, C17, B13, E14, C15);
PIN_GROUP(LPC1, C16, C14, C11, D9, F14, D10, C12, C13, AE16, AE17);
PIN_GROUP(LTPI, U25, U26, Y26, AA24);
PIN_GROUP(LTPI_PS_I2C0, G11, H7);
PIN_GROUP(LTPI_PS_I2C1, H8, H9);
PIN_GROUP(LTPI_PS_I2C2, H10, H11);
PIN_GROUP(LTPI_PS_I2C3, J9, J10);
PIN_GROUP(MACLINK0, U21);
PIN_GROUP(MACLINK1, AC24);
PIN_GROUP(MACLINK2, T24);
PIN_GROUP(MDIO0, B9, M14);
PIN_GROUP(MDIO1, C9, C10);
PIN_GROUP(MDIO2, E10, E13);
PIN_GROUP(NCTS0, AF17);
PIN_GROUP(NCTS1, AA15);
PIN_GROUP(NCTS5, V21);
PIN_GROUP(NCTS6, AB26);
PIN_GROUP(NDCD0, AA16);
PIN_GROUP(NDCD1, AB15);
PIN_GROUP(NDCD5, N26);
PIN_GROUP(NDCD6, AD26);
PIN_GROUP(NDSR0, Y16);
PIN_GROUP(NDSR1, AC15);
PIN_GROUP(NDSR5, P25);
PIN_GROUP(NDSR6, P26);
PIN_GROUP(NDTR0, J13);
PIN_GROUP(NDTR1, Y15);
PIN_GROUP(NDTR5, V23);
PIN_GROUP(NDTR6, AF26);
PIN_GROUP(NRI0, V17);
PIN_GROUP(NRI1, AD15);
PIN_GROUP(NRI5, N25);
PIN_GROUP(NRI6, AE26);
PIN_GROUP(NRTS0, AB16);
PIN_GROUP(NRTS1, AA14);
PIN_GROUP(NRTS5, W22);
PIN_GROUP(NRTS6, AF25);
PIN_GROUP(OSCCLK, C17);
PIN_GROUP(PE2SGRSTN, E10, PCIERC2_PERST);
PIN_GROUP(PWM0, AE25);
PIN_GROUP(PWM1, AD25);
PIN_GROUP(PWM10, AB17);
PIN_GROUP(PWM11, AD16);
PIN_GROUP(PWM12, AC17);
PIN_GROUP(PWM13, AD17);
PIN_GROUP(PWM14, AE16);
PIN_GROUP(PWM15, AE17);
PIN_GROUP(PWM2, AF23);
PIN_GROUP(PWM3, AF20);
PIN_GROUP(PWM4, AF21);
PIN_GROUP(PWM5, AE21);
PIN_GROUP(PWM6, AE23);
PIN_GROUP(PWM7, AD22);
PIN_GROUP(PWM8, K13);
PIN_GROUP(PWM9, AA17);
PIN_GROUP(QSPI0, C23, B18);
PIN_GROUP(QSPI1, B24, E26);
PIN_GROUP(QSPI2, B25, F26);
PIN_GROUP(RGMII0, C20, C19, A8, R14, A7, P14, D20, A6, B6, N14, B7, B8);
PIN_GROUP(RGMII1, D19, B11, D15, B12, B10, P13, C18, C6, C7, D7, N13, C8);
PIN_GROUP(RMII0, C20, A8, R14, A7, P14, A6, B6, N14);
PIN_GROUP(RMII0RCLKO, D20);
PIN_GROUP(RMII1, D19, D15, B12, B10, P13, C6, C7, D7);
PIN_GROUP(RMII1RCLKO, C18);
PIN_GROUP(SALT0, AC17);
PIN_GROUP(SALT1, AD17);
PIN_GROUP(SALT10, Y18);
PIN_GROUP(SALT11, AA12);
PIN_GROUP(SALT12, AB26);
PIN_GROUP(SALT13, AD26);
PIN_GROUP(SALT14, P26);
PIN_GROUP(SALT15, AE26);
PIN_GROUP(SALT2, AC15);
PIN_GROUP(SALT3, AD15);
PIN_GROUP(SALT4, W17);
PIN_GROUP(SALT5, V18);
PIN_GROUP(SALT6, W18);
PIN_GROUP(SALT7, Y17);
PIN_GROUP(SALT8, AA18);
PIN_GROUP(SALT9, AA13);
PIN_GROUP(SD, C16, C14, C11, D9, F14, D10, C12, C13);
PIN_GROUP(SGMII, SGMII0);
PIN_GROUP(SGPM0, U21, T24, V22, T23);
PIN_GROUP(SGPM1, AC25, AB25, AB24, W26);
PIN_GROUP(SGPS, B11, C18, N13, C8);
PIN_GROUP(SIOONCTRLN0, AE23);
PIN_GROUP(SIOONCTRLN1, AA15);
PIN_GROUP(SIOPBIN0, AD25);
PIN_GROUP(SIOPBIN1, AA16);
PIN_GROUP(SIOPBON0, AE25);
PIN_GROUP(SIOPBON1, AF17);
PIN_GROUP(SIOPWREQN0, AE21);
PIN_GROUP(SIOPWREQN1, AB16);
PIN_GROUP(SIOPWRGD1, AB15);
PIN_GROUP(SIOS3N0, AF20);
PIN_GROUP(SIOS3N1, V17);
PIN_GROUP(SIOS5N0, AF21);
PIN_GROUP(SIOS5N1, J13);
PIN_GROUP(SIOSCIN0, AF23);
PIN_GROUP(SIOSCIN1, Y16);
PIN_GROUP(SMON0, U21, T24, V22, T23);
PIN_GROUP(SMON1, W26, AC25, AB25);
PIN_GROUP(SPI0, D24, B23, B22);
PIN_GROUP(SPI0ABR, M15);
PIN_GROUP(SPI0CS1, B21);
PIN_GROUP(SPI0WPN, B19);
PIN_GROUP(SPI1, B26, A25, A24);
PIN_GROUP(SPI1ABR, A19);
PIN_GROUP(SPI1CS1, A21);
PIN_GROUP(SPI1WPN, A18);
PIN_GROUP(SPI2, D26, C26, A23, A22);
PIN_GROUP(SPI2CS1, A26);
PIN_GROUP(TACH0, AC26);
PIN_GROUP(TACH1, AA25);
PIN_GROUP(TACH10, AB26);
PIN_GROUP(TACH11, AD26);
PIN_GROUP(TACH12, P26);
PIN_GROUP(TACH13, AE26);
PIN_GROUP(TACH14, AF26);
PIN_GROUP(TACH15, AF25);
PIN_GROUP(TACH2, AB23);
PIN_GROUP(TACH3, U22);
PIN_GROUP(TACH4, V21);
PIN_GROUP(TACH5, N26);
PIN_GROUP(TACH6, P25);
PIN_GROUP(TACH7, N25);
PIN_GROUP(TACH8, V23);
PIN_GROUP(TACH9, W22);
PIN_GROUP(THRU0, AC26, AA25);
PIN_GROUP(THRU1, AB23, U22);
PIN_GROUP(THRU2, A19, A18);
PIN_GROUP(THRU3, B25, F26);
PIN_GROUP(UART0, AC16, AF16);
PIN_GROUP(UART1, W16, V16);
PIN_GROUP(UART2, AB18, AC18);
PIN_GROUP(UART3, K13, AA17);
PIN_GROUP(UART5, AB17, AD16);
PIN_GROUP(UART6, AC17, AD17);
PIN_GROUP(UART7, AE16, AE17);
PIN_GROUP(UART8, M15, B19);
PIN_GROUP(UART9, B26, A25);
PIN_GROUP(UART10, A24, B24);
PIN_GROUP(UART11, E26, A21);
PIN_GROUP(USB2CD, PORTC_MODE);
PIN_GROUP(USB2CH, PORTC_MODE);
PIN_GROUP(USB2CU, PORTC_MODE);
PIN_GROUP(USB2CUD, PORTC_MODE);
PIN_GROUP(USB2DD, PORTD_MODE);
PIN_GROUP(USB2DH, PORTD_MODE);
PIN_GROUP(USBUART, G10, K12);
PIN_GROUP(VGA, J11, E7);
PIN_GROUP(VPI, C16, C14, C11, D9, F14, D10, AC26, AA25, AB23, U22, V21, N26,
          P25, N25, V23, W22, AB26, AD26, P26, AE26, AF26, AF25, AE25, AD25,
          AF23, AF20, AF21, AE21);
PIN_GROUP(WDTRST0N, K13);
PIN_GROUP(WDTRST1N, AA17);
PIN_GROUP(WDTRST2N, AB17);
PIN_GROUP(WDTRST3N, AD16);
PIN_GROUP(WDTRST4N, AC25);
PIN_GROUP(WDTRST5N, AB25);
PIN_GROUP(WDTRST6N, AC24);
PIN_GROUP(WDTRST7N, AB24);

#define GROUP(n) PINCTRL_PINGROUP(#n, n##_pins, ARRAY_SIZE(n##_pins))

static const struct pingroup aspeed_g7_soc1_groups[] = {
        GROUP(ADC0),
        GROUP(ADC1),
        GROUP(ADC10),
        GROUP(ADC11),
        GROUP(ADC12),
        GROUP(ADC13),
        GROUP(ADC14),
        GROUP(ADC15),
        GROUP(ADC2),
        GROUP(ADC3),
        GROUP(ADC4),
        GROUP(ADC5),
        GROUP(ADC6),
        GROUP(ADC7),
        GROUP(ADC8),
        GROUP(ADC9),
        GROUP(AUXPWRGOOD0),
        GROUP(AUXPWRGOOD1),
        GROUP(CANBUS),
        GROUP(DI2C0),
        GROUP(DI2C1),
        GROUP(DI2C10),
        GROUP(DI2C11),
        GROUP(DI2C12),
        GROUP(DI2C13),
        GROUP(DI2C14),
        GROUP(DI2C15),
        GROUP(DI2C2),
        GROUP(DI2C3),
        GROUP(DI2C8),
        GROUP(DI2C9),
        GROUP(DSGPM0),
        GROUP(ESPI0),
        GROUP(ESPI1),
        GROUP(FSI0),
        GROUP(FSI1),
        GROUP(FSI2),
        GROUP(FSI3),
        GROUP(FWQSPI),
        GROUP(FWSPIABR),
        GROUP(FWWPN),
        GROUP(HBLED),
        GROUP(HVI3C0),
        GROUP(HVI3C1),
        GROUP(HVI3C12),
        GROUP(HVI3C13),
        GROUP(HVI3C14),
        GROUP(HVI3C15),
        GROUP(HVI3C2),
        GROUP(HVI3C3),
        GROUP(I2C0),
        GROUP(I2C1),
        GROUP(I2C10),
        GROUP(I2C11),
        GROUP(I2C12),
        GROUP(I2C13),
        GROUP(I2C14),
        GROUP(I2C15),
        GROUP(I2C2),
        GROUP(I2C3),
        GROUP(I2C4),
        GROUP(I2C5),
        GROUP(I2C6),
        GROUP(I2C7),
        GROUP(I2C8),
        GROUP(I2C9),
        GROUP(I2CF0),
        GROUP(I2CF1),
        GROUP(I2CF2),
        GROUP(I3C10),
        GROUP(I3C11),
        GROUP(I3C4),
        GROUP(I3C5),
        GROUP(I3C6),
        GROUP(I3C7),
        GROUP(I3C8),
        GROUP(I3C9),
        GROUP(JTAGM1),
        GROUP(LPC0),
        GROUP(LPC1),
        GROUP(LTPI),
        GROUP(LTPI_PS_I2C0),
        GROUP(LTPI_PS_I2C1),
        GROUP(LTPI_PS_I2C2),
        GROUP(LTPI_PS_I2C3),
        GROUP(MACLINK0),
        GROUP(MACLINK1),
        GROUP(MACLINK2),
        GROUP(MDIO0),
        GROUP(MDIO1),
        GROUP(MDIO2),
        GROUP(NCTS0),
        GROUP(NCTS1),
        GROUP(NCTS5),
        GROUP(NCTS6),
        GROUP(NDCD0),
        GROUP(NDCD1),
        GROUP(NDCD5),
        GROUP(NDCD6),
        GROUP(NDSR0),
        GROUP(NDSR1),
        GROUP(NDSR5),
        GROUP(NDSR6),
        GROUP(NDTR0),
        GROUP(NDTR1),
        GROUP(NDTR5),
        GROUP(NDTR6),
        GROUP(NRI0),
        GROUP(NRI1),
        GROUP(NRI5),
        GROUP(NRI6),
        GROUP(NRTS0),
        GROUP(NRTS1),
        GROUP(NRTS5),
        GROUP(NRTS6),
        GROUP(OSCCLK),
        GROUP(PE2SGRSTN),
        GROUP(PWM0),
        GROUP(PWM1),
        GROUP(PWM10),
        GROUP(PWM11),
        GROUP(PWM12),
        GROUP(PWM13),
        GROUP(PWM14),
        GROUP(PWM15),
        GROUP(PWM2),
        GROUP(PWM3),
        GROUP(PWM4),
        GROUP(PWM5),
        GROUP(PWM6),
        GROUP(PWM7),
        GROUP(PWM8),
        GROUP(PWM9),
        GROUP(QSPI0),
        GROUP(QSPI1),
        GROUP(QSPI2),
        GROUP(RGMII0),
        GROUP(RGMII1),
        GROUP(RMII0),
        GROUP(RMII0RCLKO),
        GROUP(RMII1),
        GROUP(RMII1RCLKO),
        GROUP(SALT0),
        GROUP(SALT1),
        GROUP(SALT10),
        GROUP(SALT11),
        GROUP(SALT12),
        GROUP(SALT13),
        GROUP(SALT14),
        GROUP(SALT15),
        GROUP(SALT2),
        GROUP(SALT3),
        GROUP(SALT4),
        GROUP(SALT5),
        GROUP(SALT6),
        GROUP(SALT7),
        GROUP(SALT8),
        GROUP(SALT9),
        GROUP(SD),
        GROUP(SGMII),
        GROUP(SGPM0),
        GROUP(SGPM1),
        GROUP(SGPS),
        GROUP(SIOONCTRLN0),
        GROUP(SIOONCTRLN1),
        GROUP(SIOPBIN0),
        GROUP(SIOPBIN1),
        GROUP(SIOPBON0),
        GROUP(SIOPBON1),
        GROUP(SIOPWREQN0),
        GROUP(SIOPWREQN1),
        GROUP(SIOPWRGD1),
        GROUP(SIOS3N0),
        GROUP(SIOS3N1),
        GROUP(SIOS5N0),
        GROUP(SIOS5N1),
        GROUP(SIOSCIN0),
        GROUP(SIOSCIN1),
        GROUP(SMON0),
        GROUP(SMON1),
        GROUP(SPI0),
        GROUP(SPI0ABR),
        GROUP(SPI0CS1),
        GROUP(SPI0WPN),
        GROUP(SPI1),
        GROUP(SPI1ABR),
        GROUP(SPI1CS1),
        GROUP(SPI1WPN),
        GROUP(SPI2),
        GROUP(SPI2CS1),
        GROUP(TACH0),
        GROUP(TACH1),
        GROUP(TACH10),
        GROUP(TACH11),
        GROUP(TACH12),
        GROUP(TACH13),
        GROUP(TACH14),
        GROUP(TACH15),
        GROUP(TACH2),
        GROUP(TACH3),
        GROUP(TACH4),
        GROUP(TACH5),
        GROUP(TACH6),
        GROUP(TACH7),
        GROUP(TACH8),
        GROUP(TACH9),
        GROUP(THRU0),
        GROUP(THRU1),
        GROUP(THRU2),
        GROUP(THRU3),
        GROUP(UART0),
        GROUP(UART1),
        GROUP(UART10),
        GROUP(UART11),
        GROUP(UART2),
        GROUP(UART3),
        GROUP(UART5),
        GROUP(UART6),
        GROUP(UART7),
        GROUP(UART8),
        GROUP(UART9),
        GROUP(USB2CD),
        GROUP(USB2CH),
        GROUP(USB2CU),
        GROUP(USB2CUD),
        GROUP(USB2DD),
        GROUP(USB2DH),
        GROUP(USBUART),
        GROUP(VGA),
        GROUP(VPI),
        GROUP(WDTRST0N),
        GROUP(WDTRST1N),
        GROUP(WDTRST2N),
        GROUP(WDTRST3N),
        GROUP(WDTRST4N),
        GROUP(WDTRST5N),
        GROUP(WDTRST6N),
        GROUP(WDTRST7N),
};

/**
 * VM() - Helper macro to unwrap a parenthesized list of arguments.
 * @...: The parenthesized list to be unwrapped.
 *
 * Since the C preprocessor treats commas inside braces {} as argument
 * separators for macros, we wrap lists (like mux values) in parentheses ()
 * to protect them during macro expansion. This macro strips those
 * parentheses when the values are needed for array initialization.
 */
#define VM(...) __VA_ARGS__

/**
 * FUNC() - Macro to initialize an aspeed_g7_soc1_function entry.
 * @n: Name of the pin function.
 * @m: Parenthesized list of mux values, mapped 1:1 to the groups list.
 * @...: Variable list of pin group names associated with this function.
 *
 * This macro solves complex static initialization by:
 * 1. Creating anonymous arrays for both group names and mux values
 *    using C99 Compound Literals.
 * 2. Using VM(m) to unwrap mux values into the array initializer.
 * 3. Calculating the number of groups via sizeof() division, which
 *    bypasses the __must_be_array() check performed by ARRAY_SIZE()
 *    that often fails on compound literals in the kernel environment.
 *
 * Example: FUNC(i2c0, (1, 4), "i2c0", "di2c0")
 *          Maps "i2c0" group to mux value 1 and "di2c0" group to mux value 4.
 */
#define FUNC(n, m, ...)                                                                          \
        {                                                                                        \
                .pinfunction = {                                                                 \
                        .name = #n,                                                              \
                        .groups = (const char *const[]){ __VA_ARGS__ },                          \
                        .ngroups = sizeof((const char *const[]){ __VA_ARGS__ }) / sizeof(char *), \
                },                                                                               \
                .muxvals = (const u8[]){ VM m }                                                  \
        }

static const struct aspeed_g7_soc1_function aspeed_g7_soc1_functions[] = {
        FUNC(ADC0, (0), "ADC0"),
        FUNC(ADC1, (0), "ADC1"),
        FUNC(ADC10, (0), "ADC10"),
        FUNC(ADC11, (0), "ADC11"),
        FUNC(ADC12, (0), "ADC12"),
        FUNC(ADC13, (0), "ADC13"),
        FUNC(ADC14, (0), "ADC14"),
        FUNC(ADC15, (0), "ADC15"),
        FUNC(ADC2, (0), "ADC2"),
        FUNC(ADC3, (0), "ADC3"),
        FUNC(ADC4, (0), "ADC4"),
        FUNC(ADC5, (0), "ADC5"),
        FUNC(ADC6, (0), "ADC6"),
        FUNC(ADC7, (0), "ADC7"),
        FUNC(ADC8, (0), "ADC8"),
        FUNC(ADC9, (0), "ADC9"),
        FUNC(AUXPWRGOOD0, (2), "AUXPWRGOOD0"),
        FUNC(AUXPWRGOOD1, (2), "AUXPWRGOOD1"),
        FUNC(CANBUS, (2), "CANBUS"),
        FUNC(ESPI0, (1), "ESPI0"),
        FUNC(ESPI1, (1), "ESPI1"),
        FUNC(FSI0, (2), "FSI0"),
        FUNC(FSI1, (2), "FSI1"),
        FUNC(FSI2, (2), "FSI2"),
        FUNC(FSI3, (2), "FSI3"),
        FUNC(FWQSPI, (1), "FWQSPI"),
        FUNC(FWSPIABR, (1), "FWSPIABR"),
        FUNC(FWWPN, (1), "FWWPN"),
        FUNC(HBLED, (2), "HBLED"),
        FUNC(I2C0, (1, 2, 4), "I2C0", "LTPI_PS_I2C0", "DI2C0"),
        FUNC(I2C1, (1, 2, 4), "I2C1", "LTPI_PS_I2C1", "DI2C1"),
        FUNC(I2C10, (1, 2), "I2C10", "DI2C10"),
        FUNC(I2C11, (1, 2), "I2C11", "DI2C11"),
        FUNC(I2C12, (4, 2), "I2C12", "DI2C12"),
        FUNC(I2C13, (4, 2), "I2C13", "DI2C13"),
        FUNC(I2C14, (4, 2), "I2C14", "DI2C14"),
        FUNC(I2C15, (2, 2), "I2C15", "DI2C15"),
        FUNC(I2C2, (1, 2, 4), "I2C2", "LTPI_PS_I2C2", "DI2C2"),
        FUNC(I2C3, (1, 2, 4), "I2C3", "LTPI_PS_I2C3", "DI2C3"),
        FUNC(I2C4, (1), "I2C4"),
        FUNC(I2C5, (1), "I2C5"),
        FUNC(I2C6, (1), "I2C6"),
        FUNC(I2C7, (1), "I2C7"),
        FUNC(I2C8, (1, 2), "I2C8", "DI2C8"),
        FUNC(I2C9, (1, 2), "I2C9", "DI2C9"),
        FUNC(I2CF0, (5), "I2CF0"),
        FUNC(I2CF1, (5), "I2CF1"),
        FUNC(I2CF2, (5), "I2CF2"),
        FUNC(I3C0, (1), "HVI3C0"),
        FUNC(I3C1, (1), "HVI3C1"),
        FUNC(I3C10, (1), "I3C10"),
        FUNC(I3C11, (1), "I3C11"),
        FUNC(I3C12, (1), "HVI3C12"),
        FUNC(I3C13, (1), "HVI3C13"),
        FUNC(I3C14, (1), "HVI3C14"),
        FUNC(I3C15, (1), "HVI3C15"),
        FUNC(I3C2, (1), "HVI3C2"),
        FUNC(I3C3, (1), "HVI3C3"),
        FUNC(I3C4, (1), "I3C4"),
        FUNC(I3C5, (1), "I3C5"),
        FUNC(I3C6, (1), "I3C6"),
        FUNC(I3C7, (1), "I3C7"),
        FUNC(I3C8, (1), "I3C8"),
        FUNC(I3C9, (1), "I3C9"),
        FUNC(JTAGM1, (1), "JTAGM1"),
        FUNC(LPC0, (2), "LPC0"),
        FUNC(LPC1, (2), "LPC1"),
        FUNC(LTPI, (2), "LTPI"),
        FUNC(MACLINK0, (4), "MACLINK0"),
        FUNC(MACLINK1, (3), "MACLINK1"),
        FUNC(MACLINK2, (4), "MACLINK2"),
        FUNC(MDIO0, (1), "MDIO0"),
        FUNC(MDIO1, (1), "MDIO1"),
        FUNC(MDIO2, (1), "MDIO2"),
        FUNC(NCTS0, (1), "NCTS0"),
        FUNC(NCTS1, (1), "NCTS1"),
        FUNC(NCTS5, (4), "NCTS5"),
        FUNC(NCTS6, (4), "NCTS6"),
        FUNC(NDCD0, (1), "NDCD0"),
        FUNC(NDCD1, (1), "NDCD1"),
        FUNC(NDCD5, (4), "NDCD5"),
        FUNC(NDCD6, (4), "NDCD6"),
        FUNC(NDSR0, (1), "NDSR0"),
        FUNC(NDSR1, (1), "NDSR1"),
        FUNC(NDSR5, (4), "NDSR5"),
        FUNC(NDSR6, (4), "NDSR6"),
        FUNC(NDTR0, (1), "NDTR0"),
        FUNC(NDTR1, (1), "NDTR1"),
        FUNC(NDTR5, (4), "NDTR5"),
        FUNC(NDTR6, (4), "NDTR6"),
        FUNC(NRI0, (1), "NRI0"),
        FUNC(NRI1, (1), "NRI1"),
        FUNC(NRI5, (4), "NRI5"),
        FUNC(NRI6, (4), "NRI6"),
        FUNC(NRTS0, (1), "NRTS0"),
        FUNC(NRTS1, (1), "NRTS1"),
        FUNC(NRTS5, (4), "NRTS5"),
        FUNC(NRTS6, (4), "NRTS6"),
        FUNC(OSCCLK, (3), "OSCCLK"),
        FUNC(PCIERC, (2), "PE2SGRSTN"),
        FUNC(PWM0, (1), "PWM0"),
        FUNC(PWM1, (1), "PWM1"),
        FUNC(PWM10, (3), "PWM10"),
        FUNC(PWM11, (3), "PWM11"),
        FUNC(PWM12, (3), "PWM12"),
        FUNC(PWM13, (3), "PWM13"),
        FUNC(PWM14, (3), "PWM14"),
        FUNC(PWM15, (3), "PWM15"),
        FUNC(PWM2, (1), "PWM2"),
        FUNC(PWM3, (1), "PWM3"),
        FUNC(PWM4, (1), "PWM4"),
        FUNC(PWM5, (1), "PWM5"),
        FUNC(PWM6, (1), "PWM6"),
        FUNC(PWM7, (1), "PWM7"),
        FUNC(PWM8, (3), "PWM8"),
        FUNC(PWM9, (3), "PWM9"),
        FUNC(QSPI0, (1), "QSPI0"),
        FUNC(QSPI1, (1), "QSPI1"),
        FUNC(QSPI2, (1), "QSPI2"),
        FUNC(RGMII0, (1), "RGMII0"),
        FUNC(RGMII1, (1), "RGMII1"),
        FUNC(RMII0, (2), "RMII0"),
        FUNC(RMII0RCLKO, (2), "RMII0RCLKO"),
        FUNC(RMII1, (2), "RMII1"),
        FUNC(RMII1RCLKO, (2), "RMII1RCLKO"),
        FUNC(SALT0, (2), "SALT0"),
        FUNC(SALT1, (2), "SALT1"),
        FUNC(SALT10, (2), "SALT10"),
        FUNC(SALT11, (2), "SALT11"),
        FUNC(SALT12, (2), "SALT12"),
        FUNC(SALT13, (2), "SALT13"),
        FUNC(SALT14, (2), "SALT14"),
        FUNC(SALT15, (2), "SALT15"),
        FUNC(SALT2, (2), "SALT2"),
        FUNC(SALT3, (2), "SALT3"),
        FUNC(SALT4, (2), "SALT4"),
        FUNC(SALT5, (2), "SALT5"),
        FUNC(SALT6, (2), "SALT6"),
        FUNC(SALT7, (2), "SALT7"),
        FUNC(SALT8, (2), "SALT8"),
        FUNC(SALT9, (2), "SALT9"),
        FUNC(SD, (3), "SD"),
        FUNC(SGMII, (1), "SGMII"),
        FUNC(SGPM0, (1, 4), "SGPM0", "DSGPM0"),
        FUNC(SGPM1, (1), "SGPM1"),
        FUNC(SGPS, (5), "SGPS"),
        FUNC(SIOONCTRLN0, (2), "SIOONCTRLN0"),
        FUNC(SIOONCTRLN1, (2), "SIOONCTRLN1"),
        FUNC(SIOPBIN0, (2), "SIOPBIN0"),
        FUNC(SIOPBIN1, (2), "SIOPBIN1"),
        FUNC(SIOPBON0, (2), "SIOPBON0"),
        FUNC(SIOPBON1, (2), "SIOPBON1"),
        FUNC(SIOPWREQN0, (2), "SIOPWREQN0"),
        FUNC(SIOPWREQN1, (2), "SIOPWREQN1"),
        FUNC(SIOPWRGD1, (2), "SIOPWRGD1"),
        FUNC(SIOS3N0, (2), "SIOS3N0"),
        FUNC(SIOS3N1, (2), "SIOS3N1"),
        FUNC(SIOS5N0, (2), "SIOS5N0"),
        FUNC(SIOS5N1, (2), "SIOS5N1"),
        FUNC(SIOSCIN0, (2), "SIOSCIN0"),
        FUNC(SIOSCIN1, (2), "SIOSCIN1"),
        FUNC(SMON0, (2), "SMON0"),
        FUNC(SMON1, (4), "SMON1"),
        FUNC(SPI0, (1), "SPI0"),
        FUNC(SPI0ABR, (1), "SPI0ABR"),
        FUNC(SPI0CS1, (1), "SPI0CS1"),
        FUNC(SPI0WPN, (1), "SPI0WPN"),
        FUNC(SPI1, (1), "SPI1"),
        FUNC(SPI1ABR, (1), "SPI1ABR"),
        FUNC(SPI1CS1, (1), "SPI1CS1"),
        FUNC(SPI1WPN, (1), "SPI1WPN"),
        FUNC(SPI2, (1), "SPI2"),
        FUNC(SPI2CS1, (1), "SPI2CS1"),
        FUNC(TACH0, (1), "TACH0"),
        FUNC(TACH1, (1), "TACH1"),
        FUNC(TACH10, (1), "TACH10"),
        FUNC(TACH11, (1), "TACH11"),
        FUNC(TACH12, (1), "TACH12"),
        FUNC(TACH13, (1), "TACH13"),
        FUNC(TACH14, (1), "TACH14"),
        FUNC(TACH15, (1), "TACH15"),
        FUNC(TACH2, (1), "TACH2"),
        FUNC(TACH3, (1), "TACH3"),
        FUNC(TACH4, (1), "TACH4"),
        FUNC(TACH5, (1), "TACH5"),
        FUNC(TACH6, (1), "TACH6"),
        FUNC(TACH7, (1), "TACH7"),
        FUNC(TACH8, (1), "TACH8"),
        FUNC(TACH9, (1), "TACH9"),
        FUNC(THRU0, (2), "THRU0"),
        FUNC(THRU1, (2), "THRU1"),
        FUNC(THRU2, (4), "THRU2"),
        FUNC(THRU3, (4), "THRU3"),
        FUNC(UART0, (1), "UART0"),
        FUNC(UART1, (1), "UART1"),
        FUNC(UART10, (3), "UART10"),
        FUNC(UART11, (3), "UART11"),
        FUNC(UART2, (1), "UART2"),
        FUNC(UART3, (1), "UART3"),
        FUNC(UART5, (4), "UART5"),
        FUNC(UART6, (4), "UART6"),
        FUNC(UART7, (1), "UART7"),
        FUNC(UART8, (3), "UART8"),
        FUNC(UART9, (3), "UART9"),
        FUNC(USB2C, (0, 1, 2, 3), "USB2CUD", "USB2CD", "USB2CH", "USB2CU"),
        FUNC(USB2D, (1, 2), "USB2DD", "USB2DH"),
        FUNC(USBUART, (2), "USBUART"),
        FUNC(VGA, (1), "VGA"),
        FUNC(VPI, (5), "VPI"),
        FUNC(WDTRST0N, (2), "WDTRST0N"),
        FUNC(WDTRST1N, (2), "WDTRST1N"),
        FUNC(WDTRST2N, (2), "WDTRST2N"),
        FUNC(WDTRST3N, (2), "WDTRST3N"),
        FUNC(WDTRST4N, (2), "WDTRST4N"),
        FUNC(WDTRST5N, (2), "WDTRST5N"),
        FUNC(WDTRST6N, (2), "WDTRST6N"),
        FUNC(WDTRST7N, (2), "WDTRST7N"),
};

static int aspeed_g7_soc1_pinctrl_probe(struct platform_device *pdev)
{
        struct aspeed_g7_soc1_pinctrl *pctl;
        struct device *dev = &pdev->dev;
        int i, ret;

        pctl = devm_kzalloc(dev, sizeof(*pctl), GFP_KERNEL);
        if (!pctl)
                return -ENOMEM;

        pctl->dev = dev;
        pctl->regmap = syscon_node_to_regmap(dev->parent->of_node);
        if (IS_ERR(pctl->regmap)) {
                dev_err(dev, "Failed to get regmap from parent\n");
                return PTR_ERR(pctl->regmap);
        }

        ret = devm_pinctrl_register_and_init(dev, &aspeed_g7_soc1_desc, pctl,
                                             &pctl->pctl);
        if (ret) {
                dev_err(dev, "Failed to register pinctrl\n");
                return ret;
        }

        for (i = 0; i < ARRAY_SIZE(aspeed_g7_soc1_groups); i++) {
                const struct pingroup *grp = &aspeed_g7_soc1_groups[i];

                ret = pinctrl_generic_add_group(pctl->pctl, grp->name,
                                                (const unsigned int *)grp->pins,
                                                grp->npins, pctl);
                if (ret < 0) {
                        dev_err(dev, "Failed to add group %s\n", grp->name);
                        return ret;
                }
        }

        for (i = 0; i < ARRAY_SIZE(aspeed_g7_soc1_functions); i++) {
                const struct aspeed_g7_soc1_function *func = &aspeed_g7_soc1_functions[i];

                ret = pinmux_generic_add_function(pctl->pctl, func->pinfunction.name,
                                                  func->pinfunction.groups,
                                                  func->pinfunction.ngroups, (void *)func);
                if (ret < 0) {
                        dev_err(dev, "Failed to add function %s\n", func->pinfunction.name);
                        return ret;
                }
        }

        return pinctrl_enable(pctl->pctl);
}

static const struct of_device_id aspeed_g7_soc1_pinctrl_match[] = {
        { .compatible = "aspeed,ast2700-soc1-pinctrl" },
        {}
};
MODULE_DEVICE_TABLE(of, aspeed_g7_soc1_pinctrl_match);

static struct platform_driver aspeed_g7_soc1_pinctrl_driver = {
        .probe = aspeed_g7_soc1_pinctrl_probe,
        .driver = {
                .name = "aspeed-g7-soc1-pinctrl",
                .of_match_table = aspeed_g7_soc1_pinctrl_match,
                .suppress_bind_attrs = true,
        },
};

static int __init aspeed_g7_soc1_pinctrl_init(void)
{
        return platform_driver_register(&aspeed_g7_soc1_pinctrl_driver);
}
arch_initcall(aspeed_g7_soc1_pinctrl_init);