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