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