linux/drivers/input/touchscreen/atmel-wm97xx.c
<<
>>
Prefs
   1/*
   2 * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
   3 * codecs.
   4 *
   5 * Copyright (C) 2008 - 2009 Atmel Corporation
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License version 2 as published by
   9 * the Free Software Foundation.
  10 */
  11#include <linux/module.h>
  12#include <linux/moduleparam.h>
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/delay.h>
  16#include <linux/irq.h>
  17#include <linux/interrupt.h>
  18#include <linux/wm97xx.h>
  19#include <linux/timer.h>
  20#include <linux/gpio.h>
  21#include <linux/io.h>
  22#include <linux/slab.h>
  23
  24#define AC97C_ICA               0x10
  25#define AC97C_CBRHR             0x30
  26#define AC97C_CBSR              0x38
  27#define AC97C_CBMR              0x3c
  28#define AC97C_IER               0x54
  29#define AC97C_IDR               0x58
  30
  31#define AC97C_RXRDY             (1 << 4)
  32#define AC97C_OVRUN             (1 << 5)
  33
  34#define AC97C_CMR_SIZE_20       (0 << 16)
  35#define AC97C_CMR_SIZE_18       (1 << 16)
  36#define AC97C_CMR_SIZE_16       (2 << 16)
  37#define AC97C_CMR_SIZE_10       (3 << 16)
  38#define AC97C_CMR_CEM_LITTLE    (1 << 18)
  39#define AC97C_CMR_CEM_BIG       (0 << 18)
  40#define AC97C_CMR_CENA          (1 << 21)
  41
  42#define AC97C_INT_CBEVT         (1 << 4)
  43
  44#define AC97C_SR_CAEVT          (1 << 3)
  45
  46#define AC97C_CH_MASK(slot)                                             \
  47        (0x7 << (3 * (slot - 3)))
  48#define AC97C_CH_ASSIGN(slot, channel)                                  \
  49        (AC97C_CHANNEL_##channel << (3 * (slot - 3)))
  50#define AC97C_CHANNEL_NONE      0x0
  51#define AC97C_CHANNEL_B         0x2
  52
  53#define ac97c_writel(chip, reg, val)                    \
  54        __raw_writel((val), (chip)->regs + AC97C_##reg)
  55#define ac97c_readl(chip, reg)                          \
  56        __raw_readl((chip)->regs + AC97C_##reg)
  57
  58#ifdef CONFIG_CPU_AT32AP700X
  59#define ATMEL_WM97XX_AC97C_IOMEM        (0xfff02800)
  60#define ATMEL_WM97XX_AC97C_IRQ          (29)
  61#define ATMEL_WM97XX_GPIO_DEFAULT       (32+16) /* Pin 16 on port B. */
  62#else
  63#error Unknown CPU, this driver only supports AT32AP700X CPUs.
  64#endif
  65
  66struct continuous {
  67        u16 id;    /* codec id */
  68        u8 code;   /* continuous code */
  69        u8 reads;  /* number of coord reads per read cycle */
  70        u32 speed; /* number of coords per second */
  71};
  72
  73#define WM_READS(sp) ((sp / HZ) + 1)
  74
  75static const struct continuous cinfo[] = {
  76        {WM9705_ID2, 0, WM_READS(94), 94},
  77        {WM9705_ID2, 1, WM_READS(188), 188},
  78        {WM9705_ID2, 2, WM_READS(375), 375},
  79        {WM9705_ID2, 3, WM_READS(750), 750},
  80        {WM9712_ID2, 0, WM_READS(94), 94},
  81        {WM9712_ID2, 1, WM_READS(188), 188},
  82        {WM9712_ID2, 2, WM_READS(375), 375},
  83        {WM9712_ID2, 3, WM_READS(750), 750},
  84        {WM9713_ID2, 0, WM_READS(94), 94},
  85        {WM9713_ID2, 1, WM_READS(120), 120},
  86        {WM9713_ID2, 2, WM_READS(154), 154},
  87        {WM9713_ID2, 3, WM_READS(188), 188},
  88};
  89
  90/* Continuous speed index. */
  91static int sp_idx;
  92
  93/*
  94 * Pen sampling frequency (Hz) in continuous mode.
  95 */
  96static int cont_rate = 188;
  97module_param(cont_rate, int, 0);
  98MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
  99
 100/*
 101 * Pen down detection.
 102 *
 103 * This driver can either poll or use an interrupt to indicate a pen down
 104 * event. If the irq request fails then it will fall back to polling mode.
 105 */
 106static int pen_int = 1;
 107module_param(pen_int, int, 0);
 108MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
 109
 110/*
 111 * Pressure readback.
 112 *
 113 * Set to 1 to read back pen down pressure.
 114 */
 115static int pressure;
 116module_param(pressure, int, 0);
 117MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
 118
 119/*
 120 * AC97 touch data slot.
 121 *
 122 * Touch screen readback data ac97 slot.
 123 */
 124static int ac97_touch_slot = 5;
 125module_param(ac97_touch_slot, int, 0);
 126MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
 127
 128/*
 129 * GPIO line number.
 130 *
 131 * Set to GPIO number where the signal from the WM97xx device is hooked up.
 132 */
 133static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
 134module_param(atmel_gpio_line, int, 0);
 135MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
 136
 137struct atmel_wm97xx {
 138        struct wm97xx           *wm;
 139        struct timer_list       pen_timer;
 140        void __iomem            *regs;
 141        unsigned long           ac97c_irq;
 142        unsigned long           gpio_pen;
 143        unsigned long           gpio_irq;
 144        unsigned short          x;
 145        unsigned short          y;
 146};
 147
 148static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
 149{
 150        struct atmel_wm97xx *atmel_wm97xx = dev_id;
 151        struct wm97xx *wm = atmel_wm97xx->wm;
 152        int status = ac97c_readl(atmel_wm97xx, CBSR);
 153        irqreturn_t retval = IRQ_NONE;
 154
 155        if (status & AC97C_OVRUN) {
 156                dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
 157                ac97c_readl(atmel_wm97xx, CBRHR);
 158                retval = IRQ_HANDLED;
 159        } else if (status & AC97C_RXRDY) {
 160                u16 data;
 161                u16 value;
 162                u16 source;
 163                u16 pen_down;
 164
 165                data = ac97c_readl(atmel_wm97xx, CBRHR);
 166                value = data & 0x0fff;
 167                source = data & WM97XX_ADCSEL_MASK;
 168                pen_down = (data & WM97XX_PEN_DOWN) >> 8;
 169
 170                if (source == WM97XX_ADCSEL_X)
 171                        atmel_wm97xx->x = value;
 172                if (source == WM97XX_ADCSEL_Y)
 173                        atmel_wm97xx->y = value;
 174
 175                if (!pressure && source == WM97XX_ADCSEL_Y) {
 176                        input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
 177                        input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
 178                        input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
 179                        input_sync(wm->input_dev);
 180                } else if (pressure && source == WM97XX_ADCSEL_PRES) {
 181                        input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
 182                        input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
 183                        input_report_abs(wm->input_dev, ABS_PRESSURE, value);
 184                        input_report_key(wm->input_dev, BTN_TOUCH, value);
 185                        input_sync(wm->input_dev);
 186                }
 187
 188                retval = IRQ_HANDLED;
 189        }
 190
 191        return retval;
 192}
 193
 194static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
 195{
 196        struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
 197        struct input_dev *input_dev = wm->input_dev;
 198        int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
 199
 200        if (pen_down != 0) {
 201                mod_timer(&atmel_wm97xx->pen_timer,
 202                          jiffies + msecs_to_jiffies(1));
 203        } else {
 204                if (pressure)
 205                        input_report_abs(input_dev, ABS_PRESSURE, 0);
 206                input_report_key(input_dev, BTN_TOUCH, 0);
 207                input_sync(input_dev);
 208        }
 209}
 210
 211static void atmel_wm97xx_pen_timer(unsigned long data)
 212{
 213        atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
 214}
 215
 216static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
 217{
 218        struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
 219        int idx = 0;
 220
 221        if (wm->ac97 == NULL)
 222                return -ENODEV;
 223
 224        for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
 225                if (wm->id != cinfo[idx].id)
 226                        continue;
 227
 228                sp_idx = idx;
 229
 230                if (cont_rate <= cinfo[idx].speed)
 231                        break;
 232        }
 233
 234        wm->acc_rate = cinfo[sp_idx].code;
 235        wm->acc_slot = ac97_touch_slot;
 236        dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
 237                        "%d samples/sec\n", cinfo[sp_idx].speed);
 238
 239        if (pen_int) {
 240                unsigned long reg;
 241
 242                wm->pen_irq = atmel_wm97xx->gpio_irq;
 243
 244                switch (wm->id) {
 245                case WM9712_ID2: /* Fall through. */
 246                case WM9713_ID2:
 247                        /*
 248                         * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
 249                         * (PENDOWN).
 250                         */
 251                        wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
 252                                        WM97XX_GPIO_POL_HIGH,
 253                                        WM97XX_GPIO_STICKY,
 254                                        WM97XX_GPIO_WAKE);
 255                        wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
 256                                        WM97XX_GPIO_POL_HIGH,
 257                                        WM97XX_GPIO_NOTSTICKY,
 258                                        WM97XX_GPIO_NOWAKE);
 259                case WM9705_ID2: /* Fall through. */
 260                        /*
 261                         * Enable touch data slot in AC97 controller channel B.
 262                         */
 263                        reg = ac97c_readl(atmel_wm97xx, ICA);
 264                        reg &= ~AC97C_CH_MASK(wm->acc_slot);
 265                        reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
 266                        ac97c_writel(atmel_wm97xx, ICA, reg);
 267
 268                        /*
 269                         * Enable channel and interrupt for RXRDY and OVERRUN.
 270                         */
 271                        ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
 272                                        | AC97C_CMR_CEM_BIG
 273                                        | AC97C_CMR_SIZE_16
 274                                        | AC97C_OVRUN
 275                                        | AC97C_RXRDY);
 276                        /* Dummy read to empty RXRHR. */
 277                        ac97c_readl(atmel_wm97xx, CBRHR);
 278                        /*
 279                         * Enable interrupt for channel B in the AC97
 280                         * controller.
 281                         */
 282                        ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
 283                        break;
 284                default:
 285                        dev_err(&wm->touch_dev->dev, "pen down irq not "
 286                                        "supported on this device\n");
 287                        pen_int = 0;
 288                        break;
 289                }
 290        }
 291
 292        return 0;
 293}
 294
 295static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
 296{
 297        if (pen_int) {
 298                struct atmel_wm97xx *atmel_wm97xx =
 299                        platform_get_drvdata(wm->touch_dev);
 300                unsigned long ica;
 301
 302                switch (wm->id & 0xffff) {
 303                case WM9705_ID2: /* Fall through. */
 304                case WM9712_ID2: /* Fall through. */
 305                case WM9713_ID2:
 306                        /* Disable slot and turn off channel B interrupts. */
 307                        ica = ac97c_readl(atmel_wm97xx, ICA);
 308                        ica &= ~AC97C_CH_MASK(wm->acc_slot);
 309                        ac97c_writel(atmel_wm97xx, ICA, ica);
 310                        ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
 311                        ac97c_writel(atmel_wm97xx, CBMR, 0);
 312                        wm->pen_irq = 0;
 313                        break;
 314                default:
 315                        dev_err(&wm->touch_dev->dev, "unknown codec\n");
 316                        break;
 317                }
 318        }
 319}
 320
 321static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
 322{
 323        /* Intentionally left empty. */
 324}
 325
 326static struct wm97xx_mach_ops atmel_mach_ops = {
 327        .acc_enabled    = 1,
 328        .acc_pen_up     = atmel_wm97xx_acc_pen_up,
 329        .acc_startup    = atmel_wm97xx_acc_startup,
 330        .acc_shutdown   = atmel_wm97xx_acc_shutdown,
 331        .irq_enable     = atmel_wm97xx_irq_enable,
 332        .irq_gpio       = WM97XX_GPIO_3,
 333};
 334
 335static int __init atmel_wm97xx_probe(struct platform_device *pdev)
 336{
 337        struct wm97xx *wm = platform_get_drvdata(pdev);
 338        struct atmel_wm97xx *atmel_wm97xx;
 339        int ret;
 340
 341        atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
 342        if (!atmel_wm97xx) {
 343                dev_dbg(&pdev->dev, "out of memory\n");
 344                return -ENOMEM;
 345        }
 346
 347        atmel_wm97xx->wm        = wm;
 348        atmel_wm97xx->regs      = (void *)ATMEL_WM97XX_AC97C_IOMEM;
 349        atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ;
 350        atmel_wm97xx->gpio_pen  = atmel_gpio_line;
 351        atmel_wm97xx->gpio_irq  = gpio_to_irq(atmel_wm97xx->gpio_pen);
 352
 353        setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
 354                        (unsigned long)wm);
 355
 356        ret = request_irq(atmel_wm97xx->ac97c_irq,
 357                          atmel_wm97xx_channel_b_interrupt,
 358                          IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
 359        if (ret) {
 360                dev_dbg(&pdev->dev, "could not request ac97c irq\n");
 361                goto err;
 362        }
 363
 364        platform_set_drvdata(pdev, atmel_wm97xx);
 365
 366        ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
 367        if (ret)
 368                goto err_irq;
 369
 370        return ret;
 371
 372err_irq:
 373        free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
 374err:
 375        kfree(atmel_wm97xx);
 376        return ret;
 377}
 378
 379static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
 380{
 381        struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
 382        struct wm97xx *wm = atmel_wm97xx->wm;
 383
 384        ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
 385        free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
 386        del_timer_sync(&atmel_wm97xx->pen_timer);
 387        wm97xx_unregister_mach_ops(wm);
 388        kfree(atmel_wm97xx);
 389
 390        return 0;
 391}
 392
 393#ifdef CONFIG_PM_SLEEP
 394static int atmel_wm97xx_suspend(struct *dev)
 395{
 396        struct platform_device *pdev = to_platform_device(dev);
 397        struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
 398
 399        ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
 400        disable_irq(atmel_wm97xx->gpio_irq);
 401        del_timer_sync(&atmel_wm97xx->pen_timer);
 402
 403        return 0;
 404}
 405
 406static int atmel_wm97xx_resume(struct device *dev)
 407{
 408        struct platform_device *pdev = to_platform_device(dev);
 409        struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
 410        struct wm97xx *wm = atmel_wm97xx->wm;
 411
 412        if (wm->input_dev->users) {
 413                enable_irq(atmel_wm97xx->gpio_irq);
 414                ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
 415        }
 416
 417        return 0;
 418}
 419#endif
 420
 421static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
 422                         atmel_wm97xx_suspend, atmel_wm97xx_resume);
 423
 424static struct platform_driver atmel_wm97xx_driver = {
 425        .remove         = __exit_p(atmel_wm97xx_remove),
 426        .driver         = {
 427                .name   = "wm97xx-touch",
 428                .owner  = THIS_MODULE,
 429                .pm     = &atmel_wm97xx_pm_ops,
 430        },
 431};
 432
 433module_platform_driver_probe(atmel_wm97xx_driver, atmel_wm97xx_probe);
 434
 435MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 436MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
 437MODULE_LICENSE("GPL");
 438