xref: /OK3568_Linux_fs/u-boot/drivers/gpio/sh_pfc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Pinmuxed GPIO support for SuperH.
3*4882a593Smuzhiyun  * Copy from linux kernel driver/sh/pfc.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Magnus Damm
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General Public
8*4882a593Smuzhiyun  * License.  See the file "COPYING" in the main directory of this archive
9*4882a593Smuzhiyun  * for more details.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <asm/bitops.h>
14*4882a593Smuzhiyun #include <asm/io.h>
15*4882a593Smuzhiyun #include <sh_pfc.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun static struct pinmux_info *gpioc;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define pfc_phys_to_virt(p, a) ((void *)a)
20*4882a593Smuzhiyun 
enum_in_range(pinmux_enum_t enum_id,struct pinmux_range * r)21*4882a593Smuzhiyun static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun 	if (enum_id < r->begin)
24*4882a593Smuzhiyun 		return 0;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	if (enum_id > r->end)
27*4882a593Smuzhiyun 		return 0;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	return 1;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
gpio_read_raw_reg(void * mapped_reg,unsigned long reg_width)32*4882a593Smuzhiyun static unsigned long gpio_read_raw_reg(void *mapped_reg,
33*4882a593Smuzhiyun 				       unsigned long reg_width)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	switch (reg_width) {
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	case 8:
38*4882a593Smuzhiyun 		return readb(mapped_reg);
39*4882a593Smuzhiyun 	case 16:
40*4882a593Smuzhiyun 		return readw(mapped_reg);
41*4882a593Smuzhiyun 	case 32:
42*4882a593Smuzhiyun 		return readl(mapped_reg);
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	BUG();
46*4882a593Smuzhiyun 	return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
gpio_write_raw_reg(void * mapped_reg,unsigned long reg_width,unsigned long data)49*4882a593Smuzhiyun static void gpio_write_raw_reg(void *mapped_reg,
50*4882a593Smuzhiyun 			       unsigned long reg_width,
51*4882a593Smuzhiyun 			       unsigned long data)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	switch (reg_width) {
54*4882a593Smuzhiyun 	case 8:
55*4882a593Smuzhiyun 		writeb(data, mapped_reg);
56*4882a593Smuzhiyun 		return;
57*4882a593Smuzhiyun 	case 16:
58*4882a593Smuzhiyun 		writew(data, mapped_reg);
59*4882a593Smuzhiyun 		return;
60*4882a593Smuzhiyun 	case 32:
61*4882a593Smuzhiyun 		writel(data, mapped_reg);
62*4882a593Smuzhiyun 		return;
63*4882a593Smuzhiyun 	}
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	BUG();
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
gpio_read_bit(struct pinmux_data_reg * dr,unsigned long offset,unsigned long in_pos)68*4882a593Smuzhiyun static int gpio_read_bit(struct pinmux_data_reg *dr,
69*4882a593Smuzhiyun 			 unsigned long offset,
70*4882a593Smuzhiyun 			 unsigned long in_pos)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	unsigned long pos;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	pos = dr->reg_width - (in_pos + 1);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	debug("read_bit: addr = %lx, pos = %ld, r_width = %ld\n",
77*4882a593Smuzhiyun 	      dr->reg + offset, pos, dr->reg_width);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	return (gpio_read_raw_reg(dr->mapped_reg + offset,
80*4882a593Smuzhiyun 				  dr->reg_width) >> pos) & 1;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
gpio_write_bit(struct pinmux_data_reg * dr,unsigned long in_pos,unsigned long value)83*4882a593Smuzhiyun static void gpio_write_bit(struct pinmux_data_reg *dr,
84*4882a593Smuzhiyun 			   unsigned long in_pos, unsigned long value)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	unsigned long pos;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	pos = dr->reg_width - (in_pos + 1);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	debug("write_bit addr = %lx, value = %d, pos = %ld, "
91*4882a593Smuzhiyun 		 "r_width = %ld\n",
92*4882a593Smuzhiyun 		 dr->reg, !!value, pos, dr->reg_width);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	if (value)
95*4882a593Smuzhiyun 		__set_bit(pos, &dr->reg_shadow);
96*4882a593Smuzhiyun 	else
97*4882a593Smuzhiyun 		__clear_bit(pos, &dr->reg_shadow);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
config_reg_helper(struct pinmux_info * gpioc,struct pinmux_cfg_reg * crp,unsigned long in_pos,void ** mapped_regp,unsigned long * maskp,unsigned long * posp)102*4882a593Smuzhiyun static void config_reg_helper(struct pinmux_info *gpioc,
103*4882a593Smuzhiyun 			      struct pinmux_cfg_reg *crp,
104*4882a593Smuzhiyun 			      unsigned long in_pos,
105*4882a593Smuzhiyun #if 0
106*4882a593Smuzhiyun 			      void __iomem **mapped_regp,
107*4882a593Smuzhiyun #else
108*4882a593Smuzhiyun 			      void **mapped_regp,
109*4882a593Smuzhiyun #endif
110*4882a593Smuzhiyun 			      unsigned long *maskp,
111*4882a593Smuzhiyun 			      unsigned long *posp)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	int k;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	*mapped_regp = pfc_phys_to_virt(gpioc, crp->reg);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (crp->field_width) {
118*4882a593Smuzhiyun 		*maskp = (1 << crp->field_width) - 1;
119*4882a593Smuzhiyun 		*posp = crp->reg_width - ((in_pos + 1) * crp->field_width);
120*4882a593Smuzhiyun 	} else {
121*4882a593Smuzhiyun 		*maskp = (1 << crp->var_field_width[in_pos]) - 1;
122*4882a593Smuzhiyun 		*posp = crp->reg_width;
123*4882a593Smuzhiyun 		for (k = 0; k <= in_pos; k++)
124*4882a593Smuzhiyun 			*posp -= crp->var_field_width[k];
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
read_config_reg(struct pinmux_info * gpioc,struct pinmux_cfg_reg * crp,unsigned long field)128*4882a593Smuzhiyun static int read_config_reg(struct pinmux_info *gpioc,
129*4882a593Smuzhiyun 			   struct pinmux_cfg_reg *crp,
130*4882a593Smuzhiyun 			   unsigned long field)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	void *mapped_reg;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	unsigned long mask, pos;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	debug("read_reg: addr = %lx, field = %ld, "
139*4882a593Smuzhiyun 		 "r_width = %ld, f_width = %ld\n",
140*4882a593Smuzhiyun 		 crp->reg, field, crp->reg_width, crp->field_width);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
write_config_reg(struct pinmux_info * gpioc,struct pinmux_cfg_reg * crp,unsigned long field,unsigned long value)145*4882a593Smuzhiyun static void write_config_reg(struct pinmux_info *gpioc,
146*4882a593Smuzhiyun 			     struct pinmux_cfg_reg *crp,
147*4882a593Smuzhiyun 			     unsigned long field, unsigned long value)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	void *mapped_reg;
150*4882a593Smuzhiyun 	unsigned long mask, pos, data;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	debug("write_reg addr = %lx, value = %ld, field = %ld, "
155*4882a593Smuzhiyun 		 "r_width = %ld, f_width = %ld\n",
156*4882a593Smuzhiyun 		 crp->reg, value, field, crp->reg_width, crp->field_width);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	mask = ~(mask << pos);
159*4882a593Smuzhiyun 	value = value << pos;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	data = gpio_read_raw_reg(mapped_reg, crp->reg_width);
162*4882a593Smuzhiyun 	data &= mask;
163*4882a593Smuzhiyun 	data |= value;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (gpioc->unlock_reg)
166*4882a593Smuzhiyun 		gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg),
167*4882a593Smuzhiyun 				   32, ~data);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	gpio_write_raw_reg(mapped_reg, crp->reg_width, data);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
setup_data_reg(struct pinmux_info * gpioc,unsigned gpio)172*4882a593Smuzhiyun static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
175*4882a593Smuzhiyun 	struct pinmux_data_reg *data_reg;
176*4882a593Smuzhiyun 	int k, n;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
179*4882a593Smuzhiyun 		return -1;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	k = 0;
182*4882a593Smuzhiyun 	while (1) {
183*4882a593Smuzhiyun 		data_reg = gpioc->data_regs + k;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		if (!data_reg->reg_width)
186*4882a593Smuzhiyun 			break;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		data_reg->mapped_reg = pfc_phys_to_virt(gpioc, data_reg->reg);
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 		for (n = 0; n < data_reg->reg_width; n++) {
191*4882a593Smuzhiyun 			if (data_reg->enum_ids[n] == gpiop->enum_id) {
192*4882a593Smuzhiyun 				gpiop->flags &= ~PINMUX_FLAG_DREG;
193*4882a593Smuzhiyun 				gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT);
194*4882a593Smuzhiyun 				gpiop->flags &= ~PINMUX_FLAG_DBIT;
195*4882a593Smuzhiyun 				gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT);
196*4882a593Smuzhiyun 				return 0;
197*4882a593Smuzhiyun 			}
198*4882a593Smuzhiyun 		}
199*4882a593Smuzhiyun 		k++;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	BUG();
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	return -1;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
setup_data_regs(struct pinmux_info * gpioc)207*4882a593Smuzhiyun static void setup_data_regs(struct pinmux_info *gpioc)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	struct pinmux_data_reg *drp;
210*4882a593Smuzhiyun 	int k;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
213*4882a593Smuzhiyun 		setup_data_reg(gpioc, k);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	k = 0;
216*4882a593Smuzhiyun 	while (1) {
217*4882a593Smuzhiyun 		drp = gpioc->data_regs + k;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		if (!drp->reg_width)
220*4882a593Smuzhiyun 			break;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 		drp->reg_shadow = gpio_read_raw_reg(drp->mapped_reg,
223*4882a593Smuzhiyun 						    drp->reg_width);
224*4882a593Smuzhiyun 		k++;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
get_data_reg(struct pinmux_info * gpioc,unsigned gpio,struct pinmux_data_reg ** drp,int * bitp)228*4882a593Smuzhiyun static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
229*4882a593Smuzhiyun 			struct pinmux_data_reg **drp, int *bitp)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	struct pinmux_gpio *gpiop = &gpioc->gpios[gpio];
232*4882a593Smuzhiyun 	int k, n;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (!enum_in_range(gpiop->enum_id, &gpioc->data))
235*4882a593Smuzhiyun 		return -1;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT;
238*4882a593Smuzhiyun 	n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT;
239*4882a593Smuzhiyun 	*drp = gpioc->data_regs + k;
240*4882a593Smuzhiyun 	*bitp = n;
241*4882a593Smuzhiyun 	return 0;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
get_config_reg(struct pinmux_info * gpioc,pinmux_enum_t enum_id,struct pinmux_cfg_reg ** crp,int * fieldp,int * valuep,unsigned long ** cntp)244*4882a593Smuzhiyun static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id,
245*4882a593Smuzhiyun 			  struct pinmux_cfg_reg **crp,
246*4882a593Smuzhiyun 			  int *fieldp, int *valuep,
247*4882a593Smuzhiyun 			  unsigned long **cntp)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	struct pinmux_cfg_reg *config_reg;
250*4882a593Smuzhiyun 	unsigned long r_width, f_width, curr_width, ncomb;
251*4882a593Smuzhiyun 	int k, m, n, pos, bit_pos;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	k = 0;
254*4882a593Smuzhiyun 	while (1) {
255*4882a593Smuzhiyun 		config_reg = gpioc->cfg_regs + k;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		r_width = config_reg->reg_width;
258*4882a593Smuzhiyun 		f_width = config_reg->field_width;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		if (!r_width)
261*4882a593Smuzhiyun 			break;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 		pos = 0;
264*4882a593Smuzhiyun 		m = 0;
265*4882a593Smuzhiyun 		for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) {
266*4882a593Smuzhiyun 			if (f_width)
267*4882a593Smuzhiyun 				curr_width = f_width;
268*4882a593Smuzhiyun 			else
269*4882a593Smuzhiyun 				curr_width = config_reg->var_field_width[m];
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 			ncomb = 1 << curr_width;
272*4882a593Smuzhiyun 			for (n = 0; n < ncomb; n++) {
273*4882a593Smuzhiyun 				if (config_reg->enum_ids[pos + n] == enum_id) {
274*4882a593Smuzhiyun 					*crp = config_reg;
275*4882a593Smuzhiyun 					*fieldp = m;
276*4882a593Smuzhiyun 					*valuep = n;
277*4882a593Smuzhiyun 					*cntp = &config_reg->cnt[m];
278*4882a593Smuzhiyun 					return 0;
279*4882a593Smuzhiyun 				}
280*4882a593Smuzhiyun 			}
281*4882a593Smuzhiyun 			pos += ncomb;
282*4882a593Smuzhiyun 			m++;
283*4882a593Smuzhiyun 		}
284*4882a593Smuzhiyun 		k++;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	return -1;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
get_gpio_enum_id(struct pinmux_info * gpioc,unsigned gpio,int pos,pinmux_enum_t * enum_idp)290*4882a593Smuzhiyun static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio,
291*4882a593Smuzhiyun 			    int pos, pinmux_enum_t *enum_idp)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id;
294*4882a593Smuzhiyun 	pinmux_enum_t *data = gpioc->gpio_data;
295*4882a593Smuzhiyun 	int k;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	if (!enum_in_range(enum_id, &gpioc->data)) {
298*4882a593Smuzhiyun 		if (!enum_in_range(enum_id, &gpioc->mark)) {
299*4882a593Smuzhiyun 			debug("non data/mark enum_id for gpio %d\n", gpio);
300*4882a593Smuzhiyun 			return -1;
301*4882a593Smuzhiyun 		}
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (pos) {
305*4882a593Smuzhiyun 		*enum_idp = data[pos + 1];
306*4882a593Smuzhiyun 		return pos + 1;
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	for (k = 0; k < gpioc->gpio_data_size; k++) {
310*4882a593Smuzhiyun 		if (data[k] == enum_id) {
311*4882a593Smuzhiyun 			*enum_idp = data[k + 1];
312*4882a593Smuzhiyun 			return k + 1;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 	}
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	debug("cannot locate data/mark enum_id for gpio %d\n", gpio);
317*4882a593Smuzhiyun 	return -1;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
321*4882a593Smuzhiyun 
pinmux_config_gpio(struct pinmux_info * gpioc,unsigned gpio,int pinmux_type,int cfg_mode)322*4882a593Smuzhiyun static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio,
323*4882a593Smuzhiyun 			      int pinmux_type, int cfg_mode)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct pinmux_cfg_reg *cr = NULL;
326*4882a593Smuzhiyun 	pinmux_enum_t enum_id;
327*4882a593Smuzhiyun 	struct pinmux_range *range;
328*4882a593Smuzhiyun 	int in_range, pos, field, value;
329*4882a593Smuzhiyun 	unsigned long *cntp;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	switch (pinmux_type) {
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	case PINMUX_TYPE_FUNCTION:
334*4882a593Smuzhiyun 		range = NULL;
335*4882a593Smuzhiyun 		break;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	case PINMUX_TYPE_OUTPUT:
338*4882a593Smuzhiyun 		range = &gpioc->output;
339*4882a593Smuzhiyun 		break;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT:
342*4882a593Smuzhiyun 		range = &gpioc->input;
343*4882a593Smuzhiyun 		break;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT_PULLUP:
346*4882a593Smuzhiyun 		range = &gpioc->input_pu;
347*4882a593Smuzhiyun 		break;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT_PULLDOWN:
350*4882a593Smuzhiyun 		range = &gpioc->input_pd;
351*4882a593Smuzhiyun 		break;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	default:
354*4882a593Smuzhiyun 		goto out_err;
355*4882a593Smuzhiyun 	}
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	pos = 0;
358*4882a593Smuzhiyun 	enum_id = 0;
359*4882a593Smuzhiyun 	field = 0;
360*4882a593Smuzhiyun 	value = 0;
361*4882a593Smuzhiyun 	while (1) {
362*4882a593Smuzhiyun 		pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id);
363*4882a593Smuzhiyun 		if (pos <= 0)
364*4882a593Smuzhiyun 			goto out_err;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		if (!enum_id)
367*4882a593Smuzhiyun 			break;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 		/* first check if this is a function enum */
370*4882a593Smuzhiyun 		in_range = enum_in_range(enum_id, &gpioc->function);
371*4882a593Smuzhiyun 		if (!in_range) {
372*4882a593Smuzhiyun 			/* not a function enum */
373*4882a593Smuzhiyun 			if (range) {
374*4882a593Smuzhiyun 				/*
375*4882a593Smuzhiyun 				 * other range exists, so this pin is
376*4882a593Smuzhiyun 				 * a regular GPIO pin that now is being
377*4882a593Smuzhiyun 				 * bound to a specific direction.
378*4882a593Smuzhiyun 				 *
379*4882a593Smuzhiyun 				 * for this case we only allow function enums
380*4882a593Smuzhiyun 				 * and the enums that match the other range.
381*4882a593Smuzhiyun 				 */
382*4882a593Smuzhiyun 				in_range = enum_in_range(enum_id, range);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 				/*
385*4882a593Smuzhiyun 				 * special case pass through for fixed
386*4882a593Smuzhiyun 				 * input-only or output-only pins without
387*4882a593Smuzhiyun 				 * function enum register association.
388*4882a593Smuzhiyun 				 */
389*4882a593Smuzhiyun 				if (in_range && enum_id == range->force)
390*4882a593Smuzhiyun 					continue;
391*4882a593Smuzhiyun 			} else {
392*4882a593Smuzhiyun 				/*
393*4882a593Smuzhiyun 				 * no other range exists, so this pin
394*4882a593Smuzhiyun 				 * must then be of the function type.
395*4882a593Smuzhiyun 				 *
396*4882a593Smuzhiyun 				 * allow function type pins to select
397*4882a593Smuzhiyun 				 * any combination of function/in/out
398*4882a593Smuzhiyun 				 * in their MARK lists.
399*4882a593Smuzhiyun 				 */
400*4882a593Smuzhiyun 				in_range = 1;
401*4882a593Smuzhiyun 			}
402*4882a593Smuzhiyun 		}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 		if (!in_range)
405*4882a593Smuzhiyun 			continue;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 		if (get_config_reg(gpioc, enum_id, &cr,
408*4882a593Smuzhiyun 				   &field, &value, &cntp) != 0)
409*4882a593Smuzhiyun 			goto out_err;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 		switch (cfg_mode) {
412*4882a593Smuzhiyun 		case GPIO_CFG_DRYRUN:
413*4882a593Smuzhiyun 			if (!*cntp ||
414*4882a593Smuzhiyun 			    (read_config_reg(gpioc, cr, field) != value))
415*4882a593Smuzhiyun 				continue;
416*4882a593Smuzhiyun 			break;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		case GPIO_CFG_REQ:
419*4882a593Smuzhiyun 			write_config_reg(gpioc, cr, field, value);
420*4882a593Smuzhiyun 			*cntp = *cntp + 1;
421*4882a593Smuzhiyun 			break;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 		case GPIO_CFG_FREE:
424*4882a593Smuzhiyun 			*cntp = *cntp - 1;
425*4882a593Smuzhiyun 			break;
426*4882a593Smuzhiyun 		}
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	return 0;
430*4882a593Smuzhiyun  out_err:
431*4882a593Smuzhiyun 	return -1;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun #if 0
435*4882a593Smuzhiyun static DEFINE_SPINLOCK(gpio_lock);
436*4882a593Smuzhiyun static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	return container_of(chip, struct pinmux_info, chip);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun #endif
441*4882a593Smuzhiyun 
sh_gpio_request(unsigned offset)442*4882a593Smuzhiyun static int sh_gpio_request(unsigned offset)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	struct pinmux_data_reg *dummy;
445*4882a593Smuzhiyun 	int i, ret, pinmux_type;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	ret = -1;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if (!gpioc)
450*4882a593Smuzhiyun 		goto err_out;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
453*4882a593Smuzhiyun 		goto err_out;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	/* setup pin function here if no data is associated with pin */
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (get_data_reg(gpioc, offset, &dummy, &i) != 0)
458*4882a593Smuzhiyun 		pinmux_type = PINMUX_TYPE_FUNCTION;
459*4882a593Smuzhiyun 	else
460*4882a593Smuzhiyun 		pinmux_type = PINMUX_TYPE_GPIO;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	if (pinmux_type == PINMUX_TYPE_FUNCTION) {
463*4882a593Smuzhiyun 		if (pinmux_config_gpio(gpioc, offset,
464*4882a593Smuzhiyun 				       pinmux_type,
465*4882a593Smuzhiyun 				       GPIO_CFG_DRYRUN) != 0)
466*4882a593Smuzhiyun 			goto err_out;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		if (pinmux_config_gpio(gpioc, offset,
469*4882a593Smuzhiyun 				       pinmux_type,
470*4882a593Smuzhiyun 				       GPIO_CFG_REQ) != 0)
471*4882a593Smuzhiyun 			BUG();
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
475*4882a593Smuzhiyun 	gpioc->gpios[offset].flags |= pinmux_type;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	ret = 0;
478*4882a593Smuzhiyun err_out:
479*4882a593Smuzhiyun 	return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
sh_gpio_free(unsigned offset)482*4882a593Smuzhiyun static void sh_gpio_free(unsigned offset)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	int pinmux_type;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!gpioc)
487*4882a593Smuzhiyun 		return;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE;
490*4882a593Smuzhiyun 	pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE);
491*4882a593Smuzhiyun 	gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
492*4882a593Smuzhiyun 	gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
pinmux_direction(struct pinmux_info * gpioc,unsigned gpio,int new_pinmux_type)495*4882a593Smuzhiyun static int pinmux_direction(struct pinmux_info *gpioc,
496*4882a593Smuzhiyun 			    unsigned gpio, int new_pinmux_type)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	int pinmux_type;
499*4882a593Smuzhiyun 	int ret = -1;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	if (!gpioc)
502*4882a593Smuzhiyun 		goto err_out;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	switch (pinmux_type) {
507*4882a593Smuzhiyun 	case PINMUX_TYPE_GPIO:
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 	case PINMUX_TYPE_OUTPUT:
510*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT:
511*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT_PULLUP:
512*4882a593Smuzhiyun 	case PINMUX_TYPE_INPUT_PULLDOWN:
513*4882a593Smuzhiyun 		pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE);
514*4882a593Smuzhiyun 		break;
515*4882a593Smuzhiyun 	default:
516*4882a593Smuzhiyun 		goto err_out;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	if (pinmux_config_gpio(gpioc, gpio,
520*4882a593Smuzhiyun 			       new_pinmux_type,
521*4882a593Smuzhiyun 			       GPIO_CFG_DRYRUN) != 0)
522*4882a593Smuzhiyun 		goto err_out;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	if (pinmux_config_gpio(gpioc, gpio,
525*4882a593Smuzhiyun 			       new_pinmux_type,
526*4882a593Smuzhiyun 			       GPIO_CFG_REQ) != 0)
527*4882a593Smuzhiyun 		BUG();
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE;
530*4882a593Smuzhiyun 	gpioc->gpios[gpio].flags |= new_pinmux_type;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	ret = 0;
533*4882a593Smuzhiyun  err_out:
534*4882a593Smuzhiyun 	return ret;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
sh_gpio_direction_input(unsigned offset)537*4882a593Smuzhiyun static int sh_gpio_direction_input(unsigned offset)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	return pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
sh_gpio_set_value(struct pinmux_info * gpioc,unsigned gpio,int value)542*4882a593Smuzhiyun static void sh_gpio_set_value(struct pinmux_info *gpioc,
543*4882a593Smuzhiyun 			     unsigned gpio, int value)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	struct pinmux_data_reg *dr = NULL;
546*4882a593Smuzhiyun 	int bit = 0;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
549*4882a593Smuzhiyun 		BUG();
550*4882a593Smuzhiyun 	else
551*4882a593Smuzhiyun 		gpio_write_bit(dr, bit, value);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
sh_gpio_direction_output(unsigned offset,int value)554*4882a593Smuzhiyun static int sh_gpio_direction_output(unsigned offset, int value)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	sh_gpio_set_value(gpioc, offset, value);
557*4882a593Smuzhiyun 	return pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
sh_gpio_get_value(struct pinmux_info * gpioc,unsigned gpio)560*4882a593Smuzhiyun static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	struct pinmux_data_reg *dr = NULL;
563*4882a593Smuzhiyun 	int bit = 0, offset = 0;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
566*4882a593Smuzhiyun 		return -1;
567*4882a593Smuzhiyun #if defined(CONFIG_RCAR_GEN3)
568*4882a593Smuzhiyun 	if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) == PINMUX_TYPE_INPUT)
569*4882a593Smuzhiyun 		offset += 4;
570*4882a593Smuzhiyun #endif
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	return gpio_read_bit(dr, offset, bit);
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
sh_gpio_get(unsigned offset)575*4882a593Smuzhiyun static int sh_gpio_get(unsigned offset)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun 	return sh_gpio_get_value(gpioc, offset);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
sh_gpio_set(unsigned offset,int value)580*4882a593Smuzhiyun static void sh_gpio_set(unsigned offset, int value)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	sh_gpio_set_value(gpioc, offset, value);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
register_pinmux(struct pinmux_info * pip)585*4882a593Smuzhiyun int register_pinmux(struct pinmux_info *pip)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	if (pip != NULL) {
588*4882a593Smuzhiyun 		gpioc = pip;
589*4882a593Smuzhiyun 		debug("%s deregistering\n", pip->name);
590*4882a593Smuzhiyun 		setup_data_regs(gpioc);
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun 	return 0;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
unregister_pinmux(struct pinmux_info * pip)595*4882a593Smuzhiyun int unregister_pinmux(struct pinmux_info *pip)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	debug("%s deregistering\n", pip->name);
598*4882a593Smuzhiyun 	if (gpioc != pip)
599*4882a593Smuzhiyun 		return -1;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	gpioc = NULL;
602*4882a593Smuzhiyun 	return 0;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
gpio_request(unsigned gpio,const char * label)605*4882a593Smuzhiyun int gpio_request(unsigned gpio, const char *label)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun 	sh_gpio_request(gpio);
608*4882a593Smuzhiyun 	return 0;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
gpio_free(unsigned gpio)611*4882a593Smuzhiyun int gpio_free(unsigned gpio)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	sh_gpio_free(gpio);
614*4882a593Smuzhiyun 	return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
gpio_direction_input(unsigned gpio)617*4882a593Smuzhiyun int gpio_direction_input(unsigned gpio)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	return sh_gpio_direction_input(gpio);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun 
gpio_direction_output(unsigned gpio,int value)622*4882a593Smuzhiyun int gpio_direction_output(unsigned gpio, int value)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun 	return sh_gpio_direction_output(gpio, value);
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
gpio_set_value(unsigned gpio,int value)627*4882a593Smuzhiyun void gpio_set_value(unsigned gpio, int value)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	sh_gpio_set(gpio, value);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
gpio_get_value(unsigned gpio)632*4882a593Smuzhiyun int gpio_get_value(unsigned gpio)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	return sh_gpio_get(gpio);
635*4882a593Smuzhiyun }
636