1ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng/*
2ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * Core driver for the imx pin controller
3ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng *
4ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * Copyright (C) 2012 Freescale Semiconductor, Inc.
5ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * Copyright (C) 2012 Linaro Ltd.
6ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng *
7ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * Author: Dong Aisheng <dong.aisheng@linaro.org>
8ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng *
9ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * This program is free software; you can redistribute it and/or modify
10ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * it under the terms of the GNU General Public License as published by
11ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * the Free Software Foundation; either version 2 of the License, or
12ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * (at your option) any later version.
13ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng */
14ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
15ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/err.h>
16ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/init.h>
17ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/io.h>
18ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/module.h>
19ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/of.h>
20ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/of_device.h>
21ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/pinctrl/machine.h>
22ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/pinctrl/pinconf.h>
23ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/pinctrl/pinctrl.h>
24ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/pinctrl/pinmux.h>
25ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include <linux/slab.h>
26ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
27edad3b2a57082f6166b4f13445f70e8d3fc415fbLinus Walleij#include "../core.h"
28ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#include "pinctrl-imx.h"
29ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
30ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng/* The bits in CONFIG cell defined in binding doc*/
31ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#define IMX_NO_PAD_CTL	0x80000000	/* no pin config need */
32ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng#define IMX_PAD_SION 0x40000000		/* set SION */
33ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
34ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng/**
35ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * @dev: a pointer back to containing device
36ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng * @base: the offset to the controller in virtual memory
37ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng */
38ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstruct imx_pinctrl {
39ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct device *dev;
40ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct pinctrl_dev *pctl;
41ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	void __iomem *base;
42ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info;
43ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng};
44ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
45ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic const inline struct imx_pin_group *imx_pinctrl_find_group_by_name(
46ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				const struct imx_pinctrl_soc_info *info,
47ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				const char *name)
48ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
49ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pin_group *grp = NULL;
50ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	int i;
51ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
52ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for (i = 0; i < info->ngroups; i++) {
53ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		if (!strcmp(info->groups[i].name, name)) {
54ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			grp = &info->groups[i];
55ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			break;
56ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		}
57ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
58ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
59ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return grp;
60ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
61ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
62ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_get_groups_count(struct pinctrl_dev *pctldev)
63ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
64ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
65ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
66ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
67ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return info->ngroups;
68ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
69ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
70ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic const char *imx_get_group_name(struct pinctrl_dev *pctldev,
71ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				       unsigned selector)
72ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
73ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
74ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
75ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
76ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return info->groups[selector].name;
77ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
78ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
79ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
80ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			       const unsigned **pins,
81ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			       unsigned *npins)
82ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
83ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
84ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
85ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
86ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (selector >= info->ngroups)
87ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
88ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
898f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	*pins = info->groups[selector].pin_ids;
90ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*npins = info->groups[selector].npins;
91ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
92ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
93ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
94ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
95ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
96ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		   unsigned offset)
97ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
98ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	seq_printf(s, "%s", dev_name(pctldev->dev));
99ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
100ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
101ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
102ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			struct device_node *np,
103ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			struct pinctrl_map **map, unsigned *num_maps)
104ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
105ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
106ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
107ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pin_group *grp;
108ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct pinctrl_map *new_map;
109ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct device_node *parent;
110ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	int map_num = 1;
11118071610677fc491a226fa6d5471c89a26ce670dHui Wang	int i, j;
112ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
113ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/*
114ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * first find the group of this node and check if we need create
115ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * config maps for pins
116ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 */
117ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	grp = imx_pinctrl_find_group_by_name(info, np->name);
118ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!grp) {
119ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(info->dev, "unable to find group for node %s\n",
120ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			np->name);
121ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
122ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
123ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
124ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for (i = 0; i < grp->npins; i++) {
1258f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		if (!(grp->pins[i].config & IMX_NO_PAD_CTL))
126ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			map_num++;
127ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
128ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
129ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
130ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!new_map)
131ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -ENOMEM;
132ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
133ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*map = new_map;
134ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*num_maps = map_num;
135ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
136ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* create mux map */
137ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	parent = of_get_parent(np);
138c71157c54a4f86e4f355dc6952268e8536013502Devendra Naga	if (!parent) {
139c71157c54a4f86e4f355dc6952268e8536013502Devendra Naga		kfree(new_map);
140ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
141c71157c54a4f86e4f355dc6952268e8536013502Devendra Naga	}
142ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
143ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	new_map[0].data.mux.function = parent->name;
144ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	new_map[0].data.mux.group = np->name;
145ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	of_node_put(parent);
146ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
147ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* create config map */
148ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	new_map++;
14918071610677fc491a226fa6d5471c89a26ce670dHui Wang	for (i = j = 0; i < grp->npins; i++) {
1508f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) {
15118071610677fc491a226fa6d5471c89a26ce670dHui Wang			new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
15218071610677fc491a226fa6d5471c89a26ce670dHui Wang			new_map[j].data.configs.group_or_pin =
1538f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer					pin_get_name(pctldev, grp->pins[i].pin);
1548f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			new_map[j].data.configs.configs = &grp->pins[i].config;
15518071610677fc491a226fa6d5471c89a26ce670dHui Wang			new_map[j].data.configs.num_configs = 1;
15618071610677fc491a226fa6d5471c89a26ce670dHui Wang			j++;
157ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		}
158ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
159ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
160ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
16167695f2eae210b0631fb92cf5649d0454953e230Dong Aisheng		(*map)->data.mux.function, (*map)->data.mux.group, map_num);
162ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
163ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
164ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
165ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
166ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic void imx_dt_free_map(struct pinctrl_dev *pctldev,
167ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				struct pinctrl_map *map, unsigned num_maps)
168ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
1693a86a5f8abb33956446ae31b1e9c149d7b2d1d21Devendra Naga	kfree(map);
170ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
171ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
172022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinctrl_ops imx_pctrl_ops = {
173ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_groups_count = imx_get_groups_count,
174ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_group_name = imx_get_group_name,
175ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_group_pins = imx_get_group_pins,
176ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pin_dbg_show = imx_pin_dbg_show,
177ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.dt_node_to_map = imx_dt_node_to_map,
178ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.dt_free_map = imx_dt_free_map,
179ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
180ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng};
181ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
18203e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleijstatic int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
18303e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij		       unsigned group)
184ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
185ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
186ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
187ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pin_reg *pin_reg;
188ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	unsigned int npins, pin_id;
189ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	int i;
1908f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	struct imx_pin_group *grp;
191ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
192ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/*
193ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * Configure the mux mode for each pin in the group for a specific
194ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * function.
195ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 */
1968f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	grp = &info->groups[group];
1978f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	npins = grp->npins;
198ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
199ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_dbg(ipctl->dev, "enable function %s group %s\n",
2008f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		info->functions[selector].name, grp->name);
201ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
202ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for (i = 0; i < npins; i++) {
2038f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		struct imx_pin *pin = &grp->pins[i];
2048f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin_id = pin->pin;
205e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo		pin_reg = &info->pin_regs[pin_id];
206ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
2073dac1918a4912cea9375e76cb3916b751cef22dbStefan Agner		if (pin_reg->mux_reg == -1) {
208ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
209ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				info->pins[pin_id].name);
210ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			return -EINVAL;
211ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		}
212ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
213bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		if (info->flags & SHARE_MUX_CONF_REG) {
214bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			u32 reg;
215bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			reg = readl(ipctl->base + pin_reg->mux_reg);
216bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			reg &= ~(0x7 << 20);
2178f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			reg |= (pin->mux_mode << 20);
218bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			writel(reg, ipctl->base + pin_reg->mux_reg);
219bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		} else {
2208f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
221bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		}
222ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
2238f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			pin_reg->mux_reg, pin->mux_mode);
224ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
22594176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		/*
22694176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * If the select input value begins with 0xff, it's a quirky
22794176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * select input and the value should be interpreted as below.
22894176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 *     31     23      15      7        0
22994176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 *     | 0xff | shift | width | select |
23094176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * It's used to work around the problem that the select
23194176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * input for some pin is not implemented in the select
23294176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * input register but in some general purpose register.
23394176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * We encode the select input value, width and shift of
23494176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * the bit field into input_val cell of pin function ID
23594176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * in device tree, and then decode them here for setting
23694176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 * up the select input bits in general purpose register.
23794176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo		 */
2388f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		if (pin->input_val >> 24 == 0xff) {
2398f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			u32 val = pin->input_val;
24094176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			u8 select = val & 0xff;
24194176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			u8 width = (val >> 8) & 0xff;
24294176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			u8 shift = (val >> 16) & 0xff;
24394176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			u32 mask = ((1 << width) - 1) << shift;
24494176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			/*
24594176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 * The input_reg[i] here is actually some IOMUXC general
24694176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 * purpose register, not regular select input register.
24794176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 */
248a3183c60e3e9be7abd830ebed904491625e07d2ePeter Chen			val = readl(ipctl->base + pin->input_reg);
24994176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			val &= ~mask;
25094176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			val |= select << shift;
251a3183c60e3e9be7abd830ebed904491625e07d2ePeter Chen			writel(val, ipctl->base + pin->input_reg);
252a3183c60e3e9be7abd830ebed904491625e07d2ePeter Chen		} else if (pin->input_reg) {
25394176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			/*
25494176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 * Regular select input register can never be at offset
25594176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 * 0, and we only print register value for regular case.
25694176faf279ba96394f77cde62b1fdb8304ed30dShawn Guo			 */
2578f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			writel(pin->input_val, ipctl->base + pin->input_reg);
258ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			dev_dbg(ipctl->dev,
259ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				"==>select_input: offset 0x%x val 0x%x\n",
2608f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer				pin->input_reg, pin->input_val);
261ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		}
262ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
263ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
264ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
265ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
266ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
267ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
268ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
269ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
270ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
271ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
272ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return info->nfunctions;
273ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
274ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
275ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev,
276ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng					  unsigned selector)
277ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
278ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
279ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
280ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
281ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return info->functions[selector].name;
282ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
283ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
284ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
285ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			       const char * const **groups,
286ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			       unsigned * const num_groups)
287ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
288ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
289ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
290ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
291ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*groups = info->functions[selector].groups;
292ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*num_groups = info->functions[selector].num_groups;
293ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
294ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
295ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
296ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
297022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinmux_ops imx_pmx_ops = {
298ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_functions_count = imx_pmx_get_funcs_count,
299ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_function_name = imx_pmx_get_func_name,
300ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.get_function_groups = imx_pmx_get_groups,
30103e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij	.set_mux = imx_pmx_set,
302ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng};
303ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
304ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_pinconf_get(struct pinctrl_dev *pctldev,
305ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			     unsigned pin_id, unsigned long *config)
306ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
307ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
308ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
309e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
310ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
3113dac1918a4912cea9375e76cb3916b751cef22dbStefan Agner	if (pin_reg->conf_reg == -1) {
312ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(info->dev, "Pin(%s) does not support config function\n",
313ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			info->pins[pin_id].name);
314ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
315ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
316ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
317ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	*config = readl(ipctl->base + pin_reg->conf_reg);
318ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
319bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	if (info->flags & SHARE_MUX_CONF_REG)
320bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		*config &= 0xffff;
321bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu
322ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
323ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
324ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
325ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic int imx_pinconf_set(struct pinctrl_dev *pctldev,
32603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			     unsigned pin_id, unsigned long *configs,
32703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			     unsigned num_configs)
328ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
329ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
330ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
331e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
33203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	int i;
333ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
3343dac1918a4912cea9375e76cb3916b751cef22dbStefan Agner	if (pin_reg->conf_reg == -1) {
335ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(info->dev, "Pin(%s) does not support config function\n",
336ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			info->pins[pin_id].name);
337ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
338ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
339ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
340ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_dbg(ipctl->dev, "pinconf set pin %s\n",
341ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		info->pins[pin_id].name);
342ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
34303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	for (i = 0; i < num_configs; i++) {
34403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		if (info->flags & SHARE_MUX_CONF_REG) {
34503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			u32 reg;
34603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			reg = readl(ipctl->base + pin_reg->conf_reg);
34703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			reg &= ~0xffff;
34803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			reg |= configs[i];
34903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(reg, ipctl->base + pin_reg->conf_reg);
35003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		} else {
35103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(configs[i], ipctl->base + pin_reg->conf_reg);
35203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		}
35303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
35403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			pin_reg->conf_reg, configs[i]);
35503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	} /* for each config */
356ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
357ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
358ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
359ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
360ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
361ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				   struct seq_file *s, unsigned pin_id)
362ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
363ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
364ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
365e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
366ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	unsigned long config;
367ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
368ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!pin_reg || !pin_reg->conf_reg) {
369ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		seq_printf(s, "N/A");
370ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return;
371ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
372ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
373ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	config = readl(ipctl->base + pin_reg->conf_reg);
374ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	seq_printf(s, "0x%lx", config);
375ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
376ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
377ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
378ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng					 struct seq_file *s, unsigned group)
379ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
380ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
381ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const struct imx_pinctrl_soc_info *info = ipctl->info;
382ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pin_group *grp;
383ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	unsigned long config;
384ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	const char *name;
385ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	int i, ret;
386ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
387ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (group > info->ngroups)
388ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return;
389ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
390ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	seq_printf(s, "\n");
391ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	grp = &info->groups[group];
392ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for (i = 0; i < grp->npins; i++) {
3938f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		struct imx_pin *pin = &grp->pins[i];
3948f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		name = pin_get_name(pctldev, pin->pin);
3958f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		ret = imx_pinconf_get(pctldev, pin->pin, &config);
396ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		if (ret)
397ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			return;
398ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		seq_printf(s, "%s: 0x%lx", name, config);
399ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
400ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
401ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
402022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinconf_ops imx_pinconf_ops = {
403ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pin_config_get = imx_pinconf_get,
404ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pin_config_set = imx_pinconf_set,
405ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pin_config_dbg_show = imx_pinconf_dbg_show,
406ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
407ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng};
408ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
409ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aishengstatic struct pinctrl_desc imx_pinctrl_desc = {
410ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pctlops = &imx_pctrl_ops,
411ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.pmxops = &imx_pmx_ops,
412ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.confops = &imx_pinconf_ops,
413ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	.owner = THIS_MODULE,
414ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng};
415ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
416e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo/*
417e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
418e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo * 1 u32 CONFIG, so 24 types in total for each pin.
419e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo */
420e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo#define FSL_PIN_SIZE 24
421bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu#define SHARE_FSL_PIN_SIZE 20
422ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
423150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanstatic int imx_pinctrl_parse_groups(struct device_node *np,
424150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman				    struct imx_pin_group *grp,
425150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman				    struct imx_pinctrl_soc_info *info,
426150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman				    u32 index)
427ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
428bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	int size, pin_size;
429a695145b9c4225eeadf56c3caf37cb3b525a32d4Richard Zhao	const __be32 *list;
430e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	int i;
431ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	u32 config;
432ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
433ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
434ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
435bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	if (info->flags & SHARE_MUX_CONF_REG)
436bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		pin_size = SHARE_FSL_PIN_SIZE;
437bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	else
438bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		pin_size = FSL_PIN_SIZE;
439ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* Initialise group */
440ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	grp->name = np->name;
441ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
442ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/*
443ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>,
444ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 * do sanity check and calculate pins number
445ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	 */
446ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	list = of_get_property(np, "fsl,pins", &size);
4471bf1fea95ff9161fafccbcac76b37bbadc924bd0Sascha Hauer	if (!list) {
4481bf1fea95ff9161fafccbcac76b37bbadc924bd0Sascha Hauer		dev_err(info->dev, "no fsl,pins property in node %s\n", np->full_name);
4491bf1fea95ff9161fafccbcac76b37bbadc924bd0Sascha Hauer		return -EINVAL;
4501bf1fea95ff9161fafccbcac76b37bbadc924bd0Sascha Hauer	}
4511bf1fea95ff9161fafccbcac76b37bbadc924bd0Sascha Hauer
452ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* we do not check return since it's safe node passed down */
453bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	if (!size || size % pin_size) {
45401312513c4a48bdd4dbbea07716bd2dcd5d11c87Sascha Hauer		dev_err(info->dev, "Invalid fsl,pins property in node %s\n", np->full_name);
455ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
456ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
457ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
458bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu	grp->npins = size / pin_size;
4598f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin),
460ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				GFP_KERNEL);
4618f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
462ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				GFP_KERNEL);
4638f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer	if (!grp->pins || ! grp->pin_ids)
4648f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		return -ENOMEM;
4658f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer
466e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	for (i = 0; i < grp->npins; i++) {
467e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo		u32 mux_reg = be32_to_cpu(*list++);
468bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		u32 conf_reg;
469bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		unsigned int pin_id;
470bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		struct imx_pin_reg *pin_reg;
4718f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		struct imx_pin *pin = &grp->pins[i];
472e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo
473bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		if (info->flags & SHARE_MUX_CONF_REG)
474bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			conf_reg = mux_reg;
475bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		else
476bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu			conf_reg = be32_to_cpu(*list++);
477bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu
478bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
479bf5a530971afbe959348af4d84d17636108e6abfJingchang Lu		pin_reg = &info->pin_regs[pin_id];
4808f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin->pin = pin_id;
4818f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		grp->pin_ids[i] = pin_id;
482e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo		pin_reg->mux_reg = mux_reg;
483e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo		pin_reg->conf_reg = conf_reg;
4848f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin->input_reg = be32_to_cpu(*list++);
4858f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin->mux_mode = be32_to_cpu(*list++);
4868f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin->input_val = be32_to_cpu(*list++);
487e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo
488ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		/* SION bit is in mux register */
489ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		config = be32_to_cpu(*list++);
490ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		if (config & IMX_PAD_SION)
4918f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer			pin->mux_mode |= IOMUXC_CONFIG_SION;
4928f903f8a342e466f3da33b21ae60f1b11626b81aSascha Hauer		pin->config = config & ~IMX_PAD_SION;
493ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
49408b519534e8c9a2bbf26db3e2dbab81e40b91705Fabio Estevam		dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
495406044695fb286110324491f26f3e05048488809Sascha Hauer				pin->mux_mode, pin->config);
496406044695fb286110324491f26f3e05048488809Sascha Hauer	}
4973a86a5f8abb33956446ae31b1e9c149d7b2d1d21Devendra Naga
498ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
499ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
500ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
501150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanstatic int imx_pinctrl_parse_functions(struct device_node *np,
502150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman				       struct imx_pinctrl_soc_info *info,
503150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman				       u32 index)
504ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
505ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct device_node *child;
506ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pmx_func *func;
507ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pin_group *grp;
508ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	static u32 grp_index;
509ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	u32 i = 0;
510ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
511ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
512ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
513ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	func = &info->functions[index];
514ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
515ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* Initialise function */
516ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	func->name = np->name;
517ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	func->num_groups = of_get_child_count(np);
5189eedfd688cb267d0fee06f68cbbddaf94423482eRickard Strandqvist	if (func->num_groups == 0) {
51901312513c4a48bdd4dbbea07716bd2dcd5d11c87Sascha Hauer		dev_err(info->dev, "no groups defined in %s\n", np->full_name);
520ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
521ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
522ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	func->groups = devm_kzalloc(info->dev,
523ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng			func->num_groups * sizeof(char *), GFP_KERNEL);
524ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
525ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for_each_child_of_node(np, child) {
526ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		func->groups[i] = child->name;
527ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		grp = &info->groups[grp_index++];
5285e13762cf8e5a4998c3a80d2265f0c3b3277854eSascha Hauer		imx_pinctrl_parse_groups(child, grp, info, i++);
529ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
530ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
531ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
532ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
533ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
534150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanstatic int imx_pinctrl_probe_dt(struct platform_device *pdev,
535ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng				struct imx_pinctrl_soc_info *info)
536ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
537ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct device_node *np = pdev->dev.of_node;
538ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct device_node *child;
539ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	u32 nfuncs = 0;
540ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	u32 i = 0;
541ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
542ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!np)
543ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -ENODEV;
544ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
545ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	nfuncs = of_get_child_count(np);
546ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (nfuncs <= 0) {
547ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(&pdev->dev, "no functions defined\n");
548ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
549ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
550ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
551ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	info->nfunctions = nfuncs;
552ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
553ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng					GFP_KERNEL);
554ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!info->functions)
555ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -ENOMEM;
556ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
557ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	info->ngroups = 0;
558ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	for_each_child_of_node(np, child)
559ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		info->ngroups += of_get_child_count(child);
560ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
561ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng					GFP_KERNEL);
562ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!info->groups)
563ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -ENOMEM;
564ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
5657ea46e0f9df44ce3dea5a54f7c182f98eeef7beeSascha Hauer	for_each_child_of_node(np, child)
5667ea46e0f9df44ce3dea5a54f7c182f98eeef7beeSascha Hauer		imx_pinctrl_parse_functions(child, info, i++);
567ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
568ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
569ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
570ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
571150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanint imx_pinctrl_probe(struct platform_device *pdev,
572150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartman		      struct imx_pinctrl_soc_info *info)
573ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
574ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl;
575ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct resource *res;
576ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	int ret;
577ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
578e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	if (!info || !info->pins || !info->npins) {
579ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(&pdev->dev, "wrong pinctrl info\n");
580ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
581ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
582ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	info->dev = &pdev->dev;
583ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
584ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	/* Create state holders etc for this driver */
585ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
586ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!ipctl)
587ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -ENOMEM;
588ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
5893dac1918a4912cea9375e76cb3916b751cef22dbStefan Agner	info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
590e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo				      info->npins, GFP_KERNEL);
591e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo	if (!info->pin_regs)
592e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo		return -ENOMEM;
5933dac1918a4912cea9375e76cb3916b751cef22dbStefan Agner	memset(info->pin_regs, 0xff, sizeof(*info->pin_regs) * info->npins);
594e16415313c9b00b1adc313e85c2c8a81febe0b98Shawn Guo
595ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5969e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding	ipctl->base = devm_ioremap_resource(&pdev->dev, res);
5979e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding	if (IS_ERR(ipctl->base))
5989e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding		return PTR_ERR(ipctl->base);
599ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
600ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	imx_pinctrl_desc.name = dev_name(&pdev->dev);
601ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	imx_pinctrl_desc.pins = info->pins;
602ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	imx_pinctrl_desc.npins = info->npins;
603ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
604ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	ret = imx_pinctrl_probe_dt(pdev, info);
605ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (ret) {
606ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(&pdev->dev, "fail to probe dt properties\n");
607ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return ret;
608ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
609ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
610ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	ipctl->info = info;
611ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	ipctl->dev = info->dev;
612ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	platform_set_drvdata(pdev, ipctl);
613ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	ipctl->pctl = pinctrl_register(&imx_pinctrl_desc, &pdev->dev, ipctl);
614ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	if (!ipctl->pctl) {
615ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
616ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng		return -EINVAL;
617ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	}
618ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
619ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
620ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
621ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
622ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
623ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
624f90f54b3f3c4d1c9168d5f8e97c6ac5b9ad25f5eBill Pembertonint imx_pinctrl_remove(struct platform_device *pdev)
625ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng{
626ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	struct imx_pinctrl *ipctl = platform_get_drvdata(pdev);
627ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
628ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	pinctrl_unregister(ipctl->pctl);
629ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng
630ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng	return 0;
631ae75ff8145384000e27eaa805c12e6971e3bec45Dong Aisheng}
632