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