Commit | Line | Data |
---|---|---|
e5c271ec PZ |
1 | /* |
2 | * Support for HTC Magician PDA phones: | |
3 | * i-mate JAM, O2 Xda mini, Orange SPV M500, Qtek s100, Qtek s110 | |
4 | * and T-Mobile MDA Compact. | |
5 | * | |
6 | * Copyright (c) 2006-2007 Philipp Zabel | |
7 | * | |
8 | * Based on hx4700.c, spitz.c and others. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | */ | |
15 | ||
16 | #include <linux/kernel.h> | |
17 | #include <linux/init.h> | |
18 | #include <linux/platform_device.h> | |
19 | #include <linux/gpio_keys.h> | |
20 | #include <linux/input.h> | |
70e357f8 | 21 | #include <linux/mfd/htc-egpio.h> |
e5c271ec PZ |
22 | #include <linux/mtd/mtd.h> |
23 | #include <linux/mtd/map.h> | |
24 | #include <linux/mtd/physmap.h> | |
350d115d | 25 | #include <linux/pda_power.h> |
e5c271ec PZ |
26 | |
27 | #include <asm/gpio.h> | |
28 | #include <asm/hardware.h> | |
29 | #include <asm/mach-types.h> | |
30 | #include <asm/mach/arch.h> | |
31 | #include <asm/arch/magician.h> | |
32 | #include <asm/arch/pxa-regs.h> | |
33 | #include <asm/arch/pxafb.h> | |
e6816f34 | 34 | #include <asm/arch/i2c.h> |
bdb0c16a | 35 | #include <asm/arch/mmc.h> |
e5c271ec PZ |
36 | #include <asm/arch/irda.h> |
37 | #include <asm/arch/ohci.h> | |
38 | ||
39 | #include "generic.h" | |
40 | ||
41 | /* | |
42 | * IRDA | |
43 | */ | |
44 | ||
45 | static void magician_irda_transceiver_mode(struct device *dev, int mode) | |
46 | { | |
47 | gpio_set_value(GPIO83_MAGICIAN_nIR_EN, mode & IR_OFF); | |
48 | } | |
49 | ||
50 | static struct pxaficp_platform_data magician_ficp_info = { | |
51 | .transceiver_cap = IR_SIRMODE | IR_OFF, | |
52 | .transceiver_mode = magician_irda_transceiver_mode, | |
53 | }; | |
54 | ||
55 | /* | |
56 | * GPIO Keys | |
57 | */ | |
58 | ||
59 | static struct gpio_keys_button magician_button_table[] = { | |
60 | {KEY_POWER, GPIO0_MAGICIAN_KEY_POWER, 0, "Power button"}, | |
61 | {KEY_ESC, GPIO37_MAGICIAN_KEY_HANGUP, 0, "Hangup button"}, | |
62 | {KEY_F10, GPIO38_MAGICIAN_KEY_CONTACTS, 0, "Contacts button"}, | |
63 | {KEY_CALENDAR, GPIO90_MAGICIAN_KEY_CALENDAR, 0, "Calendar button"}, | |
64 | {KEY_CAMERA, GPIO91_MAGICIAN_KEY_CAMERA, 0, "Camera button"}, | |
65 | {KEY_UP, GPIO93_MAGICIAN_KEY_UP, 0, "Up button"}, | |
66 | {KEY_DOWN, GPIO94_MAGICIAN_KEY_DOWN, 0, "Down button"}, | |
67 | {KEY_LEFT, GPIO95_MAGICIAN_KEY_LEFT, 0, "Left button"}, | |
68 | {KEY_RIGHT, GPIO96_MAGICIAN_KEY_RIGHT, 0, "Right button"}, | |
69 | {KEY_KPENTER, GPIO97_MAGICIAN_KEY_ENTER, 0, "Action button"}, | |
70 | {KEY_RECORD, GPIO98_MAGICIAN_KEY_RECORD, 0, "Record button"}, | |
71 | {KEY_VOLUMEUP, GPIO100_MAGICIAN_KEY_VOL_UP, 0, "Volume up"}, | |
72 | {KEY_VOLUMEDOWN, GPIO101_MAGICIAN_KEY_VOL_DOWN, 0, "Volume down"}, | |
73 | {KEY_PHONE, GPIO102_MAGICIAN_KEY_PHONE, 0, "Phone button"}, | |
74 | {KEY_PLAY, GPIO99_MAGICIAN_HEADPHONE_IN, 0, "Headset button"}, | |
75 | }; | |
76 | ||
77 | static struct gpio_keys_platform_data gpio_keys_data = { | |
78 | .buttons = magician_button_table, | |
79 | .nbuttons = ARRAY_SIZE(magician_button_table), | |
80 | }; | |
81 | ||
82 | static struct platform_device gpio_keys = { | |
83 | .name = "gpio-keys", | |
84 | .dev = { | |
85 | .platform_data = &gpio_keys_data, | |
86 | }, | |
87 | .id = -1, | |
88 | }; | |
89 | ||
70e357f8 PZ |
90 | |
91 | /* | |
92 | * EGPIO (Xilinx CPLD) | |
93 | * | |
94 | * 7 32-bit aligned 8-bit registers: 3x output, 1x irq, 3x input | |
95 | */ | |
96 | ||
97 | static struct resource egpio_resources[] = { | |
98 | [0] = { | |
99 | .start = PXA_CS3_PHYS, | |
100 | .end = PXA_CS3_PHYS + 0x20, | |
101 | .flags = IORESOURCE_MEM, | |
102 | }, | |
103 | [1] = { | |
104 | .start = gpio_to_irq(GPIO13_MAGICIAN_CPLD_IRQ), | |
105 | .end = gpio_to_irq(GPIO13_MAGICIAN_CPLD_IRQ), | |
106 | .flags = IORESOURCE_IRQ, | |
107 | }, | |
108 | }; | |
109 | ||
110 | static struct htc_egpio_chip egpio_chips[] = { | |
111 | [0] = { | |
112 | .reg_start = 0, | |
113 | .gpio_base = MAGICIAN_EGPIO(0, 0), | |
114 | .num_gpios = 24, | |
115 | .direction = HTC_EGPIO_OUTPUT, | |
116 | .initial_values = 0x40, /* EGPIO_MAGICIAN_GSM_RESET */ | |
117 | }, | |
118 | [1] = { | |
119 | .reg_start = 4, | |
120 | .gpio_base = MAGICIAN_EGPIO(4, 0), | |
121 | .num_gpios = 24, | |
122 | .direction = HTC_EGPIO_INPUT, | |
123 | }, | |
124 | }; | |
125 | ||
126 | static struct htc_egpio_platform_data egpio_info = { | |
127 | .reg_width = 8, | |
128 | .bus_width = 32, | |
129 | .irq_base = IRQ_BOARD_START, | |
130 | .num_irqs = 4, | |
131 | .ack_register = 3, | |
132 | .chip = egpio_chips, | |
133 | .num_chips = ARRAY_SIZE(egpio_chips), | |
134 | }; | |
135 | ||
136 | static struct platform_device egpio = { | |
137 | .name = "htc-egpio", | |
138 | .id = -1, | |
139 | .resource = egpio_resources, | |
140 | .num_resources = ARRAY_SIZE(egpio_resources), | |
141 | .dev = { | |
142 | .platform_data = &egpio_info, | |
143 | }, | |
144 | }; | |
145 | ||
e5c271ec PZ |
146 | /* |
147 | * LCD - Toppoly TD028STEB1 | |
148 | */ | |
149 | ||
150 | static struct pxafb_mode_info toppoly_modes[] = { | |
151 | { | |
152 | .pixclock = 96153, | |
153 | .bpp = 16, | |
154 | .xres = 240, | |
155 | .yres = 320, | |
156 | .hsync_len = 11, | |
157 | .vsync_len = 3, | |
158 | .left_margin = 19, | |
159 | .upper_margin = 2, | |
160 | .right_margin = 10, | |
161 | .lower_margin = 2, | |
162 | .sync = 0, | |
163 | }, | |
164 | }; | |
165 | ||
166 | static struct pxafb_mach_info toppoly_info = { | |
167 | .modes = toppoly_modes, | |
168 | .num_modes = 1, | |
169 | .fixed_modes = 1, | |
170 | .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, | |
171 | .lccr3 = LCCR3_PixRsEdg, | |
172 | }; | |
173 | ||
174 | /* | |
175 | * Backlight | |
176 | */ | |
177 | ||
178 | static void magician_set_bl_intensity(int intensity) | |
179 | { | |
180 | if (intensity) { | |
181 | PWM_CTRL0 = 1; | |
182 | PWM_PERVAL0 = 0xc8; | |
183 | PWM_PWDUTY0 = intensity; | |
184 | pxa_set_cken(CKEN_PWM0, 1); | |
185 | } else { | |
186 | pxa_set_cken(CKEN_PWM0, 0); | |
187 | } | |
188 | } | |
189 | ||
190 | static struct generic_bl_info backlight_info = { | |
191 | .default_intensity = 0x64, | |
192 | .limit_mask = 0x0b, | |
193 | .max_intensity = 0xc7, | |
194 | .set_bl_intensity = magician_set_bl_intensity, | |
195 | }; | |
196 | ||
197 | static struct platform_device backlight = { | |
df56eacd | 198 | .name = "generic-bl", |
e5c271ec PZ |
199 | .dev = { |
200 | .platform_data = &backlight_info, | |
201 | }, | |
202 | .id = -1, | |
203 | }; | |
204 | ||
205 | ||
350d115d PZ |
206 | /* |
207 | * External power | |
208 | */ | |
209 | ||
210 | static int magician_is_ac_online(void) | |
211 | { | |
212 | return gpio_get_value(EGPIO_MAGICIAN_CABLE_STATE_AC); | |
213 | } | |
214 | ||
215 | static int magician_is_usb_online(void) | |
216 | { | |
217 | return gpio_get_value(EGPIO_MAGICIAN_CABLE_STATE_USB); | |
218 | } | |
219 | ||
220 | static void magician_set_charge(int flags) | |
221 | { | |
222 | gpio_set_value(GPIO30_MAGICIAN_nCHARGE_EN, !flags); | |
223 | gpio_set_value(EGPIO_MAGICIAN_CHARGE_EN, flags); | |
224 | } | |
225 | ||
226 | static struct pda_power_pdata power_supply_info = { | |
227 | .is_ac_online = magician_is_ac_online, | |
228 | .is_usb_online = magician_is_usb_online, | |
229 | .set_charge = magician_set_charge, | |
230 | }; | |
231 | ||
232 | static struct resource power_supply_resources[] = { | |
233 | [0] = { | |
234 | .name = "ac", | |
235 | .flags = IORESOURCE_IRQ, | |
236 | .start = IRQ_MAGICIAN_AC, | |
237 | .end = IRQ_MAGICIAN_AC, | |
238 | }, | |
239 | [1] = { | |
240 | .name = "usb", | |
241 | .flags = IORESOURCE_IRQ, | |
242 | .start = IRQ_MAGICIAN_AC, | |
243 | .end = IRQ_MAGICIAN_AC, | |
244 | }, | |
245 | }; | |
246 | ||
247 | static struct platform_device power_supply = { | |
248 | .name = "pda-power", | |
249 | .id = -1, | |
250 | .dev = { | |
251 | .platform_data = &power_supply_info, | |
252 | }, | |
253 | .resource = power_supply_resources, | |
254 | .num_resources = ARRAY_SIZE(power_supply_resources), | |
255 | }; | |
256 | ||
257 | ||
bdb0c16a PZ |
258 | /* |
259 | * MMC/SD | |
260 | */ | |
261 | ||
262 | static int magician_mci_init(struct device *dev, | |
263 | irq_handler_t detect_irq, void *data) | |
264 | { | |
265 | return request_irq(IRQ_MAGICIAN_SD, detect_irq, | |
266 | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, | |
267 | "MMC card detect", data); | |
268 | } | |
269 | ||
270 | static void magician_mci_setpower(struct device *dev, unsigned int vdd) | |
271 | { | |
272 | struct pxamci_platform_data *pdata = dev->platform_data; | |
273 | ||
274 | gpio_set_value(EGPIO_MAGICIAN_SD_POWER, (1 << vdd) & pdata->ocr_mask); | |
275 | } | |
276 | ||
277 | static int magician_mci_get_ro(struct device *dev) | |
278 | { | |
279 | return (!gpio_get_value(EGPIO_MAGICIAN_nSD_READONLY)); | |
280 | } | |
281 | ||
282 | static void magician_mci_exit(struct device *dev, void *data) | |
283 | { | |
284 | free_irq(IRQ_MAGICIAN_SD, data); | |
285 | } | |
286 | ||
287 | static struct pxamci_platform_data magician_mci_info = { | |
288 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | |
289 | .init = magician_mci_init, | |
290 | .get_ro = magician_mci_get_ro, | |
291 | .setpower = magician_mci_setpower, | |
292 | .exit = magician_mci_exit, | |
293 | }; | |
294 | ||
295 | ||
e5c271ec PZ |
296 | /* |
297 | * USB OHCI | |
298 | */ | |
299 | ||
300 | static int magician_ohci_init(struct device *dev) | |
301 | { | |
302 | UHCHR = (UHCHR | UHCHR_SSEP2 | UHCHR_PCPL | UHCHR_CGR) & | |
303 | ~(UHCHR_SSEP1 | UHCHR_SSEP3 | UHCHR_SSE); | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | static struct pxaohci_platform_data magician_ohci_info = { | |
309 | .port_mode = PMM_PERPORT_MODE, | |
310 | .init = magician_ohci_init, | |
311 | .power_budget = 0, | |
312 | }; | |
313 | ||
314 | ||
315 | /* | |
316 | * StrataFlash | |
317 | */ | |
318 | ||
aa797590 PZ |
319 | static void magician_set_vpp(struct map_info *map, int vpp) |
320 | { | |
321 | gpio_set_value(EGPIO_MAGICIAN_FLASH_VPP, vpp); | |
322 | } | |
323 | ||
e5c271ec PZ |
324 | #define PXA_CS_SIZE 0x04000000 |
325 | ||
326 | static struct resource strataflash_resource = { | |
327 | .start = PXA_CS0_PHYS, | |
328 | .end = PXA_CS0_PHYS + PXA_CS_SIZE - 1, | |
329 | .flags = IORESOURCE_MEM, | |
330 | }; | |
331 | ||
332 | static struct physmap_flash_data strataflash_data = { | |
333 | .width = 4, | |
aa797590 | 334 | .set_vpp = magician_set_vpp, |
e5c271ec PZ |
335 | }; |
336 | ||
337 | static struct platform_device strataflash = { | |
338 | .name = "physmap-flash", | |
339 | .id = -1, | |
e5c271ec | 340 | .resource = &strataflash_resource, |
70e357f8 | 341 | .num_resources = 1, |
e5c271ec PZ |
342 | .dev = { |
343 | .platform_data = &strataflash_data, | |
344 | }, | |
345 | }; | |
346 | ||
347 | /* | |
348 | * Platform devices | |
349 | */ | |
350 | ||
351 | static struct platform_device *devices[] __initdata = { | |
352 | &gpio_keys, | |
70e357f8 | 353 | &egpio, |
e5c271ec | 354 | &backlight, |
350d115d | 355 | &power_supply, |
e5c271ec PZ |
356 | &strataflash, |
357 | }; | |
358 | ||
359 | static void __init magician_init(void) | |
360 | { | |
361 | platform_add_devices(devices, ARRAY_SIZE(devices)); | |
e6816f34 | 362 | pxa_set_i2c_info(NULL); |
bdb0c16a | 363 | pxa_set_mci_info(&magician_mci_info); |
e5c271ec PZ |
364 | pxa_set_ohci_info(&magician_ohci_info); |
365 | pxa_set_ficp_info(&magician_ficp_info); | |
366 | set_pxa_fb_info(&toppoly_info); | |
367 | } | |
368 | ||
369 | ||
370 | MACHINE_START(MAGICIAN, "HTC Magician") | |
371 | .phys_io = 0x40000000, | |
372 | .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, | |
373 | .boot_params = 0xa0000100, | |
374 | .map_io = pxa_map_io, | |
375 | .init_irq = pxa27x_init_irq, | |
376 | .init_machine = magician_init, | |
377 | .timer = &pxa_timer, | |
378 | MACHINE_END |