xref: /openbmc/linux/arch/arm/mach-sa1100/h3xxx.c (revision a09d2831)
1 /*
2  * Support for Compaq iPAQ H3100 and H3600 handheld computers (common code)
3  *
4  * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
5  * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  */
12 
13 #include <linux/kernel.h>
14 #include <linux/gpio.h>
15 #include <linux/gpio_keys.h>
16 #include <linux/input.h>
17 #include <linux/mfd/htc-egpio.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/partitions.h>
20 #include <linux/platform_device.h>
21 #include <linux/serial_core.h>
22 
23 #include <asm/mach/flash.h>
24 #include <asm/mach/map.h>
25 #include <asm/mach/serial_sa1100.h>
26 
27 #include <mach/h3xxx.h>
28 
29 #include "generic.h"
30 
31 void h3xxx_init_gpio(struct gpio_default_state *s, size_t n)
32 {
33 	while (n--) {
34 		const char *name = s->name;
35 		int err;
36 
37 		if (!name)
38 			name = "[init]";
39 		err = gpio_request(s->gpio, name);
40 		if (err) {
41 			printk(KERN_ERR "gpio%u: unable to request: %d\n",
42 				s->gpio, err);
43 			continue;
44 		}
45 		if (s->mode >= 0) {
46 			err = gpio_direction_output(s->gpio, s->mode);
47 		} else {
48 			err = gpio_direction_input(s->gpio);
49 		}
50 		if (err) {
51 			printk(KERN_ERR "gpio%u: unable to set direction: %d\n",
52 				s->gpio, err);
53 			continue;
54 		}
55 		if (!s->name)
56 			gpio_free(s->gpio);
57 		s++;
58 	}
59 }
60 
61 
62 /*
63  * H3xxx flash support
64  */
65 static struct mtd_partition h3xxx_partitions[] = {
66 	{
67 		.name		= "H3XXX boot firmware",
68 		.size		= 0x00040000,
69 		.offset		= 0,
70 		.mask_flags	= MTD_WRITEABLE,  /* force read-only */
71 	}, {
72 		.name		= "H3XXX rootfs",
73 		.size		= MTDPART_SIZ_FULL,
74 		.offset		= 0x00040000,
75 	}
76 };
77 
78 static void h3xxx_set_vpp(int vpp)
79 {
80 	gpio_set_value(H3XXX_EGPIO_VPP_ON, vpp);
81 }
82 
83 static int h3xxx_flash_init(void)
84 {
85 	int err = gpio_request(H3XXX_EGPIO_VPP_ON, "Flash Vpp");
86 	if (err) {
87 		pr_err("%s: can't request H3XXX_EGPIO_VPP_ON\n", __func__);
88 		return err;
89 	}
90 
91 	err = gpio_direction_output(H3XXX_EGPIO_VPP_ON, 0);
92 	if (err)
93 		gpio_free(H3XXX_EGPIO_VPP_ON);
94 
95 	return err;
96 }
97 
98 static void h3xxx_flash_exit(void)
99 {
100 	gpio_free(H3XXX_EGPIO_VPP_ON);
101 }
102 
103 static struct flash_platform_data h3xxx_flash_data = {
104 	.map_name	= "cfi_probe",
105 	.set_vpp	= h3xxx_set_vpp,
106 	.init		= h3xxx_flash_init,
107 	.exit		= h3xxx_flash_exit,
108 	.parts		= h3xxx_partitions,
109 	.nr_parts	= ARRAY_SIZE(h3xxx_partitions),
110 };
111 
112 static struct resource h3xxx_flash_resource = {
113 	.start		= SA1100_CS0_PHYS,
114 	.end		= SA1100_CS0_PHYS + SZ_32M - 1,
115 	.flags		= IORESOURCE_MEM,
116 };
117 
118 
119 /*
120  * H3xxx uart support
121  */
122 static void h3xxx_uart_set_mctrl(struct uart_port *port, u_int mctrl)
123 {
124 	if (port->mapbase == _Ser3UTCR0) {
125 		gpio_set_value(H3XXX_GPIO_COM_RTS, !(mctrl & TIOCM_RTS));
126 	}
127 }
128 
129 static u_int h3xxx_uart_get_mctrl(struct uart_port *port)
130 {
131 	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
132 
133 	if (port->mapbase == _Ser3UTCR0) {
134 		/*
135 		 * DCD and CTS bits are inverted in GPLR by RS232 transceiver
136 		 */
137 		if (gpio_get_value(H3XXX_GPIO_COM_DCD))
138 			ret &= ~TIOCM_CD;
139 		if (gpio_get_value(H3XXX_GPIO_COM_CTS))
140 			ret &= ~TIOCM_CTS;
141 	}
142 
143 	return ret;
144 }
145 
146 static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
147 {
148 	if (port->mapbase == _Ser3UTCR0) {
149 		if (!gpio_request(H3XXX_EGPIO_RS232_ON, "RS232 transceiver")) {
150 			gpio_direction_output(H3XXX_EGPIO_RS232_ON, !state);
151 			gpio_free(H3XXX_EGPIO_RS232_ON);
152 		} else {
153 			pr_err("%s: can't request H3XXX_EGPIO_RS232_ON\n",
154 				__func__);
155 		}
156 	}
157 }
158 
159 /*
160  * Enable/Disable wake up events for this serial port.
161  * Obviously, we only support this on the normal COM port.
162  */
163 static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable)
164 {
165 	int err = -EINVAL;
166 
167 	if (port->mapbase == _Ser3UTCR0) {
168 		if (enable)
169 			PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
170 		else
171 			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
172 		err = 0;
173 	}
174 	return err;
175 }
176 
177 static struct sa1100_port_fns h3xxx_port_fns __initdata = {
178 	.set_mctrl	= h3xxx_uart_set_mctrl,
179 	.get_mctrl	= h3xxx_uart_get_mctrl,
180 	.pm		= h3xxx_uart_pm,
181 	.set_wake	= h3xxx_uart_set_wake,
182 };
183 
184 /*
185  * EGPIO
186  */
187 
188 static struct resource egpio_resources[] = {
189 	[0] = {
190 		.start	= H3600_EGPIO_PHYS,
191 		.end	= H3600_EGPIO_PHYS + 0x4 - 1,
192 		.flags	= IORESOURCE_MEM,
193 	},
194 };
195 
196 static struct htc_egpio_chip egpio_chips[] = {
197 	[0] = {
198 		.reg_start	= 0,
199 		.gpio_base	= H3XXX_EGPIO_BASE,
200 		.num_gpios	= 16,
201 		.direction	= HTC_EGPIO_OUTPUT,
202 		.initial_values	= 0x0080, /* H3XXX_EGPIO_RS232_ON */
203 	},
204 };
205 
206 static struct htc_egpio_platform_data egpio_info = {
207 	.reg_width	= 16,
208 	.bus_width	= 16,
209 	.chip		= egpio_chips,
210 	.num_chips	= ARRAY_SIZE(egpio_chips),
211 };
212 
213 static struct platform_device h3xxx_egpio = {
214 	.name		= "htc-egpio",
215 	.id		= -1,
216 	.resource	= egpio_resources,
217 	.num_resources	= ARRAY_SIZE(egpio_resources),
218 	.dev		= {
219 		.platform_data = &egpio_info,
220 	},
221 };
222 
223 /*
224  * GPIO keys
225  */
226 
227 static struct gpio_keys_button h3xxx_button_table[] = {
228 	{
229 		.code		= KEY_POWER,
230 		.gpio		= H3XXX_GPIO_PWR_BUTTON,
231 		.desc		= "Power Button",
232 		.active_low	= 1,
233 		.type		= EV_KEY,
234 		.wakeup		= 1,
235 	}, {
236 		.code		= KEY_ENTER,
237 		.gpio		= H3XXX_GPIO_ACTION_BUTTON,
238 		.active_low	= 1,
239 		.desc		= "Action button",
240 		.type		= EV_KEY,
241 		.wakeup		= 0,
242 	},
243 };
244 
245 static struct gpio_keys_platform_data h3xxx_keys_data = {
246 	.buttons  = h3xxx_button_table,
247 	.nbuttons = ARRAY_SIZE(h3xxx_button_table),
248 };
249 
250 static struct platform_device h3xxx_keys = {
251 	.name	= "gpio-keys",
252 	.id	= -1,
253 	.dev	= {
254 		.platform_data = &h3xxx_keys_data,
255 	},
256 };
257 
258 static struct platform_device *h3xxx_devices[] = {
259 	&h3xxx_egpio,
260 	&h3xxx_keys,
261 };
262 
263 void __init h3xxx_mach_init(void)
264 {
265 	sa1100_register_uart_fns(&h3xxx_port_fns);
266 	sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
267 	platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices));
268 }
269 
270 static struct map_desc h3600_io_desc[] __initdata = {
271 	{	/* static memory bank 2  CS#2 */
272 		.virtual	=  H3600_BANK_2_VIRT,
273 		.pfn		= __phys_to_pfn(SA1100_CS2_PHYS),
274 		.length		= 0x02800000,
275 		.type		= MT_DEVICE
276 	}, {	/* static memory bank 4  CS#4 */
277 		.virtual	=  H3600_BANK_4_VIRT,
278 		.pfn		= __phys_to_pfn(SA1100_CS4_PHYS),
279 		.length		= 0x00800000,
280 		.type		= MT_DEVICE
281 	}, {	/* EGPIO 0		CS#5 */
282 		.virtual	=  H3600_EGPIO_VIRT,
283 		.pfn		= __phys_to_pfn(H3600_EGPIO_PHYS),
284 		.length		= 0x01000000,
285 		.type		= MT_DEVICE
286 	}
287 };
288 
289 /*
290  * Common map_io initialization
291  */
292 
293 void __init h3xxx_map_io(void)
294 {
295 	sa1100_map_io();
296 	iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
297 
298 	sa1100_register_uart(0, 3); /* Common serial port */
299 //	sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
300 
301 	/* Ensure those pins are outputs and driving low  */
302 	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
303 	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
304 
305 	/* Configure suspend conditions */
306 	PGSR = 0;
307 	PCFR = PCFR_OPDE;
308 	PSDR = 0;
309 
310 	GPCR = 0x0fffffff;	/* All outputs are set low by default */
311 	GPDR = 0;		/* Configure all GPIOs as input */
312 }
313 
314