1/*
2 * Support for Sharp SL-C7xx PDAs
3 * Models: SL-C700 (Corgi), SL-C750 (Shepherd), SL-C760 (Husky)
4 *
5 * Copyright (c) 2004-2005 Richard Purdie
6 *
7 * Based on Sharp's 2.4 kernel patches/lubbock.c
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 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/major.h>
19#include <linux/fs.h>
20#include <linux/interrupt.h>
21#include <linux/mmc/host.h>
22#include <linux/pm.h>
23
24#include <asm/setup.h>
25#include <asm/memory.h>
26#include <asm/mach-types.h>
27#include <asm/hardware.h>
28#include <asm/irq.h>
29#include <asm/io.h>
30#include <asm/system.h>
31
32#include <asm/mach/arch.h>
33#include <asm/mach/map.h>
34#include <asm/mach/irq.h>
35
36#include <asm/arch/pxa-regs.h>
37#include <asm/arch/irda.h>
38#include <asm/arch/mmc.h>
39#include <asm/arch/udc.h>
40#include <asm/arch/corgi.h>
41#include <asm/arch/sharpsl.h>
42
43#include <asm/mach/sharpsl_param.h>
44#include <asm/hardware/scoop.h>
45
46#include "generic.h"
47#include "sharpsl.h"
48
49
50/*
51 * Corgi SCOOP Device
52 */
53static struct resource corgi_scoop_resources[] = {
54	[0] = {
55		.start		= 0x10800000,
56		.end		= 0x10800fff,
57		.flags		= IORESOURCE_MEM,
58	},
59};
60
61static struct scoop_config corgi_scoop_setup = {
62	.io_dir 	= CORGI_SCOOP_IO_DIR,
63	.io_out		= CORGI_SCOOP_IO_OUT,
64};
65
66struct platform_device corgiscoop_device = {
67	.name		= "sharp-scoop",
68	.id		= -1,
69	.dev		= {
70 		.platform_data	= &corgi_scoop_setup,
71	},
72	.num_resources	= ARRAY_SIZE(corgi_scoop_resources),
73	.resource	= corgi_scoop_resources,
74};
75
76static void corgi_pcmcia_init(void)
77{
78	/* Setup default state of GPIO outputs
79	   before we enable them as outputs. */
80	GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
81		GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) |
82		GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) |
83		GPIO_bit(GPIO53_nPCE_2);
84
85	pxa_gpio_mode(GPIO48_nPOE_MD);
86	pxa_gpio_mode(GPIO49_nPWE_MD);
87	pxa_gpio_mode(GPIO50_nPIOR_MD);
88	pxa_gpio_mode(GPIO51_nPIOW_MD);
89	pxa_gpio_mode(GPIO55_nPREG_MD);
90	pxa_gpio_mode(GPIO56_nPWAIT_MD);
91	pxa_gpio_mode(GPIO57_nIOIS16_MD);
92	pxa_gpio_mode(GPIO52_nPCE_1_MD);
93	pxa_gpio_mode(GPIO53_nPCE_2_MD);
94	pxa_gpio_mode(GPIO54_pSKTSEL_MD);
95}
96
97static struct scoop_pcmcia_dev corgi_pcmcia_scoop[] = {
98{
99	.dev        = &corgiscoop_device.dev,
100	.irq        = CORGI_IRQ_GPIO_CF_IRQ,
101	.cd_irq     = CORGI_IRQ_GPIO_CF_CD,
102	.cd_irq_str = "PCMCIA0 CD",
103},
104};
105
106static struct scoop_pcmcia_config corgi_pcmcia_config = {
107	.devs         = &corgi_pcmcia_scoop[0],
108	.num_devs     = 1,
109	.pcmcia_init  = corgi_pcmcia_init,
110};
111
112EXPORT_SYMBOL(corgiscoop_device);
113
114
115/*
116 * Corgi SSP Device
117 *
118 * Set the parent as the scoop device because a lot of SSP devices
119 * also use scoop functions and this makes the power up/down order
120 * work correctly.
121 */
122struct platform_device corgissp_device = {
123	.name		= "corgi-ssp",
124	.dev		= {
125 		.parent = &corgiscoop_device.dev,
126	},
127	.id		= -1,
128};
129
130struct corgissp_machinfo corgi_ssp_machinfo = {
131	.port		= 1,
132	.cs_lcdcon	= CORGI_GPIO_LCDCON_CS,
133	.cs_ads7846	= CORGI_GPIO_ADS7846_CS,
134	.cs_max1111	= CORGI_GPIO_MAX1111_CS,
135	.clk_lcdcon	= 76,
136	.clk_ads7846	= 2,
137	.clk_max1111	= 8,
138};
139
140
141/*
142 * Corgi Backlight Device
143 */
144static struct corgibl_machinfo corgi_bl_machinfo = {
145	.max_intensity = 0x2f,
146	.default_intensity = 0x1f,
147	.limit_mask = 0x0b,
148	.set_bl_intensity = corgi_bl_set_intensity,
149};
150
151static struct platform_device corgibl_device = {
152	.name		= "corgi-bl",
153	.dev		= {
154 		.parent = &corgifb_device.dev,
155		.platform_data	= &corgi_bl_machinfo,
156	},
157	.id		= -1,
158};
159
160
161/*
162 * Corgi Keyboard Device
163 */
164static struct platform_device corgikbd_device = {
165	.name		= "corgi-keyboard",
166	.id		= -1,
167};
168
169
170/*
171 * Corgi LEDs
172 */
173static struct platform_device corgiled_device = {
174	.name		= "corgi-led",
175	.id		= -1,
176};
177
178/*
179 * Corgi Touch Screen Device
180 */
181static struct resource corgits_resources[] = {
182	[0] = {
183		.start		= CORGI_IRQ_GPIO_TP_INT,
184		.end		= CORGI_IRQ_GPIO_TP_INT,
185		.flags		= IORESOURCE_IRQ,
186	},
187};
188
189static struct corgits_machinfo  corgi_ts_machinfo = {
190	.get_hsync_len   = corgi_get_hsync_len,
191	.put_hsync       = corgi_put_hsync,
192	.wait_hsync      = corgi_wait_hsync,
193};
194
195static struct platform_device corgits_device = {
196	.name		= "corgi-ts",
197	.dev		= {
198 		.parent = &corgissp_device.dev,
199		.platform_data	= &corgi_ts_machinfo,
200	},
201	.id		= -1,
202	.num_resources	= ARRAY_SIZE(corgits_resources),
203	.resource	= corgits_resources,
204};
205
206
207/*
208 * MMC/SD Device
209 *
210 * The card detect interrupt isn't debounced so we delay it by 250ms
211 * to give the card a chance to fully insert/eject.
212 */
213static struct pxamci_platform_data corgi_mci_platform_data;
214
215static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, void *data)
216{
217	int err;
218
219	/* setup GPIO for PXA25x MMC controller	*/
220	pxa_gpio_mode(GPIO6_MMCCLK_MD);
221	pxa_gpio_mode(GPIO8_MMCCS0_MD);
222	pxa_gpio_mode(CORGI_GPIO_nSD_DETECT | GPIO_IN);
223	pxa_gpio_mode(CORGI_GPIO_SD_PWR | GPIO_OUT);
224
225	corgi_mci_platform_data.detect_delay = msecs_to_jiffies(250);
226
227	err = request_irq(CORGI_IRQ_GPIO_nSD_DETECT, corgi_detect_int,
228			  IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
229			  "MMC card detect", data);
230	if (err) {
231		printk(KERN_ERR "corgi_mci_init: MMC/SD: can't request MMC card detect IRQ\n");
232		return -1;
233	}
234
235	return 0;
236}
237
238static void corgi_mci_setpower(struct device *dev, unsigned int vdd)
239{
240	struct pxamci_platform_data* p_d = dev->platform_data;
241
242	if (( 1 << vdd) & p_d->ocr_mask)
243		GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
244	else
245		GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR);
246}
247
248static int corgi_mci_get_ro(struct device *dev)
249{
250	return GPLR(CORGI_GPIO_nSD_WP) & GPIO_bit(CORGI_GPIO_nSD_WP);
251}
252
253static void corgi_mci_exit(struct device *dev, void *data)
254{
255	free_irq(CORGI_IRQ_GPIO_nSD_DETECT, data);
256}
257
258static struct pxamci_platform_data corgi_mci_platform_data = {
259	.ocr_mask	= MMC_VDD_32_33|MMC_VDD_33_34,
260	.init 		= corgi_mci_init,
261	.get_ro		= corgi_mci_get_ro,
262	.setpower 	= corgi_mci_setpower,
263	.exit		= corgi_mci_exit,
264};
265
266
267/*
268 * Irda
269 */
270static void corgi_irda_transceiver_mode(struct device *dev, int mode)
271{
272	if (mode & IR_OFF)
273		GPSR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
274	else
275		GPCR(CORGI_GPIO_IR_ON) = GPIO_bit(CORGI_GPIO_IR_ON);
276}
277
278static struct pxaficp_platform_data corgi_ficp_platform_data = {
279	.transceiver_cap  = IR_SIRMODE | IR_OFF,
280	.transceiver_mode = corgi_irda_transceiver_mode,
281};
282
283
284/*
285 * USB Device Controller
286 */
287static struct pxa2xx_udc_mach_info udc_info __initdata = {
288	/* no connect GPIO; corgi can't tell connection status */
289	.gpio_pullup		= CORGI_GPIO_USB_PULLUP,
290};
291
292
293static struct platform_device *devices[] __initdata = {
294	&corgiscoop_device,
295	&corgissp_device,
296	&corgifb_device,
297	&corgikbd_device,
298	&corgibl_device,
299	&corgits_device,
300	&corgiled_device,
301};
302
303static void corgi_poweroff(void)
304{
305	RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
306
307	if (!machine_is_corgi())
308		/* Green LED off tells the bootloader to halt */
309		reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
310	arm_machine_restart('h');
311}
312
313static void corgi_restart(char mode)
314{
315	RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
316
317	if (!machine_is_corgi())
318		/* Green LED on tells the bootloader to reboot */
319		set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN);
320	arm_machine_restart('h');
321}
322
323static void __init corgi_init(void)
324{
325	pm_power_off = corgi_poweroff;
326	arm_pm_restart = corgi_restart;
327
328	/* setup sleep mode values */
329	PWER  = 0x00000002;
330	PFER  = 0x00000000;
331	PRER  = 0x00000002;
332	PGSR0 = 0x0158C000;
333	PGSR1 = 0x00FF0080;
334	PGSR2 = 0x0001C004;
335	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
336	PCFR |= PCFR_OPDE;
337
338	corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
339
340	pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
341	pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
342
343 	pxa_set_udc_info(&udc_info);
344	pxa_set_mci_info(&corgi_mci_platform_data);
345	pxa_set_ficp_info(&corgi_ficp_platform_data);
346
347	platform_scoop_config = &corgi_pcmcia_config;
348
349	platform_add_devices(devices, ARRAY_SIZE(devices));
350}
351
352static void __init fixup_corgi(struct machine_desc *desc,
353		struct tag *tags, char **cmdline, struct meminfo *mi)
354{
355	sharpsl_save_param();
356	mi->nr_banks=1;
357	mi->bank[0].start = 0xa0000000;
358	mi->bank[0].node = 0;
359	if (machine_is_corgi())
360		mi->bank[0].size = (32*1024*1024);
361	else
362		mi->bank[0].size = (64*1024*1024);
363}
364
365#ifdef CONFIG_MACH_CORGI
366MACHINE_START(CORGI, "SHARP Corgi")
367	.phys_io	= 0x40000000,
368	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
369	.fixup		= fixup_corgi,
370	.map_io		= pxa_map_io,
371	.init_irq	= pxa_init_irq,
372	.init_machine	= corgi_init,
373	.timer		= &pxa_timer,
374MACHINE_END
375#endif
376
377#ifdef CONFIG_MACH_SHEPHERD
378MACHINE_START(SHEPHERD, "SHARP Shepherd")
379	.phys_io	= 0x40000000,
380	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
381	.fixup		= fixup_corgi,
382	.map_io		= pxa_map_io,
383	.init_irq	= pxa_init_irq,
384	.init_machine	= corgi_init,
385	.timer		= &pxa_timer,
386MACHINE_END
387#endif
388
389#ifdef CONFIG_MACH_HUSKY
390MACHINE_START(HUSKY, "SHARP Husky")
391	.phys_io	= 0x40000000,
392	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
393	.fixup		= fixup_corgi,
394	.map_io		= pxa_map_io,
395	.init_irq	= pxa_init_irq,
396	.init_machine	= corgi_init,
397	.timer		= &pxa_timer,
398MACHINE_END
399#endif
400