1d3e51161SHeiko Stübner /*
2d3e51161SHeiko Stübner  * Pinctrl driver for Rockchip SoCs
3d3e51161SHeiko Stübner  *
4d3e51161SHeiko Stübner  * Copyright (c) 2013 MundoReader S.L.
5d3e51161SHeiko Stübner  * Author: Heiko Stuebner <heiko@sntech.de>
6d3e51161SHeiko Stübner  *
7d3e51161SHeiko Stübner  * With some ideas taken from pinctrl-samsung:
8d3e51161SHeiko Stübner  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
9d3e51161SHeiko Stübner  *		http://www.samsung.com
10d3e51161SHeiko Stübner  * Copyright (c) 2012 Linaro Ltd
11d3e51161SHeiko Stübner  *		http://www.linaro.org
12d3e51161SHeiko Stübner  *
13d3e51161SHeiko Stübner  * and pinctrl-at91:
14d3e51161SHeiko Stübner  * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
15d3e51161SHeiko Stübner  *
16d3e51161SHeiko Stübner  * This program is free software; you can redistribute it and/or modify
17d3e51161SHeiko Stübner  * it under the terms of the GNU General Public License version 2 as published
18d3e51161SHeiko Stübner  * by the Free Software Foundation.
19d3e51161SHeiko Stübner  *
20d3e51161SHeiko Stübner  * This program is distributed in the hope that it will be useful,
21d3e51161SHeiko Stübner  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22d3e51161SHeiko Stübner  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23d3e51161SHeiko Stübner  * GNU General Public License for more details.
24d3e51161SHeiko Stübner  */
25d3e51161SHeiko Stübner 
262f436204SPaul Gortmaker #include <linux/init.h>
27d3e51161SHeiko Stübner #include <linux/platform_device.h>
28d3e51161SHeiko Stübner #include <linux/io.h>
29d3e51161SHeiko Stübner #include <linux/bitops.h>
30d3e51161SHeiko Stübner #include <linux/gpio.h>
31d3e51161SHeiko Stübner #include <linux/of_address.h>
32d3e51161SHeiko Stübner #include <linux/of_irq.h>
33d3e51161SHeiko Stübner #include <linux/pinctrl/machine.h>
34d3e51161SHeiko Stübner #include <linux/pinctrl/pinconf.h>
35d3e51161SHeiko Stübner #include <linux/pinctrl/pinctrl.h>
36d3e51161SHeiko Stübner #include <linux/pinctrl/pinmux.h>
37d3e51161SHeiko Stübner #include <linux/pinctrl/pinconf-generic.h>
38d3e51161SHeiko Stübner #include <linux/irqchip/chained_irq.h>
397e865abbSHeiko Stübner #include <linux/clk.h>
40751a99abSHeiko Stübner #include <linux/regmap.h>
4114dee867SHeiko Stübner #include <linux/mfd/syscon.h>
42d3e51161SHeiko Stübner #include <dt-bindings/pinctrl/rockchip.h>
43d3e51161SHeiko Stübner 
44d3e51161SHeiko Stübner #include "core.h"
45d3e51161SHeiko Stübner #include "pinconf.h"
46d3e51161SHeiko Stübner 
47d3e51161SHeiko Stübner /* GPIO control registers */
48d3e51161SHeiko Stübner #define GPIO_SWPORT_DR		0x00
49d3e51161SHeiko Stübner #define GPIO_SWPORT_DDR		0x04
50d3e51161SHeiko Stübner #define GPIO_INTEN		0x30
51d3e51161SHeiko Stübner #define GPIO_INTMASK		0x34
52d3e51161SHeiko Stübner #define GPIO_INTTYPE_LEVEL	0x38
53d3e51161SHeiko Stübner #define GPIO_INT_POLARITY	0x3c
54d3e51161SHeiko Stübner #define GPIO_INT_STATUS		0x40
55d3e51161SHeiko Stübner #define GPIO_INT_RAWSTATUS	0x44
56d3e51161SHeiko Stübner #define GPIO_DEBOUNCE		0x48
57d3e51161SHeiko Stübner #define GPIO_PORTS_EOI		0x4c
58d3e51161SHeiko Stübner #define GPIO_EXT_PORT		0x50
59d3e51161SHeiko Stübner #define GPIO_LS_SYNC		0x60
60d3e51161SHeiko Stübner 
61a282926dSHeiko Stübner enum rockchip_pinctrl_type {
62b9c6dcabSAndy Yan 	RV1108,
63a282926dSHeiko Stübner 	RK2928,
64a282926dSHeiko Stübner 	RK3066B,
65d23c66dfSDavid Wu 	RK3128,
66a282926dSHeiko Stübner 	RK3188,
6766d750e1SHeiko Stübner 	RK3288,
68daecdc66SHeiko Stübner 	RK3368,
69b6c23275SDavid Wu 	RK3399,
70a282926dSHeiko Stübner };
71a282926dSHeiko Stübner 
72fc72c923SHeiko Stübner /**
73fc72c923SHeiko Stübner  * Encode variants of iomux registers into a type variable
74fc72c923SHeiko Stübner  */
75fc72c923SHeiko Stübner #define IOMUX_GPIO_ONLY		BIT(0)
7603716e1dSHeiko Stübner #define IOMUX_WIDTH_4BIT	BIT(1)
7795ec8ae4SHeiko Stübner #define IOMUX_SOURCE_PMU	BIT(2)
7862f49226SHeiko Stübner #define IOMUX_UNROUTED		BIT(3)
798b6c6f93Sdavid.wu #define IOMUX_WIDTH_3BIT	BIT(4)
80fc72c923SHeiko Stübner 
81fc72c923SHeiko Stübner /**
82fc72c923SHeiko Stübner  * @type: iomux variant using IOMUX_* constants
836bc0d121SHeiko Stübner  * @offset: if initialized to -1 it will be autocalculated, by specifying
846bc0d121SHeiko Stübner  *	    an initial offset value the relevant source offset can be reset
856bc0d121SHeiko Stübner  *	    to a new value for autocalculating the following iomux registers.
86fc72c923SHeiko Stübner  */
87fc72c923SHeiko Stübner struct rockchip_iomux {
88fc72c923SHeiko Stübner 	int				type;
896bc0d121SHeiko Stübner 	int				offset;
9065fca613SHeiko Stübner };
9165fca613SHeiko Stübner 
92d3e51161SHeiko Stübner /**
93b6c23275SDavid Wu  * enum type index corresponding to rockchip_perpin_drv_list arrays index.
94b6c23275SDavid Wu  */
95b6c23275SDavid Wu enum rockchip_pin_drv_type {
96b6c23275SDavid Wu 	DRV_TYPE_IO_DEFAULT = 0,
97b6c23275SDavid Wu 	DRV_TYPE_IO_1V8_OR_3V0,
98b6c23275SDavid Wu 	DRV_TYPE_IO_1V8_ONLY,
99b6c23275SDavid Wu 	DRV_TYPE_IO_1V8_3V0_AUTO,
100b6c23275SDavid Wu 	DRV_TYPE_IO_3V3_ONLY,
101b6c23275SDavid Wu 	DRV_TYPE_MAX
102b6c23275SDavid Wu };
103b6c23275SDavid Wu 
104b6c23275SDavid Wu /**
1053ba6767aSDavid Wu  * enum type index corresponding to rockchip_pull_list arrays index.
1063ba6767aSDavid Wu  */
1073ba6767aSDavid Wu enum rockchip_pin_pull_type {
1083ba6767aSDavid Wu 	PULL_TYPE_IO_DEFAULT = 0,
1093ba6767aSDavid Wu 	PULL_TYPE_IO_1V8_ONLY,
1103ba6767aSDavid Wu 	PULL_TYPE_MAX
1113ba6767aSDavid Wu };
1123ba6767aSDavid Wu 
1133ba6767aSDavid Wu /**
114b6c23275SDavid Wu  * @drv_type: drive strength variant using rockchip_perpin_drv_type
115b6c23275SDavid Wu  * @offset: if initialized to -1 it will be autocalculated, by specifying
116b6c23275SDavid Wu  *	    an initial offset value the relevant source offset can be reset
117b6c23275SDavid Wu  *	    to a new value for autocalculating the following drive strength
118b6c23275SDavid Wu  *	    registers. if used chips own cal_drv func instead to calculate
119b6c23275SDavid Wu  *	    registers offset, the variant could be ignored.
120b6c23275SDavid Wu  */
121b6c23275SDavid Wu struct rockchip_drv {
122b6c23275SDavid Wu 	enum rockchip_pin_drv_type	drv_type;
123b6c23275SDavid Wu 	int				offset;
124b6c23275SDavid Wu };
125b6c23275SDavid Wu 
126b6c23275SDavid Wu /**
127d3e51161SHeiko Stübner  * @reg_base: register base of the gpio bank
1286ca5274dSHeiko Stübner  * @reg_pull: optional separate register for additional pull settings
129d3e51161SHeiko Stübner  * @clk: clock of the gpio bank
130d3e51161SHeiko Stübner  * @irq: interrupt of the gpio bank
1315ae0c7adSDoug Anderson  * @saved_masks: Saved content of GPIO_INTEN at suspend time.
132d3e51161SHeiko Stübner  * @pin_base: first pin number
133d3e51161SHeiko Stübner  * @nr_pins: number of pins in this bank
134d3e51161SHeiko Stübner  * @name: name of the bank
135d3e51161SHeiko Stübner  * @bank_num: number of the bank, to account for holes
136fc72c923SHeiko Stübner  * @iomux: array describing the 4 iomux sources of the bank
137b6c23275SDavid Wu  * @drv: array describing the 4 drive strength sources of the bank
1383ba6767aSDavid Wu  * @pull_type: array describing the 4 pull type sources of the bank
139d3e51161SHeiko Stübner  * @valid: are all necessary informations present
140d3e51161SHeiko Stübner  * @of_node: dt node of this bank
141d3e51161SHeiko Stübner  * @drvdata: common pinctrl basedata
142d3e51161SHeiko Stübner  * @domain: irqdomain of the gpio bank
143d3e51161SHeiko Stübner  * @gpio_chip: gpiolib chip
144d3e51161SHeiko Stübner  * @grange: gpio range
145d3e51161SHeiko Stübner  * @slock: spinlock for the gpio bank
146bd35b9bfSDavid Wu  * @route_mask: bits describing the routing pins of per bank
147d3e51161SHeiko Stübner  */
148d3e51161SHeiko Stübner struct rockchip_pin_bank {
149d3e51161SHeiko Stübner 	void __iomem			*reg_base;
150751a99abSHeiko Stübner 	struct regmap			*regmap_pull;
151d3e51161SHeiko Stübner 	struct clk			*clk;
152d3e51161SHeiko Stübner 	int				irq;
1535ae0c7adSDoug Anderson 	u32				saved_masks;
154d3e51161SHeiko Stübner 	u32				pin_base;
155d3e51161SHeiko Stübner 	u8				nr_pins;
156d3e51161SHeiko Stübner 	char				*name;
157d3e51161SHeiko Stübner 	u8				bank_num;
158fc72c923SHeiko Stübner 	struct rockchip_iomux		iomux[4];
159b6c23275SDavid Wu 	struct rockchip_drv		drv[4];
1603ba6767aSDavid Wu 	enum rockchip_pin_pull_type	pull_type[4];
161d3e51161SHeiko Stübner 	bool				valid;
162d3e51161SHeiko Stübner 	struct device_node		*of_node;
163d3e51161SHeiko Stübner 	struct rockchip_pinctrl		*drvdata;
164d3e51161SHeiko Stübner 	struct irq_domain		*domain;
165d3e51161SHeiko Stübner 	struct gpio_chip		gpio_chip;
166d3e51161SHeiko Stübner 	struct pinctrl_gpio_range	grange;
16770b7aa7aSJohn Keeping 	raw_spinlock_t			slock;
1685a927501SHeiko Stübner 	u32				toggle_edge_mode;
169c04c3fa6SDavid Wu 	u32				recalced_mask;
170bd35b9bfSDavid Wu 	u32				route_mask;
171d3e51161SHeiko Stübner };
172d3e51161SHeiko Stübner 
173d3e51161SHeiko Stübner #define PIN_BANK(id, pins, label)			\
174d3e51161SHeiko Stübner 	{						\
175d3e51161SHeiko Stübner 		.bank_num	= id,			\
176d3e51161SHeiko Stübner 		.nr_pins	= pins,			\
177d3e51161SHeiko Stübner 		.name		= label,		\
1786bc0d121SHeiko Stübner 		.iomux		= {			\
1796bc0d121SHeiko Stübner 			{ .offset = -1 },		\
1806bc0d121SHeiko Stübner 			{ .offset = -1 },		\
1816bc0d121SHeiko Stübner 			{ .offset = -1 },		\
1826bc0d121SHeiko Stübner 			{ .offset = -1 },		\
1836bc0d121SHeiko Stübner 		},					\
184d3e51161SHeiko Stübner 	}
185d3e51161SHeiko Stübner 
186fc72c923SHeiko Stübner #define PIN_BANK_IOMUX_FLAGS(id, pins, label, iom0, iom1, iom2, iom3)	\
187fc72c923SHeiko Stübner 	{								\
188fc72c923SHeiko Stübner 		.bank_num	= id,					\
189fc72c923SHeiko Stübner 		.nr_pins	= pins,					\
190fc72c923SHeiko Stübner 		.name		= label,				\
191fc72c923SHeiko Stübner 		.iomux		= {					\
1926bc0d121SHeiko Stübner 			{ .type = iom0, .offset = -1 },			\
1936bc0d121SHeiko Stübner 			{ .type = iom1, .offset = -1 },			\
1946bc0d121SHeiko Stübner 			{ .type = iom2, .offset = -1 },			\
1956bc0d121SHeiko Stübner 			{ .type = iom3, .offset = -1 },			\
196fc72c923SHeiko Stübner 		},							\
197fc72c923SHeiko Stübner 	}
198fc72c923SHeiko Stübner 
199b6c23275SDavid Wu #define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \
200b6c23275SDavid Wu 	{								\
201b6c23275SDavid Wu 		.bank_num	= id,					\
202b6c23275SDavid Wu 		.nr_pins	= pins,					\
203b6c23275SDavid Wu 		.name		= label,				\
204b6c23275SDavid Wu 		.iomux		= {					\
205b6c23275SDavid Wu 			{ .offset = -1 },				\
206b6c23275SDavid Wu 			{ .offset = -1 },				\
207b6c23275SDavid Wu 			{ .offset = -1 },				\
208b6c23275SDavid Wu 			{ .offset = -1 },				\
209b6c23275SDavid Wu 		},							\
210b6c23275SDavid Wu 		.drv		= {					\
211b6c23275SDavid Wu 			{ .drv_type = type0, .offset = -1 },		\
212b6c23275SDavid Wu 			{ .drv_type = type1, .offset = -1 },		\
213b6c23275SDavid Wu 			{ .drv_type = type2, .offset = -1 },		\
214b6c23275SDavid Wu 			{ .drv_type = type3, .offset = -1 },		\
215b6c23275SDavid Wu 		},							\
216b6c23275SDavid Wu 	}
217b6c23275SDavid Wu 
2183ba6767aSDavid Wu #define PIN_BANK_DRV_FLAGS_PULL_FLAGS(id, pins, label, drv0, drv1,	\
2193ba6767aSDavid Wu 				      drv2, drv3, pull0, pull1,		\
2203ba6767aSDavid Wu 				      pull2, pull3)			\
2213ba6767aSDavid Wu 	{								\
2223ba6767aSDavid Wu 		.bank_num	= id,					\
2233ba6767aSDavid Wu 		.nr_pins	= pins,					\
2243ba6767aSDavid Wu 		.name		= label,				\
2253ba6767aSDavid Wu 		.iomux		= {					\
2263ba6767aSDavid Wu 			{ .offset = -1 },				\
2273ba6767aSDavid Wu 			{ .offset = -1 },				\
2283ba6767aSDavid Wu 			{ .offset = -1 },				\
2293ba6767aSDavid Wu 			{ .offset = -1 },				\
2303ba6767aSDavid Wu 		},							\
2313ba6767aSDavid Wu 		.drv		= {					\
2323ba6767aSDavid Wu 			{ .drv_type = drv0, .offset = -1 },		\
2333ba6767aSDavid Wu 			{ .drv_type = drv1, .offset = -1 },		\
2343ba6767aSDavid Wu 			{ .drv_type = drv2, .offset = -1 },		\
2353ba6767aSDavid Wu 			{ .drv_type = drv3, .offset = -1 },		\
2363ba6767aSDavid Wu 		},							\
2373ba6767aSDavid Wu 		.pull_type[0] = pull0,					\
2383ba6767aSDavid Wu 		.pull_type[1] = pull1,					\
2393ba6767aSDavid Wu 		.pull_type[2] = pull2,					\
2403ba6767aSDavid Wu 		.pull_type[3] = pull3,					\
2413ba6767aSDavid Wu 	}
2423ba6767aSDavid Wu 
243b6c23275SDavid Wu #define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1,	\
244b6c23275SDavid Wu 					iom2, iom3, drv0, drv1, drv2,	\
245b6c23275SDavid Wu 					drv3, offset0, offset1,		\
246b6c23275SDavid Wu 					offset2, offset3)		\
247b6c23275SDavid Wu 	{								\
248b6c23275SDavid Wu 		.bank_num	= id,					\
249b6c23275SDavid Wu 		.nr_pins	= pins,					\
250b6c23275SDavid Wu 		.name		= label,				\
251b6c23275SDavid Wu 		.iomux		= {					\
252b6c23275SDavid Wu 			{ .type = iom0, .offset = -1 },			\
253b6c23275SDavid Wu 			{ .type = iom1, .offset = -1 },			\
254b6c23275SDavid Wu 			{ .type = iom2, .offset = -1 },			\
255b6c23275SDavid Wu 			{ .type = iom3, .offset = -1 },			\
256b6c23275SDavid Wu 		},							\
257b6c23275SDavid Wu 		.drv		= {					\
258b6c23275SDavid Wu 			{ .drv_type = drv0, .offset = offset0 },	\
259b6c23275SDavid Wu 			{ .drv_type = drv1, .offset = offset1 },	\
260b6c23275SDavid Wu 			{ .drv_type = drv2, .offset = offset2 },	\
261b6c23275SDavid Wu 			{ .drv_type = drv3, .offset = offset3 },	\
262b6c23275SDavid Wu 		},							\
263b6c23275SDavid Wu 	}
264b6c23275SDavid Wu 
2653ba6767aSDavid Wu #define PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(id, pins,	\
2663ba6767aSDavid Wu 					      label, iom0, iom1, iom2,  \
2673ba6767aSDavid Wu 					      iom3, drv0, drv1, drv2,   \
2683ba6767aSDavid Wu 					      drv3, offset0, offset1,   \
2693ba6767aSDavid Wu 					      offset2, offset3, pull0,  \
2703ba6767aSDavid Wu 					      pull1, pull2, pull3)	\
2713ba6767aSDavid Wu 	{								\
2723ba6767aSDavid Wu 		.bank_num	= id,					\
2733ba6767aSDavid Wu 		.nr_pins	= pins,					\
2743ba6767aSDavid Wu 		.name		= label,				\
2753ba6767aSDavid Wu 		.iomux		= {					\
2763ba6767aSDavid Wu 			{ .type = iom0, .offset = -1 },			\
2773ba6767aSDavid Wu 			{ .type = iom1, .offset = -1 },			\
2783ba6767aSDavid Wu 			{ .type = iom2, .offset = -1 },			\
2793ba6767aSDavid Wu 			{ .type = iom3, .offset = -1 },			\
2803ba6767aSDavid Wu 		},							\
2813ba6767aSDavid Wu 		.drv		= {					\
2823ba6767aSDavid Wu 			{ .drv_type = drv0, .offset = offset0 },	\
2833ba6767aSDavid Wu 			{ .drv_type = drv1, .offset = offset1 },	\
2843ba6767aSDavid Wu 			{ .drv_type = drv2, .offset = offset2 },	\
2853ba6767aSDavid Wu 			{ .drv_type = drv3, .offset = offset3 },	\
2863ba6767aSDavid Wu 		},							\
2873ba6767aSDavid Wu 		.pull_type[0] = pull0,					\
2883ba6767aSDavid Wu 		.pull_type[1] = pull1,					\
2893ba6767aSDavid Wu 		.pull_type[2] = pull2,					\
2903ba6767aSDavid Wu 		.pull_type[3] = pull3,					\
2913ba6767aSDavid Wu 	}
2923ba6767aSDavid Wu 
293d3e51161SHeiko Stübner /**
294bd35b9bfSDavid Wu  * struct rockchip_mux_recalced_data: represent a pin iomux data.
295c04c3fa6SDavid Wu  * @num: bank number.
296c04c3fa6SDavid Wu  * @pin: pin number.
297c04c3fa6SDavid Wu  * @bit: index at register.
298c04c3fa6SDavid Wu  * @reg: register offset.
299c04c3fa6SDavid Wu  * @mask: mask bit
300c04c3fa6SDavid Wu  */
301c04c3fa6SDavid Wu struct rockchip_mux_recalced_data {
302c04c3fa6SDavid Wu 	u8 num;
303c04c3fa6SDavid Wu 	u8 pin;
30412b8f018SDavid Wu 	u32 reg;
305c04c3fa6SDavid Wu 	u8 bit;
306c04c3fa6SDavid Wu 	u8 mask;
307c04c3fa6SDavid Wu };
308c04c3fa6SDavid Wu 
309c04c3fa6SDavid Wu /**
310c04c3fa6SDavid Wu  * struct rockchip_mux_recalced_data: represent a pin iomux data.
311bd35b9bfSDavid Wu  * @bank_num: bank number.
312bd35b9bfSDavid Wu  * @pin: index at register or used to calc index.
313bd35b9bfSDavid Wu  * @func: the min pin.
314bd35b9bfSDavid Wu  * @route_offset: the max pin.
315bd35b9bfSDavid Wu  * @route_val: the register offset.
316bd35b9bfSDavid Wu  */
317bd35b9bfSDavid Wu struct rockchip_mux_route_data {
318bd35b9bfSDavid Wu 	u8 bank_num;
319bd35b9bfSDavid Wu 	u8 pin;
320bd35b9bfSDavid Wu 	u8 func;
321bd35b9bfSDavid Wu 	u32 route_offset;
322bd35b9bfSDavid Wu 	u32 route_val;
323bd35b9bfSDavid Wu };
324bd35b9bfSDavid Wu 
325bd35b9bfSDavid Wu /**
326d3e51161SHeiko Stübner  */
327d3e51161SHeiko Stübner struct rockchip_pin_ctrl {
328d3e51161SHeiko Stübner 	struct rockchip_pin_bank	*pin_banks;
329d3e51161SHeiko Stübner 	u32				nr_banks;
330d3e51161SHeiko Stübner 	u32				nr_pins;
331d3e51161SHeiko Stübner 	char				*label;
332a282926dSHeiko Stübner 	enum rockchip_pinctrl_type	type;
33395ec8ae4SHeiko Stübner 	int				grf_mux_offset;
33495ec8ae4SHeiko Stübner 	int				pmu_mux_offset;
335b6c23275SDavid Wu 	int				grf_drv_offset;
336b6c23275SDavid Wu 	int				pmu_drv_offset;
337c04c3fa6SDavid Wu 	struct rockchip_mux_recalced_data *iomux_recalced;
338c04c3fa6SDavid Wu 	u32				niomux_recalced;
339bd35b9bfSDavid Wu 	struct rockchip_mux_route_data *iomux_routes;
340bd35b9bfSDavid Wu 	u32				niomux_routes;
341b6c23275SDavid Wu 
342751a99abSHeiko Stübner 	void	(*pull_calc_reg)(struct rockchip_pin_bank *bank,
343751a99abSHeiko Stübner 				    int pin_num, struct regmap **regmap,
344751a99abSHeiko Stübner 				    int *reg, u8 *bit);
345ef17f69fSHeiko Stübner 	void	(*drv_calc_reg)(struct rockchip_pin_bank *bank,
346ef17f69fSHeiko Stübner 				    int pin_num, struct regmap **regmap,
347ef17f69fSHeiko Stübner 				    int *reg, u8 *bit);
348e3b357d7Sdavid.wu 	int	(*schmitt_calc_reg)(struct rockchip_pin_bank *bank,
349e3b357d7Sdavid.wu 				    int pin_num, struct regmap **regmap,
350e3b357d7Sdavid.wu 				    int *reg, u8 *bit);
351d3e51161SHeiko Stübner };
352d3e51161SHeiko Stübner 
353d3e51161SHeiko Stübner struct rockchip_pin_config {
354d3e51161SHeiko Stübner 	unsigned int		func;
355d3e51161SHeiko Stübner 	unsigned long		*configs;
356d3e51161SHeiko Stübner 	unsigned int		nconfigs;
357d3e51161SHeiko Stübner };
358d3e51161SHeiko Stübner 
359d3e51161SHeiko Stübner /**
360d3e51161SHeiko Stübner  * struct rockchip_pin_group: represent group of pins of a pinmux function.
361d3e51161SHeiko Stübner  * @name: name of the pin group, used to lookup the group.
362d3e51161SHeiko Stübner  * @pins: the pins included in this group.
363d3e51161SHeiko Stübner  * @npins: number of pins included in this group.
364d3e51161SHeiko Stübner  * @func: the mux function number to be programmed when selected.
365d3e51161SHeiko Stübner  * @configs: the config values to be set for each pin
366d3e51161SHeiko Stübner  * @nconfigs: number of configs for each pin
367d3e51161SHeiko Stübner  */
368d3e51161SHeiko Stübner struct rockchip_pin_group {
369d3e51161SHeiko Stübner 	const char			*name;
370d3e51161SHeiko Stübner 	unsigned int			npins;
371d3e51161SHeiko Stübner 	unsigned int			*pins;
372d3e51161SHeiko Stübner 	struct rockchip_pin_config	*data;
373d3e51161SHeiko Stübner };
374d3e51161SHeiko Stübner 
375d3e51161SHeiko Stübner /**
376d3e51161SHeiko Stübner  * struct rockchip_pmx_func: represent a pin function.
377d3e51161SHeiko Stübner  * @name: name of the pin function, used to lookup the function.
378d3e51161SHeiko Stübner  * @groups: one or more names of pin groups that provide this function.
379d3e51161SHeiko Stübner  * @num_groups: number of groups included in @groups.
380d3e51161SHeiko Stübner  */
381d3e51161SHeiko Stübner struct rockchip_pmx_func {
382d3e51161SHeiko Stübner 	const char		*name;
383d3e51161SHeiko Stübner 	const char		**groups;
384d3e51161SHeiko Stübner 	u8			ngroups;
385d3e51161SHeiko Stübner };
386d3e51161SHeiko Stübner 
387d3e51161SHeiko Stübner struct rockchip_pinctrl {
388751a99abSHeiko Stübner 	struct regmap			*regmap_base;
389bfc7a42aSHeiko Stübner 	int				reg_size;
390751a99abSHeiko Stübner 	struct regmap			*regmap_pull;
39114dee867SHeiko Stübner 	struct regmap			*regmap_pmu;
392d3e51161SHeiko Stübner 	struct device			*dev;
393d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl	*ctrl;
394d3e51161SHeiko Stübner 	struct pinctrl_desc		pctl;
395d3e51161SHeiko Stübner 	struct pinctrl_dev		*pctl_dev;
396d3e51161SHeiko Stübner 	struct rockchip_pin_group	*groups;
397d3e51161SHeiko Stübner 	unsigned int			ngroups;
398d3e51161SHeiko Stübner 	struct rockchip_pmx_func	*functions;
399d3e51161SHeiko Stübner 	unsigned int			nfunctions;
400d3e51161SHeiko Stübner };
401d3e51161SHeiko Stübner 
402751a99abSHeiko Stübner static struct regmap_config rockchip_regmap_config = {
403751a99abSHeiko Stübner 	.reg_bits = 32,
404751a99abSHeiko Stübner 	.val_bits = 32,
405751a99abSHeiko Stübner 	.reg_stride = 4,
406751a99abSHeiko Stübner };
407751a99abSHeiko Stübner 
40856411f3cSArnd Bergmann static inline const struct rockchip_pin_group *pinctrl_name_to_group(
409d3e51161SHeiko Stübner 					const struct rockchip_pinctrl *info,
410d3e51161SHeiko Stübner 					const char *name)
411d3e51161SHeiko Stübner {
412d3e51161SHeiko Stübner 	int i;
413d3e51161SHeiko Stübner 
414d3e51161SHeiko Stübner 	for (i = 0; i < info->ngroups; i++) {
4151cb95395SAxel Lin 		if (!strcmp(info->groups[i].name, name))
4161cb95395SAxel Lin 			return &info->groups[i];
417d3e51161SHeiko Stübner 	}
418d3e51161SHeiko Stübner 
4191cb95395SAxel Lin 	return NULL;
420d3e51161SHeiko Stübner }
421d3e51161SHeiko Stübner 
422d3e51161SHeiko Stübner /*
423d3e51161SHeiko Stübner  * given a pin number that is local to a pin controller, find out the pin bank
424d3e51161SHeiko Stübner  * and the register base of the pin bank.
425d3e51161SHeiko Stübner  */
426d3e51161SHeiko Stübner static struct rockchip_pin_bank *pin_to_bank(struct rockchip_pinctrl *info,
427d3e51161SHeiko Stübner 								unsigned pin)
428d3e51161SHeiko Stübner {
429d3e51161SHeiko Stübner 	struct rockchip_pin_bank *b = info->ctrl->pin_banks;
430d3e51161SHeiko Stübner 
43151578b9bSAxel Lin 	while (pin >= (b->pin_base + b->nr_pins))
432d3e51161SHeiko Stübner 		b++;
433d3e51161SHeiko Stübner 
434d3e51161SHeiko Stübner 	return b;
435d3e51161SHeiko Stübner }
436d3e51161SHeiko Stübner 
437d3e51161SHeiko Stübner static struct rockchip_pin_bank *bank_num_to_bank(
438d3e51161SHeiko Stübner 					struct rockchip_pinctrl *info,
439d3e51161SHeiko Stübner 					unsigned num)
440d3e51161SHeiko Stübner {
441d3e51161SHeiko Stübner 	struct rockchip_pin_bank *b = info->ctrl->pin_banks;
442d3e51161SHeiko Stübner 	int i;
443d3e51161SHeiko Stübner 
4441cb95395SAxel Lin 	for (i = 0; i < info->ctrl->nr_banks; i++, b++) {
445d3e51161SHeiko Stübner 		if (b->bank_num == num)
4461cb95395SAxel Lin 			return b;
447d3e51161SHeiko Stübner 	}
448d3e51161SHeiko Stübner 
449d3e51161SHeiko Stübner 	return ERR_PTR(-EINVAL);
450d3e51161SHeiko Stübner }
451d3e51161SHeiko Stübner 
452d3e51161SHeiko Stübner /*
453d3e51161SHeiko Stübner  * Pinctrl_ops handling
454d3e51161SHeiko Stübner  */
455d3e51161SHeiko Stübner 
456d3e51161SHeiko Stübner static int rockchip_get_groups_count(struct pinctrl_dev *pctldev)
457d3e51161SHeiko Stübner {
458d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
459d3e51161SHeiko Stübner 
460d3e51161SHeiko Stübner 	return info->ngroups;
461d3e51161SHeiko Stübner }
462d3e51161SHeiko Stübner 
463d3e51161SHeiko Stübner static const char *rockchip_get_group_name(struct pinctrl_dev *pctldev,
464d3e51161SHeiko Stübner 							unsigned selector)
465d3e51161SHeiko Stübner {
466d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
467d3e51161SHeiko Stübner 
468d3e51161SHeiko Stübner 	return info->groups[selector].name;
469d3e51161SHeiko Stübner }
470d3e51161SHeiko Stübner 
471d3e51161SHeiko Stübner static int rockchip_get_group_pins(struct pinctrl_dev *pctldev,
472d3e51161SHeiko Stübner 				      unsigned selector, const unsigned **pins,
473d3e51161SHeiko Stübner 				      unsigned *npins)
474d3e51161SHeiko Stübner {
475d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
476d3e51161SHeiko Stübner 
477d3e51161SHeiko Stübner 	if (selector >= info->ngroups)
478d3e51161SHeiko Stübner 		return -EINVAL;
479d3e51161SHeiko Stübner 
480d3e51161SHeiko Stübner 	*pins = info->groups[selector].pins;
481d3e51161SHeiko Stübner 	*npins = info->groups[selector].npins;
482d3e51161SHeiko Stübner 
483d3e51161SHeiko Stübner 	return 0;
484d3e51161SHeiko Stübner }
485d3e51161SHeiko Stübner 
486d3e51161SHeiko Stübner static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,
487d3e51161SHeiko Stübner 				 struct device_node *np,
488d3e51161SHeiko Stübner 				 struct pinctrl_map **map, unsigned *num_maps)
489d3e51161SHeiko Stübner {
490d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
491d3e51161SHeiko Stübner 	const struct rockchip_pin_group *grp;
492d3e51161SHeiko Stübner 	struct pinctrl_map *new_map;
493d3e51161SHeiko Stübner 	struct device_node *parent;
494d3e51161SHeiko Stübner 	int map_num = 1;
495d3e51161SHeiko Stübner 	int i;
496d3e51161SHeiko Stübner 
497d3e51161SHeiko Stübner 	/*
498d3e51161SHeiko Stübner 	 * first find the group of this node and check if we need to create
499d3e51161SHeiko Stübner 	 * config maps for pins
500d3e51161SHeiko Stübner 	 */
501d3e51161SHeiko Stübner 	grp = pinctrl_name_to_group(info, np->name);
502d3e51161SHeiko Stübner 	if (!grp) {
503d3e51161SHeiko Stübner 		dev_err(info->dev, "unable to find group for node %s\n",
504d3e51161SHeiko Stübner 			np->name);
505d3e51161SHeiko Stübner 		return -EINVAL;
506d3e51161SHeiko Stübner 	}
507d3e51161SHeiko Stübner 
508d3e51161SHeiko Stübner 	map_num += grp->npins;
509d3e51161SHeiko Stübner 	new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num,
510d3e51161SHeiko Stübner 								GFP_KERNEL);
511d3e51161SHeiko Stübner 	if (!new_map)
512d3e51161SHeiko Stübner 		return -ENOMEM;
513d3e51161SHeiko Stübner 
514d3e51161SHeiko Stübner 	*map = new_map;
515d3e51161SHeiko Stübner 	*num_maps = map_num;
516d3e51161SHeiko Stübner 
517d3e51161SHeiko Stübner 	/* create mux map */
518d3e51161SHeiko Stübner 	parent = of_get_parent(np);
519d3e51161SHeiko Stübner 	if (!parent) {
520d3e51161SHeiko Stübner 		devm_kfree(pctldev->dev, new_map);
521d3e51161SHeiko Stübner 		return -EINVAL;
522d3e51161SHeiko Stübner 	}
523d3e51161SHeiko Stübner 	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
524d3e51161SHeiko Stübner 	new_map[0].data.mux.function = parent->name;
525d3e51161SHeiko Stübner 	new_map[0].data.mux.group = np->name;
526d3e51161SHeiko Stübner 	of_node_put(parent);
527d3e51161SHeiko Stübner 
528d3e51161SHeiko Stübner 	/* create config map */
529d3e51161SHeiko Stübner 	new_map++;
530d3e51161SHeiko Stübner 	for (i = 0; i < grp->npins; i++) {
531d3e51161SHeiko Stübner 		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
532d3e51161SHeiko Stübner 		new_map[i].data.configs.group_or_pin =
533d3e51161SHeiko Stübner 				pin_get_name(pctldev, grp->pins[i]);
534d3e51161SHeiko Stübner 		new_map[i].data.configs.configs = grp->data[i].configs;
535d3e51161SHeiko Stübner 		new_map[i].data.configs.num_configs = grp->data[i].nconfigs;
536d3e51161SHeiko Stübner 	}
537d3e51161SHeiko Stübner 
538d3e51161SHeiko Stübner 	dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
539d3e51161SHeiko Stübner 		(*map)->data.mux.function, (*map)->data.mux.group, map_num);
540d3e51161SHeiko Stübner 
541d3e51161SHeiko Stübner 	return 0;
542d3e51161SHeiko Stübner }
543d3e51161SHeiko Stübner 
544d3e51161SHeiko Stübner static void rockchip_dt_free_map(struct pinctrl_dev *pctldev,
545d3e51161SHeiko Stübner 				    struct pinctrl_map *map, unsigned num_maps)
546d3e51161SHeiko Stübner {
547d3e51161SHeiko Stübner }
548d3e51161SHeiko Stübner 
549d3e51161SHeiko Stübner static const struct pinctrl_ops rockchip_pctrl_ops = {
550d3e51161SHeiko Stübner 	.get_groups_count	= rockchip_get_groups_count,
551d3e51161SHeiko Stübner 	.get_group_name		= rockchip_get_group_name,
552d3e51161SHeiko Stübner 	.get_group_pins		= rockchip_get_group_pins,
553d3e51161SHeiko Stübner 	.dt_node_to_map		= rockchip_dt_node_to_map,
554d3e51161SHeiko Stübner 	.dt_free_map		= rockchip_dt_free_map,
555d3e51161SHeiko Stübner };
556d3e51161SHeiko Stübner 
557d3e51161SHeiko Stübner /*
558d3e51161SHeiko Stübner  * Hardware access
559d3e51161SHeiko Stübner  */
560d3e51161SHeiko Stübner 
56112b8f018SDavid Wu static struct rockchip_mux_recalced_data rv1108_mux_recalced_data[] = {
56212b8f018SDavid Wu 	{
56312b8f018SDavid Wu 		.num = 1,
56412b8f018SDavid Wu 		.pin = 0,
56512b8f018SDavid Wu 		.reg = 0x418,
56612b8f018SDavid Wu 		.bit = 0,
56712b8f018SDavid Wu 		.mask = 0x3
56812b8f018SDavid Wu 	}, {
56912b8f018SDavid Wu 		.num = 1,
57012b8f018SDavid Wu 		.pin = 1,
57112b8f018SDavid Wu 		.reg = 0x418,
57212b8f018SDavid Wu 		.bit = 2,
57312b8f018SDavid Wu 		.mask = 0x3
57412b8f018SDavid Wu 	}, {
57512b8f018SDavid Wu 		.num = 1,
57612b8f018SDavid Wu 		.pin = 2,
57712b8f018SDavid Wu 		.reg = 0x418,
57812b8f018SDavid Wu 		.bit = 4,
57912b8f018SDavid Wu 		.mask = 0x3
58012b8f018SDavid Wu 	}, {
58112b8f018SDavid Wu 		.num = 1,
58212b8f018SDavid Wu 		.pin = 3,
58312b8f018SDavid Wu 		.reg = 0x418,
58412b8f018SDavid Wu 		.bit = 6,
58512b8f018SDavid Wu 		.mask = 0x3
58612b8f018SDavid Wu 	}, {
58712b8f018SDavid Wu 		.num = 1,
58812b8f018SDavid Wu 		.pin = 4,
58912b8f018SDavid Wu 		.reg = 0x418,
59012b8f018SDavid Wu 		.bit = 8,
59112b8f018SDavid Wu 		.mask = 0x3
59212b8f018SDavid Wu 	}, {
59312b8f018SDavid Wu 		.num = 1,
59412b8f018SDavid Wu 		.pin = 5,
59512b8f018SDavid Wu 		.reg = 0x418,
59612b8f018SDavid Wu 		.bit = 10,
59712b8f018SDavid Wu 		.mask = 0x3
59812b8f018SDavid Wu 	}, {
59912b8f018SDavid Wu 		.num = 1,
60012b8f018SDavid Wu 		.pin = 6,
60112b8f018SDavid Wu 		.reg = 0x418,
60212b8f018SDavid Wu 		.bit = 12,
60312b8f018SDavid Wu 		.mask = 0x3
60412b8f018SDavid Wu 	}, {
60512b8f018SDavid Wu 		.num = 1,
60612b8f018SDavid Wu 		.pin = 7,
60712b8f018SDavid Wu 		.reg = 0x418,
60812b8f018SDavid Wu 		.bit = 14,
60912b8f018SDavid Wu 		.mask = 0x3
61012b8f018SDavid Wu 	}, {
61112b8f018SDavid Wu 		.num = 1,
61212b8f018SDavid Wu 		.pin = 8,
61312b8f018SDavid Wu 		.reg = 0x41c,
61412b8f018SDavid Wu 		.bit = 0,
61512b8f018SDavid Wu 		.mask = 0x3
61612b8f018SDavid Wu 	}, {
61712b8f018SDavid Wu 		.num = 1,
61812b8f018SDavid Wu 		.pin = 9,
61912b8f018SDavid Wu 		.reg = 0x41c,
62012b8f018SDavid Wu 		.bit = 2,
62112b8f018SDavid Wu 		.mask = 0x3
62212b8f018SDavid Wu 	},
62312b8f018SDavid Wu };
62412b8f018SDavid Wu 
625d23c66dfSDavid Wu static  struct rockchip_mux_recalced_data rk3128_mux_recalced_data[] = {
626d23c66dfSDavid Wu 	{
627d23c66dfSDavid Wu 		.num = 2,
628d23c66dfSDavid Wu 		.pin = 20,
629d23c66dfSDavid Wu 		.reg = 0xe8,
630d23c66dfSDavid Wu 		.bit = 0,
631d23c66dfSDavid Wu 		.mask = 0x7
632d23c66dfSDavid Wu 	}, {
633d23c66dfSDavid Wu 		.num = 2,
634d23c66dfSDavid Wu 		.pin = 21,
635d23c66dfSDavid Wu 		.reg = 0xe8,
636d23c66dfSDavid Wu 		.bit = 4,
637d23c66dfSDavid Wu 		.mask = 0x7
638d23c66dfSDavid Wu 	}, {
639d23c66dfSDavid Wu 		.num = 2,
640d23c66dfSDavid Wu 		.pin = 22,
641d23c66dfSDavid Wu 		.reg = 0xe8,
642d23c66dfSDavid Wu 		.bit = 8,
643d23c66dfSDavid Wu 		.mask = 0x7
644d23c66dfSDavid Wu 	}, {
645d23c66dfSDavid Wu 		.num = 2,
646d23c66dfSDavid Wu 		.pin = 23,
647d23c66dfSDavid Wu 		.reg = 0xe8,
648d23c66dfSDavid Wu 		.bit = 12,
649d23c66dfSDavid Wu 		.mask = 0x7
650d23c66dfSDavid Wu 	}, {
651d23c66dfSDavid Wu 		.num = 2,
652d23c66dfSDavid Wu 		.pin = 24,
653d23c66dfSDavid Wu 		.reg = 0xd4,
654d23c66dfSDavid Wu 		.bit = 12,
655d23c66dfSDavid Wu 		.mask = 0x7
656d23c66dfSDavid Wu 	},
657d23c66dfSDavid Wu };
658d23c66dfSDavid Wu 
659c04c3fa6SDavid Wu static struct rockchip_mux_recalced_data rk3328_mux_recalced_data[] = {
6603818e4a7Sdavid.wu 	{
6613818e4a7Sdavid.wu 		.num = 2,
6623818e4a7Sdavid.wu 		.pin = 12,
6633818e4a7Sdavid.wu 		.reg = 0x24,
6643818e4a7Sdavid.wu 		.bit = 8,
6653818e4a7Sdavid.wu 		.mask = 0x3
6663818e4a7Sdavid.wu 	}, {
6673818e4a7Sdavid.wu 		.num = 2,
6683818e4a7Sdavid.wu 		.pin = 15,
6693818e4a7Sdavid.wu 		.reg = 0x28,
6703818e4a7Sdavid.wu 		.bit = 0,
6713818e4a7Sdavid.wu 		.mask = 0x7
6723818e4a7Sdavid.wu 	}, {
6733818e4a7Sdavid.wu 		.num = 2,
6743818e4a7Sdavid.wu 		.pin = 23,
6753818e4a7Sdavid.wu 		.reg = 0x30,
6763818e4a7Sdavid.wu 		.bit = 14,
6773818e4a7Sdavid.wu 		.mask = 0x3
6783818e4a7Sdavid.wu 	},
6793818e4a7Sdavid.wu };
6803818e4a7Sdavid.wu 
681c04c3fa6SDavid Wu static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
682c04c3fa6SDavid Wu 				      int *reg, u8 *bit, int *mask)
6833818e4a7Sdavid.wu {
684c04c3fa6SDavid Wu 	struct rockchip_pinctrl *info = bank->drvdata;
685c04c3fa6SDavid Wu 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
686c04c3fa6SDavid Wu 	struct rockchip_mux_recalced_data *data;
6873818e4a7Sdavid.wu 	int i;
6883818e4a7Sdavid.wu 
689c04c3fa6SDavid Wu 	for (i = 0; i < ctrl->niomux_recalced; i++) {
690c04c3fa6SDavid Wu 		data = &ctrl->iomux_recalced[i];
691c04c3fa6SDavid Wu 		if (data->num == bank->bank_num &&
692c04c3fa6SDavid Wu 		    data->pin == pin)
6933818e4a7Sdavid.wu 			break;
6943818e4a7Sdavid.wu 	}
6953818e4a7Sdavid.wu 
696c04c3fa6SDavid Wu 	if (i >= ctrl->niomux_recalced)
6973818e4a7Sdavid.wu 		return;
6983818e4a7Sdavid.wu 
6993818e4a7Sdavid.wu 	*reg = data->reg;
7003818e4a7Sdavid.wu 	*mask = data->mask;
7013818e4a7Sdavid.wu 	*bit = data->bit;
7023818e4a7Sdavid.wu }
7033818e4a7Sdavid.wu 
704d23c66dfSDavid Wu static struct rockchip_mux_route_data rk3128_mux_route_data[] = {
705d23c66dfSDavid Wu 	{
706d23c66dfSDavid Wu 		/* spi-0 */
707d23c66dfSDavid Wu 		.bank_num = 1,
708d23c66dfSDavid Wu 		.pin = 10,
709d23c66dfSDavid Wu 		.func = 1,
710d23c66dfSDavid Wu 		.route_offset = 0x144,
711d23c66dfSDavid Wu 		.route_val = BIT(16 + 3) | BIT(16 + 4),
712d23c66dfSDavid Wu 	}, {
713d23c66dfSDavid Wu 		/* spi-1 */
714d23c66dfSDavid Wu 		.bank_num = 1,
715d23c66dfSDavid Wu 		.pin = 27,
716d23c66dfSDavid Wu 		.func = 3,
717d23c66dfSDavid Wu 		.route_offset = 0x144,
718d23c66dfSDavid Wu 		.route_val = BIT(16 + 3) | BIT(16 + 4) | BIT(3),
719d23c66dfSDavid Wu 	}, {
720d23c66dfSDavid Wu 		/* spi-2 */
721d23c66dfSDavid Wu 		.bank_num = 0,
722d23c66dfSDavid Wu 		.pin = 13,
723d23c66dfSDavid Wu 		.func = 2,
724d23c66dfSDavid Wu 		.route_offset = 0x144,
725d23c66dfSDavid Wu 		.route_val = BIT(16 + 3) | BIT(16 + 4) | BIT(4),
726d23c66dfSDavid Wu 	}, {
727d23c66dfSDavid Wu 		/* i2s-0 */
728d23c66dfSDavid Wu 		.bank_num = 1,
729d23c66dfSDavid Wu 		.pin = 5,
730d23c66dfSDavid Wu 		.func = 1,
731d23c66dfSDavid Wu 		.route_offset = 0x144,
732d23c66dfSDavid Wu 		.route_val = BIT(16 + 5),
733d23c66dfSDavid Wu 	}, {
734d23c66dfSDavid Wu 		/* i2s-1 */
735d23c66dfSDavid Wu 		.bank_num = 0,
736d23c66dfSDavid Wu 		.pin = 14,
737d23c66dfSDavid Wu 		.func = 1,
738d23c66dfSDavid Wu 		.route_offset = 0x144,
739d23c66dfSDavid Wu 		.route_val = BIT(16 + 5) | BIT(5),
740d23c66dfSDavid Wu 	}, {
741d23c66dfSDavid Wu 		/* emmc-0 */
742d23c66dfSDavid Wu 		.bank_num = 1,
743d23c66dfSDavid Wu 		.pin = 22,
744d23c66dfSDavid Wu 		.func = 2,
745d23c66dfSDavid Wu 		.route_offset = 0x144,
746d23c66dfSDavid Wu 		.route_val = BIT(16 + 6),
747d23c66dfSDavid Wu 	}, {
748d23c66dfSDavid Wu 		/* emmc-1 */
749d23c66dfSDavid Wu 		.bank_num = 2,
750d23c66dfSDavid Wu 		.pin = 4,
751d23c66dfSDavid Wu 		.func = 2,
752d23c66dfSDavid Wu 		.route_offset = 0x144,
753d23c66dfSDavid Wu 		.route_val = BIT(16 + 6) | BIT(6),
754d23c66dfSDavid Wu 	},
755d23c66dfSDavid Wu };
756d23c66dfSDavid Wu 
757d4970ee0SDavid Wu static struct rockchip_mux_route_data rk3228_mux_route_data[] = {
758d4970ee0SDavid Wu 	{
759d4970ee0SDavid Wu 		/* pwm0-0 */
760d4970ee0SDavid Wu 		.bank_num = 0,
761d4970ee0SDavid Wu 		.pin = 26,
762d4970ee0SDavid Wu 		.func = 1,
763d4970ee0SDavid Wu 		.route_offset = 0x50,
764d4970ee0SDavid Wu 		.route_val = BIT(16),
765d4970ee0SDavid Wu 	}, {
766d4970ee0SDavid Wu 		/* pwm0-1 */
767d4970ee0SDavid Wu 		.bank_num = 3,
768d4970ee0SDavid Wu 		.pin = 21,
769d4970ee0SDavid Wu 		.func = 1,
770d4970ee0SDavid Wu 		.route_offset = 0x50,
771d4970ee0SDavid Wu 		.route_val = BIT(16) | BIT(0),
772d4970ee0SDavid Wu 	}, {
773d4970ee0SDavid Wu 		/* pwm1-0 */
774d4970ee0SDavid Wu 		.bank_num = 0,
775d4970ee0SDavid Wu 		.pin = 27,
776d4970ee0SDavid Wu 		.func = 1,
777d4970ee0SDavid Wu 		.route_offset = 0x50,
778d4970ee0SDavid Wu 		.route_val = BIT(16 + 1),
779d4970ee0SDavid Wu 	}, {
780d4970ee0SDavid Wu 		/* pwm1-1 */
781d4970ee0SDavid Wu 		.bank_num = 0,
782d4970ee0SDavid Wu 		.pin = 30,
783d4970ee0SDavid Wu 		.func = 2,
784d4970ee0SDavid Wu 		.route_offset = 0x50,
785d4970ee0SDavid Wu 		.route_val = BIT(16 + 1) | BIT(1),
786d4970ee0SDavid Wu 	}, {
787d4970ee0SDavid Wu 		/* pwm2-0 */
788d4970ee0SDavid Wu 		.bank_num = 0,
789d4970ee0SDavid Wu 		.pin = 28,
790d4970ee0SDavid Wu 		.func = 1,
791d4970ee0SDavid Wu 		.route_offset = 0x50,
792d4970ee0SDavid Wu 		.route_val = BIT(16 + 2),
793d4970ee0SDavid Wu 	}, {
794d4970ee0SDavid Wu 		/* pwm2-1 */
795d4970ee0SDavid Wu 		.bank_num = 1,
796d4970ee0SDavid Wu 		.pin = 12,
797d4970ee0SDavid Wu 		.func = 2,
798d4970ee0SDavid Wu 		.route_offset = 0x50,
799d4970ee0SDavid Wu 		.route_val = BIT(16 + 2) | BIT(2),
800d4970ee0SDavid Wu 	}, {
801d4970ee0SDavid Wu 		/* pwm3-0 */
802d4970ee0SDavid Wu 		.bank_num = 3,
803d4970ee0SDavid Wu 		.pin = 26,
804d4970ee0SDavid Wu 		.func = 1,
805d4970ee0SDavid Wu 		.route_offset = 0x50,
806d4970ee0SDavid Wu 		.route_val = BIT(16 + 3),
807d4970ee0SDavid Wu 	}, {
808d4970ee0SDavid Wu 		/* pwm3-1 */
809d4970ee0SDavid Wu 		.bank_num = 1,
810d4970ee0SDavid Wu 		.pin = 11,
811d4970ee0SDavid Wu 		.func = 2,
812d4970ee0SDavid Wu 		.route_offset = 0x50,
813d4970ee0SDavid Wu 		.route_val = BIT(16 + 3) | BIT(3),
814d4970ee0SDavid Wu 	}, {
815d4970ee0SDavid Wu 		/* sdio-0_d0 */
816d4970ee0SDavid Wu 		.bank_num = 1,
817d4970ee0SDavid Wu 		.pin = 1,
818d4970ee0SDavid Wu 		.func = 1,
819d4970ee0SDavid Wu 		.route_offset = 0x50,
820d4970ee0SDavid Wu 		.route_val = BIT(16 + 4),
821d4970ee0SDavid Wu 	}, {
822d4970ee0SDavid Wu 		/* sdio-1_d0 */
823d4970ee0SDavid Wu 		.bank_num = 3,
824d4970ee0SDavid Wu 		.pin = 2,
825d4970ee0SDavid Wu 		.func = 1,
826d4970ee0SDavid Wu 		.route_offset = 0x50,
827d4970ee0SDavid Wu 		.route_val = BIT(16 + 4) | BIT(4),
828d4970ee0SDavid Wu 	}, {
829d4970ee0SDavid Wu 		/* spi-0_rx */
830d4970ee0SDavid Wu 		.bank_num = 0,
831d4970ee0SDavid Wu 		.pin = 13,
832d4970ee0SDavid Wu 		.func = 2,
833d4970ee0SDavid Wu 		.route_offset = 0x50,
834d4970ee0SDavid Wu 		.route_val = BIT(16 + 5),
835d4970ee0SDavid Wu 	}, {
836d4970ee0SDavid Wu 		/* spi-1_rx */
837d4970ee0SDavid Wu 		.bank_num = 2,
838d4970ee0SDavid Wu 		.pin = 0,
839d4970ee0SDavid Wu 		.func = 2,
840d4970ee0SDavid Wu 		.route_offset = 0x50,
841d4970ee0SDavid Wu 		.route_val = BIT(16 + 5) | BIT(5),
842d4970ee0SDavid Wu 	}, {
843d4970ee0SDavid Wu 		/* emmc-0_cmd */
844d4970ee0SDavid Wu 		.bank_num = 1,
845d4970ee0SDavid Wu 		.pin = 22,
846d4970ee0SDavid Wu 		.func = 2,
847d4970ee0SDavid Wu 		.route_offset = 0x50,
848d4970ee0SDavid Wu 		.route_val = BIT(16 + 7),
849d4970ee0SDavid Wu 	}, {
850d4970ee0SDavid Wu 		/* emmc-1_cmd */
851d4970ee0SDavid Wu 		.bank_num = 2,
852d4970ee0SDavid Wu 		.pin = 4,
853d4970ee0SDavid Wu 		.func = 2,
854d4970ee0SDavid Wu 		.route_offset = 0x50,
855d4970ee0SDavid Wu 		.route_val = BIT(16 + 7) | BIT(7),
856d4970ee0SDavid Wu 	}, {
857d4970ee0SDavid Wu 		/* uart2-0_rx */
858d4970ee0SDavid Wu 		.bank_num = 1,
859d4970ee0SDavid Wu 		.pin = 19,
860d4970ee0SDavid Wu 		.func = 2,
861d4970ee0SDavid Wu 		.route_offset = 0x50,
862d4970ee0SDavid Wu 		.route_val = BIT(16 + 8),
863d4970ee0SDavid Wu 	}, {
864d4970ee0SDavid Wu 		/* uart2-1_rx */
865d4970ee0SDavid Wu 		.bank_num = 1,
866d4970ee0SDavid Wu 		.pin = 10,
867d4970ee0SDavid Wu 		.func = 2,
868d4970ee0SDavid Wu 		.route_offset = 0x50,
869d4970ee0SDavid Wu 		.route_val = BIT(16 + 8) | BIT(8),
870d4970ee0SDavid Wu 	}, {
871d4970ee0SDavid Wu 		/* uart1-0_rx */
872d4970ee0SDavid Wu 		.bank_num = 1,
873d4970ee0SDavid Wu 		.pin = 10,
874d4970ee0SDavid Wu 		.func = 1,
875d4970ee0SDavid Wu 		.route_offset = 0x50,
876d4970ee0SDavid Wu 		.route_val = BIT(16 + 11),
877d4970ee0SDavid Wu 	}, {
878d4970ee0SDavid Wu 		/* uart1-1_rx */
879d4970ee0SDavid Wu 		.bank_num = 3,
880d4970ee0SDavid Wu 		.pin = 13,
881d4970ee0SDavid Wu 		.func = 1,
882d4970ee0SDavid Wu 		.route_offset = 0x50,
883d4970ee0SDavid Wu 		.route_val = BIT(16 + 11) | BIT(11),
884d4970ee0SDavid Wu 	},
885d4970ee0SDavid Wu };
886d4970ee0SDavid Wu 
887cedc964aSDavid Wu static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
888cedc964aSDavid Wu 	{
889cedc964aSDavid Wu 		/* uart2dbg_rxm0 */
890cedc964aSDavid Wu 		.bank_num = 1,
891cedc964aSDavid Wu 		.pin = 1,
892cedc964aSDavid Wu 		.func = 2,
893cedc964aSDavid Wu 		.route_offset = 0x50,
894cedc964aSDavid Wu 		.route_val = BIT(16) | BIT(16 + 1),
895cedc964aSDavid Wu 	}, {
896cedc964aSDavid Wu 		/* uart2dbg_rxm1 */
897cedc964aSDavid Wu 		.bank_num = 2,
898cedc964aSDavid Wu 		.pin = 1,
899cedc964aSDavid Wu 		.func = 1,
900cedc964aSDavid Wu 		.route_offset = 0x50,
901cedc964aSDavid Wu 		.route_val = BIT(16) | BIT(16 + 1) | BIT(0),
902cedc964aSDavid Wu 	}, {
903cedc964aSDavid Wu 		/* gmac-m1-optimized_rxd0 */
904cedc964aSDavid Wu 		.bank_num = 1,
905cedc964aSDavid Wu 		.pin = 11,
906cedc964aSDavid Wu 		.func = 2,
907cedc964aSDavid Wu 		.route_offset = 0x50,
908cedc964aSDavid Wu 		.route_val = BIT(16 + 2) | BIT(16 + 10) | BIT(2) | BIT(10),
909cedc964aSDavid Wu 	}, {
910cedc964aSDavid Wu 		/* pdm_sdi0m0 */
911cedc964aSDavid Wu 		.bank_num = 2,
912cedc964aSDavid Wu 		.pin = 19,
913cedc964aSDavid Wu 		.func = 2,
914cedc964aSDavid Wu 		.route_offset = 0x50,
915cedc964aSDavid Wu 		.route_val = BIT(16 + 3),
916cedc964aSDavid Wu 	}, {
917cedc964aSDavid Wu 		/* pdm_sdi0m1 */
918cedc964aSDavid Wu 		.bank_num = 1,
919cedc964aSDavid Wu 		.pin = 23,
920cedc964aSDavid Wu 		.func = 3,
921cedc964aSDavid Wu 		.route_offset = 0x50,
922cedc964aSDavid Wu 		.route_val =  BIT(16 + 3) | BIT(3),
923cedc964aSDavid Wu 	}, {
924cedc964aSDavid Wu 		/* spi_rxdm2 */
925cedc964aSDavid Wu 		.bank_num = 3,
926cedc964aSDavid Wu 		.pin = 2,
927cedc964aSDavid Wu 		.func = 4,
928cedc964aSDavid Wu 		.route_offset = 0x50,
929cedc964aSDavid Wu 		.route_val =  BIT(16 + 4) | BIT(16 + 5) | BIT(5),
930cedc964aSDavid Wu 	}, {
931cedc964aSDavid Wu 		/* i2s2_sdim0 */
932cedc964aSDavid Wu 		.bank_num = 1,
933cedc964aSDavid Wu 		.pin = 24,
934cedc964aSDavid Wu 		.func = 1,
935cedc964aSDavid Wu 		.route_offset = 0x50,
936cedc964aSDavid Wu 		.route_val = BIT(16 + 6),
937cedc964aSDavid Wu 	}, {
938cedc964aSDavid Wu 		/* i2s2_sdim1 */
939cedc964aSDavid Wu 		.bank_num = 3,
940cedc964aSDavid Wu 		.pin = 2,
941cedc964aSDavid Wu 		.func = 6,
942cedc964aSDavid Wu 		.route_offset = 0x50,
943cedc964aSDavid Wu 		.route_val =  BIT(16 + 6) | BIT(6),
944cedc964aSDavid Wu 	}, {
945cedc964aSDavid Wu 		/* card_iom1 */
946cedc964aSDavid Wu 		.bank_num = 2,
947cedc964aSDavid Wu 		.pin = 22,
948cedc964aSDavid Wu 		.func = 3,
949cedc964aSDavid Wu 		.route_offset = 0x50,
950cedc964aSDavid Wu 		.route_val =  BIT(16 + 7) | BIT(7),
951cedc964aSDavid Wu 	}, {
952cedc964aSDavid Wu 		/* tsp_d5m1 */
953cedc964aSDavid Wu 		.bank_num = 2,
954cedc964aSDavid Wu 		.pin = 16,
955cedc964aSDavid Wu 		.func = 3,
956cedc964aSDavid Wu 		.route_offset = 0x50,
957cedc964aSDavid Wu 		.route_val =  BIT(16 + 8) | BIT(8),
958cedc964aSDavid Wu 	}, {
959cedc964aSDavid Wu 		/* cif_data5m1 */
960cedc964aSDavid Wu 		.bank_num = 2,
961cedc964aSDavid Wu 		.pin = 16,
962cedc964aSDavid Wu 		.func = 4,
963cedc964aSDavid Wu 		.route_offset = 0x50,
964cedc964aSDavid Wu 		.route_val =  BIT(16 + 9) | BIT(9),
965cedc964aSDavid Wu 	},
966cedc964aSDavid Wu };
967cedc964aSDavid Wu 
968accc1ce7SDavid Wu static struct rockchip_mux_route_data rk3399_mux_route_data[] = {
969accc1ce7SDavid Wu 	{
970accc1ce7SDavid Wu 		/* uart2dbga_rx */
971accc1ce7SDavid Wu 		.bank_num = 4,
972accc1ce7SDavid Wu 		.pin = 8,
973accc1ce7SDavid Wu 		.func = 2,
974accc1ce7SDavid Wu 		.route_offset = 0xe21c,
975accc1ce7SDavid Wu 		.route_val = BIT(16 + 10) | BIT(16 + 11),
976accc1ce7SDavid Wu 	}, {
977accc1ce7SDavid Wu 		/* uart2dbgb_rx */
978accc1ce7SDavid Wu 		.bank_num = 4,
979accc1ce7SDavid Wu 		.pin = 16,
980accc1ce7SDavid Wu 		.func = 2,
981accc1ce7SDavid Wu 		.route_offset = 0xe21c,
982accc1ce7SDavid Wu 		.route_val = BIT(16 + 10) | BIT(16 + 11) | BIT(10),
983accc1ce7SDavid Wu 	}, {
984accc1ce7SDavid Wu 		/* uart2dbgc_rx */
985accc1ce7SDavid Wu 		.bank_num = 4,
986accc1ce7SDavid Wu 		.pin = 19,
987accc1ce7SDavid Wu 		.func = 1,
988accc1ce7SDavid Wu 		.route_offset = 0xe21c,
989accc1ce7SDavid Wu 		.route_val = BIT(16 + 10) | BIT(16 + 11) | BIT(11),
990accc1ce7SDavid Wu 	}, {
991accc1ce7SDavid Wu 		/* pcie_clkreqn */
992accc1ce7SDavid Wu 		.bank_num = 2,
993accc1ce7SDavid Wu 		.pin = 26,
994accc1ce7SDavid Wu 		.func = 2,
995accc1ce7SDavid Wu 		.route_offset = 0xe21c,
996accc1ce7SDavid Wu 		.route_val = BIT(16 + 14),
997accc1ce7SDavid Wu 	}, {
998accc1ce7SDavid Wu 		/* pcie_clkreqnb */
999accc1ce7SDavid Wu 		.bank_num = 4,
1000accc1ce7SDavid Wu 		.pin = 24,
1001accc1ce7SDavid Wu 		.func = 1,
1002accc1ce7SDavid Wu 		.route_offset = 0xe21c,
1003accc1ce7SDavid Wu 		.route_val = BIT(16 + 14) | BIT(14),
1004accc1ce7SDavid Wu 	},
1005accc1ce7SDavid Wu };
1006accc1ce7SDavid Wu 
1007bd35b9bfSDavid Wu static bool rockchip_get_mux_route(struct rockchip_pin_bank *bank, int pin,
1008bd35b9bfSDavid Wu 				   int mux, u32 *reg, u32 *value)
1009bd35b9bfSDavid Wu {
1010bd35b9bfSDavid Wu 	struct rockchip_pinctrl *info = bank->drvdata;
1011bd35b9bfSDavid Wu 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1012bd35b9bfSDavid Wu 	struct rockchip_mux_route_data *data;
1013bd35b9bfSDavid Wu 	int i;
1014bd35b9bfSDavid Wu 
1015bd35b9bfSDavid Wu 	for (i = 0; i < ctrl->niomux_routes; i++) {
1016bd35b9bfSDavid Wu 		data = &ctrl->iomux_routes[i];
1017bd35b9bfSDavid Wu 		if ((data->bank_num == bank->bank_num) &&
1018bd35b9bfSDavid Wu 		    (data->pin == pin) && (data->func == mux))
1019bd35b9bfSDavid Wu 			break;
1020bd35b9bfSDavid Wu 	}
1021bd35b9bfSDavid Wu 
1022bd35b9bfSDavid Wu 	if (i >= ctrl->niomux_routes)
1023bd35b9bfSDavid Wu 		return false;
1024bd35b9bfSDavid Wu 
1025bd35b9bfSDavid Wu 	*reg = data->route_offset;
1026bd35b9bfSDavid Wu 	*value = data->route_val;
1027bd35b9bfSDavid Wu 
1028bd35b9bfSDavid Wu 	return true;
1029bd35b9bfSDavid Wu }
1030bd35b9bfSDavid Wu 
1031a076e2edSHeiko Stübner static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
1032a076e2edSHeiko Stübner {
1033a076e2edSHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1034fc72c923SHeiko Stübner 	int iomux_num = (pin / 8);
103595ec8ae4SHeiko Stübner 	struct regmap *regmap;
1036751a99abSHeiko Stübner 	unsigned int val;
1037ea262ad6Sdavid.wu 	int reg, ret, mask, mux_type;
1038a076e2edSHeiko Stübner 	u8 bit;
1039a076e2edSHeiko Stübner 
1040fc72c923SHeiko Stübner 	if (iomux_num > 3)
1041fc72c923SHeiko Stübner 		return -EINVAL;
1042fc72c923SHeiko Stübner 
104362f49226SHeiko Stübner 	if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
104462f49226SHeiko Stübner 		dev_err(info->dev, "pin %d is unrouted\n", pin);
104562f49226SHeiko Stübner 		return -EINVAL;
104662f49226SHeiko Stübner 	}
104762f49226SHeiko Stübner 
1048fc72c923SHeiko Stübner 	if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
1049a076e2edSHeiko Stübner 		return RK_FUNC_GPIO;
1050a076e2edSHeiko Stübner 
105195ec8ae4SHeiko Stübner 	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
105295ec8ae4SHeiko Stübner 				? info->regmap_pmu : info->regmap_base;
105395ec8ae4SHeiko Stübner 
1054a076e2edSHeiko Stübner 	/* get basic quadrupel of mux registers and the correct reg inside */
1055ea262ad6Sdavid.wu 	mux_type = bank->iomux[iomux_num].type;
10566bc0d121SHeiko Stübner 	reg = bank->iomux[iomux_num].offset;
1057ea262ad6Sdavid.wu 	if (mux_type & IOMUX_WIDTH_4BIT) {
105803716e1dSHeiko Stübner 		if ((pin % 8) >= 4)
105903716e1dSHeiko Stübner 			reg += 0x4;
106003716e1dSHeiko Stübner 		bit = (pin % 4) * 4;
10618b6c6f93Sdavid.wu 		mask = 0xf;
1062ea262ad6Sdavid.wu 	} else if (mux_type & IOMUX_WIDTH_3BIT) {
10638b6c6f93Sdavid.wu 		if ((pin % 8) >= 5)
10648b6c6f93Sdavid.wu 			reg += 0x4;
10658b6c6f93Sdavid.wu 		bit = (pin % 8 % 5) * 3;
10668b6c6f93Sdavid.wu 		mask = 0x7;
106703716e1dSHeiko Stübner 	} else {
1068a076e2edSHeiko Stübner 		bit = (pin % 8) * 2;
10698b6c6f93Sdavid.wu 		mask = 0x3;
107003716e1dSHeiko Stübner 	}
1071a076e2edSHeiko Stübner 
1072c04c3fa6SDavid Wu 	if (bank->recalced_mask & BIT(pin))
1073c04c3fa6SDavid Wu 		rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
1074ea262ad6Sdavid.wu 
107595ec8ae4SHeiko Stübner 	ret = regmap_read(regmap, reg, &val);
1076751a99abSHeiko Stübner 	if (ret)
1077751a99abSHeiko Stübner 		return ret;
1078751a99abSHeiko Stübner 
107903716e1dSHeiko Stübner 	return ((val >> bit) & mask);
1080a076e2edSHeiko Stübner }
1081a076e2edSHeiko Stübner 
108205709c3eSJohn Keeping static int rockchip_verify_mux(struct rockchip_pin_bank *bank,
108305709c3eSJohn Keeping 			       int pin, int mux)
108405709c3eSJohn Keeping {
108505709c3eSJohn Keeping 	struct rockchip_pinctrl *info = bank->drvdata;
108605709c3eSJohn Keeping 	int iomux_num = (pin / 8);
108705709c3eSJohn Keeping 
108805709c3eSJohn Keeping 	if (iomux_num > 3)
108905709c3eSJohn Keeping 		return -EINVAL;
109005709c3eSJohn Keeping 
109105709c3eSJohn Keeping 	if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
109205709c3eSJohn Keeping 		dev_err(info->dev, "pin %d is unrouted\n", pin);
109305709c3eSJohn Keeping 		return -EINVAL;
109405709c3eSJohn Keeping 	}
109505709c3eSJohn Keeping 
109605709c3eSJohn Keeping 	if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) {
109705709c3eSJohn Keeping 		if (mux != RK_FUNC_GPIO) {
109805709c3eSJohn Keeping 			dev_err(info->dev,
109905709c3eSJohn Keeping 				"pin %d only supports a gpio mux\n", pin);
110005709c3eSJohn Keeping 			return -ENOTSUPP;
110105709c3eSJohn Keeping 		}
110205709c3eSJohn Keeping 	}
110305709c3eSJohn Keeping 
110405709c3eSJohn Keeping 	return 0;
110505709c3eSJohn Keeping }
110605709c3eSJohn Keeping 
1107d3e51161SHeiko Stübner /*
1108d3e51161SHeiko Stübner  * Set a new mux function for a pin.
1109d3e51161SHeiko Stübner  *
1110d3e51161SHeiko Stübner  * The register is divided into the upper and lower 16 bit. When changing
1111d3e51161SHeiko Stübner  * a value, the previous register value is not read and changed. Instead
1112d3e51161SHeiko Stübner  * it seems the changed bits are marked in the upper 16 bit, while the
1113d3e51161SHeiko Stübner  * changed value gets set in the same offset in the lower 16 bit.
1114d3e51161SHeiko Stübner  * All pin settings seem to be 2 bit wide in both the upper and lower
1115d3e51161SHeiko Stübner  * parts.
1116d3e51161SHeiko Stübner  * @bank: pin bank to change
1117d3e51161SHeiko Stübner  * @pin: pin to change
1118d3e51161SHeiko Stübner  * @mux: new mux function to set
1119d3e51161SHeiko Stübner  */
112014797189SHeiko Stübner static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
1121d3e51161SHeiko Stübner {
1122d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1123fc72c923SHeiko Stübner 	int iomux_num = (pin / 8);
112495ec8ae4SHeiko Stübner 	struct regmap *regmap;
1125ea262ad6Sdavid.wu 	int reg, ret, mask, mux_type;
1126d3e51161SHeiko Stübner 	u8 bit;
1127bd35b9bfSDavid Wu 	u32 data, rmask, route_reg, route_val;
1128d3e51161SHeiko Stübner 
112905709c3eSJohn Keeping 	ret = rockchip_verify_mux(bank, pin, mux);
113005709c3eSJohn Keeping 	if (ret < 0)
113105709c3eSJohn Keeping 		return ret;
1132fc72c923SHeiko Stübner 
113305709c3eSJohn Keeping 	if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
1134c4a532deSHeiko Stübner 		return 0;
1135c4a532deSHeiko Stübner 
1136d3e51161SHeiko Stübner 	dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
1137d3e51161SHeiko Stübner 						bank->bank_num, pin, mux);
1138d3e51161SHeiko Stübner 
113995ec8ae4SHeiko Stübner 	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
114095ec8ae4SHeiko Stübner 				? info->regmap_pmu : info->regmap_base;
114195ec8ae4SHeiko Stübner 
1142d3e51161SHeiko Stübner 	/* get basic quadrupel of mux registers and the correct reg inside */
1143ea262ad6Sdavid.wu 	mux_type = bank->iomux[iomux_num].type;
11446bc0d121SHeiko Stübner 	reg = bank->iomux[iomux_num].offset;
1145ea262ad6Sdavid.wu 	if (mux_type & IOMUX_WIDTH_4BIT) {
114603716e1dSHeiko Stübner 		if ((pin % 8) >= 4)
114703716e1dSHeiko Stübner 			reg += 0x4;
114803716e1dSHeiko Stübner 		bit = (pin % 4) * 4;
11498b6c6f93Sdavid.wu 		mask = 0xf;
1150ea262ad6Sdavid.wu 	} else if (mux_type & IOMUX_WIDTH_3BIT) {
11518b6c6f93Sdavid.wu 		if ((pin % 8) >= 5)
11528b6c6f93Sdavid.wu 			reg += 0x4;
11538b6c6f93Sdavid.wu 		bit = (pin % 8 % 5) * 3;
11548b6c6f93Sdavid.wu 		mask = 0x7;
115503716e1dSHeiko Stübner 	} else {
1156d3e51161SHeiko Stübner 		bit = (pin % 8) * 2;
11578b6c6f93Sdavid.wu 		mask = 0x3;
115803716e1dSHeiko Stübner 	}
1159d3e51161SHeiko Stübner 
1160c04c3fa6SDavid Wu 	if (bank->recalced_mask & BIT(pin))
1161c04c3fa6SDavid Wu 		rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
1162ea262ad6Sdavid.wu 
1163bd35b9bfSDavid Wu 	if (bank->route_mask & BIT(pin)) {
1164bd35b9bfSDavid Wu 		if (rockchip_get_mux_route(bank, pin, mux, &route_reg,
1165bd35b9bfSDavid Wu 					   &route_val)) {
1166bd35b9bfSDavid Wu 			ret = regmap_write(regmap, route_reg, route_val);
1167bd35b9bfSDavid Wu 			if (ret)
1168bd35b9bfSDavid Wu 				return ret;
1169bd35b9bfSDavid Wu 		}
1170bd35b9bfSDavid Wu 	}
1171bd35b9bfSDavid Wu 
117203716e1dSHeiko Stübner 	data = (mask << (bit + 16));
117399e872d9SSonny Rao 	rmask = data | (data >> 16);
117403716e1dSHeiko Stübner 	data |= (mux & mask) << bit;
117599e872d9SSonny Rao 	ret = regmap_update_bits(regmap, reg, rmask, data);
1176d3e51161SHeiko Stübner 
1177751a99abSHeiko Stübner 	return ret;
1178d3e51161SHeiko Stübner }
1179d3e51161SHeiko Stübner 
1180b9c6dcabSAndy Yan #define RV1108_PULL_PMU_OFFSET		0x10
1181b9c6dcabSAndy Yan #define RV1108_PULL_OFFSET		0x110
1182b9c6dcabSAndy Yan #define RV1108_PULL_PINS_PER_REG	8
1183b9c6dcabSAndy Yan #define RV1108_PULL_BITS_PER_PIN	2
1184b9c6dcabSAndy Yan #define RV1108_PULL_BANK_STRIDE		16
1185688daf23SAndy Yan 
1186b9c6dcabSAndy Yan static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1187688daf23SAndy Yan 					 int pin_num, struct regmap **regmap,
1188688daf23SAndy Yan 					 int *reg, u8 *bit)
1189688daf23SAndy Yan {
1190688daf23SAndy Yan 	struct rockchip_pinctrl *info = bank->drvdata;
1191688daf23SAndy Yan 
1192688daf23SAndy Yan 	/* The first 24 pins of the first bank are located in PMU */
1193688daf23SAndy Yan 	if (bank->bank_num == 0) {
1194688daf23SAndy Yan 		*regmap = info->regmap_pmu;
1195b9c6dcabSAndy Yan 		*reg = RV1108_PULL_PMU_OFFSET;
1196688daf23SAndy Yan 	} else {
1197b9c6dcabSAndy Yan 		*reg = RV1108_PULL_OFFSET;
1198688daf23SAndy Yan 		*regmap = info->regmap_base;
1199688daf23SAndy Yan 		/* correct the offset, as we're starting with the 2nd bank */
1200688daf23SAndy Yan 		*reg -= 0x10;
1201b9c6dcabSAndy Yan 		*reg += bank->bank_num * RV1108_PULL_BANK_STRIDE;
1202688daf23SAndy Yan 	}
1203688daf23SAndy Yan 
1204b9c6dcabSAndy Yan 	*reg += ((pin_num / RV1108_PULL_PINS_PER_REG) * 4);
1205b9c6dcabSAndy Yan 	*bit = (pin_num % RV1108_PULL_PINS_PER_REG);
1206b9c6dcabSAndy Yan 	*bit *= RV1108_PULL_BITS_PER_PIN;
1207688daf23SAndy Yan }
1208688daf23SAndy Yan 
1209b9c6dcabSAndy Yan #define RV1108_DRV_PMU_OFFSET		0x20
1210b9c6dcabSAndy Yan #define RV1108_DRV_GRF_OFFSET		0x210
1211b9c6dcabSAndy Yan #define RV1108_DRV_BITS_PER_PIN		2
1212b9c6dcabSAndy Yan #define RV1108_DRV_PINS_PER_REG		8
1213b9c6dcabSAndy Yan #define RV1108_DRV_BANK_STRIDE		16
1214688daf23SAndy Yan 
1215b9c6dcabSAndy Yan static void rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
1216688daf23SAndy Yan 					int pin_num, struct regmap **regmap,
1217688daf23SAndy Yan 					int *reg, u8 *bit)
1218688daf23SAndy Yan {
1219688daf23SAndy Yan 	struct rockchip_pinctrl *info = bank->drvdata;
1220688daf23SAndy Yan 
1221688daf23SAndy Yan 	/* The first 24 pins of the first bank are located in PMU */
1222688daf23SAndy Yan 	if (bank->bank_num == 0) {
1223688daf23SAndy Yan 		*regmap = info->regmap_pmu;
1224b9c6dcabSAndy Yan 		*reg = RV1108_DRV_PMU_OFFSET;
1225688daf23SAndy Yan 	} else {
1226688daf23SAndy Yan 		*regmap = info->regmap_base;
1227b9c6dcabSAndy Yan 		*reg = RV1108_DRV_GRF_OFFSET;
1228688daf23SAndy Yan 
1229688daf23SAndy Yan 		/* correct the offset, as we're starting with the 2nd bank */
1230688daf23SAndy Yan 		*reg -= 0x10;
1231b9c6dcabSAndy Yan 		*reg += bank->bank_num * RV1108_DRV_BANK_STRIDE;
1232688daf23SAndy Yan 	}
1233688daf23SAndy Yan 
1234b9c6dcabSAndy Yan 	*reg += ((pin_num / RV1108_DRV_PINS_PER_REG) * 4);
1235b9c6dcabSAndy Yan 	*bit = pin_num % RV1108_DRV_PINS_PER_REG;
1236b9c6dcabSAndy Yan 	*bit *= RV1108_DRV_BITS_PER_PIN;
1237688daf23SAndy Yan }
1238688daf23SAndy Yan 
12395caff7eaSAndy Yan #define RV1108_SCHMITT_PMU_OFFSET		0x30
12405caff7eaSAndy Yan #define RV1108_SCHMITT_GRF_OFFSET		0x388
12415caff7eaSAndy Yan #define RV1108_SCHMITT_BANK_STRIDE		8
12425caff7eaSAndy Yan #define RV1108_SCHMITT_PINS_PER_GRF_REG		16
12435caff7eaSAndy Yan #define RV1108_SCHMITT_PINS_PER_PMU_REG		8
12445caff7eaSAndy Yan 
12455caff7eaSAndy Yan static int rv1108_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
12465caff7eaSAndy Yan 					   int pin_num,
12475caff7eaSAndy Yan 					   struct regmap **regmap,
12485caff7eaSAndy Yan 					   int *reg, u8 *bit)
12495caff7eaSAndy Yan {
12505caff7eaSAndy Yan 	struct rockchip_pinctrl *info = bank->drvdata;
12515caff7eaSAndy Yan 	int pins_per_reg;
12525caff7eaSAndy Yan 
12535caff7eaSAndy Yan 	if (bank->bank_num == 0) {
12545caff7eaSAndy Yan 		*regmap = info->regmap_pmu;
12555caff7eaSAndy Yan 		*reg = RV1108_SCHMITT_PMU_OFFSET;
12565caff7eaSAndy Yan 		pins_per_reg = RV1108_SCHMITT_PINS_PER_PMU_REG;
12575caff7eaSAndy Yan 	} else {
12585caff7eaSAndy Yan 		*regmap = info->regmap_base;
12595caff7eaSAndy Yan 		*reg = RV1108_SCHMITT_GRF_OFFSET;
12605caff7eaSAndy Yan 		pins_per_reg = RV1108_SCHMITT_PINS_PER_GRF_REG;
12615caff7eaSAndy Yan 		*reg += (bank->bank_num  - 1) * RV1108_SCHMITT_BANK_STRIDE;
12625caff7eaSAndy Yan 	}
12635caff7eaSAndy Yan 	*reg += ((pin_num / pins_per_reg) * 4);
12645caff7eaSAndy Yan 	*bit = pin_num % pins_per_reg;
12655caff7eaSAndy Yan 
12665caff7eaSAndy Yan 	return 0;
12675caff7eaSAndy Yan }
12685caff7eaSAndy Yan 
1269a282926dSHeiko Stübner #define RK2928_PULL_OFFSET		0x118
1270a282926dSHeiko Stübner #define RK2928_PULL_PINS_PER_REG	16
1271a282926dSHeiko Stübner #define RK2928_PULL_BANK_STRIDE		8
1272a282926dSHeiko Stübner 
1273a282926dSHeiko Stübner static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1274751a99abSHeiko Stübner 				    int pin_num, struct regmap **regmap,
1275751a99abSHeiko Stübner 				    int *reg, u8 *bit)
1276a282926dSHeiko Stübner {
1277a282926dSHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1278a282926dSHeiko Stübner 
1279751a99abSHeiko Stübner 	*regmap = info->regmap_base;
1280751a99abSHeiko Stübner 	*reg = RK2928_PULL_OFFSET;
1281a282926dSHeiko Stübner 	*reg += bank->bank_num * RK2928_PULL_BANK_STRIDE;
1282a282926dSHeiko Stübner 	*reg += (pin_num / RK2928_PULL_PINS_PER_REG) * 4;
1283a282926dSHeiko Stübner 
1284a282926dSHeiko Stübner 	*bit = pin_num % RK2928_PULL_PINS_PER_REG;
1285a282926dSHeiko Stübner };
1286a282926dSHeiko Stübner 
1287d23c66dfSDavid Wu #define RK3128_PULL_OFFSET	0x118
1288d23c66dfSDavid Wu 
1289d23c66dfSDavid Wu static void rk3128_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1290d23c66dfSDavid Wu 					 int pin_num, struct regmap **regmap,
1291d23c66dfSDavid Wu 					 int *reg, u8 *bit)
1292d23c66dfSDavid Wu {
1293d23c66dfSDavid Wu 	struct rockchip_pinctrl *info = bank->drvdata;
1294d23c66dfSDavid Wu 
1295d23c66dfSDavid Wu 	*regmap = info->regmap_base;
1296d23c66dfSDavid Wu 	*reg = RK3128_PULL_OFFSET;
1297d23c66dfSDavid Wu 	*reg += bank->bank_num * RK2928_PULL_BANK_STRIDE;
1298d23c66dfSDavid Wu 	*reg += ((pin_num / RK2928_PULL_PINS_PER_REG) * 4);
1299d23c66dfSDavid Wu 
1300d23c66dfSDavid Wu 	*bit = pin_num % RK2928_PULL_PINS_PER_REG;
1301d23c66dfSDavid Wu }
1302d23c66dfSDavid Wu 
1303bfc7a42aSHeiko Stübner #define RK3188_PULL_OFFSET		0x164
13046ca5274dSHeiko Stübner #define RK3188_PULL_BITS_PER_PIN	2
13056ca5274dSHeiko Stübner #define RK3188_PULL_PINS_PER_REG	8
13066ca5274dSHeiko Stübner #define RK3188_PULL_BANK_STRIDE		16
130714dee867SHeiko Stübner #define RK3188_PULL_PMU_OFFSET		0x64
13086ca5274dSHeiko Stübner 
13096ca5274dSHeiko Stübner static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1310751a99abSHeiko Stübner 				    int pin_num, struct regmap **regmap,
1311751a99abSHeiko Stübner 				    int *reg, u8 *bit)
13126ca5274dSHeiko Stübner {
13136ca5274dSHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
13146ca5274dSHeiko Stübner 
13156ca5274dSHeiko Stübner 	/* The first 12 pins of the first bank are located elsewhere */
1316fc72c923SHeiko Stübner 	if (bank->bank_num == 0 && pin_num < 12) {
131714dee867SHeiko Stübner 		*regmap = info->regmap_pmu ? info->regmap_pmu
131814dee867SHeiko Stübner 					   : bank->regmap_pull;
131914dee867SHeiko Stübner 		*reg = info->regmap_pmu ? RK3188_PULL_PMU_OFFSET : 0;
1320751a99abSHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
13216ca5274dSHeiko Stübner 		*bit = pin_num % RK3188_PULL_PINS_PER_REG;
13226ca5274dSHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
13236ca5274dSHeiko Stübner 	} else {
1324751a99abSHeiko Stübner 		*regmap = info->regmap_pull ? info->regmap_pull
1325751a99abSHeiko Stübner 					    : info->regmap_base;
1326751a99abSHeiko Stübner 		*reg = info->regmap_pull ? 0 : RK3188_PULL_OFFSET;
1327751a99abSHeiko Stübner 
1328bfc7a42aSHeiko Stübner 		/* correct the offset, as it is the 2nd pull register */
1329bfc7a42aSHeiko Stübner 		*reg -= 4;
13306ca5274dSHeiko Stübner 		*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
13316ca5274dSHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
13326ca5274dSHeiko Stübner 
13336ca5274dSHeiko Stübner 		/*
13346ca5274dSHeiko Stübner 		 * The bits in these registers have an inverse ordering
13356ca5274dSHeiko Stübner 		 * with the lowest pin being in bits 15:14 and the highest
13366ca5274dSHeiko Stübner 		 * pin in bits 1:0
13376ca5274dSHeiko Stübner 		 */
13386ca5274dSHeiko Stübner 		*bit = 7 - (pin_num % RK3188_PULL_PINS_PER_REG);
13396ca5274dSHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
13406ca5274dSHeiko Stübner 	}
13416ca5274dSHeiko Stübner }
13426ca5274dSHeiko Stübner 
1343304f077dSHeiko Stübner #define RK3288_PULL_OFFSET		0x140
1344304f077dSHeiko Stübner static void rk3288_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1345304f077dSHeiko Stübner 				    int pin_num, struct regmap **regmap,
1346304f077dSHeiko Stübner 				    int *reg, u8 *bit)
1347304f077dSHeiko Stübner {
1348304f077dSHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1349304f077dSHeiko Stübner 
1350304f077dSHeiko Stübner 	/* The first 24 pins of the first bank are located in PMU */
1351304f077dSHeiko Stübner 	if (bank->bank_num == 0) {
1352304f077dSHeiko Stübner 		*regmap = info->regmap_pmu;
1353304f077dSHeiko Stübner 		*reg = RK3188_PULL_PMU_OFFSET;
1354304f077dSHeiko Stübner 
1355304f077dSHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1356304f077dSHeiko Stübner 		*bit = pin_num % RK3188_PULL_PINS_PER_REG;
1357304f077dSHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
1358304f077dSHeiko Stübner 	} else {
1359304f077dSHeiko Stübner 		*regmap = info->regmap_base;
1360304f077dSHeiko Stübner 		*reg = RK3288_PULL_OFFSET;
1361304f077dSHeiko Stübner 
1362304f077dSHeiko Stübner 		/* correct the offset, as we're starting with the 2nd bank */
1363304f077dSHeiko Stübner 		*reg -= 0x10;
1364304f077dSHeiko Stübner 		*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
1365304f077dSHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1366304f077dSHeiko Stübner 
1367304f077dSHeiko Stübner 		*bit = (pin_num % RK3188_PULL_PINS_PER_REG);
1368304f077dSHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
1369304f077dSHeiko Stübner 	}
1370304f077dSHeiko Stübner }
1371304f077dSHeiko Stübner 
1372b547c800SHeiko Stübner #define RK3288_DRV_PMU_OFFSET		0x70
1373b547c800SHeiko Stübner #define RK3288_DRV_GRF_OFFSET		0x1c0
1374b547c800SHeiko Stübner #define RK3288_DRV_BITS_PER_PIN		2
1375b547c800SHeiko Stübner #define RK3288_DRV_PINS_PER_REG		8
1376b547c800SHeiko Stübner #define RK3288_DRV_BANK_STRIDE		16
1377b547c800SHeiko Stübner 
1378b547c800SHeiko Stübner static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
1379b547c800SHeiko Stübner 				    int pin_num, struct regmap **regmap,
1380b547c800SHeiko Stübner 				    int *reg, u8 *bit)
1381b547c800SHeiko Stübner {
1382b547c800SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1383b547c800SHeiko Stübner 
1384b547c800SHeiko Stübner 	/* The first 24 pins of the first bank are located in PMU */
1385b547c800SHeiko Stübner 	if (bank->bank_num == 0) {
1386b547c800SHeiko Stübner 		*regmap = info->regmap_pmu;
1387b547c800SHeiko Stübner 		*reg = RK3288_DRV_PMU_OFFSET;
1388b547c800SHeiko Stübner 
1389b547c800SHeiko Stübner 		*reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
1390b547c800SHeiko Stübner 		*bit = pin_num % RK3288_DRV_PINS_PER_REG;
1391b547c800SHeiko Stübner 		*bit *= RK3288_DRV_BITS_PER_PIN;
1392b547c800SHeiko Stübner 	} else {
1393b547c800SHeiko Stübner 		*regmap = info->regmap_base;
1394b547c800SHeiko Stübner 		*reg = RK3288_DRV_GRF_OFFSET;
1395b547c800SHeiko Stübner 
1396b547c800SHeiko Stübner 		/* correct the offset, as we're starting with the 2nd bank */
1397b547c800SHeiko Stübner 		*reg -= 0x10;
1398b547c800SHeiko Stübner 		*reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
1399b547c800SHeiko Stübner 		*reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
1400b547c800SHeiko Stübner 
1401b547c800SHeiko Stübner 		*bit = (pin_num % RK3288_DRV_PINS_PER_REG);
1402b547c800SHeiko Stübner 		*bit *= RK3288_DRV_BITS_PER_PIN;
1403b547c800SHeiko Stübner 	}
1404b547c800SHeiko Stübner }
1405b547c800SHeiko Stübner 
1406fea0fe60SJeffy Chen #define RK3228_PULL_OFFSET		0x100
1407fea0fe60SJeffy Chen 
1408fea0fe60SJeffy Chen static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1409fea0fe60SJeffy Chen 				    int pin_num, struct regmap **regmap,
1410fea0fe60SJeffy Chen 				    int *reg, u8 *bit)
1411fea0fe60SJeffy Chen {
1412fea0fe60SJeffy Chen 	struct rockchip_pinctrl *info = bank->drvdata;
1413fea0fe60SJeffy Chen 
1414fea0fe60SJeffy Chen 	*regmap = info->regmap_base;
1415fea0fe60SJeffy Chen 	*reg = RK3228_PULL_OFFSET;
1416fea0fe60SJeffy Chen 	*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
1417fea0fe60SJeffy Chen 	*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1418fea0fe60SJeffy Chen 
1419fea0fe60SJeffy Chen 	*bit = (pin_num % RK3188_PULL_PINS_PER_REG);
1420fea0fe60SJeffy Chen 	*bit *= RK3188_PULL_BITS_PER_PIN;
1421fea0fe60SJeffy Chen }
1422fea0fe60SJeffy Chen 
1423fea0fe60SJeffy Chen #define RK3228_DRV_GRF_OFFSET		0x200
1424fea0fe60SJeffy Chen 
1425fea0fe60SJeffy Chen static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
1426fea0fe60SJeffy Chen 				    int pin_num, struct regmap **regmap,
1427fea0fe60SJeffy Chen 				    int *reg, u8 *bit)
1428fea0fe60SJeffy Chen {
1429fea0fe60SJeffy Chen 	struct rockchip_pinctrl *info = bank->drvdata;
1430fea0fe60SJeffy Chen 
1431fea0fe60SJeffy Chen 	*regmap = info->regmap_base;
1432fea0fe60SJeffy Chen 	*reg = RK3228_DRV_GRF_OFFSET;
1433fea0fe60SJeffy Chen 	*reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
1434fea0fe60SJeffy Chen 	*reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
1435fea0fe60SJeffy Chen 
1436fea0fe60SJeffy Chen 	*bit = (pin_num % RK3288_DRV_PINS_PER_REG);
1437fea0fe60SJeffy Chen 	*bit *= RK3288_DRV_BITS_PER_PIN;
1438fea0fe60SJeffy Chen }
1439fea0fe60SJeffy Chen 
1440daecdc66SHeiko Stübner #define RK3368_PULL_GRF_OFFSET		0x100
1441daecdc66SHeiko Stübner #define RK3368_PULL_PMU_OFFSET		0x10
1442daecdc66SHeiko Stübner 
1443daecdc66SHeiko Stübner static void rk3368_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1444daecdc66SHeiko Stübner 				    int pin_num, struct regmap **regmap,
1445daecdc66SHeiko Stübner 				    int *reg, u8 *bit)
1446daecdc66SHeiko Stübner {
1447daecdc66SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1448daecdc66SHeiko Stübner 
1449daecdc66SHeiko Stübner 	/* The first 32 pins of the first bank are located in PMU */
1450daecdc66SHeiko Stübner 	if (bank->bank_num == 0) {
1451daecdc66SHeiko Stübner 		*regmap = info->regmap_pmu;
1452daecdc66SHeiko Stübner 		*reg = RK3368_PULL_PMU_OFFSET;
1453daecdc66SHeiko Stübner 
1454daecdc66SHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1455daecdc66SHeiko Stübner 		*bit = pin_num % RK3188_PULL_PINS_PER_REG;
1456daecdc66SHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
1457daecdc66SHeiko Stübner 	} else {
1458daecdc66SHeiko Stübner 		*regmap = info->regmap_base;
1459daecdc66SHeiko Stübner 		*reg = RK3368_PULL_GRF_OFFSET;
1460daecdc66SHeiko Stübner 
1461daecdc66SHeiko Stübner 		/* correct the offset, as we're starting with the 2nd bank */
1462daecdc66SHeiko Stübner 		*reg -= 0x10;
1463daecdc66SHeiko Stübner 		*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
1464daecdc66SHeiko Stübner 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1465daecdc66SHeiko Stübner 
1466daecdc66SHeiko Stübner 		*bit = (pin_num % RK3188_PULL_PINS_PER_REG);
1467daecdc66SHeiko Stübner 		*bit *= RK3188_PULL_BITS_PER_PIN;
1468daecdc66SHeiko Stübner 	}
1469daecdc66SHeiko Stübner }
1470daecdc66SHeiko Stübner 
1471daecdc66SHeiko Stübner #define RK3368_DRV_PMU_OFFSET		0x20
1472daecdc66SHeiko Stübner #define RK3368_DRV_GRF_OFFSET		0x200
1473daecdc66SHeiko Stübner 
1474daecdc66SHeiko Stübner static void rk3368_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
1475daecdc66SHeiko Stübner 				    int pin_num, struct regmap **regmap,
1476daecdc66SHeiko Stübner 				    int *reg, u8 *bit)
1477daecdc66SHeiko Stübner {
1478daecdc66SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1479daecdc66SHeiko Stübner 
1480daecdc66SHeiko Stübner 	/* The first 32 pins of the first bank are located in PMU */
1481daecdc66SHeiko Stübner 	if (bank->bank_num == 0) {
1482daecdc66SHeiko Stübner 		*regmap = info->regmap_pmu;
1483daecdc66SHeiko Stübner 		*reg = RK3368_DRV_PMU_OFFSET;
1484daecdc66SHeiko Stübner 
1485daecdc66SHeiko Stübner 		*reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
1486daecdc66SHeiko Stübner 		*bit = pin_num % RK3288_DRV_PINS_PER_REG;
1487daecdc66SHeiko Stübner 		*bit *= RK3288_DRV_BITS_PER_PIN;
1488daecdc66SHeiko Stübner 	} else {
1489daecdc66SHeiko Stübner 		*regmap = info->regmap_base;
1490daecdc66SHeiko Stübner 		*reg = RK3368_DRV_GRF_OFFSET;
1491daecdc66SHeiko Stübner 
1492daecdc66SHeiko Stübner 		/* correct the offset, as we're starting with the 2nd bank */
1493daecdc66SHeiko Stübner 		*reg -= 0x10;
1494daecdc66SHeiko Stübner 		*reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
1495daecdc66SHeiko Stübner 		*reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
1496daecdc66SHeiko Stübner 
1497daecdc66SHeiko Stübner 		*bit = (pin_num % RK3288_DRV_PINS_PER_REG);
1498daecdc66SHeiko Stübner 		*bit *= RK3288_DRV_BITS_PER_PIN;
1499daecdc66SHeiko Stübner 	}
1500daecdc66SHeiko Stübner }
1501daecdc66SHeiko Stübner 
1502b6c23275SDavid Wu #define RK3399_PULL_GRF_OFFSET		0xe040
1503b6c23275SDavid Wu #define RK3399_PULL_PMU_OFFSET		0x40
1504b6c23275SDavid Wu #define RK3399_DRV_3BITS_PER_PIN	3
1505b6c23275SDavid Wu 
1506b6c23275SDavid Wu static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
1507b6c23275SDavid Wu 					 int pin_num, struct regmap **regmap,
1508b6c23275SDavid Wu 					 int *reg, u8 *bit)
1509b6c23275SDavid Wu {
1510b6c23275SDavid Wu 	struct rockchip_pinctrl *info = bank->drvdata;
1511b6c23275SDavid Wu 
1512b6c23275SDavid Wu 	/* The bank0:16 and bank1:32 pins are located in PMU */
1513b6c23275SDavid Wu 	if ((bank->bank_num == 0) || (bank->bank_num == 1)) {
1514b6c23275SDavid Wu 		*regmap = info->regmap_pmu;
1515b6c23275SDavid Wu 		*reg = RK3399_PULL_PMU_OFFSET;
1516b6c23275SDavid Wu 
1517b6c23275SDavid Wu 		*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
1518b6c23275SDavid Wu 
1519b6c23275SDavid Wu 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1520b6c23275SDavid Wu 		*bit = pin_num % RK3188_PULL_PINS_PER_REG;
1521b6c23275SDavid Wu 		*bit *= RK3188_PULL_BITS_PER_PIN;
1522b6c23275SDavid Wu 	} else {
1523b6c23275SDavid Wu 		*regmap = info->regmap_base;
1524b6c23275SDavid Wu 		*reg = RK3399_PULL_GRF_OFFSET;
1525b6c23275SDavid Wu 
1526b6c23275SDavid Wu 		/* correct the offset, as we're starting with the 3rd bank */
1527b6c23275SDavid Wu 		*reg -= 0x20;
1528b6c23275SDavid Wu 		*reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
1529b6c23275SDavid Wu 		*reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
1530b6c23275SDavid Wu 
1531b6c23275SDavid Wu 		*bit = (pin_num % RK3188_PULL_PINS_PER_REG);
1532b6c23275SDavid Wu 		*bit *= RK3188_PULL_BITS_PER_PIN;
1533b6c23275SDavid Wu 	}
1534b6c23275SDavid Wu }
1535b6c23275SDavid Wu 
1536b6c23275SDavid Wu static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
1537b6c23275SDavid Wu 					int pin_num, struct regmap **regmap,
1538b6c23275SDavid Wu 					int *reg, u8 *bit)
1539b6c23275SDavid Wu {
1540b6c23275SDavid Wu 	struct rockchip_pinctrl *info = bank->drvdata;
1541b6c23275SDavid Wu 	int drv_num = (pin_num / 8);
1542b6c23275SDavid Wu 
1543b6c23275SDavid Wu 	/*  The bank0:16 and bank1:32 pins are located in PMU */
1544b6c23275SDavid Wu 	if ((bank->bank_num == 0) || (bank->bank_num == 1))
1545b6c23275SDavid Wu 		*regmap = info->regmap_pmu;
1546b6c23275SDavid Wu 	else
1547b6c23275SDavid Wu 		*regmap = info->regmap_base;
1548b6c23275SDavid Wu 
1549b6c23275SDavid Wu 	*reg = bank->drv[drv_num].offset;
1550b6c23275SDavid Wu 	if ((bank->drv[drv_num].drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||
1551b6c23275SDavid Wu 	    (bank->drv[drv_num].drv_type == DRV_TYPE_IO_3V3_ONLY))
1552b6c23275SDavid Wu 		*bit = (pin_num % 8) * 3;
1553b6c23275SDavid Wu 	else
1554b6c23275SDavid Wu 		*bit = (pin_num % 8) * 2;
1555b6c23275SDavid Wu }
1556b6c23275SDavid Wu 
1557b6c23275SDavid Wu static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = {
1558b6c23275SDavid Wu 	{ 2, 4, 8, 12, -1, -1, -1, -1 },
1559b6c23275SDavid Wu 	{ 3, 6, 9, 12, -1, -1, -1, -1 },
1560b6c23275SDavid Wu 	{ 5, 10, 15, 20, -1, -1, -1, -1 },
1561b6c23275SDavid Wu 	{ 4, 6, 8, 10, 12, 14, 16, 18 },
1562b6c23275SDavid Wu 	{ 4, 7, 10, 13, 16, 19, 22, 26 }
1563b6c23275SDavid Wu };
1564ef17f69fSHeiko Stübner 
1565ef17f69fSHeiko Stübner static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank,
1566ef17f69fSHeiko Stübner 				     int pin_num)
1567b547c800SHeiko Stübner {
1568ef17f69fSHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1569ef17f69fSHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1570b547c800SHeiko Stübner 	struct regmap *regmap;
1571b547c800SHeiko Stübner 	int reg, ret;
1572b6c23275SDavid Wu 	u32 data, temp, rmask_bits;
1573b547c800SHeiko Stübner 	u8 bit;
1574b6c23275SDavid Wu 	int drv_type = bank->drv[pin_num / 8].drv_type;
1575b547c800SHeiko Stübner 
1576ef17f69fSHeiko Stübner 	ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1577b547c800SHeiko Stübner 
1578b6c23275SDavid Wu 	switch (drv_type) {
1579b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_3V0_AUTO:
1580b6c23275SDavid Wu 	case DRV_TYPE_IO_3V3_ONLY:
1581b6c23275SDavid Wu 		rmask_bits = RK3399_DRV_3BITS_PER_PIN;
1582b6c23275SDavid Wu 		switch (bit) {
1583b6c23275SDavid Wu 		case 0 ... 12:
1584b6c23275SDavid Wu 			/* regular case, nothing to do */
1585b6c23275SDavid Wu 			break;
1586b6c23275SDavid Wu 		case 15:
1587b6c23275SDavid Wu 			/*
1588b6c23275SDavid Wu 			 * drive-strength offset is special, as it is
1589b6c23275SDavid Wu 			 * spread over 2 registers
1590b6c23275SDavid Wu 			 */
1591b6c23275SDavid Wu 			ret = regmap_read(regmap, reg, &data);
1592b6c23275SDavid Wu 			if (ret)
1593b6c23275SDavid Wu 				return ret;
1594b6c23275SDavid Wu 
1595b6c23275SDavid Wu 			ret = regmap_read(regmap, reg + 0x4, &temp);
1596b6c23275SDavid Wu 			if (ret)
1597b6c23275SDavid Wu 				return ret;
1598b6c23275SDavid Wu 
1599b6c23275SDavid Wu 			/*
1600b6c23275SDavid Wu 			 * the bit data[15] contains bit 0 of the value
1601b6c23275SDavid Wu 			 * while temp[1:0] contains bits 2 and 1
1602b6c23275SDavid Wu 			 */
1603b6c23275SDavid Wu 			data >>= 15;
1604b6c23275SDavid Wu 			temp &= 0x3;
1605b6c23275SDavid Wu 			temp <<= 1;
1606b6c23275SDavid Wu 			data |= temp;
1607b6c23275SDavid Wu 
1608b6c23275SDavid Wu 			return rockchip_perpin_drv_list[drv_type][data];
1609b6c23275SDavid Wu 		case 18 ... 21:
1610b6c23275SDavid Wu 			/* setting fully enclosed in the second register */
1611b6c23275SDavid Wu 			reg += 4;
1612b6c23275SDavid Wu 			bit -= 16;
1613b6c23275SDavid Wu 			break;
1614b6c23275SDavid Wu 		default:
1615b6c23275SDavid Wu 			dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n",
1616b6c23275SDavid Wu 				bit, drv_type);
1617b6c23275SDavid Wu 			return -EINVAL;
1618b6c23275SDavid Wu 		}
1619b6c23275SDavid Wu 
1620b6c23275SDavid Wu 		break;
1621b6c23275SDavid Wu 	case DRV_TYPE_IO_DEFAULT:
1622b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_OR_3V0:
1623b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_ONLY:
1624b6c23275SDavid Wu 		rmask_bits = RK3288_DRV_BITS_PER_PIN;
1625b6c23275SDavid Wu 		break;
1626b6c23275SDavid Wu 	default:
1627b6c23275SDavid Wu 		dev_err(info->dev, "unsupported pinctrl drive type: %d\n",
1628b6c23275SDavid Wu 			drv_type);
1629b6c23275SDavid Wu 		return -EINVAL;
1630b6c23275SDavid Wu 	}
1631b6c23275SDavid Wu 
1632b547c800SHeiko Stübner 	ret = regmap_read(regmap, reg, &data);
1633b547c800SHeiko Stübner 	if (ret)
1634b547c800SHeiko Stübner 		return ret;
1635b547c800SHeiko Stübner 
1636b547c800SHeiko Stübner 	data >>= bit;
1637b6c23275SDavid Wu 	data &= (1 << rmask_bits) - 1;
1638b547c800SHeiko Stübner 
1639b6c23275SDavid Wu 	return rockchip_perpin_drv_list[drv_type][data];
1640b547c800SHeiko Stübner }
1641b547c800SHeiko Stübner 
1642ef17f69fSHeiko Stübner static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
1643ef17f69fSHeiko Stübner 				     int pin_num, int strength)
1644b547c800SHeiko Stübner {
1645b547c800SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1646ef17f69fSHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1647b547c800SHeiko Stübner 	struct regmap *regmap;
1648b547c800SHeiko Stübner 	int reg, ret, i;
1649b6c23275SDavid Wu 	u32 data, rmask, rmask_bits, temp;
1650b547c800SHeiko Stübner 	u8 bit;
1651b6c23275SDavid Wu 	int drv_type = bank->drv[pin_num / 8].drv_type;
1652b6c23275SDavid Wu 
1653b6c23275SDavid Wu 	dev_dbg(info->dev, "setting drive of GPIO%d-%d to %d\n",
1654b6c23275SDavid Wu 		bank->bank_num, pin_num, strength);
1655b547c800SHeiko Stübner 
1656ef17f69fSHeiko Stübner 	ctrl->drv_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1657b547c800SHeiko Stübner 
1658b547c800SHeiko Stübner 	ret = -EINVAL;
1659b6c23275SDavid Wu 	for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[drv_type]); i++) {
1660b6c23275SDavid Wu 		if (rockchip_perpin_drv_list[drv_type][i] == strength) {
1661b547c800SHeiko Stübner 			ret = i;
1662b547c800SHeiko Stübner 			break;
1663b6c23275SDavid Wu 		} else if (rockchip_perpin_drv_list[drv_type][i] < 0) {
1664b6c23275SDavid Wu 			ret = rockchip_perpin_drv_list[drv_type][i];
1665b6c23275SDavid Wu 			break;
1666b547c800SHeiko Stübner 		}
1667b547c800SHeiko Stübner 	}
1668b547c800SHeiko Stübner 
1669b547c800SHeiko Stübner 	if (ret < 0) {
1670b547c800SHeiko Stübner 		dev_err(info->dev, "unsupported driver strength %d\n",
1671b547c800SHeiko Stübner 			strength);
1672b547c800SHeiko Stübner 		return ret;
1673b547c800SHeiko Stübner 	}
1674b547c800SHeiko Stübner 
1675b6c23275SDavid Wu 	switch (drv_type) {
1676b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_3V0_AUTO:
1677b6c23275SDavid Wu 	case DRV_TYPE_IO_3V3_ONLY:
1678b6c23275SDavid Wu 		rmask_bits = RK3399_DRV_3BITS_PER_PIN;
1679b6c23275SDavid Wu 		switch (bit) {
1680b6c23275SDavid Wu 		case 0 ... 12:
1681b6c23275SDavid Wu 			/* regular case, nothing to do */
1682b6c23275SDavid Wu 			break;
1683b6c23275SDavid Wu 		case 15:
1684b6c23275SDavid Wu 			/*
1685b6c23275SDavid Wu 			 * drive-strength offset is special, as it is spread
1686b6c23275SDavid Wu 			 * over 2 registers, the bit data[15] contains bit 0
1687b6c23275SDavid Wu 			 * of the value while temp[1:0] contains bits 2 and 1
1688b6c23275SDavid Wu 			 */
1689b6c23275SDavid Wu 			data = (ret & 0x1) << 15;
1690b6c23275SDavid Wu 			temp = (ret >> 0x1) & 0x3;
1691b6c23275SDavid Wu 
1692b6c23275SDavid Wu 			rmask = BIT(15) | BIT(31);
1693b6c23275SDavid Wu 			data |= BIT(31);
1694b6c23275SDavid Wu 			ret = regmap_update_bits(regmap, reg, rmask, data);
1695f07bedc3SJohn Keeping 			if (ret)
1696b6c23275SDavid Wu 				return ret;
1697b6c23275SDavid Wu 
1698b6c23275SDavid Wu 			rmask = 0x3 | (0x3 << 16);
1699b6c23275SDavid Wu 			temp |= (0x3 << 16);
1700b6c23275SDavid Wu 			reg += 0x4;
1701b6c23275SDavid Wu 			ret = regmap_update_bits(regmap, reg, rmask, temp);
1702b6c23275SDavid Wu 
1703b6c23275SDavid Wu 			return ret;
1704b6c23275SDavid Wu 		case 18 ... 21:
1705b6c23275SDavid Wu 			/* setting fully enclosed in the second register */
1706b6c23275SDavid Wu 			reg += 4;
1707b6c23275SDavid Wu 			bit -= 16;
1708b6c23275SDavid Wu 			break;
1709b6c23275SDavid Wu 		default:
1710b6c23275SDavid Wu 			dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n",
1711b6c23275SDavid Wu 				bit, drv_type);
1712b6c23275SDavid Wu 			return -EINVAL;
1713b6c23275SDavid Wu 		}
1714b6c23275SDavid Wu 		break;
1715b6c23275SDavid Wu 	case DRV_TYPE_IO_DEFAULT:
1716b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_OR_3V0:
1717b6c23275SDavid Wu 	case DRV_TYPE_IO_1V8_ONLY:
1718b6c23275SDavid Wu 		rmask_bits = RK3288_DRV_BITS_PER_PIN;
1719b6c23275SDavid Wu 		break;
1720b6c23275SDavid Wu 	default:
1721b6c23275SDavid Wu 		dev_err(info->dev, "unsupported pinctrl drive type: %d\n",
1722b6c23275SDavid Wu 			drv_type);
1723b6c23275SDavid Wu 		return -EINVAL;
1724b6c23275SDavid Wu 	}
1725b6c23275SDavid Wu 
1726b547c800SHeiko Stübner 	/* enable the write to the equivalent lower bits */
1727b6c23275SDavid Wu 	data = ((1 << rmask_bits) - 1) << (bit + 16);
172899e872d9SSonny Rao 	rmask = data | (data >> 16);
1729b547c800SHeiko Stübner 	data |= (ret << bit);
1730b547c800SHeiko Stübner 
173199e872d9SSonny Rao 	ret = regmap_update_bits(regmap, reg, rmask, data);
1732b547c800SHeiko Stübner 
1733b547c800SHeiko Stübner 	return ret;
1734b547c800SHeiko Stübner }
1735b547c800SHeiko Stübner 
17363ba6767aSDavid Wu static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
17373ba6767aSDavid Wu 	{
17383ba6767aSDavid Wu 		PIN_CONFIG_BIAS_DISABLE,
17393ba6767aSDavid Wu 		PIN_CONFIG_BIAS_PULL_UP,
17403ba6767aSDavid Wu 		PIN_CONFIG_BIAS_PULL_DOWN,
17413ba6767aSDavid Wu 		PIN_CONFIG_BIAS_BUS_HOLD
17423ba6767aSDavid Wu 	},
17433ba6767aSDavid Wu 	{
17443ba6767aSDavid Wu 		PIN_CONFIG_BIAS_DISABLE,
17453ba6767aSDavid Wu 		PIN_CONFIG_BIAS_PULL_DOWN,
17463ba6767aSDavid Wu 		PIN_CONFIG_BIAS_DISABLE,
17473ba6767aSDavid Wu 		PIN_CONFIG_BIAS_PULL_UP
17483ba6767aSDavid Wu 	},
17493ba6767aSDavid Wu };
17503ba6767aSDavid Wu 
1751d3e51161SHeiko Stübner static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
1752d3e51161SHeiko Stübner {
1753d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1754d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1755751a99abSHeiko Stübner 	struct regmap *regmap;
17563ba6767aSDavid Wu 	int reg, ret, pull_type;
1757d3e51161SHeiko Stübner 	u8 bit;
17586ca5274dSHeiko Stübner 	u32 data;
1759d3e51161SHeiko Stübner 
1760d3e51161SHeiko Stübner 	/* rk3066b does support any pulls */
1761a282926dSHeiko Stübner 	if (ctrl->type == RK3066B)
1762d3e51161SHeiko Stübner 		return PIN_CONFIG_BIAS_DISABLE;
1763d3e51161SHeiko Stübner 
1764751a99abSHeiko Stübner 	ctrl->pull_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1765751a99abSHeiko Stübner 
1766751a99abSHeiko Stübner 	ret = regmap_read(regmap, reg, &data);
1767751a99abSHeiko Stübner 	if (ret)
1768751a99abSHeiko Stübner 		return ret;
17696ca5274dSHeiko Stübner 
1770a282926dSHeiko Stübner 	switch (ctrl->type) {
1771a282926dSHeiko Stübner 	case RK2928:
1772d23c66dfSDavid Wu 	case RK3128:
1773751a99abSHeiko Stübner 		return !(data & BIT(bit))
1774d3e51161SHeiko Stübner 				? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT
1775d3e51161SHeiko Stübner 				: PIN_CONFIG_BIAS_DISABLE;
1776b9c6dcabSAndy Yan 	case RV1108:
1777a282926dSHeiko Stübner 	case RK3188:
177866d750e1SHeiko Stübner 	case RK3288:
1779daecdc66SHeiko Stübner 	case RK3368:
1780b6c23275SDavid Wu 	case RK3399:
17813ba6767aSDavid Wu 		pull_type = bank->pull_type[pin_num / 8];
1782751a99abSHeiko Stübner 		data >>= bit;
17836ca5274dSHeiko Stübner 		data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
17846ca5274dSHeiko Stübner 
17853ba6767aSDavid Wu 		return rockchip_pull_list[pull_type][data];
1786a282926dSHeiko Stübner 	default:
1787a282926dSHeiko Stübner 		dev_err(info->dev, "unsupported pinctrl type\n");
1788a282926dSHeiko Stübner 		return -EINVAL;
1789a282926dSHeiko Stübner 	};
1790d3e51161SHeiko Stübner }
1791d3e51161SHeiko Stübner 
1792d3e51161SHeiko Stübner static int rockchip_set_pull(struct rockchip_pin_bank *bank,
1793d3e51161SHeiko Stübner 					int pin_num, int pull)
1794d3e51161SHeiko Stübner {
1795d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = bank->drvdata;
1796d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1797751a99abSHeiko Stübner 	struct regmap *regmap;
17983ba6767aSDavid Wu 	int reg, ret, i, pull_type;
1799d3e51161SHeiko Stübner 	u8 bit;
180099e872d9SSonny Rao 	u32 data, rmask;
1801d3e51161SHeiko Stübner 
1802d3e51161SHeiko Stübner 	dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n",
1803d3e51161SHeiko Stübner 		 bank->bank_num, pin_num, pull);
1804d3e51161SHeiko Stübner 
1805d3e51161SHeiko Stübner 	/* rk3066b does support any pulls */
1806a282926dSHeiko Stübner 	if (ctrl->type == RK3066B)
1807d3e51161SHeiko Stübner 		return pull ? -EINVAL : 0;
1808d3e51161SHeiko Stübner 
1809751a99abSHeiko Stübner 	ctrl->pull_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1810d3e51161SHeiko Stübner 
18116ca5274dSHeiko Stübner 	switch (ctrl->type) {
18126ca5274dSHeiko Stübner 	case RK2928:
1813d23c66dfSDavid Wu 	case RK3128:
1814d3e51161SHeiko Stübner 		data = BIT(bit + 16);
1815d3e51161SHeiko Stübner 		if (pull == PIN_CONFIG_BIAS_DISABLE)
1816d3e51161SHeiko Stübner 			data |= BIT(bit);
1817751a99abSHeiko Stübner 		ret = regmap_write(regmap, reg, data);
1818a282926dSHeiko Stübner 		break;
1819b9c6dcabSAndy Yan 	case RV1108:
1820a282926dSHeiko Stübner 	case RK3188:
182166d750e1SHeiko Stübner 	case RK3288:
1822daecdc66SHeiko Stübner 	case RK3368:
1823b6c23275SDavid Wu 	case RK3399:
18243ba6767aSDavid Wu 		pull_type = bank->pull_type[pin_num / 8];
18253ba6767aSDavid Wu 		ret = -EINVAL;
18263ba6767aSDavid Wu 		for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
18273ba6767aSDavid Wu 			i++) {
18283ba6767aSDavid Wu 			if (rockchip_pull_list[pull_type][i] == pull) {
18293ba6767aSDavid Wu 				ret = i;
18303ba6767aSDavid Wu 				break;
18313ba6767aSDavid Wu 			}
18323ba6767aSDavid Wu 		}
18333ba6767aSDavid Wu 
18343ba6767aSDavid Wu 		if (ret < 0) {
18353ba6767aSDavid Wu 			dev_err(info->dev, "unsupported pull setting %d\n",
18363ba6767aSDavid Wu 				pull);
18373ba6767aSDavid Wu 			return ret;
18383ba6767aSDavid Wu 		}
18393ba6767aSDavid Wu 
18406ca5274dSHeiko Stübner 		/* enable the write to the equivalent lower bits */
18416ca5274dSHeiko Stübner 		data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
184299e872d9SSonny Rao 		rmask = data | (data >> 16);
18433ba6767aSDavid Wu 		data |= (ret << bit);
18446ca5274dSHeiko Stübner 
184599e872d9SSonny Rao 		ret = regmap_update_bits(regmap, reg, rmask, data);
18466ca5274dSHeiko Stübner 		break;
1847a282926dSHeiko Stübner 	default:
1848a282926dSHeiko Stübner 		dev_err(info->dev, "unsupported pinctrl type\n");
1849a282926dSHeiko Stübner 		return -EINVAL;
1850d3e51161SHeiko Stübner 	}
1851d3e51161SHeiko Stübner 
1852751a99abSHeiko Stübner 	return ret;
1853d3e51161SHeiko Stübner }
1854d3e51161SHeiko Stübner 
1855728d3f5aSdavid.wu #define RK3328_SCHMITT_BITS_PER_PIN		1
1856728d3f5aSdavid.wu #define RK3328_SCHMITT_PINS_PER_REG		16
1857728d3f5aSdavid.wu #define RK3328_SCHMITT_BANK_STRIDE		8
1858728d3f5aSdavid.wu #define RK3328_SCHMITT_GRF_OFFSET		0x380
1859728d3f5aSdavid.wu 
1860728d3f5aSdavid.wu static int rk3328_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
1861728d3f5aSdavid.wu 					   int pin_num,
1862728d3f5aSdavid.wu 					   struct regmap **regmap,
1863728d3f5aSdavid.wu 					   int *reg, u8 *bit)
1864728d3f5aSdavid.wu {
1865728d3f5aSdavid.wu 	struct rockchip_pinctrl *info = bank->drvdata;
1866728d3f5aSdavid.wu 
1867728d3f5aSdavid.wu 	*regmap = info->regmap_base;
1868728d3f5aSdavid.wu 	*reg = RK3328_SCHMITT_GRF_OFFSET;
1869728d3f5aSdavid.wu 
1870728d3f5aSdavid.wu 	*reg += bank->bank_num * RK3328_SCHMITT_BANK_STRIDE;
1871728d3f5aSdavid.wu 	*reg += ((pin_num / RK3328_SCHMITT_PINS_PER_REG) * 4);
1872728d3f5aSdavid.wu 	*bit = pin_num % RK3328_SCHMITT_PINS_PER_REG;
1873728d3f5aSdavid.wu 
1874728d3f5aSdavid.wu 	return 0;
1875728d3f5aSdavid.wu }
1876728d3f5aSdavid.wu 
1877e3b357d7Sdavid.wu static int rockchip_get_schmitt(struct rockchip_pin_bank *bank, int pin_num)
1878e3b357d7Sdavid.wu {
1879e3b357d7Sdavid.wu 	struct rockchip_pinctrl *info = bank->drvdata;
1880e3b357d7Sdavid.wu 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1881e3b357d7Sdavid.wu 	struct regmap *regmap;
1882e3b357d7Sdavid.wu 	int reg, ret;
1883e3b357d7Sdavid.wu 	u8 bit;
1884e3b357d7Sdavid.wu 	u32 data;
1885e3b357d7Sdavid.wu 
1886e3b357d7Sdavid.wu 	ret = ctrl->schmitt_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1887e3b357d7Sdavid.wu 	if (ret)
1888e3b357d7Sdavid.wu 		return ret;
1889e3b357d7Sdavid.wu 
1890e3b357d7Sdavid.wu 	ret = regmap_read(regmap, reg, &data);
1891e3b357d7Sdavid.wu 	if (ret)
1892e3b357d7Sdavid.wu 		return ret;
1893e3b357d7Sdavid.wu 
1894e3b357d7Sdavid.wu 	data >>= bit;
1895e3b357d7Sdavid.wu 	return data & 0x1;
1896e3b357d7Sdavid.wu }
1897e3b357d7Sdavid.wu 
1898e3b357d7Sdavid.wu static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
1899e3b357d7Sdavid.wu 				int pin_num, int enable)
1900e3b357d7Sdavid.wu {
1901e3b357d7Sdavid.wu 	struct rockchip_pinctrl *info = bank->drvdata;
1902e3b357d7Sdavid.wu 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
1903e3b357d7Sdavid.wu 	struct regmap *regmap;
1904e3b357d7Sdavid.wu 	int reg, ret;
1905e3b357d7Sdavid.wu 	u8 bit;
1906e3b357d7Sdavid.wu 	u32 data, rmask;
1907e3b357d7Sdavid.wu 
1908e3b357d7Sdavid.wu 	dev_dbg(info->dev, "setting input schmitt of GPIO%d-%d to %d\n",
1909e3b357d7Sdavid.wu 		bank->bank_num, pin_num, enable);
1910e3b357d7Sdavid.wu 
1911e3b357d7Sdavid.wu 	ret = ctrl->schmitt_calc_reg(bank, pin_num, &regmap, &reg, &bit);
1912e3b357d7Sdavid.wu 	if (ret)
1913e3b357d7Sdavid.wu 		return ret;
1914e3b357d7Sdavid.wu 
1915e3b357d7Sdavid.wu 	/* enable the write to the equivalent lower bits */
1916e3b357d7Sdavid.wu 	data = BIT(bit + 16) | (enable << bit);
1917e3b357d7Sdavid.wu 	rmask = BIT(bit + 16) | BIT(bit);
1918e3b357d7Sdavid.wu 
1919f07bedc3SJohn Keeping 	return regmap_update_bits(regmap, reg, rmask, data);
1920e3b357d7Sdavid.wu }
1921e3b357d7Sdavid.wu 
1922d3e51161SHeiko Stübner /*
1923d3e51161SHeiko Stübner  * Pinmux_ops handling
1924d3e51161SHeiko Stübner  */
1925d3e51161SHeiko Stübner 
1926d3e51161SHeiko Stübner static int rockchip_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
1927d3e51161SHeiko Stübner {
1928d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1929d3e51161SHeiko Stübner 
1930d3e51161SHeiko Stübner 	return info->nfunctions;
1931d3e51161SHeiko Stübner }
1932d3e51161SHeiko Stübner 
1933d3e51161SHeiko Stübner static const char *rockchip_pmx_get_func_name(struct pinctrl_dev *pctldev,
1934d3e51161SHeiko Stübner 					  unsigned selector)
1935d3e51161SHeiko Stübner {
1936d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1937d3e51161SHeiko Stübner 
1938d3e51161SHeiko Stübner 	return info->functions[selector].name;
1939d3e51161SHeiko Stübner }
1940d3e51161SHeiko Stübner 
1941d3e51161SHeiko Stübner static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev,
1942d3e51161SHeiko Stübner 				unsigned selector, const char * const **groups,
1943d3e51161SHeiko Stübner 				unsigned * const num_groups)
1944d3e51161SHeiko Stübner {
1945d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1946d3e51161SHeiko Stübner 
1947d3e51161SHeiko Stübner 	*groups = info->functions[selector].groups;
1948d3e51161SHeiko Stübner 	*num_groups = info->functions[selector].ngroups;
1949d3e51161SHeiko Stübner 
1950d3e51161SHeiko Stübner 	return 0;
1951d3e51161SHeiko Stübner }
1952d3e51161SHeiko Stübner 
195303e9f0caSLinus Walleij static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
1954d3e51161SHeiko Stübner 			    unsigned group)
1955d3e51161SHeiko Stübner {
1956d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
1957d3e51161SHeiko Stübner 	const unsigned int *pins = info->groups[group].pins;
1958d3e51161SHeiko Stübner 	const struct rockchip_pin_config *data = info->groups[group].data;
1959d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank;
196014797189SHeiko Stübner 	int cnt, ret = 0;
1961d3e51161SHeiko Stübner 
1962d3e51161SHeiko Stübner 	dev_dbg(info->dev, "enable function %s group %s\n",
1963d3e51161SHeiko Stübner 		info->functions[selector].name, info->groups[group].name);
1964d3e51161SHeiko Stübner 
1965d3e51161SHeiko Stübner 	/*
1966d3e51161SHeiko Stübner 	 * for each pin in the pin group selected, program the correspoding pin
1967d3e51161SHeiko Stübner 	 * pin function number in the config register.
1968d3e51161SHeiko Stübner 	 */
1969d3e51161SHeiko Stübner 	for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
1970d3e51161SHeiko Stübner 		bank = pin_to_bank(info, pins[cnt]);
197114797189SHeiko Stübner 		ret = rockchip_set_mux(bank, pins[cnt] - bank->pin_base,
1972d3e51161SHeiko Stübner 				       data[cnt].func);
197314797189SHeiko Stübner 		if (ret)
197414797189SHeiko Stübner 			break;
197514797189SHeiko Stübner 	}
197614797189SHeiko Stübner 
197714797189SHeiko Stübner 	if (ret) {
197814797189SHeiko Stübner 		/* revert the already done pin settings */
197914797189SHeiko Stübner 		for (cnt--; cnt >= 0; cnt--)
198014797189SHeiko Stübner 			rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0);
198114797189SHeiko Stübner 
198214797189SHeiko Stübner 		return ret;
1983d3e51161SHeiko Stübner 	}
1984d3e51161SHeiko Stübner 
1985d3e51161SHeiko Stübner 	return 0;
1986d3e51161SHeiko Stübner }
1987d3e51161SHeiko Stübner 
19886ba20a00SCaesar Wang static int rockchip_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
19896ba20a00SCaesar Wang {
19906ba20a00SCaesar Wang 	struct rockchip_pin_bank *bank = gpiochip_get_data(chip);
19916ba20a00SCaesar Wang 	u32 data;
19926ba20a00SCaesar Wang 
19936ba20a00SCaesar Wang 	data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
19946ba20a00SCaesar Wang 
19956ba20a00SCaesar Wang 	return !(data & BIT(offset));
19966ba20a00SCaesar Wang }
19976ba20a00SCaesar Wang 
1998d3e51161SHeiko Stübner /*
1999d3e51161SHeiko Stübner  * The calls to gpio_direction_output() and gpio_direction_input()
2000d3e51161SHeiko Stübner  * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
2001d3e51161SHeiko Stübner  * function called from the gpiolib interface).
2002d3e51161SHeiko Stübner  */
2003e5c2c9dbSDoug Anderson static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
2004e5c2c9dbSDoug Anderson 					    int pin, bool input)
2005d3e51161SHeiko Stübner {
2006d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank;
2007e5c2c9dbSDoug Anderson 	int ret;
2008fab262f5SDoug Anderson 	unsigned long flags;
2009d3e51161SHeiko Stübner 	u32 data;
2010d3e51161SHeiko Stübner 
201103bf81f1SLinus Walleij 	bank = gpiochip_get_data(chip);
2012d3e51161SHeiko Stübner 
201314797189SHeiko Stübner 	ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
201414797189SHeiko Stübner 	if (ret < 0)
201514797189SHeiko Stübner 		return ret;
2016d3e51161SHeiko Stübner 
201707a06ae9SLin Huang 	clk_enable(bank->clk);
201870b7aa7aSJohn Keeping 	raw_spin_lock_irqsave(&bank->slock, flags);
2019fab262f5SDoug Anderson 
2020d3e51161SHeiko Stübner 	data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
2021d3e51161SHeiko Stübner 	/* set bit to 1 for output, 0 for input */
2022d3e51161SHeiko Stübner 	if (!input)
2023d3e51161SHeiko Stübner 		data |= BIT(pin);
2024d3e51161SHeiko Stübner 	else
2025d3e51161SHeiko Stübner 		data &= ~BIT(pin);
2026d3e51161SHeiko Stübner 	writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
2027d3e51161SHeiko Stübner 
202870b7aa7aSJohn Keeping 	raw_spin_unlock_irqrestore(&bank->slock, flags);
202907a06ae9SLin Huang 	clk_disable(bank->clk);
2030fab262f5SDoug Anderson 
2031d3e51161SHeiko Stübner 	return 0;
2032d3e51161SHeiko Stübner }
2033d3e51161SHeiko Stübner 
2034e5c2c9dbSDoug Anderson static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
2035e5c2c9dbSDoug Anderson 					      struct pinctrl_gpio_range *range,
2036e5c2c9dbSDoug Anderson 					      unsigned offset, bool input)
2037e5c2c9dbSDoug Anderson {
2038e5c2c9dbSDoug Anderson 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
2039e5c2c9dbSDoug Anderson 	struct gpio_chip *chip;
2040e5c2c9dbSDoug Anderson 	int pin;
2041e5c2c9dbSDoug Anderson 
2042e5c2c9dbSDoug Anderson 	chip = range->gc;
2043e5c2c9dbSDoug Anderson 	pin = offset - chip->base;
2044e5c2c9dbSDoug Anderson 	dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
2045e5c2c9dbSDoug Anderson 		 offset, range->name, pin, input ? "input" : "output");
2046e5c2c9dbSDoug Anderson 
2047e5c2c9dbSDoug Anderson 	return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base,
2048e5c2c9dbSDoug Anderson 						input);
2049e5c2c9dbSDoug Anderson }
2050e5c2c9dbSDoug Anderson 
2051d3e51161SHeiko Stübner static const struct pinmux_ops rockchip_pmx_ops = {
2052d3e51161SHeiko Stübner 	.get_functions_count	= rockchip_pmx_get_funcs_count,
2053d3e51161SHeiko Stübner 	.get_function_name	= rockchip_pmx_get_func_name,
2054d3e51161SHeiko Stübner 	.get_function_groups	= rockchip_pmx_get_groups,
205503e9f0caSLinus Walleij 	.set_mux		= rockchip_pmx_set,
2056d3e51161SHeiko Stübner 	.gpio_set_direction	= rockchip_pmx_gpio_set_direction,
2057d3e51161SHeiko Stübner };
2058d3e51161SHeiko Stübner 
2059d3e51161SHeiko Stübner /*
2060d3e51161SHeiko Stübner  * Pinconf_ops handling
2061d3e51161SHeiko Stübner  */
2062d3e51161SHeiko Stübner 
206344b6d930SHeiko Stübner static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
206444b6d930SHeiko Stübner 					enum pin_config_param pull)
206544b6d930SHeiko Stübner {
2066a282926dSHeiko Stübner 	switch (ctrl->type) {
2067a282926dSHeiko Stübner 	case RK2928:
2068d23c66dfSDavid Wu 	case RK3128:
2069a282926dSHeiko Stübner 		return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT ||
2070a282926dSHeiko Stübner 					pull == PIN_CONFIG_BIAS_DISABLE);
2071a282926dSHeiko Stübner 	case RK3066B:
207244b6d930SHeiko Stübner 		return pull ? false : true;
2073b9c6dcabSAndy Yan 	case RV1108:
2074a282926dSHeiko Stübner 	case RK3188:
207566d750e1SHeiko Stübner 	case RK3288:
2076daecdc66SHeiko Stübner 	case RK3368:
2077b6c23275SDavid Wu 	case RK3399:
2078a282926dSHeiko Stübner 		return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
207944b6d930SHeiko Stübner 	}
208044b6d930SHeiko Stübner 
2081a282926dSHeiko Stübner 	return false;
208244b6d930SHeiko Stübner }
208344b6d930SHeiko Stübner 
2084e5c2c9dbSDoug Anderson static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
2085a076e2edSHeiko Stübner static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset);
2086a076e2edSHeiko Stübner 
2087d3e51161SHeiko Stübner /* set the pin config settings for a specified pin */
2088d3e51161SHeiko Stübner static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
208903b054e9SSherman Yin 				unsigned long *configs, unsigned num_configs)
2090d3e51161SHeiko Stübner {
2091d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
2092d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
209303b054e9SSherman Yin 	enum pin_config_param param;
209458957d2eSMika Westerberg 	u32 arg;
209503b054e9SSherman Yin 	int i;
209603b054e9SSherman Yin 	int rc;
209703b054e9SSherman Yin 
209803b054e9SSherman Yin 	for (i = 0; i < num_configs; i++) {
209903b054e9SSherman Yin 		param = pinconf_to_config_param(configs[i]);
210003b054e9SSherman Yin 		arg = pinconf_to_config_argument(configs[i]);
2101d3e51161SHeiko Stübner 
2102d3e51161SHeiko Stübner 		switch (param) {
2103d3e51161SHeiko Stübner 		case PIN_CONFIG_BIAS_DISABLE:
210403b054e9SSherman Yin 			rc =  rockchip_set_pull(bank, pin - bank->pin_base,
210503b054e9SSherman Yin 				param);
210603b054e9SSherman Yin 			if (rc)
210703b054e9SSherman Yin 				return rc;
210844b6d930SHeiko Stübner 			break;
2109d3e51161SHeiko Stübner 		case PIN_CONFIG_BIAS_PULL_UP:
2110d3e51161SHeiko Stübner 		case PIN_CONFIG_BIAS_PULL_DOWN:
2111d3e51161SHeiko Stübner 		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
21126ca5274dSHeiko Stübner 		case PIN_CONFIG_BIAS_BUS_HOLD:
211344b6d930SHeiko Stübner 			if (!rockchip_pinconf_pull_valid(info->ctrl, param))
211444b6d930SHeiko Stübner 				return -ENOTSUPP;
211544b6d930SHeiko Stübner 
211644b6d930SHeiko Stübner 			if (!arg)
211744b6d930SHeiko Stübner 				return -EINVAL;
211844b6d930SHeiko Stübner 
211903b054e9SSherman Yin 			rc = rockchip_set_pull(bank, pin - bank->pin_base,
212003b054e9SSherman Yin 				param);
212103b054e9SSherman Yin 			if (rc)
212203b054e9SSherman Yin 				return rc;
2123d3e51161SHeiko Stübner 			break;
2124a076e2edSHeiko Stübner 		case PIN_CONFIG_OUTPUT:
2125e5c2c9dbSDoug Anderson 			rockchip_gpio_set(&bank->gpio_chip,
2126e5c2c9dbSDoug Anderson 					  pin - bank->pin_base, arg);
2127e5c2c9dbSDoug Anderson 			rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip,
2128e5c2c9dbSDoug Anderson 					  pin - bank->pin_base, false);
2129a076e2edSHeiko Stübner 			if (rc)
2130a076e2edSHeiko Stübner 				return rc;
2131a076e2edSHeiko Stübner 			break;
2132b547c800SHeiko Stübner 		case PIN_CONFIG_DRIVE_STRENGTH:
2133b547c800SHeiko Stübner 			/* rk3288 is the first with per-pin drive-strength */
2134ef17f69fSHeiko Stübner 			if (!info->ctrl->drv_calc_reg)
2135b547c800SHeiko Stübner 				return -ENOTSUPP;
2136b547c800SHeiko Stübner 
2137ef17f69fSHeiko Stübner 			rc = rockchip_set_drive_perpin(bank,
2138ef17f69fSHeiko Stübner 						pin - bank->pin_base, arg);
2139b547c800SHeiko Stübner 			if (rc < 0)
2140b547c800SHeiko Stübner 				return rc;
2141b547c800SHeiko Stübner 			break;
2142e3b357d7Sdavid.wu 		case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
2143e3b357d7Sdavid.wu 			if (!info->ctrl->schmitt_calc_reg)
2144e3b357d7Sdavid.wu 				return -ENOTSUPP;
2145e3b357d7Sdavid.wu 
2146e3b357d7Sdavid.wu 			rc = rockchip_set_schmitt(bank,
2147e3b357d7Sdavid.wu 						  pin - bank->pin_base, arg);
2148e3b357d7Sdavid.wu 			if (rc < 0)
2149e3b357d7Sdavid.wu 				return rc;
2150e3b357d7Sdavid.wu 			break;
2151d3e51161SHeiko Stübner 		default:
2152d3e51161SHeiko Stübner 			return -ENOTSUPP;
2153d3e51161SHeiko Stübner 			break;
2154d3e51161SHeiko Stübner 		}
215503b054e9SSherman Yin 	} /* for each config */
2156d3e51161SHeiko Stübner 
2157d3e51161SHeiko Stübner 	return 0;
2158d3e51161SHeiko Stübner }
2159d3e51161SHeiko Stübner 
2160d3e51161SHeiko Stübner /* get the pin config settings for a specified pin */
2161d3e51161SHeiko Stübner static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
2162d3e51161SHeiko Stübner 							unsigned long *config)
2163d3e51161SHeiko Stübner {
2164d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
2165d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
2166d3e51161SHeiko Stübner 	enum pin_config_param param = pinconf_to_config_param(*config);
2167dab3eba7SHeiko Stübner 	u16 arg;
2168a076e2edSHeiko Stübner 	int rc;
2169d3e51161SHeiko Stübner 
2170d3e51161SHeiko Stübner 	switch (param) {
2171d3e51161SHeiko Stübner 	case PIN_CONFIG_BIAS_DISABLE:
217244b6d930SHeiko Stübner 		if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
2173d3e51161SHeiko Stübner 			return -EINVAL;
2174d3e51161SHeiko Stübner 
2175dab3eba7SHeiko Stübner 		arg = 0;
2176d3e51161SHeiko Stübner 		break;
217744b6d930SHeiko Stübner 	case PIN_CONFIG_BIAS_PULL_UP:
217844b6d930SHeiko Stübner 	case PIN_CONFIG_BIAS_PULL_DOWN:
217944b6d930SHeiko Stübner 	case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
21806ca5274dSHeiko Stübner 	case PIN_CONFIG_BIAS_BUS_HOLD:
218144b6d930SHeiko Stübner 		if (!rockchip_pinconf_pull_valid(info->ctrl, param))
218244b6d930SHeiko Stübner 			return -ENOTSUPP;
218344b6d930SHeiko Stübner 
218444b6d930SHeiko Stübner 		if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
218544b6d930SHeiko Stübner 			return -EINVAL;
218644b6d930SHeiko Stübner 
2187dab3eba7SHeiko Stübner 		arg = 1;
218844b6d930SHeiko Stübner 		break;
2189a076e2edSHeiko Stübner 	case PIN_CONFIG_OUTPUT:
2190a076e2edSHeiko Stübner 		rc = rockchip_get_mux(bank, pin - bank->pin_base);
2191a076e2edSHeiko Stübner 		if (rc != RK_FUNC_GPIO)
2192a076e2edSHeiko Stübner 			return -EINVAL;
2193a076e2edSHeiko Stübner 
2194a076e2edSHeiko Stübner 		rc = rockchip_gpio_get(&bank->gpio_chip, pin - bank->pin_base);
2195a076e2edSHeiko Stübner 		if (rc < 0)
2196a076e2edSHeiko Stübner 			return rc;
2197a076e2edSHeiko Stübner 
2198a076e2edSHeiko Stübner 		arg = rc ? 1 : 0;
2199a076e2edSHeiko Stübner 		break;
2200b547c800SHeiko Stübner 	case PIN_CONFIG_DRIVE_STRENGTH:
2201b547c800SHeiko Stübner 		/* rk3288 is the first with per-pin drive-strength */
2202ef17f69fSHeiko Stübner 		if (!info->ctrl->drv_calc_reg)
2203b547c800SHeiko Stübner 			return -ENOTSUPP;
2204b547c800SHeiko Stübner 
2205ef17f69fSHeiko Stübner 		rc = rockchip_get_drive_perpin(bank, pin - bank->pin_base);
2206b547c800SHeiko Stübner 		if (rc < 0)
2207b547c800SHeiko Stübner 			return rc;
2208b547c800SHeiko Stübner 
2209b547c800SHeiko Stübner 		arg = rc;
2210b547c800SHeiko Stübner 		break;
2211e3b357d7Sdavid.wu 	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
2212e3b357d7Sdavid.wu 		if (!info->ctrl->schmitt_calc_reg)
2213e3b357d7Sdavid.wu 			return -ENOTSUPP;
2214e3b357d7Sdavid.wu 
2215e3b357d7Sdavid.wu 		rc = rockchip_get_schmitt(bank, pin - bank->pin_base);
2216e3b357d7Sdavid.wu 		if (rc < 0)
2217e3b357d7Sdavid.wu 			return rc;
2218e3b357d7Sdavid.wu 
2219e3b357d7Sdavid.wu 		arg = rc;
2220e3b357d7Sdavid.wu 		break;
2221d3e51161SHeiko Stübner 	default:
2222d3e51161SHeiko Stübner 		return -ENOTSUPP;
2223d3e51161SHeiko Stübner 		break;
2224d3e51161SHeiko Stübner 	}
2225d3e51161SHeiko Stübner 
2226dab3eba7SHeiko Stübner 	*config = pinconf_to_config_packed(param, arg);
2227dab3eba7SHeiko Stübner 
2228d3e51161SHeiko Stübner 	return 0;
2229d3e51161SHeiko Stübner }
2230d3e51161SHeiko Stübner 
2231d3e51161SHeiko Stübner static const struct pinconf_ops rockchip_pinconf_ops = {
2232d3e51161SHeiko Stübner 	.pin_config_get			= rockchip_pinconf_get,
2233d3e51161SHeiko Stübner 	.pin_config_set			= rockchip_pinconf_set,
2234ed62f2f2SHeiko Stübner 	.is_generic			= true,
2235d3e51161SHeiko Stübner };
2236d3e51161SHeiko Stübner 
223765fca613SHeiko Stübner static const struct of_device_id rockchip_bank_match[] = {
223865fca613SHeiko Stübner 	{ .compatible = "rockchip,gpio-bank" },
22396ca5274dSHeiko Stübner 	{ .compatible = "rockchip,rk3188-gpio-bank0" },
224065fca613SHeiko Stübner 	{},
224165fca613SHeiko Stübner };
2242d3e51161SHeiko Stübner 
2243d3e51161SHeiko Stübner static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
2244d3e51161SHeiko Stübner 						struct device_node *np)
2245d3e51161SHeiko Stübner {
2246d3e51161SHeiko Stübner 	struct device_node *child;
2247d3e51161SHeiko Stübner 
2248d3e51161SHeiko Stübner 	for_each_child_of_node(np, child) {
224965fca613SHeiko Stübner 		if (of_match_node(rockchip_bank_match, child))
2250d3e51161SHeiko Stübner 			continue;
2251d3e51161SHeiko Stübner 
2252d3e51161SHeiko Stübner 		info->nfunctions++;
2253d3e51161SHeiko Stübner 		info->ngroups += of_get_child_count(child);
2254d3e51161SHeiko Stübner 	}
2255d3e51161SHeiko Stübner }
2256d3e51161SHeiko Stübner 
2257d3e51161SHeiko Stübner static int rockchip_pinctrl_parse_groups(struct device_node *np,
2258d3e51161SHeiko Stübner 					      struct rockchip_pin_group *grp,
2259d3e51161SHeiko Stübner 					      struct rockchip_pinctrl *info,
2260d3e51161SHeiko Stübner 					      u32 index)
2261d3e51161SHeiko Stübner {
2262d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank;
2263d3e51161SHeiko Stübner 	int size;
2264d3e51161SHeiko Stübner 	const __be32 *list;
2265d3e51161SHeiko Stübner 	int num;
2266d3e51161SHeiko Stübner 	int i, j;
2267d3e51161SHeiko Stübner 	int ret;
2268d3e51161SHeiko Stübner 
2269d3e51161SHeiko Stübner 	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
2270d3e51161SHeiko Stübner 
2271d3e51161SHeiko Stübner 	/* Initialise group */
2272d3e51161SHeiko Stübner 	grp->name = np->name;
2273d3e51161SHeiko Stübner 
2274d3e51161SHeiko Stübner 	/*
2275d3e51161SHeiko Stübner 	 * the binding format is rockchip,pins = <bank pin mux CONFIG>,
2276d3e51161SHeiko Stübner 	 * do sanity check and calculate pins number
2277d3e51161SHeiko Stübner 	 */
2278d3e51161SHeiko Stübner 	list = of_get_property(np, "rockchip,pins", &size);
2279d3e51161SHeiko Stübner 	/* we do not check return since it's safe node passed down */
2280d3e51161SHeiko Stübner 	size /= sizeof(*list);
2281d3e51161SHeiko Stübner 	if (!size || size % 4) {
2282d3e51161SHeiko Stübner 		dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
2283d3e51161SHeiko Stübner 		return -EINVAL;
2284d3e51161SHeiko Stübner 	}
2285d3e51161SHeiko Stübner 
2286d3e51161SHeiko Stübner 	grp->npins = size / 4;
2287d3e51161SHeiko Stübner 
2288d3e51161SHeiko Stübner 	grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
2289d3e51161SHeiko Stübner 						GFP_KERNEL);
2290d3e51161SHeiko Stübner 	grp->data = devm_kzalloc(info->dev, grp->npins *
2291d3e51161SHeiko Stübner 					  sizeof(struct rockchip_pin_config),
2292d3e51161SHeiko Stübner 					GFP_KERNEL);
2293d3e51161SHeiko Stübner 	if (!grp->pins || !grp->data)
2294d3e51161SHeiko Stübner 		return -ENOMEM;
2295d3e51161SHeiko Stübner 
2296d3e51161SHeiko Stübner 	for (i = 0, j = 0; i < size; i += 4, j++) {
2297d3e51161SHeiko Stübner 		const __be32 *phandle;
2298d3e51161SHeiko Stübner 		struct device_node *np_config;
2299d3e51161SHeiko Stübner 
2300d3e51161SHeiko Stübner 		num = be32_to_cpu(*list++);
2301d3e51161SHeiko Stübner 		bank = bank_num_to_bank(info, num);
2302d3e51161SHeiko Stübner 		if (IS_ERR(bank))
2303d3e51161SHeiko Stübner 			return PTR_ERR(bank);
2304d3e51161SHeiko Stübner 
2305d3e51161SHeiko Stübner 		grp->pins[j] = bank->pin_base + be32_to_cpu(*list++);
2306d3e51161SHeiko Stübner 		grp->data[j].func = be32_to_cpu(*list++);
2307d3e51161SHeiko Stübner 
2308d3e51161SHeiko Stübner 		phandle = list++;
2309d3e51161SHeiko Stübner 		if (!phandle)
2310d3e51161SHeiko Stübner 			return -EINVAL;
2311d3e51161SHeiko Stübner 
2312d3e51161SHeiko Stübner 		np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
2313dd4d01f7SSoren Brinkmann 		ret = pinconf_generic_parse_dt_config(np_config, NULL,
2314d3e51161SHeiko Stübner 				&grp->data[j].configs, &grp->data[j].nconfigs);
2315d3e51161SHeiko Stübner 		if (ret)
2316d3e51161SHeiko Stübner 			return ret;
2317d3e51161SHeiko Stübner 	}
2318d3e51161SHeiko Stübner 
2319d3e51161SHeiko Stübner 	return 0;
2320d3e51161SHeiko Stübner }
2321d3e51161SHeiko Stübner 
2322d3e51161SHeiko Stübner static int rockchip_pinctrl_parse_functions(struct device_node *np,
2323d3e51161SHeiko Stübner 						struct rockchip_pinctrl *info,
2324d3e51161SHeiko Stübner 						u32 index)
2325d3e51161SHeiko Stübner {
2326d3e51161SHeiko Stübner 	struct device_node *child;
2327d3e51161SHeiko Stübner 	struct rockchip_pmx_func *func;
2328d3e51161SHeiko Stübner 	struct rockchip_pin_group *grp;
2329d3e51161SHeiko Stübner 	int ret;
2330d3e51161SHeiko Stübner 	static u32 grp_index;
2331d3e51161SHeiko Stübner 	u32 i = 0;
2332d3e51161SHeiko Stübner 
2333d3e51161SHeiko Stübner 	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
2334d3e51161SHeiko Stübner 
2335d3e51161SHeiko Stübner 	func = &info->functions[index];
2336d3e51161SHeiko Stübner 
2337d3e51161SHeiko Stübner 	/* Initialise function */
2338d3e51161SHeiko Stübner 	func->name = np->name;
2339d3e51161SHeiko Stübner 	func->ngroups = of_get_child_count(np);
2340d3e51161SHeiko Stübner 	if (func->ngroups <= 0)
2341d3e51161SHeiko Stübner 		return 0;
2342d3e51161SHeiko Stübner 
2343d3e51161SHeiko Stübner 	func->groups = devm_kzalloc(info->dev,
2344d3e51161SHeiko Stübner 			func->ngroups * sizeof(char *), GFP_KERNEL);
2345d3e51161SHeiko Stübner 	if (!func->groups)
2346d3e51161SHeiko Stübner 		return -ENOMEM;
2347d3e51161SHeiko Stübner 
2348d3e51161SHeiko Stübner 	for_each_child_of_node(np, child) {
2349d3e51161SHeiko Stübner 		func->groups[i] = child->name;
2350d3e51161SHeiko Stübner 		grp = &info->groups[grp_index++];
2351d3e51161SHeiko Stübner 		ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
2352f7a81b7fSJulia Lawall 		if (ret) {
2353f7a81b7fSJulia Lawall 			of_node_put(child);
2354d3e51161SHeiko Stübner 			return ret;
2355d3e51161SHeiko Stübner 		}
2356f7a81b7fSJulia Lawall 	}
2357d3e51161SHeiko Stübner 
2358d3e51161SHeiko Stübner 	return 0;
2359d3e51161SHeiko Stübner }
2360d3e51161SHeiko Stübner 
2361d3e51161SHeiko Stübner static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
2362d3e51161SHeiko Stübner 					      struct rockchip_pinctrl *info)
2363d3e51161SHeiko Stübner {
2364d3e51161SHeiko Stübner 	struct device *dev = &pdev->dev;
2365d3e51161SHeiko Stübner 	struct device_node *np = dev->of_node;
2366d3e51161SHeiko Stübner 	struct device_node *child;
2367d3e51161SHeiko Stübner 	int ret;
2368d3e51161SHeiko Stübner 	int i;
2369d3e51161SHeiko Stübner 
2370d3e51161SHeiko Stübner 	rockchip_pinctrl_child_count(info, np);
2371d3e51161SHeiko Stübner 
2372d3e51161SHeiko Stübner 	dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
2373d3e51161SHeiko Stübner 	dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
2374d3e51161SHeiko Stübner 
2375d3e51161SHeiko Stübner 	info->functions = devm_kzalloc(dev, info->nfunctions *
2376d3e51161SHeiko Stübner 					      sizeof(struct rockchip_pmx_func),
2377d3e51161SHeiko Stübner 					      GFP_KERNEL);
2378d3e51161SHeiko Stübner 	if (!info->functions) {
2379d3e51161SHeiko Stübner 		dev_err(dev, "failed to allocate memory for function list\n");
2380d3e51161SHeiko Stübner 		return -EINVAL;
2381d3e51161SHeiko Stübner 	}
2382d3e51161SHeiko Stübner 
2383d3e51161SHeiko Stübner 	info->groups = devm_kzalloc(dev, info->ngroups *
2384d3e51161SHeiko Stübner 					    sizeof(struct rockchip_pin_group),
2385d3e51161SHeiko Stübner 					    GFP_KERNEL);
2386d3e51161SHeiko Stübner 	if (!info->groups) {
2387d3e51161SHeiko Stübner 		dev_err(dev, "failed allocate memory for ping group list\n");
2388d3e51161SHeiko Stübner 		return -EINVAL;
2389d3e51161SHeiko Stübner 	}
2390d3e51161SHeiko Stübner 
2391d3e51161SHeiko Stübner 	i = 0;
2392d3e51161SHeiko Stübner 
2393d3e51161SHeiko Stübner 	for_each_child_of_node(np, child) {
239465fca613SHeiko Stübner 		if (of_match_node(rockchip_bank_match, child))
2395d3e51161SHeiko Stübner 			continue;
239665fca613SHeiko Stübner 
2397d3e51161SHeiko Stübner 		ret = rockchip_pinctrl_parse_functions(child, info, i++);
2398d3e51161SHeiko Stübner 		if (ret) {
2399d3e51161SHeiko Stübner 			dev_err(&pdev->dev, "failed to parse function\n");
2400f7a81b7fSJulia Lawall 			of_node_put(child);
2401d3e51161SHeiko Stübner 			return ret;
2402d3e51161SHeiko Stübner 		}
2403d3e51161SHeiko Stübner 	}
2404d3e51161SHeiko Stübner 
2405d3e51161SHeiko Stübner 	return 0;
2406d3e51161SHeiko Stübner }
2407d3e51161SHeiko Stübner 
2408d3e51161SHeiko Stübner static int rockchip_pinctrl_register(struct platform_device *pdev,
2409d3e51161SHeiko Stübner 					struct rockchip_pinctrl *info)
2410d3e51161SHeiko Stübner {
2411d3e51161SHeiko Stübner 	struct pinctrl_desc *ctrldesc = &info->pctl;
2412d3e51161SHeiko Stübner 	struct pinctrl_pin_desc *pindesc, *pdesc;
2413d3e51161SHeiko Stübner 	struct rockchip_pin_bank *pin_bank;
2414d3e51161SHeiko Stübner 	int pin, bank, ret;
2415d3e51161SHeiko Stübner 	int k;
2416d3e51161SHeiko Stübner 
2417d3e51161SHeiko Stübner 	ctrldesc->name = "rockchip-pinctrl";
2418d3e51161SHeiko Stübner 	ctrldesc->owner = THIS_MODULE;
2419d3e51161SHeiko Stübner 	ctrldesc->pctlops = &rockchip_pctrl_ops;
2420d3e51161SHeiko Stübner 	ctrldesc->pmxops = &rockchip_pmx_ops;
2421d3e51161SHeiko Stübner 	ctrldesc->confops = &rockchip_pinconf_ops;
2422d3e51161SHeiko Stübner 
2423d3e51161SHeiko Stübner 	pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
2424d3e51161SHeiko Stübner 			info->ctrl->nr_pins, GFP_KERNEL);
2425d3e51161SHeiko Stübner 	if (!pindesc) {
2426d3e51161SHeiko Stübner 		dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
2427d3e51161SHeiko Stübner 		return -ENOMEM;
2428d3e51161SHeiko Stübner 	}
2429d3e51161SHeiko Stübner 	ctrldesc->pins = pindesc;
2430d3e51161SHeiko Stübner 	ctrldesc->npins = info->ctrl->nr_pins;
2431d3e51161SHeiko Stübner 
2432d3e51161SHeiko Stübner 	pdesc = pindesc;
2433d3e51161SHeiko Stübner 	for (bank = 0 , k = 0; bank < info->ctrl->nr_banks; bank++) {
2434d3e51161SHeiko Stübner 		pin_bank = &info->ctrl->pin_banks[bank];
2435d3e51161SHeiko Stübner 		for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) {
2436d3e51161SHeiko Stübner 			pdesc->number = k;
2437d3e51161SHeiko Stübner 			pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",
2438d3e51161SHeiko Stübner 						pin_bank->name, pin);
2439d3e51161SHeiko Stübner 			pdesc++;
2440d3e51161SHeiko Stübner 		}
2441d3e51161SHeiko Stübner 	}
2442d3e51161SHeiko Stübner 
24430fb7dcb1SDoug Anderson 	ret = rockchip_pinctrl_parse_dt(pdev, info);
24440fb7dcb1SDoug Anderson 	if (ret)
24450fb7dcb1SDoug Anderson 		return ret;
24460fb7dcb1SDoug Anderson 
24470085a2b4SLaxman Dewangan 	info->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc, info);
2448323de9efSMasahiro Yamada 	if (IS_ERR(info->pctl_dev)) {
2449d3e51161SHeiko Stübner 		dev_err(&pdev->dev, "could not register pinctrl driver\n");
2450323de9efSMasahiro Yamada 		return PTR_ERR(info->pctl_dev);
2451d3e51161SHeiko Stübner 	}
2452d3e51161SHeiko Stübner 
2453d3e51161SHeiko Stübner 	for (bank = 0; bank < info->ctrl->nr_banks; ++bank) {
2454d3e51161SHeiko Stübner 		pin_bank = &info->ctrl->pin_banks[bank];
2455d3e51161SHeiko Stübner 		pin_bank->grange.name = pin_bank->name;
2456d3e51161SHeiko Stübner 		pin_bank->grange.id = bank;
2457d3e51161SHeiko Stübner 		pin_bank->grange.pin_base = pin_bank->pin_base;
2458d3e51161SHeiko Stübner 		pin_bank->grange.base = pin_bank->gpio_chip.base;
2459d3e51161SHeiko Stübner 		pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
2460d3e51161SHeiko Stübner 		pin_bank->grange.gc = &pin_bank->gpio_chip;
2461d3e51161SHeiko Stübner 		pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
2462d3e51161SHeiko Stübner 	}
2463d3e51161SHeiko Stübner 
2464d3e51161SHeiko Stübner 	return 0;
2465d3e51161SHeiko Stübner }
2466d3e51161SHeiko Stübner 
2467d3e51161SHeiko Stübner /*
2468d3e51161SHeiko Stübner  * GPIO handling
2469d3e51161SHeiko Stübner  */
2470d3e51161SHeiko Stübner 
2471d3e51161SHeiko Stübner static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
2472d3e51161SHeiko Stübner {
247303bf81f1SLinus Walleij 	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
2474d3e51161SHeiko Stübner 	void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
2475d3e51161SHeiko Stübner 	unsigned long flags;
2476d3e51161SHeiko Stübner 	u32 data;
2477d3e51161SHeiko Stübner 
247807a06ae9SLin Huang 	clk_enable(bank->clk);
247970b7aa7aSJohn Keeping 	raw_spin_lock_irqsave(&bank->slock, flags);
2480d3e51161SHeiko Stübner 
2481d3e51161SHeiko Stübner 	data = readl(reg);
2482d3e51161SHeiko Stübner 	data &= ~BIT(offset);
2483d3e51161SHeiko Stübner 	if (value)
2484d3e51161SHeiko Stübner 		data |= BIT(offset);
2485d3e51161SHeiko Stübner 	writel(data, reg);
2486d3e51161SHeiko Stübner 
248770b7aa7aSJohn Keeping 	raw_spin_unlock_irqrestore(&bank->slock, flags);
248807a06ae9SLin Huang 	clk_disable(bank->clk);
2489d3e51161SHeiko Stübner }
2490d3e51161SHeiko Stübner 
2491d3e51161SHeiko Stübner /*
2492d3e51161SHeiko Stübner  * Returns the level of the pin for input direction and setting of the DR
2493d3e51161SHeiko Stübner  * register for output gpios.
2494d3e51161SHeiko Stübner  */
2495d3e51161SHeiko Stübner static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset)
2496d3e51161SHeiko Stübner {
249703bf81f1SLinus Walleij 	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
2498d3e51161SHeiko Stübner 	u32 data;
2499d3e51161SHeiko Stübner 
250007a06ae9SLin Huang 	clk_enable(bank->clk);
2501d3e51161SHeiko Stübner 	data = readl(bank->reg_base + GPIO_EXT_PORT);
250207a06ae9SLin Huang 	clk_disable(bank->clk);
2503d3e51161SHeiko Stübner 	data >>= offset;
2504d3e51161SHeiko Stübner 	data &= 1;
2505d3e51161SHeiko Stübner 	return data;
2506d3e51161SHeiko Stübner }
2507d3e51161SHeiko Stübner 
2508d3e51161SHeiko Stübner /*
2509d3e51161SHeiko Stübner  * gpiolib gpio_direction_input callback function. The setting of the pin
2510d3e51161SHeiko Stübner  * mux function as 'gpio input' will be handled by the pinctrl susbsystem
2511d3e51161SHeiko Stübner  * interface.
2512d3e51161SHeiko Stübner  */
2513d3e51161SHeiko Stübner static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
2514d3e51161SHeiko Stübner {
2515d3e51161SHeiko Stübner 	return pinctrl_gpio_direction_input(gc->base + offset);
2516d3e51161SHeiko Stübner }
2517d3e51161SHeiko Stübner 
2518d3e51161SHeiko Stübner /*
2519d3e51161SHeiko Stübner  * gpiolib gpio_direction_output callback function. The setting of the pin
2520d3e51161SHeiko Stübner  * mux function as 'gpio output' will be handled by the pinctrl susbsystem
2521d3e51161SHeiko Stübner  * interface.
2522d3e51161SHeiko Stübner  */
2523d3e51161SHeiko Stübner static int rockchip_gpio_direction_output(struct gpio_chip *gc,
2524d3e51161SHeiko Stübner 					  unsigned offset, int value)
2525d3e51161SHeiko Stübner {
2526d3e51161SHeiko Stübner 	rockchip_gpio_set(gc, offset, value);
2527d3e51161SHeiko Stübner 	return pinctrl_gpio_direction_output(gc->base + offset);
2528d3e51161SHeiko Stübner }
2529d3e51161SHeiko Stübner 
2530d3e51161SHeiko Stübner /*
2531d3e51161SHeiko Stübner  * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
2532d3e51161SHeiko Stübner  * and a virtual IRQ, if not already present.
2533d3e51161SHeiko Stübner  */
2534d3e51161SHeiko Stübner static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
2535d3e51161SHeiko Stübner {
253603bf81f1SLinus Walleij 	struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
2537d3e51161SHeiko Stübner 	unsigned int virq;
2538d3e51161SHeiko Stübner 
2539d3e51161SHeiko Stübner 	if (!bank->domain)
2540d3e51161SHeiko Stübner 		return -ENXIO;
2541d3e51161SHeiko Stübner 
2542d3e51161SHeiko Stübner 	virq = irq_create_mapping(bank->domain, offset);
2543d3e51161SHeiko Stübner 
2544d3e51161SHeiko Stübner 	return (virq) ? : -ENXIO;
2545d3e51161SHeiko Stübner }
2546d3e51161SHeiko Stübner 
2547d3e51161SHeiko Stübner static const struct gpio_chip rockchip_gpiolib_chip = {
254898c85d58SJonas Gorski 	.request = gpiochip_generic_request,
254998c85d58SJonas Gorski 	.free = gpiochip_generic_free,
2550d3e51161SHeiko Stübner 	.set = rockchip_gpio_set,
2551d3e51161SHeiko Stübner 	.get = rockchip_gpio_get,
25526ba20a00SCaesar Wang 	.get_direction	= rockchip_gpio_get_direction,
2553d3e51161SHeiko Stübner 	.direction_input = rockchip_gpio_direction_input,
2554d3e51161SHeiko Stübner 	.direction_output = rockchip_gpio_direction_output,
2555d3e51161SHeiko Stübner 	.to_irq = rockchip_gpio_to_irq,
2556d3e51161SHeiko Stübner 	.owner = THIS_MODULE,
2557d3e51161SHeiko Stübner };
2558d3e51161SHeiko Stübner 
2559d3e51161SHeiko Stübner /*
2560d3e51161SHeiko Stübner  * Interrupt handling
2561d3e51161SHeiko Stübner  */
2562d3e51161SHeiko Stübner 
2563bd0b9ac4SThomas Gleixner static void rockchip_irq_demux(struct irq_desc *desc)
2564d3e51161SHeiko Stübner {
25655663bb27SJiang Liu 	struct irq_chip *chip = irq_desc_get_chip(desc);
25665663bb27SJiang Liu 	struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc);
2567d3e51161SHeiko Stübner 	u32 pend;
2568d3e51161SHeiko Stübner 
2569d3e51161SHeiko Stübner 	dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
2570d3e51161SHeiko Stübner 
2571d3e51161SHeiko Stübner 	chained_irq_enter(chip, desc);
2572d3e51161SHeiko Stübner 
2573d3e51161SHeiko Stübner 	pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS);
2574d3e51161SHeiko Stübner 
2575d3e51161SHeiko Stübner 	while (pend) {
2576415f748cSThomas Gleixner 		unsigned int irq, virq;
2577d3e51161SHeiko Stübner 
2578d3e51161SHeiko Stübner 		irq = __ffs(pend);
2579d3e51161SHeiko Stübner 		pend &= ~BIT(irq);
2580d3e51161SHeiko Stübner 		virq = irq_linear_revmap(bank->domain, irq);
2581d3e51161SHeiko Stübner 
2582d3e51161SHeiko Stübner 		if (!virq) {
2583d3e51161SHeiko Stübner 			dev_err(bank->drvdata->dev, "unmapped irq %d\n", irq);
2584d3e51161SHeiko Stübner 			continue;
2585d3e51161SHeiko Stübner 		}
2586d3e51161SHeiko Stübner 
2587d3e51161SHeiko Stübner 		dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq);
2588d3e51161SHeiko Stübner 
25895a927501SHeiko Stübner 		/*
25905a927501SHeiko Stübner 		 * Triggering IRQ on both rising and falling edge
25915a927501SHeiko Stübner 		 * needs manual intervention.
25925a927501SHeiko Stübner 		 */
25935a927501SHeiko Stübner 		if (bank->toggle_edge_mode & BIT(irq)) {
259453b1bfc7SDoug Anderson 			u32 data, data_old, polarity;
259553b1bfc7SDoug Anderson 			unsigned long flags;
259653b1bfc7SDoug Anderson 
259753b1bfc7SDoug Anderson 			data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
259853b1bfc7SDoug Anderson 			do {
259970b7aa7aSJohn Keeping 				raw_spin_lock_irqsave(&bank->slock, flags);
260053b1bfc7SDoug Anderson 
260153b1bfc7SDoug Anderson 				polarity = readl_relaxed(bank->reg_base +
260253b1bfc7SDoug Anderson 							 GPIO_INT_POLARITY);
26035a927501SHeiko Stübner 				if (data & BIT(irq))
26045a927501SHeiko Stübner 					polarity &= ~BIT(irq);
26055a927501SHeiko Stübner 				else
26065a927501SHeiko Stübner 					polarity |= BIT(irq);
260753b1bfc7SDoug Anderson 				writel(polarity,
260853b1bfc7SDoug Anderson 				       bank->reg_base + GPIO_INT_POLARITY);
26095a927501SHeiko Stübner 
261070b7aa7aSJohn Keeping 				raw_spin_unlock_irqrestore(&bank->slock, flags);
261153b1bfc7SDoug Anderson 
261253b1bfc7SDoug Anderson 				data_old = data;
261353b1bfc7SDoug Anderson 				data = readl_relaxed(bank->reg_base +
261453b1bfc7SDoug Anderson 						     GPIO_EXT_PORT);
261553b1bfc7SDoug Anderson 			} while ((data & BIT(irq)) != (data_old & BIT(irq)));
26165a927501SHeiko Stübner 		}
26175a927501SHeiko Stübner 
2618d3e51161SHeiko Stübner 		generic_handle_irq(virq);
2619d3e51161SHeiko Stübner 	}
2620d3e51161SHeiko Stübner 
2621d3e51161SHeiko Stübner 	chained_irq_exit(chip, desc);
2622d3e51161SHeiko Stübner }
2623d3e51161SHeiko Stübner 
2624d3e51161SHeiko Stübner static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
2625d3e51161SHeiko Stübner {
2626d3e51161SHeiko Stübner 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
2627d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = gc->private;
2628d3e51161SHeiko Stübner 	u32 mask = BIT(d->hwirq);
2629d3e51161SHeiko Stübner 	u32 polarity;
2630d3e51161SHeiko Stübner 	u32 level;
2631d3e51161SHeiko Stübner 	u32 data;
2632fab262f5SDoug Anderson 	unsigned long flags;
263314797189SHeiko Stübner 	int ret;
2634d3e51161SHeiko Stübner 
26355a927501SHeiko Stübner 	/* make sure the pin is configured as gpio input */
26361d80df93SBrian Norris 	ret = rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO);
263714797189SHeiko Stübner 	if (ret < 0)
263814797189SHeiko Stübner 		return ret;
263914797189SHeiko Stübner 
26401d80df93SBrian Norris 	clk_enable(bank->clk);
264170b7aa7aSJohn Keeping 	raw_spin_lock_irqsave(&bank->slock, flags);
2642fab262f5SDoug Anderson 
26435a927501SHeiko Stübner 	data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
26445a927501SHeiko Stübner 	data &= ~mask;
26455a927501SHeiko Stübner 	writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
26465a927501SHeiko Stübner 
264770b7aa7aSJohn Keeping 	raw_spin_unlock_irqrestore(&bank->slock, flags);
2648fab262f5SDoug Anderson 
2649d3e51161SHeiko Stübner 	if (type & IRQ_TYPE_EDGE_BOTH)
26502dbf1bc5SThomas Gleixner 		irq_set_handler_locked(d, handle_edge_irq);
2651d3e51161SHeiko Stübner 	else
26522dbf1bc5SThomas Gleixner 		irq_set_handler_locked(d, handle_level_irq);
2653d3e51161SHeiko Stübner 
265470b7aa7aSJohn Keeping 	raw_spin_lock_irqsave(&bank->slock, flags);
2655d3e51161SHeiko Stübner 	irq_gc_lock(gc);
2656d3e51161SHeiko Stübner 
2657d3e51161SHeiko Stübner 	level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
2658d3e51161SHeiko Stübner 	polarity = readl_relaxed(gc->reg_base + GPIO_INT_POLARITY);
2659d3e51161SHeiko Stübner 
2660d3e51161SHeiko Stübner 	switch (type) {
26615a927501SHeiko Stübner 	case IRQ_TYPE_EDGE_BOTH:
26625a927501SHeiko Stübner 		bank->toggle_edge_mode |= mask;
26635a927501SHeiko Stübner 		level |= mask;
26645a927501SHeiko Stübner 
26655a927501SHeiko Stübner 		/*
26665a927501SHeiko Stübner 		 * Determine gpio state. If 1 next interrupt should be falling
26675a927501SHeiko Stübner 		 * otherwise rising.
26685a927501SHeiko Stübner 		 */
26695a927501SHeiko Stübner 		data = readl(bank->reg_base + GPIO_EXT_PORT);
26705a927501SHeiko Stübner 		if (data & mask)
26715a927501SHeiko Stübner 			polarity &= ~mask;
26725a927501SHeiko Stübner 		else
26735a927501SHeiko Stübner 			polarity |= mask;
26745a927501SHeiko Stübner 		break;
2675d3e51161SHeiko Stübner 	case IRQ_TYPE_EDGE_RISING:
26765a927501SHeiko Stübner 		bank->toggle_edge_mode &= ~mask;
2677d3e51161SHeiko Stübner 		level |= mask;
2678d3e51161SHeiko Stübner 		polarity |= mask;
2679d3e51161SHeiko Stübner 		break;
2680d3e51161SHeiko Stübner 	case IRQ_TYPE_EDGE_FALLING:
26815a927501SHeiko Stübner 		bank->toggle_edge_mode &= ~mask;
2682d3e51161SHeiko Stübner 		level |= mask;
2683d3e51161SHeiko Stübner 		polarity &= ~mask;
2684d3e51161SHeiko Stübner 		break;
2685d3e51161SHeiko Stübner 	case IRQ_TYPE_LEVEL_HIGH:
26865a927501SHeiko Stübner 		bank->toggle_edge_mode &= ~mask;
2687d3e51161SHeiko Stübner 		level &= ~mask;
2688d3e51161SHeiko Stübner 		polarity |= mask;
2689d3e51161SHeiko Stübner 		break;
2690d3e51161SHeiko Stübner 	case IRQ_TYPE_LEVEL_LOW:
26915a927501SHeiko Stübner 		bank->toggle_edge_mode &= ~mask;
2692d3e51161SHeiko Stübner 		level &= ~mask;
2693d3e51161SHeiko Stübner 		polarity &= ~mask;
2694d3e51161SHeiko Stübner 		break;
2695d3e51161SHeiko Stübner 	default:
26967cc5f970SAxel Lin 		irq_gc_unlock(gc);
269770b7aa7aSJohn Keeping 		raw_spin_unlock_irqrestore(&bank->slock, flags);
26981d80df93SBrian Norris 		clk_disable(bank->clk);
2699d3e51161SHeiko Stübner 		return -EINVAL;
2700d3e51161SHeiko Stübner 	}
2701d3e51161SHeiko Stübner 
2702d3e51161SHeiko Stübner 	writel_relaxed(level, gc->reg_base + GPIO_INTTYPE_LEVEL);
2703d3e51161SHeiko Stübner 	writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
2704d3e51161SHeiko Stübner 
2705d3e51161SHeiko Stübner 	irq_gc_unlock(gc);
270670b7aa7aSJohn Keeping 	raw_spin_unlock_irqrestore(&bank->slock, flags);
27071d80df93SBrian Norris 	clk_disable(bank->clk);
2708d3e51161SHeiko Stübner 
2709d3e51161SHeiko Stübner 	return 0;
2710d3e51161SHeiko Stübner }
2711d3e51161SHeiko Stübner 
271268bda47cSDoug Anderson static void rockchip_irq_suspend(struct irq_data *d)
271368bda47cSDoug Anderson {
271468bda47cSDoug Anderson 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
271568bda47cSDoug Anderson 	struct rockchip_pin_bank *bank = gc->private;
271668bda47cSDoug Anderson 
271707a06ae9SLin Huang 	clk_enable(bank->clk);
27185ae0c7adSDoug Anderson 	bank->saved_masks = irq_reg_readl(gc, GPIO_INTMASK);
27195ae0c7adSDoug Anderson 	irq_reg_writel(gc, ~gc->wake_active, GPIO_INTMASK);
272007a06ae9SLin Huang 	clk_disable(bank->clk);
272168bda47cSDoug Anderson }
272268bda47cSDoug Anderson 
272368bda47cSDoug Anderson static void rockchip_irq_resume(struct irq_data *d)
272468bda47cSDoug Anderson {
272568bda47cSDoug Anderson 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
272668bda47cSDoug Anderson 	struct rockchip_pin_bank *bank = gc->private;
272768bda47cSDoug Anderson 
272807a06ae9SLin Huang 	clk_enable(bank->clk);
27295ae0c7adSDoug Anderson 	irq_reg_writel(gc, bank->saved_masks, GPIO_INTMASK);
273007a06ae9SLin Huang 	clk_disable(bank->clk);
273107a06ae9SLin Huang }
273207a06ae9SLin Huang 
2733d468289aSJeffy Chen static void rockchip_irq_enable(struct irq_data *d)
273407a06ae9SLin Huang {
273507a06ae9SLin Huang 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
273607a06ae9SLin Huang 	struct rockchip_pin_bank *bank = gc->private;
273707a06ae9SLin Huang 
273807a06ae9SLin Huang 	clk_enable(bank->clk);
273907a06ae9SLin Huang 	irq_gc_mask_clr_bit(d);
274007a06ae9SLin Huang }
274107a06ae9SLin Huang 
2742d468289aSJeffy Chen static void rockchip_irq_disable(struct irq_data *d)
274307a06ae9SLin Huang {
274407a06ae9SLin Huang 	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
274507a06ae9SLin Huang 	struct rockchip_pin_bank *bank = gc->private;
274607a06ae9SLin Huang 
274707a06ae9SLin Huang 	irq_gc_mask_set_bit(d);
274807a06ae9SLin Huang 	clk_disable(bank->clk);
2749f2dd028cSDoug Anderson }
2750f2dd028cSDoug Anderson 
2751d3e51161SHeiko Stübner static int rockchip_interrupts_register(struct platform_device *pdev,
2752d3e51161SHeiko Stübner 						struct rockchip_pinctrl *info)
2753d3e51161SHeiko Stübner {
2754d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
2755d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = ctrl->pin_banks;
2756d3e51161SHeiko Stübner 	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
2757d3e51161SHeiko Stübner 	struct irq_chip_generic *gc;
2758d3e51161SHeiko Stübner 	int ret;
275907a06ae9SLin Huang 	int i, j;
2760d3e51161SHeiko Stübner 
2761d3e51161SHeiko Stübner 	for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
2762d3e51161SHeiko Stübner 		if (!bank->valid) {
2763d3e51161SHeiko Stübner 			dev_warn(&pdev->dev, "bank %s is not valid\n",
2764d3e51161SHeiko Stübner 				 bank->name);
2765d3e51161SHeiko Stübner 			continue;
2766d3e51161SHeiko Stübner 		}
2767d3e51161SHeiko Stübner 
276807a06ae9SLin Huang 		ret = clk_enable(bank->clk);
276907a06ae9SLin Huang 		if (ret) {
277007a06ae9SLin Huang 			dev_err(&pdev->dev, "failed to enable clock for bank %s\n",
277107a06ae9SLin Huang 				bank->name);
277207a06ae9SLin Huang 			continue;
277307a06ae9SLin Huang 		}
277407a06ae9SLin Huang 
2775d3e51161SHeiko Stübner 		bank->domain = irq_domain_add_linear(bank->of_node, 32,
2776d3e51161SHeiko Stübner 						&irq_generic_chip_ops, NULL);
2777d3e51161SHeiko Stübner 		if (!bank->domain) {
2778d3e51161SHeiko Stübner 			dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n",
2779d3e51161SHeiko Stübner 				 bank->name);
278007a06ae9SLin Huang 			clk_disable(bank->clk);
2781d3e51161SHeiko Stübner 			continue;
2782d3e51161SHeiko Stübner 		}
2783d3e51161SHeiko Stübner 
2784d3e51161SHeiko Stübner 		ret = irq_alloc_domain_generic_chips(bank->domain, 32, 1,
2785d3e51161SHeiko Stübner 					 "rockchip_gpio_irq", handle_level_irq,
2786d3e51161SHeiko Stübner 					 clr, 0, IRQ_GC_INIT_MASK_CACHE);
2787d3e51161SHeiko Stübner 		if (ret) {
2788d3e51161SHeiko Stübner 			dev_err(&pdev->dev, "could not alloc generic chips for bank %s\n",
2789d3e51161SHeiko Stübner 				bank->name);
2790d3e51161SHeiko Stübner 			irq_domain_remove(bank->domain);
279107a06ae9SLin Huang 			clk_disable(bank->clk);
2792d3e51161SHeiko Stübner 			continue;
2793d3e51161SHeiko Stübner 		}
2794d3e51161SHeiko Stübner 
27955ae0c7adSDoug Anderson 		/*
27965ae0c7adSDoug Anderson 		 * Linux assumes that all interrupts start out disabled/masked.
27975ae0c7adSDoug Anderson 		 * Our driver only uses the concept of masked and always keeps
27985ae0c7adSDoug Anderson 		 * things enabled, so for us that's all masked and all enabled.
27995ae0c7adSDoug Anderson 		 */
28005ae0c7adSDoug Anderson 		writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTMASK);
28015ae0c7adSDoug Anderson 		writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTEN);
28025ae0c7adSDoug Anderson 
2803d3e51161SHeiko Stübner 		gc = irq_get_domain_generic_chip(bank->domain, 0);
2804d3e51161SHeiko Stübner 		gc->reg_base = bank->reg_base;
2805d3e51161SHeiko Stübner 		gc->private = bank;
2806f2dd028cSDoug Anderson 		gc->chip_types[0].regs.mask = GPIO_INTMASK;
2807d3e51161SHeiko Stübner 		gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
2808d3e51161SHeiko Stübner 		gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
2809d468289aSJeffy Chen 		gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
2810d468289aSJeffy Chen 		gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
2811d468289aSJeffy Chen 		gc->chip_types[0].chip.irq_enable = rockchip_irq_enable;
2812d468289aSJeffy Chen 		gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
2813d3e51161SHeiko Stübner 		gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
281468bda47cSDoug Anderson 		gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
281568bda47cSDoug Anderson 		gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
2816d3e51161SHeiko Stübner 		gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
2817876d716bSDoug Anderson 		gc->wake_enabled = IRQ_MSK(bank->nr_pins);
2818d3e51161SHeiko Stübner 
281903051bc2SThomas Gleixner 		irq_set_chained_handler_and_data(bank->irq,
282003051bc2SThomas Gleixner 						 rockchip_irq_demux, bank);
282107a06ae9SLin Huang 
282207a06ae9SLin Huang 		/* map the gpio irqs here, when the clock is still running */
282307a06ae9SLin Huang 		for (j = 0 ; j < 32 ; j++)
282407a06ae9SLin Huang 			irq_create_mapping(bank->domain, j);
282507a06ae9SLin Huang 
282607a06ae9SLin Huang 		clk_disable(bank->clk);
2827d3e51161SHeiko Stübner 	}
2828d3e51161SHeiko Stübner 
2829d3e51161SHeiko Stübner 	return 0;
2830d3e51161SHeiko Stübner }
2831d3e51161SHeiko Stübner 
2832d3e51161SHeiko Stübner static int rockchip_gpiolib_register(struct platform_device *pdev,
2833d3e51161SHeiko Stübner 						struct rockchip_pinctrl *info)
2834d3e51161SHeiko Stübner {
2835d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
2836d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = ctrl->pin_banks;
2837d3e51161SHeiko Stübner 	struct gpio_chip *gc;
2838d3e51161SHeiko Stübner 	int ret;
2839d3e51161SHeiko Stübner 	int i;
2840d3e51161SHeiko Stübner 
2841d3e51161SHeiko Stübner 	for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
2842d3e51161SHeiko Stübner 		if (!bank->valid) {
2843d3e51161SHeiko Stübner 			dev_warn(&pdev->dev, "bank %s is not valid\n",
2844d3e51161SHeiko Stübner 				 bank->name);
2845d3e51161SHeiko Stübner 			continue;
2846d3e51161SHeiko Stübner 		}
2847d3e51161SHeiko Stübner 
2848d3e51161SHeiko Stübner 		bank->gpio_chip = rockchip_gpiolib_chip;
2849d3e51161SHeiko Stübner 
2850d3e51161SHeiko Stübner 		gc = &bank->gpio_chip;
2851d3e51161SHeiko Stübner 		gc->base = bank->pin_base;
2852d3e51161SHeiko Stübner 		gc->ngpio = bank->nr_pins;
285358383c78SLinus Walleij 		gc->parent = &pdev->dev;
2854d3e51161SHeiko Stübner 		gc->of_node = bank->of_node;
2855d3e51161SHeiko Stübner 		gc->label = bank->name;
2856d3e51161SHeiko Stübner 
285703bf81f1SLinus Walleij 		ret = gpiochip_add_data(gc, bank);
2858d3e51161SHeiko Stübner 		if (ret) {
2859d3e51161SHeiko Stübner 			dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
2860d3e51161SHeiko Stübner 							gc->label, ret);
2861d3e51161SHeiko Stübner 			goto fail;
2862d3e51161SHeiko Stübner 		}
2863d3e51161SHeiko Stübner 	}
2864d3e51161SHeiko Stübner 
2865d3e51161SHeiko Stübner 	rockchip_interrupts_register(pdev, info);
2866d3e51161SHeiko Stübner 
2867d3e51161SHeiko Stübner 	return 0;
2868d3e51161SHeiko Stübner 
2869d3e51161SHeiko Stübner fail:
2870d3e51161SHeiko Stübner 	for (--i, --bank; i >= 0; --i, --bank) {
2871d3e51161SHeiko Stübner 		if (!bank->valid)
2872d3e51161SHeiko Stübner 			continue;
2873b4e7c55dSabdoulaye berthe 		gpiochip_remove(&bank->gpio_chip);
2874d3e51161SHeiko Stübner 	}
2875d3e51161SHeiko Stübner 	return ret;
2876d3e51161SHeiko Stübner }
2877d3e51161SHeiko Stübner 
2878d3e51161SHeiko Stübner static int rockchip_gpiolib_unregister(struct platform_device *pdev,
2879d3e51161SHeiko Stübner 						struct rockchip_pinctrl *info)
2880d3e51161SHeiko Stübner {
2881d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
2882d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank = ctrl->pin_banks;
2883d3e51161SHeiko Stübner 	int i;
2884d3e51161SHeiko Stübner 
2885b4e7c55dSabdoulaye berthe 	for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
2886d3e51161SHeiko Stübner 		if (!bank->valid)
2887d3e51161SHeiko Stübner 			continue;
2888b4e7c55dSabdoulaye berthe 		gpiochip_remove(&bank->gpio_chip);
2889d3e51161SHeiko Stübner 	}
2890d3e51161SHeiko Stübner 
2891b4e7c55dSabdoulaye berthe 	return 0;
2892d3e51161SHeiko Stübner }
2893d3e51161SHeiko Stübner 
2894d3e51161SHeiko Stübner static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
2895622f3237SHeiko Stübner 				  struct rockchip_pinctrl *info)
2896d3e51161SHeiko Stübner {
2897d3e51161SHeiko Stübner 	struct resource res;
2898751a99abSHeiko Stübner 	void __iomem *base;
2899d3e51161SHeiko Stübner 
2900d3e51161SHeiko Stübner 	if (of_address_to_resource(bank->of_node, 0, &res)) {
2901622f3237SHeiko Stübner 		dev_err(info->dev, "cannot find IO resource for bank\n");
2902d3e51161SHeiko Stübner 		return -ENOENT;
2903d3e51161SHeiko Stübner 	}
2904d3e51161SHeiko Stübner 
2905622f3237SHeiko Stübner 	bank->reg_base = devm_ioremap_resource(info->dev, &res);
2906d3e51161SHeiko Stübner 	if (IS_ERR(bank->reg_base))
2907d3e51161SHeiko Stübner 		return PTR_ERR(bank->reg_base);
2908d3e51161SHeiko Stübner 
29096ca5274dSHeiko Stübner 	/*
29106ca5274dSHeiko Stübner 	 * special case, where parts of the pull setting-registers are
29116ca5274dSHeiko Stübner 	 * part of the PMU register space
29126ca5274dSHeiko Stübner 	 */
29136ca5274dSHeiko Stübner 	if (of_device_is_compatible(bank->of_node,
29146ca5274dSHeiko Stübner 				    "rockchip,rk3188-gpio-bank0")) {
2915a658efaaSHeiko Stübner 		struct device_node *node;
2916bfc7a42aSHeiko Stübner 
2917a658efaaSHeiko Stübner 		node = of_parse_phandle(bank->of_node->parent,
2918a658efaaSHeiko Stübner 					"rockchip,pmu", 0);
2919a658efaaSHeiko Stübner 		if (!node) {
29206ca5274dSHeiko Stübner 			if (of_address_to_resource(bank->of_node, 1, &res)) {
2921622f3237SHeiko Stübner 				dev_err(info->dev, "cannot find IO resource for bank\n");
29226ca5274dSHeiko Stübner 				return -ENOENT;
29236ca5274dSHeiko Stübner 			}
29246ca5274dSHeiko Stübner 
2925622f3237SHeiko Stübner 			base = devm_ioremap_resource(info->dev, &res);
2926751a99abSHeiko Stübner 			if (IS_ERR(base))
2927751a99abSHeiko Stübner 				return PTR_ERR(base);
2928a658efaaSHeiko Stübner 			rockchip_regmap_config.max_register =
2929a658efaaSHeiko Stübner 						    resource_size(&res) - 4;
2930a658efaaSHeiko Stübner 			rockchip_regmap_config.name =
2931a658efaaSHeiko Stübner 					    "rockchip,rk3188-gpio-bank0-pull";
2932a658efaaSHeiko Stübner 			bank->regmap_pull = devm_regmap_init_mmio(info->dev,
2933a658efaaSHeiko Stübner 						    base,
2934751a99abSHeiko Stübner 						    &rockchip_regmap_config);
2935a658efaaSHeiko Stübner 		}
29366ca5274dSHeiko Stübner 	}
293765fca613SHeiko Stübner 
2938d3e51161SHeiko Stübner 	bank->irq = irq_of_parse_and_map(bank->of_node, 0);
2939d3e51161SHeiko Stübner 
2940d3e51161SHeiko Stübner 	bank->clk = of_clk_get(bank->of_node, 0);
2941d3e51161SHeiko Stübner 	if (IS_ERR(bank->clk))
2942d3e51161SHeiko Stübner 		return PTR_ERR(bank->clk);
2943d3e51161SHeiko Stübner 
294407a06ae9SLin Huang 	return clk_prepare(bank->clk);
2945d3e51161SHeiko Stübner }
2946d3e51161SHeiko Stübner 
2947d3e51161SHeiko Stübner static const struct of_device_id rockchip_pinctrl_dt_match[];
2948d3e51161SHeiko Stübner 
2949d3e51161SHeiko Stübner /* retrieve the soc specific data */
2950d3e51161SHeiko Stübner static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
2951d3e51161SHeiko Stübner 						struct rockchip_pinctrl *d,
2952d3e51161SHeiko Stübner 						struct platform_device *pdev)
2953d3e51161SHeiko Stübner {
2954d3e51161SHeiko Stübner 	const struct of_device_id *match;
2955d3e51161SHeiko Stübner 	struct device_node *node = pdev->dev.of_node;
2956d3e51161SHeiko Stübner 	struct device_node *np;
2957d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl;
2958d3e51161SHeiko Stübner 	struct rockchip_pin_bank *bank;
2959b6c23275SDavid Wu 	int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j;
2960d3e51161SHeiko Stübner 
2961d3e51161SHeiko Stübner 	match = of_match_node(rockchip_pinctrl_dt_match, node);
2962d3e51161SHeiko Stübner 	ctrl = (struct rockchip_pin_ctrl *)match->data;
2963d3e51161SHeiko Stübner 
2964d3e51161SHeiko Stübner 	for_each_child_of_node(node, np) {
2965d3e51161SHeiko Stübner 		if (!of_find_property(np, "gpio-controller", NULL))
2966d3e51161SHeiko Stübner 			continue;
2967d3e51161SHeiko Stübner 
2968d3e51161SHeiko Stübner 		bank = ctrl->pin_banks;
2969d3e51161SHeiko Stübner 		for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
2970d3e51161SHeiko Stübner 			if (!strcmp(bank->name, np->name)) {
2971d3e51161SHeiko Stübner 				bank->of_node = np;
2972d3e51161SHeiko Stübner 
2973622f3237SHeiko Stübner 				if (!rockchip_get_bank_data(bank, d))
2974d3e51161SHeiko Stübner 					bank->valid = true;
2975d3e51161SHeiko Stübner 
2976d3e51161SHeiko Stübner 				break;
2977d3e51161SHeiko Stübner 			}
2978d3e51161SHeiko Stübner 		}
2979d3e51161SHeiko Stübner 	}
2980d3e51161SHeiko Stübner 
298195ec8ae4SHeiko Stübner 	grf_offs = ctrl->grf_mux_offset;
298295ec8ae4SHeiko Stübner 	pmu_offs = ctrl->pmu_mux_offset;
2983b6c23275SDavid Wu 	drv_pmu_offs = ctrl->pmu_drv_offset;
2984b6c23275SDavid Wu 	drv_grf_offs = ctrl->grf_drv_offset;
2985d3e51161SHeiko Stübner 	bank = ctrl->pin_banks;
2986d3e51161SHeiko Stübner 	for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
29876bc0d121SHeiko Stübner 		int bank_pins = 0;
29886bc0d121SHeiko Stübner 
298970b7aa7aSJohn Keeping 		raw_spin_lock_init(&bank->slock);
2990d3e51161SHeiko Stübner 		bank->drvdata = d;
2991d3e51161SHeiko Stübner 		bank->pin_base = ctrl->nr_pins;
2992d3e51161SHeiko Stübner 		ctrl->nr_pins += bank->nr_pins;
29936bc0d121SHeiko Stübner 
2994b6c23275SDavid Wu 		/* calculate iomux and drv offsets */
29956bc0d121SHeiko Stübner 		for (j = 0; j < 4; j++) {
29966bc0d121SHeiko Stübner 			struct rockchip_iomux *iom = &bank->iomux[j];
2997b6c23275SDavid Wu 			struct rockchip_drv *drv = &bank->drv[j];
299803716e1dSHeiko Stübner 			int inc;
29996bc0d121SHeiko Stübner 
30006bc0d121SHeiko Stübner 			if (bank_pins >= bank->nr_pins)
30016bc0d121SHeiko Stübner 				break;
30026bc0d121SHeiko Stübner 
3003b6c23275SDavid Wu 			/* preset iomux offset value, set new start value */
30046bc0d121SHeiko Stübner 			if (iom->offset >= 0) {
300595ec8ae4SHeiko Stübner 				if (iom->type & IOMUX_SOURCE_PMU)
300695ec8ae4SHeiko Stübner 					pmu_offs = iom->offset;
300795ec8ae4SHeiko Stübner 				else
30086bc0d121SHeiko Stübner 					grf_offs = iom->offset;
3009b6c23275SDavid Wu 			} else { /* set current iomux offset */
301095ec8ae4SHeiko Stübner 				iom->offset = (iom->type & IOMUX_SOURCE_PMU) ?
301195ec8ae4SHeiko Stübner 							pmu_offs : grf_offs;
30126bc0d121SHeiko Stübner 			}
30136bc0d121SHeiko Stübner 
3014b6c23275SDavid Wu 			/* preset drv offset value, set new start value */
3015b6c23275SDavid Wu 			if (drv->offset >= 0) {
3016b6c23275SDavid Wu 				if (iom->type & IOMUX_SOURCE_PMU)
3017b6c23275SDavid Wu 					drv_pmu_offs = drv->offset;
3018b6c23275SDavid Wu 				else
3019b6c23275SDavid Wu 					drv_grf_offs = drv->offset;
3020b6c23275SDavid Wu 			} else { /* set current drv offset */
3021b6c23275SDavid Wu 				drv->offset = (iom->type & IOMUX_SOURCE_PMU) ?
3022b6c23275SDavid Wu 						drv_pmu_offs : drv_grf_offs;
3023b6c23275SDavid Wu 			}
3024b6c23275SDavid Wu 
3025b6c23275SDavid Wu 			dev_dbg(d->dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset 0x%x\n",
3026b6c23275SDavid Wu 				i, j, iom->offset, drv->offset);
30276bc0d121SHeiko Stübner 
30286bc0d121SHeiko Stübner 			/*
30296bc0d121SHeiko Stübner 			 * Increase offset according to iomux width.
303003716e1dSHeiko Stübner 			 * 4bit iomux'es are spread over two registers.
30316bc0d121SHeiko Stübner 			 */
30328b6c6f93Sdavid.wu 			inc = (iom->type & (IOMUX_WIDTH_4BIT |
30338b6c6f93Sdavid.wu 					    IOMUX_WIDTH_3BIT)) ? 8 : 4;
303495ec8ae4SHeiko Stübner 			if (iom->type & IOMUX_SOURCE_PMU)
303595ec8ae4SHeiko Stübner 				pmu_offs += inc;
303695ec8ae4SHeiko Stübner 			else
303703716e1dSHeiko Stübner 				grf_offs += inc;
30386bc0d121SHeiko Stübner 
3039b6c23275SDavid Wu 			/*
3040b6c23275SDavid Wu 			 * Increase offset according to drv width.
3041b6c23275SDavid Wu 			 * 3bit drive-strenth'es are spread over two registers.
3042b6c23275SDavid Wu 			 */
3043b6c23275SDavid Wu 			if ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) ||
3044b6c23275SDavid Wu 			    (drv->drv_type == DRV_TYPE_IO_3V3_ONLY))
3045b6c23275SDavid Wu 				inc = 8;
3046b6c23275SDavid Wu 			else
3047b6c23275SDavid Wu 				inc = 4;
3048b6c23275SDavid Wu 
3049b6c23275SDavid Wu 			if (iom->type & IOMUX_SOURCE_PMU)
3050b6c23275SDavid Wu 				drv_pmu_offs += inc;
3051b6c23275SDavid Wu 			else
3052b6c23275SDavid Wu 				drv_grf_offs += inc;
3053b6c23275SDavid Wu 
30546bc0d121SHeiko Stübner 			bank_pins += 8;
30556bc0d121SHeiko Stübner 		}
3056bd35b9bfSDavid Wu 
3057c04c3fa6SDavid Wu 		/* calculate the per-bank recalced_mask */
3058c04c3fa6SDavid Wu 		for (j = 0; j < ctrl->niomux_recalced; j++) {
3059c04c3fa6SDavid Wu 			int pin = 0;
3060c04c3fa6SDavid Wu 
3061c04c3fa6SDavid Wu 			if (ctrl->iomux_recalced[j].num == bank->bank_num) {
3062c04c3fa6SDavid Wu 				pin = ctrl->iomux_recalced[j].pin;
3063c04c3fa6SDavid Wu 				bank->recalced_mask |= BIT(pin);
3064c04c3fa6SDavid Wu 			}
3065c04c3fa6SDavid Wu 		}
3066c04c3fa6SDavid Wu 
3067bd35b9bfSDavid Wu 		/* calculate the per-bank route_mask */
3068bd35b9bfSDavid Wu 		for (j = 0; j < ctrl->niomux_routes; j++) {
3069bd35b9bfSDavid Wu 			int pin = 0;
3070bd35b9bfSDavid Wu 
3071bd35b9bfSDavid Wu 			if (ctrl->iomux_routes[j].bank_num == bank->bank_num) {
3072bd35b9bfSDavid Wu 				pin = ctrl->iomux_routes[j].pin;
3073bd35b9bfSDavid Wu 				bank->route_mask |= BIT(pin);
3074bd35b9bfSDavid Wu 			}
3075bd35b9bfSDavid Wu 		}
3076d3e51161SHeiko Stübner 	}
3077d3e51161SHeiko Stübner 
3078d3e51161SHeiko Stübner 	return ctrl;
3079d3e51161SHeiko Stübner }
3080d3e51161SHeiko Stübner 
30818dca9331SChris Zhong #define RK3288_GRF_GPIO6C_IOMUX		0x64
30828dca9331SChris Zhong #define GPIO6C6_SEL_WRITE_ENABLE	BIT(28)
30838dca9331SChris Zhong 
30848dca9331SChris Zhong static u32 rk3288_grf_gpio6c_iomux;
30858dca9331SChris Zhong 
30869198f509SChris Zhong static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev)
30879198f509SChris Zhong {
30889198f509SChris Zhong 	struct rockchip_pinctrl *info = dev_get_drvdata(dev);
30898dca9331SChris Zhong 	int ret = pinctrl_force_sleep(info->pctl_dev);
30909198f509SChris Zhong 
30918dca9331SChris Zhong 	if (ret)
30928dca9331SChris Zhong 		return ret;
30938dca9331SChris Zhong 
30948dca9331SChris Zhong 	/*
30958dca9331SChris Zhong 	 * RK3288 GPIO6_C6 mux would be modified by Maskrom when resume, so save
30968dca9331SChris Zhong 	 * the setting here, and restore it at resume.
30978dca9331SChris Zhong 	 */
30988dca9331SChris Zhong 	if (info->ctrl->type == RK3288) {
30998dca9331SChris Zhong 		ret = regmap_read(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
31008dca9331SChris Zhong 				  &rk3288_grf_gpio6c_iomux);
31018dca9331SChris Zhong 		if (ret) {
31028dca9331SChris Zhong 			pinctrl_force_default(info->pctl_dev);
31038dca9331SChris Zhong 			return ret;
31048dca9331SChris Zhong 		}
31058dca9331SChris Zhong 	}
31068dca9331SChris Zhong 
31078dca9331SChris Zhong 	return 0;
31089198f509SChris Zhong }
31099198f509SChris Zhong 
31109198f509SChris Zhong static int __maybe_unused rockchip_pinctrl_resume(struct device *dev)
31119198f509SChris Zhong {
31129198f509SChris Zhong 	struct rockchip_pinctrl *info = dev_get_drvdata(dev);
31138dca9331SChris Zhong 	int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
31148dca9331SChris Zhong 			       rk3288_grf_gpio6c_iomux |
31158dca9331SChris Zhong 			       GPIO6C6_SEL_WRITE_ENABLE);
31168dca9331SChris Zhong 
31178dca9331SChris Zhong 	if (ret)
31188dca9331SChris Zhong 		return ret;
31199198f509SChris Zhong 
31209198f509SChris Zhong 	return pinctrl_force_default(info->pctl_dev);
31219198f509SChris Zhong }
31229198f509SChris Zhong 
31239198f509SChris Zhong static SIMPLE_DEV_PM_OPS(rockchip_pinctrl_dev_pm_ops, rockchip_pinctrl_suspend,
31249198f509SChris Zhong 			 rockchip_pinctrl_resume);
31259198f509SChris Zhong 
3126d3e51161SHeiko Stübner static int rockchip_pinctrl_probe(struct platform_device *pdev)
3127d3e51161SHeiko Stübner {
3128d3e51161SHeiko Stübner 	struct rockchip_pinctrl *info;
3129d3e51161SHeiko Stübner 	struct device *dev = &pdev->dev;
3130d3e51161SHeiko Stübner 	struct rockchip_pin_ctrl *ctrl;
313114dee867SHeiko Stübner 	struct device_node *np = pdev->dev.of_node, *node;
3132d3e51161SHeiko Stübner 	struct resource *res;
3133751a99abSHeiko Stübner 	void __iomem *base;
3134d3e51161SHeiko Stübner 	int ret;
3135d3e51161SHeiko Stübner 
3136d3e51161SHeiko Stübner 	if (!dev->of_node) {
3137d3e51161SHeiko Stübner 		dev_err(dev, "device tree node not found\n");
3138d3e51161SHeiko Stübner 		return -ENODEV;
3139d3e51161SHeiko Stübner 	}
3140d3e51161SHeiko Stübner 
3141d3e51161SHeiko Stübner 	info = devm_kzalloc(dev, sizeof(struct rockchip_pinctrl), GFP_KERNEL);
3142d3e51161SHeiko Stübner 	if (!info)
3143d3e51161SHeiko Stübner 		return -ENOMEM;
3144d3e51161SHeiko Stübner 
3145622f3237SHeiko Stübner 	info->dev = dev;
3146622f3237SHeiko Stübner 
3147d3e51161SHeiko Stübner 	ctrl = rockchip_pinctrl_get_soc_data(info, pdev);
3148d3e51161SHeiko Stübner 	if (!ctrl) {
3149d3e51161SHeiko Stübner 		dev_err(dev, "driver data not available\n");
3150d3e51161SHeiko Stübner 		return -EINVAL;
3151d3e51161SHeiko Stübner 	}
3152d3e51161SHeiko Stübner 	info->ctrl = ctrl;
3153d3e51161SHeiko Stübner 
31541e747e59SHeiko Stübner 	node = of_parse_phandle(np, "rockchip,grf", 0);
31551e747e59SHeiko Stübner 	if (node) {
31561e747e59SHeiko Stübner 		info->regmap_base = syscon_node_to_regmap(node);
31571e747e59SHeiko Stübner 		if (IS_ERR(info->regmap_base))
31581e747e59SHeiko Stübner 			return PTR_ERR(info->regmap_base);
31591e747e59SHeiko Stübner 	} else {
3160d3e51161SHeiko Stübner 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3161751a99abSHeiko Stübner 		base = devm_ioremap_resource(&pdev->dev, res);
3162751a99abSHeiko Stübner 		if (IS_ERR(base))
3163751a99abSHeiko Stübner 			return PTR_ERR(base);
3164751a99abSHeiko Stübner 
3165751a99abSHeiko Stübner 		rockchip_regmap_config.max_register = resource_size(res) - 4;
3166751a99abSHeiko Stübner 		rockchip_regmap_config.name = "rockchip,pinctrl";
3167751a99abSHeiko Stübner 		info->regmap_base = devm_regmap_init_mmio(&pdev->dev, base,
3168751a99abSHeiko Stübner 						    &rockchip_regmap_config);
3169d3e51161SHeiko Stübner 
3170bfc7a42aSHeiko Stübner 		/* to check for the old dt-bindings */
3171bfc7a42aSHeiko Stübner 		info->reg_size = resource_size(res);
3172bfc7a42aSHeiko Stübner 
3173bfc7a42aSHeiko Stübner 		/* Honor the old binding, with pull registers as 2nd resource */
3174bfc7a42aSHeiko Stübner 		if (ctrl->type == RK3188 && info->reg_size < 0x200) {
31756ca5274dSHeiko Stübner 			res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
3176751a99abSHeiko Stübner 			base = devm_ioremap_resource(&pdev->dev, res);
3177751a99abSHeiko Stübner 			if (IS_ERR(base))
3178751a99abSHeiko Stübner 				return PTR_ERR(base);
3179751a99abSHeiko Stübner 
31801e747e59SHeiko Stübner 			rockchip_regmap_config.max_register =
31811e747e59SHeiko Stübner 							resource_size(res) - 4;
3182751a99abSHeiko Stübner 			rockchip_regmap_config.name = "rockchip,pinctrl-pull";
31831e747e59SHeiko Stübner 			info->regmap_pull = devm_regmap_init_mmio(&pdev->dev,
31841e747e59SHeiko Stübner 						    base,
3185751a99abSHeiko Stübner 						    &rockchip_regmap_config);
31866ca5274dSHeiko Stübner 		}
31871e747e59SHeiko Stübner 	}
31886ca5274dSHeiko Stübner 
318914dee867SHeiko Stübner 	/* try to find the optional reference to the pmu syscon */
319014dee867SHeiko Stübner 	node = of_parse_phandle(np, "rockchip,pmu", 0);
319114dee867SHeiko Stübner 	if (node) {
319214dee867SHeiko Stübner 		info->regmap_pmu = syscon_node_to_regmap(node);
319314dee867SHeiko Stübner 		if (IS_ERR(info->regmap_pmu))
319414dee867SHeiko Stübner 			return PTR_ERR(info->regmap_pmu);
319514dee867SHeiko Stübner 	}
319614dee867SHeiko Stübner 
3197d3e51161SHeiko Stübner 	ret = rockchip_gpiolib_register(pdev, info);
3198d3e51161SHeiko Stübner 	if (ret)
3199d3e51161SHeiko Stübner 		return ret;
3200d3e51161SHeiko Stübner 
3201d3e51161SHeiko Stübner 	ret = rockchip_pinctrl_register(pdev, info);
3202d3e51161SHeiko Stübner 	if (ret) {
3203d3e51161SHeiko Stübner 		rockchip_gpiolib_unregister(pdev, info);
3204d3e51161SHeiko Stübner 		return ret;
3205d3e51161SHeiko Stübner 	}
3206d3e51161SHeiko Stübner 
3207d3e51161SHeiko Stübner 	platform_set_drvdata(pdev, info);
3208d3e51161SHeiko Stübner 
3209d3e51161SHeiko Stübner 	return 0;
3210d3e51161SHeiko Stübner }
3211d3e51161SHeiko Stübner 
3212b9c6dcabSAndy Yan static struct rockchip_pin_bank rv1108_pin_banks[] = {
3213688daf23SAndy Yan 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
3214688daf23SAndy Yan 					     IOMUX_SOURCE_PMU,
3215688daf23SAndy Yan 					     IOMUX_SOURCE_PMU,
3216688daf23SAndy Yan 					     IOMUX_SOURCE_PMU),
3217688daf23SAndy Yan 	PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
3218688daf23SAndy Yan 	PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0, 0, 0, 0),
3219688daf23SAndy Yan 	PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", 0, 0, 0, 0),
3220688daf23SAndy Yan };
3221688daf23SAndy Yan 
3222b9c6dcabSAndy Yan static struct rockchip_pin_ctrl rv1108_pin_ctrl = {
3223b9c6dcabSAndy Yan 	.pin_banks		= rv1108_pin_banks,
3224b9c6dcabSAndy Yan 	.nr_banks		= ARRAY_SIZE(rv1108_pin_banks),
3225b9c6dcabSAndy Yan 	.label			= "RV1108-GPIO",
3226b9c6dcabSAndy Yan 	.type			= RV1108,
3227688daf23SAndy Yan 	.grf_mux_offset		= 0x10,
3228688daf23SAndy Yan 	.pmu_mux_offset		= 0x0,
322912b8f018SDavid Wu 	.iomux_recalced		= rv1108_mux_recalced_data,
323012b8f018SDavid Wu 	.niomux_recalced	= ARRAY_SIZE(rv1108_mux_recalced_data),
3231b9c6dcabSAndy Yan 	.pull_calc_reg		= rv1108_calc_pull_reg_and_bit,
3232b9c6dcabSAndy Yan 	.drv_calc_reg		= rv1108_calc_drv_reg_and_bit,
32335caff7eaSAndy Yan 	.schmitt_calc_reg	= rv1108_calc_schmitt_reg_and_bit,
3234688daf23SAndy Yan };
3235688daf23SAndy Yan 
3236d3e51161SHeiko Stübner static struct rockchip_pin_bank rk2928_pin_banks[] = {
3237d3e51161SHeiko Stübner 	PIN_BANK(0, 32, "gpio0"),
3238d3e51161SHeiko Stübner 	PIN_BANK(1, 32, "gpio1"),
3239d3e51161SHeiko Stübner 	PIN_BANK(2, 32, "gpio2"),
3240d3e51161SHeiko Stübner 	PIN_BANK(3, 32, "gpio3"),
3241d3e51161SHeiko Stübner };
3242d3e51161SHeiko Stübner 
3243d3e51161SHeiko Stübner static struct rockchip_pin_ctrl rk2928_pin_ctrl = {
3244d3e51161SHeiko Stübner 		.pin_banks		= rk2928_pin_banks,
3245d3e51161SHeiko Stübner 		.nr_banks		= ARRAY_SIZE(rk2928_pin_banks),
3246d3e51161SHeiko Stübner 		.label			= "RK2928-GPIO",
3247a282926dSHeiko Stübner 		.type			= RK2928,
324895ec8ae4SHeiko Stübner 		.grf_mux_offset		= 0xa8,
3249a282926dSHeiko Stübner 		.pull_calc_reg		= rk2928_calc_pull_reg_and_bit,
3250d3e51161SHeiko Stübner };
3251d3e51161SHeiko Stübner 
3252c5ce7670SXing Zheng static struct rockchip_pin_bank rk3036_pin_banks[] = {
3253c5ce7670SXing Zheng 	PIN_BANK(0, 32, "gpio0"),
3254c5ce7670SXing Zheng 	PIN_BANK(1, 32, "gpio1"),
3255c5ce7670SXing Zheng 	PIN_BANK(2, 32, "gpio2"),
3256c5ce7670SXing Zheng };
3257c5ce7670SXing Zheng 
3258c5ce7670SXing Zheng static struct rockchip_pin_ctrl rk3036_pin_ctrl = {
3259c5ce7670SXing Zheng 		.pin_banks		= rk3036_pin_banks,
3260c5ce7670SXing Zheng 		.nr_banks		= ARRAY_SIZE(rk3036_pin_banks),
3261c5ce7670SXing Zheng 		.label			= "RK3036-GPIO",
3262c5ce7670SXing Zheng 		.type			= RK2928,
3263c5ce7670SXing Zheng 		.grf_mux_offset		= 0xa8,
3264c5ce7670SXing Zheng 		.pull_calc_reg		= rk2928_calc_pull_reg_and_bit,
3265c5ce7670SXing Zheng };
3266c5ce7670SXing Zheng 
3267d3e51161SHeiko Stübner static struct rockchip_pin_bank rk3066a_pin_banks[] = {
3268d3e51161SHeiko Stübner 	PIN_BANK(0, 32, "gpio0"),
3269d3e51161SHeiko Stübner 	PIN_BANK(1, 32, "gpio1"),
3270d3e51161SHeiko Stübner 	PIN_BANK(2, 32, "gpio2"),
3271d3e51161SHeiko Stübner 	PIN_BANK(3, 32, "gpio3"),
3272d3e51161SHeiko Stübner 	PIN_BANK(4, 32, "gpio4"),
3273d3e51161SHeiko Stübner 	PIN_BANK(6, 16, "gpio6"),
3274d3e51161SHeiko Stübner };
3275d3e51161SHeiko Stübner 
3276d3e51161SHeiko Stübner static struct rockchip_pin_ctrl rk3066a_pin_ctrl = {
3277d3e51161SHeiko Stübner 		.pin_banks		= rk3066a_pin_banks,
3278d3e51161SHeiko Stübner 		.nr_banks		= ARRAY_SIZE(rk3066a_pin_banks),
3279d3e51161SHeiko Stübner 		.label			= "RK3066a-GPIO",
3280a282926dSHeiko Stübner 		.type			= RK2928,
328195ec8ae4SHeiko Stübner 		.grf_mux_offset		= 0xa8,
3282a282926dSHeiko Stübner 		.pull_calc_reg		= rk2928_calc_pull_reg_and_bit,
3283d3e51161SHeiko Stübner };
3284d3e51161SHeiko Stübner 
3285d3e51161SHeiko Stübner static struct rockchip_pin_bank rk3066b_pin_banks[] = {
3286d3e51161SHeiko Stübner 	PIN_BANK(0, 32, "gpio0"),
3287d3e51161SHeiko Stübner 	PIN_BANK(1, 32, "gpio1"),
3288d3e51161SHeiko Stübner 	PIN_BANK(2, 32, "gpio2"),
3289d3e51161SHeiko Stübner 	PIN_BANK(3, 32, "gpio3"),
3290d3e51161SHeiko Stübner };
3291d3e51161SHeiko Stübner 
3292d3e51161SHeiko Stübner static struct rockchip_pin_ctrl rk3066b_pin_ctrl = {
3293d3e51161SHeiko Stübner 		.pin_banks	= rk3066b_pin_banks,
3294d3e51161SHeiko Stübner 		.nr_banks	= ARRAY_SIZE(rk3066b_pin_banks),
3295d3e51161SHeiko Stübner 		.label		= "RK3066b-GPIO",
3296a282926dSHeiko Stübner 		.type		= RK3066B,
329795ec8ae4SHeiko Stübner 		.grf_mux_offset	= 0x60,
3298d3e51161SHeiko Stübner };
3299d3e51161SHeiko Stübner 
3300d23c66dfSDavid Wu static struct rockchip_pin_bank rk3128_pin_banks[] = {
3301d23c66dfSDavid Wu 	PIN_BANK(0, 32, "gpio0"),
3302d23c66dfSDavid Wu 	PIN_BANK(1, 32, "gpio1"),
3303d23c66dfSDavid Wu 	PIN_BANK(2, 32, "gpio2"),
3304d23c66dfSDavid Wu 	PIN_BANK(3, 32, "gpio3"),
3305d23c66dfSDavid Wu };
3306d23c66dfSDavid Wu 
3307d23c66dfSDavid Wu static struct rockchip_pin_ctrl rk3128_pin_ctrl = {
3308d23c66dfSDavid Wu 		.pin_banks		= rk3128_pin_banks,
3309d23c66dfSDavid Wu 		.nr_banks		= ARRAY_SIZE(rk3128_pin_banks),
3310d23c66dfSDavid Wu 		.label			= "RK3128-GPIO",
3311d23c66dfSDavid Wu 		.type			= RK3128,
3312d23c66dfSDavid Wu 		.grf_mux_offset		= 0xa8,
3313d23c66dfSDavid Wu 		.iomux_recalced		= rk3128_mux_recalced_data,
3314d23c66dfSDavid Wu 		.niomux_recalced	= ARRAY_SIZE(rk3128_mux_recalced_data),
3315d23c66dfSDavid Wu 		.iomux_routes		= rk3128_mux_route_data,
3316d23c66dfSDavid Wu 		.niomux_routes		= ARRAY_SIZE(rk3128_mux_route_data),
3317d23c66dfSDavid Wu 		.pull_calc_reg		= rk3128_calc_pull_reg_and_bit,
3318d23c66dfSDavid Wu };
3319d23c66dfSDavid Wu 
3320d3e51161SHeiko Stübner static struct rockchip_pin_bank rk3188_pin_banks[] = {
3321fc72c923SHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_GPIO_ONLY, 0, 0, 0),
3322d3e51161SHeiko Stübner 	PIN_BANK(1, 32, "gpio1"),
3323d3e51161SHeiko Stübner 	PIN_BANK(2, 32, "gpio2"),
3324d3e51161SHeiko Stübner 	PIN_BANK(3, 32, "gpio3"),
3325d3e51161SHeiko Stübner };
3326d3e51161SHeiko Stübner 
3327d3e51161SHeiko Stübner static struct rockchip_pin_ctrl rk3188_pin_ctrl = {
3328d3e51161SHeiko Stübner 		.pin_banks		= rk3188_pin_banks,
3329d3e51161SHeiko Stübner 		.nr_banks		= ARRAY_SIZE(rk3188_pin_banks),
3330d3e51161SHeiko Stübner 		.label			= "RK3188-GPIO",
3331a282926dSHeiko Stübner 		.type			= RK3188,
333295ec8ae4SHeiko Stübner 		.grf_mux_offset		= 0x60,
33336ca5274dSHeiko Stübner 		.pull_calc_reg		= rk3188_calc_pull_reg_and_bit,
3334d3e51161SHeiko Stübner };
3335d3e51161SHeiko Stübner 
3336fea0fe60SJeffy Chen static struct rockchip_pin_bank rk3228_pin_banks[] = {
3337fea0fe60SJeffy Chen 	PIN_BANK(0, 32, "gpio0"),
3338fea0fe60SJeffy Chen 	PIN_BANK(1, 32, "gpio1"),
3339fea0fe60SJeffy Chen 	PIN_BANK(2, 32, "gpio2"),
3340fea0fe60SJeffy Chen 	PIN_BANK(3, 32, "gpio3"),
3341fea0fe60SJeffy Chen };
3342fea0fe60SJeffy Chen 
3343fea0fe60SJeffy Chen static struct rockchip_pin_ctrl rk3228_pin_ctrl = {
3344fea0fe60SJeffy Chen 		.pin_banks		= rk3228_pin_banks,
3345fea0fe60SJeffy Chen 		.nr_banks		= ARRAY_SIZE(rk3228_pin_banks),
3346fea0fe60SJeffy Chen 		.label			= "RK3228-GPIO",
3347fea0fe60SJeffy Chen 		.type			= RK3288,
3348fea0fe60SJeffy Chen 		.grf_mux_offset		= 0x0,
3349d4970ee0SDavid Wu 		.iomux_routes		= rk3228_mux_route_data,
3350d4970ee0SDavid Wu 		.niomux_routes		= ARRAY_SIZE(rk3228_mux_route_data),
3351fea0fe60SJeffy Chen 		.pull_calc_reg		= rk3228_calc_pull_reg_and_bit,
3352fea0fe60SJeffy Chen 		.drv_calc_reg		= rk3228_calc_drv_reg_and_bit,
3353fea0fe60SJeffy Chen };
3354fea0fe60SJeffy Chen 
3355304f077dSHeiko Stübner static struct rockchip_pin_bank rk3288_pin_banks[] = {
3356304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(0, 24, "gpio0", IOMUX_SOURCE_PMU,
3357304f077dSHeiko Stübner 					     IOMUX_SOURCE_PMU,
3358304f077dSHeiko Stübner 					     IOMUX_SOURCE_PMU,
3359304f077dSHeiko Stübner 					     IOMUX_UNROUTED
3360304f077dSHeiko Stübner 			    ),
3361304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_UNROUTED,
3362304f077dSHeiko Stübner 					     IOMUX_UNROUTED,
3363304f077dSHeiko Stübner 					     IOMUX_UNROUTED,
3364304f077dSHeiko Stübner 					     0
3365304f077dSHeiko Stübner 			    ),
3366304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0, 0, 0, IOMUX_UNROUTED),
3367304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", 0, 0, 0, IOMUX_WIDTH_4BIT),
3368304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(4, 32, "gpio4", IOMUX_WIDTH_4BIT,
3369304f077dSHeiko Stübner 					     IOMUX_WIDTH_4BIT,
3370304f077dSHeiko Stübner 					     0,
3371304f077dSHeiko Stübner 					     0
3372304f077dSHeiko Stübner 			    ),
3373304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(5, 32, "gpio5", IOMUX_UNROUTED,
3374304f077dSHeiko Stübner 					     0,
3375304f077dSHeiko Stübner 					     0,
3376304f077dSHeiko Stübner 					     IOMUX_UNROUTED
3377304f077dSHeiko Stübner 			    ),
3378304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(6, 32, "gpio6", 0, 0, 0, IOMUX_UNROUTED),
3379304f077dSHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(7, 32, "gpio7", 0,
3380304f077dSHeiko Stübner 					     0,
3381304f077dSHeiko Stübner 					     IOMUX_WIDTH_4BIT,
3382304f077dSHeiko Stübner 					     IOMUX_UNROUTED
3383304f077dSHeiko Stübner 			    ),
3384304f077dSHeiko Stübner 	PIN_BANK(8, 16, "gpio8"),
3385304f077dSHeiko Stübner };
3386304f077dSHeiko Stübner 
3387304f077dSHeiko Stübner static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
3388304f077dSHeiko Stübner 		.pin_banks		= rk3288_pin_banks,
3389304f077dSHeiko Stübner 		.nr_banks		= ARRAY_SIZE(rk3288_pin_banks),
3390304f077dSHeiko Stübner 		.label			= "RK3288-GPIO",
339166d750e1SHeiko Stübner 		.type			= RK3288,
3392304f077dSHeiko Stübner 		.grf_mux_offset		= 0x0,
3393304f077dSHeiko Stübner 		.pmu_mux_offset		= 0x84,
3394304f077dSHeiko Stübner 		.pull_calc_reg		= rk3288_calc_pull_reg_and_bit,
3395ef17f69fSHeiko Stübner 		.drv_calc_reg		= rk3288_calc_drv_reg_and_bit,
3396304f077dSHeiko Stübner };
3397304f077dSHeiko Stübner 
33983818e4a7Sdavid.wu static struct rockchip_pin_bank rk3328_pin_banks[] = {
33993818e4a7Sdavid.wu 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0),
34003818e4a7Sdavid.wu 	PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
34013818e4a7Sdavid.wu 	PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0,
3402c04c3fa6SDavid Wu 			     IOMUX_WIDTH_3BIT,
3403c04c3fa6SDavid Wu 			     IOMUX_WIDTH_3BIT,
34043818e4a7Sdavid.wu 			     0),
34053818e4a7Sdavid.wu 	PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3",
34063818e4a7Sdavid.wu 			     IOMUX_WIDTH_3BIT,
3407c04c3fa6SDavid Wu 			     IOMUX_WIDTH_3BIT,
34083818e4a7Sdavid.wu 			     0,
34093818e4a7Sdavid.wu 			     0),
34103818e4a7Sdavid.wu };
34113818e4a7Sdavid.wu 
34123818e4a7Sdavid.wu static struct rockchip_pin_ctrl rk3328_pin_ctrl = {
34133818e4a7Sdavid.wu 		.pin_banks		= rk3328_pin_banks,
34143818e4a7Sdavid.wu 		.nr_banks		= ARRAY_SIZE(rk3328_pin_banks),
34153818e4a7Sdavid.wu 		.label			= "RK3328-GPIO",
34163818e4a7Sdavid.wu 		.type			= RK3288,
34173818e4a7Sdavid.wu 		.grf_mux_offset		= 0x0,
3418c04c3fa6SDavid Wu 		.iomux_recalced		= rk3328_mux_recalced_data,
3419c04c3fa6SDavid Wu 		.niomux_recalced	= ARRAY_SIZE(rk3328_mux_recalced_data),
3420cedc964aSDavid Wu 		.iomux_routes		= rk3328_mux_route_data,
3421cedc964aSDavid Wu 		.niomux_routes		= ARRAY_SIZE(rk3328_mux_route_data),
34223818e4a7Sdavid.wu 		.pull_calc_reg		= rk3228_calc_pull_reg_and_bit,
34233818e4a7Sdavid.wu 		.drv_calc_reg		= rk3228_calc_drv_reg_and_bit,
3424728d3f5aSdavid.wu 		.schmitt_calc_reg	= rk3328_calc_schmitt_reg_and_bit,
34253818e4a7Sdavid.wu };
34263818e4a7Sdavid.wu 
3427daecdc66SHeiko Stübner static struct rockchip_pin_bank rk3368_pin_banks[] = {
3428daecdc66SHeiko Stübner 	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
3429daecdc66SHeiko Stübner 					     IOMUX_SOURCE_PMU,
3430daecdc66SHeiko Stübner 					     IOMUX_SOURCE_PMU,
3431daecdc66SHeiko Stübner 					     IOMUX_SOURCE_PMU
3432daecdc66SHeiko Stübner 			    ),
3433daecdc66SHeiko Stübner 	PIN_BANK(1, 32, "gpio1"),
3434daecdc66SHeiko Stübner 	PIN_BANK(2, 32, "gpio2"),
3435daecdc66SHeiko Stübner 	PIN_BANK(3, 32, "gpio3"),
3436daecdc66SHeiko Stübner };
3437daecdc66SHeiko Stübner 
3438daecdc66SHeiko Stübner static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
3439daecdc66SHeiko Stübner 		.pin_banks		= rk3368_pin_banks,
3440daecdc66SHeiko Stübner 		.nr_banks		= ARRAY_SIZE(rk3368_pin_banks),
3441daecdc66SHeiko Stübner 		.label			= "RK3368-GPIO",
3442daecdc66SHeiko Stübner 		.type			= RK3368,
3443daecdc66SHeiko Stübner 		.grf_mux_offset		= 0x0,
3444daecdc66SHeiko Stübner 		.pmu_mux_offset		= 0x0,
3445daecdc66SHeiko Stübner 		.pull_calc_reg		= rk3368_calc_pull_reg_and_bit,
3446daecdc66SHeiko Stübner 		.drv_calc_reg		= rk3368_calc_drv_reg_and_bit,
3447daecdc66SHeiko Stübner };
3448daecdc66SHeiko Stübner 
3449b6c23275SDavid Wu static struct rockchip_pin_bank rk3399_pin_banks[] = {
34503ba6767aSDavid Wu 	PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(0, 32, "gpio0",
34513ba6767aSDavid Wu 							 IOMUX_SOURCE_PMU,
3452b6c23275SDavid Wu 							 IOMUX_SOURCE_PMU,
3453b6c23275SDavid Wu 							 IOMUX_SOURCE_PMU,
3454b6c23275SDavid Wu 							 IOMUX_SOURCE_PMU,
3455b6c23275SDavid Wu 							 DRV_TYPE_IO_1V8_ONLY,
3456b6c23275SDavid Wu 							 DRV_TYPE_IO_1V8_ONLY,
3457b6c23275SDavid Wu 							 DRV_TYPE_IO_DEFAULT,
3458b6c23275SDavid Wu 							 DRV_TYPE_IO_DEFAULT,
3459*c437f65cSDavid Wu 							 0x80,
3460*c437f65cSDavid Wu 							 0x88,
3461b6c23275SDavid Wu 							 -1,
34623ba6767aSDavid Wu 							 -1,
34633ba6767aSDavid Wu 							 PULL_TYPE_IO_1V8_ONLY,
34643ba6767aSDavid Wu 							 PULL_TYPE_IO_1V8_ONLY,
34653ba6767aSDavid Wu 							 PULL_TYPE_IO_DEFAULT,
34663ba6767aSDavid Wu 							 PULL_TYPE_IO_DEFAULT
3467b6c23275SDavid Wu 							),
3468b6c23275SDavid Wu 	PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU,
3469b6c23275SDavid Wu 					IOMUX_SOURCE_PMU,
3470b6c23275SDavid Wu 					IOMUX_SOURCE_PMU,
3471b6c23275SDavid Wu 					IOMUX_SOURCE_PMU,
3472b6c23275SDavid Wu 					DRV_TYPE_IO_1V8_OR_3V0,
3473b6c23275SDavid Wu 					DRV_TYPE_IO_1V8_OR_3V0,
3474b6c23275SDavid Wu 					DRV_TYPE_IO_1V8_OR_3V0,
3475b6c23275SDavid Wu 					DRV_TYPE_IO_1V8_OR_3V0,
3476*c437f65cSDavid Wu 					0xa0,
3477*c437f65cSDavid Wu 					0xa8,
3478*c437f65cSDavid Wu 					0xb0,
3479*c437f65cSDavid Wu 					0xb8
3480b6c23275SDavid Wu 					),
34813ba6767aSDavid Wu 	PIN_BANK_DRV_FLAGS_PULL_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
3482b6c23275SDavid Wu 				      DRV_TYPE_IO_1V8_OR_3V0,
3483b6c23275SDavid Wu 				      DRV_TYPE_IO_1V8_ONLY,
34843ba6767aSDavid Wu 				      DRV_TYPE_IO_1V8_ONLY,
34853ba6767aSDavid Wu 				      PULL_TYPE_IO_DEFAULT,
34863ba6767aSDavid Wu 				      PULL_TYPE_IO_DEFAULT,
34873ba6767aSDavid Wu 				      PULL_TYPE_IO_1V8_ONLY,
34883ba6767aSDavid Wu 				      PULL_TYPE_IO_1V8_ONLY
3489b6c23275SDavid Wu 				      ),
3490b6c23275SDavid Wu 	PIN_BANK_DRV_FLAGS(3, 32, "gpio3", DRV_TYPE_IO_3V3_ONLY,
3491b6c23275SDavid Wu 			   DRV_TYPE_IO_3V3_ONLY,
3492b6c23275SDavid Wu 			   DRV_TYPE_IO_3V3_ONLY,
3493b6c23275SDavid Wu 			   DRV_TYPE_IO_1V8_OR_3V0
3494b6c23275SDavid Wu 			   ),
3495b6c23275SDavid Wu 	PIN_BANK_DRV_FLAGS(4, 32, "gpio4", DRV_TYPE_IO_1V8_OR_3V0,
3496b6c23275SDavid Wu 			   DRV_TYPE_IO_1V8_3V0_AUTO,
3497b6c23275SDavid Wu 			   DRV_TYPE_IO_1V8_OR_3V0,
3498b6c23275SDavid Wu 			   DRV_TYPE_IO_1V8_OR_3V0
3499b6c23275SDavid Wu 			   ),
3500b6c23275SDavid Wu };
3501b6c23275SDavid Wu 
3502b6c23275SDavid Wu static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
3503b6c23275SDavid Wu 		.pin_banks		= rk3399_pin_banks,
3504b6c23275SDavid Wu 		.nr_banks		= ARRAY_SIZE(rk3399_pin_banks),
3505b6c23275SDavid Wu 		.label			= "RK3399-GPIO",
3506b6c23275SDavid Wu 		.type			= RK3399,
3507b6c23275SDavid Wu 		.grf_mux_offset		= 0xe000,
3508b6c23275SDavid Wu 		.pmu_mux_offset		= 0x0,
3509b6c23275SDavid Wu 		.grf_drv_offset		= 0xe100,
3510b6c23275SDavid Wu 		.pmu_drv_offset		= 0x80,
3511accc1ce7SDavid Wu 		.iomux_routes		= rk3399_mux_route_data,
3512accc1ce7SDavid Wu 		.niomux_routes		= ARRAY_SIZE(rk3399_mux_route_data),
3513b6c23275SDavid Wu 		.pull_calc_reg		= rk3399_calc_pull_reg_and_bit,
3514b6c23275SDavid Wu 		.drv_calc_reg		= rk3399_calc_drv_reg_and_bit,
3515b6c23275SDavid Wu };
3516daecdc66SHeiko Stübner 
3517d3e51161SHeiko Stübner static const struct of_device_id rockchip_pinctrl_dt_match[] = {
3518b9c6dcabSAndy Yan 	{ .compatible = "rockchip,rv1108-pinctrl",
3519cdbbd26fSMasahiro Yamada 		.data = &rv1108_pin_ctrl },
3520d3e51161SHeiko Stübner 	{ .compatible = "rockchip,rk2928-pinctrl",
3521cdbbd26fSMasahiro Yamada 		.data = &rk2928_pin_ctrl },
3522c5ce7670SXing Zheng 	{ .compatible = "rockchip,rk3036-pinctrl",
3523cdbbd26fSMasahiro Yamada 		.data = &rk3036_pin_ctrl },
3524d3e51161SHeiko Stübner 	{ .compatible = "rockchip,rk3066a-pinctrl",
3525cdbbd26fSMasahiro Yamada 		.data = &rk3066a_pin_ctrl },
3526d3e51161SHeiko Stübner 	{ .compatible = "rockchip,rk3066b-pinctrl",
3527cdbbd26fSMasahiro Yamada 		.data = &rk3066b_pin_ctrl },
3528d23c66dfSDavid Wu 	{ .compatible = "rockchip,rk3128-pinctrl",
3529d23c66dfSDavid Wu 		.data = (void *)&rk3128_pin_ctrl },
3530d3e51161SHeiko Stübner 	{ .compatible = "rockchip,rk3188-pinctrl",
3531cdbbd26fSMasahiro Yamada 		.data = &rk3188_pin_ctrl },
3532fea0fe60SJeffy Chen 	{ .compatible = "rockchip,rk3228-pinctrl",
3533cdbbd26fSMasahiro Yamada 		.data = &rk3228_pin_ctrl },
3534304f077dSHeiko Stübner 	{ .compatible = "rockchip,rk3288-pinctrl",
3535cdbbd26fSMasahiro Yamada 		.data = &rk3288_pin_ctrl },
35363818e4a7Sdavid.wu 	{ .compatible = "rockchip,rk3328-pinctrl",
3537cdbbd26fSMasahiro Yamada 		.data = &rk3328_pin_ctrl },
3538daecdc66SHeiko Stübner 	{ .compatible = "rockchip,rk3368-pinctrl",
3539cdbbd26fSMasahiro Yamada 		.data = &rk3368_pin_ctrl },
3540b6c23275SDavid Wu 	{ .compatible = "rockchip,rk3399-pinctrl",
3541cdbbd26fSMasahiro Yamada 		.data = &rk3399_pin_ctrl },
3542d3e51161SHeiko Stübner 	{},
3543d3e51161SHeiko Stübner };
3544d3e51161SHeiko Stübner 
3545d3e51161SHeiko Stübner static struct platform_driver rockchip_pinctrl_driver = {
3546d3e51161SHeiko Stübner 	.probe		= rockchip_pinctrl_probe,
3547d3e51161SHeiko Stübner 	.driver = {
3548d3e51161SHeiko Stübner 		.name	= "rockchip-pinctrl",
35499198f509SChris Zhong 		.pm = &rockchip_pinctrl_dev_pm_ops,
35500be9e70dSAxel Lin 		.of_match_table = rockchip_pinctrl_dt_match,
3551d3e51161SHeiko Stübner 	},
3552d3e51161SHeiko Stübner };
3553d3e51161SHeiko Stübner 
3554d3e51161SHeiko Stübner static int __init rockchip_pinctrl_drv_register(void)
3555d3e51161SHeiko Stübner {
3556d3e51161SHeiko Stübner 	return platform_driver_register(&rockchip_pinctrl_driver);
3557d3e51161SHeiko Stübner }
3558d3e51161SHeiko Stübner postcore_initcall(rockchip_pinctrl_drv_register);
3559