Commit fae4339919c741f89f7e293b8c646207e1df28e1
Committed by
Paul Mundt
1 parent
fc1d003de3
Exists in
master
and in
39 other branches
sh: Break out SuperH PFC code
This file breaks out the SuperH PFC code from arch/sh/kernel/gpio.c + arch/sh/include/asm/gpio.h to drivers/sh/pfc.c + include/linux/sh_pfc.h. Similar to the INTC stuff. The non-SuperH specific file location makes it possible to share the code between multiple architectures. Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 6 changed files with 682 additions and 666 deletions Side-by-side Diff
arch/sh/include/asm/gpio.h
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | #endif |
21 | 21 | |
22 | 22 | #define ARCH_NR_GPIOS 512 |
23 | -#include <asm-generic/gpio.h> | |
23 | +#include <linux/sh_pfc.h> | |
24 | 24 | |
25 | 25 | #ifdef CONFIG_GPIOLIB |
26 | 26 | |
... | ... | @@ -52,86 +52,6 @@ |
52 | 52 | } |
53 | 53 | |
54 | 54 | #endif /* CONFIG_GPIOLIB */ |
55 | - | |
56 | -typedef unsigned short pinmux_enum_t; | |
57 | -typedef unsigned short pinmux_flag_t; | |
58 | - | |
59 | -#define PINMUX_TYPE_NONE 0 | |
60 | -#define PINMUX_TYPE_FUNCTION 1 | |
61 | -#define PINMUX_TYPE_GPIO 2 | |
62 | -#define PINMUX_TYPE_OUTPUT 3 | |
63 | -#define PINMUX_TYPE_INPUT 4 | |
64 | -#define PINMUX_TYPE_INPUT_PULLUP 5 | |
65 | -#define PINMUX_TYPE_INPUT_PULLDOWN 6 | |
66 | - | |
67 | -#define PINMUX_FLAG_TYPE (0x7) | |
68 | -#define PINMUX_FLAG_WANT_PULLUP (1 << 3) | |
69 | -#define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) | |
70 | - | |
71 | -#define PINMUX_FLAG_DBIT_SHIFT 5 | |
72 | -#define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT) | |
73 | -#define PINMUX_FLAG_DREG_SHIFT 10 | |
74 | -#define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT) | |
75 | - | |
76 | -struct pinmux_gpio { | |
77 | - pinmux_enum_t enum_id; | |
78 | - pinmux_flag_t flags; | |
79 | -}; | |
80 | - | |
81 | -#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark } | |
82 | -#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0 | |
83 | - | |
84 | -struct pinmux_cfg_reg { | |
85 | - unsigned long reg, reg_width, field_width; | |
86 | - unsigned long *cnt; | |
87 | - pinmux_enum_t *enum_ids; | |
88 | -}; | |
89 | - | |
90 | -#define PINMUX_CFG_REG(name, r, r_width, f_width) \ | |
91 | - .reg = r, .reg_width = r_width, .field_width = f_width, \ | |
92 | - .cnt = (unsigned long [r_width / f_width]) {}, \ | |
93 | - .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \ | |
94 | - | |
95 | -struct pinmux_data_reg { | |
96 | - unsigned long reg, reg_width, reg_shadow; | |
97 | - pinmux_enum_t *enum_ids; | |
98 | -}; | |
99 | - | |
100 | -#define PINMUX_DATA_REG(name, r, r_width) \ | |
101 | - .reg = r, .reg_width = r_width, \ | |
102 | - .enum_ids = (pinmux_enum_t [r_width]) \ | |
103 | - | |
104 | -struct pinmux_range { | |
105 | - pinmux_enum_t begin; | |
106 | - pinmux_enum_t end; | |
107 | - pinmux_enum_t force; | |
108 | -}; | |
109 | - | |
110 | -struct pinmux_info { | |
111 | - char *name; | |
112 | - pinmux_enum_t reserved_id; | |
113 | - struct pinmux_range data; | |
114 | - struct pinmux_range input; | |
115 | - struct pinmux_range input_pd; | |
116 | - struct pinmux_range input_pu; | |
117 | - struct pinmux_range output; | |
118 | - struct pinmux_range mark; | |
119 | - struct pinmux_range function; | |
120 | - | |
121 | - unsigned first_gpio, last_gpio; | |
122 | - | |
123 | - struct pinmux_gpio *gpios; | |
124 | - struct pinmux_cfg_reg *cfg_regs; | |
125 | - struct pinmux_data_reg *data_regs; | |
126 | - | |
127 | - pinmux_enum_t *gpio_data; | |
128 | - unsigned int gpio_data_size; | |
129 | - | |
130 | - unsigned long *gpio_in_use; | |
131 | - struct gpio_chip chip; | |
132 | -}; | |
133 | - | |
134 | -int register_pinmux(struct pinmux_info *pip); | |
135 | 55 | |
136 | 56 | #endif /* __ASM_SH_GPIO_H */ |
arch/sh/kernel/Makefile
... | ... | @@ -32,7 +32,6 @@ |
32 | 32 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
33 | 33 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o |
34 | 34 | obj-$(CONFIG_KPROBES) += kprobes.o |
35 | -obj-$(CONFIG_GENERIC_GPIO) += gpio.o | |
36 | 35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
37 | 36 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
38 | 37 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
arch/sh/kernel/gpio.c
1 | -/* | |
2 | - * Pinmuxed GPIO support for SuperH. | |
3 | - * | |
4 | - * Copyright (C) 2008 Magnus Damm | |
5 | - * | |
6 | - * This file is subject to the terms and conditions of the GNU General Public | |
7 | - * License. See the file "COPYING" in the main directory of this archive | |
8 | - * for more details. | |
9 | - */ | |
10 | - | |
11 | -#include <linux/errno.h> | |
12 | -#include <linux/kernel.h> | |
13 | -#include <linux/list.h> | |
14 | -#include <linux/module.h> | |
15 | -#include <linux/clk.h> | |
16 | -#include <linux/err.h> | |
17 | -#include <linux/io.h> | |
18 | -#include <linux/irq.h> | |
19 | -#include <linux/bitops.h> | |
20 | -#include <linux/gpio.h> | |
21 | - | |
22 | -static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | |
23 | -{ | |
24 | - if (enum_id < r->begin) | |
25 | - return 0; | |
26 | - | |
27 | - if (enum_id > r->end) | |
28 | - return 0; | |
29 | - | |
30 | - return 1; | |
31 | -} | |
32 | - | |
33 | -static unsigned long gpio_read_raw_reg(unsigned long reg, | |
34 | - unsigned long reg_width) | |
35 | -{ | |
36 | - switch (reg_width) { | |
37 | - case 8: | |
38 | - return ctrl_inb(reg); | |
39 | - case 16: | |
40 | - return ctrl_inw(reg); | |
41 | - case 32: | |
42 | - return ctrl_inl(reg); | |
43 | - } | |
44 | - | |
45 | - BUG(); | |
46 | - return 0; | |
47 | -} | |
48 | - | |
49 | -static void gpio_write_raw_reg(unsigned long reg, | |
50 | - unsigned long reg_width, | |
51 | - unsigned long data) | |
52 | -{ | |
53 | - switch (reg_width) { | |
54 | - case 8: | |
55 | - ctrl_outb(data, reg); | |
56 | - return; | |
57 | - case 16: | |
58 | - ctrl_outw(data, reg); | |
59 | - return; | |
60 | - case 32: | |
61 | - ctrl_outl(data, reg); | |
62 | - return; | |
63 | - } | |
64 | - | |
65 | - BUG(); | |
66 | -} | |
67 | - | |
68 | -static void gpio_write_bit(struct pinmux_data_reg *dr, | |
69 | - unsigned long in_pos, unsigned long value) | |
70 | -{ | |
71 | - unsigned long pos; | |
72 | - | |
73 | - pos = dr->reg_width - (in_pos + 1); | |
74 | - | |
75 | -#ifdef DEBUG | |
76 | - pr_info("write_bit addr = %lx, value = %ld, pos = %ld, " | |
77 | - "r_width = %ld\n", | |
78 | - dr->reg, !!value, pos, dr->reg_width); | |
79 | -#endif | |
80 | - | |
81 | - if (value) | |
82 | - set_bit(pos, &dr->reg_shadow); | |
83 | - else | |
84 | - clear_bit(pos, &dr->reg_shadow); | |
85 | - | |
86 | - gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow); | |
87 | -} | |
88 | - | |
89 | -static int gpio_read_reg(unsigned long reg, unsigned long reg_width, | |
90 | - unsigned long field_width, unsigned long in_pos) | |
91 | -{ | |
92 | - unsigned long data, mask, pos; | |
93 | - | |
94 | - data = 0; | |
95 | - mask = (1 << field_width) - 1; | |
96 | - pos = reg_width - ((in_pos + 1) * field_width); | |
97 | - | |
98 | -#ifdef DEBUG | |
99 | - pr_info("read_reg: addr = %lx, pos = %ld, " | |
100 | - "r_width = %ld, f_width = %ld\n", | |
101 | - reg, pos, reg_width, field_width); | |
102 | -#endif | |
103 | - | |
104 | - data = gpio_read_raw_reg(reg, reg_width); | |
105 | - return (data >> pos) & mask; | |
106 | -} | |
107 | - | |
108 | -static void gpio_write_reg(unsigned long reg, unsigned long reg_width, | |
109 | - unsigned long field_width, unsigned long in_pos, | |
110 | - unsigned long value) | |
111 | -{ | |
112 | - unsigned long mask, pos; | |
113 | - | |
114 | - mask = (1 << field_width) - 1; | |
115 | - pos = reg_width - ((in_pos + 1) * field_width); | |
116 | - | |
117 | -#ifdef DEBUG | |
118 | - pr_info("write_reg addr = %lx, value = %ld, pos = %ld, " | |
119 | - "r_width = %ld, f_width = %ld\n", | |
120 | - reg, value, pos, reg_width, field_width); | |
121 | -#endif | |
122 | - | |
123 | - mask = ~(mask << pos); | |
124 | - value = value << pos; | |
125 | - | |
126 | - switch (reg_width) { | |
127 | - case 8: | |
128 | - ctrl_outb((ctrl_inb(reg) & mask) | value, reg); | |
129 | - break; | |
130 | - case 16: | |
131 | - ctrl_outw((ctrl_inw(reg) & mask) | value, reg); | |
132 | - break; | |
133 | - case 32: | |
134 | - ctrl_outl((ctrl_inl(reg) & mask) | value, reg); | |
135 | - break; | |
136 | - } | |
137 | -} | |
138 | - | |
139 | -static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | |
140 | -{ | |
141 | - struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
142 | - struct pinmux_data_reg *data_reg; | |
143 | - int k, n; | |
144 | - | |
145 | - if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
146 | - return -1; | |
147 | - | |
148 | - k = 0; | |
149 | - while (1) { | |
150 | - data_reg = gpioc->data_regs + k; | |
151 | - | |
152 | - if (!data_reg->reg_width) | |
153 | - break; | |
154 | - | |
155 | - for (n = 0; n < data_reg->reg_width; n++) { | |
156 | - if (data_reg->enum_ids[n] == gpiop->enum_id) { | |
157 | - gpiop->flags &= ~PINMUX_FLAG_DREG; | |
158 | - gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); | |
159 | - gpiop->flags &= ~PINMUX_FLAG_DBIT; | |
160 | - gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | |
161 | - return 0; | |
162 | - } | |
163 | - } | |
164 | - k++; | |
165 | - } | |
166 | - | |
167 | - BUG(); | |
168 | - | |
169 | - return -1; | |
170 | -} | |
171 | - | |
172 | -static void setup_data_regs(struct pinmux_info *gpioc) | |
173 | -{ | |
174 | - struct pinmux_data_reg *drp; | |
175 | - int k; | |
176 | - | |
177 | - for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++) | |
178 | - setup_data_reg(gpioc, k); | |
179 | - | |
180 | - k = 0; | |
181 | - while (1) { | |
182 | - drp = gpioc->data_regs + k; | |
183 | - | |
184 | - if (!drp->reg_width) | |
185 | - break; | |
186 | - | |
187 | - drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width); | |
188 | - k++; | |
189 | - } | |
190 | -} | |
191 | - | |
192 | -static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | |
193 | - struct pinmux_data_reg **drp, int *bitp) | |
194 | -{ | |
195 | - struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
196 | - int k, n; | |
197 | - | |
198 | - if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
199 | - return -1; | |
200 | - | |
201 | - k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | |
202 | - n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | |
203 | - *drp = gpioc->data_regs + k; | |
204 | - *bitp = n; | |
205 | - return 0; | |
206 | -} | |
207 | - | |
208 | -static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | |
209 | - struct pinmux_cfg_reg **crp, int *indexp, | |
210 | - unsigned long **cntp) | |
211 | -{ | |
212 | - struct pinmux_cfg_reg *config_reg; | |
213 | - unsigned long r_width, f_width; | |
214 | - int k, n; | |
215 | - | |
216 | - k = 0; | |
217 | - while (1) { | |
218 | - config_reg = gpioc->cfg_regs + k; | |
219 | - | |
220 | - r_width = config_reg->reg_width; | |
221 | - f_width = config_reg->field_width; | |
222 | - | |
223 | - if (!r_width) | |
224 | - break; | |
225 | - for (n = 0; n < (r_width / f_width) * 1 << f_width; n++) { | |
226 | - if (config_reg->enum_ids[n] == enum_id) { | |
227 | - *crp = config_reg; | |
228 | - *indexp = n; | |
229 | - *cntp = &config_reg->cnt[n / (1 << f_width)]; | |
230 | - return 0; | |
231 | - } | |
232 | - } | |
233 | - k++; | |
234 | - } | |
235 | - | |
236 | - return -1; | |
237 | -} | |
238 | - | |
239 | -static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | |
240 | - int pos, pinmux_enum_t *enum_idp) | |
241 | -{ | |
242 | - pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | |
243 | - pinmux_enum_t *data = gpioc->gpio_data; | |
244 | - int k; | |
245 | - | |
246 | - if (!enum_in_range(enum_id, &gpioc->data)) { | |
247 | - if (!enum_in_range(enum_id, &gpioc->mark)) { | |
248 | - pr_err("non data/mark enum_id for gpio %d\n", gpio); | |
249 | - return -1; | |
250 | - } | |
251 | - } | |
252 | - | |
253 | - if (pos) { | |
254 | - *enum_idp = data[pos + 1]; | |
255 | - return pos + 1; | |
256 | - } | |
257 | - | |
258 | - for (k = 0; k < gpioc->gpio_data_size; k++) { | |
259 | - if (data[k] == enum_id) { | |
260 | - *enum_idp = data[k + 1]; | |
261 | - return k + 1; | |
262 | - } | |
263 | - } | |
264 | - | |
265 | - pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio); | |
266 | - return -1; | |
267 | -} | |
268 | - | |
269 | -static void write_config_reg(struct pinmux_info *gpioc, | |
270 | - struct pinmux_cfg_reg *crp, | |
271 | - int index) | |
272 | -{ | |
273 | - unsigned long ncomb, pos, value; | |
274 | - | |
275 | - ncomb = 1 << crp->field_width; | |
276 | - pos = index / ncomb; | |
277 | - value = index % ncomb; | |
278 | - | |
279 | - gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value); | |
280 | -} | |
281 | - | |
282 | -static int check_config_reg(struct pinmux_info *gpioc, | |
283 | - struct pinmux_cfg_reg *crp, | |
284 | - int index) | |
285 | -{ | |
286 | - unsigned long ncomb, pos, value; | |
287 | - | |
288 | - ncomb = 1 << crp->field_width; | |
289 | - pos = index / ncomb; | |
290 | - value = index % ncomb; | |
291 | - | |
292 | - if (gpio_read_reg(crp->reg, crp->reg_width, | |
293 | - crp->field_width, pos) == value) | |
294 | - return 0; | |
295 | - | |
296 | - return -1; | |
297 | -} | |
298 | - | |
299 | -enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | |
300 | - | |
301 | -static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |
302 | - int pinmux_type, int cfg_mode) | |
303 | -{ | |
304 | - struct pinmux_cfg_reg *cr = NULL; | |
305 | - pinmux_enum_t enum_id; | |
306 | - struct pinmux_range *range; | |
307 | - int in_range, pos, index; | |
308 | - unsigned long *cntp; | |
309 | - | |
310 | - switch (pinmux_type) { | |
311 | - | |
312 | - case PINMUX_TYPE_FUNCTION: | |
313 | - range = NULL; | |
314 | - break; | |
315 | - | |
316 | - case PINMUX_TYPE_OUTPUT: | |
317 | - range = &gpioc->output; | |
318 | - break; | |
319 | - | |
320 | - case PINMUX_TYPE_INPUT: | |
321 | - range = &gpioc->input; | |
322 | - break; | |
323 | - | |
324 | - case PINMUX_TYPE_INPUT_PULLUP: | |
325 | - range = &gpioc->input_pu; | |
326 | - break; | |
327 | - | |
328 | - case PINMUX_TYPE_INPUT_PULLDOWN: | |
329 | - range = &gpioc->input_pd; | |
330 | - break; | |
331 | - | |
332 | - default: | |
333 | - goto out_err; | |
334 | - } | |
335 | - | |
336 | - pos = 0; | |
337 | - enum_id = 0; | |
338 | - index = 0; | |
339 | - while (1) { | |
340 | - pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | |
341 | - if (pos <= 0) | |
342 | - goto out_err; | |
343 | - | |
344 | - if (!enum_id) | |
345 | - break; | |
346 | - | |
347 | - in_range = enum_in_range(enum_id, &gpioc->function); | |
348 | - if (!in_range && range) { | |
349 | - in_range = enum_in_range(enum_id, range); | |
350 | - | |
351 | - if (in_range && enum_id == range->force) | |
352 | - continue; | |
353 | - } | |
354 | - | |
355 | - if (!in_range) | |
356 | - continue; | |
357 | - | |
358 | - if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) | |
359 | - goto out_err; | |
360 | - | |
361 | - switch (cfg_mode) { | |
362 | - case GPIO_CFG_DRYRUN: | |
363 | - if (!*cntp || !check_config_reg(gpioc, cr, index)) | |
364 | - continue; | |
365 | - break; | |
366 | - | |
367 | - case GPIO_CFG_REQ: | |
368 | - write_config_reg(gpioc, cr, index); | |
369 | - *cntp = *cntp + 1; | |
370 | - break; | |
371 | - | |
372 | - case GPIO_CFG_FREE: | |
373 | - *cntp = *cntp - 1; | |
374 | - break; | |
375 | - } | |
376 | - } | |
377 | - | |
378 | - return 0; | |
379 | - out_err: | |
380 | - return -1; | |
381 | -} | |
382 | - | |
383 | -static DEFINE_SPINLOCK(gpio_lock); | |
384 | - | |
385 | -static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip) | |
386 | -{ | |
387 | - return container_of(chip, struct pinmux_info, chip); | |
388 | -} | |
389 | - | |
390 | -static int sh_gpio_request(struct gpio_chip *chip, unsigned offset) | |
391 | -{ | |
392 | - struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
393 | - struct pinmux_data_reg *dummy; | |
394 | - unsigned long flags; | |
395 | - int i, ret, pinmux_type; | |
396 | - | |
397 | - ret = -EINVAL; | |
398 | - | |
399 | - if (!gpioc) | |
400 | - goto err_out; | |
401 | - | |
402 | - spin_lock_irqsave(&gpio_lock, flags); | |
403 | - | |
404 | - if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE) | |
405 | - goto err_unlock; | |
406 | - | |
407 | - /* setup pin function here if no data is associated with pin */ | |
408 | - | |
409 | - if (get_data_reg(gpioc, offset, &dummy, &i) != 0) | |
410 | - pinmux_type = PINMUX_TYPE_FUNCTION; | |
411 | - else | |
412 | - pinmux_type = PINMUX_TYPE_GPIO; | |
413 | - | |
414 | - if (pinmux_type == PINMUX_TYPE_FUNCTION) { | |
415 | - if (pinmux_config_gpio(gpioc, offset, | |
416 | - pinmux_type, | |
417 | - GPIO_CFG_DRYRUN) != 0) | |
418 | - goto err_unlock; | |
419 | - | |
420 | - if (pinmux_config_gpio(gpioc, offset, | |
421 | - pinmux_type, | |
422 | - GPIO_CFG_REQ) != 0) | |
423 | - BUG(); | |
424 | - } | |
425 | - | |
426 | - gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
427 | - gpioc->gpios[offset].flags |= pinmux_type; | |
428 | - | |
429 | - ret = 0; | |
430 | - err_unlock: | |
431 | - spin_unlock_irqrestore(&gpio_lock, flags); | |
432 | - err_out: | |
433 | - return ret; | |
434 | -} | |
435 | - | |
436 | -static void sh_gpio_free(struct gpio_chip *chip, unsigned offset) | |
437 | -{ | |
438 | - struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
439 | - unsigned long flags; | |
440 | - int pinmux_type; | |
441 | - | |
442 | - if (!gpioc) | |
443 | - return; | |
444 | - | |
445 | - spin_lock_irqsave(&gpio_lock, flags); | |
446 | - | |
447 | - pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE; | |
448 | - pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE); | |
449 | - gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
450 | - gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE; | |
451 | - | |
452 | - spin_unlock_irqrestore(&gpio_lock, flags); | |
453 | -} | |
454 | - | |
455 | -static int pinmux_direction(struct pinmux_info *gpioc, | |
456 | - unsigned gpio, int new_pinmux_type) | |
457 | -{ | |
458 | - int pinmux_type; | |
459 | - int ret = -EINVAL; | |
460 | - | |
461 | - if (!gpioc) | |
462 | - goto err_out; | |
463 | - | |
464 | - pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | |
465 | - | |
466 | - switch (pinmux_type) { | |
467 | - case PINMUX_TYPE_GPIO: | |
468 | - break; | |
469 | - case PINMUX_TYPE_OUTPUT: | |
470 | - case PINMUX_TYPE_INPUT: | |
471 | - case PINMUX_TYPE_INPUT_PULLUP: | |
472 | - case PINMUX_TYPE_INPUT_PULLDOWN: | |
473 | - pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | |
474 | - break; | |
475 | - default: | |
476 | - goto err_out; | |
477 | - } | |
478 | - | |
479 | - if (pinmux_config_gpio(gpioc, gpio, | |
480 | - new_pinmux_type, | |
481 | - GPIO_CFG_DRYRUN) != 0) | |
482 | - goto err_out; | |
483 | - | |
484 | - if (pinmux_config_gpio(gpioc, gpio, | |
485 | - new_pinmux_type, | |
486 | - GPIO_CFG_REQ) != 0) | |
487 | - BUG(); | |
488 | - | |
489 | - gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; | |
490 | - gpioc->gpios[gpio].flags |= new_pinmux_type; | |
491 | - | |
492 | - ret = 0; | |
493 | - err_out: | |
494 | - return ret; | |
495 | -} | |
496 | - | |
497 | -static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | |
498 | -{ | |
499 | - struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
500 | - unsigned long flags; | |
501 | - int ret; | |
502 | - | |
503 | - spin_lock_irqsave(&gpio_lock, flags); | |
504 | - ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT); | |
505 | - spin_unlock_irqrestore(&gpio_lock, flags); | |
506 | - | |
507 | - return ret; | |
508 | -} | |
509 | - | |
510 | -static void sh_gpio_set_value(struct pinmux_info *gpioc, | |
511 | - unsigned gpio, int value) | |
512 | -{ | |
513 | - struct pinmux_data_reg *dr = NULL; | |
514 | - int bit = 0; | |
515 | - | |
516 | - if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | |
517 | - BUG(); | |
518 | - else | |
519 | - gpio_write_bit(dr, bit, value); | |
520 | -} | |
521 | - | |
522 | -static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | |
523 | - int value) | |
524 | -{ | |
525 | - struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
526 | - unsigned long flags; | |
527 | - int ret; | |
528 | - | |
529 | - sh_gpio_set_value(gpioc, offset, value); | |
530 | - spin_lock_irqsave(&gpio_lock, flags); | |
531 | - ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT); | |
532 | - spin_unlock_irqrestore(&gpio_lock, flags); | |
533 | - | |
534 | - return ret; | |
535 | -} | |
536 | - | |
537 | -static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | |
538 | -{ | |
539 | - struct pinmux_data_reg *dr = NULL; | |
540 | - int bit = 0; | |
541 | - | |
542 | - if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) { | |
543 | - BUG(); | |
544 | - return 0; | |
545 | - } | |
546 | - | |
547 | - return gpio_read_reg(dr->reg, dr->reg_width, 1, bit); | |
548 | -} | |
549 | - | |
550 | -static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) | |
551 | -{ | |
552 | - return sh_gpio_get_value(chip_to_pinmux(chip), offset); | |
553 | -} | |
554 | - | |
555 | -static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
556 | -{ | |
557 | - sh_gpio_set_value(chip_to_pinmux(chip), offset, value); | |
558 | -} | |
559 | - | |
560 | -int register_pinmux(struct pinmux_info *pip) | |
561 | -{ | |
562 | - struct gpio_chip *chip = &pip->chip; | |
563 | - | |
564 | - pr_info("sh pinmux: %s handling gpio %d -> %d\n", | |
565 | - pip->name, pip->first_gpio, pip->last_gpio); | |
566 | - | |
567 | - setup_data_regs(pip); | |
568 | - | |
569 | - chip->request = sh_gpio_request; | |
570 | - chip->free = sh_gpio_free; | |
571 | - chip->direction_input = sh_gpio_direction_input; | |
572 | - chip->get = sh_gpio_get; | |
573 | - chip->direction_output = sh_gpio_direction_output; | |
574 | - chip->set = sh_gpio_set; | |
575 | - | |
576 | - WARN_ON(pip->first_gpio != 0); /* needs testing */ | |
577 | - | |
578 | - chip->label = pip->name; | |
579 | - chip->owner = THIS_MODULE; | |
580 | - chip->base = pip->first_gpio; | |
581 | - chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1; | |
582 | - | |
583 | - return gpiochip_add(chip); | |
584 | -} |
drivers/sh/Makefile
drivers/sh/pfc.c
1 | +/* | |
2 | + * Pinmuxed GPIO support for SuperH. | |
3 | + * | |
4 | + * Copyright (C) 2008 Magnus Damm | |
5 | + * | |
6 | + * This file is subject to the terms and conditions of the GNU General Public | |
7 | + * License. See the file "COPYING" in the main directory of this archive | |
8 | + * for more details. | |
9 | + */ | |
10 | + | |
11 | +#include <linux/errno.h> | |
12 | +#include <linux/kernel.h> | |
13 | +#include <linux/list.h> | |
14 | +#include <linux/module.h> | |
15 | +#include <linux/clk.h> | |
16 | +#include <linux/err.h> | |
17 | +#include <linux/io.h> | |
18 | +#include <linux/irq.h> | |
19 | +#include <linux/bitops.h> | |
20 | +#include <linux/gpio.h> | |
21 | + | |
22 | +static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | |
23 | +{ | |
24 | + if (enum_id < r->begin) | |
25 | + return 0; | |
26 | + | |
27 | + if (enum_id > r->end) | |
28 | + return 0; | |
29 | + | |
30 | + return 1; | |
31 | +} | |
32 | + | |
33 | +static unsigned long gpio_read_raw_reg(unsigned long reg, | |
34 | + unsigned long reg_width) | |
35 | +{ | |
36 | + switch (reg_width) { | |
37 | + case 8: | |
38 | + return ctrl_inb(reg); | |
39 | + case 16: | |
40 | + return ctrl_inw(reg); | |
41 | + case 32: | |
42 | + return ctrl_inl(reg); | |
43 | + } | |
44 | + | |
45 | + BUG(); | |
46 | + return 0; | |
47 | +} | |
48 | + | |
49 | +static void gpio_write_raw_reg(unsigned long reg, | |
50 | + unsigned long reg_width, | |
51 | + unsigned long data) | |
52 | +{ | |
53 | + switch (reg_width) { | |
54 | + case 8: | |
55 | + ctrl_outb(data, reg); | |
56 | + return; | |
57 | + case 16: | |
58 | + ctrl_outw(data, reg); | |
59 | + return; | |
60 | + case 32: | |
61 | + ctrl_outl(data, reg); | |
62 | + return; | |
63 | + } | |
64 | + | |
65 | + BUG(); | |
66 | +} | |
67 | + | |
68 | +static void gpio_write_bit(struct pinmux_data_reg *dr, | |
69 | + unsigned long in_pos, unsigned long value) | |
70 | +{ | |
71 | + unsigned long pos; | |
72 | + | |
73 | + pos = dr->reg_width - (in_pos + 1); | |
74 | + | |
75 | +#ifdef DEBUG | |
76 | + pr_info("write_bit addr = %lx, value = %ld, pos = %ld, " | |
77 | + "r_width = %ld\n", | |
78 | + dr->reg, !!value, pos, dr->reg_width); | |
79 | +#endif | |
80 | + | |
81 | + if (value) | |
82 | + set_bit(pos, &dr->reg_shadow); | |
83 | + else | |
84 | + clear_bit(pos, &dr->reg_shadow); | |
85 | + | |
86 | + gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow); | |
87 | +} | |
88 | + | |
89 | +static int gpio_read_reg(unsigned long reg, unsigned long reg_width, | |
90 | + unsigned long field_width, unsigned long in_pos) | |
91 | +{ | |
92 | + unsigned long data, mask, pos; | |
93 | + | |
94 | + data = 0; | |
95 | + mask = (1 << field_width) - 1; | |
96 | + pos = reg_width - ((in_pos + 1) * field_width); | |
97 | + | |
98 | +#ifdef DEBUG | |
99 | + pr_info("read_reg: addr = %lx, pos = %ld, " | |
100 | + "r_width = %ld, f_width = %ld\n", | |
101 | + reg, pos, reg_width, field_width); | |
102 | +#endif | |
103 | + | |
104 | + data = gpio_read_raw_reg(reg, reg_width); | |
105 | + return (data >> pos) & mask; | |
106 | +} | |
107 | + | |
108 | +static void gpio_write_reg(unsigned long reg, unsigned long reg_width, | |
109 | + unsigned long field_width, unsigned long in_pos, | |
110 | + unsigned long value) | |
111 | +{ | |
112 | + unsigned long mask, pos; | |
113 | + | |
114 | + mask = (1 << field_width) - 1; | |
115 | + pos = reg_width - ((in_pos + 1) * field_width); | |
116 | + | |
117 | +#ifdef DEBUG | |
118 | + pr_info("write_reg addr = %lx, value = %ld, pos = %ld, " | |
119 | + "r_width = %ld, f_width = %ld\n", | |
120 | + reg, value, pos, reg_width, field_width); | |
121 | +#endif | |
122 | + | |
123 | + mask = ~(mask << pos); | |
124 | + value = value << pos; | |
125 | + | |
126 | + switch (reg_width) { | |
127 | + case 8: | |
128 | + ctrl_outb((ctrl_inb(reg) & mask) | value, reg); | |
129 | + break; | |
130 | + case 16: | |
131 | + ctrl_outw((ctrl_inw(reg) & mask) | value, reg); | |
132 | + break; | |
133 | + case 32: | |
134 | + ctrl_outl((ctrl_inl(reg) & mask) | value, reg); | |
135 | + break; | |
136 | + } | |
137 | +} | |
138 | + | |
139 | +static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | |
140 | +{ | |
141 | + struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
142 | + struct pinmux_data_reg *data_reg; | |
143 | + int k, n; | |
144 | + | |
145 | + if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
146 | + return -1; | |
147 | + | |
148 | + k = 0; | |
149 | + while (1) { | |
150 | + data_reg = gpioc->data_regs + k; | |
151 | + | |
152 | + if (!data_reg->reg_width) | |
153 | + break; | |
154 | + | |
155 | + for (n = 0; n < data_reg->reg_width; n++) { | |
156 | + if (data_reg->enum_ids[n] == gpiop->enum_id) { | |
157 | + gpiop->flags &= ~PINMUX_FLAG_DREG; | |
158 | + gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); | |
159 | + gpiop->flags &= ~PINMUX_FLAG_DBIT; | |
160 | + gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | |
161 | + return 0; | |
162 | + } | |
163 | + } | |
164 | + k++; | |
165 | + } | |
166 | + | |
167 | + BUG(); | |
168 | + | |
169 | + return -1; | |
170 | +} | |
171 | + | |
172 | +static void setup_data_regs(struct pinmux_info *gpioc) | |
173 | +{ | |
174 | + struct pinmux_data_reg *drp; | |
175 | + int k; | |
176 | + | |
177 | + for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++) | |
178 | + setup_data_reg(gpioc, k); | |
179 | + | |
180 | + k = 0; | |
181 | + while (1) { | |
182 | + drp = gpioc->data_regs + k; | |
183 | + | |
184 | + if (!drp->reg_width) | |
185 | + break; | |
186 | + | |
187 | + drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width); | |
188 | + k++; | |
189 | + } | |
190 | +} | |
191 | + | |
192 | +static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | |
193 | + struct pinmux_data_reg **drp, int *bitp) | |
194 | +{ | |
195 | + struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | |
196 | + int k, n; | |
197 | + | |
198 | + if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | |
199 | + return -1; | |
200 | + | |
201 | + k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | |
202 | + n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | |
203 | + *drp = gpioc->data_regs + k; | |
204 | + *bitp = n; | |
205 | + return 0; | |
206 | +} | |
207 | + | |
208 | +static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | |
209 | + struct pinmux_cfg_reg **crp, int *indexp, | |
210 | + unsigned long **cntp) | |
211 | +{ | |
212 | + struct pinmux_cfg_reg *config_reg; | |
213 | + unsigned long r_width, f_width; | |
214 | + int k, n; | |
215 | + | |
216 | + k = 0; | |
217 | + while (1) { | |
218 | + config_reg = gpioc->cfg_regs + k; | |
219 | + | |
220 | + r_width = config_reg->reg_width; | |
221 | + f_width = config_reg->field_width; | |
222 | + | |
223 | + if (!r_width) | |
224 | + break; | |
225 | + for (n = 0; n < (r_width / f_width) * 1 << f_width; n++) { | |
226 | + if (config_reg->enum_ids[n] == enum_id) { | |
227 | + *crp = config_reg; | |
228 | + *indexp = n; | |
229 | + *cntp = &config_reg->cnt[n / (1 << f_width)]; | |
230 | + return 0; | |
231 | + } | |
232 | + } | |
233 | + k++; | |
234 | + } | |
235 | + | |
236 | + return -1; | |
237 | +} | |
238 | + | |
239 | +static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | |
240 | + int pos, pinmux_enum_t *enum_idp) | |
241 | +{ | |
242 | + pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | |
243 | + pinmux_enum_t *data = gpioc->gpio_data; | |
244 | + int k; | |
245 | + | |
246 | + if (!enum_in_range(enum_id, &gpioc->data)) { | |
247 | + if (!enum_in_range(enum_id, &gpioc->mark)) { | |
248 | + pr_err("non data/mark enum_id for gpio %d\n", gpio); | |
249 | + return -1; | |
250 | + } | |
251 | + } | |
252 | + | |
253 | + if (pos) { | |
254 | + *enum_idp = data[pos + 1]; | |
255 | + return pos + 1; | |
256 | + } | |
257 | + | |
258 | + for (k = 0; k < gpioc->gpio_data_size; k++) { | |
259 | + if (data[k] == enum_id) { | |
260 | + *enum_idp = data[k + 1]; | |
261 | + return k + 1; | |
262 | + } | |
263 | + } | |
264 | + | |
265 | + pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio); | |
266 | + return -1; | |
267 | +} | |
268 | + | |
269 | +static void write_config_reg(struct pinmux_info *gpioc, | |
270 | + struct pinmux_cfg_reg *crp, | |
271 | + int index) | |
272 | +{ | |
273 | + unsigned long ncomb, pos, value; | |
274 | + | |
275 | + ncomb = 1 << crp->field_width; | |
276 | + pos = index / ncomb; | |
277 | + value = index % ncomb; | |
278 | + | |
279 | + gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value); | |
280 | +} | |
281 | + | |
282 | +static int check_config_reg(struct pinmux_info *gpioc, | |
283 | + struct pinmux_cfg_reg *crp, | |
284 | + int index) | |
285 | +{ | |
286 | + unsigned long ncomb, pos, value; | |
287 | + | |
288 | + ncomb = 1 << crp->field_width; | |
289 | + pos = index / ncomb; | |
290 | + value = index % ncomb; | |
291 | + | |
292 | + if (gpio_read_reg(crp->reg, crp->reg_width, | |
293 | + crp->field_width, pos) == value) | |
294 | + return 0; | |
295 | + | |
296 | + return -1; | |
297 | +} | |
298 | + | |
299 | +enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | |
300 | + | |
301 | +static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |
302 | + int pinmux_type, int cfg_mode) | |
303 | +{ | |
304 | + struct pinmux_cfg_reg *cr = NULL; | |
305 | + pinmux_enum_t enum_id; | |
306 | + struct pinmux_range *range; | |
307 | + int in_range, pos, index; | |
308 | + unsigned long *cntp; | |
309 | + | |
310 | + switch (pinmux_type) { | |
311 | + | |
312 | + case PINMUX_TYPE_FUNCTION: | |
313 | + range = NULL; | |
314 | + break; | |
315 | + | |
316 | + case PINMUX_TYPE_OUTPUT: | |
317 | + range = &gpioc->output; | |
318 | + break; | |
319 | + | |
320 | + case PINMUX_TYPE_INPUT: | |
321 | + range = &gpioc->input; | |
322 | + break; | |
323 | + | |
324 | + case PINMUX_TYPE_INPUT_PULLUP: | |
325 | + range = &gpioc->input_pu; | |
326 | + break; | |
327 | + | |
328 | + case PINMUX_TYPE_INPUT_PULLDOWN: | |
329 | + range = &gpioc->input_pd; | |
330 | + break; | |
331 | + | |
332 | + default: | |
333 | + goto out_err; | |
334 | + } | |
335 | + | |
336 | + pos = 0; | |
337 | + enum_id = 0; | |
338 | + index = 0; | |
339 | + while (1) { | |
340 | + pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | |
341 | + if (pos <= 0) | |
342 | + goto out_err; | |
343 | + | |
344 | + if (!enum_id) | |
345 | + break; | |
346 | + | |
347 | + in_range = enum_in_range(enum_id, &gpioc->function); | |
348 | + if (!in_range && range) { | |
349 | + in_range = enum_in_range(enum_id, range); | |
350 | + | |
351 | + if (in_range && enum_id == range->force) | |
352 | + continue; | |
353 | + } | |
354 | + | |
355 | + if (!in_range) | |
356 | + continue; | |
357 | + | |
358 | + if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) | |
359 | + goto out_err; | |
360 | + | |
361 | + switch (cfg_mode) { | |
362 | + case GPIO_CFG_DRYRUN: | |
363 | + if (!*cntp || !check_config_reg(gpioc, cr, index)) | |
364 | + continue; | |
365 | + break; | |
366 | + | |
367 | + case GPIO_CFG_REQ: | |
368 | + write_config_reg(gpioc, cr, index); | |
369 | + *cntp = *cntp + 1; | |
370 | + break; | |
371 | + | |
372 | + case GPIO_CFG_FREE: | |
373 | + *cntp = *cntp - 1; | |
374 | + break; | |
375 | + } | |
376 | + } | |
377 | + | |
378 | + return 0; | |
379 | + out_err: | |
380 | + return -1; | |
381 | +} | |
382 | + | |
383 | +static DEFINE_SPINLOCK(gpio_lock); | |
384 | + | |
385 | +static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip) | |
386 | +{ | |
387 | + return container_of(chip, struct pinmux_info, chip); | |
388 | +} | |
389 | + | |
390 | +static int sh_gpio_request(struct gpio_chip *chip, unsigned offset) | |
391 | +{ | |
392 | + struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
393 | + struct pinmux_data_reg *dummy; | |
394 | + unsigned long flags; | |
395 | + int i, ret, pinmux_type; | |
396 | + | |
397 | + ret = -EINVAL; | |
398 | + | |
399 | + if (!gpioc) | |
400 | + goto err_out; | |
401 | + | |
402 | + spin_lock_irqsave(&gpio_lock, flags); | |
403 | + | |
404 | + if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE) | |
405 | + goto err_unlock; | |
406 | + | |
407 | + /* setup pin function here if no data is associated with pin */ | |
408 | + | |
409 | + if (get_data_reg(gpioc, offset, &dummy, &i) != 0) | |
410 | + pinmux_type = PINMUX_TYPE_FUNCTION; | |
411 | + else | |
412 | + pinmux_type = PINMUX_TYPE_GPIO; | |
413 | + | |
414 | + if (pinmux_type == PINMUX_TYPE_FUNCTION) { | |
415 | + if (pinmux_config_gpio(gpioc, offset, | |
416 | + pinmux_type, | |
417 | + GPIO_CFG_DRYRUN) != 0) | |
418 | + goto err_unlock; | |
419 | + | |
420 | + if (pinmux_config_gpio(gpioc, offset, | |
421 | + pinmux_type, | |
422 | + GPIO_CFG_REQ) != 0) | |
423 | + BUG(); | |
424 | + } | |
425 | + | |
426 | + gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
427 | + gpioc->gpios[offset].flags |= pinmux_type; | |
428 | + | |
429 | + ret = 0; | |
430 | + err_unlock: | |
431 | + spin_unlock_irqrestore(&gpio_lock, flags); | |
432 | + err_out: | |
433 | + return ret; | |
434 | +} | |
435 | + | |
436 | +static void sh_gpio_free(struct gpio_chip *chip, unsigned offset) | |
437 | +{ | |
438 | + struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
439 | + unsigned long flags; | |
440 | + int pinmux_type; | |
441 | + | |
442 | + if (!gpioc) | |
443 | + return; | |
444 | + | |
445 | + spin_lock_irqsave(&gpio_lock, flags); | |
446 | + | |
447 | + pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE; | |
448 | + pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE); | |
449 | + gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | |
450 | + gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE; | |
451 | + | |
452 | + spin_unlock_irqrestore(&gpio_lock, flags); | |
453 | +} | |
454 | + | |
455 | +static int pinmux_direction(struct pinmux_info *gpioc, | |
456 | + unsigned gpio, int new_pinmux_type) | |
457 | +{ | |
458 | + int pinmux_type; | |
459 | + int ret = -EINVAL; | |
460 | + | |
461 | + if (!gpioc) | |
462 | + goto err_out; | |
463 | + | |
464 | + pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | |
465 | + | |
466 | + switch (pinmux_type) { | |
467 | + case PINMUX_TYPE_GPIO: | |
468 | + break; | |
469 | + case PINMUX_TYPE_OUTPUT: | |
470 | + case PINMUX_TYPE_INPUT: | |
471 | + case PINMUX_TYPE_INPUT_PULLUP: | |
472 | + case PINMUX_TYPE_INPUT_PULLDOWN: | |
473 | + pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | |
474 | + break; | |
475 | + default: | |
476 | + goto err_out; | |
477 | + } | |
478 | + | |
479 | + if (pinmux_config_gpio(gpioc, gpio, | |
480 | + new_pinmux_type, | |
481 | + GPIO_CFG_DRYRUN) != 0) | |
482 | + goto err_out; | |
483 | + | |
484 | + if (pinmux_config_gpio(gpioc, gpio, | |
485 | + new_pinmux_type, | |
486 | + GPIO_CFG_REQ) != 0) | |
487 | + BUG(); | |
488 | + | |
489 | + gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; | |
490 | + gpioc->gpios[gpio].flags |= new_pinmux_type; | |
491 | + | |
492 | + ret = 0; | |
493 | + err_out: | |
494 | + return ret; | |
495 | +} | |
496 | + | |
497 | +static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | |
498 | +{ | |
499 | + struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
500 | + unsigned long flags; | |
501 | + int ret; | |
502 | + | |
503 | + spin_lock_irqsave(&gpio_lock, flags); | |
504 | + ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT); | |
505 | + spin_unlock_irqrestore(&gpio_lock, flags); | |
506 | + | |
507 | + return ret; | |
508 | +} | |
509 | + | |
510 | +static void sh_gpio_set_value(struct pinmux_info *gpioc, | |
511 | + unsigned gpio, int value) | |
512 | +{ | |
513 | + struct pinmux_data_reg *dr = NULL; | |
514 | + int bit = 0; | |
515 | + | |
516 | + if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | |
517 | + BUG(); | |
518 | + else | |
519 | + gpio_write_bit(dr, bit, value); | |
520 | +} | |
521 | + | |
522 | +static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | |
523 | + int value) | |
524 | +{ | |
525 | + struct pinmux_info *gpioc = chip_to_pinmux(chip); | |
526 | + unsigned long flags; | |
527 | + int ret; | |
528 | + | |
529 | + sh_gpio_set_value(gpioc, offset, value); | |
530 | + spin_lock_irqsave(&gpio_lock, flags); | |
531 | + ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT); | |
532 | + spin_unlock_irqrestore(&gpio_lock, flags); | |
533 | + | |
534 | + return ret; | |
535 | +} | |
536 | + | |
537 | +static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | |
538 | +{ | |
539 | + struct pinmux_data_reg *dr = NULL; | |
540 | + int bit = 0; | |
541 | + | |
542 | + if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) { | |
543 | + BUG(); | |
544 | + return 0; | |
545 | + } | |
546 | + | |
547 | + return gpio_read_reg(dr->reg, dr->reg_width, 1, bit); | |
548 | +} | |
549 | + | |
550 | +static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) | |
551 | +{ | |
552 | + return sh_gpio_get_value(chip_to_pinmux(chip), offset); | |
553 | +} | |
554 | + | |
555 | +static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |
556 | +{ | |
557 | + sh_gpio_set_value(chip_to_pinmux(chip), offset, value); | |
558 | +} | |
559 | + | |
560 | +int register_pinmux(struct pinmux_info *pip) | |
561 | +{ | |
562 | + struct gpio_chip *chip = &pip->chip; | |
563 | + | |
564 | + pr_info("sh pinmux: %s handling gpio %d -> %d\n", | |
565 | + pip->name, pip->first_gpio, pip->last_gpio); | |
566 | + | |
567 | + setup_data_regs(pip); | |
568 | + | |
569 | + chip->request = sh_gpio_request; | |
570 | + chip->free = sh_gpio_free; | |
571 | + chip->direction_input = sh_gpio_direction_input; | |
572 | + chip->get = sh_gpio_get; | |
573 | + chip->direction_output = sh_gpio_direction_output; | |
574 | + chip->set = sh_gpio_set; | |
575 | + | |
576 | + WARN_ON(pip->first_gpio != 0); /* needs testing */ | |
577 | + | |
578 | + chip->label = pip->name; | |
579 | + chip->owner = THIS_MODULE; | |
580 | + chip->base = pip->first_gpio; | |
581 | + chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1; | |
582 | + | |
583 | + return gpiochip_add(chip); | |
584 | +} |
include/linux/sh_pfc.h
1 | +/* | |
2 | + * SuperH Pin Function Controller Support | |
3 | + * | |
4 | + * Copyright (c) 2008 Magnus Damm | |
5 | + * | |
6 | + * This file is subject to the terms and conditions of the GNU General Public | |
7 | + * License. See the file "COPYING" in the main directory of this archive | |
8 | + * for more details. | |
9 | + */ | |
10 | + | |
11 | +#ifndef __SH_PFC_H | |
12 | +#define __SH_PFC_H | |
13 | + | |
14 | +#include <asm-generic/gpio.h> | |
15 | + | |
16 | +typedef unsigned short pinmux_enum_t; | |
17 | +typedef unsigned short pinmux_flag_t; | |
18 | + | |
19 | +#define PINMUX_TYPE_NONE 0 | |
20 | +#define PINMUX_TYPE_FUNCTION 1 | |
21 | +#define PINMUX_TYPE_GPIO 2 | |
22 | +#define PINMUX_TYPE_OUTPUT 3 | |
23 | +#define PINMUX_TYPE_INPUT 4 | |
24 | +#define PINMUX_TYPE_INPUT_PULLUP 5 | |
25 | +#define PINMUX_TYPE_INPUT_PULLDOWN 6 | |
26 | + | |
27 | +#define PINMUX_FLAG_TYPE (0x7) | |
28 | +#define PINMUX_FLAG_WANT_PULLUP (1 << 3) | |
29 | +#define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) | |
30 | + | |
31 | +#define PINMUX_FLAG_DBIT_SHIFT 5 | |
32 | +#define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT) | |
33 | +#define PINMUX_FLAG_DREG_SHIFT 10 | |
34 | +#define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT) | |
35 | + | |
36 | +struct pinmux_gpio { | |
37 | + pinmux_enum_t enum_id; | |
38 | + pinmux_flag_t flags; | |
39 | +}; | |
40 | + | |
41 | +#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark } | |
42 | +#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0 | |
43 | + | |
44 | +struct pinmux_cfg_reg { | |
45 | + unsigned long reg, reg_width, field_width; | |
46 | + unsigned long *cnt; | |
47 | + pinmux_enum_t *enum_ids; | |
48 | +}; | |
49 | + | |
50 | +#define PINMUX_CFG_REG(name, r, r_width, f_width) \ | |
51 | + .reg = r, .reg_width = r_width, .field_width = f_width, \ | |
52 | + .cnt = (unsigned long [r_width / f_width]) {}, \ | |
53 | + .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \ | |
54 | + | |
55 | +struct pinmux_data_reg { | |
56 | + unsigned long reg, reg_width, reg_shadow; | |
57 | + pinmux_enum_t *enum_ids; | |
58 | +}; | |
59 | + | |
60 | +#define PINMUX_DATA_REG(name, r, r_width) \ | |
61 | + .reg = r, .reg_width = r_width, \ | |
62 | + .enum_ids = (pinmux_enum_t [r_width]) \ | |
63 | + | |
64 | +struct pinmux_range { | |
65 | + pinmux_enum_t begin; | |
66 | + pinmux_enum_t end; | |
67 | + pinmux_enum_t force; | |
68 | +}; | |
69 | + | |
70 | +struct pinmux_info { | |
71 | + char *name; | |
72 | + pinmux_enum_t reserved_id; | |
73 | + struct pinmux_range data; | |
74 | + struct pinmux_range input; | |
75 | + struct pinmux_range input_pd; | |
76 | + struct pinmux_range input_pu; | |
77 | + struct pinmux_range output; | |
78 | + struct pinmux_range mark; | |
79 | + struct pinmux_range function; | |
80 | + | |
81 | + unsigned first_gpio, last_gpio; | |
82 | + | |
83 | + struct pinmux_gpio *gpios; | |
84 | + struct pinmux_cfg_reg *cfg_regs; | |
85 | + struct pinmux_data_reg *data_regs; | |
86 | + | |
87 | + pinmux_enum_t *gpio_data; | |
88 | + unsigned int gpio_data_size; | |
89 | + | |
90 | + unsigned long *gpio_in_use; | |
91 | + struct gpio_chip chip; | |
92 | +}; | |
93 | + | |
94 | +int register_pinmux(struct pinmux_info *pip); | |
95 | + | |
96 | +#endif /* __SH_PFC_H */ |