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 <dt-bindings/pin/pin.h>
12 
13 #include "dev_pin_dm.h"
14 
15 static const char * const gpio_suffixes[] =
16 {
17     "gpios", "gpio"
18 };
19 
rt_ofw_get_named_pin(struct rt_ofw_node * np,const char * propname,int index,rt_uint8_t * out_mode,rt_uint8_t * out_value)20 rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index,
21         rt_uint8_t *out_mode, rt_uint8_t *out_value)
22 {
23     rt_ssize_t pin = -1;
24     rt_uint8_t mode;
25     rt_uint8_t value;
26     rt_uint32_t flags;
27     char gpios_name[64];
28     struct rt_device_pin *pin_dev = 0;
29     struct rt_ofw_node *pin_dev_np = 0;
30     struct rt_ofw_cell_args pin_args = {0};
31 
32     if (!np && index < 0)
33     {
34         return -RT_EINVAL;
35     }
36 
37     for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i)
38     {
39         if (propname)
40         {
41             rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]);
42         }
43         else
44         {
45             rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]);
46         }
47 
48         pin = rt_ofw_parse_phandle_cells(np, gpios_name, "#gpio-cells", index, &pin_args);
49 
50         if (pin >= 0)
51         {
52             break;
53         }
54     }
55 
56     if (pin < 0)
57     {
58         return pin;
59     }
60 
61     pin_dev_np = pin_args.data;
62 
63     if (!rt_ofw_data(pin_dev_np))
64     {
65         rt_platform_ofw_request(pin_dev_np);
66     }
67 
68     pin_dev = rt_ofw_data(pin_dev_np);
69 
70     if (!pin_dev)
71     {
72         pin = -RT_ERROR;
73 
74         goto _out_converts;
75     }
76 
77     value = PIN_LOW;
78     mode = PIN_MODE_OUTPUT;
79 
80     if (pin_dev->ops->pin_parse)
81     {
82         pin = pin_dev->ops->pin_parse(&pin_dev->parent, &pin_args, &flags);
83     }
84     else
85     {
86         /*
87          * We always assume that the args[0] is the pin number if driver not
88          * implemented `pin_parse`.
89          */
90         pin = pin_args.args[0];
91 
92         goto _out_converts;
93     }
94 
95     if (out_mode)
96     {
97         if (flags & PIN_OPEN_DRAIN)
98         {
99             mode = PIN_MODE_OUTPUT_OD;
100         }
101 
102         switch (flags & RT_GENMASK(6, 4))
103         {
104         case PIN_PULL_UP:
105             mode = PIN_MODE_INPUT_PULLUP;
106             break;
107 
108         case PIN_PULL_DOWN:
109             mode = PIN_MODE_INPUT_PULLDOWN;
110             break;
111 
112         case PIN_PULL_DISABLE:
113             mode = PIN_MODE_INPUT;
114             break;
115         }
116     }
117 
118     if (out_value)
119     {
120         if ((flags & 1) == PIN_ACTIVE_HIGH)
121         {
122             value = PIN_HIGH;
123         }
124         else if ((flags & 1) == PIN_ACTIVE_LOW)
125         {
126             value = PIN_LOW;
127         }
128     }
129 
130 _out_converts:
131     rt_ofw_node_put(pin_dev_np);
132 
133     if (pin >= 0)
134     {
135         /* Get virtual pin */
136         pin += pin_dev->pin_start;
137 
138         if (out_mode)
139         {
140             *out_mode = mode;
141         }
142 
143         if (out_value)
144         {
145             *out_value = value;
146         }
147     }
148 
149     return pin;
150 }
151 
rt_ofw_get_named_pin_count(struct rt_ofw_node * np,const char * propname)152 rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname)
153 {
154     char gpios_name[64];
155     rt_ssize_t count = 0;
156 
157     if (!np)
158     {
159         return -RT_EINVAL;
160     }
161 
162     for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i)
163     {
164         if (propname)
165         {
166             rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]);
167         }
168         else
169         {
170             rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]);
171         }
172 
173         count = rt_ofw_count_phandle_cells(np, propname, "#gpio-cells");
174 
175         if (count > 0)
176         {
177             break;
178         }
179     }
180 
181     return count;
182 }
183