11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/mach-sa1100/neponset.c 31da177e4SLinus Torvalds */ 49590e898SRussell King #include <linux/err.h> 51da177e4SLinus Torvalds #include <linux/init.h> 61da177e4SLinus Torvalds #include <linux/ioport.h> 7ced8d21cSRussell King #include <linux/irq.h> 892e617d9SRussell King #include <linux/kernel.h> 9ae14c2e2SRussell King #include <linux/module.h> 10d052d1beSRussell King #include <linux/platform_device.h> 1151f93390SRussell King #include <linux/pm.h> 1292e617d9SRussell King #include <linux/serial_core.h> 13ae14c2e2SRussell King #include <linux/slab.h> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <asm/mach-types.h> 161da177e4SLinus Torvalds #include <asm/mach/map.h> 171da177e4SLinus Torvalds #include <asm/mach/serial_sa1100.h> 181da177e4SLinus Torvalds #include <asm/hardware/sa1111.h> 191da177e4SLinus Torvalds #include <asm/sizes.h> 201da177e4SLinus Torvalds 2192e617d9SRussell King #include <mach/hardware.h> 2292e617d9SRussell King #include <mach/assabet.h> 2392e617d9SRussell King #include <mach/neponset.h> 2492e617d9SRussell King 25ced8d21cSRussell King #define NEP_IRQ_SMC91X 0 26ced8d21cSRussell King #define NEP_IRQ_USAR 1 27ced8d21cSRussell King #define NEP_IRQ_SA1111 2 28ced8d21cSRussell King #define NEP_IRQ_NR 3 29ced8d21cSRussell King 30bab50a35SRussell King extern void sa1110_mb_disable(void); 31bab50a35SRussell King 32ae14c2e2SRussell King struct neponset_drvdata { 339590e898SRussell King struct platform_device *sa1111; 349590e898SRussell King struct platform_device *smc91x; 35ced8d21cSRussell King unsigned irq_base; 36ae14c2e2SRussell King #ifdef CONFIG_PM_SLEEP 37ae14c2e2SRussell King u32 ncr0; 38ae14c2e2SRussell King u32 mdm_ctl_0; 39ae14c2e2SRussell King #endif 40ae14c2e2SRussell King }; 41ae14c2e2SRussell King 426ad1b614SRussell King void neponset_ncr_frob(unsigned int mask, unsigned int val) 436ad1b614SRussell King { 446ad1b614SRussell King unsigned long flags; 456ad1b614SRussell King 466ad1b614SRussell King local_irq_save(flags); 476ad1b614SRussell King NCR_0 = (NCR_0 & ~mask) | val; 486ad1b614SRussell King local_irq_restore(flags); 496ad1b614SRussell King } 506ad1b614SRussell King 511da177e4SLinus Torvalds static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds u_int mdm_ctl0 = MDM_CTL_0; 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 561da177e4SLinus Torvalds if (mctrl & TIOCM_RTS) 571da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_RTS2; 581da177e4SLinus Torvalds else 591da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_RTS2; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds if (mctrl & TIOCM_DTR) 621da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_DTR2; 631da177e4SLinus Torvalds else 641da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_DTR2; 651da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 661da177e4SLinus Torvalds if (mctrl & TIOCM_RTS) 671da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_RTS1; 681da177e4SLinus Torvalds else 691da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_RTS1; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds if (mctrl & TIOCM_DTR) 721da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_DTR1; 731da177e4SLinus Torvalds else 741da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_DTR1; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds MDM_CTL_0 = mdm_ctl0; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds static u_int neponset_get_mctrl(struct uart_port *port) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; 831da177e4SLinus Torvalds u_int mdm_ctl1 = MDM_CTL_1; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 861da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD2) 871da177e4SLinus Torvalds ret &= ~TIOCM_CD; 881da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS2) 891da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 901da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR2) 911da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 921da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 931da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD1) 941da177e4SLinus Torvalds ret &= ~TIOCM_CD; 951da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS1) 961da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 971da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR1) 981da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds return ret; 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 104cdea4606SRussell King static struct sa1100_port_fns neponset_port_fns __devinitdata = { 1051da177e4SLinus Torvalds .set_mctrl = neponset_set_mctrl, 1061da177e4SLinus Torvalds .get_mctrl = neponset_get_mctrl, 1071da177e4SLinus Torvalds }; 1081da177e4SLinus Torvalds 10971045520SRussell King /* 11092e617d9SRussell King * Install handler for Neponset IRQ. Note that we have to loop here 11192e617d9SRussell King * since the ETHERNET and USAR IRQs are level based, and we need to 11292e617d9SRussell King * ensure that the IRQ signal is deasserted before returning. This 11392e617d9SRussell King * is rather unfortunate. 11492e617d9SRussell King */ 115ced8d21cSRussell King static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc) 11692e617d9SRussell King { 117ced8d21cSRussell King struct neponset_drvdata *d = irq_desc_get_handler_data(desc); 11892e617d9SRussell King unsigned int irr; 11992e617d9SRussell King 12092e617d9SRussell King while (1) { 12192e617d9SRussell King /* 12292e617d9SRussell King * Acknowledge the parent IRQ. 12392e617d9SRussell King */ 12492e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 12592e617d9SRussell King 12692e617d9SRussell King /* 12792e617d9SRussell King * Read the interrupt reason register. Let's have all 12892e617d9SRussell King * active IRQ bits high. Note: there is a typo in the 12992e617d9SRussell King * Neponset user's guide for the SA1111 IRR level. 13092e617d9SRussell King */ 13192e617d9SRussell King irr = IRR ^ (IRR_ETHERNET | IRR_USAR); 13292e617d9SRussell King 13392e617d9SRussell King if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) 13492e617d9SRussell King break; 13592e617d9SRussell King 13692e617d9SRussell King /* 13792e617d9SRussell King * Since there is no individual mask, we have to 13892e617d9SRussell King * mask the parent IRQ. This is safe, since we'll 13992e617d9SRussell King * recheck the register for any pending IRQs. 14092e617d9SRussell King */ 14192e617d9SRussell King if (irr & (IRR_ETHERNET | IRR_USAR)) { 14292e617d9SRussell King desc->irq_data.chip->irq_mask(&desc->irq_data); 14392e617d9SRussell King 14492e617d9SRussell King /* 14592e617d9SRussell King * Ack the interrupt now to prevent re-entering 14692e617d9SRussell King * this neponset handler. Again, this is safe 14792e617d9SRussell King * since we'll check the IRR register prior to 14892e617d9SRussell King * leaving. 14992e617d9SRussell King */ 15092e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 15192e617d9SRussell King 152ced8d21cSRussell King if (irr & IRR_ETHERNET) 153ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X); 15492e617d9SRussell King 155ced8d21cSRussell King if (irr & IRR_USAR) 156ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_USAR); 15792e617d9SRussell King 15892e617d9SRussell King desc->irq_data.chip->irq_unmask(&desc->irq_data); 15992e617d9SRussell King } 16092e617d9SRussell King 161ced8d21cSRussell King if (irr & IRR_SA1111) 162ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SA1111); 16392e617d9SRussell King } 16492e617d9SRussell King } 16592e617d9SRussell King 166ced8d21cSRussell King /* Yes, we really do not have any kind of masking or unmasking */ 16771045520SRussell King static void nochip_noop(struct irq_data *irq) 16871045520SRussell King { 16971045520SRussell King } 17071045520SRussell King 17171045520SRussell King static struct irq_chip nochip = { 17271045520SRussell King .name = "neponset", 17371045520SRussell King .irq_ack = nochip_noop, 17471045520SRussell King .irq_mask = nochip_noop, 17571045520SRussell King .irq_unmask = nochip_noop, 17671045520SRussell King }; 17771045520SRussell King 17892e617d9SRussell King static struct sa1111_platform_data sa1111_info = { 17992e617d9SRussell King .irq_base = IRQ_BOARD_END, 18092e617d9SRussell King }; 18192e617d9SRussell King 182cdea4606SRussell King static int __devinit neponset_probe(struct platform_device *dev) 1831da177e4SLinus Torvalds { 184ae14c2e2SRussell King struct neponset_drvdata *d; 185d2e539a5SRussell King struct resource *sa1111_res, *smc91x_res; 186ced8d21cSRussell King struct resource sa1111_resources[] = { 187ced8d21cSRussell King DEFINE_RES_MEM(0x40000000, SZ_8K), 188ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 189ced8d21cSRussell King }; 1909590e898SRussell King struct platform_device_info sa1111_devinfo = { 1919590e898SRussell King .parent = &dev->dev, 1929590e898SRussell King .name = "sa1111", 1939590e898SRussell King .id = 0, 1949590e898SRussell King .res = sa1111_resources, 1959590e898SRussell King .num_res = ARRAY_SIZE(sa1111_resources), 1969590e898SRussell King .data = &sa1111_info, 1979590e898SRussell King .size_data = sizeof(sa1111_info), 1989590e898SRussell King .dma_mask = 0xffffffffUL, 1999590e898SRussell King }; 200ced8d21cSRussell King struct resource smc91x_resources[] = { 201ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 202ced8d21cSRussell King 0x02000000, "smc91x-regs"), 203ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, 204ced8d21cSRussell King 0x02000000, "smc91x-attrib"), 205ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 206ced8d21cSRussell King }; 2079590e898SRussell King struct platform_device_info smc91x_devinfo = { 2089590e898SRussell King .parent = &dev->dev, 2099590e898SRussell King .name = "smc91x", 2109590e898SRussell King .id = 0, 2119590e898SRussell King .res = smc91x_resources, 2129590e898SRussell King .num_res = ARRAY_SIZE(smc91x_resources), 2139590e898SRussell King }; 214b6bdfcf5SRussell King int ret, irq; 215b6bdfcf5SRussell King 216b6bdfcf5SRussell King irq = ret = platform_get_irq(dev, 0); 217b6bdfcf5SRussell King if (ret < 0) 218b6bdfcf5SRussell King goto err_alloc; 219ae14c2e2SRussell King 220d2e539a5SRussell King smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1); 221d2e539a5SRussell King sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2); 222d2e539a5SRussell King if (!smc91x_res || !sa1111_res) { 223d2e539a5SRussell King ret = -ENXIO; 224d2e539a5SRussell King goto err_alloc; 225d2e539a5SRussell King } 226d2e539a5SRussell King 227bab50a35SRussell King if (WHOAMI != 0x11) { 228bab50a35SRussell King dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n", 229bab50a35SRussell King WHOAMI); 230bab50a35SRussell King ret = -ENODEV; 231bab50a35SRussell King goto err_alloc; 232bab50a35SRussell King } 233bab50a35SRussell King 234ae14c2e2SRussell King d = kzalloc(sizeof(*d), GFP_KERNEL); 235ae14c2e2SRussell King if (!d) { 236ae14c2e2SRussell King ret = -ENOMEM; 237ae14c2e2SRussell King goto err_alloc; 238ae14c2e2SRussell King } 239ae14c2e2SRussell King 240ced8d21cSRussell King ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1); 241ced8d21cSRussell King if (ret <= 0) { 242ced8d21cSRussell King dev_err(&dev->dev, "unable to allocate %u irqs: %d\n", 243ced8d21cSRussell King NEP_IRQ_NR, ret); 244ced8d21cSRussell King if (ret == 0) 245ced8d21cSRussell King ret = -ENOMEM; 246ced8d21cSRussell King goto err_irq_alloc; 247ced8d21cSRussell King } 2481da177e4SLinus Torvalds 249ced8d21cSRussell King d->irq_base = ret; 250ced8d21cSRussell King 251ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, 252ced8d21cSRussell King handle_simple_irq); 253ced8d21cSRussell King set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE); 254ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, 255ced8d21cSRussell King handle_simple_irq); 256ced8d21cSRussell King set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE); 257ced8d21cSRussell King irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); 258ced8d21cSRussell King 259b6bdfcf5SRussell King irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); 260b6bdfcf5SRussell King irq_set_handler_data(irq, d); 261b6bdfcf5SRussell King irq_set_chained_handler(irq, neponset_irq_handler); 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /* 264ced8d21cSRussell King * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately 265ced8d21cSRussell King * something on the Neponset activates this IRQ on sleep (eth?) 2661da177e4SLinus Torvalds */ 2671da177e4SLinus Torvalds #if 0 268b6bdfcf5SRussell King enable_irq_wake(irq); 2691da177e4SLinus Torvalds #endif 2701da177e4SLinus Torvalds 271ced8d21cSRussell King dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n", 272ced8d21cSRussell King d->irq_base, d->irq_base + NEP_IRQ_NR - 1); 2731da177e4SLinus Torvalds 274ced8d21cSRussell King sa1100_register_uart_fns(&neponset_port_fns); 275ced8d21cSRussell King 276bab50a35SRussell King /* Ensure that the memory bus request/grant signals are setup */ 277bab50a35SRussell King sa1110_mb_disable(); 278bab50a35SRussell King 279ced8d21cSRussell King /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */ 2801da177e4SLinus Torvalds NCR_0 = NCR_GP01_OFF; 2811da177e4SLinus Torvalds 282d2e539a5SRussell King sa1111_resources[0].parent = sa1111_res; 283ced8d21cSRussell King sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111; 284ced8d21cSRussell King sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111; 2859590e898SRussell King d->sa1111 = platform_device_register_full(&sa1111_devinfo); 286ced8d21cSRussell King 287d2e539a5SRussell King smc91x_resources[0].parent = smc91x_res; 288d2e539a5SRussell King smc91x_resources[1].parent = smc91x_res; 289ced8d21cSRussell King smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X; 290ced8d21cSRussell King smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X; 2919590e898SRussell King d->smc91x = platform_device_register_full(&smc91x_devinfo); 2929590e898SRussell King 293ae14c2e2SRussell King platform_set_drvdata(dev, d); 294ae14c2e2SRussell King 295ae14c2e2SRussell King return 0; 296ae14c2e2SRussell King 297ced8d21cSRussell King err_irq_alloc: 298ced8d21cSRussell King kfree(d); 299ae14c2e2SRussell King err_alloc: 300ae14c2e2SRussell King return ret; 301ae14c2e2SRussell King } 302ae14c2e2SRussell King 303ae14c2e2SRussell King static int __devexit neponset_remove(struct platform_device *dev) 304ae14c2e2SRussell King { 305ae14c2e2SRussell King struct neponset_drvdata *d = platform_get_drvdata(dev); 306b6bdfcf5SRussell King int irq = platform_get_irq(dev, 0); 307ae14c2e2SRussell King 3089590e898SRussell King if (!IS_ERR(d->sa1111)) 3099590e898SRussell King platform_device_unregister(d->sa1111); 3109590e898SRussell King if (!IS_ERR(d->smc91x)) 3119590e898SRussell King platform_device_unregister(d->smc91x); 312b6bdfcf5SRussell King irq_set_chained_handler(irq, NULL); 313ced8d21cSRussell King irq_free_descs(d->irq_base, NEP_IRQ_NR); 314ae14c2e2SRussell King kfree(d); 315ae14c2e2SRussell King 3161da177e4SLinus Torvalds return 0; 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 31951f93390SRussell King #ifdef CONFIG_PM_SLEEP 32051f93390SRussell King static int neponset_suspend(struct device *dev) 3211da177e4SLinus Torvalds { 32251f93390SRussell King struct neponset_drvdata *d = dev_get_drvdata(dev); 323ae14c2e2SRussell King 324ae14c2e2SRussell King d->ncr0 = NCR_0; 325ae14c2e2SRussell King d->mdm_ctl_0 = MDM_CTL_0; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds return 0; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 33051f93390SRussell King static int neponset_resume(struct device *dev) 3311da177e4SLinus Torvalds { 33251f93390SRussell King struct neponset_drvdata *d = dev_get_drvdata(dev); 333ae14c2e2SRussell King 334ae14c2e2SRussell King NCR_0 = d->ncr0; 335ae14c2e2SRussell King MDM_CTL_0 = d->mdm_ctl_0; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds return 0; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 34051f93390SRussell King static const struct dev_pm_ops neponset_pm_ops = { 34151f93390SRussell King .suspend_noirq = neponset_suspend, 34251f93390SRussell King .resume_noirq = neponset_resume, 34351f93390SRussell King .freeze_noirq = neponset_suspend, 34451f93390SRussell King .restore_noirq = neponset_resume, 34551f93390SRussell King }; 34651f93390SRussell King #define PM_OPS &neponset_pm_ops 3471da177e4SLinus Torvalds #else 34851f93390SRussell King #define PM_OPS NULL 3491da177e4SLinus Torvalds #endif 3501da177e4SLinus Torvalds 3513ae5eaecSRussell King static struct platform_driver neponset_device_driver = { 3521da177e4SLinus Torvalds .probe = neponset_probe, 353ae14c2e2SRussell King .remove = __devexit_p(neponset_remove), 3543ae5eaecSRussell King .driver = { 3553ae5eaecSRussell King .name = "neponset", 356398e58d0SRussell King .owner = THIS_MODULE, 35751f93390SRussell King .pm = PM_OPS, 3583ae5eaecSRussell King }, 3591da177e4SLinus Torvalds }; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds static int __init neponset_init(void) 3621da177e4SLinus Torvalds { 363bab50a35SRussell King return platform_driver_register(&neponset_device_driver); 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds subsys_initcall(neponset_init); 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds static struct map_desc neponset_io_desc[] __initdata = { 36992519d82SDeepak Saxena { /* System Registers */ 37092519d82SDeepak Saxena .virtual = 0xf3000000, 37192519d82SDeepak Saxena .pfn = __phys_to_pfn(0x10000000), 37292519d82SDeepak Saxena .length = SZ_1M, 37392519d82SDeepak Saxena .type = MT_DEVICE 37492519d82SDeepak Saxena }, { /* SA-1111 */ 37592519d82SDeepak Saxena .virtual = 0xf4000000, 37692519d82SDeepak Saxena .pfn = __phys_to_pfn(0x40000000), 37792519d82SDeepak Saxena .length = SZ_1M, 37892519d82SDeepak Saxena .type = MT_DEVICE 37992519d82SDeepak Saxena } 3801da177e4SLinus Torvalds }; 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds void __init neponset_map_io(void) 3831da177e4SLinus Torvalds { 3841da177e4SLinus Torvalds iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc)); 3851da177e4SLinus Torvalds } 386