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