1/*
2 * arch/arm/mach-pnx4008/gpio.c
3 *
4 * PNX4008 GPIO driver
5 *
6 * Author: Dmitry Chigirev <source@mvista.com>
7 *
8 * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips:
9 * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
10 *
11 * 2005 (c) MontaVista Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
14 * or implied.
15 */
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/io.h>
20#include <mach/hardware.h>
21#include <mach/platform.h>
22#include <mach/gpio-pnx4008.h>
23
24/* register definitions */
25#define PIO_VA_BASE	IO_ADDRESS(PNX4008_PIO_BASE)
26
27#define PIO_INP_STATE	(0x00U)
28#define PIO_OUTP_SET	(0x04U)
29#define PIO_OUTP_CLR	(0x08U)
30#define PIO_OUTP_STATE	(0x0CU)
31#define PIO_DRV_SET	(0x10U)
32#define PIO_DRV_CLR	(0x14U)
33#define PIO_DRV_STATE	(0x18U)
34#define PIO_SDINP_STATE	(0x1CU)
35#define PIO_SDOUTP_SET	(0x20U)
36#define PIO_SDOUTP_CLR	(0x24U)
37#define PIO_MUX_SET	(0x28U)
38#define PIO_MUX_CLR	(0x2CU)
39#define PIO_MUX_STATE	(0x30U)
40
41static inline void gpio_lock(void)
42{
43	local_irq_disable();
44}
45
46static inline void gpio_unlock(void)
47{
48	local_irq_enable();
49}
50
51/* Inline functions */
52static inline int gpio_read_bit(u32 reg, int gpio)
53{
54	u32 bit, val;
55	int ret = -EFAULT;
56
57	if (gpio < 0)
58		goto out;
59
60	bit = GPIO_BIT(gpio);
61	if (bit) {
62		val = __raw_readl(PIO_VA_BASE + reg);
63		ret = (val & bit) ? 1 : 0;
64	}
65out:
66	return ret;
67}
68
69static inline int gpio_set_bit(u32 reg, int gpio)
70{
71	u32 bit, val;
72	int ret = -EFAULT;
73
74	if (gpio < 0)
75		goto out;
76
77	bit = GPIO_BIT(gpio);
78	if (bit) {
79		val = __raw_readl(PIO_VA_BASE + reg);
80		val |= bit;
81		__raw_writel(val, PIO_VA_BASE + reg);
82		ret = 0;
83	}
84out:
85	return ret;
86}
87
88/* Very simple access control, bitmap for allocated/free */
89static unsigned long access_map[4];
90#define INP_INDEX	0
91#define OUTP_INDEX	1
92#define GPIO_INDEX	2
93#define MUX_INDEX	3
94
95/*GPIO to Input Mapping */
96static short gpio_to_inp_map[32] = {
97	-1, -1, -1, -1, -1, -1, -1, -1,
98	-1, -1, -1, -1, -1, -1, -1, -1,
99	-1, -1, -1, -1, -1, -1, -1, -1,
100	-1, 10, 11, 12, 13, 14, 24, -1
101};
102
103/*GPIO to Mux Mapping */
104static short gpio_to_mux_map[32] = {
105	-1, -1, -1, -1, -1, -1, -1, -1,
106	-1, -1, -1, -1, -1, -1, -1, -1,
107	-1, -1, -1, -1, -1, -1, -1, -1,
108	-1, -1, -1, 0, 1, 4, 5, -1
109};
110
111/*Output to Mux Mapping */
112static short outp_to_mux_map[32] = {
113	-1, -1, -1, 6, -1, -1, -1, -1,
114	-1, -1, -1, -1, -1, -1, -1, -1,
115	-1, -1, -1, -1, -1, 2, -1, -1,
116	-1, -1, -1, -1, -1, -1, -1, -1
117};
118
119int pnx4008_gpio_register_pin(unsigned short pin)
120{
121	unsigned long bit = GPIO_BIT(pin);
122	int ret = -EBUSY;	/* Already in use */
123
124	gpio_lock();
125
126	if (GPIO_ISBID(pin)) {
127		if (access_map[GPIO_INDEX] & bit)
128			goto out;
129		access_map[GPIO_INDEX] |= bit;
130
131	} else if (GPIO_ISRAM(pin)) {
132		if (access_map[GPIO_INDEX] & bit)
133			goto out;
134		access_map[GPIO_INDEX] |= bit;
135
136	} else if (GPIO_ISMUX(pin)) {
137		if (access_map[MUX_INDEX] & bit)
138			goto out;
139		access_map[MUX_INDEX] |= bit;
140
141	} else if (GPIO_ISOUT(pin)) {
142		if (access_map[OUTP_INDEX] & bit)
143			goto out;
144		access_map[OUTP_INDEX] |= bit;
145
146	} else if (GPIO_ISIN(pin)) {
147		if (access_map[INP_INDEX] & bit)
148			goto out;
149		access_map[INP_INDEX] |= bit;
150	} else
151		goto out;
152	ret = 0;
153
154out:
155	gpio_unlock();
156	return ret;
157}
158
159EXPORT_SYMBOL(pnx4008_gpio_register_pin);
160
161int pnx4008_gpio_unregister_pin(unsigned short pin)
162{
163	unsigned long bit = GPIO_BIT(pin);
164	int ret = -EFAULT;	/* Not registered */
165
166	gpio_lock();
167
168	if (GPIO_ISBID(pin)) {
169		if (~access_map[GPIO_INDEX] & bit)
170			goto out;
171		access_map[GPIO_INDEX] &= ~bit;
172	} else if (GPIO_ISRAM(pin)) {
173		if (~access_map[GPIO_INDEX] & bit)
174			goto out;
175		access_map[GPIO_INDEX] &= ~bit;
176	} else if (GPIO_ISMUX(pin)) {
177		if (~access_map[MUX_INDEX] & bit)
178			goto out;
179		access_map[MUX_INDEX] &= ~bit;
180	} else if (GPIO_ISOUT(pin)) {
181		if (~access_map[OUTP_INDEX] & bit)
182			goto out;
183		access_map[OUTP_INDEX] &= ~bit;
184	} else if (GPIO_ISIN(pin)) {
185		if (~access_map[INP_INDEX] & bit)
186			goto out;
187		access_map[INP_INDEX] &= ~bit;
188	} else
189		goto out;
190	ret = 0;
191
192out:
193	gpio_unlock();
194	return ret;
195}
196
197EXPORT_SYMBOL(pnx4008_gpio_unregister_pin);
198
199unsigned long pnx4008_gpio_read_pin(unsigned short pin)
200{
201	unsigned long ret = -EFAULT;
202	int gpio = GPIO_BIT_MASK(pin);
203	gpio_lock();
204	if (GPIO_ISOUT(pin)) {
205		ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
206	} else if (GPIO_ISRAM(pin)) {
207		if (gpio_read_bit(PIO_DRV_STATE, gpio) == 0) {
208			ret = gpio_read_bit(PIO_SDINP_STATE, gpio);
209		}
210	} else if (GPIO_ISBID(pin)) {
211		ret = gpio_read_bit(PIO_DRV_STATE, gpio);
212		if (ret > 0)
213			ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
214		else if (ret == 0)
215			ret =
216			    gpio_read_bit(PIO_INP_STATE, gpio_to_inp_map[gpio]);
217	} else if (GPIO_ISIN(pin)) {
218		ret = gpio_read_bit(PIO_INP_STATE, gpio);
219	}
220	gpio_unlock();
221	return ret;
222}
223
224EXPORT_SYMBOL(pnx4008_gpio_read_pin);
225
226/* Write Value to output */
227int pnx4008_gpio_write_pin(unsigned short pin, int output)
228{
229	int gpio = GPIO_BIT_MASK(pin);
230	int ret = -EFAULT;
231
232	gpio_lock();
233	if (GPIO_ISOUT(pin)) {
234		printk( "writing '%x' to '%x'\n",
235				gpio, output ? PIO_OUTP_SET : PIO_OUTP_CLR );
236		ret = gpio_set_bit(output ? PIO_OUTP_SET : PIO_OUTP_CLR, gpio);
237	} else if (GPIO_ISRAM(pin)) {
238		if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
239			ret = gpio_set_bit(output ? PIO_SDOUTP_SET :
240					   PIO_SDOUTP_CLR, gpio);
241	} else if (GPIO_ISBID(pin)) {
242		if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
243			ret = gpio_set_bit(output ? PIO_OUTP_SET :
244					   PIO_OUTP_CLR, gpio);
245	}
246	gpio_unlock();
247	return ret;
248}
249
250EXPORT_SYMBOL(pnx4008_gpio_write_pin);
251
252/* Value = 1 : Set GPIO pin as output */
253/* Value = 0 : Set GPIO pin as input */
254int pnx4008_gpio_set_pin_direction(unsigned short pin, int output)
255{
256	int gpio = GPIO_BIT_MASK(pin);
257	int ret = -EFAULT;
258
259	gpio_lock();
260	if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
261		ret = gpio_set_bit(output ? PIO_DRV_SET : PIO_DRV_CLR, gpio);
262	}
263	gpio_unlock();
264	return ret;
265}
266
267EXPORT_SYMBOL(pnx4008_gpio_set_pin_direction);
268
269/* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/
270int pnx4008_gpio_read_pin_direction(unsigned short pin)
271{
272	int gpio = GPIO_BIT_MASK(pin);
273	int ret = -EFAULT;
274
275	gpio_lock();
276	if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
277		ret = gpio_read_bit(PIO_DRV_STATE, gpio);
278	}
279	gpio_unlock();
280	return ret;
281}
282
283EXPORT_SYMBOL(pnx4008_gpio_read_pin_direction);
284
285/* Value = 1 : Set pin to muxed function  */
286/* Value = 0 : Set pin as GPIO */
287int pnx4008_gpio_set_pin_mux(unsigned short pin, int output)
288{
289	int gpio = GPIO_BIT_MASK(pin);
290	int ret = -EFAULT;
291
292	gpio_lock();
293	if (GPIO_ISBID(pin)) {
294		ret =
295		    gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
296				 gpio_to_mux_map[gpio]);
297	} else if (GPIO_ISOUT(pin)) {
298		ret =
299		    gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
300				 outp_to_mux_map[gpio]);
301	} else if (GPIO_ISMUX(pin)) {
302		ret = gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, gpio);
303	}
304	gpio_unlock();
305	return ret;
306}
307
308EXPORT_SYMBOL(pnx4008_gpio_set_pin_mux);
309
310/* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/
311int pnx4008_gpio_read_pin_mux(unsigned short pin)
312{
313	int gpio = GPIO_BIT_MASK(pin);
314	int ret = -EFAULT;
315
316	gpio_lock();
317	if (GPIO_ISBID(pin)) {
318		ret = gpio_read_bit(PIO_MUX_STATE, gpio_to_mux_map[gpio]);
319	} else if (GPIO_ISOUT(pin)) {
320		ret = gpio_read_bit(PIO_MUX_STATE, outp_to_mux_map[gpio]);
321	} else if (GPIO_ISMUX(pin)) {
322		ret = gpio_read_bit(PIO_MUX_STATE, gpio);
323	}
324	gpio_unlock();
325	return ret;
326}
327
328EXPORT_SYMBOL(pnx4008_gpio_read_pin_mux);
329