xref: /optee_os/core/drivers/pinctrl/pinctrl.c (revision b357d34fe91f4e7f6e0eacea17a7fbe5f6c01e7e)
19aec039eSClément Léger // SPDX-License-Identifier: BSD-2-Clause
29aec039eSClément Léger /*
39aec039eSClément Léger  * Copyright (c) 2023, Microchip
49aec039eSClément Léger  */
59aec039eSClément Léger 
69aec039eSClément Léger #include <assert.h>
79aec039eSClément Léger #include <drivers/pinctrl.h>
89aec039eSClément Léger #include <libfdt.h>
99aec039eSClément Léger #include <stdio.h>
109aec039eSClément Léger #include <tee_api_defines.h>
119aec039eSClément Léger #include <tee_api_defines_extensions.h>
129aec039eSClément Léger #include <tee_api_types.h>
139aec039eSClément Léger #include <util.h>
149aec039eSClément Léger 
159aec039eSClément Léger static const char * const pin_modes[PINCTRL_DT_PROP_MAX] = {
169aec039eSClément Léger 	[PINCTRL_DT_PROP_BIAS_DISABLE] = "bias-disable",
179aec039eSClément Léger 	[PINCTRL_DT_PROP_BIAS_PULL_UP] = "bias-pull-up",
189aec039eSClément Léger 	[PINCTRL_DT_PROP_BIAS_PULL_DOWN] = "bias-pull-down",
199aec039eSClément Léger };
209aec039eSClément Léger 
pinctrl_parse_dt_pin_modes(const void * fdt,int node,bitstr_t ** modes)219aec039eSClément Léger TEE_Result pinctrl_parse_dt_pin_modes(const void *fdt, int node,
229aec039eSClément Léger 				      bitstr_t **modes)
239aec039eSClément Léger {
249aec039eSClément Léger 	unsigned int i = 0;
259aec039eSClément Léger 	bitstr_t *modes_ptr = NULL;
269aec039eSClément Léger 
279aec039eSClément Léger 	modes_ptr = bit_alloc(PINCTRL_DT_PROP_MAX);
289aec039eSClément Léger 	if (!modes_ptr)
299aec039eSClément Léger 		return TEE_ERROR_OUT_OF_MEMORY;
309aec039eSClément Léger 
319aec039eSClément Léger 	for (i = 0; i < ARRAY_SIZE(pin_modes); i++)
329aec039eSClément Léger 		if (fdt_getprop(fdt, node, pin_modes[i], NULL))
339aec039eSClément Léger 			bit_set(modes_ptr, i);
349aec039eSClément Léger 
359aec039eSClément Léger 	*modes = modes_ptr;
369aec039eSClément Léger 
379aec039eSClément Léger 	return TEE_SUCCESS;
389aec039eSClément Léger }
399aec039eSClément Léger 
pinctrl_apply_state(struct pinctrl_state * state)409aec039eSClément Léger TEE_Result pinctrl_apply_state(struct pinctrl_state *state)
419aec039eSClément Léger {
429aec039eSClément Léger 	unsigned int i = 0;
439aec039eSClément Léger 	struct pinconf *conf = NULL;
449aec039eSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
459aec039eSClément Léger 
469aec039eSClément Léger 	for (i = 0; i < state->conf_count; i++) {
479aec039eSClément Léger 		conf = state->confs[i];
489aec039eSClément Léger 
499aec039eSClément Léger 		res = conf->ops->conf_apply(conf);
509aec039eSClément Léger 		if (res) {
519aec039eSClément Léger 			EMSG("Failed to apply pin conf");
529aec039eSClément Léger 			return res;
539aec039eSClément Léger 		}
549aec039eSClément Léger 	}
559aec039eSClément Léger 
569aec039eSClément Léger 	return TEE_SUCCESS;
579aec039eSClément Léger }
589aec039eSClément Léger 
pinctrl_free_state(struct pinctrl_state * state)599aec039eSClément Léger void pinctrl_free_state(struct pinctrl_state *state)
609aec039eSClément Léger {
619aec039eSClément Léger 	unsigned int i = 0;
629aec039eSClément Léger 
639aec039eSClément Léger 	for (i = 0; i < state->conf_count; i++)
649aec039eSClément Léger 		state->confs[i]->ops->conf_free(state->confs[i]);
659aec039eSClément Léger 
669aec039eSClément Léger 	free(state);
679aec039eSClément Léger }
689aec039eSClément Léger 
pinctrl_get_state_by_idx(const void * fdt,int nodeoffset,unsigned int pinctrl_index,struct pinctrl_state ** state_ret)699aec039eSClément Léger TEE_Result pinctrl_get_state_by_idx(const void *fdt, int nodeoffset,
709aec039eSClément Léger 				    unsigned int pinctrl_index,
719aec039eSClément Léger 				    struct pinctrl_state **state_ret)
729aec039eSClément Léger {
739aec039eSClément Léger 	int bw = 0;
749aec039eSClément Léger 	unsigned int conf_id = 0;
759aec039eSClément Léger 	const uint32_t *prop = NULL;
769aec039eSClément Léger 	unsigned int conf_count = 0;
779aec039eSClément Léger 	/* Enough char to hold "pinctrl-<max_int>" */
789aec039eSClément Léger 	char prop_name[8 + 20 + 1] = { };
799aec039eSClément Léger 	struct pinctrl_state *state = NULL;
809aec039eSClément Léger 	TEE_Result res = TEE_ERROR_GENERIC;
819aec039eSClément Léger 
829aec039eSClément Léger 	bw = snprintf(prop_name, sizeof(prop_name), "pinctrl-%d",
839aec039eSClément Léger 		      pinctrl_index);
849aec039eSClément Léger 	if (bw >= (int)sizeof(prop_name))
859aec039eSClément Léger 		return TEE_ERROR_OVERFLOW;
869aec039eSClément Léger 
879aec039eSClément Léger 	prop = fdt_getprop(fdt, nodeoffset, prop_name, (int *)&conf_count);
889aec039eSClément Léger 	if (!prop)
899aec039eSClément Léger 		return TEE_ERROR_ITEM_NOT_FOUND;
909aec039eSClément Léger 
919aec039eSClément Léger 	conf_count /= sizeof(uint32_t);
929aec039eSClément Léger 	state = calloc(1, sizeof(struct pinctrl_state) +
939aec039eSClément Léger 			  conf_count * sizeof(struct pinconf *));
949aec039eSClément Léger 	if (!state)
959aec039eSClément Léger 		return TEE_ERROR_OUT_OF_MEMORY;
969aec039eSClément Léger 
979aec039eSClément Léger 	state->conf_count = conf_count;
989aec039eSClément Léger 	for (conf_id = 0; conf_id < conf_count; conf_id++) {
99*b357d34fSEtienne Carriere 		void *pinconf = NULL;
100*b357d34fSEtienne Carriere 
101*b357d34fSEtienne Carriere 		res = dt_driver_device_from_node_idx_prop(prop_name, fdt,
1029aec039eSClément Léger 							  nodeoffset, conf_id,
1039aec039eSClément Léger 							  DT_DRIVER_PINCTRL,
104*b357d34fSEtienne Carriere 							  &pinconf);
1059aec039eSClément Léger 		if (res) {
1069aec039eSClément Léger 			free(state);
1079aec039eSClément Léger 			return res;
1089aec039eSClément Léger 		}
109*b357d34fSEtienne Carriere 
110*b357d34fSEtienne Carriere 		state->confs[conf_id] = pinconf;
1119aec039eSClément Léger 	}
1129aec039eSClément Léger 
1139aec039eSClément Léger 	*state_ret = state;
1149aec039eSClément Léger 
1159aec039eSClément Léger 	return TEE_SUCCESS;
1169aec039eSClément Léger }
1179aec039eSClément Léger 
pinctrl_get_state_by_name(const void * fdt,int nodeoffset,const char * name,struct pinctrl_state ** state)1189aec039eSClément Léger TEE_Result pinctrl_get_state_by_name(const void *fdt, int nodeoffset,
1199aec039eSClément Léger 				     const char *name,
1209aec039eSClément Léger 				     struct pinctrl_state **state)
1219aec039eSClément Léger {
1229aec039eSClément Léger 	int pinctrl_index = 0;
1239aec039eSClément Léger 
1249aec039eSClément Léger 	if (!name)
1259aec039eSClément Léger 		name = "default";
1269aec039eSClément Léger 
1279aec039eSClément Léger 	pinctrl_index = fdt_stringlist_search(fdt, nodeoffset, "pinctrl-names",
1289aec039eSClément Léger 					      name);
1299aec039eSClément Léger 	if (pinctrl_index < 0) {
1309aec039eSClément Léger 		*state = NULL;
131f12b4eadSEtienne Carriere 		if (pinctrl_index == -FDT_ERR_NOTFOUND)
132f12b4eadSEtienne Carriere 			return TEE_ERROR_ITEM_NOT_FOUND;
133f12b4eadSEtienne Carriere 		else
1349aec039eSClément Léger 			return TEE_ERROR_GENERIC;
1359aec039eSClément Léger 	}
1369aec039eSClément Léger 
1379aec039eSClément Léger 	return pinctrl_get_state_by_idx(fdt, nodeoffset, pinctrl_index, state);
1389aec039eSClément Léger }
139