diff options
author | Soren Brinkmann <soren.brinkmann@xilinx.com> | 2015-01-09 10:43:46 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-01-11 16:32:19 -0500 |
commit | dd4d01f7bad886c22687224bc7070b87de8deb51 (patch) | |
tree | f1e2e99a8cc4859a48372212213ceb59aa183e38 /drivers/pinctrl/pinconf-generic.c | |
parent | 31c89c959667194350f496947b576c149503ce98 (diff) |
pinctrl: pinconf-generic: Allow driver to specify DT params
Additionally to the generic DT parameters, allow drivers to provide
driver-specific DT parameters to be used with the generic parser
infrastructure.
To achieve this 'struct pinctrl_desc' is extended to pass custom pinconf
option to the core. In order to pass this kind of information, the
related data structures - 'struct pinconf_generic_dt_params',
'pin_config_item' - are moved from pinconf internals to the
pinconf-generic header.
Additionally pinconfg-generic is refactored to not only iterate over the
generic pinconf parameters but also take the parameters into account
that are provided through the driver's 'struct pinctrl_desc'.
In particular 'pinconf_generic_parse_dt_config()' and
'pinconf_generic_dump' helpers are split into two parts each. In order
to have a more generic helper that can be used to process the generic
parameters as well as the driver-specific ones.
v2:
- fix typo
- add missing documentation for @conf_items member in struct
- rebase to pinctrl/devel: conflict in abx500
- rename _pinconf_generic_dump() to pinconf_generic_dump_one()
- removed '_' from _parse_dt_cfg()
- removed BUG_ONs, error condition is handled in if statements
- removed pinconf_generic_dump_group() & pinconf_generic_dump_pin
helpers
- fixed up corresponding call sites
- renamed pinconf_generic_dump() to pinconf_generic_dump_pins()
- added kernel-doc to pinconf_generic_dump_pins()
- add kernel-doc
- more verbose commit message
Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
Tested-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinconf-generic.c')
-rw-r--r-- | drivers/pinctrl/pinconf-generic.c | 182 |
1 files changed, 100 insertions, 82 deletions
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 21b3d90ebb2d..e0886665b70a 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c | |||
@@ -27,17 +27,6 @@ | |||
27 | #include "pinctrl-utils.h" | 27 | #include "pinctrl-utils.h" |
28 | 28 | ||
29 | #ifdef CONFIG_DEBUG_FS | 29 | #ifdef CONFIG_DEBUG_FS |
30 | |||
31 | struct pin_config_item { | ||
32 | const enum pin_config_param param; | ||
33 | const char * const display; | ||
34 | const char * const format; | ||
35 | bool has_arg; | ||
36 | }; | ||
37 | |||
38 | #define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \ | ||
39 | .has_arg = d } | ||
40 | |||
41 | static const struct pin_config_item conf_items[] = { | 30 | static const struct pin_config_item conf_items[] = { |
42 | PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), | 31 | PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false), |
43 | PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), | 32 | PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false), |
@@ -60,22 +49,25 @@ static const struct pin_config_item conf_items[] = { | |||
60 | PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), | 49 | PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true), |
61 | }; | 50 | }; |
62 | 51 | ||
63 | void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, | 52 | static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev, |
64 | struct seq_file *s, unsigned pin) | 53 | struct seq_file *s, const char *gname, |
54 | unsigned pin, | ||
55 | const struct pin_config_item *items, | ||
56 | int nitems) | ||
65 | { | 57 | { |
66 | const struct pinconf_ops *ops = pctldev->desc->confops; | ||
67 | int i; | 58 | int i; |
68 | 59 | ||
69 | if (!ops->is_generic) | 60 | for (i = 0; i < nitems; i++) { |
70 | return; | ||
71 | |||
72 | for (i = 0; i < ARRAY_SIZE(conf_items); i++) { | ||
73 | unsigned long config; | 61 | unsigned long config; |
74 | int ret; | 62 | int ret; |
75 | 63 | ||
76 | /* We want to check out this parameter */ | 64 | /* We want to check out this parameter */ |
77 | config = pinconf_to_config_packed(conf_items[i].param, 0); | 65 | config = pinconf_to_config_packed(items[i].param, 0); |
78 | ret = pin_config_get_for_pin(pctldev, pin, &config); | 66 | if (gname) |
67 | ret = pin_config_group_get(dev_name(pctldev->dev), | ||
68 | gname, &config); | ||
69 | else | ||
70 | ret = pin_config_get_for_pin(pctldev, pin, &config); | ||
79 | /* These are legal errors */ | 71 | /* These are legal errors */ |
80 | if (ret == -EINVAL || ret == -ENOTSUPP) | 72 | if (ret == -EINVAL || ret == -ENOTSUPP) |
81 | continue; | 73 | continue; |
@@ -85,56 +77,46 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev, | |||
85 | } | 77 | } |
86 | /* Space between multiple configs */ | 78 | /* Space between multiple configs */ |
87 | seq_puts(s, " "); | 79 | seq_puts(s, " "); |
88 | seq_puts(s, conf_items[i].display); | 80 | seq_puts(s, items[i].display); |
89 | /* Print unit if available */ | 81 | /* Print unit if available */ |
90 | if (conf_items[i].has_arg) { | 82 | if (items[i].has_arg) { |
91 | seq_printf(s, " (%u", | 83 | seq_printf(s, " (%u", |
92 | pinconf_to_config_argument(config)); | 84 | pinconf_to_config_argument(config)); |
93 | if (conf_items[i].format) | 85 | if (items[i].format) |
94 | seq_printf(s, " %s)", conf_items[i].format); | 86 | seq_printf(s, " %s)", items[i].format); |
95 | else | 87 | else |
96 | seq_puts(s, ")"); | 88 | seq_puts(s, ")"); |
97 | } | 89 | } |
98 | } | 90 | } |
99 | } | 91 | } |
100 | 92 | ||
101 | void pinconf_generic_dump_group(struct pinctrl_dev *pctldev, | 93 | /** |
102 | struct seq_file *s, const char *gname) | 94 | * pinconf_generic_dump_pins - Print information about pin or group of pins |
95 | * @pctldev: Pincontrol device | ||
96 | * @s: File to print to | ||
97 | * @gname: Group name specifying pins | ||
98 | * @pin: Pin number specyfying pin | ||
99 | * | ||
100 | * Print the pinconf configuration for the requested pin(s) to @s. Pins can be | ||
101 | * specified either by pin using @pin or by group using @gname. Only one needs | ||
102 | * to be specified the other can be NULL/0. | ||
103 | */ | ||
104 | void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s, | ||
105 | const char *gname, unsigned pin) | ||
103 | { | 106 | { |
104 | const struct pinconf_ops *ops = pctldev->desc->confops; | 107 | const struct pinconf_ops *ops = pctldev->desc->confops; |
105 | int i; | ||
106 | 108 | ||
107 | if (!ops->is_generic) | 109 | if (!ops->is_generic) |
108 | return; | 110 | return; |
109 | 111 | ||
110 | for (i = 0; i < ARRAY_SIZE(conf_items); i++) { | 112 | /* generic parameters */ |
111 | unsigned long config; | 113 | pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items, |
112 | int ret; | 114 | ARRAY_SIZE(conf_items)); |
113 | 115 | /* driver-specific parameters */ | |
114 | /* We want to check out this parameter */ | 116 | if (pctldev->desc->num_dt_params && pctldev->desc->conf_items) |
115 | config = pinconf_to_config_packed(conf_items[i].param, 0); | 117 | pinconf_generic_dump_one(pctldev, s, gname, pin, |
116 | ret = pin_config_group_get(dev_name(pctldev->dev), gname, | 118 | pctldev->desc->conf_items, |
117 | &config); | 119 | pctldev->desc->num_dt_params); |
118 | /* These are legal errors */ | ||
119 | if (ret == -EINVAL || ret == -ENOTSUPP) | ||
120 | continue; | ||
121 | if (ret) { | ||
122 | seq_printf(s, "ERROR READING CONFIG SETTING %d ", i); | ||
123 | continue; | ||
124 | } | ||
125 | /* Space between multiple configs */ | ||
126 | seq_puts(s, " "); | ||
127 | seq_puts(s, conf_items[i].display); | ||
128 | /* Print unit if available */ | ||
129 | if (conf_items[i].has_arg) { | ||
130 | seq_printf(s, " (%u", | ||
131 | pinconf_to_config_argument(config)); | ||
132 | if (conf_items[i].format) | ||
133 | seq_printf(s, " %s)", conf_items[i].format); | ||
134 | else | ||
135 | seq_puts(s, ")"); | ||
136 | } | ||
137 | } | ||
138 | } | 120 | } |
139 | 121 | ||
140 | void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, | 122 | void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, |
@@ -148,17 +130,21 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev, | |||
148 | seq_printf(s, "%s: 0x%x", conf_items[i].display, | 130 | seq_printf(s, "%s: 0x%x", conf_items[i].display, |
149 | pinconf_to_config_argument(config)); | 131 | pinconf_to_config_argument(config)); |
150 | } | 132 | } |
133 | |||
134 | if (!pctldev->desc->num_dt_params || !pctldev->desc->conf_items) | ||
135 | return; | ||
136 | |||
137 | for (i = 0; i < pctldev->desc->num_dt_params; i++) { | ||
138 | if (pinconf_to_config_param(config) != pctldev->desc->conf_items[i].param) | ||
139 | continue; | ||
140 | seq_printf(s, "%s: 0x%x", pctldev->desc->conf_items[i].display, | ||
141 | pinconf_to_config_argument(config)); | ||
142 | } | ||
151 | } | 143 | } |
152 | EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); | 144 | EXPORT_SYMBOL_GPL(pinconf_generic_dump_config); |
153 | #endif | 145 | #endif |
154 | 146 | ||
155 | #ifdef CONFIG_OF | 147 | #ifdef CONFIG_OF |
156 | struct pinconf_generic_dt_params { | ||
157 | const char * const property; | ||
158 | enum pin_config_param param; | ||
159 | u32 default_value; | ||
160 | }; | ||
161 | |||
162 | static const struct pinconf_generic_dt_params dt_params[] = { | 148 | static const struct pinconf_generic_dt_params dt_params[] = { |
163 | { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, | 149 | { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, |
164 | { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, | 150 | { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 }, |
@@ -184,6 +170,47 @@ static const struct pinconf_generic_dt_params dt_params[] = { | |||
184 | }; | 170 | }; |
185 | 171 | ||
186 | /** | 172 | /** |
173 | * parse_dt_cfg - Parse DT pinconf parameters | ||
174 | * @np: DT node | ||
175 | * @params: Array of describing DT parameters | ||
176 | * @count: Number of entries in @params | ||
177 | * @cfg: Array of parsed config options | ||
178 | * @ncfg: Number of entries in @cfg | ||
179 | * | ||
180 | * Parse the config options described in @params from @np and puts the result | ||
181 | * in @cfg. @cfg does not need to be empty, entries are added beggining at | ||
182 | * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg | ||
183 | * needs to have enough memory allocated to hold all possible entries. | ||
184 | */ | ||
185 | static void parse_dt_cfg(struct device_node *np, | ||
186 | const struct pinconf_generic_dt_params *params, | ||
187 | unsigned int count, unsigned long *cfg, | ||
188 | unsigned int *ncfg) | ||
189 | { | ||
190 | int i; | ||
191 | |||
192 | for (i = 0; i < count; i++) { | ||
193 | u32 val; | ||
194 | int ret; | ||
195 | const struct pinconf_generic_dt_params *par = ¶ms[i]; | ||
196 | |||
197 | ret = of_property_read_u32(np, par->property, &val); | ||
198 | |||
199 | /* property not found */ | ||
200 | if (ret == -EINVAL) | ||
201 | continue; | ||
202 | |||
203 | /* use default value, when no value is specified */ | ||
204 | if (ret) | ||
205 | val = par->default_value; | ||
206 | |||
207 | pr_debug("found %s with value %u\n", par->property, val); | ||
208 | cfg[*ncfg] = pinconf_to_config_packed(par->param, val); | ||
209 | (*ncfg)++; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /** | ||
187 | * pinconf_generic_parse_dt_config() | 214 | * pinconf_generic_parse_dt_config() |
188 | * parse the config properties into generic pinconfig values. | 215 | * parse the config properties into generic pinconfig values. |
189 | * @np: node containing the pinconfig properties | 216 | * @np: node containing the pinconfig properties |
@@ -191,39 +218,29 @@ static const struct pinconf_generic_dt_params dt_params[] = { | |||
191 | * @nconfigs: umber of configurations | 218 | * @nconfigs: umber of configurations |
192 | */ | 219 | */ |
193 | int pinconf_generic_parse_dt_config(struct device_node *np, | 220 | int pinconf_generic_parse_dt_config(struct device_node *np, |
221 | struct pinctrl_dev *pctldev, | ||
194 | unsigned long **configs, | 222 | unsigned long **configs, |
195 | unsigned int *nconfigs) | 223 | unsigned int *nconfigs) |
196 | { | 224 | { |
197 | unsigned long *cfg; | 225 | unsigned long *cfg; |
198 | unsigned int ncfg = 0; | 226 | unsigned int max_cfg, ncfg = 0; |
199 | int ret; | 227 | int ret; |
200 | int i; | ||
201 | u32 val; | ||
202 | 228 | ||
203 | if (!np) | 229 | if (!np) |
204 | return -EINVAL; | 230 | return -EINVAL; |
205 | 231 | ||
206 | /* allocate a temporary array big enough to hold one of each option */ | 232 | /* allocate a temporary array big enough to hold one of each option */ |
207 | cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL); | 233 | max_cfg = ARRAY_SIZE(dt_params); |
234 | if (pctldev) | ||
235 | max_cfg += pctldev->desc->num_dt_params; | ||
236 | cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL); | ||
208 | if (!cfg) | 237 | if (!cfg) |
209 | return -ENOMEM; | 238 | return -ENOMEM; |
210 | 239 | ||
211 | for (i = 0; i < ARRAY_SIZE(dt_params); i++) { | 240 | parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg); |
212 | const struct pinconf_generic_dt_params *par = &dt_params[i]; | 241 | if (pctldev && pctldev->desc->num_dt_params && pctldev->desc->params) |
213 | ret = of_property_read_u32(np, par->property, &val); | 242 | parse_dt_cfg(np, pctldev->desc->params, |
214 | 243 | pctldev->desc->num_dt_params, cfg, &ncfg); | |
215 | /* property not found */ | ||
216 | if (ret == -EINVAL) | ||
217 | continue; | ||
218 | |||
219 | /* use default value, when no value is specified */ | ||
220 | if (ret) | ||
221 | val = par->default_value; | ||
222 | |||
223 | pr_debug("found %s with value %u\n", par->property, val); | ||
224 | cfg[ncfg] = pinconf_to_config_packed(par->param, val); | ||
225 | ncfg++; | ||
226 | } | ||
227 | 244 | ||
228 | ret = 0; | 245 | ret = 0; |
229 | 246 | ||
@@ -274,7 +291,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, | |||
274 | function = NULL; | 291 | function = NULL; |
275 | } | 292 | } |
276 | 293 | ||
277 | ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); | 294 | ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, |
295 | &num_configs); | ||
278 | if (ret < 0) { | 296 | if (ret < 0) { |
279 | dev_err(dev, "could not parse node property\n"); | 297 | dev_err(dev, "could not parse node property\n"); |
280 | return ret; | 298 | return ret; |