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 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 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 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 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++) { 999aec039eSClément Léger state->confs[conf_id] = 1009aec039eSClément Léger dt_driver_device_from_node_idx_prop(prop_name, fdt, 1019aec039eSClément Léger nodeoffset, conf_id, 1029aec039eSClément Léger DT_DRIVER_PINCTRL, 1039aec039eSClément Léger &res); 1049aec039eSClément Léger if (res) { 1059aec039eSClément Léger free(state); 1069aec039eSClément Léger return res; 1079aec039eSClément Léger } 1089aec039eSClément Léger } 1099aec039eSClément Léger 1109aec039eSClément Léger *state_ret = state; 1119aec039eSClément Léger 1129aec039eSClément Léger return TEE_SUCCESS; 1139aec039eSClément Léger } 1149aec039eSClément Léger 1159aec039eSClément Léger TEE_Result pinctrl_get_state_by_name(const void *fdt, int nodeoffset, 1169aec039eSClément Léger const char *name, 1179aec039eSClément Léger struct pinctrl_state **state) 1189aec039eSClément Léger { 1199aec039eSClément Léger int pinctrl_index = 0; 1209aec039eSClément Léger 1219aec039eSClément Léger if (!name) 1229aec039eSClément Léger name = "default"; 1239aec039eSClément Léger 1249aec039eSClément Léger pinctrl_index = fdt_stringlist_search(fdt, nodeoffset, "pinctrl-names", 1259aec039eSClément Léger name); 1269aec039eSClément Léger if (pinctrl_index < 0) { 1279aec039eSClément Léger *state = NULL; 128*f12b4eadSEtienne Carriere if (pinctrl_index == -FDT_ERR_NOTFOUND) 129*f12b4eadSEtienne Carriere return TEE_ERROR_ITEM_NOT_FOUND; 130*f12b4eadSEtienne Carriere else 1319aec039eSClément Léger return TEE_ERROR_GENERIC; 1329aec039eSClément Léger } 1339aec039eSClément Léger 1349aec039eSClément Léger return pinctrl_get_state_by_idx(fdt, nodeoffset, pinctrl_index, state); 1359aec039eSClément Léger } 136