1/*
2 * Coldfire generic GPIO support.
3 *
4 * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/device.h>
20
21#include <linux/io.h>
22#include <asm/coldfire.h>
23#include <asm/mcfsim.h>
24#include <asm/mcfgpio.h>
25
26int __mcfgpio_get_value(unsigned gpio)
27{
28	return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
29}
30EXPORT_SYMBOL(__mcfgpio_get_value);
31
32void __mcfgpio_set_value(unsigned gpio, int value)
33{
34	if (gpio < MCFGPIO_SCR_START) {
35		unsigned long flags;
36		MCFGPIO_PORTTYPE data;
37
38		local_irq_save(flags);
39		data = mcfgpio_read(__mcfgpio_podr(gpio));
40		if (value)
41			data |= mcfgpio_bit(gpio);
42		else
43			data &= ~mcfgpio_bit(gpio);
44		mcfgpio_write(data, __mcfgpio_podr(gpio));
45		local_irq_restore(flags);
46	} else {
47		if (value)
48			mcfgpio_write(mcfgpio_bit(gpio),
49					MCFGPIO_SETR_PORT(gpio));
50		else
51			mcfgpio_write(~mcfgpio_bit(gpio),
52					MCFGPIO_CLRR_PORT(gpio));
53	}
54}
55EXPORT_SYMBOL(__mcfgpio_set_value);
56
57int __mcfgpio_direction_input(unsigned gpio)
58{
59	unsigned long flags;
60	MCFGPIO_PORTTYPE dir;
61
62	local_irq_save(flags);
63	dir = mcfgpio_read(__mcfgpio_pddr(gpio));
64	dir &= ~mcfgpio_bit(gpio);
65	mcfgpio_write(dir, __mcfgpio_pddr(gpio));
66	local_irq_restore(flags);
67
68	return 0;
69}
70EXPORT_SYMBOL(__mcfgpio_direction_input);
71
72int __mcfgpio_direction_output(unsigned gpio, int value)
73{
74	unsigned long flags;
75	MCFGPIO_PORTTYPE data;
76
77	local_irq_save(flags);
78	data = mcfgpio_read(__mcfgpio_pddr(gpio));
79	data |= mcfgpio_bit(gpio);
80	mcfgpio_write(data, __mcfgpio_pddr(gpio));
81
82	/* now set the data to output */
83	if (gpio < MCFGPIO_SCR_START) {
84		data = mcfgpio_read(__mcfgpio_podr(gpio));
85		if (value)
86			data |= mcfgpio_bit(gpio);
87		else
88			data &= ~mcfgpio_bit(gpio);
89		mcfgpio_write(data, __mcfgpio_podr(gpio));
90	} else {
91		 if (value)
92			mcfgpio_write(mcfgpio_bit(gpio),
93					MCFGPIO_SETR_PORT(gpio));
94		 else
95			 mcfgpio_write(~mcfgpio_bit(gpio),
96					 MCFGPIO_CLRR_PORT(gpio));
97	}
98	local_irq_restore(flags);
99	return 0;
100}
101EXPORT_SYMBOL(__mcfgpio_direction_output);
102
103int __mcfgpio_request(unsigned gpio)
104{
105	return 0;
106}
107EXPORT_SYMBOL(__mcfgpio_request);
108
109void __mcfgpio_free(unsigned gpio)
110{
111	__mcfgpio_direction_input(gpio);
112}
113EXPORT_SYMBOL(__mcfgpio_free);
114
115#ifdef CONFIG_GPIOLIB
116
117static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
118{
119	return __mcfgpio_direction_input(offset);
120}
121
122static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
123{
124	return __mcfgpio_get_value(offset);
125}
126
127static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
128				    int value)
129{
130	return __mcfgpio_direction_output(offset, value);
131}
132
133static void mcfgpio_set_value(struct gpio_chip *chip, unsigned offset,
134			      int value)
135{
136	__mcfgpio_set_value(offset, value);
137}
138
139static int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
140{
141	return __mcfgpio_request(offset);
142}
143
144static void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
145{
146	__mcfgpio_free(offset);
147}
148
149static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset)
150{
151#if defined(MCFGPIO_IRQ_MIN)
152	if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX))
153#else
154	if (offset < MCFGPIO_IRQ_MAX)
155#endif
156		return MCFGPIO_IRQ_VECBASE + offset;
157	else
158		return -EINVAL;
159}
160
161static struct bus_type mcfgpio_subsys = {
162	.name		= "gpio",
163	.dev_name	= "gpio",
164};
165
166static struct gpio_chip mcfgpio_chip = {
167	.label			= "mcfgpio",
168	.request		= mcfgpio_request,
169	.free			= mcfgpio_free,
170	.direction_input	= mcfgpio_direction_input,
171	.direction_output	= mcfgpio_direction_output,
172	.get			= mcfgpio_get_value,
173	.set			= mcfgpio_set_value,
174	.to_irq			= mcfgpio_to_irq,
175	.base			= 0,
176	.ngpio			= MCFGPIO_PIN_MAX,
177};
178
179static int __init mcfgpio_sysinit(void)
180{
181	gpiochip_add(&mcfgpio_chip);
182	return subsys_system_register(&mcfgpio_subsys, NULL);
183}
184
185core_initcall(mcfgpio_sysinit);
186#endif
187