root/drivers/input/mouse/pxa930_trkball.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pxa930_trkball_interrupt
  2. write_tbcr
  3. pxa930_trkball_config
  4. pxa930_trkball_open
  5. pxa930_trkball_disable
  6. pxa930_trkball_close
  7. pxa930_trkball_probe
  8. pxa930_trkball_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * PXA930 track ball mouse driver
   4  *
   5  * Copyright (C) 2007 Marvell International Ltd.
   6  * 2008-02-28: Yong Yao <yaoyong@marvell.com>
   7  *             initial version
   8  */
   9 
  10 #include <linux/input.h>
  11 #include <linux/interrupt.h>
  12 #include <linux/module.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/delay.h>
  15 #include <linux/io.h>
  16 #include <linux/slab.h>
  17 
  18 #include <mach/hardware.h>
  19 #include <linux/platform_data/mouse-pxa930_trkball.h>
  20 
  21 /* Trackball Controller Register Definitions */
  22 #define TBCR            (0x000C)
  23 #define TBCNTR          (0x0010)
  24 #define TBSBC           (0x0014)
  25 
  26 #define TBCR_TBRST      (1 << 1)
  27 #define TBCR_TBSB       (1 << 10)
  28 
  29 #define TBCR_Y_FLT(n)   (((n) & 0xf) << 6)
  30 #define TBCR_X_FLT(n)   (((n) & 0xf) << 2)
  31 
  32 #define TBCNTR_YM(n)    (((n) >> 24) & 0xff)
  33 #define TBCNTR_YP(n)    (((n) >> 16) & 0xff)
  34 #define TBCNTR_XM(n)    (((n) >> 8) & 0xff)
  35 #define TBCNTR_XP(n)    ((n) & 0xff)
  36 
  37 #define TBSBC_TBSBC     (0x1)
  38 
  39 struct pxa930_trkball {
  40         struct pxa930_trkball_platform_data *pdata;
  41 
  42         /* Memory Mapped Register */
  43         struct resource *mem;
  44         void __iomem *mmio_base;
  45 
  46         struct input_dev *input;
  47 };
  48 
  49 static irqreturn_t pxa930_trkball_interrupt(int irq, void *dev_id)
  50 {
  51         struct pxa930_trkball *trkball = dev_id;
  52         struct input_dev *input = trkball->input;
  53         int tbcntr, x, y;
  54 
  55         /* According to the spec software must read TBCNTR twice:
  56          * if the read value is the same, the reading is valid
  57          */
  58         tbcntr = __raw_readl(trkball->mmio_base + TBCNTR);
  59 
  60         if (tbcntr == __raw_readl(trkball->mmio_base + TBCNTR)) {
  61                 x = (TBCNTR_XP(tbcntr) - TBCNTR_XM(tbcntr)) / 2;
  62                 y = (TBCNTR_YP(tbcntr) - TBCNTR_YM(tbcntr)) / 2;
  63 
  64                 input_report_rel(input, REL_X, x);
  65                 input_report_rel(input, REL_Y, y);
  66                 input_sync(input);
  67         }
  68 
  69         __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC);
  70         __raw_writel(0, trkball->mmio_base + TBSBC);
  71 
  72         return IRQ_HANDLED;
  73 }
  74 
  75 /* For TBCR, we need to wait for a while to make sure it has been modified. */
  76 static int write_tbcr(struct pxa930_trkball *trkball, int v)
  77 {
  78         int i = 100;
  79 
  80         __raw_writel(v, trkball->mmio_base + TBCR);
  81 
  82         while (--i) {
  83                 if (__raw_readl(trkball->mmio_base + TBCR) == v)
  84                         break;
  85                 msleep(1);
  86         }
  87 
  88         if (i == 0) {
  89                 pr_err("%s: timed out writing TBCR(%x)!\n", __func__, v);
  90                 return -ETIMEDOUT;
  91         }
  92 
  93         return 0;
  94 }
  95 
  96 static void pxa930_trkball_config(struct pxa930_trkball *trkball)
  97 {
  98         uint32_t tbcr;
  99 
 100         /* According to spec, need to write the filters of x,y to 0xf first! */
 101         tbcr = __raw_readl(trkball->mmio_base + TBCR);
 102         write_tbcr(trkball, tbcr | TBCR_X_FLT(0xf) | TBCR_Y_FLT(0xf));
 103         write_tbcr(trkball, TBCR_X_FLT(trkball->pdata->x_filter) |
 104                             TBCR_Y_FLT(trkball->pdata->y_filter));
 105 
 106         /* According to spec, set TBCR_TBRST first, before clearing it! */
 107         tbcr = __raw_readl(trkball->mmio_base + TBCR);
 108         write_tbcr(trkball, tbcr | TBCR_TBRST);
 109         write_tbcr(trkball, tbcr & ~TBCR_TBRST);
 110 
 111         __raw_writel(TBSBC_TBSBC, trkball->mmio_base + TBSBC);
 112         __raw_writel(0, trkball->mmio_base + TBSBC);
 113 
 114         pr_debug("%s: final TBCR=%x!\n", __func__,
 115                  __raw_readl(trkball->mmio_base + TBCR));
 116 }
 117 
 118 static int pxa930_trkball_open(struct input_dev *dev)
 119 {
 120         struct pxa930_trkball *trkball = input_get_drvdata(dev);
 121 
 122         pxa930_trkball_config(trkball);
 123 
 124         return 0;
 125 }
 126 
 127 static void pxa930_trkball_disable(struct pxa930_trkball *trkball)
 128 {
 129         uint32_t tbcr = __raw_readl(trkball->mmio_base + TBCR);
 130 
 131         /* Held in reset, gate the 32-KHz input clock off */
 132         write_tbcr(trkball, tbcr | TBCR_TBRST);
 133 }
 134 
 135 static void pxa930_trkball_close(struct input_dev *dev)
 136 {
 137         struct pxa930_trkball *trkball = input_get_drvdata(dev);
 138 
 139         pxa930_trkball_disable(trkball);
 140 }
 141 
 142 static int pxa930_trkball_probe(struct platform_device *pdev)
 143 {
 144         struct pxa930_trkball *trkball;
 145         struct input_dev *input;
 146         struct resource *res;
 147         int irq, error;
 148 
 149         irq = platform_get_irq(pdev, 0);
 150         if (irq < 0)
 151                 return -ENXIO;
 152 
 153         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 154         if (!res) {
 155                 dev_err(&pdev->dev, "failed to get register memory\n");
 156                 return -ENXIO;
 157         }
 158 
 159         trkball = kzalloc(sizeof(struct pxa930_trkball), GFP_KERNEL);
 160         if (!trkball)
 161                 return -ENOMEM;
 162 
 163         trkball->pdata = dev_get_platdata(&pdev->dev);
 164         if (!trkball->pdata) {
 165                 dev_err(&pdev->dev, "no platform data defined\n");
 166                 error = -EINVAL;
 167                 goto failed;
 168         }
 169 
 170         trkball->mmio_base = ioremap_nocache(res->start, resource_size(res));
 171         if (!trkball->mmio_base) {
 172                 dev_err(&pdev->dev, "failed to ioremap registers\n");
 173                 error = -ENXIO;
 174                 goto failed;
 175         }
 176 
 177         /* held the module in reset, will be enabled in open() */
 178         pxa930_trkball_disable(trkball);
 179 
 180         error = request_irq(irq, pxa930_trkball_interrupt, 0,
 181                             pdev->name, trkball);
 182         if (error) {
 183                 dev_err(&pdev->dev, "failed to request irq: %d\n", error);
 184                 goto failed_free_io;
 185         }
 186 
 187         platform_set_drvdata(pdev, trkball);
 188 
 189         input = input_allocate_device();
 190         if (!input) {
 191                 dev_err(&pdev->dev, "failed to allocate input device\n");
 192                 error = -ENOMEM;
 193                 goto failed_free_irq;
 194         }
 195 
 196         input->name = pdev->name;
 197         input->id.bustype = BUS_HOST;
 198         input->open = pxa930_trkball_open;
 199         input->close = pxa930_trkball_close;
 200         input->dev.parent = &pdev->dev;
 201         input_set_drvdata(input, trkball);
 202 
 203         trkball->input = input;
 204 
 205         input_set_capability(input, EV_REL, REL_X);
 206         input_set_capability(input, EV_REL, REL_Y);
 207 
 208         error = input_register_device(input);
 209         if (error) {
 210                 dev_err(&pdev->dev, "unable to register input device\n");
 211                 goto failed_free_input;
 212         }
 213 
 214         return 0;
 215 
 216 failed_free_input:
 217         input_free_device(input);
 218 failed_free_irq:
 219         free_irq(irq, trkball);
 220 failed_free_io:
 221         iounmap(trkball->mmio_base);
 222 failed:
 223         kfree(trkball);
 224         return error;
 225 }
 226 
 227 static int pxa930_trkball_remove(struct platform_device *pdev)
 228 {
 229         struct pxa930_trkball *trkball = platform_get_drvdata(pdev);
 230         int irq = platform_get_irq(pdev, 0);
 231 
 232         input_unregister_device(trkball->input);
 233         free_irq(irq, trkball);
 234         iounmap(trkball->mmio_base);
 235         kfree(trkball);
 236 
 237         return 0;
 238 }
 239 
 240 static struct platform_driver pxa930_trkball_driver = {
 241         .driver         = {
 242                 .name   = "pxa930-trkball",
 243         },
 244         .probe          = pxa930_trkball_probe,
 245         .remove         = pxa930_trkball_remove,
 246 };
 247 module_platform_driver(pxa930_trkball_driver);
 248 
 249 MODULE_AUTHOR("Yong Yao <yaoyong@marvell.com>");
 250 MODULE_DESCRIPTION("PXA930 Trackball Mouse Driver");
 251 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */