| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 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 | }; |