xref: /OK3568_Linux_fs/kernel/arch/arm/mach-pxa/idp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/arch/arm/mach-pxa/idp.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  2001-09-13: Cliff Brake <cbrake@accelent.com>
8*4882a593Smuzhiyun  *              Initial code
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *  2005-02-15: Cliff Brake <cliff.brake@gmail.com>
11*4882a593Smuzhiyun  *  		<http://www.vibren.com> <http://bec-systems.com>
12*4882a593Smuzhiyun  *              Updated for 2.6 kernel
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/irq.h>
18*4882a593Smuzhiyun #include <linux/leds.h>
19*4882a593Smuzhiyun #include <linux/platform_device.h>
20*4882a593Smuzhiyun #include <linux/fb.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <asm/setup.h>
23*4882a593Smuzhiyun #include <asm/memory.h>
24*4882a593Smuzhiyun #include <asm/mach-types.h>
25*4882a593Smuzhiyun #include <mach/hardware.h>
26*4882a593Smuzhiyun #include <asm/irq.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <asm/mach/arch.h>
29*4882a593Smuzhiyun #include <asm/mach/map.h>
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #include "pxa25x.h"
32*4882a593Smuzhiyun #include "idp.h"
33*4882a593Smuzhiyun #include <linux/platform_data/video-pxafb.h>
34*4882a593Smuzhiyun #include <mach/bitfield.h>
35*4882a593Smuzhiyun #include <linux/platform_data/mmc-pxamci.h>
36*4882a593Smuzhiyun #include <linux/smc91x.h>
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "generic.h"
39*4882a593Smuzhiyun #include "devices.h"
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /* TODO:
42*4882a593Smuzhiyun  * - add pxa2xx_audio_ops_t device structure
43*4882a593Smuzhiyun  * - Ethernet interrupt
44*4882a593Smuzhiyun  */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static unsigned long idp_pin_config[] __initdata = {
47*4882a593Smuzhiyun 	/* LCD */
48*4882a593Smuzhiyun 	GPIOxx_LCD_DSTN_16BPP,
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	/* BTUART */
51*4882a593Smuzhiyun 	GPIO42_BTUART_RXD,
52*4882a593Smuzhiyun 	GPIO43_BTUART_TXD,
53*4882a593Smuzhiyun 	GPIO44_BTUART_CTS,
54*4882a593Smuzhiyun 	GPIO45_BTUART_RTS,
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	/* STUART */
57*4882a593Smuzhiyun 	GPIO46_STUART_RXD,
58*4882a593Smuzhiyun 	GPIO47_STUART_TXD,
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	/* MMC */
61*4882a593Smuzhiyun 	GPIO6_MMC_CLK,
62*4882a593Smuzhiyun 	GPIO8_MMC_CS0,
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	/* Ethernet */
65*4882a593Smuzhiyun 	GPIO33_nCS_5,	/* Ethernet CS */
66*4882a593Smuzhiyun 	GPIO4_GPIO,	/* Ethernet IRQ */
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun static struct resource smc91x_resources[] = {
70*4882a593Smuzhiyun 	[0] = {
71*4882a593Smuzhiyun 		.start	= (IDP_ETH_PHYS + 0x300),
72*4882a593Smuzhiyun 		.end	= (IDP_ETH_PHYS + 0xfffff),
73*4882a593Smuzhiyun 		.flags	= IORESOURCE_MEM,
74*4882a593Smuzhiyun 	},
75*4882a593Smuzhiyun 	[1] = {
76*4882a593Smuzhiyun 		.start	= PXA_GPIO_TO_IRQ(4),
77*4882a593Smuzhiyun 		.end	= PXA_GPIO_TO_IRQ(4),
78*4882a593Smuzhiyun 		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
79*4882a593Smuzhiyun 	}
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static struct smc91x_platdata smc91x_platdata = {
83*4882a593Smuzhiyun 	.flags = SMC91X_USE_8BIT | SMC91X_USE_16BIT | SMC91X_USE_32BIT |
84*4882a593Smuzhiyun 		 SMC91X_USE_DMA | SMC91X_NOWAIT,
85*4882a593Smuzhiyun 	.pxa_u16_align4 = true,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun static struct platform_device smc91x_device = {
89*4882a593Smuzhiyun 	.name		= "smc91x",
90*4882a593Smuzhiyun 	.id		= 0,
91*4882a593Smuzhiyun 	.num_resources	= ARRAY_SIZE(smc91x_resources),
92*4882a593Smuzhiyun 	.resource	= smc91x_resources,
93*4882a593Smuzhiyun 	.dev.platform_data = &smc91x_platdata,
94*4882a593Smuzhiyun };
95*4882a593Smuzhiyun 
idp_backlight_power(int on)96*4882a593Smuzhiyun static void idp_backlight_power(int on)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	if (on) {
99*4882a593Smuzhiyun 		IDP_CPLD_LCD |= (1<<1);
100*4882a593Smuzhiyun 	} else {
101*4882a593Smuzhiyun 		IDP_CPLD_LCD &= ~(1<<1);
102*4882a593Smuzhiyun 	}
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
idp_vlcd(int on)105*4882a593Smuzhiyun static void idp_vlcd(int on)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	if (on) {
108*4882a593Smuzhiyun 		IDP_CPLD_LCD |= (1<<2);
109*4882a593Smuzhiyun 	} else {
110*4882a593Smuzhiyun 		IDP_CPLD_LCD &= ~(1<<2);
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
idp_lcd_power(int on,struct fb_var_screeninfo * var)114*4882a593Smuzhiyun static void idp_lcd_power(int on, struct fb_var_screeninfo *var)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	if (on) {
117*4882a593Smuzhiyun 		IDP_CPLD_LCD |= (1<<0);
118*4882a593Smuzhiyun 	} else {
119*4882a593Smuzhiyun 		IDP_CPLD_LCD &= ~(1<<0);
120*4882a593Smuzhiyun 	}
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* call idp_vlcd for now as core driver does not support
123*4882a593Smuzhiyun 	 * both power and vlcd hooks.  Note, this is not technically
124*4882a593Smuzhiyun 	 * the correct sequence, but seems to work.  Disclaimer:
125*4882a593Smuzhiyun 	 * this may eventually damage the display.
126*4882a593Smuzhiyun 	 */
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	idp_vlcd(on);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun static struct pxafb_mode_info sharp_lm8v31_mode = {
132*4882a593Smuzhiyun 	.pixclock	= 270000,
133*4882a593Smuzhiyun 	.xres		= 640,
134*4882a593Smuzhiyun 	.yres		= 480,
135*4882a593Smuzhiyun 	.bpp		= 16,
136*4882a593Smuzhiyun 	.hsync_len	= 1,
137*4882a593Smuzhiyun 	.left_margin	= 3,
138*4882a593Smuzhiyun 	.right_margin	= 3,
139*4882a593Smuzhiyun 	.vsync_len	= 1,
140*4882a593Smuzhiyun 	.upper_margin	= 0,
141*4882a593Smuzhiyun 	.lower_margin	= 0,
142*4882a593Smuzhiyun 	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
143*4882a593Smuzhiyun 	.cmap_greyscale	= 0,
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun static struct pxafb_mach_info sharp_lm8v31 = {
147*4882a593Smuzhiyun 	.modes          = &sharp_lm8v31_mode,
148*4882a593Smuzhiyun 	.num_modes      = 1,
149*4882a593Smuzhiyun 	.cmap_inverse	= 0,
150*4882a593Smuzhiyun 	.cmap_static	= 0,
151*4882a593Smuzhiyun 	.lcd_conn	= LCD_COLOR_DSTN_16BPP | LCD_PCLK_EDGE_FALL |
152*4882a593Smuzhiyun 			  LCD_AC_BIAS_FREQ(255),
153*4882a593Smuzhiyun 	.pxafb_backlight_power = &idp_backlight_power,
154*4882a593Smuzhiyun 	.pxafb_lcd_power = &idp_lcd_power
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun static struct pxamci_platform_data idp_mci_platform_data = {
158*4882a593Smuzhiyun 	.ocr_mask		= MMC_VDD_32_33|MMC_VDD_33_34,
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun 
idp_init(void)161*4882a593Smuzhiyun static void __init idp_init(void)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	printk("idp_init()\n");
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	pxa2xx_mfp_config(ARRAY_AND_SIZE(idp_pin_config));
166*4882a593Smuzhiyun 	pxa_set_ffuart_info(NULL);
167*4882a593Smuzhiyun 	pxa_set_btuart_info(NULL);
168*4882a593Smuzhiyun 	pxa_set_stuart_info(NULL);
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	platform_device_register(&smc91x_device);
171*4882a593Smuzhiyun 	//platform_device_register(&mst_audio_device);
172*4882a593Smuzhiyun 	pxa_set_fb_info(NULL, &sharp_lm8v31);
173*4882a593Smuzhiyun 	pxa_set_mci_info(&idp_mci_platform_data);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun static struct map_desc idp_io_desc[] __initdata = {
177*4882a593Smuzhiyun   	{
178*4882a593Smuzhiyun 		.virtual	=  IDP_COREVOLT_VIRT,
179*4882a593Smuzhiyun 		.pfn		= __phys_to_pfn(IDP_COREVOLT_PHYS),
180*4882a593Smuzhiyun 		.length		= IDP_COREVOLT_SIZE,
181*4882a593Smuzhiyun 		.type		= MT_DEVICE
182*4882a593Smuzhiyun 	}, {
183*4882a593Smuzhiyun 		.virtual	=  IDP_CPLD_VIRT,
184*4882a593Smuzhiyun 		.pfn		= __phys_to_pfn(IDP_CPLD_PHYS),
185*4882a593Smuzhiyun 		.length		= IDP_CPLD_SIZE,
186*4882a593Smuzhiyun 		.type		= MT_DEVICE
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun 
idp_map_io(void)190*4882a593Smuzhiyun static void __init idp_map_io(void)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	pxa25x_map_io();
193*4882a593Smuzhiyun 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun /* LEDs */
197*4882a593Smuzhiyun #if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
198*4882a593Smuzhiyun struct idp_led {
199*4882a593Smuzhiyun 	struct led_classdev     cdev;
200*4882a593Smuzhiyun 	u8                      mask;
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun  * The triggers lines up below will only be used if the
205*4882a593Smuzhiyun  * LED triggers are compiled in.
206*4882a593Smuzhiyun  */
207*4882a593Smuzhiyun static const struct {
208*4882a593Smuzhiyun 	const char *name;
209*4882a593Smuzhiyun 	const char *trigger;
210*4882a593Smuzhiyun } idp_leds[] = {
211*4882a593Smuzhiyun 	{ "idp:green", "heartbeat", },
212*4882a593Smuzhiyun 	{ "idp:red", "cpu0", },
213*4882a593Smuzhiyun };
214*4882a593Smuzhiyun 
idp_led_set(struct led_classdev * cdev,enum led_brightness b)215*4882a593Smuzhiyun static void idp_led_set(struct led_classdev *cdev,
216*4882a593Smuzhiyun 		enum led_brightness b)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct idp_led *led = container_of(cdev,
219*4882a593Smuzhiyun 			struct idp_led, cdev);
220*4882a593Smuzhiyun 	u32 reg = IDP_CPLD_LED_CONTROL;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (b != LED_OFF)
223*4882a593Smuzhiyun 		reg &= ~led->mask;
224*4882a593Smuzhiyun 	else
225*4882a593Smuzhiyun 		reg |= led->mask;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	IDP_CPLD_LED_CONTROL = reg;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
idp_led_get(struct led_classdev * cdev)230*4882a593Smuzhiyun static enum led_brightness idp_led_get(struct led_classdev *cdev)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct idp_led *led = container_of(cdev,
233*4882a593Smuzhiyun 			struct idp_led, cdev);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
idp_leds_init(void)238*4882a593Smuzhiyun static int __init idp_leds_init(void)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	int i;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (!machine_is_pxa_idp())
243*4882a593Smuzhiyun 		return -ENODEV;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(idp_leds); i++) {
246*4882a593Smuzhiyun 		struct idp_led *led;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 		led = kzalloc(sizeof(*led), GFP_KERNEL);
249*4882a593Smuzhiyun 		if (!led)
250*4882a593Smuzhiyun 			break;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 		led->cdev.name = idp_leds[i].name;
253*4882a593Smuzhiyun 		led->cdev.brightness_set = idp_led_set;
254*4882a593Smuzhiyun 		led->cdev.brightness_get = idp_led_get;
255*4882a593Smuzhiyun 		led->cdev.default_trigger = idp_leds[i].trigger;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		if (i == 0)
258*4882a593Smuzhiyun 			led->mask = IDP_HB_LED;
259*4882a593Smuzhiyun 		else
260*4882a593Smuzhiyun 			led->mask = IDP_BUSY_LED;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		if (led_classdev_register(NULL, &led->cdev) < 0) {
263*4882a593Smuzhiyun 			kfree(led);
264*4882a593Smuzhiyun 			break;
265*4882a593Smuzhiyun 		}
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	return 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun /*
272*4882a593Smuzhiyun  * Since we may have triggers on any subsystem, defer registration
273*4882a593Smuzhiyun  * until after subsystem_init.
274*4882a593Smuzhiyun  */
275*4882a593Smuzhiyun fs_initcall(idp_leds_init);
276*4882a593Smuzhiyun #endif
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
279*4882a593Smuzhiyun 	/* Maintainer: Vibren Technologies */
280*4882a593Smuzhiyun 	.map_io		= idp_map_io,
281*4882a593Smuzhiyun 	.nr_irqs	= PXA_NR_IRQS,
282*4882a593Smuzhiyun 	.init_irq	= pxa25x_init_irq,
283*4882a593Smuzhiyun 	.handle_irq	= pxa25x_handle_irq,
284*4882a593Smuzhiyun 	.init_time	= pxa_timer_init,
285*4882a593Smuzhiyun 	.init_machine	= idp_init,
286*4882a593Smuzhiyun 	.restart	= pxa_restart,
287*4882a593Smuzhiyun MACHINE_END
288