Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add support for trackball on pxa930 and pxa935

Signed-off-by: Yong Yao <yaoyong@marvell.com>
Signed-off-by: Eric Miao <eric.miao@marvell.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Yong Yao and committed by
Dmitry Torokhov
105ca239 9bcc00b9

+299 -13
+10
arch/arm/mach-pxa/include/mach/pxa930_trkball.h
··· 1 + #ifndef __ASM_ARCH_PXA930_TRKBALL_H 2 + #define __ASM_ARCH_PXA930_TRKBALL_H 3 + 4 + struct pxa930_trkball_platform_data { 5 + int x_filter; 6 + int y_filter; 7 + }; 8 + 9 + #endif /* __ASM_ARCH_PXA930_TRKBALL_H */ 10 +
+6
drivers/input/mouse/Kconfig
··· 286 286 To compile this driver as a module, choose M here: the 287 287 module will be called gpio_mouse. 288 288 289 + config MOUSE_PXA930_TRKBALL 290 + tristate "PXA930 Trackball mouse" 291 + depends on CPU_PXA930 || CPU_PXA935 292 + help 293 + Say Y here to support PXA930 Trackball mouse. 294 + 289 295 endif
+14 -13
drivers/input/mouse/Makefile
··· 4 4 5 5 # Each configuration option enables a list of files. 6 6 7 - obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o 8 - obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o 9 - obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o 10 - obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o 11 - obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o 12 - obj-$(CONFIG_MOUSE_INPORT) += inport.o 13 - obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o 14 - obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o 15 - obj-$(CONFIG_MOUSE_PS2) += psmouse.o 16 - obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o 17 - obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o 18 - obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o 19 - obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o 7 + obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o 8 + obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o 9 + obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o 10 + obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o 11 + obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o 12 + obj-$(CONFIG_MOUSE_INPORT) += inport.o 13 + obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o 14 + obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o 15 + obj-$(CONFIG_MOUSE_PS2) += psmouse.o 16 + obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o 17 + obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o 18 + obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o 19 + obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o 20 + obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o 20 21 21 22 psmouse-objs := psmouse-base.o synaptics.o 22 23
+269
drivers/input/mouse/pxa930_trkball.c
··· 1 + /* 2 + * PXA930 track ball mouse driver 3 + * 4 + * Copyright (C) 2007 Marvell International Ltd. 5 + * 2008-02-28: Yong Yao <yaoyong@marvell.com> 6 + * initial version 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/init.h> 14 + #include <linux/input.h> 15 + #include <linux/version.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/module.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/delay.h> 20 + #include <linux/io.h> 21 + 22 + #include <mach/hardware.h> 23 + #include <mach/pxa930_trkball.h> 24 + 25 + /* Trackball Controller Register Definitions */ 26 + #define TBCR (0x000C) 27 + #define TBCNTR (0x0010) 28 + #define TBSBC (0x0014) 29 + 30 + #define TBCR_TBRST (1 << 1) 31 + #define TBCR_TBSB (1 << 10) 32 + 33 + #define TBCR_Y_FLT(n) (((n) & 0xf) << 6) 34 + #define TBCR_X_FLT(n) (((n) & 0xf) << 2) 35 + 36 + #define TBCNTR_YM(n) (((n) >> 24) & 0xff) 37 + #define TBCNTR_YP(n) (((n) >> 16) & 0xff) 38 + #define TBCNTR_XM(n) (((n) >> 8) & 0xff) 39 + #define TBCNTR_XP(n) ((n) & 0xff) 40 + 41 + #define TBSBC_TBSBC (0x1) 42 + 43 + struct pxa930_trkball { 44 + struct pxa930_trkball_platform_data *pdata; 45 + 46 + /* Memory Mapped Register */ 47 + struct resource *mem; 48 + void __iomem *mmio_base; 49 + 50 + struct input_dev *input; 51 + }; 52 + 53 + static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id) 54 + { 55 + struct pxa930_trkball *trkball = dev_id; 56 + struct input_dev *input = trkball->input; 57 + int tbcntr, x, y; 58 + 59 + /* According to the spec software must read TBCNTR twice: 60 + * if the read value is the same, the reading is valid 61 + */ 62 + tbcntr = __raw_readl(trkball->mmio_base + TBCNTR); 63 + 64 + if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) { 65 + x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2; 66 + y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2; 67 + 68 + input_report_rel(input, REL_X, x); 69 + input_report_rel(input, REL_Y, y); 70 + input_sync(input); 71 + } 72 + 73 + __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); 74 + __raw_writel(0, trkball->mmio_base + TBSBC); 75 + 76 + return IRQ_HANDLED; 77 + } 78 + 79 + /* For TBCR, we need to wait for a while to make sure it has been modified. */ 80 + static int write_tbcr(struct pxa930_trkball *trkball, int v) 81 + { 82 + int i = 100; 83 + 84 + __raw_writel(v, trkball->mmio_base + TBCR); 85 + 86 + while (i--) { 87 + if (__raw_readl(trkball->mmio_base + TBCR) == v) 88 + break; 89 + msleep(1); 90 + } 91 + 92 + if (i == 0) { 93 + pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v); 94 + return -ETIMEDOUT; 95 + } 96 + 97 + return 0; 98 + } 99 + 100 + static void pxa930_trkball_config(struct pxa930_trkball *trkball) 101 + { 102 + uint32_t tbcr; 103 + 104 + /* According to spec, need to write the filters of x,y to 0xf first! */ 105 + tbcr = __raw_readl(trkball->mmio_base + TBCR); 106 + write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf)); 107 + write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) | 108 + TBCR_Y_FLT(trkball->pdata->y_filter)); 109 + 110 + /* According to spec, set TBCR_TBRST first, before clearing it! */ 111 + tbcr = __raw_readl(trkball->mmio_base + TBCR); 112 + write_tbcr(trkball, tbcr | TBCR_TBRST); 113 + write_tbcr(trkball, tbcr & ~TBCR_TBRST); 114 + 115 + __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC); 116 + __raw_writel(0, trkball->mmio_base + TBSBC); 117 + 118 + pr_debug("%s: final TBCR=%x!\n", __func__, 119 + __raw_readl(trkball->mmio_base + TBCR)); 120 + } 121 + 122 + static int pxa930_trkball_open(struct input_dev *dev) 123 + { 124 + struct pxa930_trkball *trkball = input_get_drvdata(dev); 125 + 126 + pxa930_trkball_config(trkball); 127 + 128 + return 0; 129 + } 130 + 131 + static void pxa930_trkball_disable(struct pxa930_trkball *trkball) 132 + { 133 + uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR); 134 + 135 + /* Held in reset, gate the 32-KHz input clock off */ 136 + write_tbcr(trkball, tbcr | TBCR_TBRST); 137 + } 138 + 139 + static void pxa930_trkball_close(struct input_dev *dev) 140 + { 141 + struct pxa930_trkball *trkball = input_get_drvdata(dev); 142 + 143 + pxa930_trkball_disable(trkball); 144 + } 145 + 146 + static int __devinit pxa930_trkball_probe(struct platform_device *pdev) 147 + { 148 + struct pxa930_trkball *trkball; 149 + struct input_dev *input; 150 + struct resource *res; 151 + int irq, error; 152 + 153 + irq = platform_get_irq(pdev, 0); 154 + if (irq < 0) { 155 + dev_err(&pdev->dev, "failed to get trkball irq\n"); 156 + return -ENXIO; 157 + } 158 + 159 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 160 + if (!res) { 161 + dev_err(&pdev->dev, "failed to get register memory\n"); 162 + return -ENXIO; 163 + } 164 + 165 + trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL); 166 + if (!trkball) 167 + return -ENOMEM; 168 + 169 + trkball->pdata = pdev->dev.platform_data; 170 + if (!trkball->pdata) { 171 + dev_err(&pdev->dev, "no platform data defined\n"); 172 + error = -EINVAL; 173 + goto failed; 174 + } 175 + 176 + trkball->mmio_base = ioremap_nocache(res->start, resource_size(res)); 177 + if (!trkball->mmio_base) { 178 + dev_err(&pdev->dev, "failed to ioremap registers\n"); 179 + error = -ENXIO; 180 + goto failed; 181 + } 182 + 183 + /* held the module in reset, will be enabled in open() */ 184 + pxa930_trkball_disable(trkball); 185 + 186 + error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED, 187 + pdev->name, trkball); 188 + if (error) { 189 + dev_err(&pdev->dev, "failed to request irq: %d\n", ret); 190 + goto failed_free_io; 191 + } 192 + 193 + platform_set_drvdata(pdev, trkball); 194 + 195 + input = input_allocate_device(); 196 + if (!input) { 197 + dev_err(&pdev->dev, "failed to allocate input device\n"); 198 + error = -ENOMEM; 199 + goto failed_free_irq; 200 + } 201 + 202 + input->name = pdev->name; 203 + input->id.bustype = BUS_HOST; 204 + input->open = pxa930_trkball_open; 205 + input->close = pxa930_trkball_close; 206 + input->dev.parent = &pdev->dev; 207 + input_set_drvdata(input, trkball); 208 + 209 + trkball->input = input; 210 + 211 + input_set_capability(input, EV_REL, REL_X); 212 + input_set_capability(input, EV_REL, REL_Y); 213 + 214 + error = input_register_device(input); 215 + if (error) { 216 + dev_err(&pdev->dev, "unable to register input device\n"); 217 + goto failed_free_input; 218 + } 219 + 220 + return 0; 221 + 222 + failed_free_input: 223 + input_free_device(input); 224 + failed_free_irq: 225 + free_irq(irq, trkball); 226 + failed_free_io: 227 + iounmap(trkball->mmio_base); 228 + failed: 229 + kfree(trkball); 230 + return ret; 231 + } 232 + 233 + static int __devexit pxa930_trkball_remove(struct platform_device *pdev) 234 + { 235 + struct pxa930_trkball *trkball = platform_get_drvdata(pdev); 236 + int irq = platform_get_irq(pdev, 0); 237 + 238 + input_unregister_device(trkball->input); 239 + free_irq(irq, trkball); 240 + iounmap(trkball->mmio_base); 241 + kfree(trkball); 242 + 243 + return 0; 244 + } 245 + 246 + static struct platform_driver pxa930_trkball_driver = { 247 + .driver = { 248 + .name = "pxa930-trkball", 249 + }, 250 + .probe = pxa930_trkball_probe, 251 + .remove = __devexit_p(pxa930_trkball_remove), 252 + }; 253 + 254 + static int __init pxa930_trkball_init(void) 255 + { 256 + return platform_driver_register(&pxa930_trkball_driver); 257 + } 258 + 259 + static void __exit pxa930_trkball_exit(void) 260 + { 261 + platform_driver_unregister(&pxa930_trkball_driver); 262 + } 263 + 264 + module_init(pxa930_trkball_init); 265 + module_exit(pxa930_trkball_exit); 266 + 267 + MODULE_AUTHOR("Yong Yao <yaoyong@marvell.com>"); 268 + MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver"); 269 + MODULE_LICENSE("GPL");