xref: /openbmc/linux/drivers/input/joystick/n64joy.c (revision 3bdffa8ffb45c4f217d31a9250e90432ac31b35e)
1*3bdffa8fSLauri Kasanen // SPDX-License-Identifier: GPL-2.0
2*3bdffa8fSLauri Kasanen /*
3*3bdffa8fSLauri Kasanen  * Support for the four N64 controllers.
4*3bdffa8fSLauri Kasanen  *
5*3bdffa8fSLauri Kasanen  * Copyright (c) 2021 Lauri Kasanen
6*3bdffa8fSLauri Kasanen  */
7*3bdffa8fSLauri Kasanen 
8*3bdffa8fSLauri Kasanen #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9*3bdffa8fSLauri Kasanen 
10*3bdffa8fSLauri Kasanen #include <linux/errno.h>
11*3bdffa8fSLauri Kasanen #include <linux/init.h>
12*3bdffa8fSLauri Kasanen #include <linux/input.h>
13*3bdffa8fSLauri Kasanen #include <linux/limits.h>
14*3bdffa8fSLauri Kasanen #include <linux/kernel.h>
15*3bdffa8fSLauri Kasanen #include <linux/module.h>
16*3bdffa8fSLauri Kasanen #include <linux/mutex.h>
17*3bdffa8fSLauri Kasanen #include <linux/platform_device.h>
18*3bdffa8fSLauri Kasanen #include <linux/slab.h>
19*3bdffa8fSLauri Kasanen #include <linux/timer.h>
20*3bdffa8fSLauri Kasanen 
21*3bdffa8fSLauri Kasanen MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
22*3bdffa8fSLauri Kasanen MODULE_DESCRIPTION("Driver for N64 controllers");
23*3bdffa8fSLauri Kasanen MODULE_LICENSE("GPL");
24*3bdffa8fSLauri Kasanen 
25*3bdffa8fSLauri Kasanen #define PIF_RAM 0x1fc007c0
26*3bdffa8fSLauri Kasanen 
27*3bdffa8fSLauri Kasanen #define SI_DRAM_REG 0
28*3bdffa8fSLauri Kasanen #define SI_READ_REG 1
29*3bdffa8fSLauri Kasanen #define SI_WRITE_REG 4
30*3bdffa8fSLauri Kasanen #define SI_STATUS_REG 6
31*3bdffa8fSLauri Kasanen 
32*3bdffa8fSLauri Kasanen #define SI_STATUS_DMA_BUSY  BIT(0)
33*3bdffa8fSLauri Kasanen #define SI_STATUS_IO_BUSY   BIT(1)
34*3bdffa8fSLauri Kasanen 
35*3bdffa8fSLauri Kasanen #define N64_CONTROLLER_ID 0x0500
36*3bdffa8fSLauri Kasanen 
37*3bdffa8fSLauri Kasanen #define MAX_CONTROLLERS 4
38*3bdffa8fSLauri Kasanen 
39*3bdffa8fSLauri Kasanen static const char *n64joy_phys[MAX_CONTROLLERS] = {
40*3bdffa8fSLauri Kasanen 	"n64joy/port0",
41*3bdffa8fSLauri Kasanen 	"n64joy/port1",
42*3bdffa8fSLauri Kasanen 	"n64joy/port2",
43*3bdffa8fSLauri Kasanen 	"n64joy/port3",
44*3bdffa8fSLauri Kasanen };
45*3bdffa8fSLauri Kasanen 
46*3bdffa8fSLauri Kasanen struct n64joy_priv {
47*3bdffa8fSLauri Kasanen 	u64 si_buf[8] ____cacheline_aligned;
48*3bdffa8fSLauri Kasanen 	struct timer_list timer;
49*3bdffa8fSLauri Kasanen 	struct mutex n64joy_mutex;
50*3bdffa8fSLauri Kasanen 	struct input_dev *n64joy_dev[MAX_CONTROLLERS];
51*3bdffa8fSLauri Kasanen 	u32 __iomem *reg_base;
52*3bdffa8fSLauri Kasanen 	u8 n64joy_opened;
53*3bdffa8fSLauri Kasanen };
54*3bdffa8fSLauri Kasanen 
55*3bdffa8fSLauri Kasanen struct joydata {
56*3bdffa8fSLauri Kasanen 	unsigned int: 16; /* unused */
57*3bdffa8fSLauri Kasanen 	unsigned int err: 2;
58*3bdffa8fSLauri Kasanen 	unsigned int: 14; /* unused */
59*3bdffa8fSLauri Kasanen 
60*3bdffa8fSLauri Kasanen 	union {
61*3bdffa8fSLauri Kasanen 		u32 data;
62*3bdffa8fSLauri Kasanen 
63*3bdffa8fSLauri Kasanen 		struct {
64*3bdffa8fSLauri Kasanen 			unsigned int a: 1;
65*3bdffa8fSLauri Kasanen 			unsigned int b: 1;
66*3bdffa8fSLauri Kasanen 			unsigned int z: 1;
67*3bdffa8fSLauri Kasanen 			unsigned int start: 1;
68*3bdffa8fSLauri Kasanen 			unsigned int up: 1;
69*3bdffa8fSLauri Kasanen 			unsigned int down: 1;
70*3bdffa8fSLauri Kasanen 			unsigned int left: 1;
71*3bdffa8fSLauri Kasanen 			unsigned int right: 1;
72*3bdffa8fSLauri Kasanen 			unsigned int: 2; /* unused */
73*3bdffa8fSLauri Kasanen 			unsigned int l: 1;
74*3bdffa8fSLauri Kasanen 			unsigned int r: 1;
75*3bdffa8fSLauri Kasanen 			unsigned int c_up: 1;
76*3bdffa8fSLauri Kasanen 			unsigned int c_down: 1;
77*3bdffa8fSLauri Kasanen 			unsigned int c_left: 1;
78*3bdffa8fSLauri Kasanen 			unsigned int c_right: 1;
79*3bdffa8fSLauri Kasanen 			signed int x: 8;
80*3bdffa8fSLauri Kasanen 			signed int y: 8;
81*3bdffa8fSLauri Kasanen 		};
82*3bdffa8fSLauri Kasanen 	};
83*3bdffa8fSLauri Kasanen };
84*3bdffa8fSLauri Kasanen 
85*3bdffa8fSLauri Kasanen static void n64joy_write_reg(u32 __iomem *reg_base, const u8 reg, const u32 value)
86*3bdffa8fSLauri Kasanen {
87*3bdffa8fSLauri Kasanen 	writel(value, reg_base + reg);
88*3bdffa8fSLauri Kasanen }
89*3bdffa8fSLauri Kasanen 
90*3bdffa8fSLauri Kasanen static u32 n64joy_read_reg(u32 __iomem *reg_base, const u8 reg)
91*3bdffa8fSLauri Kasanen {
92*3bdffa8fSLauri Kasanen 	return readl(reg_base + reg);
93*3bdffa8fSLauri Kasanen }
94*3bdffa8fSLauri Kasanen 
95*3bdffa8fSLauri Kasanen static void n64joy_wait_si_dma(u32 __iomem *reg_base)
96*3bdffa8fSLauri Kasanen {
97*3bdffa8fSLauri Kasanen 	while (n64joy_read_reg(reg_base, SI_STATUS_REG) &
98*3bdffa8fSLauri Kasanen 	       (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY))
99*3bdffa8fSLauri Kasanen 		cpu_relax();
100*3bdffa8fSLauri Kasanen }
101*3bdffa8fSLauri Kasanen 
102*3bdffa8fSLauri Kasanen static void n64joy_exec_pif(struct n64joy_priv *priv, const u64 in[8])
103*3bdffa8fSLauri Kasanen {
104*3bdffa8fSLauri Kasanen 	unsigned long flags;
105*3bdffa8fSLauri Kasanen 
106*3bdffa8fSLauri Kasanen 	dma_cache_wback_inv((unsigned long) in, 8 * 8);
107*3bdffa8fSLauri Kasanen 	dma_cache_inv((unsigned long) priv->si_buf, 8 * 8);
108*3bdffa8fSLauri Kasanen 
109*3bdffa8fSLauri Kasanen 	local_irq_save(flags);
110*3bdffa8fSLauri Kasanen 
111*3bdffa8fSLauri Kasanen 	n64joy_wait_si_dma(priv->reg_base);
112*3bdffa8fSLauri Kasanen 
113*3bdffa8fSLauri Kasanen 	barrier();
114*3bdffa8fSLauri Kasanen 	n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(in));
115*3bdffa8fSLauri Kasanen 	barrier();
116*3bdffa8fSLauri Kasanen 	n64joy_write_reg(priv->reg_base, SI_WRITE_REG, PIF_RAM);
117*3bdffa8fSLauri Kasanen 	barrier();
118*3bdffa8fSLauri Kasanen 
119*3bdffa8fSLauri Kasanen 	n64joy_wait_si_dma(priv->reg_base);
120*3bdffa8fSLauri Kasanen 
121*3bdffa8fSLauri Kasanen 	barrier();
122*3bdffa8fSLauri Kasanen 	n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(priv->si_buf));
123*3bdffa8fSLauri Kasanen 	barrier();
124*3bdffa8fSLauri Kasanen 	n64joy_write_reg(priv->reg_base, SI_READ_REG, PIF_RAM);
125*3bdffa8fSLauri Kasanen 	barrier();
126*3bdffa8fSLauri Kasanen 
127*3bdffa8fSLauri Kasanen 	n64joy_wait_si_dma(priv->reg_base);
128*3bdffa8fSLauri Kasanen 
129*3bdffa8fSLauri Kasanen 	local_irq_restore(flags);
130*3bdffa8fSLauri Kasanen }
131*3bdffa8fSLauri Kasanen 
132*3bdffa8fSLauri Kasanen static const u64 polldata[] ____cacheline_aligned = {
133*3bdffa8fSLauri Kasanen 	0xff010401ffffffff,
134*3bdffa8fSLauri Kasanen 	0xff010401ffffffff,
135*3bdffa8fSLauri Kasanen 	0xff010401ffffffff,
136*3bdffa8fSLauri Kasanen 	0xff010401ffffffff,
137*3bdffa8fSLauri Kasanen 	0xfe00000000000000,
138*3bdffa8fSLauri Kasanen 	0,
139*3bdffa8fSLauri Kasanen 	0,
140*3bdffa8fSLauri Kasanen 	1
141*3bdffa8fSLauri Kasanen };
142*3bdffa8fSLauri Kasanen 
143*3bdffa8fSLauri Kasanen static void n64joy_poll(struct timer_list *t)
144*3bdffa8fSLauri Kasanen {
145*3bdffa8fSLauri Kasanen 	const struct joydata *data;
146*3bdffa8fSLauri Kasanen 	struct n64joy_priv *priv = container_of(t, struct n64joy_priv, timer);
147*3bdffa8fSLauri Kasanen 	struct input_dev *dev;
148*3bdffa8fSLauri Kasanen 	u32 i;
149*3bdffa8fSLauri Kasanen 
150*3bdffa8fSLauri Kasanen 	n64joy_exec_pif(priv, polldata);
151*3bdffa8fSLauri Kasanen 
152*3bdffa8fSLauri Kasanen 	data = (struct joydata *) priv->si_buf;
153*3bdffa8fSLauri Kasanen 
154*3bdffa8fSLauri Kasanen 	for (i = 0; i < MAX_CONTROLLERS; i++) {
155*3bdffa8fSLauri Kasanen 		if (!priv->n64joy_dev[i])
156*3bdffa8fSLauri Kasanen 			continue;
157*3bdffa8fSLauri Kasanen 
158*3bdffa8fSLauri Kasanen 		dev = priv->n64joy_dev[i];
159*3bdffa8fSLauri Kasanen 
160*3bdffa8fSLauri Kasanen 		/* d-pad */
161*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_DPAD_UP, data[i].up);
162*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_DPAD_DOWN, data[i].down);
163*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_DPAD_LEFT, data[i].left);
164*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_DPAD_RIGHT, data[i].right);
165*3bdffa8fSLauri Kasanen 
166*3bdffa8fSLauri Kasanen 		/* c buttons */
167*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_FORWARD, data[i].c_up);
168*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_BACK, data[i].c_down);
169*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_LEFT, data[i].c_left);
170*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_RIGHT, data[i].c_right);
171*3bdffa8fSLauri Kasanen 
172*3bdffa8fSLauri Kasanen 		/* matching buttons */
173*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_START, data[i].start);
174*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_Z, data[i].z);
175*3bdffa8fSLauri Kasanen 
176*3bdffa8fSLauri Kasanen 		/* remaining ones: a, b, l, r */
177*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_0, data[i].a);
178*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_1, data[i].b);
179*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_2, data[i].l);
180*3bdffa8fSLauri Kasanen 		input_report_key(dev, BTN_3, data[i].r);
181*3bdffa8fSLauri Kasanen 
182*3bdffa8fSLauri Kasanen 		input_report_abs(dev, ABS_X, data[i].x);
183*3bdffa8fSLauri Kasanen 		input_report_abs(dev, ABS_Y, data[i].y);
184*3bdffa8fSLauri Kasanen 
185*3bdffa8fSLauri Kasanen 		input_sync(dev);
186*3bdffa8fSLauri Kasanen 	}
187*3bdffa8fSLauri Kasanen 
188*3bdffa8fSLauri Kasanen 	mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
189*3bdffa8fSLauri Kasanen }
190*3bdffa8fSLauri Kasanen 
191*3bdffa8fSLauri Kasanen static int n64joy_open(struct input_dev *dev)
192*3bdffa8fSLauri Kasanen {
193*3bdffa8fSLauri Kasanen 	struct n64joy_priv *priv = input_get_drvdata(dev);
194*3bdffa8fSLauri Kasanen 	int err;
195*3bdffa8fSLauri Kasanen 
196*3bdffa8fSLauri Kasanen 	err = mutex_lock_interruptible(&priv->n64joy_mutex);
197*3bdffa8fSLauri Kasanen 	if (err)
198*3bdffa8fSLauri Kasanen 		return err;
199*3bdffa8fSLauri Kasanen 
200*3bdffa8fSLauri Kasanen 	if (!priv->n64joy_opened) {
201*3bdffa8fSLauri Kasanen 		/*
202*3bdffa8fSLauri Kasanen 		 * We could use the vblank irq, but it's not important if
203*3bdffa8fSLauri Kasanen 		 * the poll point slightly changes.
204*3bdffa8fSLauri Kasanen 		 */
205*3bdffa8fSLauri Kasanen 		timer_setup(&priv->timer, n64joy_poll, 0);
206*3bdffa8fSLauri Kasanen 		mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
207*3bdffa8fSLauri Kasanen 	}
208*3bdffa8fSLauri Kasanen 
209*3bdffa8fSLauri Kasanen 	priv->n64joy_opened++;
210*3bdffa8fSLauri Kasanen 
211*3bdffa8fSLauri Kasanen 	mutex_unlock(&priv->n64joy_mutex);
212*3bdffa8fSLauri Kasanen 	return err;
213*3bdffa8fSLauri Kasanen }
214*3bdffa8fSLauri Kasanen 
215*3bdffa8fSLauri Kasanen static void n64joy_close(struct input_dev *dev)
216*3bdffa8fSLauri Kasanen {
217*3bdffa8fSLauri Kasanen 	struct n64joy_priv *priv = input_get_drvdata(dev);
218*3bdffa8fSLauri Kasanen 
219*3bdffa8fSLauri Kasanen 	mutex_lock(&priv->n64joy_mutex);
220*3bdffa8fSLauri Kasanen 	if (!--priv->n64joy_opened)
221*3bdffa8fSLauri Kasanen 		del_timer_sync(&priv->timer);
222*3bdffa8fSLauri Kasanen 	mutex_unlock(&priv->n64joy_mutex);
223*3bdffa8fSLauri Kasanen }
224*3bdffa8fSLauri Kasanen 
225*3bdffa8fSLauri Kasanen static const u64 __initconst scandata[] ____cacheline_aligned = {
226*3bdffa8fSLauri Kasanen 	0xff010300ffffffff,
227*3bdffa8fSLauri Kasanen 	0xff010300ffffffff,
228*3bdffa8fSLauri Kasanen 	0xff010300ffffffff,
229*3bdffa8fSLauri Kasanen 	0xff010300ffffffff,
230*3bdffa8fSLauri Kasanen 	0xfe00000000000000,
231*3bdffa8fSLauri Kasanen 	0,
232*3bdffa8fSLauri Kasanen 	0,
233*3bdffa8fSLauri Kasanen 	1
234*3bdffa8fSLauri Kasanen };
235*3bdffa8fSLauri Kasanen 
236*3bdffa8fSLauri Kasanen /*
237*3bdffa8fSLauri Kasanen  * The target device is embedded and RAM-constrained. We save RAM
238*3bdffa8fSLauri Kasanen  * by initializing in __init code that gets dropped late in boot.
239*3bdffa8fSLauri Kasanen  * For the same reason there is no module or unloading support.
240*3bdffa8fSLauri Kasanen  */
241*3bdffa8fSLauri Kasanen static int __init n64joy_probe(struct platform_device *pdev)
242*3bdffa8fSLauri Kasanen {
243*3bdffa8fSLauri Kasanen 	const struct joydata *data;
244*3bdffa8fSLauri Kasanen 	struct n64joy_priv *priv;
245*3bdffa8fSLauri Kasanen 	struct input_dev *dev;
246*3bdffa8fSLauri Kasanen 	int err = 0;
247*3bdffa8fSLauri Kasanen 	u32 i, j, found = 0;
248*3bdffa8fSLauri Kasanen 
249*3bdffa8fSLauri Kasanen 	priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
250*3bdffa8fSLauri Kasanen 	if (!priv)
251*3bdffa8fSLauri Kasanen 		return -ENOMEM;
252*3bdffa8fSLauri Kasanen 	mutex_init(&priv->n64joy_mutex);
253*3bdffa8fSLauri Kasanen 
254*3bdffa8fSLauri Kasanen 	priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
255*3bdffa8fSLauri Kasanen 	if (!priv->reg_base) {
256*3bdffa8fSLauri Kasanen 		err = -EINVAL;
257*3bdffa8fSLauri Kasanen 		goto fail;
258*3bdffa8fSLauri Kasanen 	}
259*3bdffa8fSLauri Kasanen 
260*3bdffa8fSLauri Kasanen 	/* The controllers are not hotpluggable, so we can scan in init */
261*3bdffa8fSLauri Kasanen 	n64joy_exec_pif(priv, scandata);
262*3bdffa8fSLauri Kasanen 
263*3bdffa8fSLauri Kasanen 	data = (struct joydata *) priv->si_buf;
264*3bdffa8fSLauri Kasanen 
265*3bdffa8fSLauri Kasanen 	for (i = 0; i < MAX_CONTROLLERS; i++) {
266*3bdffa8fSLauri Kasanen 		if (!data[i].err && data[i].data >> 16 == N64_CONTROLLER_ID) {
267*3bdffa8fSLauri Kasanen 			found++;
268*3bdffa8fSLauri Kasanen 
269*3bdffa8fSLauri Kasanen 			dev = priv->n64joy_dev[i] = input_allocate_device();
270*3bdffa8fSLauri Kasanen 			if (!priv->n64joy_dev[i]) {
271*3bdffa8fSLauri Kasanen 				err = -ENOMEM;
272*3bdffa8fSLauri Kasanen 				goto fail;
273*3bdffa8fSLauri Kasanen 			}
274*3bdffa8fSLauri Kasanen 
275*3bdffa8fSLauri Kasanen 			input_set_drvdata(dev, priv);
276*3bdffa8fSLauri Kasanen 
277*3bdffa8fSLauri Kasanen 			dev->name = "N64 controller";
278*3bdffa8fSLauri Kasanen 			dev->phys = n64joy_phys[i];
279*3bdffa8fSLauri Kasanen 			dev->id.bustype = BUS_HOST;
280*3bdffa8fSLauri Kasanen 			dev->id.vendor = 0;
281*3bdffa8fSLauri Kasanen 			dev->id.product = data[i].data >> 16;
282*3bdffa8fSLauri Kasanen 			dev->id.version = 0;
283*3bdffa8fSLauri Kasanen 			dev->dev.parent = &pdev->dev;
284*3bdffa8fSLauri Kasanen 
285*3bdffa8fSLauri Kasanen 			dev->open = n64joy_open;
286*3bdffa8fSLauri Kasanen 			dev->close = n64joy_close;
287*3bdffa8fSLauri Kasanen 
288*3bdffa8fSLauri Kasanen 			/* d-pad */
289*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_DPAD_UP);
290*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_DPAD_DOWN);
291*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_DPAD_LEFT);
292*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_DPAD_RIGHT);
293*3bdffa8fSLauri Kasanen 			/* c buttons */
294*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_LEFT);
295*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_RIGHT);
296*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_FORWARD);
297*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_BACK);
298*3bdffa8fSLauri Kasanen 			/* matching buttons */
299*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_START);
300*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_Z);
301*3bdffa8fSLauri Kasanen 			/* remaining ones: a, b, l, r */
302*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_0);
303*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_1);
304*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_2);
305*3bdffa8fSLauri Kasanen 			input_set_capability(dev, EV_KEY, BTN_3);
306*3bdffa8fSLauri Kasanen 
307*3bdffa8fSLauri Kasanen 			for (j = 0; j < 2; j++)
308*3bdffa8fSLauri Kasanen 				input_set_abs_params(dev, ABS_X + j,
309*3bdffa8fSLauri Kasanen 						     S8_MIN, S8_MAX, 0, 0);
310*3bdffa8fSLauri Kasanen 
311*3bdffa8fSLauri Kasanen 			err = input_register_device(dev);
312*3bdffa8fSLauri Kasanen 			if (err) {
313*3bdffa8fSLauri Kasanen 				input_free_device(dev);
314*3bdffa8fSLauri Kasanen 				goto fail;
315*3bdffa8fSLauri Kasanen 			}
316*3bdffa8fSLauri Kasanen 		}
317*3bdffa8fSLauri Kasanen 	}
318*3bdffa8fSLauri Kasanen 
319*3bdffa8fSLauri Kasanen 	pr_info("%u controller(s) connected\n", found);
320*3bdffa8fSLauri Kasanen 
321*3bdffa8fSLauri Kasanen 	if (!found)
322*3bdffa8fSLauri Kasanen 		return -ENODEV;
323*3bdffa8fSLauri Kasanen 
324*3bdffa8fSLauri Kasanen 	return 0;
325*3bdffa8fSLauri Kasanen fail:
326*3bdffa8fSLauri Kasanen 	for (i = 0; i < MAX_CONTROLLERS; i++) {
327*3bdffa8fSLauri Kasanen 		if (!priv->n64joy_dev[i])
328*3bdffa8fSLauri Kasanen 			continue;
329*3bdffa8fSLauri Kasanen 		input_unregister_device(priv->n64joy_dev[i]);
330*3bdffa8fSLauri Kasanen 	}
331*3bdffa8fSLauri Kasanen 	return err;
332*3bdffa8fSLauri Kasanen }
333*3bdffa8fSLauri Kasanen 
334*3bdffa8fSLauri Kasanen static struct platform_driver n64joy_driver = {
335*3bdffa8fSLauri Kasanen 	.driver = {
336*3bdffa8fSLauri Kasanen 		.name = "n64joy",
337*3bdffa8fSLauri Kasanen 	},
338*3bdffa8fSLauri Kasanen };
339*3bdffa8fSLauri Kasanen 
340*3bdffa8fSLauri Kasanen static int __init n64joy_init(void)
341*3bdffa8fSLauri Kasanen {
342*3bdffa8fSLauri Kasanen 	return platform_driver_probe(&n64joy_driver, n64joy_probe);
343*3bdffa8fSLauri Kasanen }
344*3bdffa8fSLauri Kasanen 
345*3bdffa8fSLauri Kasanen module_init(n64joy_init);
346