1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2023, Microchip
4 */
5
6 #include <assert.h>
7 #include <drivers/pinctrl.h>
8 #include <libfdt.h>
9 #include <stdio.h>
10 #include <tee_api_defines.h>
11 #include <tee_api_defines_extensions.h>
12 #include <tee_api_types.h>
13 #include <util.h>
14
15 static const char * const pin_modes[PINCTRL_DT_PROP_MAX] = {
16 [PINCTRL_DT_PROP_BIAS_DISABLE] = "bias-disable",
17 [PINCTRL_DT_PROP_BIAS_PULL_UP] = "bias-pull-up",
18 [PINCTRL_DT_PROP_BIAS_PULL_DOWN] = "bias-pull-down",
19 };
20
pinctrl_parse_dt_pin_modes(const void * fdt,int node,bitstr_t ** modes)21 TEE_Result pinctrl_parse_dt_pin_modes(const void *fdt, int node,
22 bitstr_t **modes)
23 {
24 unsigned int i = 0;
25 bitstr_t *modes_ptr = NULL;
26
27 modes_ptr = bit_alloc(PINCTRL_DT_PROP_MAX);
28 if (!modes_ptr)
29 return TEE_ERROR_OUT_OF_MEMORY;
30
31 for (i = 0; i < ARRAY_SIZE(pin_modes); i++)
32 if (fdt_getprop(fdt, node, pin_modes[i], NULL))
33 bit_set(modes_ptr, i);
34
35 *modes = modes_ptr;
36
37 return TEE_SUCCESS;
38 }
39
pinctrl_apply_state(struct pinctrl_state * state)40 TEE_Result pinctrl_apply_state(struct pinctrl_state *state)
41 {
42 unsigned int i = 0;
43 struct pinconf *conf = NULL;
44 TEE_Result res = TEE_ERROR_GENERIC;
45
46 for (i = 0; i < state->conf_count; i++) {
47 conf = state->confs[i];
48
49 res = conf->ops->conf_apply(conf);
50 if (res) {
51 EMSG("Failed to apply pin conf");
52 return res;
53 }
54 }
55
56 return TEE_SUCCESS;
57 }
58
pinctrl_free_state(struct pinctrl_state * state)59 void pinctrl_free_state(struct pinctrl_state *state)
60 {
61 unsigned int i = 0;
62
63 for (i = 0; i < state->conf_count; i++)
64 state->confs[i]->ops->conf_free(state->confs[i]);
65
66 free(state);
67 }
68
pinctrl_get_state_by_idx(const void * fdt,int nodeoffset,unsigned int pinctrl_index,struct pinctrl_state ** state_ret)69 TEE_Result pinctrl_get_state_by_idx(const void *fdt, int nodeoffset,
70 unsigned int pinctrl_index,
71 struct pinctrl_state **state_ret)
72 {
73 int bw = 0;
74 unsigned int conf_id = 0;
75 const uint32_t *prop = NULL;
76 unsigned int conf_count = 0;
77 /* Enough char to hold "pinctrl-<max_int>" */
78 char prop_name[8 + 20 + 1] = { };
79 struct pinctrl_state *state = NULL;
80 TEE_Result res = TEE_ERROR_GENERIC;
81
82 bw = snprintf(prop_name, sizeof(prop_name), "pinctrl-%d",
83 pinctrl_index);
84 if (bw >= (int)sizeof(prop_name))
85 return TEE_ERROR_OVERFLOW;
86
87 prop = fdt_getprop(fdt, nodeoffset, prop_name, (int *)&conf_count);
88 if (!prop)
89 return TEE_ERROR_ITEM_NOT_FOUND;
90
91 conf_count /= sizeof(uint32_t);
92 state = calloc(1, sizeof(struct pinctrl_state) +
93 conf_count * sizeof(struct pinconf *));
94 if (!state)
95 return TEE_ERROR_OUT_OF_MEMORY;
96
97 state->conf_count = conf_count;
98 for (conf_id = 0; conf_id < conf_count; conf_id++) {
99 void *pinconf = NULL;
100
101 res = dt_driver_device_from_node_idx_prop(prop_name, fdt,
102 nodeoffset, conf_id,
103 DT_DRIVER_PINCTRL,
104 &pinconf);
105 if (res) {
106 free(state);
107 return res;
108 }
109
110 state->confs[conf_id] = pinconf;
111 }
112
113 *state_ret = state;
114
115 return TEE_SUCCESS;
116 }
117
pinctrl_get_state_by_name(const void * fdt,int nodeoffset,const char * name,struct pinctrl_state ** state)118 TEE_Result pinctrl_get_state_by_name(const void *fdt, int nodeoffset,
119 const char *name,
120 struct pinctrl_state **state)
121 {
122 int pinctrl_index = 0;
123
124 if (!name)
125 name = "default";
126
127 pinctrl_index = fdt_stringlist_search(fdt, nodeoffset, "pinctrl-names",
128 name);
129 if (pinctrl_index < 0) {
130 *state = NULL;
131 if (pinctrl_index == -FDT_ERR_NOTFOUND)
132 return TEE_ERROR_ITEM_NOT_FOUND;
133 else
134 return TEE_ERROR_GENERIC;
135 }
136
137 return pinctrl_get_state_by_idx(fdt, nodeoffset, pinctrl_index, state);
138 }
139