xref: /openbmc/linux/arch/arm/mach-sa1100/neponset.c (revision f85fac0e)
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>
81da177e4SLinus Torvalds #include <linux/init.h>
91da177e4SLinus Torvalds #include <linux/ioport.h>
10ced8d21cSRussell King #include <linux/irq.h>
1192e617d9SRussell King #include <linux/kernel.h>
12ae14c2e2SRussell King #include <linux/module.h>
136920b5a7SRussell King #include <linux/platform_data/sa11x0-serial.h>
14d052d1beSRussell King #include <linux/platform_device.h>
1551f93390SRussell King #include <linux/pm.h>
1692e617d9SRussell King #include <linux/serial_core.h>
17ae14c2e2SRussell King #include <linux/slab.h>
18b70661c7SArnd Bergmann #include <linux/smc91x.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #include <asm/mach-types.h>
211da177e4SLinus Torvalds #include <asm/mach/map.h>
221da177e4SLinus Torvalds #include <asm/hardware/sa1111.h>
231da177e4SLinus Torvalds #include <asm/sizes.h>
241da177e4SLinus Torvalds 
2592e617d9SRussell King #include <mach/hardware.h>
2692e617d9SRussell King #include <mach/assabet.h>
2792e617d9SRussell King #include <mach/neponset.h>
28f314f33bSRob Herring #include <mach/irqs.h>
2992e617d9SRussell King 
30ced8d21cSRussell King #define NEP_IRQ_SMC91X	0
31ced8d21cSRussell King #define NEP_IRQ_USAR	1
32ced8d21cSRussell King #define NEP_IRQ_SA1111	2
33ced8d21cSRussell King #define NEP_IRQ_NR	3
34ced8d21cSRussell King 
35f942b0fdSRussell King #define WHOAMI		0x00
36f942b0fdSRussell King #define LEDS		0x10
37f942b0fdSRussell King #define SWPK		0x20
38f942b0fdSRussell King #define IRR		0x24
39f942b0fdSRussell King #define KP_Y_IN		0x80
40f942b0fdSRussell King #define KP_X_OUT	0x90
41f942b0fdSRussell King #define NCR_0		0xa0
42f942b0fdSRussell King #define MDM_CTL_0	0xb0
43f942b0fdSRussell King #define MDM_CTL_1	0xb4
44f942b0fdSRussell King #define AUD_CTL		0xc0
45f942b0fdSRussell King 
46f942b0fdSRussell King #define IRR_ETHERNET	(1 << 0)
47f942b0fdSRussell King #define IRR_USAR	(1 << 1)
48f942b0fdSRussell King #define IRR_SA1111	(1 << 2)
49f942b0fdSRussell King 
50f85fac0eSRussell King #define NCR_NGPIO	7
51f85fac0eSRussell King 
52f942b0fdSRussell King #define MDM_CTL0_RTS1	(1 << 0)
53f942b0fdSRussell King #define MDM_CTL0_DTR1	(1 << 1)
54f942b0fdSRussell King #define MDM_CTL0_RTS2	(1 << 2)
55f942b0fdSRussell King #define MDM_CTL0_DTR2	(1 << 3)
56f85fac0eSRussell King #define MDM_CTL0_NGPIO	4
57f942b0fdSRussell King 
58f942b0fdSRussell King #define MDM_CTL1_CTS1	(1 << 0)
59f942b0fdSRussell King #define MDM_CTL1_DSR1	(1 << 1)
60f942b0fdSRussell King #define MDM_CTL1_DCD1	(1 << 2)
61f942b0fdSRussell King #define MDM_CTL1_CTS2	(1 << 3)
62f942b0fdSRussell King #define MDM_CTL1_DSR2	(1 << 4)
63f942b0fdSRussell King #define MDM_CTL1_DCD2	(1 << 5)
64f85fac0eSRussell King #define MDM_CTL1_NGPIO	6
65f942b0fdSRussell King 
66f942b0fdSRussell King #define AUD_SEL_1341	(1 << 0)
67f942b0fdSRussell King #define AUD_MUTE_1341	(1 << 1)
68f85fac0eSRussell King #define AUD_NGPIO	2
69f942b0fdSRussell King 
70bab50a35SRussell King extern void sa1110_mb_disable(void);
71bab50a35SRussell King 
72f85fac0eSRussell King #define to_neponset_gpio_chip(x) container_of(x, struct neponset_gpio_chip, gc)
73f85fac0eSRussell King 
74f85fac0eSRussell King static const char *neponset_ncr_names[] = {
75f85fac0eSRussell King 	"gp01_off", "tp_power", "ms_power", "enet_osc",
76f85fac0eSRussell King 	"spi_kb_wk_up", "a0vpp", "a1vpp"
77f85fac0eSRussell King };
78f85fac0eSRussell King 
79f85fac0eSRussell King static const char *neponset_mdmctl0_names[] = {
80f85fac0eSRussell King 	"rts3", "dtr3", "rts1", "dtr1",
81f85fac0eSRussell King };
82f85fac0eSRussell King 
83f85fac0eSRussell King static const char *neponset_mdmctl1_names[] = {
84f85fac0eSRussell King 	"cts3", "dsr3", "dcd3", "cts1", "dsr1", "dcd1"
85f85fac0eSRussell King };
86f85fac0eSRussell King 
87f85fac0eSRussell King static const char *neponset_aud_names[] = {
88f85fac0eSRussell King 	"sel_1341", "mute_1341",
89f85fac0eSRussell King };
90f85fac0eSRussell King 
91ae14c2e2SRussell King struct neponset_drvdata {
92f942b0fdSRussell King 	void __iomem *base;
939590e898SRussell King 	struct platform_device *sa1111;
949590e898SRussell King 	struct platform_device *smc91x;
95ced8d21cSRussell King 	unsigned irq_base;
96f85fac0eSRussell King 	struct gpio_chip *gpio[4];
97ae14c2e2SRussell King };
98ae14c2e2SRussell King 
99f85fac0eSRussell King static struct neponset_drvdata *nep;
100f942b0fdSRussell King 
1016ad1b614SRussell King void neponset_ncr_frob(unsigned int mask, unsigned int val)
1026ad1b614SRussell King {
103f85fac0eSRussell King 	struct neponset_drvdata *n = nep;
104f85fac0eSRussell King 	unsigned long m = mask, v = val;
105f942b0fdSRussell King 
106f85fac0eSRussell King 	if (nep)
107f85fac0eSRussell King 		n->gpio[0]->set_multiple(n->gpio[0], &m, &v);
108f85fac0eSRussell King 	else
109f85fac0eSRussell King 		WARN(1, "nep unset\n");
1106ad1b614SRussell King }
111ef0c1484SRussell King EXPORT_SYMBOL(neponset_ncr_frob);
1126ad1b614SRussell King 
1131da177e4SLinus Torvalds static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
1141da177e4SLinus Torvalds {
115f85fac0eSRussell King 	struct neponset_drvdata *n = nep;
116f85fac0eSRussell King 	unsigned long mask, val = 0;
1171da177e4SLinus Torvalds 
118f85fac0eSRussell King 	if (!n)
119f942b0fdSRussell King 		return;
120f942b0fdSRussell King 
1211da177e4SLinus Torvalds 	if (port->mapbase == _Ser1UTCR0) {
122f85fac0eSRussell King 		mask = MDM_CTL0_RTS2 | MDM_CTL0_DTR2;
1231da177e4SLinus Torvalds 
124f85fac0eSRussell King 		if (!(mctrl & TIOCM_RTS))
125f85fac0eSRussell King 			val |= MDM_CTL0_RTS2;
126f85fac0eSRussell King 
127f85fac0eSRussell King 		if (!(mctrl & TIOCM_DTR))
128f85fac0eSRussell King 			val |= MDM_CTL0_DTR2;
1291da177e4SLinus Torvalds 	} else if (port->mapbase == _Ser3UTCR0) {
130f85fac0eSRussell King 		mask = MDM_CTL0_RTS1 | MDM_CTL0_DTR1;
1311da177e4SLinus Torvalds 
132f85fac0eSRussell King 		if (!(mctrl & TIOCM_RTS))
133f85fac0eSRussell King 			val |= MDM_CTL0_RTS1;
134f85fac0eSRussell King 
135f85fac0eSRussell King 		if (!(mctrl & TIOCM_DTR))
136f85fac0eSRussell King 			val |= MDM_CTL0_DTR1;
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 
139f85fac0eSRussell King 	n->gpio[1]->set_multiple(n->gpio[1], &mask, &val);
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds static u_int neponset_get_mctrl(struct uart_port *port)
1431da177e4SLinus Torvalds {
144f85fac0eSRussell King 	void __iomem *base = nep->base;
1451da177e4SLinus Torvalds 	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
146f942b0fdSRussell King 	u_int mdm_ctl1;
1471da177e4SLinus Torvalds 
148f942b0fdSRussell King 	if (!base)
149f942b0fdSRussell King 		return ret;
150f942b0fdSRussell King 
151f942b0fdSRussell King 	mdm_ctl1 = readb_relaxed(base + MDM_CTL_1);
1521da177e4SLinus Torvalds 	if (port->mapbase == _Ser1UTCR0) {
1531da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_DCD2)
1541da177e4SLinus Torvalds 			ret &= ~TIOCM_CD;
1551da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_CTS2)
1561da177e4SLinus Torvalds 			ret &= ~TIOCM_CTS;
1571da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_DSR2)
1581da177e4SLinus Torvalds 			ret &= ~TIOCM_DSR;
1591da177e4SLinus Torvalds 	} else if (port->mapbase == _Ser3UTCR0) {
1601da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_DCD1)
1611da177e4SLinus Torvalds 			ret &= ~TIOCM_CD;
1621da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_CTS1)
1631da177e4SLinus Torvalds 			ret &= ~TIOCM_CTS;
1641da177e4SLinus Torvalds 		if (mdm_ctl1 & MDM_CTL1_DSR1)
1651da177e4SLinus Torvalds 			ret &= ~TIOCM_DSR;
1661da177e4SLinus Torvalds 	}
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	return ret;
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds 
171351a102dSGreg Kroah-Hartman static struct sa1100_port_fns neponset_port_fns = {
1721da177e4SLinus Torvalds 	.set_mctrl	= neponset_set_mctrl,
1731da177e4SLinus Torvalds 	.get_mctrl	= neponset_get_mctrl,
1741da177e4SLinus Torvalds };
1751da177e4SLinus Torvalds 
17671045520SRussell King /*
17792e617d9SRussell King  * Install handler for Neponset IRQ.  Note that we have to loop here
17892e617d9SRussell King  * since the ETHERNET and USAR IRQs are level based, and we need to
17992e617d9SRussell King  * ensure that the IRQ signal is deasserted before returning.  This
18092e617d9SRussell King  * is rather unfortunate.
18192e617d9SRussell King  */
182bd0b9ac4SThomas Gleixner static void neponset_irq_handler(struct irq_desc *desc)
18392e617d9SRussell King {
184ced8d21cSRussell King 	struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
18592e617d9SRussell King 	unsigned int irr;
18692e617d9SRussell King 
18792e617d9SRussell King 	while (1) {
18892e617d9SRussell King 		/*
18992e617d9SRussell King 		 * Acknowledge the parent IRQ.
19092e617d9SRussell King 		 */
19192e617d9SRussell King 		desc->irq_data.chip->irq_ack(&desc->irq_data);
19292e617d9SRussell King 
19392e617d9SRussell King 		/*
19492e617d9SRussell King 		 * Read the interrupt reason register.  Let's have all
19592e617d9SRussell King 		 * active IRQ bits high.  Note: there is a typo in the
19692e617d9SRussell King 		 * Neponset user's guide for the SA1111 IRR level.
19792e617d9SRussell King 		 */
198f942b0fdSRussell King 		irr = readb_relaxed(d->base + IRR);
199f942b0fdSRussell King 		irr ^= IRR_ETHERNET | IRR_USAR;
20092e617d9SRussell King 
20192e617d9SRussell King 		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
20292e617d9SRussell King 			break;
20392e617d9SRussell King 
20492e617d9SRussell King 		/*
20592e617d9SRussell King 		 * Since there is no individual mask, we have to
20692e617d9SRussell King 		 * mask the parent IRQ.  This is safe, since we'll
20792e617d9SRussell King 		 * recheck the register for any pending IRQs.
20892e617d9SRussell King 		 */
20992e617d9SRussell King 		if (irr & (IRR_ETHERNET | IRR_USAR)) {
21092e617d9SRussell King 			desc->irq_data.chip->irq_mask(&desc->irq_data);
21192e617d9SRussell King 
21292e617d9SRussell King 			/*
21392e617d9SRussell King 			 * Ack the interrupt now to prevent re-entering
21492e617d9SRussell King 			 * this neponset handler.  Again, this is safe
21592e617d9SRussell King 			 * since we'll check the IRR register prior to
21692e617d9SRussell King 			 * leaving.
21792e617d9SRussell King 			 */
21892e617d9SRussell King 			desc->irq_data.chip->irq_ack(&desc->irq_data);
21992e617d9SRussell King 
220ced8d21cSRussell King 			if (irr & IRR_ETHERNET)
221ced8d21cSRussell King 				generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
22292e617d9SRussell King 
223ced8d21cSRussell King 			if (irr & IRR_USAR)
224ced8d21cSRussell King 				generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
22592e617d9SRussell King 
22692e617d9SRussell King 			desc->irq_data.chip->irq_unmask(&desc->irq_data);
22792e617d9SRussell King 		}
22892e617d9SRussell King 
229ced8d21cSRussell King 		if (irr & IRR_SA1111)
230ced8d21cSRussell King 			generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
23192e617d9SRussell King 	}
23292e617d9SRussell King }
23392e617d9SRussell King 
234ced8d21cSRussell King /* Yes, we really do not have any kind of masking or unmasking */
23571045520SRussell King static void nochip_noop(struct irq_data *irq)
23671045520SRussell King {
23771045520SRussell King }
23871045520SRussell King 
23971045520SRussell King static struct irq_chip nochip = {
24071045520SRussell King 	.name = "neponset",
24171045520SRussell King 	.irq_ack = nochip_noop,
24271045520SRussell King 	.irq_mask = nochip_noop,
24371045520SRussell King 	.irq_unmask = nochip_noop,
24471045520SRussell King };
24571045520SRussell King 
246f85fac0eSRussell King static int neponset_init_gpio(struct gpio_chip **gcp,
247f85fac0eSRussell King 	struct device *dev, const char *label, void __iomem *reg,
248f85fac0eSRussell King 	unsigned num, bool in, const char *const * names)
249f85fac0eSRussell King {
250f85fac0eSRussell King 	struct gpio_chip *gc;
251f85fac0eSRussell King 
252f85fac0eSRussell King 	gc = gpio_reg_init(dev, reg, -1, num, label, in ? 0xffffffff : 0,
253f85fac0eSRussell King 			   readl_relaxed(reg), names, NULL, NULL);
254f85fac0eSRussell King 	if (IS_ERR(gc))
255f85fac0eSRussell King 		return PTR_ERR(gc);
256f85fac0eSRussell King 
257f85fac0eSRussell King 	*gcp = gc;
258f85fac0eSRussell King 
259f85fac0eSRussell King 	return 0;
260f85fac0eSRussell King }
261f85fac0eSRussell King 
26292e617d9SRussell King static struct sa1111_platform_data sa1111_info = {
26307be45f5SRussell King 	.disable_devs	= SA1111_DEVID_PS2_MSE,
26492e617d9SRussell King };
26592e617d9SRussell King 
266351a102dSGreg Kroah-Hartman static int neponset_probe(struct platform_device *dev)
2671da177e4SLinus Torvalds {
268ae14c2e2SRussell King 	struct neponset_drvdata *d;
269f942b0fdSRussell King 	struct resource *nep_res, *sa1111_res, *smc91x_res;
270ced8d21cSRussell King 	struct resource sa1111_resources[] = {
271ced8d21cSRussell King 		DEFINE_RES_MEM(0x40000000, SZ_8K),
272ced8d21cSRussell King 		{ .flags = IORESOURCE_IRQ },
273ced8d21cSRussell King 	};
2749590e898SRussell King 	struct platform_device_info sa1111_devinfo = {
2759590e898SRussell King 		.parent = &dev->dev,
2769590e898SRussell King 		.name = "sa1111",
2779590e898SRussell King 		.id = 0,
2789590e898SRussell King 		.res = sa1111_resources,
2799590e898SRussell King 		.num_res = ARRAY_SIZE(sa1111_resources),
2809590e898SRussell King 		.data = &sa1111_info,
2819590e898SRussell King 		.size_data = sizeof(sa1111_info),
2829590e898SRussell King 		.dma_mask = 0xffffffffUL,
2839590e898SRussell King 	};
284ced8d21cSRussell King 	struct resource smc91x_resources[] = {
285ced8d21cSRussell King 		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
286ced8d21cSRussell King 			0x02000000, "smc91x-regs"),
287ced8d21cSRussell King 		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
288ced8d21cSRussell King 			0x02000000, "smc91x-attrib"),
289ced8d21cSRussell King 		{ .flags = IORESOURCE_IRQ },
290ced8d21cSRussell King 	};
291b70661c7SArnd Bergmann 	struct smc91x_platdata smc91x_platdata = {
292b70661c7SArnd Bergmann 		.flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
293b70661c7SArnd Bergmann 	};
2949590e898SRussell King 	struct platform_device_info smc91x_devinfo = {
2959590e898SRussell King 		.parent = &dev->dev,
2969590e898SRussell King 		.name = "smc91x",
2979590e898SRussell King 		.id = 0,
2989590e898SRussell King 		.res = smc91x_resources,
2999590e898SRussell King 		.num_res = ARRAY_SIZE(smc91x_resources),
30004b91701SArnd Bergmann 		.data = &smc91x_platdata,
30104b91701SArnd Bergmann 		.size_data = sizeof(smc91x_platdata),
3029590e898SRussell King 	};
303b6bdfcf5SRussell King 	int ret, irq;
304b6bdfcf5SRussell King 
305f85fac0eSRussell King 	if (nep)
306f942b0fdSRussell King 		return -EBUSY;
307f942b0fdSRussell King 
308b6bdfcf5SRussell King 	irq = ret = platform_get_irq(dev, 0);
309b6bdfcf5SRussell King 	if (ret < 0)
310b6bdfcf5SRussell King 		goto err_alloc;
311ae14c2e2SRussell King 
312f942b0fdSRussell King 	nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
313d2e539a5SRussell King 	smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
314d2e539a5SRussell King 	sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
315f942b0fdSRussell King 	if (!nep_res || !smc91x_res || !sa1111_res) {
316d2e539a5SRussell King 		ret = -ENXIO;
317d2e539a5SRussell King 		goto err_alloc;
318d2e539a5SRussell King 	}
319d2e539a5SRussell King 
320ae14c2e2SRussell King 	d = kzalloc(sizeof(*d), GFP_KERNEL);
321ae14c2e2SRussell King 	if (!d) {
322ae14c2e2SRussell King 		ret = -ENOMEM;
323ae14c2e2SRussell King 		goto err_alloc;
324ae14c2e2SRussell King 	}
325ae14c2e2SRussell King 
326f942b0fdSRussell King 	d->base = ioremap(nep_res->start, SZ_4K);
327f942b0fdSRussell King 	if (!d->base) {
328f942b0fdSRussell King 		ret = -ENOMEM;
329f942b0fdSRussell King 		goto err_ioremap;
330f942b0fdSRussell King 	}
331f942b0fdSRussell King 
332f942b0fdSRussell King 	if (readb_relaxed(d->base + WHOAMI) != 0x11) {
333f942b0fdSRussell King 		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
334f942b0fdSRussell King 			 readb_relaxed(d->base + WHOAMI));
335f942b0fdSRussell King 		ret = -ENODEV;
336f942b0fdSRussell King 		goto err_id;
337f942b0fdSRussell King 	}
338f942b0fdSRussell King 
339ced8d21cSRussell King 	ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
340ced8d21cSRussell King 	if (ret <= 0) {
341ced8d21cSRussell King 		dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
342ced8d21cSRussell King 			NEP_IRQ_NR, ret);
343ced8d21cSRussell King 		if (ret == 0)
344ced8d21cSRussell King 			ret = -ENOMEM;
345ced8d21cSRussell King 		goto err_irq_alloc;
346ced8d21cSRussell King 	}
3471da177e4SLinus Torvalds 
348ced8d21cSRussell King 	d->irq_base = ret;
349ced8d21cSRussell King 
350ced8d21cSRussell King 	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
351ced8d21cSRussell King 		handle_simple_irq);
352e8d36d5dSRob Herring 	irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE);
353ced8d21cSRussell King 	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
354ced8d21cSRussell King 		handle_simple_irq);
355e8d36d5dSRob Herring 	irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE);
356ced8d21cSRussell King 	irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
357ced8d21cSRussell King 
358b6bdfcf5SRussell King 	irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
359056c0acfSRussell King 	irq_set_chained_handler_and_data(irq, neponset_irq_handler, d);
3601da177e4SLinus Torvalds 
361f85fac0eSRussell King 	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
362f85fac0eSRussell King 	writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
363f85fac0eSRussell King 
364f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[0], &dev->dev, "neponset-ncr",
365f85fac0eSRussell King 			   d->base + NCR_0, NCR_NGPIO, false,
366f85fac0eSRussell King 			   neponset_ncr_names);
367f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[1], &dev->dev, "neponset-mdm-ctl0",
368f85fac0eSRussell King 			   d->base + MDM_CTL_0, MDM_CTL0_NGPIO, false,
369f85fac0eSRussell King 			   neponset_mdmctl0_names);
370f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[2], &dev->dev, "neponset-mdm-ctl1",
371f85fac0eSRussell King 			   d->base + MDM_CTL_1, MDM_CTL1_NGPIO, true,
372f85fac0eSRussell King 			   neponset_mdmctl1_names);
373f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[3], &dev->dev, "neponset-aud-ctl",
374f85fac0eSRussell King 			   d->base + AUD_CTL, AUD_NGPIO, false,
375f85fac0eSRussell King 			   neponset_aud_names);
376f85fac0eSRussell King 
3771da177e4SLinus Torvalds 	/*
378ced8d21cSRussell King 	 * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
379ced8d21cSRussell King 	 * something on the Neponset activates this IRQ on sleep (eth?)
3801da177e4SLinus Torvalds 	 */
3811da177e4SLinus Torvalds #if 0
382b6bdfcf5SRussell King 	enable_irq_wake(irq);
3831da177e4SLinus Torvalds #endif
3841da177e4SLinus Torvalds 
385ced8d21cSRussell King 	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
386ced8d21cSRussell King 		 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
387f85fac0eSRussell King 	nep = d;
3881da177e4SLinus Torvalds 
389ced8d21cSRussell King 	sa1100_register_uart_fns(&neponset_port_fns);
390ced8d21cSRussell King 
391bab50a35SRussell King 	/* Ensure that the memory bus request/grant signals are setup */
392bab50a35SRussell King 	sa1110_mb_disable();
393bab50a35SRussell King 
394d2e539a5SRussell King 	sa1111_resources[0].parent = sa1111_res;
395ced8d21cSRussell King 	sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
396ced8d21cSRussell King 	sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
3979590e898SRussell King 	d->sa1111 = platform_device_register_full(&sa1111_devinfo);
398ced8d21cSRussell King 
399d2e539a5SRussell King 	smc91x_resources[0].parent = smc91x_res;
400d2e539a5SRussell King 	smc91x_resources[1].parent = smc91x_res;
401ced8d21cSRussell King 	smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
402ced8d21cSRussell King 	smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
4039590e898SRussell King 	d->smc91x = platform_device_register_full(&smc91x_devinfo);
4049590e898SRussell King 
405ae14c2e2SRussell King 	platform_set_drvdata(dev, d);
406ae14c2e2SRussell King 
407ae14c2e2SRussell King 	return 0;
408ae14c2e2SRussell King 
409ced8d21cSRussell King  err_irq_alloc:
410f942b0fdSRussell King  err_id:
411f942b0fdSRussell King 	iounmap(d->base);
412f942b0fdSRussell King  err_ioremap:
413ced8d21cSRussell King 	kfree(d);
414ae14c2e2SRussell King  err_alloc:
415ae14c2e2SRussell King 	return ret;
416ae14c2e2SRussell King }
417ae14c2e2SRussell King 
418351a102dSGreg Kroah-Hartman static int neponset_remove(struct platform_device *dev)
419ae14c2e2SRussell King {
420ae14c2e2SRussell King 	struct neponset_drvdata *d = platform_get_drvdata(dev);
421b6bdfcf5SRussell King 	int irq = platform_get_irq(dev, 0);
422ae14c2e2SRussell King 
4239590e898SRussell King 	if (!IS_ERR(d->sa1111))
4249590e898SRussell King 		platform_device_unregister(d->sa1111);
4259590e898SRussell King 	if (!IS_ERR(d->smc91x))
4269590e898SRussell King 		platform_device_unregister(d->smc91x);
427b6bdfcf5SRussell King 	irq_set_chained_handler(irq, NULL);
428ced8d21cSRussell King 	irq_free_descs(d->irq_base, NEP_IRQ_NR);
429f85fac0eSRussell King 	nep = NULL;
430f942b0fdSRussell King 	iounmap(d->base);
431ae14c2e2SRussell King 	kfree(d);
432ae14c2e2SRussell King 
4331da177e4SLinus Torvalds 	return 0;
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds 
43651f93390SRussell King #ifdef CONFIG_PM_SLEEP
43751f93390SRussell King static int neponset_resume(struct device *dev)
4381da177e4SLinus Torvalds {
43951f93390SRussell King 	struct neponset_drvdata *d = dev_get_drvdata(dev);
440f85fac0eSRussell King 	int i, ret = 0;
441ae14c2e2SRussell King 
442f85fac0eSRussell King 	for (i = 0; i < ARRAY_SIZE(d->gpio); i++) {
443f85fac0eSRussell King 		ret = gpio_reg_resume(d->gpio[i]);
444f85fac0eSRussell King 		if (ret)
445f85fac0eSRussell King 			break;
446f85fac0eSRussell King 	}
4471da177e4SLinus Torvalds 
448f85fac0eSRussell King 	return ret;
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds 
45151f93390SRussell King static const struct dev_pm_ops neponset_pm_ops = {
45251f93390SRussell King 	.resume_noirq = neponset_resume,
45351f93390SRussell King 	.restore_noirq = neponset_resume,
45451f93390SRussell King };
45551f93390SRussell King #define PM_OPS &neponset_pm_ops
4561da177e4SLinus Torvalds #else
45751f93390SRussell King #define PM_OPS NULL
4581da177e4SLinus Torvalds #endif
4591da177e4SLinus Torvalds 
4603ae5eaecSRussell King static struct platform_driver neponset_device_driver = {
4611da177e4SLinus Torvalds 	.probe		= neponset_probe,
462351a102dSGreg Kroah-Hartman 	.remove		= neponset_remove,
4633ae5eaecSRussell King 	.driver		= {
4643ae5eaecSRussell King 		.name	= "neponset",
46551f93390SRussell King 		.pm	= PM_OPS,
4663ae5eaecSRussell King 	},
4671da177e4SLinus Torvalds };
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds static int __init neponset_init(void)
4701da177e4SLinus Torvalds {
471bab50a35SRussell King 	return platform_driver_register(&neponset_device_driver);
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds subsys_initcall(neponset_init);
475