2 * Experimental driver for the CPLD in the HTC Magician
4 * Copyright 2006 Philipp Zabel
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
12 #include <linux/module.h>
13 #include <linux/version.h>
15 #include <linux/interrupt.h>
16 #include <linux/platform_device.h>
20 #include <asm/mach/irq.h>
22 #include <asm/arch/hardware.h>
23 #include <asm/arch/pxa-regs.h>
25 #include <asm/arch/magician.h>
27 struct magician_cpld_registers
36 struct magician_cpld_data
38 struct magician_cpld_registers
*mapping
;
40 u32 cached_egpio
[3]; // cached egpio registers
43 static inline int u8pos(int bit
)
48 static inline int u8bit(int bit
)
50 return 1<<(bit
& (8-1));
53 void magician_egpio_enable (struct platform_device
*dev
, int bit
)
56 struct magician_cpld_data
*cpld
= platform_get_drvdata(dev
);
59 local_irq_save(flags
);
61 cpld
->cached_egpio
[pos
] |= u8bit(bit
);
62 printk("egpio set: reg %d = 0x%08x\n", pos
, cpld
->cached_egpio
[pos
]);
63 cpld
->mapping
->egpio
[pos
] = cpld
->cached_egpio
[pos
];
65 local_irq_restore(flags
);
68 void magician_egpio_disable (struct platform_device
*dev
, int bit
)
71 struct magician_cpld_data
*cpld
= platform_get_drvdata(dev
);
74 local_irq_save(flags
);
76 cpld
->cached_egpio
[pos
] &= ~u8bit(bit
);
77 printk("egpio set: reg %d = 0x%08x\n", pos
, cpld
->cached_egpio
[pos
]);
78 cpld
->mapping
->egpio
[pos
] = cpld
->cached_egpio
[pos
];
80 local_irq_restore(flags
);
83 static void magician_cpld_ack_gpio(unsigned int irq
)
85 // GEDR0 = (1 << (irq - IRQ_GPIO0));
86 printk ("magician_cpld_ack_gpio(%d)\n", irq
);
89 static void magician_cpld_mask_irq(unsigned int irq
)
93 static void magician_cpld_unmask_irq(unsigned int irq
)
97 static struct irqchip magician_cpld_chip
= {
98 .ack
= magician_cpld_ack_gpio
,
99 .mask
= magician_cpld_mask_irq
,
100 .unmask
= magician_cpld_unmask_irq
,
104 * Demux handler for CPLD edge detect interrupts
106 static void magician_cpld_irq_handler(unsigned int irq
, struct irqdesc
*desc
)
108 struct magician_cpld_data
*cpld
= desc
->chip_data
;
109 int result
, cable_state
;
111 /* Acknowledge the parent IRQ */
112 desc
->chip
->ack(irq
);
114 result
= cpld
->mapping
->irq_state
;
115 printk ("cpld irq 0x%02x ", result
);
116 cpld
->mapping
->irq_state
= result
; // ACK (clear)
117 printk ("(0x%02x)\n", cpld
->mapping
->irq_state
);
119 cable_state
= cpld
->mapping
->cable_state
;
123 irq
= IRQ_MAGICIAN_SD
;
124 desc
= &irq_desc
[irq
];
125 desc_handle_irq(irq
, desc
);
128 irq
= IRQ_MAGICIAN_EP
;
129 printk ("ep_state = 0x%02x\n", cpld
->mapping
->cpld18
);
130 desc
= &irq_desc
[irq
];
131 desc_handle_irq(irq
, desc
);
134 irq
= IRQ_MAGICIAN_AC
;
135 printk ("cable_state = 0x%02x\n", cable_state
); // pCPLDRegs->cable_state
136 desc
= &irq_desc
[irq
];
137 desc_handle_irq(irq
, desc
);
140 irq
= IRQ_MAGICIAN_USBC
;
141 desc
= &irq_desc
[irq
];
142 desc_handle_irq(irq
, desc
);
145 printk ("magician_cpld: unknown irq 0x%x\n", result
);
149 static int magician_cpld_probe (struct platform_device
*dev
)
151 struct magician_cpld_data
*cpld
;
152 struct resource
*res
;
154 cpld
= kmalloc (sizeof (struct magician_cpld_data
), GFP_KERNEL
);
157 memset (cpld
, 0, sizeof (*cpld
));
159 platform_set_drvdata(dev
, cpld
);
161 res
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
162 cpld
->mapping
= (struct magician_cpld_registers
*)ioremap (res
->start
, res
->end
- res
->start
);
163 if (!cpld
->mapping
) {
164 printk ("magician_cpld: couldn't ioremap\n");
169 printk ("MainBoardID = %x\n", cpld
->mapping
->cpld14
& 0x7);
170 printk ("SD write protect bit: %d\n", cpld
->mapping
->cpld14
& 0x10);
171 printk("magician_cpld: lcd_select = %d (%s)\n", cpld
->mapping
->cpld14
& 0x8,
172 (cpld
->mapping
->cpld14
& 0x8) ? "samsung" : "toppoly");
175 * Initial values. FIXME: if we're not booting from wince, we should set them ourselves.
177 cpld
->cached_egpio
[0] = cpld
->mapping
->egpio
[0];
178 cpld
->cached_egpio
[1] = cpld
->mapping
->egpio
[1];
179 cpld
->cached_egpio
[2] = cpld
->mapping
->egpio
[2];
180 printk ("initial egpios: 0x%02x 0x%02x 0x%02x\n", cpld
->cached_egpio
[0], cpld
->cached_egpio
[1], cpld
->cached_egpio
[2]);
182 cpld
->irq_nr
= platform_get_irq(dev
, 0);
183 if (cpld
->irq_nr
>= 0) {
187 * Setup handlers for CPLD irqs, muxed into IRQ_GPIO(13)
189 for (irq
= IRQ_MAGICIAN_SD
; irq
<= IRQ_MAGICIAN_AC
; irq
++) {
190 set_irq_chip(irq
, &magician_cpld_chip
);
191 set_irq_handler(irq
, handle_simple_irq
);
192 set_irq_flags(irq
, IRQF_VALID
| IRQF_PROBE
); // | ACK
195 set_irq_chained_handler(cpld
->irq_nr
, magician_cpld_irq_handler
);
196 set_irq_type (cpld
->irq_nr
, IRQT_RISING
);
197 set_irq_data (cpld
->irq_nr
, cpld
);
198 set_irq_chipdata(cpld
->irq_nr
, cpld
);
203 static int magician_cpld_remove (struct platform_device
*dev
)
205 struct magician_cpld_data
*cpld
= platform_get_drvdata(dev
);
207 if (cpld
->irq_nr
>= 0) {
210 for (irq
= IRQ_MAGICIAN_SD
; irq
<= IRQ_MAGICIAN_AC
; irq
++) {
211 set_irq_chip(irq
, NULL
);
212 set_irq_handler(irq
, NULL
);
213 set_irq_flags(irq
, 0);
216 set_irq_chained_handler(cpld
->irq_nr
, NULL
);
219 iounmap((void *)cpld
->mapping
);
221 platform_set_drvdata(dev
, NULL
);
227 struct platform_driver magician_cpld_driver
= {
228 .probe
= magician_cpld_probe
,
229 .remove
= magician_cpld_remove
,
231 .name
= "magician-cpld",
235 static int magician_cpld_init (void)
237 return platform_driver_register (&magician_cpld_driver
);
240 static void magician_cpld_exit (void)
242 platform_driver_unregister (&magician_cpld_driver
);
245 module_init (magician_cpld_init
);
246 module_exit (magician_cpld_exit
);
248 MODULE_LICENSE("GPL");
249 MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");
250 MODULE_DESCRIPTION("Experimental driver for the CPLD in the HTC Magician");
251 MODULE_SUPPORTED_DEVICE("magician-cpld");
253 EXPORT_SYMBOL(magician_egpio_enable
);
254 EXPORT_SYMBOL(magician_egpio_disable
);