root/drivers/input/mouse/navpoint.c

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

DEFINITIONS

This source file includes following definitions.
  1. navpoint_packet
  2. navpoint_irq
  3. navpoint_up
  4. navpoint_down
  5. navpoint_open
  6. navpoint_close
  7. navpoint_probe
  8. navpoint_remove
  9. navpoint_suspend
  10. navpoint_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Synaptics NavPoint (PXA27x SSP/SPI) driver.
   4  *
   5  * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/module.h>
  10 #include <linux/platform_device.h>
  11 #include <linux/clk.h>
  12 #include <linux/delay.h>
  13 #include <linux/gpio.h>
  14 #include <linux/input.h>
  15 #include <linux/input/navpoint.h>
  16 #include <linux/interrupt.h>
  17 #include <linux/mutex.h>
  18 #include <linux/pxa2xx_ssp.h>
  19 #include <linux/slab.h>
  20 
  21 /*
  22  * Synaptics Modular Embedded Protocol: Module Packet Format.
  23  * Module header byte 2:0 = Length (# bytes that follow)
  24  * Module header byte 4:3 = Control
  25  * Module header byte 7:5 = Module Address
  26  */
  27 #define HEADER_LENGTH(byte)     ((byte) & 0x07)
  28 #define HEADER_CONTROL(byte)    (((byte) >> 3) & 0x03)
  29 #define HEADER_ADDRESS(byte)    ((byte) >> 5)
  30 
  31 struct navpoint {
  32         struct ssp_device       *ssp;
  33         struct input_dev        *input;
  34         struct device           *dev;
  35         int                     gpio;
  36         int                     index;
  37         u8                      data[1 + HEADER_LENGTH(0xff)];
  38 };
  39 
  40 /*
  41  * Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
  42  */
  43 static const u32 sscr0 = 0
  44         | SSCR0_TUM             /* TIM = 1; No TUR interrupts */
  45         | SSCR0_RIM             /* RIM = 1; No ROR interrupts */
  46         | SSCR0_SSE             /* SSE = 1; SSP enabled */
  47         | SSCR0_Motorola        /* FRF = 0; Motorola SPI */
  48         | SSCR0_DataSize(16)    /* DSS = 15; Data size = 16-bit */
  49         ;
  50 static const u32 sscr1 = 0
  51         | SSCR1_SCFR            /* SCFR = 1; SSPSCLK only during transfers */
  52         | SSCR1_SCLKDIR         /* SCLKDIR = 1; Slave mode */
  53         | SSCR1_SFRMDIR         /* SFRMDIR = 1; Slave mode */
  54         | SSCR1_RWOT            /* RWOT = 1; Receive without transmit mode */
  55         | SSCR1_RxTresh(1)      /* RFT = 0; Receive FIFO threshold = 1 */
  56         | SSCR1_SPH             /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
  57         | SSCR1_RIE             /* RIE = 1; Receive FIFO interrupt enabled */
  58         ;
  59 static const u32 sssr = 0
  60         | SSSR_BCE              /* BCE = 1; Clear BCE */
  61         | SSSR_TUR              /* TUR = 1; Clear TUR */
  62         | SSSR_EOC              /* EOC = 1; Clear EOC */
  63         | SSSR_TINT             /* TINT = 1; Clear TINT */
  64         | SSSR_PINT             /* PINT = 1; Clear PINT */
  65         | SSSR_ROR              /* ROR = 1; Clear ROR */
  66         ;
  67 
  68 /*
  69  * MEP Query $22: Touchpad Coordinate Range Query is not supported by
  70  * the NavPoint module, so sampled values provide the default limits.
  71  */
  72 #define NAVPOINT_X_MIN          1278
  73 #define NAVPOINT_X_MAX          5340
  74 #define NAVPOINT_Y_MIN          1572
  75 #define NAVPOINT_Y_MAX          4396
  76 #define NAVPOINT_PRESSURE_MIN   0
  77 #define NAVPOINT_PRESSURE_MAX   255
  78 
  79 static void navpoint_packet(struct navpoint *navpoint)
  80 {
  81         int finger;
  82         int gesture;
  83         int x, y, z;
  84 
  85         switch (navpoint->data[0]) {
  86         case 0xff:      /* Garbage (packet?) between reset and Hello packet */
  87         case 0x00:      /* Module 0, NULL packet */
  88                 break;
  89 
  90         case 0x0e:      /* Module 0, Absolute packet */
  91                 finger = (navpoint->data[1] & 0x01);
  92                 gesture = (navpoint->data[1] & 0x02);
  93                 x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
  94                 y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
  95                 z = navpoint->data[6];
  96                 input_report_key(navpoint->input, BTN_TOUCH, finger);
  97                 input_report_abs(navpoint->input, ABS_X, x);
  98                 input_report_abs(navpoint->input, ABS_Y, y);
  99                 input_report_abs(navpoint->input, ABS_PRESSURE, z);
 100                 input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
 101                 input_report_key(navpoint->input, BTN_LEFT, gesture);
 102                 input_sync(navpoint->input);
 103                 break;
 104 
 105         case 0x19:      /* Module 0, Hello packet */
 106                 if ((navpoint->data[1] & 0xf0) == 0x10)
 107                         break;
 108                 /* FALLTHROUGH */
 109         default:
 110                 dev_warn(navpoint->dev,
 111                          "spurious packet: data=0x%02x,0x%02x,...\n",
 112                          navpoint->data[0], navpoint->data[1]);
 113                 break;
 114         }
 115 }
 116 
 117 static irqreturn_t navpoint_irq(int irq, void *dev_id)
 118 {
 119         struct navpoint *navpoint = dev_id;
 120         struct ssp_device *ssp = navpoint->ssp;
 121         irqreturn_t ret = IRQ_NONE;
 122         u32 status;
 123 
 124         status = pxa_ssp_read_reg(ssp, SSSR);
 125         if (status & sssr) {
 126                 dev_warn(navpoint->dev,
 127                          "unexpected interrupt: status=0x%08x\n", status);
 128                 pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
 129                 ret = IRQ_HANDLED;
 130         }
 131 
 132         while (status & SSSR_RNE) {
 133                 u32 data;
 134 
 135                 data = pxa_ssp_read_reg(ssp, SSDR);
 136                 navpoint->data[navpoint->index + 0] = (data >> 8);
 137                 navpoint->data[navpoint->index + 1] = data;
 138                 navpoint->index += 2;
 139                 if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
 140                         navpoint_packet(navpoint);
 141                         navpoint->index = 0;
 142                 }
 143                 status = pxa_ssp_read_reg(ssp, SSSR);
 144                 ret = IRQ_HANDLED;
 145         }
 146 
 147         return ret;
 148 }
 149 
 150 static void navpoint_up(struct navpoint *navpoint)
 151 {
 152         struct ssp_device *ssp = navpoint->ssp;
 153         int timeout;
 154 
 155         clk_prepare_enable(ssp->clk);
 156 
 157         pxa_ssp_write_reg(ssp, SSCR1, sscr1);
 158         pxa_ssp_write_reg(ssp, SSSR, sssr);
 159         pxa_ssp_write_reg(ssp, SSTO, 0);
 160         pxa_ssp_write_reg(ssp, SSCR0, sscr0);   /* SSCR0_SSE written last */
 161 
 162         /* Wait until SSP port is ready for slave clock operations */
 163         for (timeout = 100; timeout != 0; --timeout) {
 164                 if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
 165                         break;
 166                 msleep(1);
 167         }
 168 
 169         if (timeout == 0)
 170                 dev_err(navpoint->dev,
 171                         "timeout waiting for SSSR[CSS] to clear\n");
 172 
 173         if (gpio_is_valid(navpoint->gpio))
 174                 gpio_set_value(navpoint->gpio, 1);
 175 }
 176 
 177 static void navpoint_down(struct navpoint *navpoint)
 178 {
 179         struct ssp_device *ssp = navpoint->ssp;
 180 
 181         if (gpio_is_valid(navpoint->gpio))
 182                 gpio_set_value(navpoint->gpio, 0);
 183 
 184         pxa_ssp_write_reg(ssp, SSCR0, 0);
 185 
 186         clk_disable_unprepare(ssp->clk);
 187 }
 188 
 189 static int navpoint_open(struct input_dev *input)
 190 {
 191         struct navpoint *navpoint = input_get_drvdata(input);
 192 
 193         navpoint_up(navpoint);
 194 
 195         return 0;
 196 }
 197 
 198 static void navpoint_close(struct input_dev *input)
 199 {
 200         struct navpoint *navpoint = input_get_drvdata(input);
 201 
 202         navpoint_down(navpoint);
 203 }
 204 
 205 static int navpoint_probe(struct platform_device *pdev)
 206 {
 207         const struct navpoint_platform_data *pdata =
 208                                         dev_get_platdata(&pdev->dev);
 209         struct ssp_device *ssp;
 210         struct input_dev *input;
 211         struct navpoint *navpoint;
 212         int error;
 213 
 214         if (!pdata) {
 215                 dev_err(&pdev->dev, "no platform data\n");
 216                 return -EINVAL;
 217         }
 218 
 219         if (gpio_is_valid(pdata->gpio)) {
 220                 error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
 221                                          "SYNAPTICS_ON");
 222                 if (error)
 223                         return error;
 224         }
 225 
 226         ssp = pxa_ssp_request(pdata->port, pdev->name);
 227         if (!ssp) {
 228                 error = -ENODEV;
 229                 goto err_free_gpio;
 230         }
 231 
 232         /* HaRET does not disable devices before jumping into Linux */
 233         if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
 234                 pxa_ssp_write_reg(ssp, SSCR0, 0);
 235                 dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
 236         }
 237 
 238         navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
 239         input = input_allocate_device();
 240         if (!navpoint || !input) {
 241                 error = -ENOMEM;
 242                 goto err_free_mem;
 243         }
 244 
 245         navpoint->ssp = ssp;
 246         navpoint->input = input;
 247         navpoint->dev = &pdev->dev;
 248         navpoint->gpio = pdata->gpio;
 249 
 250         input->name = pdev->name;
 251         input->dev.parent = &pdev->dev;
 252 
 253         __set_bit(EV_KEY, input->evbit);
 254         __set_bit(EV_ABS, input->evbit);
 255         __set_bit(BTN_LEFT, input->keybit);
 256         __set_bit(BTN_TOUCH, input->keybit);
 257         __set_bit(BTN_TOOL_FINGER, input->keybit);
 258 
 259         input_set_abs_params(input, ABS_X,
 260                              NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
 261         input_set_abs_params(input, ABS_Y,
 262                              NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
 263         input_set_abs_params(input, ABS_PRESSURE,
 264                              NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
 265                              0, 0);
 266 
 267         input->open = navpoint_open;
 268         input->close = navpoint_close;
 269 
 270         input_set_drvdata(input, navpoint);
 271 
 272         error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
 273         if (error)
 274                 goto err_free_mem;
 275 
 276         error = input_register_device(input);
 277         if (error)
 278                 goto err_free_irq;
 279 
 280         platform_set_drvdata(pdev, navpoint);
 281         dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
 282 
 283         return 0;
 284 
 285 err_free_irq:
 286         free_irq(ssp->irq, navpoint);
 287 err_free_mem:
 288         input_free_device(input);
 289         kfree(navpoint);
 290         pxa_ssp_free(ssp);
 291 err_free_gpio:
 292         if (gpio_is_valid(pdata->gpio))
 293                 gpio_free(pdata->gpio);
 294 
 295         return error;
 296 }
 297 
 298 static int navpoint_remove(struct platform_device *pdev)
 299 {
 300         const struct navpoint_platform_data *pdata =
 301                                         dev_get_platdata(&pdev->dev);
 302         struct navpoint *navpoint = platform_get_drvdata(pdev);
 303         struct ssp_device *ssp = navpoint->ssp;
 304 
 305         free_irq(ssp->irq, navpoint);
 306 
 307         input_unregister_device(navpoint->input);
 308         kfree(navpoint);
 309 
 310         pxa_ssp_free(ssp);
 311 
 312         if (gpio_is_valid(pdata->gpio))
 313                 gpio_free(pdata->gpio);
 314 
 315         return 0;
 316 }
 317 
 318 static int __maybe_unused navpoint_suspend(struct device *dev)
 319 {
 320         struct platform_device *pdev = to_platform_device(dev);
 321         struct navpoint *navpoint = platform_get_drvdata(pdev);
 322         struct input_dev *input = navpoint->input;
 323 
 324         mutex_lock(&input->mutex);
 325         if (input->users)
 326                 navpoint_down(navpoint);
 327         mutex_unlock(&input->mutex);
 328 
 329         return 0;
 330 }
 331 
 332 static int __maybe_unused navpoint_resume(struct device *dev)
 333 {
 334         struct platform_device *pdev = to_platform_device(dev);
 335         struct navpoint *navpoint = platform_get_drvdata(pdev);
 336         struct input_dev *input = navpoint->input;
 337 
 338         mutex_lock(&input->mutex);
 339         if (input->users)
 340                 navpoint_up(navpoint);
 341         mutex_unlock(&input->mutex);
 342 
 343         return 0;
 344 }
 345 
 346 static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
 347 
 348 static struct platform_driver navpoint_driver = {
 349         .probe          = navpoint_probe,
 350         .remove         = navpoint_remove,
 351         .driver = {
 352                 .name   = "navpoint",
 353                 .pm     = &navpoint_pm_ops,
 354         },
 355 };
 356 
 357 module_platform_driver(navpoint_driver);
 358 
 359 MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
 360 MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
 361 MODULE_LICENSE("GPL");
 362 MODULE_ALIAS("platform:navpoint");

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