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
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>
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
42 # define debug(s, args...) printk (KERN_INFO s, ##args)
44 # define debug(s, args...)
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
= {
56 /* dc00 */ 0x00000001,
57 /* dc01 */ 0x00000003,
58 /* dc02 */ 0x00000001,
59 /* dc03 NOT SET */ 0x0,
60 /* dc04 */ 0x00000004,
61 /* dc05 */ 0x00000001,
65 /* cc00 */ 0x00000000,
66 /* cc01 */ 0x00001010,
67 /* cc02 */ 0x000009a0,
68 /* cc03 */ 0xa2202200,
69 /* cc04 */ 0x00000004,
73 /* mm00 */ 0x00000001,
74 /* mm01 */ 0x1b676ca8,
75 /* mm02 */ 0x00000000,
76 /* mm03 */ 0x00000000,
77 /* mm04 */ 0x00000000,
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,
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,
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,
223 /* fp70 */ 0x6e0812af,
224 /* fp71 */ 0x4116e7b4,
225 /* fp72 */ 0x7714bcdb,
229 /* fp76 */ 0x9bb93ec3,
230 /* fp77 */ 0xb2021123,
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,
249 /* sp00 */ 0x40481189,
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 */
265 .end
= MQ_BASE
+ MQ11xx_FB_SIZE
- 1,
266 .flags
= IORESOURCE_MEM
,
268 /* Non-synchronous memory */
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 */
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 */
282 .start
= AXIMX5_IRQ (MQ1132_INT
),
283 .flags
= IORESOURCE_IRQ
,
287 struct platform_device aximx5_mq1132
= {
290 .num_resources
= ARRAY_SIZE(mq1132_resources
),
291 .resource
= mq1132_resources
,
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 */
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
)
322 case MQ11XX_UDC_CMD_DISCONNECT
:
323 SET_AXIMX5_GPIO_N (USB_PULL_UP
, 0);
325 case MQ11XX_UDC_CMD_CONNECT
:
326 SET_AXIMX5_GPIO_N (USB_PULL_UP
, 1);
331 void aximx5_udc_release (struct device
*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",
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
,
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
);
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
))
377 if (type
== old_type
)
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
;
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
);
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
)
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 */
421 wait_event_interruptible (cradle_event
, old_count
!= cradle_event_count
);
423 /* Wait for a steady contact */
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
)
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
,
442 set_irq_type (AXIMX5_IRQ (CRADLE_DETECT_N
), IRQT_BOTHEDGE
);
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 ();
454 aximx5_init_latch ();
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");