[go: nahoru, domu]

1f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/*
2f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC.
3f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *
4f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *		http://www.samsung.com
6f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *
7f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * This program is free software; you can redistribute it and/or modify
8f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * it under the terms of the GNU General Public License as published by
9f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * the Free Software Foundation; either version 2 of the License, or
10f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * (at your option) any later version.
11f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
12f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
13f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/module.h>
14f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/platform_device.h>
15f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/io.h>
16f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/slab.h>
17f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/err.h>
18f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/gpio.h>
19f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/device.h>
20f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinctrl.h>
21f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinmux.h>
22f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinconf.h>
238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/interrupt.h>
248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/irqdomain.h>
258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/of_irq.h>
26ebe629a39e04db3fe876d34833a2d8a6a6d4c134Sachin Kamat#include "../core.h"
27f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
28f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* EXYNOS5440 GPIO and Pinctrl register offsets */
29f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_MUX		0x00
30f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_IE			0x04
31f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_INT		0x08
32f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_TYPE		0x0C
33f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_VAL		0x10
34f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_OE			0x14
35f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_IN			0x18
36f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_PE			0x1C
37f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_PS			0x20
38f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_SR			0x24
39f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_DS0		0x28
40f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_DS1		0x2C
41f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
42f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define EXYNOS5440_MAX_PINS		23
438dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#define EXYNOS5440_MAX_GPIO_INT	8
44f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PIN_NAME_LENGTH		10
45f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
46f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GROUP_SUFFIX		"-grp"
47f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GSUFFIX_LEN		sizeof(GROUP_SUFFIX)
48f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define FUNCTION_SUFFIX		"-mux"
49f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define FSUFFIX_LEN		sizeof(FUNCTION_SUFFIX)
50f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
51f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/*
52f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * pin configuration type and its value are packed together into a 16-bits.
53f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * The upper 8-bits represent the configuration type and the lower 8-bits
54f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * hold the value of the configuration type.
55f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
56f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_TYPE_MASK		0xFF
57f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_VALUE_SHIFT		8
58f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_VALUE_MASK		(0xFF << PINCFG_VALUE_SHIFT)
59f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_PACK(type, value)	(((value) << PINCFG_VALUE_SHIFT) | type)
60f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_UNPACK_TYPE(cfg)		((cfg) & PINCFG_TYPE_MASK)
61f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_UNPACK_VALUE(cfg)	(((cfg) & PINCFG_VALUE_MASK) >> \
62f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham						PINCFG_VALUE_SHIFT)
63f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
64f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/**
65f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * enum pincfg_type - possible pin configuration types supported.
66f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_PUD: Pull up/down configuration.
67f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_DRV: Drive strength configuration.
68f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration.
69f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration.
70f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
71f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamenum pincfg_type {
72f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	PINCFG_TYPE_PUD,
73f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	PINCFG_TYPE_DRV,
74f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	PINCFG_TYPE_SKEW_RATE,
75f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	PINCFG_TYPE_INPUT_TYPE
76f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
77f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
78f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/**
79f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pin_group: represent group of pins for pincfg setting.
80f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @name: name of the pin group, used to lookup the group.
81f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pins: the pins included in this group.
82f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @num_pins: number of pins included in this group.
83f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
84f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pin_group {
85f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const char		*name;
86f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const unsigned int	*pins;
87f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u8			num_pins;
88f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
89f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
90f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/**
91f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pmx_func: represent a pin function.
92f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @name: name of the pin function, used to lookup the function.
93f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @groups: one or more names of pin groups that provide this function.
94f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @num_groups: number of groups included in @groups.
95f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @function: the function number to be programmed when selected.
96f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
97f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pmx_func {
98f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const char		*name;
99f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const char		**groups;
100f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u8			num_groups;
101f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned long		function;
102f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
103f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
104f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/**
105f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pinctrl_priv_data: driver's private runtime data.
106f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @reg_base: ioremapped based address of the register space.
107f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @gc: gpio chip registered with gpiolib.
108f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pin_groups: list of pin groups parsed from device tree.
109f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @nr_groups: number of pin groups available.
110f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pmx_functions: list of pin functions parsed from device tree.
111f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @nr_functions: number of pin functions available.
112f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
113f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pinctrl_priv_data {
114f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem			*reg_base;
115f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct gpio_chip		*gc;
1168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct irq_domain		*irq_domain;
117f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
118f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const struct exynos5440_pin_group	*pin_groups;
119f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned int			nr_groups;
120f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const struct exynos5440_pmx_func	*pmx_functions;
121f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned int			nr_functions;
122f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
123f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/**
1258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
1268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * @priv: driver's private runtime data.
1278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * @gpio_int: gpio interrupt number.
1288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham */
1298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstruct exynos5440_gpio_intr_data {
1308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data	*priv;
1318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	unsigned int				gpio_int;
1328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham};
1338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
134f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of all possible config options supported */
135d5fd5da290cef159be1295c162b4c71b8c1971a2Axel Linstatic struct pin_config {
136f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	char		*prop_cfg;
137f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned int	cfg_type;
138f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} pcfgs[] = {
139f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{ "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD },
140f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{ "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV },
141f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{ "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE },
142f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{ "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE },
143f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
144f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
145f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* check if the selector is a valid pin group selector */
146f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_group_count(struct pinctrl_dev *pctldev)
147f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
148f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
149f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
150f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
151f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return priv->nr_groups;
152f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
153f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
154f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the name of the group selected by the group selector */
155f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev,
156f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham						unsigned selector)
157f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
158f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
159f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
160f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
161f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return priv->pin_groups[selector].name;
162f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
163f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
164f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the pin numbers associated with the specified group */
165f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_group_pins(struct pinctrl_dev *pctldev,
166f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		unsigned selector, const unsigned **pins, unsigned *num_pins)
167f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
168f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
169f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
170f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
171f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*pins = priv->pin_groups[selector].pins;
172f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*num_pins = priv->pin_groups[selector].num_pins;
173f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
174f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
175f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
176f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* create pinctrl_map entries by parsing device tree nodes */
177f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev,
178f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			struct device_node *np, struct pinctrl_map **maps,
179f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			unsigned *nmaps)
180f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
181f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device *dev = pctldev->dev;
182f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct pinctrl_map *map;
183f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned long *cfg = NULL;
184f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	char *gname, *fname;
185f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int cfg_cnt = 0, map_cnt = 0, idx = 0;
186f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
187f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* count the number of config options specfied in the node */
188f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++)
189f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (of_find_property(np, pcfgs[idx].prop_cfg, NULL))
190f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			cfg_cnt++;
191f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
192f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/*
193f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * Find out the number of map entries to create. All the config options
194f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * can be accomadated into a single config map entry.
195f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 */
196f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (cfg_cnt)
197f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		map_cnt = 1;
198f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (of_find_property(np, "samsung,exynos5440-pin-function", NULL))
199f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		map_cnt++;
200f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!map_cnt) {
201f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "node %s does not have either config or function "
202f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				"configurations\n", np->name);
203f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
204f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
205f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
206f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* Allocate memory for pin-map entries */
207f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL);
208f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!map) {
209f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "could not alloc memory for pin-maps\n");
210f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
211f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
212f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*nmaps = 0;
213f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
214f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/*
215f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * Allocate memory for pin group name. The pin group name is derived
216f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * from the node name from which these map entries are be created.
217f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 */
218f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL);
219f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!gname) {
220f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "failed to alloc memory for group name\n");
221f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		goto free_map;
222f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
22379bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham	snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX);
224f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
225f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/*
226f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * don't have config options? then skip over to creating function
227f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * map entries.
228f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 */
229f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!cfg_cnt)
230f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		goto skip_cfgs;
231f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
232f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* Allocate memory for config entries */
233f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL);
234f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!cfg) {
235f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "failed to alloc memory for configs\n");
236f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		goto free_gname;
237f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
238f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
239f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* Prepare a list of config settings */
240f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) {
241f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		u32 value;
242f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value))
243f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			cfg[cfg_cnt++] =
244f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				PINCFG_PACK(pcfgs[idx].cfg_type, value);
245f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
246f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
247f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* create the config map entry */
248f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	map[*nmaps].data.configs.group_or_pin = gname;
249f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	map[*nmaps].data.configs.configs = cfg;
250f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	map[*nmaps].data.configs.num_configs = cfg_cnt;
251f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
252f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*nmaps += 1;
253f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
254f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamskip_cfgs:
255f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* create the function map entry */
256f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) {
257f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		fname = kzalloc(strlen(np->name) + FSUFFIX_LEN,	GFP_KERNEL);
258f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!fname) {
259f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			dev_err(dev, "failed to alloc memory for func name\n");
260f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			goto free_cfg;
261f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		}
26279bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham		snprintf(fname, strlen(np->name) + 4, "%s%s", np->name,
26379bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham			 FUNCTION_SUFFIX);
264f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
265f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		map[*nmaps].data.mux.group = gname;
266f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		map[*nmaps].data.mux.function = fname;
267f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
268f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		*nmaps += 1;
269f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
270f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
271f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*maps = map;
272f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
273f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
274f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_cfg:
275f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	kfree(cfg);
276f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_gname:
277f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	kfree(gname);
278f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_map:
279f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	kfree(map);
280f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return -ENOMEM;
281f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
282f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
283f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* free the memory allocated to hold the pin-map table */
284f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
285f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			     struct pinctrl_map *map, unsigned num_maps)
286f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
287f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int idx;
288f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
289f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (idx = 0; idx < num_maps; idx++) {
290f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) {
291f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			kfree(map[idx].data.mux.function);
292f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			if (!idx)
293f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				kfree(map[idx].data.mux.group);
294f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		} else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) {
295f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			kfree(map[idx].data.configs.configs);
296f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			if (!idx)
297f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				kfree(map[idx].data.configs.group_or_pin);
298f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		}
299f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	};
300f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
301f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	kfree(map);
302f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
303f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
304f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinctrl callbacks for the pinctrl core */
305022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinctrl_ops exynos5440_pctrl_ops = {
306f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_groups_count	= exynos5440_get_group_count,
307f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_group_name		= exynos5440_get_group_name,
308f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_group_pins		= exynos5440_get_group_pins,
309f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.dt_node_to_map		= exynos5440_dt_node_to_map,
310f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.dt_free_map		= exynos5440_dt_free_map,
311f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
312f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
313f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* check if the selector is a valid pin function selector */
314f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_functions_count(struct pinctrl_dev *pctldev)
315f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
316f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
317f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
318f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
319f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return priv->nr_functions;
320f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
321f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
322f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the name of the pin function specified */
323f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev,
324f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham						unsigned selector)
325f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
326f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
327f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
328f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
329f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return priv->pmx_functions[selector].name;
330f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
331f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
332f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the groups associated for the specified function selector */
333f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev,
334f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		unsigned selector, const char * const **groups,
335f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		unsigned * const num_groups)
336f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
337f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
338f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
339f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
340f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*groups = priv->pmx_functions[selector].groups;
341f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*num_groups = priv->pmx_functions[selector].num_groups;
342f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
343f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
344f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
345f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* enable or disable a pinmux function */
346f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
347f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					unsigned group, bool enable)
348f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
349f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
350f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base;
351f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 function;
352f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
353f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
354f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
355f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	base = priv->reg_base;
356f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	function = priv->pmx_functions[selector].function;
357f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
358f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data = readl(base + GPIO_MUX);
359f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (enable)
360f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data |= (1 << function);
361f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	else
362f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data &= ~(1 << function);
363f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_MUX);
364f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
365f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
366f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* enable a specified pinmux by writing to registers */
36703e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleijstatic int exynos5440_pinmux_set_mux(struct pinctrl_dev *pctldev,
36803e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij				     unsigned selector,
36903e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij				     unsigned group)
370f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
371f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	exynos5440_pinmux_setup(pctldev, selector, group, true);
372f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
373f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
374f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
375f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/*
376f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * The calls to gpio_direction_output() and gpio_direction_input()
377f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
378f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * function called from the gpiolib interface).
379f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
380f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
381f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		struct pinctrl_gpio_range *range, unsigned offset, bool input)
382f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
383f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
384f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
385f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
386f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
387022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinmux_ops exynos5440_pinmux_ops = {
388f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_functions_count	= exynos5440_get_functions_count,
389f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_function_name	= exynos5440_pinmux_get_fname,
390f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.get_function_groups	= exynos5440_pinmux_get_groups,
39103e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij	.set_mux		= exynos5440_pinmux_set_mux,
392f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.gpio_set_direction	= exynos5440_pinmux_gpio_set_direction,
393f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
394f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
395f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* set the pin config settings for a specified pin */
396f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
39703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin				unsigned long *configs,
39803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin				unsigned num_configs)
399f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
400f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
401f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base;
40203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	enum pincfg_type cfg_type;
40303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	u32 cfg_value;
404f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
40503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	int i;
406f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
407f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
408f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	base = priv->reg_base;
409f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
41003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	for (i = 0; i < num_configs; i++) {
41103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		cfg_type = PINCFG_UNPACK_TYPE(configs[i]);
41203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		cfg_value = PINCFG_UNPACK_VALUE(configs[i]);
41303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin
41403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		switch (cfg_type) {
41503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		case PINCFG_TYPE_PUD:
41603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			/* first set pull enable/disable bit */
41703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_PE);
41803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
41903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			if (cfg_value)
42003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin				data |= (1 << pin);
42103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_PE);
42203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin
42303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			/* then set pull up/down bit */
42403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_PS);
42503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
42603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			if (cfg_value == 2)
42703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin				data |= (1 << pin);
42803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_PS);
42903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			break;
43003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin
43103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		case PINCFG_TYPE_DRV:
43203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			/* set the first bit of the drive strength */
43303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_DS0);
43403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
43503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data |= ((cfg_value & 1) << pin);
43603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_DS0);
43703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			cfg_value >>= 1;
43803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin
43903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			/* set the second bit of the driver strength */
44003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_DS1);
44103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
44203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data |= ((cfg_value & 1) << pin);
44303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_DS1);
44403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			break;
44503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		case PINCFG_TYPE_SKEW_RATE:
44603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_SR);
44703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
44803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data |= ((cfg_value & 1) << pin);
44903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_SR);
45003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			break;
45103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		case PINCFG_TYPE_INPUT_TYPE:
45203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data = readl(base + GPIO_TYPE);
45303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data &= ~(1 << pin);
45403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			data |= ((cfg_value & 1) << pin);
45503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			writel(data, base + GPIO_TYPE);
45603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			break;
45703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		default:
45803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			WARN_ON(1);
45903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			return -EINVAL;
46003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		}
46103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin	} /* for each config */
462f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
463f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
464f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
465f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
466f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* get the pin config settings for a specified pin */
467f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
468f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					unsigned long *config)
469f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
470f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
471f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base;
472f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
473f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
474f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
475f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
476f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	base = priv->reg_base;
477f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
478f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	switch (cfg_type) {
479f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	case PINCFG_TYPE_PUD:
480f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = readl(base + GPIO_PE);
481f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = (data >> pin) & 1;
482f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!data)
483f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			*config = 0;
484f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		else
485f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			*config = ((readl(base + GPIO_PS) >> pin) & 1) + 1;
486f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		break;
487f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	case PINCFG_TYPE_DRV:
488f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = readl(base + GPIO_DS0);
489f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = (data >> pin) & 1;
490f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		*config = data;
491f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = readl(base + GPIO_DS1);
492f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = (data >> pin) & 1;
493f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		*config |= (data << 1);
494f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		break;
495f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	case PINCFG_TYPE_SKEW_RATE:
496f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = readl(base + GPIO_SR);
497f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		*config = (data >> pin) & 1;
498f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		break;
499f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	case PINCFG_TYPE_INPUT_TYPE:
500f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data = readl(base + GPIO_TYPE);
501f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		*config = (data >> pin) & 1;
502f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		break;
503f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	default:
504f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		WARN_ON(1);
505f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
506f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
507f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
508f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
509f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
510f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
511f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* set the pin config settings for a specified pin group */
512f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
51303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			unsigned group, unsigned long *configs,
51403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin			unsigned num_configs)
515f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
516f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
517f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const unsigned int *pins;
518f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned int cnt;
519f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
520f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
521f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pins = priv->pin_groups[group].pins;
522f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
523f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++)
52403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin		exynos5440_pinconf_set(pctldev, pins[cnt], configs,
52503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin				       num_configs);
526f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
527f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
528f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
529f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
530f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* get the pin config settings for a specified pin group */
531f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
532f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				unsigned int group, unsigned long *config)
533f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
534f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
535f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	const unsigned int *pins;
536f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
537f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv = pinctrl_dev_get_drvdata(pctldev);
538f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pins = priv->pin_groups[group].pins;
539f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	exynos5440_pinconf_get(pctldev, pins[0], config);
540f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
541f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
542f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
543f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
544022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinconf_ops exynos5440_pinconf_ops = {
545f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.pin_config_get		= exynos5440_pinconf_get,
546f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.pin_config_set		= exynos5440_pinconf_set,
547f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.pin_config_group_get	= exynos5440_pinconf_group_get,
548f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.pin_config_group_set	= exynos5440_pinconf_group_set,
549f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
550f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
551f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_set callback function */
552f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
553f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
554f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
555f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base = priv->reg_base;
556f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
557f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
558f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data = readl(base + GPIO_VAL);
559f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data &= ~(1 << offset);
560f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (value)
561f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		data |= 1 << offset;
562f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_VAL);
563f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
564f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
565f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_get callback function */
566f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset)
567f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
568f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
569f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base = priv->reg_base;
570f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
571f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
572f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data = readl(base + GPIO_IN);
573f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data >>= offset;
574f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data &= 1;
575f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return data;
576f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
577f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
578f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_direction_input callback function */
579f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
580f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
581f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
582f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base = priv->reg_base;
583f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
584f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
585f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* first disable the data output enable on this pin */
586f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data = readl(base + GPIO_OE);
587f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data &= ~(1 << offset);
588f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_OE);
589f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
590f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* now enable input on this pin */
591f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data =  readl(base + GPIO_IE);
592f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data |= 1 << offset;
593f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_IE);
594f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
595f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
596f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
597f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_direction_output callback function */
598f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
599f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham							int value)
600f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
601f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
602f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	void __iomem *base = priv->reg_base;
603f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	u32 data;
604f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
605f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	exynos5440_gpio_set(gc, offset, value);
606f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
607f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* first disable the data input enable on this pin */
608f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data = readl(base + GPIO_IE);
609f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data &= ~(1 << offset);
610f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_IE);
611f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
612f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* now enable output on this pin */
613f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data =  readl(base + GPIO_OE);
614f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	data |= 1 << offset;
615f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	writel(data, base + GPIO_OE);
616f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
617f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
618f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
6198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* gpiolib gpio_to_irq callback function */
6208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
6218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
6228dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
6238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	unsigned int virq;
6248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
6258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (offset < 16 || offset > 23)
6268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return -ENXIO;
6278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
6288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (!priv->irq_domain)
6298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return -ENXIO;
6308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
6318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	virq = irq_create_mapping(priv->irq_domain, offset - 16);
6328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	return virq ? : -ENXIO;
6338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
6348dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
635f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
636312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
637f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			struct device_node *cfg_np, unsigned int **pin_list,
638f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			unsigned int *npins)
639f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
640f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device *dev = &pdev->dev;
641f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct property *prop;
642f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
643f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL);
644f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!prop)
645f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOENT;
646f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
647f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*npins = prop->length / sizeof(unsigned long);
648f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!*npins) {
649f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "invalid pin list in %s node", cfg_np->name);
650f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
651f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
652f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
653f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	*pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL);
654f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!*pin_list) {
655f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "failed to allocate memory for pin list\n");
656f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
657f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
658f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
659f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins",
660f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			*pin_list, *npins);
661f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
662f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
663f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/*
664f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Parse the information about all the available pin groups and pin functions
665f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * from device node of the pin-controller.
666f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */
667312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
668f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				struct exynos5440_pinctrl_priv_data *priv)
669f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
670f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device *dev = &pdev->dev;
671f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device_node *dev_np = dev->of_node;
672f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device_node *cfg_np;
673f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pin_group *groups, *grp;
674f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pmx_func *functions, *func;
675f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned *pin_list;
676f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	unsigned int npins, grp_cnt, func_idx = 0;
677f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	char *gname, *fname;
678f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int ret;
679f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
680f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grp_cnt = of_get_child_count(dev_np);
681f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!grp_cnt)
682f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
683f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
684f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL);
685f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!groups) {
686f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "failed allocate memory for ping group list\n");
687f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
688f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
689f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grp = groups;
690f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
691f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL);
692f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!functions) {
693f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "failed to allocate memory for function list\n");
694f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
695f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
696f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	func = functions;
697f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
698f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/*
699f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * Iterate over all the child nodes of the pin controller node
700f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * and create pin groups and pin function lists.
701f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 */
702f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for_each_child_of_node(dev_np, cfg_np) {
703f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		u32 function;
704f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
705f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np,
706f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					&pin_list, &npins);
707f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham		if (ret) {
708f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham			gname = NULL;
709f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham			goto skip_to_pin_function;
710f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham		}
711f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
712f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		/* derive pin group name from the node name */
713f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
714f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					GFP_KERNEL);
715f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!gname) {
716f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			dev_err(dev, "failed to alloc memory for group name\n");
717f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			return -ENOMEM;
718f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		}
71979bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham		snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
72079bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham			 GROUP_SUFFIX);
721f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
722f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		grp->name = gname;
723f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		grp->pins = pin_list;
724f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		grp->num_pins = npins;
725f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		grp++;
726f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
727f9819739427e6049d2d318743a4a25817018afd4Thomas Abrahamskip_to_pin_function:
728f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function",
729f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham						&function);
730f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (ret)
731f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			continue;
732f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
733f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		/* derive function name from the node name */
734f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN,
735f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					GFP_KERNEL);
736f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!fname) {
737f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			dev_err(dev, "failed to alloc memory for func name\n");
738f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			return -ENOMEM;
739f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		}
74079bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham		snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
74179bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham			 FUNCTION_SUFFIX);
742f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
743f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func->name = fname;
744f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
745f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		if (!func->groups) {
746f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			dev_err(dev, "failed to alloc memory for group list "
747f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					"in pin function");
748f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham			return -ENOMEM;
749f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		}
750f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func->groups[0] = gname;
751f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham		func->num_groups = gname ? 1 : 0;
752f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func->function = function;
753f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func++;
754f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		func_idx++;
755f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
756f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
757f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv->pin_groups = groups;
758f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv->nr_groups = grp_cnt;
759f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv->pmx_functions = functions;
760f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv->nr_functions = func_idx;
761f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
762f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
763f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
764f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* register the pinctrl interface with the pinctrl subsystem */
765312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_register(struct platform_device *pdev,
766f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				struct exynos5440_pinctrl_priv_data *priv)
767f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
768f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device *dev = &pdev->dev;
769f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct pinctrl_desc *ctrldesc;
770f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct pinctrl_dev *pctl_dev;
771f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct pinctrl_pin_desc *pindesc, *pdesc;
772f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct pinctrl_gpio_range grange;
773f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	char *pin_names;
774f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int pin, ret;
775f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
776f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL);
777f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!ctrldesc) {
778f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "could not allocate memory for pinctrl desc\n");
779f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
780f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
781f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
782f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->name = "exynos5440-pinctrl";
783f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->owner = THIS_MODULE;
784f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->pctlops = &exynos5440_pctrl_ops;
785f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->pmxops = &exynos5440_pinmux_ops;
786f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->confops = &exynos5440_pinconf_ops;
787f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
788f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
789f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				EXYNOS5440_MAX_PINS, GFP_KERNEL);
790f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!pindesc) {
791f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
792f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
793f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
794f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->pins = pindesc;
795f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ctrldesc->npins = EXYNOS5440_MAX_PINS;
796f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
797f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* dynamically populate the pin number and pin name for pindesc */
798f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
799f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		pdesc->number = pin;
800f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
801f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/*
802f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * allocate space for storing the dynamically generated names for all
803f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 * the pins which belong to this pin-controller.
804f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	 */
805f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
806f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					ctrldesc->npins, GFP_KERNEL);
807f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!pin_names) {
808f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(&pdev->dev, "mem alloc for pin names failed\n");
809f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
810f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
811f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
812f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	/* for each pin, set the name of the pin */
813f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	for (pin = 0; pin < ctrldesc->npins; pin++) {
81479bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham		snprintf(pin_names, 6, "gpio%02d", pin);
815f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		pdesc = pindesc + pin;
816f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		pdesc->name = pin_names;
817f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		pin_names += PIN_NAME_LENGTH;
818f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
819f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
820f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ret = exynos5440_pinctrl_parse_dt(pdev, priv);
821f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (ret)
822f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return ret;
823f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
824f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv);
825f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!pctl_dev) {
826f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(&pdev->dev, "could not register pinctrl driver\n");
827f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -EINVAL;
828f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
829f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
830f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grange.name = "exynos5440-pctrl-gpio-range";
831f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grange.id = 0;
832f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grange.base = 0;
833f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grange.npins = EXYNOS5440_MAX_PINS;
834f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	grange.gc = priv->gc;
835f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	pinctrl_add_gpio_range(pctl_dev, &grange);
836f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
837f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
838f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
839f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* register the gpiolib interface with the gpiolib subsystem */
840312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_gpiolib_register(struct platform_device *pdev,
841f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				struct exynos5440_pinctrl_priv_data *priv)
842f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
843f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct gpio_chip *gc;
844f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int ret;
845f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
846f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
847f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!gc) {
848f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n");
849f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
850f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
851f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
852f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	priv->gc = gc;
853f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->base = 0;
854f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->ngpio = EXYNOS5440_MAX_PINS;
855f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->dev = &pdev->dev;
856f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->set = exynos5440_gpio_set;
857f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->get = exynos5440_gpio_get;
858f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->direction_input = exynos5440_gpio_direction_input;
859f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->direction_output = exynos5440_gpio_direction_output;
8608dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	gc->to_irq = exynos5440_gpio_to_irq;
861f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->label = "gpiolib-exynos5440";
862f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	gc->owner = THIS_MODULE;
863f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ret = gpiochip_add(gc);
864f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (ret) {
865f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(&pdev->dev, "failed to register gpio_chip %s, error "
866f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham					"code: %d\n", gc->label, ret);
867f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return ret;
868f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
869f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
870f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
871f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
872f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
873f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* unregister the gpiolib interface with the gpiolib subsystem */
874312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_gpiolib_unregister(struct platform_device *pdev,
875f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham				struct exynos5440_pinctrl_priv_data *priv)
876f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
8772fcea6cecbc965b4e02a39537d9d939f5251bbbdLinus Walleij	gpiochip_remove(priv->gc);
878f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
879f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
880f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
8818dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
8828dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
8838dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data *d;
8848dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	unsigned long gpio_int;
8858dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
8868dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	d = irq_data_get_irq_chip_data(irqd);
8878dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	gpio_int = readl(d->reg_base + GPIO_INT);
8888dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	gpio_int |= 1 << irqd->hwirq;
8898dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	writel(gpio_int, d->reg_base + GPIO_INT);
8908dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
8918dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
8928dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic void exynos5440_gpio_irq_mask(struct irq_data *irqd)
8938dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
8948dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data *d;
8958dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	unsigned long gpio_int;
8968dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
8978dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	d = irq_data_get_irq_chip_data(irqd);
8988dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	gpio_int = readl(d->reg_base + GPIO_INT);
8998dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	gpio_int &= ~(1 << irqd->hwirq);
9008dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	writel(gpio_int, d->reg_base + GPIO_INT);
9018dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
9028dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9038dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* irq_chip for gpio interrupts */
9048dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic struct irq_chip exynos5440_gpio_irq_chip = {
9058dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	.name		= "exynos5440_gpio_irq_chip",
9068dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	.irq_unmask	= exynos5440_gpio_irq_unmask,
9078dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	.irq_mask	= exynos5440_gpio_irq_mask,
9088dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham};
9098dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9108dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* interrupt handler for GPIO interrupts 0..7 */
9118dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic irqreturn_t exynos5440_gpio_irq(int irq, void *data)
9128dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
9138dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_gpio_intr_data *intd = data;
9148dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data *d = intd->priv;
9158dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	int virq;
9168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9178dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
9188dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (!virq)
9198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return IRQ_NONE;
9208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	generic_handle_irq(virq);
9218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	return IRQ_HANDLED;
9228dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
9238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
9258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham					irq_hw_number_t hw)
9268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
9278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_pinctrl_priv_data *d = h->host_data;
9288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	irq_set_chip_data(virq, d);
9308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
9318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham					handle_level_irq);
9328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	set_irq_flags(virq, IRQF_VALID);
9338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	return 0;
9348dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
9358dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9368dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* irq domain callbacks for gpio interrupt controller */
9378dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
9388dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	.map	= exynos5440_gpio_irq_map,
9398dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	.xlate	= irq_domain_xlate_twocell,
9408dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham};
9418dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9428dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* setup handling of gpio interrupts */
9438dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_irq_init(struct platform_device *pdev,
9448dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham				struct exynos5440_pinctrl_priv_data *priv)
9458dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{
9468dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct device *dev = &pdev->dev;
9478dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	struct exynos5440_gpio_intr_data *intd;
9488dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	int i, irq, ret;
9498dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9508dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
9518dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham					GFP_KERNEL);
9528dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (!intd) {
9538dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		dev_err(dev, "failed to allocate memory for gpio intr data\n");
9548dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return -ENOMEM;
9558dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	}
9568dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9578dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
9588dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		irq = irq_of_parse_and_map(dev->of_node, i);
9598dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		if (irq <= 0) {
9608dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham			dev_err(dev, "irq parsing failed\n");
9618dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham			return -EINVAL;
9628dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		}
9638dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9648dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		intd->gpio_int = i;
9658dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		intd->priv = priv;
9668dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
9678dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham					0, dev_name(dev), intd++);
9688dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		if (ret) {
9698dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham			dev_err(dev, "irq request failed\n");
9708dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham			return -ENXIO;
9718dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		}
9728dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	}
9738dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9748dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	priv->irq_domain = irq_domain_add_linear(dev->of_node,
9758dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham				EXYNOS5440_MAX_GPIO_INT,
9768dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham				&exynos5440_gpio_irqd_ops, priv);
9778dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (!priv->irq_domain) {
9788dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		dev_err(dev, "failed to create irq domain\n");
9798dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return -ENXIO;
9808dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	}
9818dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
9828dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	return 0;
9838dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}
9848dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
985150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanstatic int exynos5440_pinctrl_probe(struct platform_device *pdev)
986f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
987f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct device *dev = &pdev->dev;
988f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct exynos5440_pinctrl_priv_data *priv;
989f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	struct resource *res;
990f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	int ret;
991f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
992f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!dev->of_node) {
993f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "device tree node not found\n");
994f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENODEV;
995f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
996f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
997c078d78aa96ceafab7379b6a50e92d9d8e2f97b5Wei Yongjun	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
998f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (!priv) {
999f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		dev_err(dev, "could not allocate memory for private data\n");
1000f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return -ENOMEM;
1001f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
1002f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1003f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
10049e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding	priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
10059e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding	if (IS_ERR(priv->reg_base))
10069e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding		return PTR_ERR(priv->reg_base);
1007f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1008f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ret = exynos5440_gpiolib_register(pdev, priv);
1009f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (ret)
1010f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return ret;
1011f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1012f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	ret = exynos5440_pinctrl_register(pdev, priv);
1013f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	if (ret) {
1014f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		exynos5440_gpiolib_unregister(pdev, priv);
1015f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		return ret;
10168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	}
10178dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham
10188dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	ret = exynos5440_gpio_irq_init(pdev, priv);
10198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham	if (ret) {
10208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		dev_err(dev, "failed to setup gpio interrupts\n");
10218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham		return ret;
1022f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	}
1023f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1024f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	platform_set_drvdata(pdev, priv);
1025f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
1026f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return 0;
1027f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
1028f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1029f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const struct of_device_id exynos5440_pinctrl_dt_match[] = {
1030f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{ .compatible = "samsung,exynos5440-pinctrl" },
1031f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	{},
1032f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
1033f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match);
1034f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1035f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic struct platform_driver exynos5440_pinctrl_driver = {
1036f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.probe		= exynos5440_pinctrl_probe,
1037f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	.driver = {
1038f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		.name	= "exynos5440-pinctrl",
1039f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham		.owner	= THIS_MODULE,
1040606fca94f7bd156d37be1b38b3aded3ede5994b1Sachin Kamat		.of_match_table = exynos5440_pinctrl_dt_match,
1041f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	},
1042f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham};
1043f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1044f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int __init exynos5440_pinctrl_drv_register(void)
1045f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
1046f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	return platform_driver_register(&exynos5440_pinctrl_driver);
1047f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
1048f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahampostcore_initcall(exynos5440_pinctrl_drv_register);
1049f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1050f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void __exit exynos5440_pinctrl_drv_unregister(void)
1051f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{
1052f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham	platform_driver_unregister(&exynos5440_pinctrl_driver);
1053f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}
1054f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahammodule_exit(exynos5440_pinctrl_drv_unregister);
1055f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham
1056f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
1057f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver");
1058f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_LICENSE("GPL v2");
1059