hh.org updates
[hh.org.git] / arch / arm / mach-pxa / aximx5 / aximx5_misc.c
blob2c6ee80bb1bcd5d3603d9cc0c4d179fcb2678903
1 /*
2 * Miscelaneous device handlers for Dell Axim X5.
3 * Tracks cradle insertion/removal, provides the MediaQ
4 * platform device, provides SIR support.
6 * Copyright © 2004 Andrew Zabolotny
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
10 * more details.
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/ioport.h>
16 #include <linux/device.h>
17 #include <linux/interrupt.h>
18 #include <linux/irq.h>
19 #include <linux/delay.h>
20 #include <linux/dock-hotplug.h>
21 #include <linux/platform_device.h>
22 #include <asm/io.h>
23 #include <asm/irq.h>
24 #include <asm/setup.h>
25 #include <asm/mach/arch.h>
26 #include <asm/mach/map.h>
27 #include <asm/mach-types.h>
28 #include <asm/hardware.h>
29 #include <asm/arch/pxa-regs.h>
30 #include <asm/arch/irqs.h>
31 #include <asm/arch/aximx5-gpio.h>
33 #include "../drivers/soc/mq11xx.h"
34 #include "../drivers/usb/gadget/mq11xx_udc.h"
36 #if defined CONFIG_DOCKING_HOTPLUG || \
37 (defined CONFIG_AXIMX5_MISC_MODULE && defined CONFIG_DOCKING_HOTPLUG_MODULE)
38 # define DOCKING_HOTPLUG
39 #endif
41 #if 0
42 # define debug(s, args...) printk (KERN_INFO s, ##args)
43 #else
44 # define debug(s, args...)
45 #endif
46 #define debug_func(s, args...) debug ("%s: " s, __FUNCTION__, ##args)
48 #define MQ_BASE 0x14000000
50 extern int driver_pxa_ac97_wm97xx;
52 /* MediaQ 1132 init state */
53 static struct mediaq11xx_init_data aximx5_mq1132_init_data = {
54 /* DC */
56 /* dc00 */ 0x00000001,
57 /* dc01 */ 0x00000003,
58 /* dc02 */ 0x00000001,
59 /* dc03 NOT SET */ 0x0,
60 /* dc04 */ 0x00000004,
61 /* dc05 */ 0x00000001,
63 /* CC */
65 /* cc00 */ 0x00000000,
66 /* cc01 */ 0x00001010,
67 /* cc02 */ 0x000009a0,
68 /* cc03 */ 0xa2202200,
69 /* cc04 */ 0x00000004,
71 /* MIU */
73 /* mm00 */ 0x00000001,
74 /* mm01 */ 0x1b676ca8,
75 /* mm02 */ 0x00000000,
76 /* mm03 */ 0x00000000,
77 /* mm04 */ 0x00000000,
79 /* GC */
81 /* gc00 */ 0x080100c8, /* powered down */
82 /* gc01 */ 0x00000000,
83 /* gc02 */ 0x00f0011a,
84 /* gc03 */ 0x013f015e,
85 /* gc04 */ 0x011100fa,
86 /* gc05 */ 0x01590157,
87 /* gc06 */ 0x00000000,
88 /* gc07 NOT SET */ 0x0,
89 /* gc08 */ 0x00ef0000,
90 /* gc09 */ 0x013f0000,
91 /* gc0a */ 0x00000000,
92 /* gc0b */ 0x011700f2,
93 /* gc0c */ 0x00000000,
94 /* gc0d */ 0x000091a6,
95 /* gc0e */ 0x000001e0,
96 /* gc0f NOT SET */ 0x0,
97 /* gc10 */ 0x031f071f,
98 /* gc11 */ 0x000000ff,
99 /* gc12 NOT SET */ 0x0,
100 /* gc13 NOT SET */ 0x0,
101 /* gc14 */ 0x00000000,
102 /* gc15 */ 0x00000000,
103 /* gc16 */ 0x00000000,
104 /* gc17 */ 0x00000000,
105 /* gc18 */ 0x00000000,
106 /* gc19 */ 0x00000000,
107 /* gc1a */ 0x00000000,
109 /* FP */
111 /* fp00 */ 0x00406120,
112 /* fp01 */ 0x001d5008,
113 /* fp02 */ 0xbffcfcff,
114 /* fp03 */ 0x00000000,
115 /* fp04 */ 0x80bd0001,
116 /* fp05 */ 0x89000000,
117 /* fp06 */ 0x80000000,
118 /* fp07 */ 0x00000000,
119 /* fp08 */ 0x3afe46fb,
120 /* fp09 NOT SET */ 0x0,
121 /* fp0a */ 0x00000000,
122 /* fp0b */ 0x00000000,
123 /* fp0c NOT SET */ 0x0,
124 /* fp0d NOT SET */ 0x0,
125 /* fp0e NOT SET */ 0x0,
126 /* fp0f */ 0x00005ca0,
127 /* fp10 */ 0x513fc706,
128 /* fp11 */ 0x18f8b182,
129 /* fp12 */ 0xff8d6644,
130 /* fp13 */ 0xae133357,
131 /* fp14 */ 0x2b90bee1,
132 /* fp15 */ 0xa6fee27a,
133 /* fp16 */ 0x5aa04ee2,
134 /* fp17 */ 0xb4e957f8,
135 /* fp18 */ 0xd2fe9cfb,
136 /* fp19 */ 0x94ff70fb,
137 /* fp1a */ 0x7bfe5efb,
138 /* fp1b */ 0x3ab676ad,
139 /* fp1c */ 0x32e2ec5c,
140 /* fp1d */ 0xc1309546,
141 /* fp1e */ 0xf6933d7a,
142 /* fp1f */ 0x02bfa020,
143 /* fp20 */ 0x0,
144 /* fp21 */ 0x0,
145 /* fp22 */ 0x0,
146 /* fp23 */ 0x0,
147 /* fp24 */ 0x0,
148 /* fp25 */ 0x0,
149 /* fp26 */ 0x0,
150 /* fp27 */ 0x0,
151 /* fp28 */ 0x0,
152 /* fp29 */ 0x0,
153 /* fp2a */ 0x0,
154 /* fp2b */ 0x0,
155 /* fp2c */ 0x0,
156 /* fp2d */ 0x0,
157 /* fp2e */ 0x0,
158 /* fp2f */ 0x0,
159 /* fp30 */ 0xc3089f9a,
160 /* fp31 */ 0x4488419f,
161 /* fp32 */ 0x4131a146,
162 /* fp33 */ 0xdbc01ccd,
163 /* fp34 */ 0x7649f9d6,
164 /* fp35 */ 0xa0122146,
165 /* fp36 */ 0x1c2ed6e7,
166 /* fp37 */ 0x182d52e9,
167 /* fp38 */ 0xb3d06f09,
168 /* fp39 */ 0x663a5cf4,
169 /* fp3a */ 0x54fb278b,
170 /* fp3b */ 0x07181a1b,
171 /* fp3c */ 0x4d201fdd,
172 /* fp3d */ 0x082459ef,
173 /* fp3e */ 0xe044b973,
174 /* fp3f */ 0x749c7102,
175 /* fp40 */ 0x0,
176 /* fp41 */ 0x0,
177 /* fp42 */ 0x0,
178 /* fp43 */ 0x0,
179 /* fp44 */ 0x0,
180 /* fp45 */ 0x0,
181 /* fp46 */ 0x0,
182 /* fp47 */ 0x0,
183 /* fp48 */ 0x0,
184 /* fp49 */ 0x0,
185 /* fp4a */ 0x0,
186 /* fp4b */ 0x0,
187 /* fp4c */ 0x0,
188 /* fp4d */ 0x0,
189 /* fp4e */ 0x0,
190 /* fp4f */ 0x0,
191 /* fp50 */ 0x0,
192 /* fp51 */ 0x0,
193 /* fp52 */ 0x0,
194 /* fp53 */ 0x0,
195 /* fp54 */ 0x0,
196 /* fp55 */ 0x0,
197 /* fp56 */ 0x0,
198 /* fp57 */ 0x0,
199 /* fp58 */ 0x0,
200 /* fp59 */ 0x0,
201 /* fp5a */ 0x0,
202 /* fp5b */ 0x0,
203 /* fp5c */ 0x0,
204 /* fp5d */ 0x0,
205 /* fp5e */ 0x0,
206 /* fp5f */ 0x0,
207 /* fp60 */ 0x0,
208 /* fp61 */ 0x0,
209 /* fp62 */ 0x0,
210 /* fp63 */ 0x0,
211 /* fp64 */ 0x0,
212 /* fp65 */ 0x0,
213 /* fp66 */ 0x0,
214 /* fp67 */ 0x0,
215 /* fp68 */ 0x0,
216 /* fp69 */ 0x0,
217 /* fp6a */ 0x0,
218 /* fp6b */ 0x0,
219 /* fp6c */ 0x0,
220 /* fp6d */ 0x0,
221 /* fp6e */ 0x0,
222 /* fp6f */ 0x0,
223 /* fp70 */ 0x6e0812af,
224 /* fp71 */ 0x4116e7b4,
225 /* fp72 */ 0x7714bcdb,
226 /* fp73 */ 0x0,
227 /* fp74 */ 0x0,
228 /* fp75 */ 0x0,
229 /* fp76 */ 0x9bb93ec3,
230 /* fp77 */ 0xb2021123,
232 /* GE */
234 /* ge00 NOT SET */ 0x0,
235 /* ge01 NOT SET */ 0x0,
236 /* ge02 NOT SET */ 0x0,
237 /* ge03 NOT SET */ 0x0,
238 /* ge04 NOT SET */ 0x0,
239 /* ge05 NOT SET */ 0x0,
240 /* ge06 NOT SET */ 0x0,
241 /* ge07 NOT SET */ 0x0,
242 /* ge08 NOT SET */ 0x0,
243 /* ge09 NOT SET */ 0x0,
244 /* ge0a */ 0x400001e0,
245 /* ge0b */ 0x00000000,
247 /* SPI */
249 /* sp00 */ 0x40481189,
250 /* sp01 */ 0,
251 /* sp02 NOT SET */ 0,
252 /* sp03 NOT SET */ 0,
253 /* sp04 */ 0x004ef9ff,
254 /* sp05 NOT SET */ 0,
255 /* sp06 NOT SET */ 0,
256 /* sp07 */ 0xfffffff0,
257 /* sp08 */ 0x002ffc7d,
261 static struct resource mq1132_resources[] = {
262 /* Synchronous memory */
263 [0] = {
264 .start = MQ_BASE,
265 .end = MQ_BASE + MQ11xx_FB_SIZE - 1,
266 .flags = IORESOURCE_MEM,
268 /* Non-synchronous memory */
269 [1] = {
270 .start = MQ_BASE + MQ11xx_FB_SIZE + MQ11xx_REG_SIZE,
271 .end = MQ_BASE + MQ11xx_FB_SIZE * 2 - 1,
272 .flags = IORESOURCE_MEM,
274 /* MediaQ registers */
275 [2] = {
276 .start = MQ_BASE + MQ11xx_FB_SIZE,
277 .end = MQ_BASE + MQ11xx_FB_SIZE + MQ11xx_REG_SIZE - 1,
278 .flags = IORESOURCE_MEM,
280 /* MediaQ interrupt number */
281 [3] = {
282 .start = AXIMX5_IRQ (MQ1132_INT),
283 .flags = IORESOURCE_IRQ,
287 struct platform_device aximx5_mq1132 = {
288 .name = "mq11xx",
289 .id = 0,
290 .num_resources = ARRAY_SIZE(mq1132_resources),
291 .resource = mq1132_resources,
292 .dev = {
293 .platform_data = &aximx5_mq1132_init_data,
297 //-----------------------------------------------// Battery latch IRQ //-----//
299 static irqreturn_t aximx5_battery_latch (int irq, void *dev_id, struct pt_regs *regs)
301 /* todo: go to sleep immediately or something like that */
302 return IRQ_HANDLED;
305 static void aximx5_init_latch (void)
307 request_irq (AXIMX5_IRQ (BATTERY_LATCH), &aximx5_battery_latch,
308 0, "Battery latch", NULL);
309 set_irq_type (AXIMX5_IRQ (BATTERY_LATCH), IRQT_BOTHEDGE);
312 //-------------------------------------------// USB Device Controller //-----//
314 int aximx5_udc_is_connected (void)
316 return !GET_AXIMX5_GPIO (CRADLE_DETECT_N);
319 void aximx5_udc_command (int cmd)
321 switch (cmd) {
322 case MQ11XX_UDC_CMD_DISCONNECT:
323 SET_AXIMX5_GPIO_N (USB_PULL_UP, 0);
324 break;
325 case MQ11XX_UDC_CMD_CONNECT:
326 SET_AXIMX5_GPIO_N (USB_PULL_UP, 1);
327 break;
331 void aximx5_udc_release (struct device *dev)
333 (void)dev;
336 static struct mq11xx_udc_mach_info aximx5_udc_info = {
337 .udc_is_connected = &aximx5_udc_is_connected,
338 .udc_command = &aximx5_udc_command,
341 static struct platform_device aximx5_udc = {
342 .name = "mq11xx_udc",
343 .dev = {
344 .platform_data = &aximx5_udc_info,
345 .release = aximx5_udc_release
349 //----------------------------------------// Cradle insertion/removal //-----//
351 #ifdef DOCKING_HOTPLUG
353 static wait_queue_head_t cradle_event;
354 static volatile int cradle_event_count;
356 static struct dock_hotplug_caps_t dockcaps = {
357 UNKNOWN_DOCKING_IDENTIFIER,
359 DOCKCAPS_HOT
362 static irqreturn_t aximx5_cradle (int irq, void *dev_id, struct pt_regs *regs)
364 cradle_event_count++;
365 wake_up_interruptible (&cradle_event);
366 return IRQ_HANDLED;
369 static int check_cradle (void)
371 static int old_type = -1;
372 int type = AXIMX5_CONNECTOR_TYPE;
374 if (GET_AXIMX5_GPIO (CRADLE_DETECT_N))
375 type = -1;
377 if (type == old_type)
378 return 0;
380 /* If we're going in a dock, find out its type */
381 if (type != 7 && type != -1) {
382 dockcaps.flavour = AXIMX5_CONNECTOR_IS_CRADLE (type) ?
383 DOCKFLAV_CRADLE : DOCKFLAV_CABLE;
384 dockcaps.capabilities &= ~(DOCKCAPS_UDC | DOCKCAPS_RS232);
387 if (AXIMX5_CONNECTOR_IS_SERIAL (type))
388 dockcaps.capabilities |= DOCKCAPS_RS232;
389 else if (AXIMX5_CONNECTOR_IS_USB (type))
390 dockcaps.capabilities |= DOCKCAPS_UDC;
391 else {
392 /* If we get a cradle code out of range ... */
393 if (type >= 0 && type < 7)
394 printk (KERN_INFO "Unknown connector=%d: "
395 "please mail this to anpaza@mail.ru\n", type);
396 if (old_type == -1)
397 return 0;
398 type = -1;
400 old_type = type;
402 /* Setup RS-232 transceiver power */
403 SET_AXIMX5_GPIO (RS232_DCD, dockcaps.capabilities & DOCKCAPS_RS232);
405 return dock_hotplug_event(type != -1, &dockcaps);
408 /* This thread handles cradle insertion/removal */
409 static int cradle_thread (void *arg)
411 int old_count;
413 /* set up thread context */
414 daemonize ("kcradle");
415 /* This thread is low priority */
416 set_user_nice (current, 5);
417 /* At startup check if we're in cradle */
418 goto again;
420 for (;;) {
421 wait_event_interruptible (cradle_event, old_count != cradle_event_count);
423 /* Wait for a steady contact */
424 again: do {
425 old_count = cradle_event_count;
426 set_task_state (current, TASK_INTERRUPTIBLE);
427 schedule_timeout(HZ/2);
428 } while (old_count != cradle_event_count);
430 /* Now see what we have to do ... */
431 if (check_cradle () == EAGAIN)
432 goto again;
436 static void aximx5_init_cradle (void)
438 init_waitqueue_head (&cradle_event);
439 kernel_thread (cradle_thread, NULL, 0);
440 request_irq (AXIMX5_IRQ (CRADLE_DETECT_N), &aximx5_cradle,
441 0, "Cradle", NULL);
442 set_irq_type (AXIMX5_IRQ (CRADLE_DETECT_N), IRQT_BOTHEDGE);
445 #endif
447 static int __init aximx5_misc_init(void)
449 platform_device_register (&aximx5_mq1132);
450 platform_device_register (&aximx5_udc);
451 #ifdef DOCKING_HOTPLUG
452 aximx5_init_cradle ();
453 #endif
454 aximx5_init_latch ();
455 return 0;
458 module_init (aximx5_misc_init);
459 /* No module_exit function since this driver should be never unloaded */
461 MODULE_AUTHOR ("Andrew Zabolotny <zap@homelink.ru>");
462 MODULE_DESCRIPTION ("Miscelaneous device support for Dell Axim X5");
463 MODULE_LICENSE ("GPL");