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