1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <linux/compat.h>
10*4882a593Smuzhiyun #include <dm/pinctrl.h>
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun /**
13*4882a593Smuzhiyun * pinctrl_pin_name_to_selector() - return the pin selector for a pin
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * @dev: pin controller device
16*4882a593Smuzhiyun * @pin: the pin name to look up
17*4882a593Smuzhiyun * @return: pin selector, or negative error code on failure
18*4882a593Smuzhiyun */
pinctrl_pin_name_to_selector(struct udevice * dev,const char * pin)19*4882a593Smuzhiyun static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
22*4882a593Smuzhiyun unsigned npins, selector;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun if (!ops->get_pins_count || !ops->get_pin_name) {
25*4882a593Smuzhiyun dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
26*4882a593Smuzhiyun return -ENOSYS;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun npins = ops->get_pins_count(dev);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* See if this pctldev has this pin */
32*4882a593Smuzhiyun for (selector = 0; selector < npins; selector++) {
33*4882a593Smuzhiyun const char *pname = ops->get_pin_name(dev, selector);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (!strcmp(pin, pname))
36*4882a593Smuzhiyun return selector;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun return -ENOSYS;
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /**
43*4882a593Smuzhiyun * pinctrl_group_name_to_selector() - return the group selector for a group
44*4882a593Smuzhiyun *
45*4882a593Smuzhiyun * @dev: pin controller device
46*4882a593Smuzhiyun * @group: the pin group name to look up
47*4882a593Smuzhiyun * @return: pin group selector, or negative error code on failure
48*4882a593Smuzhiyun */
pinctrl_group_name_to_selector(struct udevice * dev,const char * group)49*4882a593Smuzhiyun static int pinctrl_group_name_to_selector(struct udevice *dev,
50*4882a593Smuzhiyun const char *group)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
53*4882a593Smuzhiyun unsigned ngroups, selector;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun if (!ops->get_groups_count || !ops->get_group_name) {
56*4882a593Smuzhiyun dev_dbg(dev, "get_groups_count or get_group_name missing\n");
57*4882a593Smuzhiyun return -ENOSYS;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun ngroups = ops->get_groups_count(dev);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* See if this pctldev has this group */
63*4882a593Smuzhiyun for (selector = 0; selector < ngroups; selector++) {
64*4882a593Smuzhiyun const char *gname = ops->get_group_name(dev, selector);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (!strcmp(group, gname))
67*4882a593Smuzhiyun return selector;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun return -ENOSYS;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(PINMUX)
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun * pinmux_func_name_to_selector() - return the function selector for a function
76*4882a593Smuzhiyun *
77*4882a593Smuzhiyun * @dev: pin controller device
78*4882a593Smuzhiyun * @function: the function name to look up
79*4882a593Smuzhiyun * @return: function selector, or negative error code on failure
80*4882a593Smuzhiyun */
pinmux_func_name_to_selector(struct udevice * dev,const char * function)81*4882a593Smuzhiyun static int pinmux_func_name_to_selector(struct udevice *dev,
82*4882a593Smuzhiyun const char *function)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
85*4882a593Smuzhiyun unsigned nfuncs, selector = 0;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (!ops->get_functions_count || !ops->get_function_name) {
88*4882a593Smuzhiyun dev_dbg(dev,
89*4882a593Smuzhiyun "get_functions_count or get_function_name missing\n");
90*4882a593Smuzhiyun return -ENOSYS;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun nfuncs = ops->get_functions_count(dev);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* See if this pctldev has this function */
96*4882a593Smuzhiyun for (selector = 0; selector < nfuncs; selector++) {
97*4882a593Smuzhiyun const char *fname = ops->get_function_name(dev, selector);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (!strcmp(function, fname))
100*4882a593Smuzhiyun return selector;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return -ENOSYS;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /**
107*4882a593Smuzhiyun * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
108*4882a593Smuzhiyun *
109*4882a593Smuzhiyun * @dev: pin controller device
110*4882a593Smuzhiyun * @is_group: target of operation (true: pin group, false: pin)
111*4882a593Smuzhiyun * @selector: pin selector or group selector, depending on @is_group
112*4882a593Smuzhiyun * @func_selector: function selector
113*4882a593Smuzhiyun * @return: 0 on success, or negative error code on failure
114*4882a593Smuzhiyun */
pinmux_enable_setting(struct udevice * dev,bool is_group,unsigned selector,unsigned func_selector)115*4882a593Smuzhiyun static int pinmux_enable_setting(struct udevice *dev, bool is_group,
116*4882a593Smuzhiyun unsigned selector, unsigned func_selector)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (is_group) {
121*4882a593Smuzhiyun if (!ops->pinmux_group_set) {
122*4882a593Smuzhiyun dev_dbg(dev, "pinmux_group_set op missing\n");
123*4882a593Smuzhiyun return -ENOSYS;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return ops->pinmux_group_set(dev, selector, func_selector);
127*4882a593Smuzhiyun } else {
128*4882a593Smuzhiyun if (!ops->pinmux_set) {
129*4882a593Smuzhiyun dev_dbg(dev, "pinmux_set op missing\n");
130*4882a593Smuzhiyun return -ENOSYS;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun return ops->pinmux_set(dev, selector, func_selector);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun #else
pinmux_func_name_to_selector(struct udevice * dev,const char * function)136*4882a593Smuzhiyun static int pinmux_func_name_to_selector(struct udevice *dev,
137*4882a593Smuzhiyun const char *function)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
pinmux_enable_setting(struct udevice * dev,bool is_group,unsigned selector,unsigned func_selector)142*4882a593Smuzhiyun static int pinmux_enable_setting(struct udevice *dev, bool is_group,
143*4882a593Smuzhiyun unsigned selector, unsigned func_selector)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun #endif
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(PINCONF)
150*4882a593Smuzhiyun /**
151*4882a593Smuzhiyun * pinconf_prop_name_to_param() - return parameter ID for a property name
152*4882a593Smuzhiyun *
153*4882a593Smuzhiyun * @dev: pin controller device
154*4882a593Smuzhiyun * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
155*4882a593Smuzhiyun * @default_value: return default value in case no value is specified in DTS
156*4882a593Smuzhiyun * @return: return pamater ID, or negative error code on failure
157*4882a593Smuzhiyun */
pinconf_prop_name_to_param(struct udevice * dev,const char * property,u32 * default_value)158*4882a593Smuzhiyun static int pinconf_prop_name_to_param(struct udevice *dev,
159*4882a593Smuzhiyun const char *property, u32 *default_value)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
162*4882a593Smuzhiyun const struct pinconf_param *p, *end;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (!ops->pinconf_num_params || !ops->pinconf_params) {
165*4882a593Smuzhiyun dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
166*4882a593Smuzhiyun return -ENOSYS;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun p = ops->pinconf_params;
170*4882a593Smuzhiyun end = p + ops->pinconf_num_params;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* See if this pctldev supports this parameter */
173*4882a593Smuzhiyun for (; p < end; p++) {
174*4882a593Smuzhiyun if (!strcmp(property, p->property)) {
175*4882a593Smuzhiyun *default_value = p->default_value;
176*4882a593Smuzhiyun return p->param;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return -ENOSYS;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /**
184*4882a593Smuzhiyun * pinconf_enable_setting() - apply pin configuration for a certain pin/group
185*4882a593Smuzhiyun *
186*4882a593Smuzhiyun * @dev: pin controller device
187*4882a593Smuzhiyun * @is_group: target of operation (true: pin group, false: pin)
188*4882a593Smuzhiyun * @selector: pin selector or group selector, depending on @is_group
189*4882a593Smuzhiyun * @param: configuration paramter
190*4882a593Smuzhiyun * @argument: argument taken by some configuration parameters
191*4882a593Smuzhiyun * @return: 0 on success, or negative error code on failure
192*4882a593Smuzhiyun */
pinconf_enable_setting(struct udevice * dev,bool is_group,unsigned selector,unsigned param,u32 argument)193*4882a593Smuzhiyun static int pinconf_enable_setting(struct udevice *dev, bool is_group,
194*4882a593Smuzhiyun unsigned selector, unsigned param,
195*4882a593Smuzhiyun u32 argument)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (is_group) {
200*4882a593Smuzhiyun if (!ops->pinconf_group_set) {
201*4882a593Smuzhiyun dev_dbg(dev, "pinconf_group_set op missing\n");
202*4882a593Smuzhiyun return -ENOSYS;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return ops->pinconf_group_set(dev, selector, param,
206*4882a593Smuzhiyun argument);
207*4882a593Smuzhiyun } else {
208*4882a593Smuzhiyun if (!ops->pinconf_set) {
209*4882a593Smuzhiyun dev_dbg(dev, "pinconf_set op missing\n");
210*4882a593Smuzhiyun return -ENOSYS;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun return ops->pinconf_set(dev, selector, param, argument);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun #else
pinconf_prop_name_to_param(struct udevice * dev,const char * property,u32 * default_value)216*4882a593Smuzhiyun static int pinconf_prop_name_to_param(struct udevice *dev,
217*4882a593Smuzhiyun const char *property, u32 *default_value)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun return -ENOSYS;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
pinconf_enable_setting(struct udevice * dev,bool is_group,unsigned selector,unsigned param,u32 argument)222*4882a593Smuzhiyun static int pinconf_enable_setting(struct udevice *dev, bool is_group,
223*4882a593Smuzhiyun unsigned selector, unsigned param,
224*4882a593Smuzhiyun u32 argument)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun return 0;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun #endif
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /**
231*4882a593Smuzhiyun * pinctrl_generic_set_state_one() - set state for a certain pin/group
232*4882a593Smuzhiyun * Apply all pin multiplexing and pin configurations specified by @config
233*4882a593Smuzhiyun * for a given pin or pin group.
234*4882a593Smuzhiyun *
235*4882a593Smuzhiyun * @dev: pin controller device
236*4882a593Smuzhiyun * @config: pseudo device pointing to config node
237*4882a593Smuzhiyun * @is_group: target of operation (true: pin group, false: pin)
238*4882a593Smuzhiyun * @selector: pin selector or group selector, depending on @is_group
239*4882a593Smuzhiyun * @return: 0 on success, or negative error code on failure
240*4882a593Smuzhiyun */
pinctrl_generic_set_state_one(struct udevice * dev,struct udevice * config,bool is_group,unsigned selector)241*4882a593Smuzhiyun static int pinctrl_generic_set_state_one(struct udevice *dev,
242*4882a593Smuzhiyun struct udevice *config,
243*4882a593Smuzhiyun bool is_group, unsigned selector)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun const char *propname;
246*4882a593Smuzhiyun const void *value;
247*4882a593Smuzhiyun struct ofprop property;
248*4882a593Smuzhiyun int len, func_selector, param, ret;
249*4882a593Smuzhiyun u32 arg, default_val;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun dev_for_each_property(property, config) {
252*4882a593Smuzhiyun value = dev_read_prop_by_prop(&property, &propname, &len);
253*4882a593Smuzhiyun if (!value)
254*4882a593Smuzhiyun return -EINVAL;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (!strcmp(propname, "function")) {
257*4882a593Smuzhiyun func_selector = pinmux_func_name_to_selector(dev,
258*4882a593Smuzhiyun value);
259*4882a593Smuzhiyun if (func_selector < 0)
260*4882a593Smuzhiyun return func_selector;
261*4882a593Smuzhiyun ret = pinmux_enable_setting(dev, is_group,
262*4882a593Smuzhiyun selector,
263*4882a593Smuzhiyun func_selector);
264*4882a593Smuzhiyun } else {
265*4882a593Smuzhiyun param = pinconf_prop_name_to_param(dev, propname,
266*4882a593Smuzhiyun &default_val);
267*4882a593Smuzhiyun if (param < 0)
268*4882a593Smuzhiyun continue; /* just skip unknown properties */
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (len >= sizeof(fdt32_t))
271*4882a593Smuzhiyun arg = fdt32_to_cpu(*(fdt32_t *)value);
272*4882a593Smuzhiyun else
273*4882a593Smuzhiyun arg = default_val;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun ret = pinconf_enable_setting(dev, is_group,
276*4882a593Smuzhiyun selector, param, arg);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (ret)
280*4882a593Smuzhiyun return ret;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun return 0;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /**
287*4882a593Smuzhiyun * pinctrl_generic_set_state_subnode() - apply all settings in config node
288*4882a593Smuzhiyun *
289*4882a593Smuzhiyun * @dev: pin controller device
290*4882a593Smuzhiyun * @config: pseudo device pointing to config node
291*4882a593Smuzhiyun * @return: 0 on success, or negative error code on failure
292*4882a593Smuzhiyun */
pinctrl_generic_set_state_subnode(struct udevice * dev,struct udevice * config)293*4882a593Smuzhiyun static int pinctrl_generic_set_state_subnode(struct udevice *dev,
294*4882a593Smuzhiyun struct udevice *config)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun const char *subnode_target_type = "pins";
297*4882a593Smuzhiyun bool is_group = false;
298*4882a593Smuzhiyun const char *name;
299*4882a593Smuzhiyun int strings_count, selector, i, ret;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun strings_count = dev_read_string_count(config, subnode_target_type);
302*4882a593Smuzhiyun if (strings_count < 0) {
303*4882a593Smuzhiyun subnode_target_type = "groups";
304*4882a593Smuzhiyun is_group = true;
305*4882a593Smuzhiyun strings_count = dev_read_string_count(config,
306*4882a593Smuzhiyun subnode_target_type);
307*4882a593Smuzhiyun if (strings_count < 0) {
308*4882a593Smuzhiyun /* skip this node; may contain config child nodes */
309*4882a593Smuzhiyun return 0;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun for (i = 0; i < strings_count; i++) {
314*4882a593Smuzhiyun ret = dev_read_string_index(config, subnode_target_type, i,
315*4882a593Smuzhiyun &name);
316*4882a593Smuzhiyun if (ret)
317*4882a593Smuzhiyun return ret;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (is_group)
320*4882a593Smuzhiyun selector = pinctrl_group_name_to_selector(dev, name);
321*4882a593Smuzhiyun else
322*4882a593Smuzhiyun selector = pinctrl_pin_name_to_selector(dev, name);
323*4882a593Smuzhiyun if (selector < 0)
324*4882a593Smuzhiyun return selector;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun ret = pinctrl_generic_set_state_one(dev, config,
327*4882a593Smuzhiyun is_group, selector);
328*4882a593Smuzhiyun if (ret)
329*4882a593Smuzhiyun return ret;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
pinctrl_generic_set_state(struct udevice * dev,struct udevice * config)335*4882a593Smuzhiyun int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun struct udevice *child;
338*4882a593Smuzhiyun int ret;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun ret = pinctrl_generic_set_state_subnode(dev, config);
341*4882a593Smuzhiyun if (ret)
342*4882a593Smuzhiyun return ret;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun for (device_find_first_child(config, &child);
345*4882a593Smuzhiyun child;
346*4882a593Smuzhiyun device_find_next_child(&child)) {
347*4882a593Smuzhiyun ret = pinctrl_generic_set_state_subnode(dev, child);
348*4882a593Smuzhiyun if (ret)
349*4882a593Smuzhiyun return ret;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun return 0;
353*4882a593Smuzhiyun }
354