blob: 87b872fdca7e9d519bb594dd73ebc3acd8ac0d5a [file] [log] [blame]
Uwe Kleine-König689f2a02007-09-30 20:35:09 +01001/*
2 * arch/arm/mach-ns9xxx/gpio.c
3 *
4 * Copyright (C) 2006 by Digi International Inc.
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11#include <linux/compiler.h>
12#include <linux/init.h>
13#include <linux/spinlock.h>
14#include <linux/module.h>
15
16#include <asm/arch-ns9xxx/gpio.h>
17#include <asm/arch-ns9xxx/processor.h>
18#include <asm/arch-ns9xxx/regs-bbu.h>
19#include <asm/bug.h>
20#include <asm/types.h>
21#include <asm/bitops.h>
22
23#if defined(CONFIG_PROCESSOR_NS9360)
24#define GPIO_MAX 72
25#elif defined(CONFIG_PROCESSOR_NS9750)
26#define GPIO_MAX 49
27#endif
28
29/* protects BBU_GCONFx and BBU_GCTRLx */
30static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
31
32/* only access gpiores with atomic ops */
33static DECLARE_BITMAP(gpiores, GPIO_MAX);
34
35static inline int ns9xxx_valid_gpio(unsigned gpio)
36{
37#if defined(CONFIG_PROCESSOR_NS9360)
38 if (processor_is_ns9360())
39 return gpio <= 72;
40 else
41#endif
42#if defined(CONFIG_PROCESSOR_NS9750)
43 if (processor_is_ns9750())
44 return gpio <= 49;
45 else
46#endif
47 BUG();
48}
49
50static inline volatile u32 *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
51{
52 if (gpio < 56)
53 return &BBU_GCONFb1(gpio / 8);
54 else
55 /*
56 * this could be optimised away on
57 * ns9750 only builds, but it isn't ...
58 */
59 return &BBU_GCONFb2((gpio - 56) / 8);
60}
61
62static inline volatile u32 *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
63{
64 if (gpio < 32)
65 return &BBU_GCTRL1;
66 else if (gpio < 64)
67 return &BBU_GCTRL2;
68 else
69 /* this could be optimised away on ns9750 only builds */
70 return &BBU_GCTRL3;
71}
72
73static inline volatile u32 *ns9xxx_gpio_get_gstataddr(unsigned gpio)
74{
75 if (gpio < 32)
76 return &BBU_GSTAT1;
77 else if (gpio < 64)
78 return &BBU_GSTAT2;
79 else
80 /* this could be optimised away on ns9750 only builds */
81 return &BBU_GSTAT3;
82}
83
84int gpio_request(unsigned gpio, const char *label)
85{
86 if (likely(ns9xxx_valid_gpio(gpio)))
87 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
88 else
89 return -EINVAL;
90}
91EXPORT_SYMBOL(gpio_request);
92
93void gpio_free(unsigned gpio)
94{
95 clear_bit(gpio, gpiores);
96 return;
97}
98EXPORT_SYMBOL(gpio_free);
99
100/*
101 * each gpio can serve for 4 different purposes [0..3]. These are called
102 * "functions" and passed in the parameter func. Functions 0-2 are always some
103 * special things, function 3 is GPIO. If func == 3 dir specifies input or
104 * output, and with inv you can enable an inverter (independent of func).
105 */
106static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
107{
108 volatile u32 *conf = ns9xxx_gpio_get_gconfaddr(gpio);
109 u32 confval;
110 unsigned long flags;
111
112 spin_lock_irqsave(&gpio_lock, flags);
113
114 confval = *conf;
115 REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
116 REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
117 REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
118 *conf = confval;
119
120 spin_unlock_irqrestore(&gpio_lock, flags);
121
122 return 0;
123}
124
125int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
126{
127 if (likely(ns9xxx_valid_gpio(gpio))) {
128 if (func == 3) {
129 printk(KERN_WARNING "use gpio_direction_input "
130 "or gpio_direction_output\n");
131 return -EINVAL;
132 } else
133 return __ns9xxx_gpio_configure(gpio, 0, inv, func);
134 } else
135 return -EINVAL;
136}
137EXPORT_SYMBOL(ns9xxx_gpio_configure);
138
139int gpio_direction_input(unsigned gpio)
140{
141 if (likely(ns9xxx_valid_gpio(gpio))) {
142 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
143 } else
144 return -EINVAL;
145}
146EXPORT_SYMBOL(gpio_direction_input);
147
148int gpio_direction_output(unsigned gpio, int value)
149{
150 if (likely(ns9xxx_valid_gpio(gpio))) {
151 gpio_set_value(gpio, value);
152
153 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
154 } else
155 return -EINVAL;
156}
157EXPORT_SYMBOL(gpio_direction_output);
158
159int gpio_get_value(unsigned gpio)
160{
161 volatile u32 *stat = ns9xxx_gpio_get_gstataddr(gpio);
162 int ret;
163
164 ret = 1 & (*stat >> (gpio & 31));
165
166 return ret;
167}
168EXPORT_SYMBOL(gpio_get_value);
169
170void gpio_set_value(unsigned gpio, int value)
171{
172 volatile u32 *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
173 unsigned long flags;
174
175 spin_lock_irqsave(&gpio_lock, flags);
176
177 if (value)
178 *ctrl |= 1 << (gpio & 31);
179 else
180 *ctrl &= ~(1 << (gpio & 31));
181
182 spin_unlock_irqrestore(&gpio_lock, flags);
183}
184EXPORT_SYMBOL(gpio_set_value);