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