xref: /openbmc/linux/arch/arm/mach-sa1100/neponset.c (revision 74a5b94b)
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>
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>
2387dfb311SMasahiro Yamada #include <linux/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 #define MDM_CTL0_NGPIO	4
52f85fac0eSRussell King #define MDM_CTL1_NGPIO	6
53f85fac0eSRussell King #define AUD_NGPIO	2
54f942b0fdSRussell King 
55bab50a35SRussell King extern void sa1110_mb_disable(void);
56bab50a35SRussell King 
57f85fac0eSRussell King #define to_neponset_gpio_chip(x) container_of(x, struct neponset_gpio_chip, gc)
58f85fac0eSRussell King 
59f85fac0eSRussell King static const char *neponset_ncr_names[] = {
60f85fac0eSRussell King 	"gp01_off", "tp_power", "ms_power", "enet_osc",
61f85fac0eSRussell King 	"spi_kb_wk_up", "a0vpp", "a1vpp"
62f85fac0eSRussell King };
63f85fac0eSRussell King 
64f85fac0eSRussell King static const char *neponset_mdmctl0_names[] = {
65f85fac0eSRussell King 	"rts3", "dtr3", "rts1", "dtr1",
66f85fac0eSRussell King };
67f85fac0eSRussell King 
68f85fac0eSRussell King static const char *neponset_mdmctl1_names[] = {
69f85fac0eSRussell King 	"cts3", "dsr3", "dcd3", "cts1", "dsr1", "dcd1"
70f85fac0eSRussell King };
71f85fac0eSRussell King 
72f85fac0eSRussell King static const char *neponset_aud_names[] = {
73f85fac0eSRussell King 	"sel_1341", "mute_1341",
74f85fac0eSRussell King };
75f85fac0eSRussell King 
76ae14c2e2SRussell King struct neponset_drvdata {
77f942b0fdSRussell King 	void __iomem *base;
789590e898SRussell King 	struct platform_device *sa1111;
799590e898SRussell King 	struct platform_device *smc91x;
80ced8d21cSRussell King 	unsigned irq_base;
81f85fac0eSRussell King 	struct gpio_chip *gpio[4];
82ae14c2e2SRussell King };
83ae14c2e2SRussell King 
845c9e4d8cSRussell King static struct gpiod_lookup_table neponset_uart1_gpio_table = {
855c9e4d8cSRussell King 	.dev_id = "sa11x0-uart.1",
865c9e4d8cSRussell King 	.table = {
875c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl0", 2, "rts", GPIO_ACTIVE_LOW),
885c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl0", 3, "dtr", GPIO_ACTIVE_LOW),
895c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 3, "cts", GPIO_ACTIVE_LOW),
905c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 4, "dsr", GPIO_ACTIVE_LOW),
915c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 5, "dcd", GPIO_ACTIVE_LOW),
925c9e4d8cSRussell King 		{ },
935c9e4d8cSRussell King 	},
945c9e4d8cSRussell King };
955c9e4d8cSRussell King 
965c9e4d8cSRussell King static struct gpiod_lookup_table neponset_uart3_gpio_table = {
975c9e4d8cSRussell King 	.dev_id = "sa11x0-uart.3",
985c9e4d8cSRussell King 	.table = {
995c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl0", 0, "rts", GPIO_ACTIVE_LOW),
1005c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl0", 1, "dtr", GPIO_ACTIVE_LOW),
1015c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 0, "cts", GPIO_ACTIVE_LOW),
1025c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 1, "dsr", GPIO_ACTIVE_LOW),
1035c9e4d8cSRussell King 		GPIO_LOOKUP("neponset-mdm-ctl1", 2, "dcd", GPIO_ACTIVE_LOW),
1045c9e4d8cSRussell King 		{ },
1055c9e4d8cSRussell King 	},
1065c9e4d8cSRussell King };
1075c9e4d8cSRussell King 
108e2125d05SRussell King static struct gpiod_lookup_table neponset_pcmcia_table = {
109e2125d05SRussell King 	.dev_id = "1800",
110e2125d05SRussell King 	.table = {
111e2125d05SRussell King 		GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH),
112e2125d05SRussell King 		GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH),
113e2125d05SRussell King 		GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH),
114e2125d05SRussell King 		GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH),
115e2125d05SRussell King 		GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH),
116e2125d05SRussell King 		GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH),
117e2125d05SRussell King 		{ },
118e2125d05SRussell King 	},
119e2125d05SRussell King };
120e2125d05SRussell King 
121f85fac0eSRussell King static struct neponset_drvdata *nep;
122f942b0fdSRussell King 
neponset_ncr_frob(unsigned int mask,unsigned int val)1236ad1b614SRussell King void neponset_ncr_frob(unsigned int mask, unsigned int val)
1246ad1b614SRussell King {
125f85fac0eSRussell King 	struct neponset_drvdata *n = nep;
126f85fac0eSRussell King 	unsigned long m = mask, v = val;
127f942b0fdSRussell King 
128f85fac0eSRussell King 	if (nep)
129f85fac0eSRussell King 		n->gpio[0]->set_multiple(n->gpio[0], &m, &v);
130f85fac0eSRussell King 	else
131f85fac0eSRussell King 		WARN(1, "nep unset\n");
1326ad1b614SRussell King }
133ef0c1484SRussell King EXPORT_SYMBOL(neponset_ncr_frob);
1346ad1b614SRussell King 
13571045520SRussell King /*
13692e617d9SRussell King  * Install handler for Neponset IRQ.  Note that we have to loop here
13792e617d9SRussell King  * since the ETHERNET and USAR IRQs are level based, and we need to
13892e617d9SRussell King  * ensure that the IRQ signal is deasserted before returning.  This
13992e617d9SRussell King  * is rather unfortunate.
14092e617d9SRussell King  */
neponset_irq_handler(struct irq_desc * desc)141bd0b9ac4SThomas Gleixner static void neponset_irq_handler(struct irq_desc *desc)
14292e617d9SRussell King {
143ced8d21cSRussell King 	struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
14492e617d9SRussell King 	unsigned int irr;
14592e617d9SRussell King 
14692e617d9SRussell King 	while (1) {
14792e617d9SRussell King 		/*
14892e617d9SRussell King 		 * Acknowledge the parent IRQ.
14992e617d9SRussell King 		 */
15092e617d9SRussell King 		desc->irq_data.chip->irq_ack(&desc->irq_data);
15192e617d9SRussell King 
15292e617d9SRussell King 		/*
15392e617d9SRussell King 		 * Read the interrupt reason register.  Let's have all
15492e617d9SRussell King 		 * active IRQ bits high.  Note: there is a typo in the
15592e617d9SRussell King 		 * Neponset user's guide for the SA1111 IRR level.
15692e617d9SRussell King 		 */
157f942b0fdSRussell King 		irr = readb_relaxed(d->base + IRR);
158f942b0fdSRussell King 		irr ^= IRR_ETHERNET | IRR_USAR;
15992e617d9SRussell King 
16092e617d9SRussell King 		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
16192e617d9SRussell King 			break;
16292e617d9SRussell King 
16392e617d9SRussell King 		/*
16492e617d9SRussell King 		 * Since there is no individual mask, we have to
16592e617d9SRussell King 		 * mask the parent IRQ.  This is safe, since we'll
16692e617d9SRussell King 		 * recheck the register for any pending IRQs.
16792e617d9SRussell King 		 */
16892e617d9SRussell King 		if (irr & (IRR_ETHERNET | IRR_USAR)) {
16992e617d9SRussell King 			desc->irq_data.chip->irq_mask(&desc->irq_data);
17092e617d9SRussell King 
17192e617d9SRussell King 			/*
17292e617d9SRussell King 			 * Ack the interrupt now to prevent re-entering
17392e617d9SRussell King 			 * this neponset handler.  Again, this is safe
17492e617d9SRussell King 			 * since we'll check the IRR register prior to
17592e617d9SRussell King 			 * leaving.
17692e617d9SRussell King 			 */
17792e617d9SRussell King 			desc->irq_data.chip->irq_ack(&desc->irq_data);
17892e617d9SRussell King 
179ced8d21cSRussell King 			if (irr & IRR_ETHERNET)
180ced8d21cSRussell King 				generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
18192e617d9SRussell King 
182ced8d21cSRussell King 			if (irr & IRR_USAR)
183ced8d21cSRussell King 				generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
18492e617d9SRussell King 
18592e617d9SRussell King 			desc->irq_data.chip->irq_unmask(&desc->irq_data);
18692e617d9SRussell King 		}
18792e617d9SRussell King 
188ced8d21cSRussell King 		if (irr & IRR_SA1111)
189ced8d21cSRussell King 			generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
19092e617d9SRussell King 	}
19192e617d9SRussell King }
19292e617d9SRussell King 
193ced8d21cSRussell King /* Yes, we really do not have any kind of masking or unmasking */
nochip_noop(struct irq_data * irq)19471045520SRussell King static void nochip_noop(struct irq_data *irq)
19571045520SRussell King {
19671045520SRussell King }
19771045520SRussell King 
19871045520SRussell King static struct irq_chip nochip = {
19971045520SRussell King 	.name = "neponset",
20071045520SRussell King 	.irq_ack = nochip_noop,
20171045520SRussell King 	.irq_mask = nochip_noop,
20271045520SRussell King 	.irq_unmask = nochip_noop,
20371045520SRussell King };
20471045520SRussell King 
neponset_init_gpio(struct gpio_chip ** gcp,struct device * dev,const char * label,void __iomem * reg,unsigned num,bool in,const char * const * names)205f85fac0eSRussell King static int neponset_init_gpio(struct gpio_chip **gcp,
206f85fac0eSRussell King 	struct device *dev, const char *label, void __iomem *reg,
207f85fac0eSRussell King 	unsigned num, bool in, const char *const * names)
208f85fac0eSRussell King {
209f85fac0eSRussell King 	struct gpio_chip *gc;
210f85fac0eSRussell King 
211f85fac0eSRussell King 	gc = gpio_reg_init(dev, reg, -1, num, label, in ? 0xffffffff : 0,
212f85fac0eSRussell King 			   readl_relaxed(reg), names, NULL, NULL);
213f85fac0eSRussell King 	if (IS_ERR(gc))
214f85fac0eSRussell King 		return PTR_ERR(gc);
215f85fac0eSRussell King 
216f85fac0eSRussell King 	*gcp = gc;
217f85fac0eSRussell King 
218f85fac0eSRussell King 	return 0;
219f85fac0eSRussell King }
220f85fac0eSRussell King 
22192e617d9SRussell King static struct sa1111_platform_data sa1111_info = {
22207be45f5SRussell King 	.disable_devs	= SA1111_DEVID_PS2_MSE,
22392e617d9SRussell King };
22492e617d9SRussell King 
neponset_probe(struct platform_device * dev)225351a102dSGreg Kroah-Hartman static int neponset_probe(struct platform_device *dev)
2261da177e4SLinus Torvalds {
227ae14c2e2SRussell King 	struct neponset_drvdata *d;
228f942b0fdSRussell King 	struct resource *nep_res, *sa1111_res, *smc91x_res;
229ced8d21cSRussell King 	struct resource sa1111_resources[] = {
230ced8d21cSRussell King 		DEFINE_RES_MEM(0x40000000, SZ_8K),
231ced8d21cSRussell King 		{ .flags = IORESOURCE_IRQ },
232ced8d21cSRussell King 	};
2339590e898SRussell King 	struct platform_device_info sa1111_devinfo = {
2349590e898SRussell King 		.parent = &dev->dev,
2359590e898SRussell King 		.name = "sa1111",
2369590e898SRussell King 		.id = 0,
2379590e898SRussell King 		.res = sa1111_resources,
2389590e898SRussell King 		.num_res = ARRAY_SIZE(sa1111_resources),
2399590e898SRussell King 		.data = &sa1111_info,
2409590e898SRussell King 		.size_data = sizeof(sa1111_info),
2419590e898SRussell King 		.dma_mask = 0xffffffffUL,
2429590e898SRussell King 	};
243ced8d21cSRussell King 	struct resource smc91x_resources[] = {
244ced8d21cSRussell King 		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
245ced8d21cSRussell King 			0x02000000, "smc91x-regs"),
246ced8d21cSRussell King 		DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
247ced8d21cSRussell King 			0x02000000, "smc91x-attrib"),
248ced8d21cSRussell King 		{ .flags = IORESOURCE_IRQ },
249ced8d21cSRussell King 	};
250b70661c7SArnd Bergmann 	struct smc91x_platdata smc91x_platdata = {
251b70661c7SArnd Bergmann 		.flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
252b70661c7SArnd Bergmann 	};
2539590e898SRussell King 	struct platform_device_info smc91x_devinfo = {
2549590e898SRussell King 		.parent = &dev->dev,
2559590e898SRussell King 		.name = "smc91x",
2569590e898SRussell King 		.id = 0,
2579590e898SRussell King 		.res = smc91x_resources,
2589590e898SRussell King 		.num_res = ARRAY_SIZE(smc91x_resources),
25904b91701SArnd Bergmann 		.data = &smc91x_platdata,
26004b91701SArnd Bergmann 		.size_data = sizeof(smc91x_platdata),
2619590e898SRussell King 	};
262b6bdfcf5SRussell King 	int ret, irq;
263b6bdfcf5SRussell King 
264f85fac0eSRussell King 	if (nep)
265f942b0fdSRussell King 		return -EBUSY;
266f942b0fdSRussell King 
267b6bdfcf5SRussell King 	irq = ret = platform_get_irq(dev, 0);
268b6bdfcf5SRussell King 	if (ret < 0)
269b6bdfcf5SRussell King 		goto err_alloc;
270ae14c2e2SRussell King 
271f942b0fdSRussell King 	nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
272d2e539a5SRussell King 	smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
273d2e539a5SRussell King 	sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
274f942b0fdSRussell King 	if (!nep_res || !smc91x_res || !sa1111_res) {
275d2e539a5SRussell King 		ret = -ENXIO;
276d2e539a5SRussell King 		goto err_alloc;
277d2e539a5SRussell King 	}
278d2e539a5SRussell King 
279ae14c2e2SRussell King 	d = kzalloc(sizeof(*d), GFP_KERNEL);
280ae14c2e2SRussell King 	if (!d) {
281ae14c2e2SRussell King 		ret = -ENOMEM;
282ae14c2e2SRussell King 		goto err_alloc;
283ae14c2e2SRussell King 	}
284ae14c2e2SRussell King 
285f942b0fdSRussell King 	d->base = ioremap(nep_res->start, SZ_4K);
286f942b0fdSRussell King 	if (!d->base) {
287f942b0fdSRussell King 		ret = -ENOMEM;
288f942b0fdSRussell King 		goto err_ioremap;
289f942b0fdSRussell King 	}
290f942b0fdSRussell King 
291f942b0fdSRussell King 	if (readb_relaxed(d->base + WHOAMI) != 0x11) {
292f942b0fdSRussell King 		dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
293f942b0fdSRussell King 			 readb_relaxed(d->base + WHOAMI));
294f942b0fdSRussell King 		ret = -ENODEV;
295f942b0fdSRussell King 		goto err_id;
296f942b0fdSRussell King 	}
297f942b0fdSRussell King 
298ced8d21cSRussell King 	ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
299ced8d21cSRussell King 	if (ret <= 0) {
300ced8d21cSRussell King 		dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
301ced8d21cSRussell King 			NEP_IRQ_NR, ret);
302ced8d21cSRussell King 		if (ret == 0)
303ced8d21cSRussell King 			ret = -ENOMEM;
304ced8d21cSRussell King 		goto err_irq_alloc;
305ced8d21cSRussell King 	}
3061da177e4SLinus Torvalds 
307ced8d21cSRussell King 	d->irq_base = ret;
308ced8d21cSRussell King 
309ced8d21cSRussell King 	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
310ced8d21cSRussell King 		handle_simple_irq);
311e8d36d5dSRob Herring 	irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE);
312ced8d21cSRussell King 	irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
313ced8d21cSRussell King 		handle_simple_irq);
314e8d36d5dSRob Herring 	irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE);
315ced8d21cSRussell King 	irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
316ced8d21cSRussell King 
317b6bdfcf5SRussell King 	irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
318056c0acfSRussell King 	irq_set_chained_handler_and_data(irq, neponset_irq_handler, d);
3191da177e4SLinus Torvalds 
320f85fac0eSRussell King 	/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
321f85fac0eSRussell King 	writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
322f85fac0eSRussell King 
323f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[0], &dev->dev, "neponset-ncr",
324f85fac0eSRussell King 			   d->base + NCR_0, NCR_NGPIO, false,
325f85fac0eSRussell King 			   neponset_ncr_names);
326f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[1], &dev->dev, "neponset-mdm-ctl0",
327f85fac0eSRussell King 			   d->base + MDM_CTL_0, MDM_CTL0_NGPIO, false,
328f85fac0eSRussell King 			   neponset_mdmctl0_names);
329f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[2], &dev->dev, "neponset-mdm-ctl1",
330f85fac0eSRussell King 			   d->base + MDM_CTL_1, MDM_CTL1_NGPIO, true,
331f85fac0eSRussell King 			   neponset_mdmctl1_names);
332f85fac0eSRussell King 	neponset_init_gpio(&d->gpio[3], &dev->dev, "neponset-aud-ctl",
333f85fac0eSRussell King 			   d->base + AUD_CTL, AUD_NGPIO, false,
334f85fac0eSRussell King 			   neponset_aud_names);
335f85fac0eSRussell King 
3365c9e4d8cSRussell King 	gpiod_add_lookup_table(&neponset_uart1_gpio_table);
3375c9e4d8cSRussell King 	gpiod_add_lookup_table(&neponset_uart3_gpio_table);
338e2125d05SRussell King 	gpiod_add_lookup_table(&neponset_pcmcia_table);
339e2125d05SRussell King 
3401da177e4SLinus Torvalds 	/*
341ced8d21cSRussell King 	 * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
342ced8d21cSRussell King 	 * something on the Neponset activates this IRQ on sleep (eth?)
3431da177e4SLinus Torvalds 	 */
3441da177e4SLinus Torvalds #if 0
345b6bdfcf5SRussell King 	enable_irq_wake(irq);
3461da177e4SLinus Torvalds #endif
3471da177e4SLinus Torvalds 
348ced8d21cSRussell King 	dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
349ced8d21cSRussell King 		 d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
350f85fac0eSRussell King 	nep = d;
3511da177e4SLinus Torvalds 
352bab50a35SRussell King 	/* Ensure that the memory bus request/grant signals are setup */
353bab50a35SRussell King 	sa1110_mb_disable();
354bab50a35SRussell King 
355d2e539a5SRussell King 	sa1111_resources[0].parent = sa1111_res;
356ced8d21cSRussell King 	sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
357ced8d21cSRussell King 	sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
3589590e898SRussell King 	d->sa1111 = platform_device_register_full(&sa1111_devinfo);
359ced8d21cSRussell King 
360d2e539a5SRussell King 	smc91x_resources[0].parent = smc91x_res;
361d2e539a5SRussell King 	smc91x_resources[1].parent = smc91x_res;
362ced8d21cSRussell King 	smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
363ced8d21cSRussell King 	smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
3649590e898SRussell King 	d->smc91x = platform_device_register_full(&smc91x_devinfo);
3659590e898SRussell King 
366ae14c2e2SRussell King 	platform_set_drvdata(dev, d);
367ae14c2e2SRussell King 
368ae14c2e2SRussell King 	return 0;
369ae14c2e2SRussell King 
370ced8d21cSRussell King  err_irq_alloc:
371f942b0fdSRussell King  err_id:
372f942b0fdSRussell King 	iounmap(d->base);
373f942b0fdSRussell King  err_ioremap:
374ced8d21cSRussell King 	kfree(d);
375ae14c2e2SRussell King  err_alloc:
376ae14c2e2SRussell King 	return ret;
377ae14c2e2SRussell King }
378ae14c2e2SRussell King 
neponset_remove(struct platform_device * dev)379*74a5b94bSUwe Kleine-König static void neponset_remove(struct platform_device *dev)
380ae14c2e2SRussell King {
381ae14c2e2SRussell King 	struct neponset_drvdata *d = platform_get_drvdata(dev);
382b6bdfcf5SRussell King 	int irq = platform_get_irq(dev, 0);
383ae14c2e2SRussell King 
3849590e898SRussell King 	if (!IS_ERR(d->sa1111))
3859590e898SRussell King 		platform_device_unregister(d->sa1111);
3869590e898SRussell King 	if (!IS_ERR(d->smc91x))
3879590e898SRussell King 		platform_device_unregister(d->smc91x);
388e2125d05SRussell King 
389e2125d05SRussell King 	gpiod_remove_lookup_table(&neponset_pcmcia_table);
3905c9e4d8cSRussell King 	gpiod_remove_lookup_table(&neponset_uart3_gpio_table);
3915c9e4d8cSRussell King 	gpiod_remove_lookup_table(&neponset_uart1_gpio_table);
392e2125d05SRussell King 
393b6bdfcf5SRussell King 	irq_set_chained_handler(irq, NULL);
394ced8d21cSRussell King 	irq_free_descs(d->irq_base, NEP_IRQ_NR);
395f85fac0eSRussell King 	nep = NULL;
396f942b0fdSRussell King 	iounmap(d->base);
397ae14c2e2SRussell King 	kfree(d);
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
40051f93390SRussell King #ifdef CONFIG_PM_SLEEP
neponset_resume(struct device * dev)40151f93390SRussell King static int neponset_resume(struct device *dev)
4021da177e4SLinus Torvalds {
40351f93390SRussell King 	struct neponset_drvdata *d = dev_get_drvdata(dev);
404f85fac0eSRussell King 	int i, ret = 0;
405ae14c2e2SRussell King 
406f85fac0eSRussell King 	for (i = 0; i < ARRAY_SIZE(d->gpio); i++) {
407f85fac0eSRussell King 		ret = gpio_reg_resume(d->gpio[i]);
408f85fac0eSRussell King 		if (ret)
409f85fac0eSRussell King 			break;
410f85fac0eSRussell King 	}
4111da177e4SLinus Torvalds 
412f85fac0eSRussell King 	return ret;
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds 
41551f93390SRussell King static const struct dev_pm_ops neponset_pm_ops = {
41651f93390SRussell King 	.resume_noirq = neponset_resume,
41751f93390SRussell King 	.restore_noirq = neponset_resume,
41851f93390SRussell King };
41951f93390SRussell King #define PM_OPS &neponset_pm_ops
4201da177e4SLinus Torvalds #else
42151f93390SRussell King #define PM_OPS NULL
4221da177e4SLinus Torvalds #endif
4231da177e4SLinus Torvalds 
4243ae5eaecSRussell King static struct platform_driver neponset_device_driver = {
4251da177e4SLinus Torvalds 	.probe		= neponset_probe,
426*74a5b94bSUwe Kleine-König 	.remove_new	= neponset_remove,
4273ae5eaecSRussell King 	.driver		= {
4283ae5eaecSRussell King 		.name	= "neponset",
42951f93390SRussell King 		.pm	= PM_OPS,
4303ae5eaecSRussell King 	},
4311da177e4SLinus Torvalds };
4321da177e4SLinus Torvalds 
neponset_init(void)4331da177e4SLinus Torvalds static int __init neponset_init(void)
4341da177e4SLinus Torvalds {
435bab50a35SRussell King 	return platform_driver_register(&neponset_device_driver);
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds subsys_initcall(neponset_init);
439