1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-11-26 GuEe-GUI first version
9 */
10
11 #include <rtthread.h>
12 #include <rtservice.h>
13 #include <rtdevice.h>
14
15 #define DBG_TAG "rtdm.pinctrl"
16 #define DBG_LVL DBG_INFO
17 #include <rtdbg.h>
18
19 #ifdef RT_USING_OFW
ofw_pin_ctrl_confs_apply(struct rt_ofw_node * np,int index)20 static rt_err_t ofw_pin_ctrl_confs_apply(struct rt_ofw_node *np, int index)
21 {
22 rt_err_t err = -RT_EEMPTY;
23 rt_phandle phandle;
24 const fdt32_t *cell;
25 struct rt_ofw_prop *prop;
26 char pinctrl_n_name[sizeof("pinctrl-0")];
27
28 rt_sprintf(pinctrl_n_name, "pinctrl-%d", index);
29 index = 0;
30
31 rt_ofw_foreach_prop_u32(np, pinctrl_n_name, prop, cell, phandle)
32 {
33 struct rt_device_pin *pinctrl = RT_NULL;
34 struct rt_ofw_node *conf_np, *pinctrl_np;
35
36 conf_np = pinctrl_np = rt_ofw_find_node_by_phandle(phandle);
37
38 if (!conf_np)
39 {
40 err = -RT_EIO;
41
42 break;
43 }
44 /*
45 * We always assume the phandle in pinctrl-N is the pinctrl-device
46 * node's child node. If not, we need a better way to find it:
47 *
48 * / {
49 * serial@4600 {
50 * device_type = "serial";
51 * reg = <0x4600 0x100>;
52 * clock-frequency = <0>;
53 * pinctrl-names = "default";
54 * pinctrl-0 = <&uart_pin>;
55 * };
56 *
57 * i2c@4700 {
58 * reg = <0x4700 0x100>;
59 * pinctrl-names = "default";
60 * pinctrl-0 = <&i2c_pin_scl, &i2c_pin_sda>;
61 * };
62 *
63 * pinctrl: pinctrl {
64 *
65 * uart_pin {
66 * multi,pins =
67 * <0 PD0 1 &uart_rx_pull_up>,
68 * <0 PD1 1 &uart_tx_pull_up>;
69 * };
70 *
71 * i2c_pin_scl {
72 * single,pins = <0 PB1>;
73 * pull = <&i2c_pull_none_smt>;
74 * function = <1>;
75 * };
76 *
77 * i2c_pin_sda {
78 * single,pins = <0 PB2>;
79 * pull = <&i2c_pull_none_smt>;
80 * function = <1>;
81 * };
82 * };
83 * }
84 */
85 rt_ofw_foreach_parent_node(pinctrl_np)
86 {
87 if (rt_ofw_prop_read_bool(pinctrl_np, "compatible"))
88 {
89 break;
90 }
91 }
92
93 if (pinctrl_np)
94 {
95 if (!rt_ofw_data(pinctrl_np))
96 {
97 rt_platform_ofw_request(pinctrl_np);
98 }
99
100 pinctrl = rt_ofw_data(pinctrl_np);
101
102 rt_ofw_node_put(pinctrl_np);
103 }
104
105 if (!pinctrl || !pinctrl->ops || !pinctrl->ops->pin_ctrl_confs_apply)
106 {
107 if (index)
108 {
109 err = -RT_EEMPTY;
110 }
111 else
112 {
113 err = -RT_ERROR;
114 }
115
116 rt_ofw_node_put(conf_np);
117
118 break;
119 }
120
121 err = pinctrl->ops->pin_ctrl_confs_apply(&pinctrl->parent, conf_np);
122 rt_ofw_node_put(conf_np);
123
124 if (err)
125 {
126 break;
127 }
128
129 ++index;
130 }
131
132 return err;
133 }
134
ofw_pin_ctrl_confs_lookup(struct rt_ofw_node * np,const char * name)135 static int ofw_pin_ctrl_confs_lookup(struct rt_ofw_node *np, const char *name)
136 {
137 return rt_ofw_prop_index_of_string(np, "pinctrl-names", name);
138 }
139
ofw_pin_ctrl_confs_apply_by_name(struct rt_ofw_node * np,const char * name)140 static rt_err_t ofw_pin_ctrl_confs_apply_by_name(struct rt_ofw_node *np, const char *name)
141 {
142 int index;
143 rt_err_t err;
144
145 index = ofw_pin_ctrl_confs_lookup(np, name);
146
147 if (index >= 0)
148 {
149 err = ofw_pin_ctrl_confs_apply(np, index);
150 }
151 else
152 {
153 err = -RT_EEMPTY;
154 }
155
156 return err;
157 }
158 #endif /* RT_USING_OFW */
159
rt_pin_ctrl_confs_lookup(struct rt_device * device,const char * name)160 rt_ssize_t rt_pin_ctrl_confs_lookup(struct rt_device *device, const char *name)
161 {
162 rt_ssize_t res;
163
164 if (device && name)
165 {
166 res = -RT_ENOSYS;
167
168 #ifdef RT_USING_OFW
169 if (device->ofw_node)
170 {
171 res = ofw_pin_ctrl_confs_lookup(device->ofw_node, name);
172 }
173 #endif /* RT_USING_OFW */
174 }
175 else
176 {
177 res = -RT_EINVAL;
178 }
179
180 return res;
181 }
182
rt_pin_ctrl_confs_apply(struct rt_device * device,int index)183 rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index)
184 {
185 rt_err_t err;
186
187 if (device && index >= 0)
188 {
189 err = -RT_ENOSYS;
190
191 #ifdef RT_USING_OFW
192 if (device->ofw_node)
193 {
194 err = ofw_pin_ctrl_confs_apply(device->ofw_node, index);
195 }
196 #endif /* RT_USING_OFW */
197 }
198 else
199 {
200 err = -RT_EINVAL;
201 }
202
203 return err;
204 }
205
rt_pin_ctrl_confs_apply_by_name(struct rt_device * device,const char * name)206 rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name)
207 {
208 rt_err_t err;
209
210 if (device)
211 {
212 if (!name)
213 {
214 name = "default";
215 }
216
217 err = -RT_ENOSYS;
218
219 #ifdef RT_USING_OFW
220 if (device->ofw_node)
221 {
222 err = ofw_pin_ctrl_confs_apply_by_name(device->ofw_node, name);
223 }
224 #endif /* RT_USING_OFW */
225
226 RT_UNUSED(name);
227 }
228 else
229 {
230 err = -RT_EINVAL;
231 }
232
233 return err;
234 }
235