1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Pinctrl driver for the Wondermedia SoC's |
4 | * |
5 | * Copyright (c) 2013 Tony Prisk <linux@prisktech.co.nz> |
6 | */ |
7 | |
8 | #include <linux/err.h> |
9 | #include <linux/gpio/driver.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/io.h> |
12 | #include <linux/irq.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_irq.h> |
15 | #include <linux/pinctrl/consumer.h> |
16 | #include <linux/pinctrl/machine.h> |
17 | #include <linux/pinctrl/pinconf.h> |
18 | #include <linux/pinctrl/pinconf-generic.h> |
19 | #include <linux/pinctrl/pinctrl.h> |
20 | #include <linux/pinctrl/pinmux.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> |
23 | |
24 | #include "pinctrl-wmt.h" |
25 | |
26 | static inline void wmt_setbits(struct wmt_pinctrl_data *data, u32 reg, |
27 | u32 mask) |
28 | { |
29 | u32 val; |
30 | |
31 | val = readl_relaxed(data->base + reg); |
32 | val |= mask; |
33 | writel_relaxed(val, data->base + reg); |
34 | } |
35 | |
36 | static inline void wmt_clearbits(struct wmt_pinctrl_data *data, u32 reg, |
37 | u32 mask) |
38 | { |
39 | u32 val; |
40 | |
41 | val = readl_relaxed(data->base + reg); |
42 | val &= ~mask; |
43 | writel_relaxed(val, data->base + reg); |
44 | } |
45 | |
46 | enum wmt_func_sel { |
47 | WMT_FSEL_GPIO_IN = 0, |
48 | WMT_FSEL_GPIO_OUT = 1, |
49 | WMT_FSEL_ALT = 2, |
50 | WMT_FSEL_COUNT = 3, |
51 | }; |
52 | |
53 | static const char * const wmt_functions[WMT_FSEL_COUNT] = { |
54 | [WMT_FSEL_GPIO_IN] = "gpio_in" , |
55 | [WMT_FSEL_GPIO_OUT] = "gpio_out" , |
56 | [WMT_FSEL_ALT] = "alt" , |
57 | }; |
58 | |
59 | static int wmt_pmx_get_functions_count(struct pinctrl_dev *pctldev) |
60 | { |
61 | return WMT_FSEL_COUNT; |
62 | } |
63 | |
64 | static const char *wmt_pmx_get_function_name(struct pinctrl_dev *pctldev, |
65 | unsigned selector) |
66 | { |
67 | return wmt_functions[selector]; |
68 | } |
69 | |
70 | static int wmt_pmx_get_function_groups(struct pinctrl_dev *pctldev, |
71 | unsigned selector, |
72 | const char * const **groups, |
73 | unsigned * const num_groups) |
74 | { |
75 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
76 | |
77 | /* every pin does every function */ |
78 | *groups = data->groups; |
79 | *num_groups = data->ngroups; |
80 | |
81 | return 0; |
82 | } |
83 | |
84 | static int wmt_set_pinmux(struct wmt_pinctrl_data *data, unsigned func, |
85 | unsigned pin) |
86 | { |
87 | u32 bank = WMT_BANK_FROM_PIN(pin); |
88 | u32 bit = WMT_BIT_FROM_PIN(pin); |
89 | u32 reg_en = data->banks[bank].reg_en; |
90 | u32 reg_dir = data->banks[bank].reg_dir; |
91 | |
92 | if (reg_dir == NO_REG) { |
93 | dev_err(data->dev, "pin:%d no direction register defined\n" , |
94 | pin); |
95 | return -EINVAL; |
96 | } |
97 | |
98 | /* |
99 | * If reg_en == NO_REG, we assume it is a dedicated GPIO and cannot be |
100 | * disabled (as on VT8500) and that no alternate function is available. |
101 | */ |
102 | switch (func) { |
103 | case WMT_FSEL_GPIO_IN: |
104 | if (reg_en != NO_REG) |
105 | wmt_setbits(data, reg: reg_en, BIT(bit)); |
106 | wmt_clearbits(data, reg: reg_dir, BIT(bit)); |
107 | break; |
108 | case WMT_FSEL_GPIO_OUT: |
109 | if (reg_en != NO_REG) |
110 | wmt_setbits(data, reg: reg_en, BIT(bit)); |
111 | wmt_setbits(data, reg: reg_dir, BIT(bit)); |
112 | break; |
113 | case WMT_FSEL_ALT: |
114 | if (reg_en == NO_REG) { |
115 | dev_err(data->dev, "pin:%d no alt function available\n" , |
116 | pin); |
117 | return -EINVAL; |
118 | } |
119 | wmt_clearbits(data, reg: reg_en, BIT(bit)); |
120 | } |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static int wmt_pmx_set_mux(struct pinctrl_dev *pctldev, |
126 | unsigned func_selector, |
127 | unsigned group_selector) |
128 | { |
129 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
130 | u32 pinnum = data->pins[group_selector].number; |
131 | |
132 | return wmt_set_pinmux(data, func: func_selector, pin: pinnum); |
133 | } |
134 | |
135 | static void wmt_pmx_gpio_disable_free(struct pinctrl_dev *pctldev, |
136 | struct pinctrl_gpio_range *range, |
137 | unsigned offset) |
138 | { |
139 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
140 | |
141 | /* disable by setting GPIO_IN */ |
142 | wmt_set_pinmux(data, func: WMT_FSEL_GPIO_IN, pin: offset); |
143 | } |
144 | |
145 | static int wmt_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, |
146 | struct pinctrl_gpio_range *range, |
147 | unsigned offset, |
148 | bool input) |
149 | { |
150 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
151 | |
152 | wmt_set_pinmux(data, func: (input ? WMT_FSEL_GPIO_IN : WMT_FSEL_GPIO_OUT), |
153 | pin: offset); |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | static const struct pinmux_ops wmt_pinmux_ops = { |
159 | .get_functions_count = wmt_pmx_get_functions_count, |
160 | .get_function_name = wmt_pmx_get_function_name, |
161 | .get_function_groups = wmt_pmx_get_function_groups, |
162 | .set_mux = wmt_pmx_set_mux, |
163 | .gpio_disable_free = wmt_pmx_gpio_disable_free, |
164 | .gpio_set_direction = wmt_pmx_gpio_set_direction, |
165 | }; |
166 | |
167 | static int wmt_get_groups_count(struct pinctrl_dev *pctldev) |
168 | { |
169 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
170 | |
171 | return data->ngroups; |
172 | } |
173 | |
174 | static const char *wmt_get_group_name(struct pinctrl_dev *pctldev, |
175 | unsigned selector) |
176 | { |
177 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
178 | |
179 | return data->groups[selector]; |
180 | } |
181 | |
182 | static int wmt_get_group_pins(struct pinctrl_dev *pctldev, |
183 | unsigned selector, |
184 | const unsigned **pins, |
185 | unsigned *num_pins) |
186 | { |
187 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
188 | |
189 | *pins = &data->pins[selector].number; |
190 | *num_pins = 1; |
191 | |
192 | return 0; |
193 | } |
194 | |
195 | static int wmt_pctl_find_group_by_pin(struct wmt_pinctrl_data *data, u32 pin) |
196 | { |
197 | int i; |
198 | |
199 | for (i = 0; i < data->npins; i++) { |
200 | if (data->pins[i].number == pin) |
201 | return i; |
202 | } |
203 | |
204 | return -EINVAL; |
205 | } |
206 | |
207 | static int wmt_pctl_dt_node_to_map_func(struct wmt_pinctrl_data *data, |
208 | struct device_node *np, |
209 | u32 pin, u32 fnum, |
210 | struct pinctrl_map **maps) |
211 | { |
212 | int group; |
213 | struct pinctrl_map *map = *maps; |
214 | |
215 | if (fnum >= ARRAY_SIZE(wmt_functions)) { |
216 | dev_err(data->dev, "invalid wm,function %d\n" , fnum); |
217 | return -EINVAL; |
218 | } |
219 | |
220 | group = wmt_pctl_find_group_by_pin(data, pin); |
221 | if (group < 0) { |
222 | dev_err(data->dev, "unable to match pin %d to group\n" , pin); |
223 | return group; |
224 | } |
225 | |
226 | map->type = PIN_MAP_TYPE_MUX_GROUP; |
227 | map->data.mux.group = data->groups[group]; |
228 | map->data.mux.function = wmt_functions[fnum]; |
229 | (*maps)++; |
230 | |
231 | return 0; |
232 | } |
233 | |
234 | static int wmt_pctl_dt_node_to_map_pull(struct wmt_pinctrl_data *data, |
235 | struct device_node *np, |
236 | u32 pin, u32 pull, |
237 | struct pinctrl_map **maps) |
238 | { |
239 | int group; |
240 | unsigned long *configs; |
241 | struct pinctrl_map *map = *maps; |
242 | |
243 | if (pull > 2) { |
244 | dev_err(data->dev, "invalid wm,pull %d\n" , pull); |
245 | return -EINVAL; |
246 | } |
247 | |
248 | group = wmt_pctl_find_group_by_pin(data, pin); |
249 | if (group < 0) { |
250 | dev_err(data->dev, "unable to match pin %d to group\n" , pin); |
251 | return group; |
252 | } |
253 | |
254 | configs = kzalloc(size: sizeof(*configs), GFP_KERNEL); |
255 | if (!configs) |
256 | return -ENOMEM; |
257 | |
258 | switch (pull) { |
259 | case 0: |
260 | configs[0] = PIN_CONFIG_BIAS_DISABLE; |
261 | break; |
262 | case 1: |
263 | configs[0] = PIN_CONFIG_BIAS_PULL_DOWN; |
264 | break; |
265 | case 2: |
266 | configs[0] = PIN_CONFIG_BIAS_PULL_UP; |
267 | break; |
268 | default: |
269 | configs[0] = PIN_CONFIG_BIAS_DISABLE; |
270 | dev_err(data->dev, "invalid pull state %d - disabling\n" , pull); |
271 | } |
272 | |
273 | map->type = PIN_MAP_TYPE_CONFIGS_PIN; |
274 | map->data.configs.group_or_pin = data->groups[group]; |
275 | map->data.configs.configs = configs; |
276 | map->data.configs.num_configs = 1; |
277 | (*maps)++; |
278 | |
279 | return 0; |
280 | } |
281 | |
282 | static void wmt_pctl_dt_free_map(struct pinctrl_dev *pctldev, |
283 | struct pinctrl_map *maps, |
284 | unsigned num_maps) |
285 | { |
286 | int i; |
287 | |
288 | for (i = 0; i < num_maps; i++) |
289 | if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN) |
290 | kfree(objp: maps[i].data.configs.configs); |
291 | |
292 | kfree(objp: maps); |
293 | } |
294 | |
295 | static int wmt_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, |
296 | struct device_node *np, |
297 | struct pinctrl_map **map, |
298 | unsigned *num_maps) |
299 | { |
300 | struct pinctrl_map *maps, *cur_map; |
301 | struct property *pins, *funcs, *pulls; |
302 | u32 pin, func, pull; |
303 | int num_pins, num_funcs, num_pulls, maps_per_pin; |
304 | int i, err; |
305 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
306 | |
307 | pins = of_find_property(np, name: "wm,pins" , NULL); |
308 | if (!pins) { |
309 | dev_err(data->dev, "missing wmt,pins property\n" ); |
310 | return -EINVAL; |
311 | } |
312 | |
313 | funcs = of_find_property(np, name: "wm,function" , NULL); |
314 | pulls = of_find_property(np, name: "wm,pull" , NULL); |
315 | |
316 | if (!funcs && !pulls) { |
317 | dev_err(data->dev, "neither wm,function nor wm,pull specified\n" ); |
318 | return -EINVAL; |
319 | } |
320 | |
321 | /* |
322 | * The following lines calculate how many values are defined for each |
323 | * of the properties. |
324 | */ |
325 | num_pins = pins->length / sizeof(u32); |
326 | num_funcs = funcs ? (funcs->length / sizeof(u32)) : 0; |
327 | num_pulls = pulls ? (pulls->length / sizeof(u32)) : 0; |
328 | |
329 | if (num_funcs > 1 && num_funcs != num_pins) { |
330 | dev_err(data->dev, "wm,function must have 1 or %d entries\n" , |
331 | num_pins); |
332 | return -EINVAL; |
333 | } |
334 | |
335 | if (num_pulls > 1 && num_pulls != num_pins) { |
336 | dev_err(data->dev, "wm,pull must have 1 or %d entries\n" , |
337 | num_pins); |
338 | return -EINVAL; |
339 | } |
340 | |
341 | maps_per_pin = 0; |
342 | if (num_funcs) |
343 | maps_per_pin++; |
344 | if (num_pulls) |
345 | maps_per_pin++; |
346 | |
347 | cur_map = maps = kcalloc(n: num_pins * maps_per_pin, size: sizeof(*maps), |
348 | GFP_KERNEL); |
349 | if (!maps) |
350 | return -ENOMEM; |
351 | |
352 | for (i = 0; i < num_pins; i++) { |
353 | err = of_property_read_u32_index(np, propname: "wm,pins" , index: i, out_value: &pin); |
354 | if (err) |
355 | goto fail; |
356 | |
357 | if (pin >= (data->nbanks * 32)) { |
358 | dev_err(data->dev, "invalid wm,pins value\n" ); |
359 | err = -EINVAL; |
360 | goto fail; |
361 | } |
362 | |
363 | if (num_funcs) { |
364 | err = of_property_read_u32_index(np, propname: "wm,function" , |
365 | index: (num_funcs > 1 ? i : 0), out_value: &func); |
366 | if (err) |
367 | goto fail; |
368 | |
369 | err = wmt_pctl_dt_node_to_map_func(data, np, pin, fnum: func, |
370 | maps: &cur_map); |
371 | if (err) |
372 | goto fail; |
373 | } |
374 | |
375 | if (num_pulls) { |
376 | err = of_property_read_u32_index(np, propname: "wm,pull" , |
377 | index: (num_pulls > 1 ? i : 0), out_value: &pull); |
378 | if (err) |
379 | goto fail; |
380 | |
381 | err = wmt_pctl_dt_node_to_map_pull(data, np, pin, pull, |
382 | maps: &cur_map); |
383 | if (err) |
384 | goto fail; |
385 | } |
386 | } |
387 | *map = maps; |
388 | *num_maps = num_pins * maps_per_pin; |
389 | return 0; |
390 | |
391 | /* |
392 | * The fail path removes any maps that have been allocated. The fail path is |
393 | * only called from code after maps has been kzalloc'd. It is also safe to |
394 | * pass 'num_pins * maps_per_pin' as the map count even though we probably |
395 | * failed before all the mappings were read as all maps are allocated at once, |
396 | * and configs are only allocated for .type = PIN_MAP_TYPE_CONFIGS_PIN - there |
397 | * is no failpath where a config can be allocated without .type being set. |
398 | */ |
399 | fail: |
400 | wmt_pctl_dt_free_map(pctldev, maps, num_maps: num_pins * maps_per_pin); |
401 | return err; |
402 | } |
403 | |
404 | static const struct pinctrl_ops wmt_pctl_ops = { |
405 | .get_groups_count = wmt_get_groups_count, |
406 | .get_group_name = wmt_get_group_name, |
407 | .get_group_pins = wmt_get_group_pins, |
408 | .dt_node_to_map = wmt_pctl_dt_node_to_map, |
409 | .dt_free_map = wmt_pctl_dt_free_map, |
410 | }; |
411 | |
412 | static int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, |
413 | unsigned long *config) |
414 | { |
415 | return -ENOTSUPP; |
416 | } |
417 | |
418 | static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, |
419 | unsigned long *configs, unsigned num_configs) |
420 | { |
421 | struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); |
422 | enum pin_config_param param; |
423 | u32 arg; |
424 | u32 bank = WMT_BANK_FROM_PIN(pin); |
425 | u32 bit = WMT_BIT_FROM_PIN(pin); |
426 | u32 reg_pull_en = data->banks[bank].reg_pull_en; |
427 | u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg; |
428 | int i; |
429 | |
430 | if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) { |
431 | dev_err(data->dev, "bias functions not supported on pin %d\n" , |
432 | pin); |
433 | return -EINVAL; |
434 | } |
435 | |
436 | for (i = 0; i < num_configs; i++) { |
437 | param = pinconf_to_config_param(config: configs[i]); |
438 | arg = pinconf_to_config_argument(config: configs[i]); |
439 | |
440 | if ((param == PIN_CONFIG_BIAS_PULL_DOWN) || |
441 | (param == PIN_CONFIG_BIAS_PULL_UP)) { |
442 | if (arg == 0) |
443 | param = PIN_CONFIG_BIAS_DISABLE; |
444 | } |
445 | |
446 | switch (param) { |
447 | case PIN_CONFIG_BIAS_DISABLE: |
448 | wmt_clearbits(data, reg: reg_pull_en, BIT(bit)); |
449 | break; |
450 | case PIN_CONFIG_BIAS_PULL_DOWN: |
451 | wmt_clearbits(data, reg: reg_pull_cfg, BIT(bit)); |
452 | wmt_setbits(data, reg: reg_pull_en, BIT(bit)); |
453 | break; |
454 | case PIN_CONFIG_BIAS_PULL_UP: |
455 | wmt_setbits(data, reg: reg_pull_cfg, BIT(bit)); |
456 | wmt_setbits(data, reg: reg_pull_en, BIT(bit)); |
457 | break; |
458 | default: |
459 | dev_err(data->dev, "unknown pinconf param\n" ); |
460 | return -EINVAL; |
461 | } |
462 | } /* for each config */ |
463 | |
464 | return 0; |
465 | } |
466 | |
467 | static const struct pinconf_ops wmt_pinconf_ops = { |
468 | .pin_config_get = wmt_pinconf_get, |
469 | .pin_config_set = wmt_pinconf_set, |
470 | }; |
471 | |
472 | static struct pinctrl_desc wmt_desc = { |
473 | .owner = THIS_MODULE, |
474 | .name = "pinctrl-wmt" , |
475 | .pctlops = &wmt_pctl_ops, |
476 | .pmxops = &wmt_pinmux_ops, |
477 | .confops = &wmt_pinconf_ops, |
478 | }; |
479 | |
480 | static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset) |
481 | { |
482 | struct wmt_pinctrl_data *data = gpiochip_get_data(gc: chip); |
483 | u32 bank = WMT_BANK_FROM_PIN(offset); |
484 | u32 bit = WMT_BIT_FROM_PIN(offset); |
485 | u32 reg_dir = data->banks[bank].reg_dir; |
486 | u32 val; |
487 | |
488 | val = readl_relaxed(data->base + reg_dir); |
489 | if (val & BIT(bit)) |
490 | return GPIO_LINE_DIRECTION_OUT; |
491 | |
492 | return GPIO_LINE_DIRECTION_IN; |
493 | } |
494 | |
495 | static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset) |
496 | { |
497 | struct wmt_pinctrl_data *data = gpiochip_get_data(gc: chip); |
498 | u32 bank = WMT_BANK_FROM_PIN(offset); |
499 | u32 bit = WMT_BIT_FROM_PIN(offset); |
500 | u32 reg_data_in = data->banks[bank].reg_data_in; |
501 | |
502 | if (reg_data_in == NO_REG) { |
503 | dev_err(data->dev, "no data in register defined\n" ); |
504 | return -EINVAL; |
505 | } |
506 | |
507 | return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit)); |
508 | } |
509 | |
510 | static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset, |
511 | int val) |
512 | { |
513 | struct wmt_pinctrl_data *data = gpiochip_get_data(gc: chip); |
514 | u32 bank = WMT_BANK_FROM_PIN(offset); |
515 | u32 bit = WMT_BIT_FROM_PIN(offset); |
516 | u32 reg_data_out = data->banks[bank].reg_data_out; |
517 | |
518 | if (reg_data_out == NO_REG) { |
519 | dev_err(data->dev, "no data out register defined\n" ); |
520 | return; |
521 | } |
522 | |
523 | if (val) |
524 | wmt_setbits(data, reg: reg_data_out, BIT(bit)); |
525 | else |
526 | wmt_clearbits(data, reg: reg_data_out, BIT(bit)); |
527 | } |
528 | |
529 | static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset, |
530 | int value) |
531 | { |
532 | wmt_gpio_set_value(chip, offset, val: value); |
533 | return pinctrl_gpio_direction_output(gc: chip, offset); |
534 | } |
535 | |
536 | static const struct gpio_chip wmt_gpio_chip = { |
537 | .label = "gpio-wmt" , |
538 | .owner = THIS_MODULE, |
539 | .request = gpiochip_generic_request, |
540 | .free = gpiochip_generic_free, |
541 | .get_direction = wmt_gpio_get_direction, |
542 | .direction_input = pinctrl_gpio_direction_input, |
543 | .direction_output = wmt_gpio_direction_output, |
544 | .get = wmt_gpio_get_value, |
545 | .set = wmt_gpio_set_value, |
546 | .can_sleep = false, |
547 | }; |
548 | |
549 | int wmt_pinctrl_probe(struct platform_device *pdev, |
550 | struct wmt_pinctrl_data *data) |
551 | { |
552 | int err; |
553 | |
554 | data->base = devm_platform_ioremap_resource(pdev, index: 0); |
555 | if (IS_ERR(ptr: data->base)) |
556 | return PTR_ERR(ptr: data->base); |
557 | |
558 | wmt_desc.pins = data->pins; |
559 | wmt_desc.npins = data->npins; |
560 | |
561 | data->gpio_chip = wmt_gpio_chip; |
562 | data->gpio_chip.parent = &pdev->dev; |
563 | data->gpio_chip.ngpio = data->nbanks * 32; |
564 | |
565 | platform_set_drvdata(pdev, data); |
566 | |
567 | data->dev = &pdev->dev; |
568 | |
569 | data->pctl_dev = devm_pinctrl_register(dev: &pdev->dev, pctldesc: &wmt_desc, driver_data: data); |
570 | if (IS_ERR(ptr: data->pctl_dev)) { |
571 | dev_err(&pdev->dev, "Failed to register pinctrl\n" ); |
572 | return PTR_ERR(ptr: data->pctl_dev); |
573 | } |
574 | |
575 | err = gpiochip_add_data(&data->gpio_chip, data); |
576 | if (err) { |
577 | dev_err(&pdev->dev, "could not add GPIO chip\n" ); |
578 | return err; |
579 | } |
580 | |
581 | err = gpiochip_add_pin_range(gc: &data->gpio_chip, pinctl_name: dev_name(dev: data->dev), |
582 | gpio_offset: 0, pin_offset: 0, npins: data->nbanks * 32); |
583 | if (err) |
584 | goto fail_range; |
585 | |
586 | dev_info(&pdev->dev, "Pin controller initialized\n" ); |
587 | |
588 | return 0; |
589 | |
590 | fail_range: |
591 | gpiochip_remove(gc: &data->gpio_chip); |
592 | return err; |
593 | } |
594 | |