1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/arch/arm/mach-sa1100/neponset.c 41da177e4SLinus Torvalds */ 59590e898SRussell King #include <linux/err.h> 6f85fac0eSRussell King #include <linux/gpio/driver.h> 7f85fac0eSRussell King #include <linux/gpio/gpio-reg.h> 8e2125d05SRussell King #include <linux/gpio/machine.h> 91da177e4SLinus Torvalds #include <linux/init.h> 101da177e4SLinus Torvalds #include <linux/ioport.h> 11ced8d21cSRussell King #include <linux/irq.h> 1292e617d9SRussell King #include <linux/kernel.h> 13ae14c2e2SRussell King #include <linux/module.h> 146920b5a7SRussell King #include <linux/platform_data/sa11x0-serial.h> 15d052d1beSRussell King #include <linux/platform_device.h> 1651f93390SRussell King #include <linux/pm.h> 1792e617d9SRussell King #include <linux/serial_core.h> 18ae14c2e2SRussell King #include <linux/slab.h> 19b70661c7SArnd Bergmann #include <linux/smc91x.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include <asm/mach-types.h> 221da177e4SLinus Torvalds #include <asm/mach/map.h> 231da177e4SLinus Torvalds #include <asm/hardware/sa1111.h> 241da177e4SLinus Torvalds #include <asm/sizes.h> 251da177e4SLinus Torvalds 2692e617d9SRussell King #include <mach/hardware.h> 2792e617d9SRussell King #include <mach/assabet.h> 2892e617d9SRussell King #include <mach/neponset.h> 29f314f33bSRob Herring #include <mach/irqs.h> 3092e617d9SRussell King 31ced8d21cSRussell King #define NEP_IRQ_SMC91X 0 32ced8d21cSRussell King #define NEP_IRQ_USAR 1 33ced8d21cSRussell King #define NEP_IRQ_SA1111 2 34ced8d21cSRussell King #define NEP_IRQ_NR 3 35ced8d21cSRussell King 36f942b0fdSRussell King #define WHOAMI 0x00 37f942b0fdSRussell King #define LEDS 0x10 38f942b0fdSRussell King #define SWPK 0x20 39f942b0fdSRussell King #define IRR 0x24 40f942b0fdSRussell King #define KP_Y_IN 0x80 41f942b0fdSRussell King #define KP_X_OUT 0x90 42f942b0fdSRussell King #define NCR_0 0xa0 43f942b0fdSRussell King #define MDM_CTL_0 0xb0 44f942b0fdSRussell King #define MDM_CTL_1 0xb4 45f942b0fdSRussell King #define AUD_CTL 0xc0 46f942b0fdSRussell King 47f942b0fdSRussell King #define IRR_ETHERNET (1 << 0) 48f942b0fdSRussell King #define IRR_USAR (1 << 1) 49f942b0fdSRussell King #define IRR_SA1111 (1 << 2) 50f942b0fdSRussell King 51f85fac0eSRussell King #define NCR_NGPIO 7 52f85fac0eSRussell King 53f942b0fdSRussell King #define MDM_CTL0_RTS1 (1 << 0) 54f942b0fdSRussell King #define MDM_CTL0_DTR1 (1 << 1) 55f942b0fdSRussell King #define MDM_CTL0_RTS2 (1 << 2) 56f942b0fdSRussell King #define MDM_CTL0_DTR2 (1 << 3) 57f85fac0eSRussell King #define MDM_CTL0_NGPIO 4 58f942b0fdSRussell King 59f942b0fdSRussell King #define MDM_CTL1_CTS1 (1 << 0) 60f942b0fdSRussell King #define MDM_CTL1_DSR1 (1 << 1) 61f942b0fdSRussell King #define MDM_CTL1_DCD1 (1 << 2) 62f942b0fdSRussell King #define MDM_CTL1_CTS2 (1 << 3) 63f942b0fdSRussell King #define MDM_CTL1_DSR2 (1 << 4) 64f942b0fdSRussell King #define MDM_CTL1_DCD2 (1 << 5) 65f85fac0eSRussell King #define MDM_CTL1_NGPIO 6 66f942b0fdSRussell King 67f942b0fdSRussell King #define AUD_SEL_1341 (1 << 0) 68f942b0fdSRussell King #define AUD_MUTE_1341 (1 << 1) 69f85fac0eSRussell King #define AUD_NGPIO 2 70f942b0fdSRussell King 71bab50a35SRussell King extern void sa1110_mb_disable(void); 72bab50a35SRussell King 73f85fac0eSRussell King #define to_neponset_gpio_chip(x) container_of(x, struct neponset_gpio_chip, gc) 74f85fac0eSRussell King 75f85fac0eSRussell King static const char *neponset_ncr_names[] = { 76f85fac0eSRussell King "gp01_off", "tp_power", "ms_power", "enet_osc", 77f85fac0eSRussell King "spi_kb_wk_up", "a0vpp", "a1vpp" 78f85fac0eSRussell King }; 79f85fac0eSRussell King 80f85fac0eSRussell King static const char *neponset_mdmctl0_names[] = { 81f85fac0eSRussell King "rts3", "dtr3", "rts1", "dtr1", 82f85fac0eSRussell King }; 83f85fac0eSRussell King 84f85fac0eSRussell King static const char *neponset_mdmctl1_names[] = { 85f85fac0eSRussell King "cts3", "dsr3", "dcd3", "cts1", "dsr1", "dcd1" 86f85fac0eSRussell King }; 87f85fac0eSRussell King 88f85fac0eSRussell King static const char *neponset_aud_names[] = { 89f85fac0eSRussell King "sel_1341", "mute_1341", 90f85fac0eSRussell King }; 91f85fac0eSRussell King 92ae14c2e2SRussell King struct neponset_drvdata { 93f942b0fdSRussell King void __iomem *base; 949590e898SRussell King struct platform_device *sa1111; 959590e898SRussell King struct platform_device *smc91x; 96ced8d21cSRussell King unsigned irq_base; 97f85fac0eSRussell King struct gpio_chip *gpio[4]; 98ae14c2e2SRussell King }; 99ae14c2e2SRussell King 100e2125d05SRussell King static struct gpiod_lookup_table neponset_pcmcia_table = { 101e2125d05SRussell King .dev_id = "1800", 102e2125d05SRussell King .table = { 103e2125d05SRussell King GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH), 104e2125d05SRussell King GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH), 105e2125d05SRussell King GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH), 106e2125d05SRussell King GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH), 107e2125d05SRussell King GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH), 108e2125d05SRussell King GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH), 109e2125d05SRussell King { }, 110e2125d05SRussell King }, 111e2125d05SRussell King }; 112e2125d05SRussell King 113f85fac0eSRussell King static struct neponset_drvdata *nep; 114f942b0fdSRussell King 1156ad1b614SRussell King void neponset_ncr_frob(unsigned int mask, unsigned int val) 1166ad1b614SRussell King { 117f85fac0eSRussell King struct neponset_drvdata *n = nep; 118f85fac0eSRussell King unsigned long m = mask, v = val; 119f942b0fdSRussell King 120f85fac0eSRussell King if (nep) 121f85fac0eSRussell King n->gpio[0]->set_multiple(n->gpio[0], &m, &v); 122f85fac0eSRussell King else 123f85fac0eSRussell King WARN(1, "nep unset\n"); 1246ad1b614SRussell King } 125ef0c1484SRussell King EXPORT_SYMBOL(neponset_ncr_frob); 1266ad1b614SRussell King 1271da177e4SLinus Torvalds static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) 1281da177e4SLinus Torvalds { 129f85fac0eSRussell King struct neponset_drvdata *n = nep; 130f85fac0eSRussell King unsigned long mask, val = 0; 1311da177e4SLinus Torvalds 132f85fac0eSRussell King if (!n) 133f942b0fdSRussell King return; 134f942b0fdSRussell King 1351da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 136f85fac0eSRussell King mask = MDM_CTL0_RTS2 | MDM_CTL0_DTR2; 1371da177e4SLinus Torvalds 138f85fac0eSRussell King if (!(mctrl & TIOCM_RTS)) 139f85fac0eSRussell King val |= MDM_CTL0_RTS2; 140f85fac0eSRussell King 141f85fac0eSRussell King if (!(mctrl & TIOCM_DTR)) 142f85fac0eSRussell King val |= MDM_CTL0_DTR2; 1431da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 144f85fac0eSRussell King mask = MDM_CTL0_RTS1 | MDM_CTL0_DTR1; 1451da177e4SLinus Torvalds 146f85fac0eSRussell King if (!(mctrl & TIOCM_RTS)) 147f85fac0eSRussell King val |= MDM_CTL0_RTS1; 148f85fac0eSRussell King 149f85fac0eSRussell King if (!(mctrl & TIOCM_DTR)) 150f85fac0eSRussell King val |= MDM_CTL0_DTR1; 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 153f85fac0eSRussell King n->gpio[1]->set_multiple(n->gpio[1], &mask, &val); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static u_int neponset_get_mctrl(struct uart_port *port) 1571da177e4SLinus Torvalds { 158f85fac0eSRussell King void __iomem *base = nep->base; 1591da177e4SLinus Torvalds u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; 160f942b0fdSRussell King u_int mdm_ctl1; 1611da177e4SLinus Torvalds 162f942b0fdSRussell King if (!base) 163f942b0fdSRussell King return ret; 164f942b0fdSRussell King 165f942b0fdSRussell King mdm_ctl1 = readb_relaxed(base + MDM_CTL_1); 1661da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 1671da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD2) 1681da177e4SLinus Torvalds ret &= ~TIOCM_CD; 1691da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS2) 1701da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 1711da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR2) 1721da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 1731da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 1741da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD1) 1751da177e4SLinus Torvalds ret &= ~TIOCM_CD; 1761da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS1) 1771da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 1781da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR1) 1791da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds return ret; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 185351a102dSGreg Kroah-Hartman static struct sa1100_port_fns neponset_port_fns = { 1861da177e4SLinus Torvalds .set_mctrl = neponset_set_mctrl, 1871da177e4SLinus Torvalds .get_mctrl = neponset_get_mctrl, 1881da177e4SLinus Torvalds }; 1891da177e4SLinus Torvalds 19071045520SRussell King /* 19192e617d9SRussell King * Install handler for Neponset IRQ. Note that we have to loop here 19292e617d9SRussell King * since the ETHERNET and USAR IRQs are level based, and we need to 19392e617d9SRussell King * ensure that the IRQ signal is deasserted before returning. This 19492e617d9SRussell King * is rather unfortunate. 19592e617d9SRussell King */ 196bd0b9ac4SThomas Gleixner static void neponset_irq_handler(struct irq_desc *desc) 19792e617d9SRussell King { 198ced8d21cSRussell King struct neponset_drvdata *d = irq_desc_get_handler_data(desc); 19992e617d9SRussell King unsigned int irr; 20092e617d9SRussell King 20192e617d9SRussell King while (1) { 20292e617d9SRussell King /* 20392e617d9SRussell King * Acknowledge the parent IRQ. 20492e617d9SRussell King */ 20592e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 20692e617d9SRussell King 20792e617d9SRussell King /* 20892e617d9SRussell King * Read the interrupt reason register. Let's have all 20992e617d9SRussell King * active IRQ bits high. Note: there is a typo in the 21092e617d9SRussell King * Neponset user's guide for the SA1111 IRR level. 21192e617d9SRussell King */ 212f942b0fdSRussell King irr = readb_relaxed(d->base + IRR); 213f942b0fdSRussell King irr ^= IRR_ETHERNET | IRR_USAR; 21492e617d9SRussell King 21592e617d9SRussell King if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) 21692e617d9SRussell King break; 21792e617d9SRussell King 21892e617d9SRussell King /* 21992e617d9SRussell King * Since there is no individual mask, we have to 22092e617d9SRussell King * mask the parent IRQ. This is safe, since we'll 22192e617d9SRussell King * recheck the register for any pending IRQs. 22292e617d9SRussell King */ 22392e617d9SRussell King if (irr & (IRR_ETHERNET | IRR_USAR)) { 22492e617d9SRussell King desc->irq_data.chip->irq_mask(&desc->irq_data); 22592e617d9SRussell King 22692e617d9SRussell King /* 22792e617d9SRussell King * Ack the interrupt now to prevent re-entering 22892e617d9SRussell King * this neponset handler. Again, this is safe 22992e617d9SRussell King * since we'll check the IRR register prior to 23092e617d9SRussell King * leaving. 23192e617d9SRussell King */ 23292e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 23392e617d9SRussell King 234ced8d21cSRussell King if (irr & IRR_ETHERNET) 235ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X); 23692e617d9SRussell King 237ced8d21cSRussell King if (irr & IRR_USAR) 238ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_USAR); 23992e617d9SRussell King 24092e617d9SRussell King desc->irq_data.chip->irq_unmask(&desc->irq_data); 24192e617d9SRussell King } 24292e617d9SRussell King 243ced8d21cSRussell King if (irr & IRR_SA1111) 244ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SA1111); 24592e617d9SRussell King } 24692e617d9SRussell King } 24792e617d9SRussell King 248ced8d21cSRussell King /* Yes, we really do not have any kind of masking or unmasking */ 24971045520SRussell King static void nochip_noop(struct irq_data *irq) 25071045520SRussell King { 25171045520SRussell King } 25271045520SRussell King 25371045520SRussell King static struct irq_chip nochip = { 25471045520SRussell King .name = "neponset", 25571045520SRussell King .irq_ack = nochip_noop, 25671045520SRussell King .irq_mask = nochip_noop, 25771045520SRussell King .irq_unmask = nochip_noop, 25871045520SRussell King }; 25971045520SRussell King 260f85fac0eSRussell King static int neponset_init_gpio(struct gpio_chip **gcp, 261f85fac0eSRussell King struct device *dev, const char *label, void __iomem *reg, 262f85fac0eSRussell King unsigned num, bool in, const char *const * names) 263f85fac0eSRussell King { 264f85fac0eSRussell King struct gpio_chip *gc; 265f85fac0eSRussell King 266f85fac0eSRussell King gc = gpio_reg_init(dev, reg, -1, num, label, in ? 0xffffffff : 0, 267f85fac0eSRussell King readl_relaxed(reg), names, NULL, NULL); 268f85fac0eSRussell King if (IS_ERR(gc)) 269f85fac0eSRussell King return PTR_ERR(gc); 270f85fac0eSRussell King 271f85fac0eSRussell King *gcp = gc; 272f85fac0eSRussell King 273f85fac0eSRussell King return 0; 274f85fac0eSRussell King } 275f85fac0eSRussell King 27692e617d9SRussell King static struct sa1111_platform_data sa1111_info = { 27707be45f5SRussell King .disable_devs = SA1111_DEVID_PS2_MSE, 27892e617d9SRussell King }; 27992e617d9SRussell King 280351a102dSGreg Kroah-Hartman static int neponset_probe(struct platform_device *dev) 2811da177e4SLinus Torvalds { 282ae14c2e2SRussell King struct neponset_drvdata *d; 283f942b0fdSRussell King struct resource *nep_res, *sa1111_res, *smc91x_res; 284ced8d21cSRussell King struct resource sa1111_resources[] = { 285ced8d21cSRussell King DEFINE_RES_MEM(0x40000000, SZ_8K), 286ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 287ced8d21cSRussell King }; 2889590e898SRussell King struct platform_device_info sa1111_devinfo = { 2899590e898SRussell King .parent = &dev->dev, 2909590e898SRussell King .name = "sa1111", 2919590e898SRussell King .id = 0, 2929590e898SRussell King .res = sa1111_resources, 2939590e898SRussell King .num_res = ARRAY_SIZE(sa1111_resources), 2949590e898SRussell King .data = &sa1111_info, 2959590e898SRussell King .size_data = sizeof(sa1111_info), 2969590e898SRussell King .dma_mask = 0xffffffffUL, 2979590e898SRussell King }; 298ced8d21cSRussell King struct resource smc91x_resources[] = { 299ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 300ced8d21cSRussell King 0x02000000, "smc91x-regs"), 301ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, 302ced8d21cSRussell King 0x02000000, "smc91x-attrib"), 303ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 304ced8d21cSRussell King }; 305b70661c7SArnd Bergmann struct smc91x_platdata smc91x_platdata = { 306b70661c7SArnd Bergmann .flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT, 307b70661c7SArnd Bergmann }; 3089590e898SRussell King struct platform_device_info smc91x_devinfo = { 3099590e898SRussell King .parent = &dev->dev, 3109590e898SRussell King .name = "smc91x", 3119590e898SRussell King .id = 0, 3129590e898SRussell King .res = smc91x_resources, 3139590e898SRussell King .num_res = ARRAY_SIZE(smc91x_resources), 31404b91701SArnd Bergmann .data = &smc91x_platdata, 31504b91701SArnd Bergmann .size_data = sizeof(smc91x_platdata), 3169590e898SRussell King }; 317b6bdfcf5SRussell King int ret, irq; 318b6bdfcf5SRussell King 319f85fac0eSRussell King if (nep) 320f942b0fdSRussell King return -EBUSY; 321f942b0fdSRussell King 322b6bdfcf5SRussell King irq = ret = platform_get_irq(dev, 0); 323b6bdfcf5SRussell King if (ret < 0) 324b6bdfcf5SRussell King goto err_alloc; 325ae14c2e2SRussell King 326f942b0fdSRussell King nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0); 327d2e539a5SRussell King smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1); 328d2e539a5SRussell King sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2); 329f942b0fdSRussell King if (!nep_res || !smc91x_res || !sa1111_res) { 330d2e539a5SRussell King ret = -ENXIO; 331d2e539a5SRussell King goto err_alloc; 332d2e539a5SRussell King } 333d2e539a5SRussell King 334ae14c2e2SRussell King d = kzalloc(sizeof(*d), GFP_KERNEL); 335ae14c2e2SRussell King if (!d) { 336ae14c2e2SRussell King ret = -ENOMEM; 337ae14c2e2SRussell King goto err_alloc; 338ae14c2e2SRussell King } 339ae14c2e2SRussell King 340f942b0fdSRussell King d->base = ioremap(nep_res->start, SZ_4K); 341f942b0fdSRussell King if (!d->base) { 342f942b0fdSRussell King ret = -ENOMEM; 343f942b0fdSRussell King goto err_ioremap; 344f942b0fdSRussell King } 345f942b0fdSRussell King 346f942b0fdSRussell King if (readb_relaxed(d->base + WHOAMI) != 0x11) { 347f942b0fdSRussell King dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n", 348f942b0fdSRussell King readb_relaxed(d->base + WHOAMI)); 349f942b0fdSRussell King ret = -ENODEV; 350f942b0fdSRussell King goto err_id; 351f942b0fdSRussell King } 352f942b0fdSRussell King 353ced8d21cSRussell King ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1); 354ced8d21cSRussell King if (ret <= 0) { 355ced8d21cSRussell King dev_err(&dev->dev, "unable to allocate %u irqs: %d\n", 356ced8d21cSRussell King NEP_IRQ_NR, ret); 357ced8d21cSRussell King if (ret == 0) 358ced8d21cSRussell King ret = -ENOMEM; 359ced8d21cSRussell King goto err_irq_alloc; 360ced8d21cSRussell King } 3611da177e4SLinus Torvalds 362ced8d21cSRussell King d->irq_base = ret; 363ced8d21cSRussell King 364ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, 365ced8d21cSRussell King handle_simple_irq); 366e8d36d5dSRob Herring irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE); 367ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, 368ced8d21cSRussell King handle_simple_irq); 369e8d36d5dSRob Herring irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE); 370ced8d21cSRussell King irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); 371ced8d21cSRussell King 372b6bdfcf5SRussell King irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); 373056c0acfSRussell King irq_set_chained_handler_and_data(irq, neponset_irq_handler, d); 3741da177e4SLinus Torvalds 375f85fac0eSRussell King /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */ 376f85fac0eSRussell King writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0); 377f85fac0eSRussell King 378f85fac0eSRussell King neponset_init_gpio(&d->gpio[0], &dev->dev, "neponset-ncr", 379f85fac0eSRussell King d->base + NCR_0, NCR_NGPIO, false, 380f85fac0eSRussell King neponset_ncr_names); 381f85fac0eSRussell King neponset_init_gpio(&d->gpio[1], &dev->dev, "neponset-mdm-ctl0", 382f85fac0eSRussell King d->base + MDM_CTL_0, MDM_CTL0_NGPIO, false, 383f85fac0eSRussell King neponset_mdmctl0_names); 384f85fac0eSRussell King neponset_init_gpio(&d->gpio[2], &dev->dev, "neponset-mdm-ctl1", 385f85fac0eSRussell King d->base + MDM_CTL_1, MDM_CTL1_NGPIO, true, 386f85fac0eSRussell King neponset_mdmctl1_names); 387f85fac0eSRussell King neponset_init_gpio(&d->gpio[3], &dev->dev, "neponset-aud-ctl", 388f85fac0eSRussell King d->base + AUD_CTL, AUD_NGPIO, false, 389f85fac0eSRussell King neponset_aud_names); 390f85fac0eSRussell King 391e2125d05SRussell King gpiod_add_lookup_table(&neponset_pcmcia_table); 392e2125d05SRussell King 3931da177e4SLinus Torvalds /* 394ced8d21cSRussell King * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately 395ced8d21cSRussell King * something on the Neponset activates this IRQ on sleep (eth?) 3961da177e4SLinus Torvalds */ 3971da177e4SLinus Torvalds #if 0 398b6bdfcf5SRussell King enable_irq_wake(irq); 3991da177e4SLinus Torvalds #endif 4001da177e4SLinus Torvalds 401ced8d21cSRussell King dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n", 402ced8d21cSRussell King d->irq_base, d->irq_base + NEP_IRQ_NR - 1); 403f85fac0eSRussell King nep = d; 4041da177e4SLinus Torvalds 405ced8d21cSRussell King sa1100_register_uart_fns(&neponset_port_fns); 406ced8d21cSRussell King 407bab50a35SRussell King /* Ensure that the memory bus request/grant signals are setup */ 408bab50a35SRussell King sa1110_mb_disable(); 409bab50a35SRussell King 410d2e539a5SRussell King sa1111_resources[0].parent = sa1111_res; 411ced8d21cSRussell King sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111; 412ced8d21cSRussell King sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111; 4139590e898SRussell King d->sa1111 = platform_device_register_full(&sa1111_devinfo); 414ced8d21cSRussell King 415d2e539a5SRussell King smc91x_resources[0].parent = smc91x_res; 416d2e539a5SRussell King smc91x_resources[1].parent = smc91x_res; 417ced8d21cSRussell King smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X; 418ced8d21cSRussell King smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X; 4199590e898SRussell King d->smc91x = platform_device_register_full(&smc91x_devinfo); 4209590e898SRussell King 421ae14c2e2SRussell King platform_set_drvdata(dev, d); 422ae14c2e2SRussell King 423ae14c2e2SRussell King return 0; 424ae14c2e2SRussell King 425ced8d21cSRussell King err_irq_alloc: 426f942b0fdSRussell King err_id: 427f942b0fdSRussell King iounmap(d->base); 428f942b0fdSRussell King err_ioremap: 429ced8d21cSRussell King kfree(d); 430ae14c2e2SRussell King err_alloc: 431ae14c2e2SRussell King return ret; 432ae14c2e2SRussell King } 433ae14c2e2SRussell King 434351a102dSGreg Kroah-Hartman static int neponset_remove(struct platform_device *dev) 435ae14c2e2SRussell King { 436ae14c2e2SRussell King struct neponset_drvdata *d = platform_get_drvdata(dev); 437b6bdfcf5SRussell King int irq = platform_get_irq(dev, 0); 438ae14c2e2SRussell King 4399590e898SRussell King if (!IS_ERR(d->sa1111)) 4409590e898SRussell King platform_device_unregister(d->sa1111); 4419590e898SRussell King if (!IS_ERR(d->smc91x)) 4429590e898SRussell King platform_device_unregister(d->smc91x); 443e2125d05SRussell King 444e2125d05SRussell King gpiod_remove_lookup_table(&neponset_pcmcia_table); 445e2125d05SRussell King 446b6bdfcf5SRussell King irq_set_chained_handler(irq, NULL); 447ced8d21cSRussell King irq_free_descs(d->irq_base, NEP_IRQ_NR); 448f85fac0eSRussell King nep = NULL; 449f942b0fdSRussell King iounmap(d->base); 450ae14c2e2SRussell King kfree(d); 451ae14c2e2SRussell King 4521da177e4SLinus Torvalds return 0; 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 45551f93390SRussell King #ifdef CONFIG_PM_SLEEP 45651f93390SRussell King static int neponset_resume(struct device *dev) 4571da177e4SLinus Torvalds { 45851f93390SRussell King struct neponset_drvdata *d = dev_get_drvdata(dev); 459f85fac0eSRussell King int i, ret = 0; 460ae14c2e2SRussell King 461f85fac0eSRussell King for (i = 0; i < ARRAY_SIZE(d->gpio); i++) { 462f85fac0eSRussell King ret = gpio_reg_resume(d->gpio[i]); 463f85fac0eSRussell King if (ret) 464f85fac0eSRussell King break; 465f85fac0eSRussell King } 4661da177e4SLinus Torvalds 467f85fac0eSRussell King return ret; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 47051f93390SRussell King static const struct dev_pm_ops neponset_pm_ops = { 47151f93390SRussell King .resume_noirq = neponset_resume, 47251f93390SRussell King .restore_noirq = neponset_resume, 47351f93390SRussell King }; 47451f93390SRussell King #define PM_OPS &neponset_pm_ops 4751da177e4SLinus Torvalds #else 47651f93390SRussell King #define PM_OPS NULL 4771da177e4SLinus Torvalds #endif 4781da177e4SLinus Torvalds 4793ae5eaecSRussell King static struct platform_driver neponset_device_driver = { 4801da177e4SLinus Torvalds .probe = neponset_probe, 481351a102dSGreg Kroah-Hartman .remove = neponset_remove, 4823ae5eaecSRussell King .driver = { 4833ae5eaecSRussell King .name = "neponset", 48451f93390SRussell King .pm = PM_OPS, 4853ae5eaecSRussell King }, 4861da177e4SLinus Torvalds }; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds static int __init neponset_init(void) 4891da177e4SLinus Torvalds { 490bab50a35SRussell King return platform_driver_register(&neponset_device_driver); 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds subsys_initcall(neponset_init); 494