1 /*
2  * linux/arch/arm/mach-omap1/board-palmte.c
3  *
4  * Modified from board-generic.c
5  *
6  * Support for the Palm Tungsten E PDA.
7  *
8  * Original version : Laurent Gonzalez
9  *
10  * Maintainers : http://palmtelinux.sf.net
11  *                palmtelinux-developpers@lists.sf.net
12  *
13  * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License version 2 as
17  * published by the Free Software Foundation.
18  */
19 
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/input.h>
23 #include <linux/platform_device.h>
24 #include <linux/mtd/mtd.h>
25 #include <linux/mtd/partitions.h>
26 #include <linux/spi/spi.h>
27 #include <linux/spi/tsc2102.h>
28 #include <linux/interrupt.h>
29 #include <linux/apm-emulation.h>
30 
31 #include <asm/hardware.h>
32 #include <asm/mach-types.h>
33 #include <asm/mach/arch.h>
34 #include <asm/mach/map.h>
35 #include <asm/mach/flash.h>
36 
37 #include <asm/arch/gpio.h>
38 #include <asm/arch/mux.h>
39 #include <asm/arch/usb.h>
40 #include <asm/arch/tc.h>
41 #include <asm/arch/dma.h>
42 #include <asm/arch/board.h>
43 #include <asm/arch/irda.h>
44 #include <asm/arch/keypad.h>
45 #include <asm/arch/common.h>
46 #include <asm/arch/mcbsp.h>
47 #include <asm/arch/omap-alsa.h>
48 
49 static void __init omap_palmte_init_irq(void)
50 {
51 	omap1_init_common_hw();
52 	omap_init_irq();
53 	omap_gpio_init();
54 }
55 
56 static const int palmte_keymap[] = {
57 	KEY(0, 0, KEY_F1),		/* Calendar */
58 	KEY(0, 1, KEY_F2),		/* Contacts */
59 	KEY(0, 2, KEY_F3),		/* Tasks List */
60 	KEY(0, 3, KEY_F4),		/* Note Pad */
61 	KEY(0, 4, KEY_POWER),
62 	KEY(1, 0, KEY_LEFT),
63 	KEY(1, 1, KEY_DOWN),
64 	KEY(1, 2, KEY_UP),
65 	KEY(1, 3, KEY_RIGHT),
66 	KEY(1, 4, KEY_CENTER),
67 	0,
68 };
69 
70 static struct omap_kp_platform_data palmte_kp_data = {
71 	.rows	= 8,
72 	.cols	= 8,
73 	.keymap = (int *) palmte_keymap,
74 	.rep	= 1,
75 	.delay	= 12,
76 };
77 
78 static struct resource palmte_kp_resources[] = {
79 	[0]	= {
80 		.start	= INT_KEYBOARD,
81 		.end	= INT_KEYBOARD,
82 		.flags	= IORESOURCE_IRQ,
83 	},
84 };
85 
86 static struct platform_device palmte_kp_device = {
87 	.name		= "omap-keypad",
88 	.id		= -1,
89 	.dev		= {
90 		.platform_data	= &palmte_kp_data,
91 	},
92 	.num_resources	= ARRAY_SIZE(palmte_kp_resources),
93 	.resource	= palmte_kp_resources,
94 };
95 
96 static struct mtd_partition palmte_rom_partitions[] = {
97 	/* PalmOS "Small ROM", contains the bootloader and the debugger */
98 	{
99 		.name		= "smallrom",
100 		.offset		= 0,
101 		.size		= 0xa000,
102 		.mask_flags	= MTD_WRITEABLE,
103 	},
104 	/* PalmOS "Big ROM", a filesystem with all the OS code and data */
105 	{
106 		.name		= "bigrom",
107 		.offset		= SZ_128K,
108 		/*
109 		 * 0x5f0000 bytes big in the multi-language ("EFIGS") version,
110 		 * 0x7b0000 bytes in the English-only ("enUS") version.
111 		 */
112 		.size		= 0x7b0000,
113 		.mask_flags	= MTD_WRITEABLE,
114 	},
115 };
116 
117 static struct flash_platform_data palmte_rom_data = {
118 	.map_name	= "map_rom",
119 	.width		= 2,
120 	.parts		= palmte_rom_partitions,
121 	.nr_parts	= ARRAY_SIZE(palmte_rom_partitions),
122 };
123 
124 static struct resource palmte_rom_resource = {
125 	.start		= OMAP_CS0_PHYS,
126 	.end		= OMAP_CS0_PHYS + SZ_8M - 1,
127 	.flags		= IORESOURCE_MEM,
128 };
129 
130 static struct platform_device palmte_rom_device = {
131 	.name		= "omapflash",
132 	.id		= -1,
133 	.dev		= {
134 		.platform_data	= &palmte_rom_data,
135 	},
136 	.num_resources	= 1,
137 	.resource	= &palmte_rom_resource,
138 };
139 
140 static struct platform_device palmte_lcd_device = {
141 	.name		= "lcd_palmte",
142 	.id		= -1,
143 };
144 
145 static struct omap_backlight_config palmte_backlight_config = {
146 	.default_intensity	= 0xa0,
147 };
148 
149 static struct platform_device palmte_backlight_device = {
150 	.name		= "omap-bl",
151 	.id		= -1,
152 	.dev		= {
153 		.platform_data	= &palmte_backlight_config,
154 	},
155 };
156 
157 static struct omap_irda_config palmte_irda_config = {
158 	.transceiver_cap	= IR_SIRMODE,
159 	.rx_channel		= OMAP_DMA_UART3_RX,
160 	.tx_channel		= OMAP_DMA_UART3_TX,
161 	.dest_start		= UART3_THR,
162 	.src_start		= UART3_RHR,
163 	.tx_trigger		= 0,
164 	.rx_trigger		= 0,
165 };
166 
167 static struct resource palmte_irda_resources[] = {
168 	[0]	= {
169 		.start	= INT_UART3,
170 		.end	= INT_UART3,
171 		.flags	= IORESOURCE_IRQ,
172 	},
173 };
174 
175 static struct platform_device palmte_irda_device = {
176 	.name		= "omapirda",
177 	.id		= -1,
178 	.dev		= {
179 		.platform_data	= &palmte_irda_config,
180 	},
181 	.num_resources	= ARRAY_SIZE(palmte_irda_resources),
182 	.resource	= palmte_irda_resources,
183 };
184 
185 static struct platform_device *palmte_devices[] __initdata = {
186 	&palmte_rom_device,
187 	&palmte_kp_device,
188 	&palmte_lcd_device,
189 	&palmte_backlight_device,
190 	&palmte_irda_device,
191 };
192 
193 static struct omap_usb_config palmte_usb_config __initdata = {
194 	.register_dev	= 1,	/* Mini-B only receptacle */
195 	.hmc_mode	= 0,
196 	.pins[0]	= 2,
197 };
198 
199 static struct omap_mmc_config palmte_mmc_config __initdata = {
200 	.mmc[0]		= {
201 		.enabled 	= 1,
202 		.wp_pin		= PALMTE_MMC_WP_GPIO,
203 		.power_pin	= PALMTE_MMC_POWER_GPIO,
204 		.switch_pin	= PALMTE_MMC_SWITCH_GPIO,
205 	},
206 };
207 
208 static struct omap_lcd_config palmte_lcd_config __initdata = {
209 	.ctrl_name	= "internal",
210 };
211 
212 static struct omap_uart_config palmte_uart_config __initdata = {
213 	.enabled_uarts = (1 << 0) | (1 << 1) | (0 << 2),
214 };
215 
216 static struct omap_mcbsp_reg_cfg palmte_mcbsp1_regs = {
217 	.spcr2	= FRST | GRST | XRST | XINTM(3),
218 	.xcr2	= XDATDLY(1) | XFIG,
219 	.xcr1	= XWDLEN1(OMAP_MCBSP_WORD_32),
220 	.pcr0	= SCLKME | FSXP | CLKXP,
221 };
222 
223 static struct omap_alsa_codec_config palmte_alsa_config = {
224 	.name			= "TSC2102 audio",
225 	.mcbsp_regs_alsa	= &palmte_mcbsp1_regs,
226 	.codec_configure_dev	= NULL,	/* tsc2102_configure, */
227 	.codec_set_samplerate	= NULL,	/* tsc2102_set_samplerate, */
228 	.codec_clock_setup	= NULL,	/* tsc2102_clock_setup, */
229 	.codec_clock_on		= NULL,	/* tsc2102_clock_on, */
230 	.codec_clock_off	= NULL,	/* tsc2102_clock_off, */
231 	.get_default_samplerate	= NULL,	/* tsc2102_get_default_samplerate, */
232 };
233 
234 #ifdef CONFIG_APM
235 /*
236  * Values measured in 10 minute intervals averaged over 10 samples.
237  * May differ slightly from device to device but should be accurate
238  * enough to give basic idea of battery life left and trigger
239  * potential alerts.
240  */
241 static const int palmte_battery_sample[] = {
242 	2194, 2157, 2138, 2120,
243 	2104, 2089, 2075, 2061,
244 	2048, 2038, 2026, 2016,
245 	2008, 1998, 1989, 1980,
246 	1970, 1958, 1945, 1928,
247 	1910, 1888, 1860, 1827,
248 	1791, 1751, 1709, 1656,
249 };
250 
251 #define INTERVAL		10
252 #define BATTERY_HIGH_TRESHOLD	66
253 #define BATTERY_LOW_TRESHOLD	33
254 
255 static void palmte_get_power_status(struct apm_power_info *info, int *battery)
256 {
257 	int charging, batt, hi, lo, mid;
258 
259 	charging = !omap_get_gpio_datain(PALMTE_DC_GPIO);
260 	batt = battery[0];
261 	if (charging)
262 		batt -= 60;
263 
264 	hi = ARRAY_SIZE(palmte_battery_sample);
265 	lo = 0;
266 
267 	info->battery_flag = 0;
268 	info->units = APM_UNITS_MINS;
269 
270 	if (batt > palmte_battery_sample[lo]) {
271 		info->battery_life = 100;
272 		info->time = INTERVAL * ARRAY_SIZE(palmte_battery_sample);
273 	} else if (batt <= palmte_battery_sample[hi - 1]) {
274 		info->battery_life = 0;
275 		info->time = 0;
276 	} else {
277 		while (hi > lo + 1) {
278 			mid = (hi + lo) >> 1;
279 			if (batt <= palmte_battery_sample[mid])
280 				lo = mid;
281 			else
282 				hi = mid;
283 		}
284 
285 		mid = palmte_battery_sample[lo] - palmte_battery_sample[hi];
286 		hi = palmte_battery_sample[lo] - batt;
287 		info->battery_life = 100 - (100 * lo + 100 * hi / mid) /
288 			ARRAY_SIZE(palmte_battery_sample);
289 		info->time = INTERVAL * (ARRAY_SIZE(palmte_battery_sample) -
290 				lo) - INTERVAL * hi / mid;
291 	}
292 
293 	if (charging) {
294 		info->ac_line_status = APM_AC_ONLINE;
295 		info->battery_status = APM_BATTERY_STATUS_CHARGING;
296 		info->battery_flag |= APM_BATTERY_FLAG_CHARGING;
297 	} else {
298 		info->ac_line_status = APM_AC_OFFLINE;
299 		if (info->battery_life > BATTERY_HIGH_TRESHOLD)
300 			info->battery_status = APM_BATTERY_STATUS_HIGH;
301 		else if (info->battery_life > BATTERY_LOW_TRESHOLD)
302 			info->battery_status = APM_BATTERY_STATUS_LOW;
303 		else
304 			info->battery_status = APM_BATTERY_STATUS_CRITICAL;
305 	}
306 
307 	if (info->battery_life > BATTERY_HIGH_TRESHOLD)
308 		info->battery_flag |= APM_BATTERY_FLAG_HIGH;
309 	else if (info->battery_life > BATTERY_LOW_TRESHOLD)
310 		info->battery_flag |= APM_BATTERY_FLAG_LOW;
311 	else
312 		info->battery_flag |= APM_BATTERY_FLAG_CRITICAL;
313 }
314 #else
315 #define palmte_get_power_status	NULL
316 #endif
317 
318 static struct tsc2102_config palmte_tsc2102_config = {
319 	.use_internal	= 0,
320 	.monitor	= TSC_BAT1 | TSC_AUX | TSC_TEMP,
321 	.temp_at25c	= { 2200, 2615 },
322 	.apm_report	= palmte_get_power_status,
323 	.alsa_config	= &palmte_alsa_config,
324 };
325 
326 static struct omap_board_config_kernel palmte_config[] __initdata = {
327 	{ OMAP_TAG_USB,		&palmte_usb_config },
328 	{ OMAP_TAG_MMC,		&palmte_mmc_config },
329 	{ OMAP_TAG_LCD,		&palmte_lcd_config },
330 	{ OMAP_TAG_UART,	&palmte_uart_config },
331 };
332 
333 static struct spi_board_info palmte_spi_info[] __initdata = {
334 	{
335 		.modalias	= "tsc2102",
336 		.bus_num	= 2,	/* uWire (officially) */
337 		.chip_select	= 0,	/* As opposed to 3 */
338 		.irq		= OMAP_GPIO_IRQ(PALMTE_PINTDAV_GPIO),
339 		.platform_data	= &palmte_tsc2102_config,
340 		.max_speed_hz	= 8000000,
341 	},
342 };
343 
344 static void palmte_headphones_detect(void *data, int state)
345 {
346 	if (state) {
347 		/* Headphones connected, disable speaker */
348 		omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 0);
349 		printk(KERN_INFO "PM: speaker off\n");
350 	} else {
351 		/* Headphones unplugged, re-enable speaker */
352 		omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 1);
353 		printk(KERN_INFO "PM: speaker on\n");
354 	}
355 }
356 
357 static void __init palmte_misc_gpio_setup(void)
358 {
359 	/* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
360 	if (omap_request_gpio(PALMTE_PINTDAV_GPIO)) {
361 		printk(KERN_ERR "Could not reserve PINTDAV GPIO!\n");
362 		return;
363 	}
364 	omap_set_gpio_direction(PALMTE_PINTDAV_GPIO, 1);
365 
366 	/* Set USB-or-DC-IN pin as input (unused) */
367 	if (omap_request_gpio(PALMTE_USB_OR_DC_GPIO)) {
368 		printk(KERN_ERR "Could not reserve cable signal GPIO!\n");
369 		return;
370 	}
371 	omap_set_gpio_direction(PALMTE_USB_OR_DC_GPIO, 1);
372 }
373 
374 static void __init omap_palmte_init(void)
375 {
376 	omap_board_config = palmte_config;
377 	omap_board_config_size = ARRAY_SIZE(palmte_config);
378 
379 	platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
380 
381 	spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
382 	palmte_misc_gpio_setup();
383 	omap_serial_init();
384 	omap_register_i2c_bus(1, 100, NULL, 0);
385 }
386 
387 static void __init omap_palmte_map_io(void)
388 {
389 	omap1_map_common_io();
390 }
391 
392 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
393 	.phys_io	= 0xfff00000,
394 	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
395 	.boot_params	= 0x10000100,
396 	.map_io		= omap_palmte_map_io,
397 	.init_irq	= omap_palmte_init_irq,
398 	.init_machine	= omap_palmte_init,
399 	.timer		= &omap_timer,
400 MACHINE_END
401