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