Merge branches 'sh/serial-rework' and 'sh/oprofile'
[linux-2.6] / arch / arm / mach-ns9xxx / gpio.c
1 /*
2  * arch/arm/mach-ns9xxx/gpio.c
3  *
4  * Copyright (C) 2006,2007 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 #include <linux/bitops.h>
16
17 #include <mach/gpio.h>
18 #include <mach/processor.h>
19 #include <mach/processor-ns9360.h>
20 #include <asm/bug.h>
21 #include <asm/types.h>
22
23 #include "gpio-ns9360.h"
24
25 #if defined(CONFIG_PROCESSOR_NS9360)
26 #define GPIO_MAX 72
27 #elif defined(CONFIG_PROCESSOR_NS9750)
28 #define GPIO_MAX 49
29 #endif
30
31 /* protects BBU_GCONFx and BBU_GCTRLx */
32 static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
33
34 /* only access gpiores with atomic ops */
35 static DECLARE_BITMAP(gpiores, GPIO_MAX + 1);
36
37 static inline int ns9xxx_valid_gpio(unsigned gpio)
38 {
39 #if defined(CONFIG_PROCESSOR_NS9360)
40         if (processor_is_ns9360())
41                 return gpio <= 72;
42         else
43 #endif
44 #if defined(CONFIG_PROCESSOR_NS9750)
45         if (processor_is_ns9750())
46                 return gpio <= 49;
47         else
48 #endif
49         {
50                 BUG();
51                 return 0;
52         }
53 }
54
55 int gpio_request(unsigned gpio, const char *label)
56 {
57         if (likely(ns9xxx_valid_gpio(gpio)))
58                 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
59         else
60                 return -EINVAL;
61 }
62 EXPORT_SYMBOL(gpio_request);
63
64 void gpio_free(unsigned gpio)
65 {
66         clear_bit(gpio, gpiores);
67         return;
68 }
69 EXPORT_SYMBOL(gpio_free);
70
71 int gpio_direction_input(unsigned gpio)
72 {
73         if (likely(ns9xxx_valid_gpio(gpio))) {
74                 int ret = -EINVAL;
75                 unsigned long flags;
76
77                 spin_lock_irqsave(&gpio_lock, flags);
78 #if defined(CONFIG_PROCESSOR_NS9360)
79                 if (processor_is_ns9360())
80                         ret = __ns9360_gpio_configure(gpio, 0, 0, 3);
81                 else
82 #endif
83                         BUG();
84
85                 spin_unlock_irqrestore(&gpio_lock, flags);
86
87                 return ret;
88
89         } else
90                 return -EINVAL;
91 }
92 EXPORT_SYMBOL(gpio_direction_input);
93
94 int gpio_direction_output(unsigned gpio, int value)
95 {
96         if (likely(ns9xxx_valid_gpio(gpio))) {
97                 int ret = -EINVAL;
98                 unsigned long flags;
99
100                 gpio_set_value(gpio, value);
101
102                 spin_lock_irqsave(&gpio_lock, flags);
103 #if defined(CONFIG_PROCESSOR_NS9360)
104                 if (processor_is_ns9360())
105                         ret = __ns9360_gpio_configure(gpio, 1, 0, 3);
106                 else
107 #endif
108                         BUG();
109
110                 spin_unlock_irqrestore(&gpio_lock, flags);
111
112                 return ret;
113         } else
114                 return -EINVAL;
115 }
116 EXPORT_SYMBOL(gpio_direction_output);
117
118 int gpio_get_value(unsigned gpio)
119 {
120 #if defined(CONFIG_PROCESSOR_NS9360)
121         if (processor_is_ns9360())
122                 return ns9360_gpio_get_value(gpio);
123         else
124 #endif
125         {
126                 BUG();
127                 return -EINVAL;
128         }
129 }
130 EXPORT_SYMBOL(gpio_get_value);
131
132 void gpio_set_value(unsigned gpio, int value)
133 {
134         unsigned long flags;
135         spin_lock_irqsave(&gpio_lock, flags);
136 #if defined(CONFIG_PROCESSOR_NS9360)
137         if (processor_is_ns9360())
138                 ns9360_gpio_set_value(gpio, value);
139         else
140 #endif
141                 BUG();
142
143         spin_unlock_irqrestore(&gpio_lock, flags);
144 }
145 EXPORT_SYMBOL(gpio_set_value);