blob: 5286e9fc1d307bac62f1341dd6c4e728a83be33a [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>
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010019#include <asm/io.h>
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010020#include <asm/bug.h>
21#include <asm/types.h>
22#include <asm/bitops.h>
23
24#if defined(CONFIG_PROCESSOR_NS9360)
25#define GPIO_MAX 72
26#elif defined(CONFIG_PROCESSOR_NS9750)
27#define GPIO_MAX 49
28#endif
29
30/* protects BBU_GCONFx and BBU_GCTRLx */
31static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
32
33/* only access gpiores with atomic ops */
Uwe Kleine-Königac5bbf22008-03-06 16:21:42 +010034static DECLARE_BITMAP(gpiores, GPIO_MAX + 1);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010035
36static inline int ns9xxx_valid_gpio(unsigned gpio)
37{
38#if defined(CONFIG_PROCESSOR_NS9360)
39 if (processor_is_ns9360())
40 return gpio <= 72;
41 else
42#endif
43#if defined(CONFIG_PROCESSOR_NS9750)
44 if (processor_is_ns9750())
45 return gpio <= 49;
46 else
47#endif
48 BUG();
49}
50
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010051static inline void __iomem *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010052{
53 if (gpio < 56)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010054 return BBU_GCONFb1(gpio / 8);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010055 else
56 /*
57 * this could be optimised away on
58 * ns9750 only builds, but it isn't ...
59 */
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010060 return BBU_GCONFb2((gpio - 56) / 8);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010061}
62
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010063static inline void __iomem *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010064{
65 if (gpio < 32)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010066 return BBU_GCTRL1;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010067 else if (gpio < 64)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010068 return BBU_GCTRL2;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010069 else
70 /* this could be optimised away on ns9750 only builds */
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010071 return BBU_GCTRL3;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010072}
73
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010074static inline void __iomem *ns9xxx_gpio_get_gstataddr(unsigned gpio)
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010075{
76 if (gpio < 32)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010077 return BBU_GSTAT1;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010078 else if (gpio < 64)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010079 return BBU_GSTAT2;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010080 else
81 /* this could be optimised away on ns9750 only builds */
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +010082 return BBU_GSTAT3;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +010083}
84
85int gpio_request(unsigned gpio, const char *label)
86{
87 if (likely(ns9xxx_valid_gpio(gpio)))
88 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
89 else
90 return -EINVAL;
91}
92EXPORT_SYMBOL(gpio_request);
93
94void gpio_free(unsigned gpio)
95{
96 clear_bit(gpio, gpiores);
97 return;
98}
99EXPORT_SYMBOL(gpio_free);
100
101/*
102 * each gpio can serve for 4 different purposes [0..3]. These are called
103 * "functions" and passed in the parameter func. Functions 0-2 are always some
104 * special things, function 3 is GPIO. If func == 3 dir specifies input or
105 * output, and with inv you can enable an inverter (independent of func).
106 */
107static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
108{
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100109 void __iomem *conf = ns9xxx_gpio_get_gconfaddr(gpio);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100110 u32 confval;
111 unsigned long flags;
112
113 spin_lock_irqsave(&gpio_lock, flags);
114
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100115 confval = __raw_readl(conf);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100116 REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
117 REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
118 REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100119 __raw_writel(confval, conf);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100120
121 spin_unlock_irqrestore(&gpio_lock, flags);
122
123 return 0;
124}
125
126int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
127{
128 if (likely(ns9xxx_valid_gpio(gpio))) {
129 if (func == 3) {
130 printk(KERN_WARNING "use gpio_direction_input "
131 "or gpio_direction_output\n");
132 return -EINVAL;
133 } else
134 return __ns9xxx_gpio_configure(gpio, 0, inv, func);
135 } else
136 return -EINVAL;
137}
138EXPORT_SYMBOL(ns9xxx_gpio_configure);
139
140int gpio_direction_input(unsigned gpio)
141{
142 if (likely(ns9xxx_valid_gpio(gpio))) {
143 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
144 } else
145 return -EINVAL;
146}
147EXPORT_SYMBOL(gpio_direction_input);
148
149int gpio_direction_output(unsigned gpio, int value)
150{
151 if (likely(ns9xxx_valid_gpio(gpio))) {
152 gpio_set_value(gpio, value);
153
154 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
155 } else
156 return -EINVAL;
157}
158EXPORT_SYMBOL(gpio_direction_output);
159
160int gpio_get_value(unsigned gpio)
161{
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100162 void __iomem *stat = ns9xxx_gpio_get_gstataddr(gpio);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100163 int ret;
164
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100165 ret = 1 & (__raw_readl(stat) >> (gpio & 31));
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100166
167 return ret;
168}
169EXPORT_SYMBOL(gpio_get_value);
170
171void gpio_set_value(unsigned gpio, int value)
172{
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100173 void __iomem *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
174 u32 ctrlval;
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100175 unsigned long flags;
176
177 spin_lock_irqsave(&gpio_lock, flags);
178
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100179 ctrlval = __raw_readl(ctrl);
180
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100181 if (value)
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100182 ctrlval |= 1 << (gpio & 31);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100183 else
Uwe Kleine-König361c7ad2007-09-30 20:36:33 +0100184 ctrlval &= ~(1 << (gpio & 31));
185
186 __raw_writel(ctrlval, ctrl);
Uwe Kleine-König689f2a02007-09-30 20:35:09 +0100187
188 spin_unlock_irqrestore(&gpio_lock, flags);
189}
190EXPORT_SYMBOL(gpio_set_value);