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> 106920b5a7SRussell King #include <linux/platform_data/sa11x0-serial.h> 11d052d1beSRussell King #include <linux/platform_device.h> 1251f93390SRussell King #include <linux/pm.h> 1392e617d9SRussell King #include <linux/serial_core.h> 14ae14c2e2SRussell King #include <linux/slab.h> 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <asm/mach-types.h> 171da177e4SLinus Torvalds #include <asm/mach/map.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> 24f314f33bSRob Herring #include <mach/irqs.h> 2592e617d9SRussell King 26ced8d21cSRussell King #define NEP_IRQ_SMC91X 0 27ced8d21cSRussell King #define NEP_IRQ_USAR 1 28ced8d21cSRussell King #define NEP_IRQ_SA1111 2 29ced8d21cSRussell King #define NEP_IRQ_NR 3 30ced8d21cSRussell King 31f942b0fdSRussell King #define WHOAMI 0x00 32f942b0fdSRussell King #define LEDS 0x10 33f942b0fdSRussell King #define SWPK 0x20 34f942b0fdSRussell King #define IRR 0x24 35f942b0fdSRussell King #define KP_Y_IN 0x80 36f942b0fdSRussell King #define KP_X_OUT 0x90 37f942b0fdSRussell King #define NCR_0 0xa0 38f942b0fdSRussell King #define MDM_CTL_0 0xb0 39f942b0fdSRussell King #define MDM_CTL_1 0xb4 40f942b0fdSRussell King #define AUD_CTL 0xc0 41f942b0fdSRussell King 42f942b0fdSRussell King #define IRR_ETHERNET (1 << 0) 43f942b0fdSRussell King #define IRR_USAR (1 << 1) 44f942b0fdSRussell King #define IRR_SA1111 (1 << 2) 45f942b0fdSRussell King 46f942b0fdSRussell King #define MDM_CTL0_RTS1 (1 << 0) 47f942b0fdSRussell King #define MDM_CTL0_DTR1 (1 << 1) 48f942b0fdSRussell King #define MDM_CTL0_RTS2 (1 << 2) 49f942b0fdSRussell King #define MDM_CTL0_DTR2 (1 << 3) 50f942b0fdSRussell King 51f942b0fdSRussell King #define MDM_CTL1_CTS1 (1 << 0) 52f942b0fdSRussell King #define MDM_CTL1_DSR1 (1 << 1) 53f942b0fdSRussell King #define MDM_CTL1_DCD1 (1 << 2) 54f942b0fdSRussell King #define MDM_CTL1_CTS2 (1 << 3) 55f942b0fdSRussell King #define MDM_CTL1_DSR2 (1 << 4) 56f942b0fdSRussell King #define MDM_CTL1_DCD2 (1 << 5) 57f942b0fdSRussell King 58f942b0fdSRussell King #define AUD_SEL_1341 (1 << 0) 59f942b0fdSRussell King #define AUD_MUTE_1341 (1 << 1) 60f942b0fdSRussell King 61bab50a35SRussell King extern void sa1110_mb_disable(void); 62bab50a35SRussell King 63ae14c2e2SRussell King struct neponset_drvdata { 64f942b0fdSRussell King void __iomem *base; 659590e898SRussell King struct platform_device *sa1111; 669590e898SRussell King struct platform_device *smc91x; 67ced8d21cSRussell King unsigned irq_base; 68ae14c2e2SRussell King #ifdef CONFIG_PM_SLEEP 69ae14c2e2SRussell King u32 ncr0; 70ae14c2e2SRussell King u32 mdm_ctl_0; 71ae14c2e2SRussell King #endif 72ae14c2e2SRussell King }; 73ae14c2e2SRussell King 74f942b0fdSRussell King static void __iomem *nep_base; 75f942b0fdSRussell King 766ad1b614SRussell King void neponset_ncr_frob(unsigned int mask, unsigned int val) 776ad1b614SRussell King { 78f942b0fdSRussell King void __iomem *base = nep_base; 79f942b0fdSRussell King 80f942b0fdSRussell King if (base) { 816ad1b614SRussell King unsigned long flags; 82f942b0fdSRussell King unsigned v; 836ad1b614SRussell King 846ad1b614SRussell King local_irq_save(flags); 85f942b0fdSRussell King v = readb_relaxed(base + NCR_0); 86f942b0fdSRussell King writeb_relaxed((v & ~mask) | val, base + NCR_0); 876ad1b614SRussell King local_irq_restore(flags); 88f942b0fdSRussell King } else { 89f942b0fdSRussell King WARN(1, "nep_base unset\n"); 90f942b0fdSRussell King } 916ad1b614SRussell King } 92ef0c1484SRussell King EXPORT_SYMBOL(neponset_ncr_frob); 936ad1b614SRussell King 941da177e4SLinus Torvalds static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) 951da177e4SLinus Torvalds { 96f942b0fdSRussell King void __iomem *base = nep_base; 97f942b0fdSRussell King u_int mdm_ctl0; 981da177e4SLinus Torvalds 99f942b0fdSRussell King if (!base) 100f942b0fdSRussell King return; 101f942b0fdSRussell King 102f942b0fdSRussell King mdm_ctl0 = readb_relaxed(base + MDM_CTL_0); 1031da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 1041da177e4SLinus Torvalds if (mctrl & TIOCM_RTS) 1051da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_RTS2; 1061da177e4SLinus Torvalds else 1071da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_RTS2; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds if (mctrl & TIOCM_DTR) 1101da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_DTR2; 1111da177e4SLinus Torvalds else 1121da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_DTR2; 1131da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 1141da177e4SLinus Torvalds if (mctrl & TIOCM_RTS) 1151da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_RTS1; 1161da177e4SLinus Torvalds else 1171da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_RTS1; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds if (mctrl & TIOCM_DTR) 1201da177e4SLinus Torvalds mdm_ctl0 &= ~MDM_CTL0_DTR1; 1211da177e4SLinus Torvalds else 1221da177e4SLinus Torvalds mdm_ctl0 |= MDM_CTL0_DTR1; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 125f942b0fdSRussell King writeb_relaxed(mdm_ctl0, base + MDM_CTL_0); 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds static u_int neponset_get_mctrl(struct uart_port *port) 1291da177e4SLinus Torvalds { 130f942b0fdSRussell King void __iomem *base = nep_base; 1311da177e4SLinus Torvalds u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; 132f942b0fdSRussell King u_int mdm_ctl1; 1331da177e4SLinus Torvalds 134f942b0fdSRussell King if (!base) 135f942b0fdSRussell King return ret; 136f942b0fdSRussell King 137f942b0fdSRussell King mdm_ctl1 = readb_relaxed(base + MDM_CTL_1); 1381da177e4SLinus Torvalds if (port->mapbase == _Ser1UTCR0) { 1391da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD2) 1401da177e4SLinus Torvalds ret &= ~TIOCM_CD; 1411da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS2) 1421da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 1431da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR2) 1441da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 1451da177e4SLinus Torvalds } else if (port->mapbase == _Ser3UTCR0) { 1461da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DCD1) 1471da177e4SLinus Torvalds ret &= ~TIOCM_CD; 1481da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_CTS1) 1491da177e4SLinus Torvalds ret &= ~TIOCM_CTS; 1501da177e4SLinus Torvalds if (mdm_ctl1 & MDM_CTL1_DSR1) 1511da177e4SLinus Torvalds ret &= ~TIOCM_DSR; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds return ret; 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 157351a102dSGreg Kroah-Hartman static struct sa1100_port_fns neponset_port_fns = { 1581da177e4SLinus Torvalds .set_mctrl = neponset_set_mctrl, 1591da177e4SLinus Torvalds .get_mctrl = neponset_get_mctrl, 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 16271045520SRussell King /* 16392e617d9SRussell King * Install handler for Neponset IRQ. Note that we have to loop here 16492e617d9SRussell King * since the ETHERNET and USAR IRQs are level based, and we need to 16592e617d9SRussell King * ensure that the IRQ signal is deasserted before returning. This 16692e617d9SRussell King * is rather unfortunate. 16792e617d9SRussell King */ 168ced8d21cSRussell King static void neponset_irq_handler(unsigned int irq, struct irq_desc *desc) 16992e617d9SRussell King { 170ced8d21cSRussell King struct neponset_drvdata *d = irq_desc_get_handler_data(desc); 17192e617d9SRussell King unsigned int irr; 17292e617d9SRussell King 17392e617d9SRussell King while (1) { 17492e617d9SRussell King /* 17592e617d9SRussell King * Acknowledge the parent IRQ. 17692e617d9SRussell King */ 17792e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 17892e617d9SRussell King 17992e617d9SRussell King /* 18092e617d9SRussell King * Read the interrupt reason register. Let's have all 18192e617d9SRussell King * active IRQ bits high. Note: there is a typo in the 18292e617d9SRussell King * Neponset user's guide for the SA1111 IRR level. 18392e617d9SRussell King */ 184f942b0fdSRussell King irr = readb_relaxed(d->base + IRR); 185f942b0fdSRussell King irr ^= IRR_ETHERNET | IRR_USAR; 18692e617d9SRussell King 18792e617d9SRussell King if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0) 18892e617d9SRussell King break; 18992e617d9SRussell King 19092e617d9SRussell King /* 19192e617d9SRussell King * Since there is no individual mask, we have to 19292e617d9SRussell King * mask the parent IRQ. This is safe, since we'll 19392e617d9SRussell King * recheck the register for any pending IRQs. 19492e617d9SRussell King */ 19592e617d9SRussell King if (irr & (IRR_ETHERNET | IRR_USAR)) { 19692e617d9SRussell King desc->irq_data.chip->irq_mask(&desc->irq_data); 19792e617d9SRussell King 19892e617d9SRussell King /* 19992e617d9SRussell King * Ack the interrupt now to prevent re-entering 20092e617d9SRussell King * this neponset handler. Again, this is safe 20192e617d9SRussell King * since we'll check the IRR register prior to 20292e617d9SRussell King * leaving. 20392e617d9SRussell King */ 20492e617d9SRussell King desc->irq_data.chip->irq_ack(&desc->irq_data); 20592e617d9SRussell King 206ced8d21cSRussell King if (irr & IRR_ETHERNET) 207ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X); 20892e617d9SRussell King 209ced8d21cSRussell King if (irr & IRR_USAR) 210ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_USAR); 21192e617d9SRussell King 21292e617d9SRussell King desc->irq_data.chip->irq_unmask(&desc->irq_data); 21392e617d9SRussell King } 21492e617d9SRussell King 215ced8d21cSRussell King if (irr & IRR_SA1111) 216ced8d21cSRussell King generic_handle_irq(d->irq_base + NEP_IRQ_SA1111); 21792e617d9SRussell King } 21892e617d9SRussell King } 21992e617d9SRussell King 220ced8d21cSRussell King /* Yes, we really do not have any kind of masking or unmasking */ 22171045520SRussell King static void nochip_noop(struct irq_data *irq) 22271045520SRussell King { 22371045520SRussell King } 22471045520SRussell King 22571045520SRussell King static struct irq_chip nochip = { 22671045520SRussell King .name = "neponset", 22771045520SRussell King .irq_ack = nochip_noop, 22871045520SRussell King .irq_mask = nochip_noop, 22971045520SRussell King .irq_unmask = nochip_noop, 23071045520SRussell King }; 23171045520SRussell King 23292e617d9SRussell King static struct sa1111_platform_data sa1111_info = { 23307be45f5SRussell King .disable_devs = SA1111_DEVID_PS2_MSE, 23492e617d9SRussell King }; 23592e617d9SRussell King 236351a102dSGreg Kroah-Hartman static int neponset_probe(struct platform_device *dev) 2371da177e4SLinus Torvalds { 238ae14c2e2SRussell King struct neponset_drvdata *d; 239f942b0fdSRussell King struct resource *nep_res, *sa1111_res, *smc91x_res; 240ced8d21cSRussell King struct resource sa1111_resources[] = { 241ced8d21cSRussell King DEFINE_RES_MEM(0x40000000, SZ_8K), 242ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 243ced8d21cSRussell King }; 2449590e898SRussell King struct platform_device_info sa1111_devinfo = { 2459590e898SRussell King .parent = &dev->dev, 2469590e898SRussell King .name = "sa1111", 2479590e898SRussell King .id = 0, 2489590e898SRussell King .res = sa1111_resources, 2499590e898SRussell King .num_res = ARRAY_SIZE(sa1111_resources), 2509590e898SRussell King .data = &sa1111_info, 2519590e898SRussell King .size_data = sizeof(sa1111_info), 2529590e898SRussell King .dma_mask = 0xffffffffUL, 2539590e898SRussell King }; 254ced8d21cSRussell King struct resource smc91x_resources[] = { 255ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS, 256ced8d21cSRussell King 0x02000000, "smc91x-regs"), 257ced8d21cSRussell King DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000, 258ced8d21cSRussell King 0x02000000, "smc91x-attrib"), 259ced8d21cSRussell King { .flags = IORESOURCE_IRQ }, 260ced8d21cSRussell King }; 2619590e898SRussell King struct platform_device_info smc91x_devinfo = { 2629590e898SRussell King .parent = &dev->dev, 2639590e898SRussell King .name = "smc91x", 2649590e898SRussell King .id = 0, 2659590e898SRussell King .res = smc91x_resources, 2669590e898SRussell King .num_res = ARRAY_SIZE(smc91x_resources), 2679590e898SRussell King }; 268b6bdfcf5SRussell King int ret, irq; 269b6bdfcf5SRussell King 270f942b0fdSRussell King if (nep_base) 271f942b0fdSRussell King return -EBUSY; 272f942b0fdSRussell King 273b6bdfcf5SRussell King irq = ret = platform_get_irq(dev, 0); 274b6bdfcf5SRussell King if (ret < 0) 275b6bdfcf5SRussell King goto err_alloc; 276ae14c2e2SRussell King 277f942b0fdSRussell King nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0); 278d2e539a5SRussell King smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1); 279d2e539a5SRussell King sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2); 280f942b0fdSRussell King if (!nep_res || !smc91x_res || !sa1111_res) { 281d2e539a5SRussell King ret = -ENXIO; 282d2e539a5SRussell King goto err_alloc; 283d2e539a5SRussell King } 284d2e539a5SRussell King 285ae14c2e2SRussell King d = kzalloc(sizeof(*d), GFP_KERNEL); 286ae14c2e2SRussell King if (!d) { 287ae14c2e2SRussell King ret = -ENOMEM; 288ae14c2e2SRussell King goto err_alloc; 289ae14c2e2SRussell King } 290ae14c2e2SRussell King 291f942b0fdSRussell King d->base = ioremap(nep_res->start, SZ_4K); 292f942b0fdSRussell King if (!d->base) { 293f942b0fdSRussell King ret = -ENOMEM; 294f942b0fdSRussell King goto err_ioremap; 295f942b0fdSRussell King } 296f942b0fdSRussell King 297f942b0fdSRussell King if (readb_relaxed(d->base + WHOAMI) != 0x11) { 298f942b0fdSRussell King dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n", 299f942b0fdSRussell King readb_relaxed(d->base + WHOAMI)); 300f942b0fdSRussell King ret = -ENODEV; 301f942b0fdSRussell King goto err_id; 302f942b0fdSRussell King } 303f942b0fdSRussell King 304ced8d21cSRussell King ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1); 305ced8d21cSRussell King if (ret <= 0) { 306ced8d21cSRussell King dev_err(&dev->dev, "unable to allocate %u irqs: %d\n", 307ced8d21cSRussell King NEP_IRQ_NR, ret); 308ced8d21cSRussell King if (ret == 0) 309ced8d21cSRussell King ret = -ENOMEM; 310ced8d21cSRussell King goto err_irq_alloc; 311ced8d21cSRussell King } 3121da177e4SLinus Torvalds 313ced8d21cSRussell King d->irq_base = ret; 314ced8d21cSRussell King 315ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, 316ced8d21cSRussell King handle_simple_irq); 317ced8d21cSRussell King set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE); 318ced8d21cSRussell King irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, 319ced8d21cSRussell King handle_simple_irq); 320ced8d21cSRussell King set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE); 321ced8d21cSRussell King irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); 322ced8d21cSRussell King 323b6bdfcf5SRussell King irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); 324b6bdfcf5SRussell King irq_set_handler_data(irq, d); 325b6bdfcf5SRussell King irq_set_chained_handler(irq, neponset_irq_handler); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* 328ced8d21cSRussell King * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately 329ced8d21cSRussell King * something on the Neponset activates this IRQ on sleep (eth?) 3301da177e4SLinus Torvalds */ 3311da177e4SLinus Torvalds #if 0 332b6bdfcf5SRussell King enable_irq_wake(irq); 3331da177e4SLinus Torvalds #endif 3341da177e4SLinus Torvalds 335ced8d21cSRussell King dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n", 336ced8d21cSRussell King d->irq_base, d->irq_base + NEP_IRQ_NR - 1); 337f942b0fdSRussell King nep_base = d->base; 3381da177e4SLinus Torvalds 339ced8d21cSRussell King sa1100_register_uart_fns(&neponset_port_fns); 340ced8d21cSRussell King 341bab50a35SRussell King /* Ensure that the memory bus request/grant signals are setup */ 342bab50a35SRussell King sa1110_mb_disable(); 343bab50a35SRussell King 344ced8d21cSRussell King /* Disable GPIO 0/1 drivers so the buttons work on the Assabet */ 345f942b0fdSRussell King writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0); 3461da177e4SLinus Torvalds 347d2e539a5SRussell King sa1111_resources[0].parent = sa1111_res; 348ced8d21cSRussell King sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111; 349ced8d21cSRussell King sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111; 3509590e898SRussell King d->sa1111 = platform_device_register_full(&sa1111_devinfo); 351ced8d21cSRussell King 352d2e539a5SRussell King smc91x_resources[0].parent = smc91x_res; 353d2e539a5SRussell King smc91x_resources[1].parent = smc91x_res; 354ced8d21cSRussell King smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X; 355ced8d21cSRussell King smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X; 3569590e898SRussell King d->smc91x = platform_device_register_full(&smc91x_devinfo); 3579590e898SRussell King 358ae14c2e2SRussell King platform_set_drvdata(dev, d); 359ae14c2e2SRussell King 360ae14c2e2SRussell King return 0; 361ae14c2e2SRussell King 362ced8d21cSRussell King err_irq_alloc: 363f942b0fdSRussell King err_id: 364f942b0fdSRussell King iounmap(d->base); 365f942b0fdSRussell King err_ioremap: 366ced8d21cSRussell King kfree(d); 367ae14c2e2SRussell King err_alloc: 368ae14c2e2SRussell King return ret; 369ae14c2e2SRussell King } 370ae14c2e2SRussell King 371351a102dSGreg Kroah-Hartman static int neponset_remove(struct platform_device *dev) 372ae14c2e2SRussell King { 373ae14c2e2SRussell King struct neponset_drvdata *d = platform_get_drvdata(dev); 374b6bdfcf5SRussell King int irq = platform_get_irq(dev, 0); 375ae14c2e2SRussell King 3769590e898SRussell King if (!IS_ERR(d->sa1111)) 3779590e898SRussell King platform_device_unregister(d->sa1111); 3789590e898SRussell King if (!IS_ERR(d->smc91x)) 3799590e898SRussell King platform_device_unregister(d->smc91x); 380b6bdfcf5SRussell King irq_set_chained_handler(irq, NULL); 381ced8d21cSRussell King irq_free_descs(d->irq_base, NEP_IRQ_NR); 382f942b0fdSRussell King nep_base = NULL; 383f942b0fdSRussell King iounmap(d->base); 384ae14c2e2SRussell King kfree(d); 385ae14c2e2SRussell King 3861da177e4SLinus Torvalds return 0; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 38951f93390SRussell King #ifdef CONFIG_PM_SLEEP 39051f93390SRussell King static int neponset_suspend(struct device *dev) 3911da177e4SLinus Torvalds { 39251f93390SRussell King struct neponset_drvdata *d = dev_get_drvdata(dev); 393ae14c2e2SRussell King 394f942b0fdSRussell King d->ncr0 = readb_relaxed(d->base + NCR_0); 395f942b0fdSRussell King d->mdm_ctl_0 = readb_relaxed(d->base + MDM_CTL_0); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds return 0; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 40051f93390SRussell King static int neponset_resume(struct device *dev) 4011da177e4SLinus Torvalds { 40251f93390SRussell King struct neponset_drvdata *d = dev_get_drvdata(dev); 403ae14c2e2SRussell King 404f942b0fdSRussell King writeb_relaxed(d->ncr0, d->base + NCR_0); 405f942b0fdSRussell King writeb_relaxed(d->mdm_ctl_0, d->base + MDM_CTL_0); 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds return 0; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 41051f93390SRussell King static const struct dev_pm_ops neponset_pm_ops = { 41151f93390SRussell King .suspend_noirq = neponset_suspend, 41251f93390SRussell King .resume_noirq = neponset_resume, 41351f93390SRussell King .freeze_noirq = neponset_suspend, 41451f93390SRussell King .restore_noirq = neponset_resume, 41551f93390SRussell King }; 41651f93390SRussell King #define PM_OPS &neponset_pm_ops 4171da177e4SLinus Torvalds #else 41851f93390SRussell King #define PM_OPS NULL 4191da177e4SLinus Torvalds #endif 4201da177e4SLinus Torvalds 4213ae5eaecSRussell King static struct platform_driver neponset_device_driver = { 4221da177e4SLinus Torvalds .probe = neponset_probe, 423351a102dSGreg Kroah-Hartman .remove = neponset_remove, 4243ae5eaecSRussell King .driver = { 4253ae5eaecSRussell King .name = "neponset", 426398e58d0SRussell King .owner = THIS_MODULE, 42751f93390SRussell King .pm = PM_OPS, 4283ae5eaecSRussell King }, 4291da177e4SLinus Torvalds }; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds static int __init neponset_init(void) 4321da177e4SLinus Torvalds { 433bab50a35SRussell King return platform_driver_register(&neponset_device_driver); 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds subsys_initcall(neponset_init); 437