blob: 164bc9801ed72246312144a59e89d80f492ca292 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/mach-sa1100/neponset.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 */
Russell King9590e892012-01-24 22:36:47 +00004#include <linux/err.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <linux/ioport.h>
Russell King92e617d2012-01-24 22:13:00 +00007#include <linux/kernel.h>
Russell Kingae14c2e2012-01-24 22:10:02 +00008#include <linux/module.h>
Russell Kingd052d1b2005-10-29 19:07:23 +01009#include <linux/platform_device.h>
Russell King92e617d2012-01-24 22:13:00 +000010#include <linux/serial_core.h>
Russell Kingae14c2e2012-01-24 22:10:02 +000011#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <asm/mach-types.h>
14#include <asm/irq.h>
15#include <asm/mach/map.h>
16#include <asm/mach/irq.h>
17#include <asm/mach/serial_sa1100.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/hardware/sa1111.h>
19#include <asm/sizes.h>
20
Russell King92e617d2012-01-24 22:13:00 +000021#include <mach/hardware.h>
22#include <mach/assabet.h>
23#include <mach/neponset.h>
24
Russell Kingae14c2e2012-01-24 22:10:02 +000025struct neponset_drvdata {
Russell King9590e892012-01-24 22:36:47 +000026 struct platform_device *sa1111;
27 struct platform_device *smc91x;
Russell Kingae14c2e2012-01-24 22:10:02 +000028#ifdef CONFIG_PM_SLEEP
29 u32 ncr0;
30 u32 mdm_ctl_0;
31#endif
32};
33
Russell King6ad1b612012-01-16 09:31:47 +000034void neponset_ncr_frob(unsigned int mask, unsigned int val)
35{
36 unsigned long flags;
37
38 local_irq_save(flags);
39 NCR_0 = (NCR_0 & ~mask) | val;
40 local_irq_restore(flags);
41}
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
44{
45 u_int mdm_ctl0 = MDM_CTL_0;
46
47 if (port->mapbase == _Ser1UTCR0) {
48 if (mctrl & TIOCM_RTS)
49 mdm_ctl0 &= ~MDM_CTL0_RTS2;
50 else
51 mdm_ctl0 |= MDM_CTL0_RTS2;
52
53 if (mctrl & TIOCM_DTR)
54 mdm_ctl0 &= ~MDM_CTL0_DTR2;
55 else
56 mdm_ctl0 |= MDM_CTL0_DTR2;
57 } else if (port->mapbase == _Ser3UTCR0) {
58 if (mctrl & TIOCM_RTS)
59 mdm_ctl0 &= ~MDM_CTL0_RTS1;
60 else
61 mdm_ctl0 |= MDM_CTL0_RTS1;
62
63 if (mctrl & TIOCM_DTR)
64 mdm_ctl0 &= ~MDM_CTL0_DTR1;
65 else
66 mdm_ctl0 |= MDM_CTL0_DTR1;
67 }
68
69 MDM_CTL_0 = mdm_ctl0;
70}
71
72static u_int neponset_get_mctrl(struct uart_port *port)
73{
74 u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
75 u_int mdm_ctl1 = MDM_CTL_1;
76
77 if (port->mapbase == _Ser1UTCR0) {
78 if (mdm_ctl1 & MDM_CTL1_DCD2)
79 ret &= ~TIOCM_CD;
80 if (mdm_ctl1 & MDM_CTL1_CTS2)
81 ret &= ~TIOCM_CTS;
82 if (mdm_ctl1 & MDM_CTL1_DSR2)
83 ret &= ~TIOCM_DSR;
84 } else if (port->mapbase == _Ser3UTCR0) {
85 if (mdm_ctl1 & MDM_CTL1_DCD1)
86 ret &= ~TIOCM_CD;
87 if (mdm_ctl1 & MDM_CTL1_CTS1)
88 ret &= ~TIOCM_CTS;
89 if (mdm_ctl1 & MDM_CTL1_DSR1)
90 ret &= ~TIOCM_DSR;
91 }
92
93 return ret;
94}
95
Russell Kingcdea4602007-05-30 17:48:45 +010096static struct sa1100_port_fns neponset_port_fns __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 .set_mctrl = neponset_set_mctrl,
98 .get_mctrl = neponset_get_mctrl,
99};
100
Russell King71045522012-01-16 00:17:41 +0000101/*
Russell King92e617d2012-01-24 22:13:00 +0000102 * Install handler for Neponset IRQ. Note that we have to loop here
103 * since the ETHERNET and USAR IRQs are level based, and we need to
104 * ensure that the IRQ signal is deasserted before returning. This
105 * is rather unfortunate.
106 */
107static void
108neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
109{
110 unsigned int irr;
111
112 while (1) {
113 /*
114 * Acknowledge the parent IRQ.
115 */
116 desc->irq_data.chip->irq_ack(&desc->irq_data);
117
118 /*
119 * Read the interrupt reason register. Let's have all
120 * active IRQ bits high. Note: there is a typo in the
121 * Neponset user's guide for the SA1111 IRR level.
122 */
123 irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
124
125 if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
126 break;
127
128 /*
129 * Since there is no individual mask, we have to
130 * mask the parent IRQ. This is safe, since we'll
131 * recheck the register for any pending IRQs.
132 */
133 if (irr & (IRR_ETHERNET | IRR_USAR)) {
134 desc->irq_data.chip->irq_mask(&desc->irq_data);
135
136 /*
137 * Ack the interrupt now to prevent re-entering
138 * this neponset handler. Again, this is safe
139 * since we'll check the IRR register prior to
140 * leaving.
141 */
142 desc->irq_data.chip->irq_ack(&desc->irq_data);
143
144 if (irr & IRR_ETHERNET) {
145 generic_handle_irq(IRQ_NEPONSET_SMC9196);
146 }
147
148 if (irr & IRR_USAR) {
149 generic_handle_irq(IRQ_NEPONSET_USAR);
150 }
151
152 desc->irq_data.chip->irq_unmask(&desc->irq_data);
153 }
154
155 if (irr & IRR_SA1111) {
156 generic_handle_irq(IRQ_NEPONSET_SA1111);
157 }
158 }
159}
160
161/*
Russell King71045522012-01-16 00:17:41 +0000162 * Yes, we really do not have any kind of masking or unmasking
163 */
164static void nochip_noop(struct irq_data *irq)
165{
166}
167
168static struct irq_chip nochip = {
169 .name = "neponset",
170 .irq_ack = nochip_noop,
171 .irq_mask = nochip_noop,
172 .irq_unmask = nochip_noop,
173};
174
Russell King92e617d2012-01-24 22:13:00 +0000175static struct resource sa1111_resources[] = {
176 [0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
177 [1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SA1111),
178};
179
180static struct sa1111_platform_data sa1111_info = {
181 .irq_base = IRQ_BOARD_END,
182};
183
Russell King92e617d2012-01-24 22:13:00 +0000184static struct resource smc91x_resources[] = {
185 [0] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 0x02000000, "smc91x-regs"),
186 [1] = DEFINE_RES_IRQ(IRQ_NEPONSET_SMC9196),
187 [2] = DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
188 0x02000000, "smc91x-attrib"),
189};
190
Russell Kingcdea4602007-05-30 17:48:45 +0100191static int __devinit neponset_probe(struct platform_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Russell Kingae14c2e2012-01-24 22:10:02 +0000193 struct neponset_drvdata *d;
Russell King9590e892012-01-24 22:36:47 +0000194 struct platform_device_info sa1111_devinfo = {
195 .parent = &dev->dev,
196 .name = "sa1111",
197 .id = 0,
198 .res = sa1111_resources,
199 .num_res = ARRAY_SIZE(sa1111_resources),
200 .data = &sa1111_info,
201 .size_data = sizeof(sa1111_info),
202 .dma_mask = 0xffffffffUL,
203 };
204 struct platform_device_info smc91x_devinfo = {
205 .parent = &dev->dev,
206 .name = "smc91x",
207 .id = 0,
208 .res = smc91x_resources,
209 .num_res = ARRAY_SIZE(smc91x_resources),
210 };
Russell Kingae14c2e2012-01-24 22:10:02 +0000211 int ret;
212
213 d = kzalloc(sizeof(*d), GFP_KERNEL);
214 if (!d) {
215 ret = -ENOMEM;
216 goto err_alloc;
217 }
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 sa1100_register_uart_fns(&neponset_port_fns);
220
221 /*
222 * Install handler for GPIO25.
223 */
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100224 irq_set_irq_type(IRQ_GPIO25, IRQ_TYPE_EDGE_RISING);
225 irq_set_chained_handler(IRQ_GPIO25, neponset_irq_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
227 /*
228 * We would set IRQ_GPIO25 to be a wake-up IRQ, but
229 * unfortunately something on the Neponset activates
230 * this IRQ on sleep (ethernet?)
231 */
232#if 0
233 enable_irq_wake(IRQ_GPIO25);
234#endif
235
236 /*
237 * Setup other Neponset IRQs. SA1111 will be done by the
238 * generic SA1111 code.
239 */
Russell King71045522012-01-16 00:17:41 +0000240 irq_set_chip_and_handler(IRQ_NEPONSET_SMC9196, &nochip,
241 handle_simple_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
Russell King71045522012-01-16 00:17:41 +0000243 irq_set_chip_and_handler(IRQ_NEPONSET_USAR, &nochip,
244 handle_simple_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
Russell King71045522012-01-16 00:17:41 +0000246 irq_set_chip(IRQ_NEPONSET_SA1111, &nochip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248 /*
249 * Disable GPIO 0/1 drivers so the buttons work on the module.
250 */
251 NCR_0 = NCR_GP01_OFF;
252
Russell King9590e892012-01-24 22:36:47 +0000253 d->sa1111 = platform_device_register_full(&sa1111_devinfo);
254 d->smc91x = platform_device_register_full(&smc91x_devinfo);
255
Russell Kingae14c2e2012-01-24 22:10:02 +0000256 platform_set_drvdata(dev, d);
257
258 return 0;
259
260 err_alloc:
261 return ret;
262}
263
264static int __devexit neponset_remove(struct platform_device *dev)
265{
266 struct neponset_drvdata *d = platform_get_drvdata(dev);
267
Russell King9590e892012-01-24 22:36:47 +0000268 if (!IS_ERR(d->sa1111))
269 platform_device_unregister(d->sa1111);
270 if (!IS_ERR(d->smc91x))
271 platform_device_unregister(d->smc91x);
Russell Kingae14c2e2012-01-24 22:10:02 +0000272 irq_set_chained_handler(IRQ_GPIO25, NULL);
273
274 kfree(d);
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return 0;
277}
278
279#ifdef CONFIG_PM
Russell King3ae5eae2005-11-09 22:32:44 +0000280static int neponset_suspend(struct platform_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Russell Kingae14c2e2012-01-24 22:10:02 +0000282 struct neponset_drvdata *d = platform_get_drvdata(dev);
283
284 d->ncr0 = NCR_0;
285 d->mdm_ctl_0 = MDM_CTL_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 return 0;
288}
289
Russell King3ae5eae2005-11-09 22:32:44 +0000290static int neponset_resume(struct platform_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
Russell Kingae14c2e2012-01-24 22:10:02 +0000292 struct neponset_drvdata *d = platform_get_drvdata(dev);
293
294 NCR_0 = d->ncr0;
295 MDM_CTL_0 = d->mdm_ctl_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 return 0;
298}
299
300#else
301#define neponset_suspend NULL
302#define neponset_resume NULL
303#endif
304
Russell King3ae5eae2005-11-09 22:32:44 +0000305static struct platform_driver neponset_device_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 .probe = neponset_probe,
Russell Kingae14c2e2012-01-24 22:10:02 +0000307 .remove = __devexit_p(neponset_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 .suspend = neponset_suspend,
309 .resume = neponset_resume,
Russell King3ae5eae2005-11-09 22:32:44 +0000310 .driver = {
311 .name = "neponset",
Russell King398e58d2012-01-24 23:33:28 +0000312 .owner = THIS_MODULE,
Russell King3ae5eae2005-11-09 22:32:44 +0000313 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314};
315
316static struct resource neponset_resources[] = {
Russell Kinga1810992012-01-12 10:25:29 +0000317 [0] = DEFINE_RES_MEM(0x10000000, 0x08000000),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318};
319
320static struct platform_device neponset_device = {
321 .name = "neponset",
322 .id = 0,
323 .num_resources = ARRAY_SIZE(neponset_resources),
324 .resource = neponset_resources,
325};
326
Russell Kingcdcb81f2007-07-20 10:32:46 +0100327extern void sa1110_mb_disable(void);
328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static int __init neponset_init(void)
330{
Russell King3ae5eae2005-11-09 22:32:44 +0000331 platform_driver_register(&neponset_device_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 /*
334 * The Neponset is only present on the Assabet machine type.
335 */
336 if (!machine_is_assabet())
337 return -ENODEV;
338
339 /*
340 * Ensure that the memory bus request/grant signals are setup,
341 * and the grant is held in its inactive state, whether or not
342 * we actually have a Neponset attached.
343 */
344 sa1110_mb_disable();
345
346 if (!machine_has_neponset()) {
347 printk(KERN_DEBUG "Neponset expansion board not present\n");
348 return -ENODEV;
349 }
350
351 if (WHOAMI != 0x11) {
352 printk(KERN_WARNING "Neponset board detected, but "
353 "wrong ID: %02x\n", WHOAMI);
354 return -ENODEV;
355 }
356
Russell King9590e892012-01-24 22:36:47 +0000357 return platform_device_register(&neponset_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
359
360subsys_initcall(neponset_init);
361
362static struct map_desc neponset_io_desc[] __initdata = {
Deepak Saxena92519d82005-10-28 15:19:04 +0100363 { /* System Registers */
364 .virtual = 0xf3000000,
365 .pfn = __phys_to_pfn(0x10000000),
366 .length = SZ_1M,
367 .type = MT_DEVICE
368 }, { /* SA-1111 */
369 .virtual = 0xf4000000,
370 .pfn = __phys_to_pfn(0x40000000),
371 .length = SZ_1M,
372 .type = MT_DEVICE
373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374};
375
376void __init neponset_map_io(void)
377{
378 iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
379}