1/*
2 * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/export.h>
16#include <linux/mfd/syscon.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/regmap.h>
23
24#include "../core.h"
25#include "../pinctrl-utils.h"
26#include "pinctrl-uniphier.h"
27
28struct uniphier_pinctrl_priv {
29	struct pinctrl_dev *pctldev;
30	struct regmap *regmap;
31	struct uniphier_pinctrl_socdata *socdata;
32};
33
34static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev)
35{
36	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
37
38	return priv->socdata->groups_count;
39}
40
41static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev,
42						unsigned selector)
43{
44	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
45
46	return priv->socdata->groups[selector].name;
47}
48
49static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev,
50					unsigned selector,
51					const unsigned **pins,
52					unsigned *num_pins)
53{
54	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
55
56	*pins = priv->socdata->groups[selector].pins;
57	*num_pins = priv->socdata->groups[selector].num_pins;
58
59	return 0;
60}
61
62#ifdef CONFIG_DEBUG_FS
63static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
64				       struct seq_file *s, unsigned offset)
65{
66	const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset];
67	const char *pull_dir, *drv_str;
68
69	switch (uniphier_pin_get_pull_dir(pin->drv_data)) {
70	case UNIPHIER_PIN_PULL_UP:
71		pull_dir = "UP";
72		break;
73	case UNIPHIER_PIN_PULL_DOWN:
74		pull_dir = "DOWN";
75		break;
76	case UNIPHIER_PIN_PULL_NONE:
77		pull_dir = "NONE";
78		break;
79	default:
80		BUG();
81	}
82
83	switch (uniphier_pin_get_drv_str(pin->drv_data)) {
84	case UNIPHIER_PIN_DRV_4_8:
85		drv_str = "4/8(mA)";
86		break;
87	case UNIPHIER_PIN_DRV_8_12_16_20:
88		drv_str = "8/12/16/20(mA)";
89		break;
90	case UNIPHIER_PIN_DRV_FIXED_4:
91		drv_str = "4(mA)";
92		break;
93	case UNIPHIER_PIN_DRV_FIXED_5:
94		drv_str = "5(mA)";
95		break;
96	case UNIPHIER_PIN_DRV_FIXED_8:
97		drv_str = "8(mA)";
98		break;
99	case UNIPHIER_PIN_DRV_NONE:
100		drv_str = "NONE";
101		break;
102	default:
103		BUG();
104	}
105
106	seq_printf(s, " PULL_DIR=%s  DRV_STR=%s", pull_dir, drv_str);
107}
108#endif
109
110static const struct pinctrl_ops uniphier_pctlops = {
111	.get_groups_count = uniphier_pctl_get_groups_count,
112	.get_group_name = uniphier_pctl_get_group_name,
113	.get_group_pins = uniphier_pctl_get_group_pins,
114#ifdef CONFIG_DEBUG_FS
115	.pin_dbg_show = uniphier_pctl_pin_dbg_show,
116#endif
117	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
118	.dt_free_map = pinctrl_utils_dt_free_map,
119};
120
121static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev,
122				      const struct pinctrl_pin_desc *pin,
123				      enum pin_config_param param)
124{
125	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
126	enum uniphier_pin_pull_dir pull_dir =
127				uniphier_pin_get_pull_dir(pin->drv_data);
128	unsigned int pupdctrl, reg, shift, val;
129	unsigned int expected = 1;
130	int ret;
131
132	switch (param) {
133	case PIN_CONFIG_BIAS_DISABLE:
134		if (pull_dir == UNIPHIER_PIN_PULL_NONE)
135			return 0;
136		if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED ||
137		    pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED)
138			return -EINVAL;
139		expected = 0;
140		break;
141	case PIN_CONFIG_BIAS_PULL_UP:
142		if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED)
143			return 0;
144		if (pull_dir != UNIPHIER_PIN_PULL_UP)
145			return -EINVAL;
146		break;
147	case PIN_CONFIG_BIAS_PULL_DOWN:
148		if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED)
149			return 0;
150		if (pull_dir != UNIPHIER_PIN_PULL_DOWN)
151			return -EINVAL;
152		break;
153	default:
154		BUG();
155	}
156
157	pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
158
159	reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
160	shift = pupdctrl % 32;
161
162	ret = regmap_read(priv->regmap, reg, &val);
163	if (ret)
164		return ret;
165
166	val = (val >> shift) & 1;
167
168	return (val == expected) ? 0 : -EINVAL;
169}
170
171static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev,
172				       const struct pinctrl_pin_desc *pin,
173				       u16 *strength)
174{
175	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
176	enum uniphier_pin_drv_str drv_str =
177				uniphier_pin_get_drv_str(pin->drv_data);
178	const unsigned int strength_4_8[] = {4, 8};
179	const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20};
180	const unsigned int *supported_strength;
181	unsigned int drvctrl, reg, shift, mask, width, val;
182	int ret;
183
184	switch (drv_str) {
185	case UNIPHIER_PIN_DRV_4_8:
186		supported_strength = strength_4_8;
187		width = 1;
188		break;
189	case UNIPHIER_PIN_DRV_8_12_16_20:
190		supported_strength = strength_8_12_16_20;
191		width = 2;
192		break;
193	case UNIPHIER_PIN_DRV_FIXED_4:
194		*strength = 4;
195		return 0;
196	case UNIPHIER_PIN_DRV_FIXED_5:
197		*strength = 5;
198		return 0;
199	case UNIPHIER_PIN_DRV_FIXED_8:
200		*strength = 8;
201		return 0;
202	default:
203		/* drive strength control is not supported for this pin */
204		return -EINVAL;
205	}
206
207	drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
208	drvctrl *= width;
209
210	reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
211			     UNIPHIER_PINCTRL_DRVCTRL_BASE;
212
213	reg += drvctrl / 32 * 4;
214	shift = drvctrl % 32;
215	mask = (1U << width) - 1;
216
217	ret = regmap_read(priv->regmap, reg, &val);
218	if (ret)
219		return ret;
220
221	*strength = supported_strength[(val >> shift) & mask];
222
223	return 0;
224}
225
226static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev,
227					const struct pinctrl_pin_desc *pin)
228{
229	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
230	unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
231	unsigned int val;
232	int ret;
233
234	if (iectrl == UNIPHIER_PIN_IECTRL_NONE)
235		/* This pin is always input-enabled. */
236		return 0;
237
238	ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val);
239	if (ret)
240		return ret;
241
242	return val & BIT(iectrl) ? 0 : -EINVAL;
243}
244
245static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev,
246					unsigned pin,
247					unsigned long *configs)
248{
249	const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
250	enum pin_config_param param = pinconf_to_config_param(*configs);
251	bool has_arg = false;
252	u16 arg;
253	int ret;
254
255	switch (param) {
256	case PIN_CONFIG_BIAS_DISABLE:
257	case PIN_CONFIG_BIAS_PULL_UP:
258	case PIN_CONFIG_BIAS_PULL_DOWN:
259		ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param);
260		break;
261	case PIN_CONFIG_DRIVE_STRENGTH:
262		ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg);
263		has_arg = true;
264		break;
265	case PIN_CONFIG_INPUT_ENABLE:
266		ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc);
267		break;
268	default:
269		/* unsupported parameter */
270		ret = -EINVAL;
271		break;
272	}
273
274	if (ret == 0 && has_arg)
275		*configs = pinconf_to_config_packed(param, arg);
276
277	return ret;
278}
279
280static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev,
281				      const struct pinctrl_pin_desc *pin,
282				      enum pin_config_param param,
283				      u16 arg)
284{
285	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
286	enum uniphier_pin_pull_dir pull_dir =
287				uniphier_pin_get_pull_dir(pin->drv_data);
288	unsigned int pupdctrl, reg, shift;
289	unsigned int val = 1;
290
291	switch (param) {
292	case PIN_CONFIG_BIAS_DISABLE:
293		if (pull_dir == UNIPHIER_PIN_PULL_NONE)
294			return 0;
295		if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED ||
296		    pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) {
297			dev_err(pctldev->dev,
298				"can not disable pull register for pin %u (%s)\n",
299				pin->number, pin->name);
300			return -EINVAL;
301		}
302		val = 0;
303		break;
304	case PIN_CONFIG_BIAS_PULL_UP:
305		if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0)
306			return 0;
307		if (pull_dir != UNIPHIER_PIN_PULL_UP) {
308			dev_err(pctldev->dev,
309				"pull-up is unsupported for pin %u (%s)\n",
310				pin->number, pin->name);
311			return -EINVAL;
312		}
313		if (arg == 0) {
314			dev_err(pctldev->dev, "pull-up can not be total\n");
315			return -EINVAL;
316		}
317		break;
318	case PIN_CONFIG_BIAS_PULL_DOWN:
319		if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0)
320			return 0;
321		if (pull_dir != UNIPHIER_PIN_PULL_DOWN) {
322			dev_err(pctldev->dev,
323				"pull-down is unsupported for pin %u (%s)\n",
324				pin->number, pin->name);
325			return -EINVAL;
326		}
327		if (arg == 0) {
328			dev_err(pctldev->dev, "pull-down can not be total\n");
329			return -EINVAL;
330		}
331		break;
332	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
333		if (pull_dir == UNIPHIER_PIN_PULL_NONE) {
334			dev_err(pctldev->dev,
335				"pull-up/down is unsupported for pin %u (%s)\n",
336				pin->number, pin->name);
337			return -EINVAL;
338		}
339
340		if (arg == 0)
341			return 0; /* configuration ingored */
342		break;
343	default:
344		BUG();
345	}
346
347	pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data);
348
349	reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4;
350	shift = pupdctrl % 32;
351
352	return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift);
353}
354
355static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev,
356				       const struct pinctrl_pin_desc *pin,
357				       u16 strength)
358{
359	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
360	enum uniphier_pin_drv_str drv_str =
361				uniphier_pin_get_drv_str(pin->drv_data);
362	const unsigned int strength_4_8[] = {4, 8, -1};
363	const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1};
364	const unsigned int *supported_strength;
365	unsigned int drvctrl, reg, shift, mask, width, val;
366
367	switch (drv_str) {
368	case UNIPHIER_PIN_DRV_4_8:
369		supported_strength = strength_4_8;
370		width = 1;
371		break;
372	case UNIPHIER_PIN_DRV_8_12_16_20:
373		supported_strength = strength_8_12_16_20;
374		width = 2;
375		break;
376	default:
377		dev_err(pctldev->dev,
378			"cannot change drive strength for pin %u (%s)\n",
379			pin->number, pin->name);
380		return -EINVAL;
381	}
382
383	for (val = 0; supported_strength[val] > 0; val++) {
384		if (supported_strength[val] > strength)
385			break;
386	}
387
388	if (val == 0) {
389		dev_err(pctldev->dev,
390			"unsupported drive strength %u mA for pin %u (%s)\n",
391			strength, pin->number, pin->name);
392		return -EINVAL;
393	}
394
395	val--;
396
397	drvctrl = uniphier_pin_get_drvctrl(pin->drv_data);
398	drvctrl *= width;
399
400	reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE :
401			     UNIPHIER_PINCTRL_DRVCTRL_BASE;
402
403	reg += drvctrl / 32 * 4;
404	shift = drvctrl % 32;
405	mask = (1U << width) - 1;
406
407	return regmap_update_bits(priv->regmap, reg,
408				  mask << shift, val << shift);
409}
410
411static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev,
412					  const struct pinctrl_pin_desc *pin,
413					  u16 enable)
414{
415	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
416	unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data);
417
418	if (enable == 0) {
419		/*
420		 * Multiple pins share one input enable, so per-pin disabling
421		 * is impossible.
422		 */
423		dev_err(pctldev->dev, "unable to disable input\n");
424		return -EINVAL;
425	}
426
427	if (iectrl == UNIPHIER_PIN_IECTRL_NONE)
428		/* This pin is always input-enabled. nothing to do. */
429		return 0;
430
431	return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL,
432				  BIT(iectrl), BIT(iectrl));
433}
434
435static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev,
436					unsigned pin,
437					unsigned long *configs,
438					unsigned num_configs)
439{
440	const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin];
441	int i, ret;
442
443	for (i = 0; i < num_configs; i++) {
444		enum pin_config_param param =
445					pinconf_to_config_param(configs[i]);
446		u16 arg = pinconf_to_config_argument(configs[i]);
447
448		switch (param) {
449		case PIN_CONFIG_BIAS_DISABLE:
450		case PIN_CONFIG_BIAS_PULL_UP:
451		case PIN_CONFIG_BIAS_PULL_DOWN:
452		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
453			ret = uniphier_conf_pin_bias_set(pctldev, pin_desc,
454							 param, arg);
455			break;
456		case PIN_CONFIG_DRIVE_STRENGTH:
457			ret = uniphier_conf_pin_drive_set(pctldev, pin_desc,
458							  arg);
459			break;
460		case PIN_CONFIG_INPUT_ENABLE:
461			ret = uniphier_conf_pin_input_enable(pctldev,
462							     pin_desc, arg);
463			break;
464		default:
465			dev_err(pctldev->dev,
466				"unsupported configuration parameter %u\n",
467				param);
468			return -EINVAL;
469		}
470
471		if (ret)
472			return ret;
473	}
474
475	return 0;
476}
477
478static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
479					      unsigned selector,
480					      unsigned long *configs,
481					      unsigned num_configs)
482{
483	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
484	const unsigned *pins = priv->socdata->groups[selector].pins;
485	unsigned num_pins = priv->socdata->groups[selector].num_pins;
486	int i, ret;
487
488	for (i = 0; i < num_pins; i++) {
489		ret = uniphier_conf_pin_config_set(pctldev, pins[i],
490						   configs, num_configs);
491		if (ret)
492			return ret;
493	}
494
495	return 0;
496}
497
498static const struct pinconf_ops uniphier_confops = {
499	.is_generic = true,
500	.pin_config_get = uniphier_conf_pin_config_get,
501	.pin_config_set = uniphier_conf_pin_config_set,
502	.pin_config_group_set = uniphier_conf_pin_config_group_set,
503};
504
505static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev)
506{
507	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
508
509	return priv->socdata->functions_count;
510}
511
512static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev,
513						  unsigned selector)
514{
515	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
516
517	return priv->socdata->functions[selector].name;
518}
519
520static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev,
521					    unsigned selector,
522					    const char * const **groups,
523					    unsigned *num_groups)
524{
525	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
526
527	*groups = priv->socdata->functions[selector].groups;
528	*num_groups = priv->socdata->functions[selector].num_groups;
529
530	return 0;
531}
532
533static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin,
534				    unsigned muxval)
535{
536	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
537	unsigned mux_bits = priv->socdata->mux_bits;
538	unsigned reg_stride = priv->socdata->reg_stride;
539	unsigned reg, reg_end, shift, mask;
540	int ret;
541
542	/* some pins need input-enabling */
543	ret = uniphier_conf_pin_input_enable(pctldev,
544					     &pctldev->desc->pins[pin], 1);
545	if (ret)
546		return ret;
547
548	reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
549	reg_end = reg + reg_stride;
550	shift = pin * mux_bits % 32;
551	mask = (1U << mux_bits) - 1;
552
553	/*
554	 * If reg_stride is greater than 4, the MSB of each pinsel shall be
555	 * stored in the offset+4.
556	 */
557	for (; reg < reg_end; reg += 4) {
558		ret = regmap_update_bits(priv->regmap, reg,
559					 mask << shift, muxval << shift);
560		if (ret)
561			return ret;
562		muxval >>= mux_bits;
563	}
564
565	if (priv->socdata->load_pinctrl) {
566		ret = regmap_write(priv->regmap,
567				   UNIPHIER_PINCTRL_LOAD_PINMUX, 1);
568		if (ret)
569			return ret;
570	}
571
572	return 0;
573}
574
575static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev,
576				unsigned func_selector,
577				unsigned group_selector)
578{
579	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
580	const struct uniphier_pinctrl_group *grp =
581					&priv->socdata->groups[group_selector];
582	int i;
583	int ret;
584
585	for (i = 0; i < grp->num_pins; i++) {
586		ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i],
587					       grp->muxvals[i]);
588		if (ret)
589			return ret;
590	}
591
592	return 0;
593}
594
595static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
596					    struct pinctrl_gpio_range *range,
597					    unsigned offset)
598{
599	struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev);
600	const struct uniphier_pinctrl_group *groups = priv->socdata->groups;
601	int groups_count = priv->socdata->groups_count;
602	enum uniphier_pinmux_gpio_range_type range_type;
603	int i, j;
604
605	if (strstr(range->name, "irq"))
606		range_type = UNIPHIER_PINMUX_GPIO_RANGE_IRQ;
607	else
608		range_type = UNIPHIER_PINMUX_GPIO_RANGE_PORT;
609
610	for (i = 0; i < groups_count; i++) {
611		if (groups[i].range_type != range_type)
612			continue;
613
614		for (j = 0; j < groups[i].num_pins; j++)
615			if (groups[i].pins[j] == offset)
616				goto found;
617	}
618
619	dev_err(pctldev->dev, "pin %u does not support GPIO\n", offset);
620	return -EINVAL;
621
622found:
623	return uniphier_pmx_set_one_mux(pctldev, offset, groups[i].muxvals[j]);
624}
625
626static const struct pinmux_ops uniphier_pmxops = {
627	.get_functions_count = uniphier_pmx_get_functions_count,
628	.get_function_name = uniphier_pmx_get_function_name,
629	.get_function_groups = uniphier_pmx_get_function_groups,
630	.set_mux = uniphier_pmx_set_mux,
631	.gpio_request_enable = uniphier_pmx_gpio_request_enable,
632	.strict = true,
633};
634
635int uniphier_pinctrl_probe(struct platform_device *pdev,
636			   struct pinctrl_desc *desc,
637			   struct uniphier_pinctrl_socdata *socdata)
638{
639	struct device *dev = &pdev->dev;
640	struct uniphier_pinctrl_priv *priv;
641
642	if (!socdata ||
643	    !socdata->groups ||
644	    !socdata->groups_count ||
645	    !socdata->functions ||
646	    !socdata->functions_count ||
647	    !socdata->mux_bits ||
648	    !socdata->reg_stride) {
649		dev_err(dev, "pinctrl socdata lacks necessary members\n");
650		return -EINVAL;
651	}
652
653	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
654	if (!priv)
655		return -ENOMEM;
656
657	priv->regmap = syscon_node_to_regmap(dev->of_node);
658	if (IS_ERR(priv->regmap)) {
659		dev_err(dev, "failed to get regmap\n");
660		return PTR_ERR(priv->regmap);
661	}
662
663	priv->socdata = socdata;
664	desc->pctlops = &uniphier_pctlops;
665	desc->pmxops = &uniphier_pmxops;
666	desc->confops = &uniphier_confops;
667
668	priv->pctldev = pinctrl_register(desc, dev, priv);
669	if (IS_ERR(priv->pctldev)) {
670		dev_err(dev, "failed to register UniPhier pinctrl driver\n");
671		return PTR_ERR(priv->pctldev);
672	}
673
674	platform_set_drvdata(pdev, priv);
675
676	return 0;
677}
678EXPORT_SYMBOL_GPL(uniphier_pinctrl_probe);
679
680int uniphier_pinctrl_remove(struct platform_device *pdev)
681{
682	struct uniphier_pinctrl_priv *priv = platform_get_drvdata(pdev);
683
684	pinctrl_unregister(priv->pctldev);
685
686	return 0;
687}
688EXPORT_SYMBOL_GPL(uniphier_pinctrl_remove);
689