xref: /optee_os/core/drivers/pinctrl/pinctrl.c (revision b357d34fe91f4e7f6e0eacea17a7fbe5f6c01e7e)
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