1 /* linux/arch/arm/mach-vt8500/gpio.c
2  *
3  * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 
16 #include <linux/gpio.h>
17 #include <linux/init.h>
18 #include <linux/irq.h>
19 #include <linux/io.h>
20 
21 #include "devices.h"
22 
23 #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
24 
25 #define ENABLE_REGS	0x0
26 #define DIRECTION_REGS	0x20
27 #define OUTVALUE_REGS	0x40
28 #define INVALUE_REGS	0x60
29 
30 #define EXT_REGOFF	0x1c
31 
32 static void __iomem *regbase;
33 
34 struct vt8500_gpio_chip {
35 	struct gpio_chip	chip;
36 	unsigned int		shift;
37 	unsigned int		regoff;
38 };
39 
40 static int gpio_to_irq_map[8];
41 
vt8500_muxed_gpio_request(struct gpio_chip * chip,unsigned offset)42 static int vt8500_muxed_gpio_request(struct gpio_chip *chip,
43 				     unsigned offset)
44 {
45 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
46 	unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff);
47 
48 	val |= (1 << vt8500_chip->shift << offset);
49 	writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff);
50 
51 	return 0;
52 }
53 
vt8500_muxed_gpio_free(struct gpio_chip * chip,unsigned offset)54 static void vt8500_muxed_gpio_free(struct gpio_chip *chip,
55 				   unsigned offset)
56 {
57 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
58 	unsigned val = readl(regbase + ENABLE_REGS + vt8500_chip->regoff);
59 
60 	val &= ~(1 << vt8500_chip->shift << offset);
61 	writel(val, regbase + ENABLE_REGS + vt8500_chip->regoff);
62 }
63 
vt8500_muxed_gpio_direction_input(struct gpio_chip * chip,unsigned offset)64 static int vt8500_muxed_gpio_direction_input(struct gpio_chip *chip,
65 				       unsigned offset)
66 {
67 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
68 	unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff);
69 
70 	val &= ~(1 << vt8500_chip->shift << offset);
71 	writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff);
72 
73 	return 0;
74 }
75 
vt8500_muxed_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)76 static int vt8500_muxed_gpio_direction_output(struct gpio_chip *chip,
77 					unsigned offset, int value)
78 {
79 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
80 	unsigned val = readl(regbase + DIRECTION_REGS + vt8500_chip->regoff);
81 
82 	val |= (1 << vt8500_chip->shift << offset);
83 	writel(val, regbase + DIRECTION_REGS + vt8500_chip->regoff);
84 
85 	if (value) {
86 		val = readl(regbase + OUTVALUE_REGS + vt8500_chip->regoff);
87 		val |= (1 << vt8500_chip->shift << offset);
88 		writel(val, regbase + OUTVALUE_REGS + vt8500_chip->regoff);
89 	}
90 	return 0;
91 }
92 
vt8500_muxed_gpio_get_value(struct gpio_chip * chip,unsigned offset)93 static int vt8500_muxed_gpio_get_value(struct gpio_chip *chip,
94 				       unsigned offset)
95 {
96 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
97 
98 	return (readl(regbase + INVALUE_REGS + vt8500_chip->regoff)
99 		>> vt8500_chip->shift >> offset) & 1;
100 }
101 
vt8500_muxed_gpio_set_value(struct gpio_chip * chip,unsigned offset,int value)102 static void vt8500_muxed_gpio_set_value(struct gpio_chip *chip,
103 					unsigned offset, int value)
104 {
105 	struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
106 	unsigned val = readl(regbase + INVALUE_REGS + vt8500_chip->regoff);
107 
108 	if (value)
109 		val |= (1 << vt8500_chip->shift << offset);
110 	else
111 		val &= ~(1 << vt8500_chip->shift << offset);
112 
113 	writel(val, regbase + INVALUE_REGS + vt8500_chip->regoff);
114 }
115 
116 #define VT8500_GPIO_BANK(__name, __shift, __off, __base, __num)		\
117 {									\
118 	.chip = {							\
119 		.label			= __name,			\
120 		.request		= vt8500_muxed_gpio_request,	\
121 		.free			= vt8500_muxed_gpio_free,	\
122 		.direction_input  = vt8500_muxed_gpio_direction_input,	\
123 		.direction_output = vt8500_muxed_gpio_direction_output,	\
124 		.get			= vt8500_muxed_gpio_get_value,	\
125 		.set			= vt8500_muxed_gpio_set_value,	\
126 		.can_sleep		= 0,				\
127 		.base			= __base,			\
128 		.ngpio			= __num,			\
129 	},								\
130 	.shift		= __shift,					\
131 	.regoff		= __off,					\
132 }
133 
134 static struct vt8500_gpio_chip vt8500_muxed_gpios[] = {
135 	VT8500_GPIO_BANK("uart0",	0,	0x0,	8,	4),
136 	VT8500_GPIO_BANK("uart1",	4,	0x0,	12,	4),
137 	VT8500_GPIO_BANK("spi0",	8,	0x0,	16,	4),
138 	VT8500_GPIO_BANK("spi1",	12,	0x0,	20,	4),
139 	VT8500_GPIO_BANK("spi2",	16,	0x0,	24,	4),
140 	VT8500_GPIO_BANK("pwmout",	24,	0x0,	28,	2),
141 
142 	VT8500_GPIO_BANK("sdmmc",	0,	0x4,	30,	11),
143 	VT8500_GPIO_BANK("ms",		16,	0x4,	41,	7),
144 	VT8500_GPIO_BANK("i2c0",	24,	0x4,	48,	2),
145 	VT8500_GPIO_BANK("i2c1",	26,	0x4,	50,	2),
146 
147 	VT8500_GPIO_BANK("mii",		0,	0x8,	52,	20),
148 	VT8500_GPIO_BANK("see",		20,	0x8,	72,	4),
149 	VT8500_GPIO_BANK("ide",		24,	0x8,	76,	7),
150 
151 	VT8500_GPIO_BANK("ccir",	0,	0xc,	83,	19),
152 
153 	VT8500_GPIO_BANK("ts",		8,	0x10,	102,	11),
154 
155 	VT8500_GPIO_BANK("lcd",		0,	0x14,	113,	23),
156 };
157 
vt8500_gpio_direction_input(struct gpio_chip * chip,unsigned offset)158 static int vt8500_gpio_direction_input(struct gpio_chip *chip,
159 				       unsigned offset)
160 {
161 	unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF);
162 
163 	val &= ~(1 << offset);
164 	writel(val, regbase + DIRECTION_REGS + EXT_REGOFF);
165 	return 0;
166 }
167 
vt8500_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)168 static int vt8500_gpio_direction_output(struct gpio_chip *chip,
169 					unsigned offset, int value)
170 {
171 	unsigned val = readl(regbase + DIRECTION_REGS + EXT_REGOFF);
172 
173 	val |= (1 << offset);
174 	writel(val, regbase + DIRECTION_REGS + EXT_REGOFF);
175 
176 	if (value) {
177 		val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF);
178 		val |= (1 << offset);
179 		writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF);
180 	}
181 	return 0;
182 }
183 
vt8500_gpio_get_value(struct gpio_chip * chip,unsigned offset)184 static int vt8500_gpio_get_value(struct gpio_chip *chip,
185 				       unsigned offset)
186 {
187 	return (readl(regbase + INVALUE_REGS + EXT_REGOFF) >> offset) & 1;
188 }
189 
vt8500_gpio_set_value(struct gpio_chip * chip,unsigned offset,int value)190 static void vt8500_gpio_set_value(struct gpio_chip *chip,
191 					unsigned offset, int value)
192 {
193 	unsigned val = readl(regbase + OUTVALUE_REGS + EXT_REGOFF);
194 
195 	if (value)
196 		val |= (1 << offset);
197 	else
198 		val &= ~(1 << offset);
199 
200 	writel(val, regbase + OUTVALUE_REGS + EXT_REGOFF);
201 }
202 
vt8500_gpio_to_irq(struct gpio_chip * chip,unsigned offset)203 static int vt8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
204 {
205 	if (offset > 7)
206 		return -EINVAL;
207 
208 	return gpio_to_irq_map[offset];
209 }
210 
211 static struct gpio_chip vt8500_external_gpios = {
212 	.label			= "extgpio",
213 	.direction_input	= vt8500_gpio_direction_input,
214 	.direction_output	= vt8500_gpio_direction_output,
215 	.get			= vt8500_gpio_get_value,
216 	.set			= vt8500_gpio_set_value,
217 	.to_irq			= vt8500_gpio_to_irq,
218 	.can_sleep		= 0,
219 	.base			= 0,
220 	.ngpio			= 8,
221 };
222 
vt8500_gpio_init(void)223 void __init vt8500_gpio_init(void)
224 {
225 	int i;
226 
227 	for (i = 0; i < 8; i++)
228 		gpio_to_irq_map[i] = wmt_gpio_ext_irq[i];
229 
230 	regbase = ioremap(wmt_gpio_base, SZ_64K);
231 	if (!regbase) {
232 		printk(KERN_ERR "Failed to map MMIO registers for GPIO\n");
233 		return;
234 	}
235 
236 	gpiochip_add(&vt8500_external_gpios);
237 
238 	for (i = 0; i < ARRAY_SIZE(vt8500_muxed_gpios); i++)
239 		gpiochip_add(&vt8500_muxed_gpios[i].chip);
240 }
241