Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pinctrl: meson: support amlogic S6/S7/S7D SoC

In some Amlogic SoCs, to save register space or due to some
abnormal arrangements, two sets of pins share one mux register.

A group starting from pin0 is the main pin group, which acquires
the register address through DTS and has management permissions,
but the register bit offset is undetermined.

Another GPIO group as a subordinate group. Some pins mux use share
register and bit offset from bit0 . But this group do not have
register management permissions.

This submission implements this situation.

Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
Link: https://lore.kernel.org/20250527-s6-s7-pinctrl-v3-3-44f6a0451519@amlogic.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Xianwei Zhao and committed by
Linus Walleij
1f8e5dfd cfdedf73

+99 -2
+99 -2
drivers/pinctrl/meson/pinctrl-amlogic-a4.c
··· 50 50 u32 bit_offset[AML_NUM_REG]; 51 51 }; 52 52 53 + /* 54 + * partial bank(subordinate) pins mux config use other bank(main) mux registgers 55 + * m_bank_id: the main bank which pin_id from 0, but register bit not from bit 0 56 + * m_bit_offs: bit offset the main bank mux register 57 + * sid: start pin_id of subordinate bank 58 + * eid: end pin_id of subordinate bank 59 + */ 60 + struct multi_mux { 61 + unsigned int m_bank_id; 62 + unsigned int m_bit_offs; 63 + unsigned int sid; 64 + unsigned int eid; 65 + }; 66 + 53 67 struct aml_pctl_data { 54 68 unsigned int number; 69 + const struct multi_mux *p_mux; 55 70 }; 56 71 57 72 struct aml_pmx_func { ··· 86 71 struct gpio_chip gpio_chip; 87 72 struct aml_pio_control pc; 88 73 u32 bank_id; 74 + u32 mux_bit_offs; 89 75 unsigned int pin_base; 90 76 struct regmap *reg_mux; 91 77 struct regmap *reg_gpio; 92 78 struct regmap *reg_ds; 79 + const struct multi_mux *p_mux; 93 80 }; 94 81 95 82 struct aml_pinctrl { ··· 123 106 "GPIOCC", "TEST_N", "ANALOG" 124 107 }; 125 108 109 + const struct multi_mux multi_mux_s7[] = { 110 + { 111 + .m_bank_id = AMLOGIC_GPIO_CC, 112 + .m_bit_offs = 24, 113 + .sid = (AMLOGIC_GPIO_X << 8) + 16, 114 + .eid = (AMLOGIC_GPIO_X << 8) + 19, 115 + }, 116 + }; 117 + 118 + const struct aml_pctl_data s7_priv_data = { 119 + .number = ARRAY_SIZE(multi_mux_s7), 120 + .p_mux = multi_mux_s7, 121 + }; 122 + 123 + const struct multi_mux multi_mux_s6[] = { 124 + { 125 + .m_bank_id = AMLOGIC_GPIO_CC, 126 + .m_bit_offs = 24, 127 + .sid = (AMLOGIC_GPIO_X << 8) + 16, 128 + .eid = (AMLOGIC_GPIO_X << 8) + 19, 129 + }, { 130 + .m_bank_id = AMLOGIC_GPIO_F, 131 + .m_bit_offs = 4, 132 + .sid = (AMLOGIC_GPIO_D << 8) + 6, 133 + .eid = (AMLOGIC_GPIO_D << 8) + 6, 134 + }, 135 + }; 136 + 137 + const struct aml_pctl_data s6_priv_data = { 138 + .number = ARRAY_SIZE(multi_mux_s6), 139 + .p_mux = multi_mux_s6, 140 + }; 141 + 126 142 static int aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range *range, 127 143 unsigned int pin, unsigned int *reg, 128 144 unsigned int *offset) 129 145 { 130 146 unsigned int shift; 131 147 132 - shift = (pin - range->pin_base) << 2; 148 + shift = ((pin - range->pin_base) << 2) + *offset; 133 149 *reg = (shift / 32) * 4; 134 150 *offset = shift % 32; 135 151 ··· 174 124 int pin_id, int func) 175 125 { 176 126 struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc); 127 + unsigned int shift; 177 128 int reg; 178 - int offset; 129 + int i; 130 + unsigned int offset = bank->mux_bit_offs; 131 + const struct multi_mux *p_mux; 179 132 133 + /* peculiar mux reg set */ 134 + if (bank->p_mux) { 135 + p_mux = bank->p_mux; 136 + if (pin_id >= p_mux->sid && pin_id <= p_mux->eid) { 137 + bank = NULL; 138 + for (i = 0; i < info->nbanks; i++) { 139 + if (info->banks[i].bank_id == p_mux->m_bank_id) { 140 + bank = &info->banks[i]; 141 + break; 142 + } 143 + } 144 + 145 + if (!bank || !bank->reg_mux) 146 + return -EINVAL; 147 + 148 + shift = (pin_id - p_mux->sid) << 2; 149 + reg = (shift / 32) * 4; 150 + offset = shift % 32; 151 + return regmap_update_bits(bank->reg_mux, reg, 152 + 0xf << offset, (func & 0xf) << offset); 153 + } 154 + } 155 + 156 + /* normal mux reg set */ 180 157 if (!bank->reg_mux) 181 158 return 0; 182 159 ··· 899 822 static void init_bank_register_bit(struct aml_pinctrl *info, 900 823 struct aml_gpio_bank *bank) 901 824 { 825 + const struct aml_pctl_data *data = info->data; 826 + const struct multi_mux *p_mux; 902 827 int i; 903 828 904 829 for (i = 0; i < AML_NUM_REG; i++) { 905 830 bank->pc.reg_offset[i] = aml_def_regoffs[i]; 906 831 bank->pc.bit_offset[i] = 0; 832 + } 833 + 834 + bank->mux_bit_offs = 0; 835 + 836 + if (data) { 837 + for (i = 0; i < data->number; i++) { 838 + p_mux = &data->p_mux[i]; 839 + if (bank->bank_id == p_mux->m_bank_id) { 840 + bank->mux_bit_offs = p_mux->m_bit_offs; 841 + break; 842 + } 843 + if (p_mux->sid >> 8 == bank->bank_id) { 844 + bank->p_mux = p_mux; 845 + break; 846 + } 847 + } 907 848 } 908 849 } 909 850 ··· 1089 994 1090 995 static const struct of_device_id aml_pctl_of_match[] = { 1091 996 { .compatible = "amlogic,pinctrl-a4", }, 997 + { .compatible = "amlogic,pinctrl-s7", .data = &s7_priv_data, }, 998 + { .compatible = "amlogic,pinctrl-s6", .data = &s6_priv_data, }, 1092 999 { /* sentinel */ } 1093 1000 }; 1094 1001 MODULE_DEVICE_TABLE(of, aml_pctl_dt_match);