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

pinctrl: meson: rework pinmux ops

This change prepare the introduction of new meson SoC. This new SoC will
share the same gpio/pinconf registers but the pinmux part will be
different. While the format of the data associated with each pinmux group
will change, the way to handle pinmuxing will be similar.

To deal with this new situation, the meson_pmx_struture is kept but the
data associated to it is now generic. This allows to reuse the basic
functions which would otherwise be copy/pasted in each pinmux driver
(such as getting the name a count of groups and functions) Only the
functions actually using this specific data is taken out of the common
code and is handling the SoC pinmuxing

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Jerome Brunet and committed by
Linus Walleij
ce385aa2 277d14eb

+194 -109
+7
drivers/pinctrl/meson/Kconfig
··· 14 14 config PINCTRL_MESON8 15 15 bool "Meson 8 SoC pinctrl driver" 16 16 depends on ARM 17 + select PINCTRL_MESON8_PMX 17 18 default y 18 19 19 20 config PINCTRL_MESON8B 20 21 bool "Meson 8b SoC pinctrl driver" 21 22 depends on ARM 23 + select PINCTRL_MESON8_PMX 22 24 default y 23 25 24 26 config PINCTRL_MESON_GXBB 25 27 bool "Meson gxbb SoC pinctrl driver" 26 28 depends on ARM64 29 + select PINCTRL_MESON8_PMX 27 30 default y 28 31 29 32 config PINCTRL_MESON_GXL 30 33 bool "Meson gxl SoC pinctrl driver" 31 34 depends on ARM64 35 + select PINCTRL_MESON8_PMX 32 36 default y 37 + 38 + config PINCTRL_MESON8_PMX 39 + bool 33 40 34 41 endif
+1
drivers/pinctrl/meson/Makefile
··· 1 1 obj-$(CONFIG_PINCTRL_MESON) += pinctrl-meson.o 2 + obj-$(CONFIG_PINCTRL_MESON8_PMX) += pinctrl-meson8-pmx.o 2 3 obj-$(CONFIG_PINCTRL_MESON8) += pinctrl-meson8.o 3 4 obj-$(CONFIG_PINCTRL_MESON8B) += pinctrl-meson8b.o 4 5 obj-$(CONFIG_PINCTRL_MESON_GXBB) += pinctrl-meson-gxbb.o
+3
drivers/pinctrl/meson/pinctrl-meson-gxbb.c
··· 14 14 15 15 #include <dt-bindings/gpio/meson-gxbb-gpio.h> 16 16 #include "pinctrl-meson.h" 17 + #include "pinctrl-meson8-pmx.h" 17 18 18 19 static const struct pinctrl_pin_desc meson_gxbb_periphs_pins[] = { 19 20 MESON_PIN(GPIOZ_0), ··· 835 834 .num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups), 836 835 .num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions), 837 836 .num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks), 837 + .pmx_ops = &meson8_pmx_ops, 838 838 }; 839 839 840 840 static struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { ··· 848 846 .num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups), 849 847 .num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions), 850 848 .num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks), 849 + .pmx_ops = &meson8_pmx_ops, 851 850 }; 852 851 853 852 static const struct of_device_id meson_gxbb_pinctrl_dt_match[] = {
+3
drivers/pinctrl/meson/pinctrl-meson-gxl.c
··· 14 14 15 15 #include <dt-bindings/gpio/meson-gxl-gpio.h> 16 16 #include "pinctrl-meson.h" 17 + #include "pinctrl-meson8-pmx.h" 17 18 18 19 static const struct pinctrl_pin_desc meson_gxl_periphs_pins[] = { 19 20 MESON_PIN(GPIOZ_0), ··· 820 819 .num_groups = ARRAY_SIZE(meson_gxl_periphs_groups), 821 820 .num_funcs = ARRAY_SIZE(meson_gxl_periphs_functions), 822 821 .num_banks = ARRAY_SIZE(meson_gxl_periphs_banks), 822 + .pmx_ops = &meson8_pmx_ops, 823 823 }; 824 824 825 825 static struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = { ··· 833 831 .num_groups = ARRAY_SIZE(meson_gxl_aobus_groups), 834 832 .num_funcs = ARRAY_SIZE(meson_gxl_aobus_functions), 835 833 .num_banks = ARRAY_SIZE(meson_gxl_aobus_banks), 834 + .pmx_ops = &meson8_pmx_ops, 836 835 }; 837 836 838 837 static const struct of_device_id meson_gxl_pinctrl_dt_match[] = {
+7 -89
drivers/pinctrl/meson/pinctrl-meson.c
··· 31 31 * In some cases the register ranges for pull enable and pull 32 32 * direction are the same and thus there are only 3 register ranges. 33 33 * 34 - * Every pinmux group can be enabled by a specific bit in the first 35 - * register range; when all groups for a given pin are disabled the 36 - * pin acts as a GPIO. 37 - * 38 34 * For the pull and GPIO configuration every bank uses a contiguous 39 35 * set of bits in the register sets described above; the same register 40 36 * can be shared by more banks with different offsets. ··· 144 148 .pin_dbg_show = meson_pin_dbg_show, 145 149 }; 146 150 147 - /** 148 - * meson_pmx_disable_other_groups() - disable other groups using a given pin 149 - * 150 - * @pc: meson pin controller device 151 - * @pin: number of the pin 152 - * @sel_group: index of the selected group, or -1 if none 153 - * 154 - * The function disables all pinmux groups using a pin except the 155 - * selected one. If @sel_group is -1 all groups are disabled, leaving 156 - * the pin in GPIO mode. 157 - */ 158 - static void meson_pmx_disable_other_groups(struct meson_pinctrl *pc, 159 - unsigned int pin, int sel_group) 160 - { 161 - struct meson_pmx_group *group; 162 - int i, j; 163 - 164 - for (i = 0; i < pc->data->num_groups; i++) { 165 - group = &pc->data->groups[i]; 166 - if (group->is_gpio || i == sel_group) 167 - continue; 168 - 169 - for (j = 0; j < group->num_pins; j++) { 170 - if (group->pins[j] == pin) { 171 - /* We have found a group using the pin */ 172 - regmap_update_bits(pc->reg_mux, 173 - group->reg * 4, 174 - BIT(group->bit), 0); 175 - } 176 - } 177 - } 178 - } 179 - 180 - static int meson_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num, 181 - unsigned group_num) 182 - { 183 - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 184 - struct meson_pmx_func *func = &pc->data->funcs[func_num]; 185 - struct meson_pmx_group *group = &pc->data->groups[group_num]; 186 - int i, ret = 0; 187 - 188 - dev_dbg(pc->dev, "enable function %s, group %s\n", func->name, 189 - group->name); 190 - 191 - /* 192 - * Disable groups using the same pin. 193 - * The selected group is not disabled to avoid glitches. 194 - */ 195 - for (i = 0; i < group->num_pins; i++) 196 - meson_pmx_disable_other_groups(pc, group->pins[i], group_num); 197 - 198 - /* Function 0 (GPIO) doesn't need any additional setting */ 199 - if (func_num) 200 - ret = regmap_update_bits(pc->reg_mux, group->reg * 4, 201 - BIT(group->bit), BIT(group->bit)); 202 - 203 - return ret; 204 - } 205 - 206 - static int meson_pmx_request_gpio(struct pinctrl_dev *pcdev, 207 - struct pinctrl_gpio_range *range, 208 - unsigned offset) 209 - { 210 - struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 211 - 212 - meson_pmx_disable_other_groups(pc, offset, -1); 213 - 214 - return 0; 215 - } 216 - 217 - static int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev) 151 + int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev) 218 152 { 219 153 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 220 154 221 155 return pc->data->num_funcs; 222 156 } 223 157 224 - static const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev, 225 - unsigned selector) 158 + const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev, 159 + unsigned selector) 226 160 { 227 161 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 228 162 229 163 return pc->data->funcs[selector].name; 230 164 } 231 165 232 - static int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, 233 - const char * const **groups, 234 - unsigned * const num_groups) 166 + int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, 167 + const char * const **groups, 168 + unsigned * const num_groups) 235 169 { 236 170 struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 237 171 ··· 170 244 171 245 return 0; 172 246 } 173 - 174 - static const struct pinmux_ops meson_pmx_ops = { 175 - .set_mux = meson_pmx_set_mux, 176 - .get_functions_count = meson_pmx_get_funcs_count, 177 - .get_function_name = meson_pmx_get_func_name, 178 - .get_function_groups = meson_pmx_get_groups, 179 - .gpio_request_enable = meson_pmx_request_gpio, 180 - }; 181 247 182 248 static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, 183 249 unsigned long *configs, unsigned num_configs) ··· 527 609 pc->desc.name = "pinctrl-meson"; 528 610 pc->desc.owner = THIS_MODULE; 529 611 pc->desc.pctlops = &meson_pctrl_ops; 530 - pc->desc.pmxops = &meson_pmx_ops; 612 + pc->desc.pmxops = pc->data->pmx_ops; 531 613 pc->desc.confops = &meson_pinconf_ops; 532 614 pc->desc.pins = pc->data->pins; 533 615 pc->desc.npins = pc->data->num_pins;
+11 -20
drivers/pinctrl/meson/pinctrl-meson.h
··· 32 32 const char *name; 33 33 const unsigned int *pins; 34 34 unsigned int num_pins; 35 - bool is_gpio; 36 - unsigned int reg; 37 - unsigned int bit; 35 + const void *data; 38 36 }; 39 37 40 38 /** ··· 107 109 unsigned int num_funcs; 108 110 struct meson_bank *banks; 109 111 unsigned int num_banks; 112 + const struct pinmux_ops *pmx_ops; 110 113 }; 111 114 112 115 struct meson_pinctrl { ··· 122 123 struct gpio_chip chip; 123 124 struct device_node *of_node; 124 125 }; 125 - 126 - #define GROUP(grp, r, b) \ 127 - { \ 128 - .name = #grp, \ 129 - .pins = grp ## _pins, \ 130 - .num_pins = ARRAY_SIZE(grp ## _pins), \ 131 - .reg = r, \ 132 - .bit = b, \ 133 - } 134 - 135 - #define GPIO_GROUP(gpio) \ 136 - { \ 137 - .name = #gpio, \ 138 - .pins = (const unsigned int[]){ gpio }, \ 139 - .num_pins = 1, \ 140 - .is_gpio = true, \ 141 - } 142 126 143 127 #define FUNCTION(fn) \ 144 128 { \ ··· 147 165 } 148 166 149 167 #define MESON_PIN(x) PINCTRL_PIN(x, #x) 168 + 169 + /* Common pmx functions */ 170 + int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev); 171 + const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev, 172 + unsigned selector); 173 + int meson_pmx_get_groups(struct pinctrl_dev *pcdev, 174 + unsigned selector, 175 + const char * const **groups, 176 + unsigned * const num_groups); 150 177 151 178 /* Common probe function */ 152 179 int meson_pinctrl_probe(struct platform_device *pdev);
+108
drivers/pinctrl/meson/pinctrl-meson8-pmx.c
··· 1 + /* 2 + * First generation of pinmux driver for Amlogic Meson SoCs 3 + * 4 + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 5 + * Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * version 2 as published by the Free Software Foundation. 10 + * 11 + * You should have received a copy of the GNU General Public License 12 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 13 + */ 14 + 15 + /* For this first generation of pinctrl driver every pinmux group can be 16 + * enabled by a specific bit in the first register range. When all groups for 17 + * a given pin are disabled the pin acts as a GPIO. 18 + */ 19 + #include <linux/device.h> 20 + #include <linux/regmap.h> 21 + #include <linux/pinctrl/pinctrl.h> 22 + #include <linux/pinctrl/pinmux.h> 23 + 24 + #include "pinctrl-meson.h" 25 + #include "pinctrl-meson8-pmx.h" 26 + 27 + /** 28 + * meson8_pmx_disable_other_groups() - disable other groups using a given pin 29 + * 30 + * @pc: meson pin controller device 31 + * @pin: number of the pin 32 + * @sel_group: index of the selected group, or -1 if none 33 + * 34 + * The function disables all pinmux groups using a pin except the 35 + * selected one. If @sel_group is -1 all groups are disabled, leaving 36 + * the pin in GPIO mode. 37 + */ 38 + static void meson8_pmx_disable_other_groups(struct meson_pinctrl *pc, 39 + unsigned int pin, int sel_group) 40 + { 41 + struct meson_pmx_group *group; 42 + struct meson8_pmx_data *pmx_data; 43 + int i, j; 44 + 45 + for (i = 0; i < pc->data->num_groups; i++) { 46 + group = &pc->data->groups[i]; 47 + pmx_data = (struct meson8_pmx_data *)group->data; 48 + if (pmx_data->is_gpio || i == sel_group) 49 + continue; 50 + 51 + for (j = 0; j < group->num_pins; j++) { 52 + if (group->pins[j] == pin) { 53 + /* We have found a group using the pin */ 54 + regmap_update_bits(pc->reg_mux, 55 + pmx_data->reg * 4, 56 + BIT(pmx_data->bit), 0); 57 + } 58 + } 59 + } 60 + } 61 + 62 + static int meson8_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num, 63 + unsigned group_num) 64 + { 65 + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 66 + struct meson_pmx_func *func = &pc->data->funcs[func_num]; 67 + struct meson_pmx_group *group = &pc->data->groups[group_num]; 68 + struct meson8_pmx_data *pmx_data = 69 + (struct meson8_pmx_data *)group->data; 70 + int i, ret = 0; 71 + 72 + dev_dbg(pc->dev, "enable function %s, group %s\n", func->name, 73 + group->name); 74 + 75 + /* 76 + * Disable groups using the same pin. 77 + * The selected group is not disabled to avoid glitches. 78 + */ 79 + for (i = 0; i < group->num_pins; i++) 80 + meson8_pmx_disable_other_groups(pc, group->pins[i], group_num); 81 + 82 + /* Function 0 (GPIO) doesn't need any additional setting */ 83 + if (func_num) 84 + ret = regmap_update_bits(pc->reg_mux, pmx_data->reg * 4, 85 + BIT(pmx_data->bit), 86 + BIT(pmx_data->bit)); 87 + 88 + return ret; 89 + } 90 + 91 + static int meson8_pmx_request_gpio(struct pinctrl_dev *pcdev, 92 + struct pinctrl_gpio_range *range, 93 + unsigned offset) 94 + { 95 + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); 96 + 97 + meson8_pmx_disable_other_groups(pc, offset, -1); 98 + 99 + return 0; 100 + } 101 + 102 + const struct pinmux_ops meson8_pmx_ops = { 103 + .set_mux = meson8_pmx_set_mux, 104 + .get_functions_count = meson_pmx_get_funcs_count, 105 + .get_function_name = meson_pmx_get_func_name, 106 + .get_function_groups = meson_pmx_get_groups, 107 + .gpio_request_enable = meson8_pmx_request_gpio, 108 + };
+48
drivers/pinctrl/meson/pinctrl-meson8-pmx.h
··· 1 + /* 2 + * First generation of pinmux driver for Amlogic Meson SoCs 3 + * 4 + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 5 + * Copyright (C) 2017 Jerome Brunet <jbrunet@baylibre.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License 9 + * version 2 as published by the Free Software Foundation. 10 + * 11 + * You should have received a copy of the GNU General Public License 12 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 13 + */ 14 + 15 + struct meson8_pmx_data { 16 + bool is_gpio; 17 + unsigned int reg; 18 + unsigned int bit; 19 + }; 20 + 21 + #define PMX_DATA(r, b, g) \ 22 + { \ 23 + .reg = r, \ 24 + .bit = b, \ 25 + .is_gpio = g, \ 26 + } 27 + 28 + #define GROUP(grp, r, b) \ 29 + { \ 30 + .name = #grp, \ 31 + .pins = grp ## _pins, \ 32 + .num_pins = ARRAY_SIZE(grp ## _pins), \ 33 + .data = (const struct meson8_pmx_data[]){ \ 34 + PMX_DATA(r, b, false), \ 35 + }, \ 36 + } 37 + 38 + #define GPIO_GROUP(gpio) \ 39 + { \ 40 + .name = #gpio, \ 41 + .pins = (const unsigned int[]){ gpio }, \ 42 + .num_pins = 1, \ 43 + .data = (const struct meson8_pmx_data[]){ \ 44 + PMX_DATA(0, 0, true), \ 45 + }, \ 46 + } 47 + 48 + extern const struct pinmux_ops meson8_pmx_ops;
+3
drivers/pinctrl/meson/pinctrl-meson8.c
··· 13 13 14 14 #include <dt-bindings/gpio/meson8-gpio.h> 15 15 #include "pinctrl-meson.h" 16 + #include "pinctrl-meson8-pmx.h" 16 17 17 18 static const struct pinctrl_pin_desc meson8_cbus_pins[] = { 18 19 MESON_PIN(GPIOX_0), ··· 1055 1054 .num_groups = ARRAY_SIZE(meson8_cbus_groups), 1056 1055 .num_funcs = ARRAY_SIZE(meson8_cbus_functions), 1057 1056 .num_banks = ARRAY_SIZE(meson8_cbus_banks), 1057 + .pmx_ops = &meson8_pmx_ops, 1058 1058 }; 1059 1059 1060 1060 static struct meson_pinctrl_data meson8_aobus_pinctrl_data = { ··· 1068 1066 .num_groups = ARRAY_SIZE(meson8_aobus_groups), 1069 1067 .num_funcs = ARRAY_SIZE(meson8_aobus_functions), 1070 1068 .num_banks = ARRAY_SIZE(meson8_aobus_banks), 1069 + .pmx_ops = &meson8_pmx_ops, 1071 1070 }; 1072 1071 1073 1072 static const struct of_device_id meson8_pinctrl_dt_match[] = {
+3
drivers/pinctrl/meson/pinctrl-meson8b.c
··· 14 14 15 15 #include <dt-bindings/gpio/meson8b-gpio.h> 16 16 #include "pinctrl-meson.h" 17 + #include "pinctrl-meson8-pmx.h" 17 18 18 19 static const struct pinctrl_pin_desc meson8b_cbus_pins[] = { 19 20 MESON_PIN(GPIOX_0), ··· 915 914 .num_groups = ARRAY_SIZE(meson8b_cbus_groups), 916 915 .num_funcs = ARRAY_SIZE(meson8b_cbus_functions), 917 916 .num_banks = ARRAY_SIZE(meson8b_cbus_banks), 917 + .pmx_ops = &meson8_pmx_ops, 918 918 }; 919 919 920 920 static struct meson_pinctrl_data meson8b_aobus_pinctrl_data = { ··· 928 926 .num_groups = ARRAY_SIZE(meson8b_aobus_groups), 929 927 .num_funcs = ARRAY_SIZE(meson8b_aobus_functions), 930 928 .num_banks = ARRAY_SIZE(meson8b_aobus_banks), 929 + .pmx_ops = &meson8_pmx_ops, 931 930 }; 932 931 933 932 static const struct of_device_id meson8b_pinctrl_dt_match[] = {