1/*
2 * linux/arch/arm/mach-sa1100/collie.c
3 *
4 * May be copied or modified under the terms of the GNU General Public
5 * License.  See linux/COPYING for more information.
6 *
7 * This file contains all Collie-specific tweaks.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * ChangeLog:
14 *  2006 Pavel Machek <pavel@ucw.cz>
15 *  03-06-2004 John Lenz <lenz@cs.wisc.edu>
16 *  06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
17 *  04-16-2001 Lineo Japan,Inc. ...
18 */
19
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/tty.h>
23#include <linux/delay.h>
24#include <linux/platform_data/sa11x0-serial.h>
25#include <linux/platform_device.h>
26#include <linux/mfd/ucb1x00.h>
27#include <linux/mtd/mtd.h>
28#include <linux/mtd/partitions.h>
29#include <linux/timer.h>
30#include <linux/gpio_keys.h>
31#include <linux/input.h>
32#include <linux/gpio.h>
33#include <linux/gpio/machine.h>
34#include <linux/power/gpio-charger.h>
35
36#include <video/sa1100fb.h>
37
38#include <mach/hardware.h>
39#include <asm/mach-types.h>
40#include <asm/page.h>
41#include <asm/setup.h>
42#include <mach/collie.h>
43
44#include <asm/mach/arch.h>
45#include <asm/mach/flash.h>
46#include <asm/mach/map.h>
47
48#include <asm/hardware/scoop.h>
49#include <asm/mach/sharpsl_param.h>
50#include <asm/hardware/locomo.h>
51#include <linux/platform_data/mfd-mcp-sa11x0.h>
52#include <mach/irqs.h>
53
54#include "generic.h"
55
56static struct resource collie_scoop_resources[] = {
57	[0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
58};
59
60static struct scoop_config collie_scoop_setup = {
61	.io_dir 	= COLLIE_SCOOP_IO_DIR,
62	.io_out		= COLLIE_SCOOP_IO_OUT,
63	.gpio_base	= COLLIE_SCOOP_GPIO_BASE,
64};
65
66struct platform_device colliescoop_device = {
67	.name		= "sharp-scoop",
68	.id		= -1,
69	.dev		= {
70 		.platform_data	= &collie_scoop_setup,
71	},
72	.num_resources	= ARRAY_SIZE(collie_scoop_resources),
73	.resource	= collie_scoop_resources,
74};
75
76static struct scoop_pcmcia_dev collie_pcmcia_scoop[] = {
77	{
78	.dev		= &colliescoop_device.dev,
79	.irq		= COLLIE_IRQ_GPIO_CF_IRQ,
80	.cd_irq		= COLLIE_IRQ_GPIO_CF_CD,
81	.cd_irq_str	= "PCMCIA0 CD",
82	},
83};
84
85static struct scoop_pcmcia_config collie_pcmcia_config = {
86	.devs		= &collie_pcmcia_scoop[0],
87	.num_devs	= 1,
88};
89
90static struct ucb1x00_plat_data collie_ucb1x00_data = {
91	.gpio_base	= COLLIE_TC35143_GPIO_BASE,
92};
93
94static struct mcp_plat_data collie_mcp_data = {
95	.mccr0		= MCCR0_ADM | MCCR0_ExtClk,
96	.sclk_rate	= 9216000,
97	.codec_pdata	= &collie_ucb1x00_data,
98};
99
100/* Battery management GPIOs */
101static struct gpiod_lookup_table collie_battery_gpiod_table = {
102	/* the MCP codec mcp0 has the ucb1x00 as attached device */
103	.dev_id = "ucb1x00",
104	.table = {
105		/* This is found on the main GPIO on the SA1100 */
106		GPIO_LOOKUP("gpio", COLLIE_GPIO_CO,
107			    "main battery full", GPIO_ACTIVE_HIGH),
108		GPIO_LOOKUP("gpio", COLLIE_GPIO_MAIN_BAT_LOW,
109			    "main battery low", GPIO_ACTIVE_HIGH),
110		/*
111		 * This is GPIO 0 on the Scoop expander, which is registered
112		 * from common/scoop.c with this gpio chip label.
113		 */
114		GPIO_LOOKUP("sharp-scoop", 0,
115			    "main charge on", GPIO_ACTIVE_HIGH),
116		{ },
117	},
118};
119
120/*
121 * Collie AC IN
122 */
123static struct gpiod_lookup_table collie_power_gpiod_table = {
124	.dev_id = "gpio-charger",
125	.table = {
126		GPIO_LOOKUP("gpio", COLLIE_GPIO_AC_IN,
127			    NULL, GPIO_ACTIVE_HIGH),
128		{ },
129	},
130};
131
132static char *collie_ac_supplied_to[] = {
133	"main-battery",
134	"backup-battery",
135};
136
137static struct gpio_charger_platform_data collie_power_data = {
138	.name			= "charger",
139	.type			= POWER_SUPPLY_TYPE_MAINS,
140	.supplied_to		= collie_ac_supplied_to,
141	.num_supplicants	= ARRAY_SIZE(collie_ac_supplied_to),
142};
143
144static struct platform_device collie_power_device = {
145	.name			= "gpio-charger",
146	.id			= -1,
147	.dev.platform_data	= &collie_power_data,
148};
149
150#ifdef CONFIG_SHARP_LOCOMO
151/*
152 * low-level UART features.
153 */
154struct platform_device collie_locomo_device;
155
156static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
157{
158	if (mctrl & TIOCM_RTS)
159		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
160	else
161		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
162
163	if (mctrl & TIOCM_DTR)
164		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
165	else
166		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
167}
168
169static u_int collie_uart_get_mctrl(struct uart_port *port)
170{
171	int ret = TIOCM_CD;
172	unsigned int r;
173
174	r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
175	if (r == -ENODEV)
176		return ret;
177	if (r & LOCOMO_GPIO_CTS)
178		ret |= TIOCM_CTS;
179	if (r & LOCOMO_GPIO_DSR)
180		ret |= TIOCM_DSR;
181
182	return ret;
183}
184
185static struct sa1100_port_fns collie_port_fns __initdata = {
186	.set_mctrl	= collie_uart_set_mctrl,
187	.get_mctrl	= collie_uart_get_mctrl,
188};
189
190static int collie_uart_probe(struct locomo_dev *dev)
191{
192	return 0;
193}
194
195static struct locomo_driver collie_uart_driver = {
196	.drv = {
197		.name = "collie_uart",
198	},
199	.devid	= LOCOMO_DEVID_UART,
200	.probe	= collie_uart_probe,
201};
202
203static int __init collie_uart_init(void)
204{
205	return locomo_driver_register(&collie_uart_driver);
206}
207device_initcall(collie_uart_init);
208
209#endif
210
211
212static struct resource locomo_resources[] = {
213	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
214	[1] = DEFINE_RES_IRQ(IRQ_GPIO25),
215};
216
217static struct locomo_platform_data locomo_info = {
218	.irq_base	= IRQ_BOARD_START,
219};
220
221struct platform_device collie_locomo_device = {
222	.name		= "locomo",
223	.id		= 0,
224	.dev		= {
225		.platform_data	= &locomo_info,
226	},
227	.num_resources	= ARRAY_SIZE(locomo_resources),
228	.resource	= locomo_resources,
229};
230
231static struct gpio_keys_button collie_gpio_keys[] = {
232	{
233		.type	= EV_PWR,
234		.code	= KEY_RESERVED,
235		.gpio	= COLLIE_GPIO_ON_KEY,
236		.desc	= "On key",
237		.wakeup	= 1,
238		.active_low = 1,
239	},
240	{
241		.type	= EV_PWR,
242		.code	= KEY_WAKEUP,
243		.gpio	= COLLIE_GPIO_WAKEUP,
244		.desc	= "Sync",
245		.wakeup = 1,
246		.active_low = 1,
247	},
248};
249
250static struct gpio_keys_platform_data collie_gpio_keys_data = {
251	.buttons	= collie_gpio_keys,
252	.nbuttons	= ARRAY_SIZE(collie_gpio_keys),
253};
254
255static struct platform_device collie_gpio_keys_device = {
256	.name	= "gpio-keys",
257	.id	= -1,
258	.dev	= {
259		.platform_data = &collie_gpio_keys_data,
260	},
261};
262
263static struct platform_device *devices[] __initdata = {
264	&collie_locomo_device,
265	&colliescoop_device,
266	&collie_power_device,
267	&collie_gpio_keys_device,
268};
269
270static struct mtd_partition collie_partitions[] = {
271	{
272		.name		= "bootloader",
273		.offset 	= 0,
274		.size		= 0x000C0000,
275		.mask_flags	= MTD_WRITEABLE
276	}, {
277		.name		= "kernel",
278		.offset 	= MTDPART_OFS_APPEND,
279		.size		= 0x00100000,
280	}, {
281		.name		= "rootfs",
282		.offset 	= MTDPART_OFS_APPEND,
283		.size		= 0x00e20000,
284	}, {
285		.name		= "bootblock",
286		.offset		= MTDPART_OFS_APPEND,
287		.size		= 0x00020000,
288		.mask_flags	= MTD_WRITEABLE
289	}
290};
291
292static int collie_flash_init(void)
293{
294	int rc = gpio_request(COLLIE_GPIO_VPEN, "flash Vpp enable");
295	if (rc)
296		return rc;
297
298	rc = gpio_direction_output(COLLIE_GPIO_VPEN, 1);
299	if (rc)
300		gpio_free(COLLIE_GPIO_VPEN);
301
302	return rc;
303}
304
305static void collie_set_vpp(int vpp)
306{
307	gpio_set_value(COLLIE_GPIO_VPEN, vpp);
308}
309
310static void collie_flash_exit(void)
311{
312	gpio_free(COLLIE_GPIO_VPEN);
313}
314
315static struct flash_platform_data collie_flash_data = {
316	.map_name	= "cfi_probe",
317	.init		= collie_flash_init,
318	.set_vpp	= collie_set_vpp,
319	.exit		= collie_flash_exit,
320	.parts		= collie_partitions,
321	.nr_parts	= ARRAY_SIZE(collie_partitions),
322};
323
324static struct resource collie_flash_resources[] = {
325	DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
326};
327
328static struct sa1100fb_mach_info collie_lcd_info = {
329	.pixclock	= 171521,	.bpp		= 16,
330	.xres		= 320,		.yres		= 240,
331
332	.hsync_len	= 5,		.vsync_len	= 1,
333	.left_margin	= 11,		.upper_margin	= 2,
334	.right_margin	= 30,		.lower_margin	= 0,
335
336	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
337
338	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
339	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
340
341#ifdef CONFIG_BACKLIGHT_LOCOMO
342	.lcd_power	= locomolcd_power
343#endif
344};
345
346static void __init collie_init(void)
347{
348	int ret = 0;
349
350	/* cpu initialize */
351	GAFR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK |
352		GPIO_MCP_CLK | GPIO_32_768kHz;
353
354	GPDR = GPIO_LDD8 | GPIO_LDD9 | GPIO_LDD10 | GPIO_LDD11 | GPIO_LDD12 |
355		GPIO_LDD13 | GPIO_LDD14 | GPIO_LDD15 | GPIO_SSP_TXD |
356		GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SDLC_SCLK |
357		_COLLIE_GPIO_UCB1x00_RESET | _COLLIE_GPIO_nMIC_ON |
358		_COLLIE_GPIO_nREMOCON_ON | GPIO_32_768kHz;
359
360	PPDR = PPC_LDD0 | PPC_LDD1 | PPC_LDD2 | PPC_LDD3 | PPC_LDD4 | PPC_LDD5 |
361		PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS |
362		PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM;
363
364	PWER = 0;
365
366	PGSR = _COLLIE_GPIO_nREMOCON_ON;
367
368	PSDR = PPC_RXD1 | PPC_RXD2 | PPC_RXD3 | PPC_RXD4;
369
370	PCFR = PCFR_OPDE;
371
372	GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
373
374	sa11x0_ppc_configure_mcp();
375
376
377	platform_scoop_config = &collie_pcmcia_config;
378
379	gpiod_add_lookup_table(&collie_power_gpiod_table);
380	gpiod_add_lookup_table(&collie_battery_gpiod_table);
381
382	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
383	if (ret) {
384		printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
385	}
386
387	sa11x0_register_lcd(&collie_lcd_info);
388	sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
389			    ARRAY_SIZE(collie_flash_resources));
390	sa11x0_register_mcp(&collie_mcp_data);
391
392	sharpsl_save_param();
393}
394
395static struct map_desc collie_io_desc[] __initdata = {
396	{	/* 32M main flash (cs0) */
397		.virtual	= 0xe8000000,
398		.pfn		= __phys_to_pfn(0x00000000),
399		.length		= 0x02000000,
400		.type		= MT_DEVICE
401	}, {	/* 32M boot flash (cs1) */
402		.virtual	= 0xea000000,
403		.pfn		= __phys_to_pfn(0x08000000),
404		.length		= 0x02000000,
405		.type		= MT_DEVICE
406	}
407};
408
409static void __init collie_map_io(void)
410{
411	sa1100_map_io();
412	iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
413
414#ifdef CONFIG_SHARP_LOCOMO
415	sa1100_register_uart_fns(&collie_port_fns);
416#endif
417	sa1100_register_uart(0, 3);
418	sa1100_register_uart(1, 1);
419}
420
421MACHINE_START(COLLIE, "Sharp-Collie")
422	.map_io		= collie_map_io,
423	.nr_irqs	= SA1100_NR_IRQS,
424	.init_irq	= sa1100_init_irq,
425	.init_time	= sa1100_timer_init,
426	.init_machine	= collie_init,
427	.init_late	= sa11x0_init_late,
428	.restart	= sa11x0_restart,
429MACHINE_END
430