hh.org updates
[hh.org.git] / arch / arm / mach-pxa / magician / magician_cpld.c
blobdbbd1166d18f4d96da008c1cddfb70b58be43293
1 /*
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>
18 #include <asm/io.h>
19 #include <asm/irq.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
29 u32 egpio[3];
30 u32 irq_state;
31 u32 cable_state;
32 u32 cpld14;
33 u32 cpld18;
36 struct magician_cpld_data
38 struct magician_cpld_registers *mapping;
39 int irq_nr;
40 u32 cached_egpio[3]; // cached egpio registers
43 static inline int u8pos(int bit)
45 return bit/8;
48 static inline int u8bit(int bit)
50 return 1<<(bit & (8-1));
53 void magician_egpio_enable (struct platform_device *dev, int bit)
55 unsigned long flags;
56 struct magician_cpld_data *cpld = platform_get_drvdata(dev);
57 int pos = u8pos(bit);
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)
70 unsigned long flags;
71 struct magician_cpld_data *cpld = platform_get_drvdata(dev);
72 int pos = u8pos(bit);
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;
121 switch (result) {
122 case 0x1:
123 irq = IRQ_MAGICIAN_SD;
124 desc = &irq_desc[irq];
125 desc_handle_irq(irq, desc);
126 break;
127 case 0x2:
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);
132 break;
133 case 0x8:
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);
138 break;
139 case 0xc:
140 irq = IRQ_MAGICIAN_USBC;
141 desc = &irq_desc[irq];
142 desc_handle_irq(irq, desc);
143 break;
144 default:
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);
155 if (!cpld)
156 return -ENOMEM;
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");
165 kfree (cpld);
166 return -ENOMEM;
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) {
184 unsigned int irq;
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);
200 return 0;
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) {
208 unsigned int irq;
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);
220 kfree(cpld);
221 platform_set_drvdata(dev, NULL);
223 return 0;
227 struct platform_driver magician_cpld_driver = {
228 .probe = magician_cpld_probe,
229 .remove = magician_cpld_remove,
230 .driver = {
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);