linux-old/drivers/sound/ac97_plugin_wm97xx.c
<<
>>
Prefs
   1/*
   2 * ac97_plugin_wm97xx.c  --  Touch screen driver for Wolfson WM9705 and WM9712
   3 *                           AC97 Codecs.
   4 *
   5 * Copyright 2003 Wolfson Microelectronics PLC.
   6 * Author: Liam Girdwood
   7 *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
   8 *
   9 *  This program is free software; you can redistribute  it and/or modify it
  10 *  under  the terms of  the GNU General  Public License as published by the
  11 *  Free Software Foundation;  either version 2 of the  License, or (at your
  12 *  option) any later version.
  13 *
  14 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  15 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  16 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  17 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  18 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  20 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  21 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  22 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 *
  25 *  You should have received a copy of the  GNU General Public License along
  26 *  with this program; if not, write  to the Free Software Foundation, Inc.,
  27 *  675 Mass Ave, Cambridge, MA 02139, USA.
  28 *
  29 * Notes:
  30 *
  31 *  Features:
  32 *       - supports WM9705, WM9712
  33 *       - polling mode
  34 *       - coordinate polling
  35 *       - adjustable rpu/dpp settings
  36 *       - adjustable pressure current
  37 *       - adjustable sample settle delay
  38 *       - 4 and 5 wire touchscreens (5 wire is WM9712 only)
  39 *       - pen down detection
  40 *       - battery monitor
  41 *       - sample AUX adc's
  42 *       - power management
  43 *       - direct AC97 IO from userspace (#define WM97XX_TS_DEBUG)
  44 *
  45 *  TODO:
  46 *       - continuous mode
  47 *       - adjustable sample rate
  48 *       - AUX adc in coordinate / continous modes
  49 *       - Official device identifier or misc device ?
  50 *
  51 *  Revision history
  52 *    7th May 2003   Initial version.
  53 *    6th June 2003  Added non module support and AC97 registration.
  54 *   18th June 2003  Added AUX adc sampling. 
  55 *   23rd June 2003  Did some minimal reformatting, fixed a couple of
  56 *                   locking bugs and noted a race to fix.
  57 *   24th June 2003  Added power management and fixed race condition.
  58 */
  59
  60#include <linux/module.h>
  61#include <linux/version.h>
  62#include <linux/kernel.h>
  63#include <linux/init.h>
  64#include <linux/fs.h>
  65#include <linux/delay.h>
  66#include <linux/poll.h>
  67#include <linux/string.h>
  68#include <linux/proc_fs.h>
  69#include <linux/miscdevice.h>
  70#include <linux/pm.h>
  71#include <linux/wm97xx.h>       /* WM97xx registers and bits */
  72#include <asm/uaccess.h>        /* get_user,copy_to_user */
  73#include <asm/io.h>
  74
  75#define TS_NAME "ac97_plugin_wm97xx"
  76#define TS_MINOR 16
  77#define WM_TS_VERSION "0.6"
  78#define AC97_NUM_REG 64
  79
  80
  81/*
  82 * Debug
  83 */
  84 
  85#define PFX TS_NAME
  86#define WM97XX_TS_DEBUG 0
  87
  88#ifdef WM97XX_TS_DEBUG
  89#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
  90#else
  91#define dbg(format, arg...) do {} while (0)
  92#endif
  93#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
  94#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
  95#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
  96
  97/*
  98 * Module parameters
  99 */
 100        
 101        
 102/*
 103 * Set the codec sample mode.
 104 *
 105 * The WM9712 can sample touchscreen data in 3 different operating
 106 * modes. i.e. polling, coordinate and continous.
 107 *
 108 * Polling:-     The driver polls the codec and issues 3 seperate commands
 109 *               over the AC97 link to read X,Y and pressure.
 110 * 
 111 * Coordinate: - The driver polls the codec and only issues 1 command over
 112 *               the AC97 link to read X,Y and pressure. This mode has
 113 *               strict timing requirements and may drop samples if 
 114 *               interrupted. However, it is less demanding on the AC97
 115 *               link. Note: this mode requires a larger delay than polling
 116 *               mode.
 117 *
 118 * Continuous:-  The codec automatically samples X,Y and pressure and then
 119 *               sends the data over the AC97 link in slots. This is the
 120 *               same method used by the codec when recording audio.
 121 *
 122 * Set mode = 0 for polling, 1 for coordinate and 2 for continuous.
 123 *            
 124 */
 125MODULE_PARM(mode,"i");
 126MODULE_PARM_DESC(mode, "Set WM97XX operation mode");
 127static int mode = 0;    
 128        
 129/*
 130 * WM9712 - Set internal pull up for pen detect. 
 131 * 
 132 * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
 133 * i.e. pull up resistance = 64k Ohms / rpu.
 134 * 
 135 * Adjust this value if you are having problems with pen detect not 
 136 * detecting any down events.
 137 */
 138MODULE_PARM(rpu,"i");
 139MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
 140static int rpu = 0;     
 141
 142/*
 143 * WM9705 - Pen detect comparator threshold. 
 144 * 
 145 * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
 146 * i.e. 1 =  Vmid/15 threshold
 147 *      15 =  Vmid/1 threshold
 148 * 
 149 * Adjust this value if you are having problems with pen detect not 
 150 * detecting any down events.
 151 */
 152MODULE_PARM(pdd,"i");
 153MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
 154static int pdd = 0;     
 155        
 156/*
 157 * Set current used for pressure measurement.
 158 *
 159 * Set pil = 2 to use 400uA 
 160 *     pil = 1 to use 200uA and
 161 *     pil = 0 to disable pressure measurement.
 162 *
 163 * This is used to increase the range of values returned by the adc
 164 * when measureing touchpanel pressure. 
 165 */
 166MODULE_PARM(pil,"i");
 167MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
 168static int pil = 0;
 169
 170/*
 171 * WM9712 - Set five_wire = 1 to use a 5 wire touchscreen.
 172 * 
 173 * NOTE: Five wire mode does not allow for readback of pressure.
 174 */
 175MODULE_PARM(five_wire,"i");
 176MODULE_PARM_DESC(five_wire, "Set 5 wire touchscreen.");
 177static int five_wire = 0;       
 178
 179/*
 180 * Set adc sample delay.
 181 * 
 182 * For accurate touchpanel measurements, some settling time may be
 183 * required between the switch matrix applying a voltage across the
 184 * touchpanel plate and the ADC sampling the signal.
 185 *
 186 * This delay can be set by setting delay = n, where n is the array
 187 * position of the delay in the array delay_table below.
 188 * Long delays > 1ms are supported for completeness, but are not
 189 * recommended.
 190 */
 191MODULE_PARM(delay,"i");
 192MODULE_PARM_DESC(delay, "Set adc sample delay.");
 193static int delay = 4;   
 194
 195
 196/* +++++++++++++ Lifted from include/linux/h3600_ts.h ++++++++++++++*/
 197typedef struct {
 198        unsigned short pressure;  // touch pressure
 199        unsigned short x;         // calibrated X
 200        unsigned short y;         // calibrated Y
 201        unsigned short millisecs; // timestamp of this event
 202} TS_EVENT;
 203
 204typedef struct {
 205        int xscale;
 206        int xtrans;
 207        int yscale;
 208        int ytrans;
 209        int xyswap;
 210} TS_CAL;
 211
 212/* Use 'f' as magic number */
 213#define IOC_MAGIC  'f'
 214
 215#define TS_GET_RATE             _IO(IOC_MAGIC, 8)
 216#define TS_SET_RATE             _IO(IOC_MAGIC, 9)
 217#define TS_GET_CAL              _IOR(IOC_MAGIC, 10, TS_CAL)
 218#define TS_SET_CAL              _IOW(IOC_MAGIC, 11, TS_CAL)
 219
 220/* +++++++++++++ Done lifted from include/linux/h3600_ts.h +++++++++*/
 221
 222#define TS_GET_COMP1                    _IOR(IOC_MAGIC, 12, short)
 223#define TS_GET_COMP2                    _IOR(IOC_MAGIC, 13, short)
 224#define TS_GET_BMON                     _IOR(IOC_MAGIC, 14, short)
 225#define TS_GET_WIPER                    _IOR(IOC_MAGIC, 15, short)
 226
 227#ifdef WM97XX_TS_DEBUG
 228/* debug get/set ac97 codec register ioctl's */
 229#define TS_GET_AC97_REG                 _IOR(IOC_MAGIC, 20, short)
 230#define TS_SET_AC97_REG                 _IOW(IOC_MAGIC, 21, short)
 231#define TS_SET_AC97_INDEX               _IOW(IOC_MAGIC, 22, short)
 232#endif
 233
 234#define EVENT_BUFSIZE 128
 235
 236typedef struct {
 237        TS_CAL cal;                       /* Calibration values */
 238        TS_EVENT event_buf[EVENT_BUFSIZE];/* The event queue */
 239        int nextIn, nextOut;
 240        int event_count;
 241        int is_wm9712:1;                  /* are we a WM912 or a WM9705 */
 242        int is_registered:1;              /* Is the driver AC97 registered */
 243        int line_pgal:5;
 244        int line_pgar:5;
 245        int phone_pga:5;
 246        int mic_pgal:5;
 247        int mic_pgar:5;
 248        int overruns;                     /* event buffer overruns */
 249        int adc_errs;                     /* sample read back errors */
 250#ifdef WM97XX_TS_DEBUG
 251        short ac97_index;
 252#endif
 253        struct fasync_struct *fasync;     /* asynch notification */
 254        struct timer_list acq_timer;      /* Timer for triggering acquisitions */
 255        wait_queue_head_t wait;           /* read wait queue */
 256        spinlock_t lock;
 257        struct ac97_codec *codec;
 258        struct proc_dir_entry *wm97xx_ts_ps;
 259#ifdef WM97XX_TS_DEBUG
 260        struct proc_dir_entry *wm97xx_debug_ts_ps;
 261#endif
 262        struct pm_dev * pm;
 263} wm97xx_ts_t;
 264
 265static inline void poll_delay (void);
 266static int __init wm97xx_ts_init_module(void);
 267static int wm97xx_poll_read_adc (wm97xx_ts_t* ts, u16 adcsel, u16* sample);
 268static int wm97xx_coord_read_adc (wm97xx_ts_t* ts, u16* x, u16* y, 
 269                                  u16* pressure);
 270static inline int pendown (wm97xx_ts_t *ts);
 271static void wm97xx_acq_timer(unsigned long data);
 272static int wm97xx_fasync(int fd, struct file *filp, int mode);
 273static int wm97xx_ioctl(struct inode * inode, struct file *filp,
 274                            unsigned int cmd, unsigned long arg);
 275static unsigned int wm97xx_poll(struct file * filp, poll_table * wait);
 276static ssize_t wm97xx_read(struct file * filp, char * buf, size_t count, 
 277                               loff_t * l);
 278static int wm97xx_open(struct inode * inode, struct file * filp);
 279static int wm97xx_release(struct inode * inode, struct file * filp);
 280static void init_wm97xx_phy(void);
 281static int adc_get (wm97xx_ts_t *ts, unsigned short *value, int id);
 282static int wm97xx_probe(struct ac97_codec *codec, struct ac97_driver *driver);
 283static void wm97xx_remove(struct ac97_codec *codec,  struct ac97_driver *driver);
 284static void wm97xx_ts_cleanup_module(void);
 285static int wm97xx_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
 286static void wm97xx_suspend(void);
 287static void wm97xx_resume(void);
 288static void wm9712_pga_save(wm97xx_ts_t* ts);
 289static void wm9712_pga_restore(wm97xx_ts_t* ts);
 290
 291/* AC97 registration info */
 292static struct ac97_driver wm9705_driver = {
 293        codec_id: 0x574D4C05,
 294        codec_mask: 0xFFFFFFFF,
 295        name: "Wolfson WM9705 Touchscreen/BMON",
 296        probe:  wm97xx_probe,
 297        remove: __devexit_p(wm97xx_remove),
 298};
 299
 300static struct ac97_driver wm9712_driver = {
 301        codec_id: 0x574D4C12,
 302        codec_mask: 0xFFFFFFFF,
 303        name: "Wolfson WM9712 Touchscreen/BMON",
 304        probe:  wm97xx_probe,
 305        remove: __devexit_p(wm97xx_remove),
 306};
 307
 308/* we only support a single touchscreen */
 309static wm97xx_ts_t wm97xx_ts;
 310
 311/*
 312 * ADC sample delay times in uS
 313 */
 314static const int delay_table[16] = {
 315        21,             // 1 AC97 Link frames
 316        42,             // 2
 317        84,             // 4
 318        167,            // 8
 319        333,            // 16
 320        667,            // 32
 321        1000,           // 48
 322        1333,           // 64
 323        2000,           // 96
 324        2667,           // 128
 325        3333,           // 160
 326        4000,           // 192
 327        4667,           // 224
 328        5333,           // 256
 329        6000,           // 288
 330        0               // No delay, switch matrix always on
 331};
 332
 333/*
 334 * Delay after issuing a POLL command.
 335 *
 336 * The delay is 3 AC97 link frames + the touchpanel settling delay
 337 */
 338
 339static inline void poll_delay(void)
 340{ 
 341        int pdelay = 3 * AC97_LINK_FRAME + delay_table[delay];
 342        udelay (pdelay);
 343}
 344
 345
 346/*
 347 * sample the auxillary ADC's 
 348 */
 349
 350static int adc_get(wm97xx_ts_t* ts, unsigned short * value, int id)
 351{
 352        short adcsel = 0;
 353        
 354        /* first find out our adcsel flag */
 355        if (ts->is_wm9712) {
 356                switch (id) {
 357                        case TS_COMP1:
 358                                adcsel = WM9712_ADCSEL_COMP1;
 359                                break;
 360                        case TS_COMP2:
 361                                adcsel = WM9712_ADCSEL_COMP2;
 362                                break;
 363                        case TS_BMON:
 364                                adcsel = WM9712_ADCSEL_BMON;
 365                                break;
 366                        case TS_WIPER:
 367                                adcsel = WM9712_ADCSEL_WIPER;
 368                                break;
 369                }
 370        } else {
 371                switch (id) {
 372                        case TS_COMP1:
 373                                adcsel = WM9705_ADCSEL_PCBEEP;
 374                                break;
 375                        case TS_COMP2:
 376                                adcsel = WM9705_ADCSEL_PHONE;
 377                                break;
 378                        case TS_BMON:
 379                                adcsel = WM9705_ADCSEL_BMON;
 380                                break;
 381                        case TS_WIPER:
 382                                adcsel = WM9705_ADCSEL_AUX;
 383                                break;
 384                }
 385        }
 386        
 387        /* now sample the adc */
 388        if (mode == 1) {
 389                /* coordinate mode - not currently available (TODO) */
 390                        return 0;
 391        }
 392        else
 393        {
 394                /* polling mode */
 395                if (!wm97xx_poll_read_adc(ts, adcsel, value))
 396                        return 0;       
 397        }
 398        
 399        return 1;
 400}
 401
 402
 403/*
 404 * Read a sample from the adc in polling mode.
 405 */
 406static int wm97xx_poll_read_adc (wm97xx_ts_t* ts, u16 adcsel, u16* sample)
 407{
 408        u16 dig1;
 409        int timeout = 5 * delay;
 410
 411        /* set up digitiser */
 412        dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1); 
 413        dig1&=0x0fff;
 414        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1 | adcsel |
 415                WM97XX_POLL); 
 416
 417        /* wait 3 AC97 time slots + delay for conversion */
 418        poll_delay();
 419
 420        /* wait for POLL to go low */
 421        while ((ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1) & WM97XX_POLL) && timeout) { 
 422                udelay(AC97_LINK_FRAME);
 423                timeout--;      
 424        }
 425        if (timeout > 0)
 426                *sample = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
 427        else {
 428                ts->adc_errs++;
 429                err ("adc sample timeout");
 430                return 0;
 431        }
 432        
 433        /* check we have correct sample */
 434        if ((*sample & 0x7000) != adcsel ) { 
 435                err ("adc wrong sample, read %x got %x", adcsel, *sample & 0x7000);
 436                return 0;
 437        }
 438        return 1;
 439}
 440
 441/*
 442 * Read a sample from the adc in coordinate mode.
 443 */
 444static int wm97xx_coord_read_adc(wm97xx_ts_t* ts, u16* x, u16* y, u16* pressure)
 445{
 446        u16 dig1;
 447        int timeout = 5 * delay;
 448
 449        /* set up digitiser */
 450        dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1); 
 451        dig1&=0x0fff;
 452        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1 | WM97XX_ADCSEL_PRES |
 453                WM97XX_POLL); 
 454
 455        /* wait 3 AC97 time slots + delay for conversion */
 456        poll_delay();
 457        
 458        /* read X then wait for 1 AC97 link frame + settling delay */
 459        *x = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
 460        udelay (AC97_LINK_FRAME + delay_table[delay]);
 461
 462        /* read Y */
 463        *y = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
 464        
 465        /* wait for POLL to go low and then read pressure */
 466        while ((ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)&& timeout) {
 467                        udelay(AC97_LINK_FRAME);
 468                        timeout--;
 469        }
 470        if (timeout > 0)                
 471                *pressure = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
 472        else {
 473                ts->adc_errs++;
 474                err ("adc sample timeout");
 475                return 0;
 476        }
 477        
 478        /* check we have correct samples */
 479        if (((*x & 0x7000) == 0x1000) && ((*y & 0x7000) == 0x2000) && 
 480                ((*pressure & 0x7000) == 0x3000)) { 
 481                return 1;
 482        } else {
 483                ts->adc_errs++;
 484                err ("adc got wrong samples, got x 0x%x y 0x%x pressure 0x%x", *x, *y, *pressure);
 485                return 0;
 486        }
 487}
 488
 489/*
 490 * Is the pen down ?
 491 */
 492static inline int pendown (wm97xx_ts_t *ts)
 493{
 494        return ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD) & WM97XX_PEN_DOWN;
 495}
 496
 497/*
 498 * X,Y coordinates and pressure aquisition function.
 499 * This function is run by a kernel timer and it's frequency between
 500 * calls is the touchscreen polling rate;
 501 */
 502 
 503static void wm97xx_acq_timer(unsigned long data)
 504{
 505        wm97xx_ts_t* ts = (wm97xx_ts_t*)data;
 506        unsigned long flags;
 507        long x,y;
 508        TS_EVENT event;
 509        
 510        spin_lock_irqsave(&ts->lock, flags);
 511
 512        /* are we still registered ? */
 513        if (!ts->is_registered) {
 514                spin_unlock_irqrestore(&ts->lock, flags);
 515                return; /* we better stop then */
 516        }
 517        
 518        /* read coordinates if pen is down */
 519        if (!pendown(ts))
 520                goto acq_exit;
 521        
 522        if (mode == 1) {
 523                /* coordinate mode */
 524                if (!wm97xx_coord_read_adc(ts, (u16*)&x, (u16*)&y, &event.pressure))
 525                        goto acq_exit;
 526        } else
 527        {
 528                /* polling mode */
 529                if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_X, (u16*)&x))
 530                        goto acq_exit;
 531                if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_Y, (u16*)&y))
 532                        goto acq_exit;
 533                
 534                /* only read pressure if we have to */
 535                if (!five_wire && pil) {
 536                        if (!wm97xx_poll_read_adc(ts, WM97XX_ADCSEL_PRES, &event.pressure))
 537                                goto acq_exit;
 538                }
 539                else
 540                        event.pressure = 0;
 541        }
 542        /* timestamp this new event. */
 543        event.millisecs = jiffies;
 544
 545        /* calibrate and remove unwanted bits from samples */
 546        event.pressure &= 0x0fff;
 547        
 548        x &= 0x00000fff;
 549        x = ((ts->cal.xscale * x) >> 8) + ts->cal.xtrans;
 550        event.x = (u16)x;
 551        
 552        y &= 0x00000fff;
 553        y = ((ts->cal.yscale * y) >> 8) + ts->cal.ytrans;
 554        event.y = (u16)y;
 555        
 556        /* add this event to the event queue */
 557        ts->event_buf[ts->nextIn++] = event;
 558        if (ts->nextIn == EVENT_BUFSIZE)
 559                ts->nextIn = 0;
 560        if (ts->event_count < EVENT_BUFSIZE) {
 561                ts->event_count++;
 562        } else {
 563                /* throw out the oldest event */
 564                if (++ts->nextOut == EVENT_BUFSIZE) {
 565                        ts->nextOut = 0;
 566                        ts->overruns++;
 567                }
 568        }
 569
 570        /* async notify */
 571        if (ts->fasync)
 572                kill_fasync(&ts->fasync, SIGIO, POLL_IN);
 573        /* wake up any read call */
 574        if (waitqueue_active(&ts->wait))
 575                wake_up_interruptible(&ts->wait);
 576
 577        /* schedule next acquire */
 578acq_exit:
 579        ts->acq_timer.expires = jiffies + HZ / 100;
 580        add_timer(&ts->acq_timer);
 581
 582        spin_unlock_irqrestore(&ts->lock, flags);
 583}
 584        
 585        
 586/* +++++++++++++ File operations ++++++++++++++*/
 587
 588static int wm97xx_fasync(int fd, struct file *filp, int mode)
 589{
 590        wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
 591        return fasync_helper(fd, filp, mode, &ts->fasync);
 592}
 593
 594static int wm97xx_ioctl(struct inode * inode, struct file *filp,
 595             unsigned int cmd, unsigned long arg)
 596{
 597        unsigned short adc_value;
 598#ifdef WM97XX_TS_DEBUG
 599        short data;
 600#endif  
 601        wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
 602
 603        switch(cmd) {
 604        case TS_GET_RATE:       /* TODO: what is this? */
 605                break;
 606        case TS_SET_RATE:       /* TODO: what is this? */
 607                break;
 608        case TS_GET_CAL:
 609                if(copy_to_user((char *)arg, (char *)&ts->cal, sizeof(TS_CAL)))
 610                        return -EFAULT;
 611                break;
 612        case TS_SET_CAL:
 613                if(copy_from_user((char *)&ts->cal, (char *)arg, sizeof(TS_CAL)))
 614                        return -EFAULT;
 615                break;
 616        case TS_GET_COMP1:
 617                if (adc_get(ts, &adc_value, TS_COMP1)) {
 618                        if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
 619                                return -EFAULT;
 620                }
 621                else
 622                        return -EIO;
 623                break;
 624        case TS_GET_COMP2:
 625                if (adc_get(ts, &adc_value, TS_COMP2)) {
 626                        if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
 627                                return -EFAULT;
 628                }
 629                else
 630                        return -EIO;
 631                break;
 632        case TS_GET_BMON:
 633                if (adc_get(ts, &adc_value, TS_BMON)) {
 634                        if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
 635                                return -EFAULT;
 636                }
 637                else
 638                        return -EIO;
 639                break;
 640        case TS_GET_WIPER:
 641                if (adc_get(ts, &adc_value, TS_WIPER)) {
 642                        if(copy_to_user((char *)arg, (char *)&adc_value, sizeof(adc_value)))
 643                                return -EFAULT;
 644                }
 645                else
 646                        return -EIO;
 647                break;
 648#ifdef WM97XX_TS_DEBUG
 649                /* debug get/set ac97 codec register ioctl's 
 650                 *
 651                 * This is direct IO to the codec registers - BE CAREFULL
 652                 */
 653        case TS_GET_AC97_REG: /* read from ac97 reg (index) */
 654                data = ts->codec->codec_read(ts->codec, ts->ac97_index);
 655                if(copy_to_user((char *)arg, (char *)&data, sizeof(data)))
 656                        return -EFAULT;
 657                break;
 658        case TS_SET_AC97_REG: /* write to ac97 reg (index) */
 659                if(copy_from_user((char *)&data, (char *)arg, sizeof(data)))
 660                        return -EFAULT;
 661                ts->codec->codec_write(ts->codec, ts->ac97_index, data);
 662                break;
 663        case TS_SET_AC97_INDEX: /* set ac97 reg index */
 664                if(copy_from_user((char *)&ts->ac97_index, (char *)arg, sizeof(ts->ac97_index)))
 665                        return -EFAULT;
 666                break;
 667#endif
 668        default:
 669                return -EINVAL;
 670        }
 671
 672        return 0;
 673}
 674
 675static unsigned int wm97xx_poll(struct file * filp, poll_table * wait)
 676{
 677        wm97xx_ts_t *ts = (wm97xx_ts_t *)filp->private_data;
 678        poll_wait(filp, &ts->wait, wait);
 679        if (ts->event_count)
 680                return POLLIN | POLLRDNORM;
 681        return 0;
 682}
 683
 684static ssize_t wm97xx_read(struct file *filp, char *buf, size_t count, loff_t *l)
 685{
 686        wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
 687        unsigned long flags;
 688        TS_EVENT event;
 689        int i;
 690
 691        /* are we still registered with AC97 layer ? */
 692        spin_lock_irqsave(&ts->lock, flags);
 693        if (!ts->is_registered) {
 694                spin_unlock_irqrestore(&ts->lock, flags);
 695                return -ENXIO;
 696        }
 697        
 698        if (ts->event_count == 0) {
 699                if (filp->f_flags & O_NONBLOCK)
 700                        return -EAGAIN;
 701                spin_unlock_irqrestore(&ts->lock, flags);
 702
 703                wait_event_interruptible(ts->wait, ts->event_count != 0);
 704                
 705                /* are we still registered after sleep ? */
 706                spin_lock_irqsave(&ts->lock, flags);
 707                if (!ts->is_registered) {
 708                        spin_unlock_irqrestore(&ts->lock, flags);
 709                        return -ENXIO;
 710                }
 711                if (signal_pending(current))
 712                        return -ERESTARTSYS;
 713        }
 714        
 715        for (i = count; i >= sizeof(TS_EVENT);
 716            i -= sizeof(TS_EVENT), buf += sizeof(TS_EVENT)) {
 717                if (ts->event_count == 0)
 718                        break;
 719                spin_lock_irqsave(&ts->lock, flags);
 720                event = ts->event_buf[ts->nextOut++];
 721                if (ts->nextOut == EVENT_BUFSIZE)
 722                        ts->nextOut = 0;
 723                if (ts->event_count)
 724                        ts->event_count--;
 725                spin_unlock_irqrestore(&ts->lock, flags);
 726                if(copy_to_user(buf, &event, sizeof(TS_EVENT)))
 727                        return i != count  ? count - i : -EFAULT;
 728        }
 729        return count - i;
 730}
 731
 732
 733static int wm97xx_open(struct inode * inode, struct file * filp)
 734{
 735        wm97xx_ts_t* ts;
 736        unsigned long flags;
 737        u16 val;
 738        int minor = MINOR(inode->i_rdev);
 739        
 740        if (minor != TS_MINOR)
 741                return -ENODEV;
 742        
 743        filp->private_data = ts = &wm97xx_ts;
 744
 745        spin_lock_irqsave(&ts->lock, flags);
 746        
 747        /* are we registered with AC97 layer ? */
 748        if (!ts->is_registered) {
 749                spin_unlock_irqrestore(&ts->lock, flags);
 750                return -ENXIO;
 751        }
 752        
 753        /* start digitiser */
 754        val = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
 755        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, 
 756                val | WM97XX_PRP_DET_DIG);
 757        
 758        /* flush event queue */
 759        ts->nextIn = ts->nextOut = ts->event_count = 0;
 760        
 761        /* Set up timer. */
 762        init_timer(&ts->acq_timer);
 763        ts->acq_timer.function = wm97xx_acq_timer;
 764        ts->acq_timer.data = (unsigned long)ts;
 765        ts->acq_timer.expires = jiffies + HZ / 100;
 766        add_timer(&ts->acq_timer);
 767
 768        spin_unlock_irqrestore(&ts->lock, flags);
 769        return 0;
 770}
 771
 772static int wm97xx_release(struct inode * inode, struct file * filp)
 773{
 774        wm97xx_ts_t* ts = (wm97xx_ts_t*)filp->private_data;
 775        unsigned long flags;
 776        u16 val;
 777        
 778        wm97xx_fasync(-1, filp, 0);
 779        del_timer_sync(&ts->acq_timer);
 780
 781        spin_lock_irqsave(&ts->lock, flags);
 782        
 783        /* stop digitiser */
 784        val = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
 785        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, 
 786                val & ~WM97XX_PRP_DET_DIG);
 787        
 788        spin_unlock_irqrestore(&ts->lock, flags);
 789        return 0;
 790}
 791
 792static struct file_operations ts_fops = {
 793        owner:          THIS_MODULE,
 794        read:           wm97xx_read,
 795        poll:           wm97xx_poll,
 796        ioctl:          wm97xx_ioctl,
 797        fasync:         wm97xx_fasync,
 798        open:           wm97xx_open,
 799        release:        wm97xx_release,
 800};
 801
 802/* +++++++++++++ End File operations ++++++++++++++*/
 803
 804#ifdef CONFIG_PROC_FS
 805static int wm97xx_read_proc (char *page, char **start, off_t off,
 806                    int count, int *eof, void *data)
 807{
 808        int len = 0, prpu;
 809        u16 dig1, dig2, digrd, adcsel, adcsrc, slt, prp, rev;
 810        unsigned long flags;
 811        char srev = ' ';
 812        
 813        wm97xx_ts_t* ts;
 814
 815        if ((ts = data) == NULL)
 816                return -ENODEV;
 817        
 818        spin_lock_irqsave(&ts->lock, flags);
 819        if (!ts->is_registered) {
 820                spin_unlock_irqrestore(&ts->lock, flags);
 821                len += sprintf (page+len, "No device registered\n");
 822                return len;
 823        }
 824
 825        dig1 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER1);
 826        dig2 = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER2);
 827        digrd = ts->codec->codec_read(ts->codec, AC97_WM97XX_DIGITISER_RD);
 828        rev = (ts->codec->codec_read(ts->codec, AC97_WM9712_REV) & 0x000c) >> 2;
 829
 830        spin_unlock_irqrestore(&ts->lock, flags);
 831        
 832        adcsel = dig1 & 0x7000;
 833        adcsrc = digrd & 0x7000;
 834        slt = (dig1 & 0x7) + 5;
 835        prp = dig2 & 0xc000;
 836        prpu = dig2 & 0x003f;
 837
 838        /* driver version */
 839        len += sprintf (page+len, "Wolfson WM97xx Version %s\n", WM_TS_VERSION);
 840        
 841        /* what we are using */
 842        len += sprintf (page+len, "Using %s", ts->is_wm9712 ? "WM9712" : "WM9705");
 843        if (ts->is_wm9712) {
 844                switch (rev) {
 845                        case 0x0:
 846                                srev = 'A';
 847                        break;
 848                        case 0x1:
 849                                srev = 'B';
 850                        break;
 851                        case 0x2:
 852                                srev = 'D';
 853                        break;
 854                        case 0x3:
 855                                srev = 'E';
 856                        break;
 857                }
 858                len += sprintf (page+len, " silicon rev %c\n",srev);
 859        } else
 860                len += sprintf (page+len, "\n");
 861                
 862        /* WM97xx settings */
 863        len += sprintf (page+len, "Settings     :\n%s%s%s%s",
 864                        dig1 & WM97XX_POLL ? " -sampling adc data(poll)\n" : "",
 865                        adcsel ==  WM97XX_ADCSEL_X ? " -adc set to X coordinate\n" : "",
 866                        adcsel ==  WM97XX_ADCSEL_Y ? " -adc set to Y coordinate\n" : "",
 867                        adcsel ==  WM97XX_ADCSEL_PRES ? " -adc set to pressure\n" : "");
 868        if (ts->is_wm9712) {
 869                len += sprintf (page+len, "%s%s%s%s", 
 870                        adcsel ==  WM9712_ADCSEL_COMP1 ? " -adc set to COMP1/AUX1\n" : "",
 871                        adcsel ==  WM9712_ADCSEL_COMP2 ? " -adc set to COMP2/AUX2\n" : "",
 872                        adcsel ==  WM9712_ADCSEL_BMON ? " -adc set to BMON\n" : "",
 873                        adcsel ==  WM9712_ADCSEL_WIPER ? " -adc set to WIPER\n" : "");
 874                } else {
 875                len += sprintf (page+len, "%s%s%s%s",
 876                        adcsel ==  WM9705_ADCSEL_PCBEEP ? " -adc set to PCBEEP\n" : "",
 877                        adcsel ==  WM9705_ADCSEL_PHONE ? " -adc set to PHONE\n" : "",
 878                        adcsel ==  WM9705_ADCSEL_BMON ? " -adc set to BMON\n" : "",
 879                        adcsel ==  WM9705_ADCSEL_AUX ? " -adc set to AUX\n" : "");
 880                }
 881                
 882        len += sprintf (page+len, "%s%s%s%s%s%s",
 883                        dig1 & WM97XX_COO ? " -coordinate sampling\n" : " -individual sampling\n",
 884                        dig1 & WM97XX_CTC ? " -continuous mode\n" : " -polling mode\n",
 885                        prp == WM97XX_PRP_DET ? " -pen detect enabled, no wake up\n" : "",
 886                        prp == WM97XX_PRP_DETW ? " -pen detect enabled, wake up\n" : "",
 887                        prp == WM97XX_PRP_DET_DIG ? " -pen digitiser and pen detect enabled\n" : "",
 888                        dig1 & WM97XX_SLEN ? " -read back using slot " : " -read back using AC97\n");
 889        
 890        if ((dig1 & WM97XX_SLEN) && slt !=12)   
 891                len += sprintf(page+len, "%d\n", slt);
 892        len += sprintf (page+len, " -adc sample delay %d uSecs\n", delay_table[(dig1 & 0x00f0) >> 4]);
 893        
 894        if (ts->is_wm9712) {
 895                if (prpu)
 896                        len += sprintf (page+len, " -rpu %d Ohms\n", 64000/ prpu);
 897                len += sprintf (page+len, " -pressure current %s uA\n", dig2 & WM9712_PIL ? "400" : "200");
 898                len += sprintf (page+len, " -using %s wire touchscreen mode", dig2 & WM9712_45W ? "5" : "4");
 899        } else {
 900                len += sprintf (page+len, " -pressure current %s uA\n", dig2 & WM9705_PIL ? "400" : "200");
 901                len += sprintf (page+len, " -%s impedance for PHONE and PCBEEP\n", dig2 & WM9705_PHIZ ? "high" : "low");
 902        }
 903        
 904        /* WM97xx digitiser read */
 905        len += sprintf(page+len, "\nADC data:\n%s%d\n%s%s\n",
 906                " -adc value (decimal) : ", digrd & 0x0fff,
 907                " -pen ", digrd & 0x8000 ? "Down" : "Up");
 908        if (ts->is_wm9712) {
 909                len += sprintf (page+len, "%s%s%s%s", 
 910                        adcsrc ==  WM9712_ADCSEL_COMP1 ? " -adc value is COMP1/AUX1\n" : "",
 911                        adcsrc ==  WM9712_ADCSEL_COMP2 ? " -adc value is COMP2/AUX2\n" : "",
 912                        adcsrc ==  WM9712_ADCSEL_BMON ? " -adc value is BMON\n" : "",
 913                        adcsrc ==  WM9712_ADCSEL_WIPER ? " -adc value is WIPER\n" : "");
 914                } else {
 915                len += sprintf (page+len, "%s%s%s%s",
 916                        adcsrc ==  WM9705_ADCSEL_PCBEEP ? " -adc value is PCBEEP\n" : "",
 917                        adcsrc ==  WM9705_ADCSEL_PHONE ? " -adc value is PHONE\n" : "",
 918                        adcsrc ==  WM9705_ADCSEL_BMON ? " -adc value is BMON\n" : "",
 919                        adcsrc ==  WM9705_ADCSEL_AUX ? " -adc value is AUX\n" : "");
 920                }
 921                
 922        /* register dump */
 923        len += sprintf(page+len, "\nRegisters:\n%s%x\n%s%x\n%s%x\n",
 924                " -digitiser 1    (0x76) : 0x", dig1,
 925                " -digitiser 2    (0x78) : 0x", dig2,
 926                " -digitiser read (0x7a) : 0x", digrd);
 927                
 928        /* errors */
 929        len += sprintf(page+len, "\nErrors:\n%s%d\n%s%d\n",
 930                " -buffer overruns ", ts->overruns,
 931                " -coordinate errors ", ts->adc_errs);
 932                
 933        return len;
 934}
 935
 936#ifdef WM97XX_TS_DEBUG
 937/* dump all the AC97 register space */
 938static int wm_debug_read_proc (char *page, char **start, off_t off,
 939                    int count, int *eof, void *data)
 940{
 941        int len = 0, i;
 942        unsigned long flags;
 943        wm97xx_ts_t* ts;
 944        u16 reg[AC97_NUM_REG];
 945
 946        if ((ts = data) == NULL)
 947                return -ENODEV;
 948
 949        spin_lock_irqsave(&ts->lock, flags);
 950        if (!ts->is_registered) {
 951                spin_unlock_irqrestore(&ts->lock, flags);
 952                len += sprintf (page+len, "Not registered\n");
 953                return len;
 954        }
 955        
 956        for (i=0; i < AC97_NUM_REG; i++) {
 957                reg[i] = ts->codec->codec_read(ts->codec, i * 2);
 958        }
 959        spin_unlock_irqrestore(&ts->lock, flags);
 960        
 961        for (i=0; i < AC97_NUM_REG; i++) {
 962                len += sprintf (page+len, "0x%2.2x : 0x%4.4x\n",i * 2, reg[i]);
 963        }
 964                
 965        return len;
 966}
 967#endif
 968
 969#endif
 970
 971#ifdef CONFIG_PM
 972/* WM97xx Power Management
 973 * The WM9712 has extra powerdown states that are controlled in 
 974 * seperate registers from the AC97 power management.
 975 * We will only power down into the extra WM9712 states and leave 
 976 * the AC97 power management to the sound driver.
 977 */
 978static int wm97xx_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
 979{
 980        switch(rqst) {
 981                case PM_SUSPEND:
 982                        wm97xx_suspend();
 983                        break;
 984                case PM_RESUME:
 985                        wm97xx_resume();
 986                        break;
 987        }
 988        return 0;
 989}
 990
 991/*
 992 * Power down the codec
 993 */
 994static void wm97xx_suspend(void)
 995{
 996        wm97xx_ts_t* ts = &wm97xx_ts;
 997        u16 reg;
 998        unsigned long flags;
 999        
1000        /* are we registered */
1001        spin_lock_irqsave(&ts->lock, flags);
1002        if (!ts->is_registered) {
1003                spin_unlock_irqrestore(&ts->lock, flags);
1004                return;
1005        }
1006        
1007        /* wm9705 does not have extra PM */
1008        if (!ts->is_wm9712) {
1009                spin_unlock_irqrestore(&ts->lock, flags);
1010                return;
1011        }
1012        
1013        /* save and mute the PGA's */
1014        wm9712_pga_save(ts);
1015        
1016        reg = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL);
1017        ts->codec->codec_write(ts->codec, AC97_PHONE_VOL, reg | 0x001f);
1018        
1019        reg = ts->codec->codec_read(ts->codec, AC97_MIC_VOL);
1020        ts->codec->codec_write(ts->codec, AC97_MIC_VOL, reg | 0x1f1f);
1021        
1022        reg = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL);
1023        ts->codec->codec_write(ts->codec, AC97_LINEIN_VOL, reg | 0x1f1f);
1024        
1025        /* power down, dont disable the AC link */
1026        ts->codec->codec_write(ts->codec, AC97_WM9712_POWER, WM9712_PD(14) | WM9712_PD(13) |
1027                                                        WM9712_PD(12) | WM9712_PD(11) | WM9712_PD(10) |                    
1028                                                        WM9712_PD(9) | WM9712_PD(8) | WM9712_PD(7) |
1029                                                        WM9712_PD(6) | WM9712_PD(5) | WM9712_PD(4) |
1030                                                        WM9712_PD(3) | WM9712_PD(2) | WM9712_PD(1) |
1031                                                        WM9712_PD(0));
1032        
1033        spin_unlock_irqrestore(&ts->lock, flags);
1034}
1035
1036/*
1037 * Power up the Codec
1038 */
1039static void wm97xx_resume(void)
1040{
1041        wm97xx_ts_t* ts = &wm97xx_ts;
1042        unsigned long flags;
1043        
1044        /* are we registered */
1045        spin_lock_irqsave(&ts->lock, flags);
1046        if (!ts->is_registered) {
1047                spin_unlock_irqrestore(&ts->lock, flags);
1048                return;
1049        }
1050        
1051        /* wm9705 does not have extra PM */
1052        if (!ts->is_wm9712) {
1053                spin_unlock_irqrestore(&ts->lock, flags);
1054                return;
1055        }
1056
1057        /* power up */
1058        ts->codec->codec_write(ts->codec, AC97_WM9712_POWER, 0x0);
1059        
1060        /* restore PGA state */
1061        wm9712_pga_restore(ts);
1062        
1063        spin_unlock_irqrestore(&ts->lock, flags);
1064}
1065
1066
1067/* save state of wm9712 PGA's */
1068static void wm9712_pga_save(wm97xx_ts_t* ts)
1069{
1070        ts->phone_pga = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL) & 0x001f;
1071        ts->line_pgal = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL) & 0x1f00;
1072        ts->line_pgar = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL) & 0x001f;
1073        ts->mic_pgal = ts->codec->codec_read(ts->codec, AC97_MIC_VOL) & 0x1f00;
1074        ts->mic_pgar = ts->codec->codec_read(ts->codec, AC97_MIC_VOL) & 0x001f;
1075}
1076
1077/* restore state of wm9712 PGA's */
1078static void wm9712_pga_restore(wm97xx_ts_t* ts)
1079{
1080        u16 reg;
1081        
1082        reg = ts->codec->codec_read(ts->codec, AC97_PHONE_VOL);
1083        ts->codec->codec_write(ts->codec, AC97_PHONE_VOL, reg | ts->phone_pga);
1084        
1085        reg = ts->codec->codec_read(ts->codec, AC97_LINEIN_VOL);
1086        ts->codec->codec_write(ts->codec, AC97_LINEIN_VOL, reg | ts->line_pgar | (ts->line_pgal << 8));
1087
1088        reg = ts->codec->codec_read(ts->codec, AC97_MIC_VOL);
1089        ts->codec->codec_write(ts->codec, AC97_MIC_VOL, reg | ts->mic_pgar | (ts->mic_pgal << 8));
1090}
1091
1092#endif
1093
1094/*
1095 * set up the physical settings of the device 
1096 */
1097
1098static void init_wm97xx_phy(void)
1099{
1100        u16 dig1, dig2, aux, vid;
1101        wm97xx_ts_t *ts = &wm97xx_ts;
1102
1103        /* default values */
1104        dig1 = WM97XX_DELAY(4) | WM97XX_SLT(6);
1105        if (ts->is_wm9712)
1106                dig2 = WM9712_RPU(1);
1107        else {
1108                dig2 = 0x0;
1109                
1110                /* 
1111                 * mute VIDEO and AUX as they share X and Y touchscreen 
1112                 * inputs on the WM9705 
1113                 */
1114                aux = ts->codec->codec_read(ts->codec, AC97_AUX_VOL);
1115                if (!(aux & 0x8000)) {
1116                        info("muting AUX mixer as it shares X touchscreen coordinate");
1117                        ts->codec->codec_write(ts->codec, AC97_AUX_VOL, 0x8000 | aux);
1118                }
1119                
1120                vid = ts->codec->codec_read(ts->codec, AC97_VIDEO_VOL);
1121                if (!(vid & 0x8000)) {
1122                        info("muting VIDEO mixer as it shares Y touchscreen coordinate");
1123                        ts->codec->codec_write(ts->codec, AC97_VIDEO_VOL, 0x8000 | vid);
1124                }
1125        }
1126        
1127        /* WM9712 rpu */
1128        if (ts->is_wm9712 && rpu) {
1129                dig2 &= 0xffc0;
1130                dig2 |= WM9712_RPU(rpu);
1131                info("setting pen detect pull-up to %d Ohms",64000 / rpu);
1132        }
1133        
1134        /* touchpanel pressure */
1135        if  (pil == 2) {
1136                if (ts->is_wm9712)
1137                        dig2 |= WM9712_PIL;
1138                else
1139                        dig2 |= WM9705_PIL;
1140                info("setting pressure measurement current to 400uA.");
1141        } else if (pil) 
1142                info ("setting pressure measurement current to 200uA.");
1143        
1144        /* WM9712 five wire */
1145        if (ts->is_wm9712 && five_wire) {
1146                dig2 |= WM9712_45W;
1147                info("setting 5-wire touchscreen mode.");
1148        }               
1149        
1150        /* sample settling delay */
1151        if (delay!=4) {
1152                if (delay < 0 || delay > 15) {
1153                        info ("supplied delay out of range.");
1154                        delay = 4;
1155                }
1156                dig1 &= 0xff0f;
1157                dig1 |= WM97XX_DELAY(delay);
1158                info("setting adc sample delay to %d u Secs.", delay_table[delay]);
1159        }
1160        
1161        /* coordinate mode */
1162        if (mode == 1) {
1163                dig1 |= WM97XX_COO;
1164                info("using coordinate mode");
1165        }               
1166        
1167        /* WM9705 pdd */
1168        if (pdd && !ts->is_wm9712) {
1169                dig2 |= (pdd & 0x000f);
1170                info("setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
1171        }
1172        
1173        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER1, dig1);
1174        ts->codec->codec_write(ts->codec, AC97_WM97XX_DIGITISER2, dig2); 
1175}
1176
1177
1178/*
1179 * Called by the audio codec initialisation to register
1180 * the touchscreen driver.
1181 */
1182
1183static int wm97xx_probe(struct ac97_codec *codec, struct ac97_driver *driver)
1184{
1185         unsigned long flags;
1186        u16 id1, id2;
1187        wm97xx_ts_t *ts = &wm97xx_ts;
1188                
1189        spin_lock_irqsave(&ts->lock, flags);
1190        
1191        /* we only support 1 touchscreen at the moment */
1192        if (ts->is_registered) {
1193                spin_unlock_irqrestore(&ts->lock, flags);
1194                return -1;
1195        }
1196        
1197        /* 
1198         * We can only use a WM9705 or WM9712 that has been *first* initialised
1199         * by the AC97 audio driver. This is because we have to use the audio 
1200         * drivers codec read() and write() functions to sample the touchscreen 
1201         *      
1202         * If an initialsed WM97xx is found then get the codec read and write 
1203         * functions.            
1204         */
1205        
1206        /* test for a WM9712 or a WM9705 */
1207        id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
1208        id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
1209        if (id1 == WM97XX_ID1 && id2 == WM9712_ID2) {
1210                ts->is_wm9712 = 1;
1211                info("registered a WM9712");
1212        } else if (id1 == WM97XX_ID1 && id2 == WM9705_ID2) {
1213                    ts->is_wm9712 = 0;
1214                    info("registered a WM9705");
1215        } else {
1216                err("could not find a WM97xx codec. Found a 0x%4x:0x%4x instead",
1217                    id1, id2);
1218                spin_unlock_irqrestore(&ts->lock, flags);
1219                return -1;
1220        }
1221        
1222        /* set up AC97 codec interface */
1223        ts->codec = codec;
1224        codec->driver_private = (void*)&ts;
1225        codec->codec_unregister = 0;
1226        
1227        /* set up physical characteristics */
1228        init_wm97xx_phy();
1229                
1230        ts->is_registered = 1;
1231        spin_unlock_irqrestore(&ts->lock, flags);
1232        return 0;
1233}
1234
1235/* this is called by the audio driver when ac97_codec is unloaded */
1236
1237static void wm97xx_remove(struct ac97_codec *codec, struct ac97_driver *driver)
1238{
1239        unsigned long flags;
1240        u16 dig1, dig2;
1241        wm97xx_ts_t *ts = codec->driver_private;
1242        
1243        spin_lock_irqsave(&ts->lock, flags);
1244                        
1245        /* check that are registered */
1246        if (!ts->is_registered) {
1247                err("double unregister");
1248                spin_unlock_irqrestore(&ts->lock, flags);
1249                return;
1250        }
1251        
1252        ts->is_registered = 0;
1253        wake_up_interruptible(&ts->wait); /* So we see its gone */
1254        
1255        /* restore default digitiser values */
1256        dig1 = WM97XX_DELAY(4) | WM97XX_SLT(6);
1257        if (ts->is_wm9712)
1258                dig2 = WM9712_RPU(1);
1259        else 
1260                dig2 = 0x0;
1261                
1262        codec->codec_write(codec, AC97_WM97XX_DIGITISER1, dig1);
1263        codec->codec_write(codec, AC97_WM97XX_DIGITISER2, dig2); 
1264        ts->codec = NULL;
1265                
1266        spin_unlock_irqrestore(&ts->lock, flags);
1267}
1268
1269static struct miscdevice wm97xx_misc = { 
1270        minor:  TS_MINOR,
1271        name:   "touchscreen/wm97xx",
1272        fops:   &ts_fops,
1273};
1274
1275static int __init wm97xx_ts_init_module(void)
1276{
1277        wm97xx_ts_t* ts = &wm97xx_ts;
1278        int ret;
1279        char proc_str[64];
1280        
1281        info("Wolfson WM9705/WM9712 Touchscreen Controller");
1282        info("Version %s  liam.girdwood@wolfsonmicro.com", WM_TS_VERSION);
1283        
1284        memset(ts, 0, sizeof(wm97xx_ts_t));
1285        
1286        /* register our misc device */
1287        if ((ret = misc_register(&wm97xx_misc)) < 0) {
1288                err("can't register misc device");
1289                return ret;
1290        }
1291        
1292        init_waitqueue_head(&ts->wait);
1293        spin_lock_init(&ts->lock);
1294        
1295        // initial calibration values
1296        ts->cal.xscale = 256;
1297        ts->cal.xtrans = 0;
1298        ts->cal.yscale = 256;
1299        ts->cal.ytrans = 0;
1300        
1301        /* reset error counters */
1302        ts->overruns = 0;
1303        ts->adc_errs = 0;
1304        
1305        /* register with the AC97 layer */
1306        ac97_register_driver(&wm9705_driver);
1307        ac97_register_driver(&wm9712_driver);
1308        
1309#ifdef CONFIG_PROC_FS
1310        /* register proc interface */
1311        sprintf(proc_str, "driver/%s", TS_NAME);
1312        if ((ts->wm97xx_ts_ps = create_proc_read_entry (proc_str, 0, NULL,
1313                                             wm97xx_read_proc, ts)) == 0)
1314                err("could not register proc interface /proc/%s", proc_str);
1315#ifdef WM97XX_TS_DEBUG
1316        if ((ts->wm97xx_debug_ts_ps = create_proc_read_entry ("driver/ac97_registers",
1317                0, NULL,wm_debug_read_proc, ts)) == 0)
1318                err("could not register proc interface /proc/driver/ac97_registers");
1319#endif
1320#endif
1321#ifdef CONFIG_PM
1322        if ((ts->pm = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, wm97xx_pm_event)) == 0)
1323                err("could not register with power management");
1324#endif
1325        return 0;
1326}
1327
1328static void wm97xx_ts_cleanup_module(void)
1329{
1330        wm97xx_ts_t* ts = &wm97xx_ts;
1331
1332#ifdef CONFIG_PM
1333        pm_unregister (ts->pm);
1334#endif
1335        ac97_unregister_driver(&wm9705_driver);
1336        ac97_unregister_driver(&wm9712_driver);
1337        misc_deregister(&wm97xx_misc);
1338}
1339
1340/* Module information */
1341MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1342MODULE_DESCRIPTION("WM9705/WM9712 Touch Screen / BMON Driver");
1343MODULE_LICENSE("GPL");
1344
1345module_init(wm97xx_ts_init_module);
1346module_exit(wm97xx_ts_cleanup_module);
1347
1348#ifndef MODULE
1349
1350static int __init wm97xx_ts_setup(char *options)
1351{
1352        char *this_opt = options;
1353
1354        if (!options || !*options)
1355                return 0;
1356
1357        /* parse the options and check for out of range values */
1358        for(this_opt=strtok(options, ",");
1359            this_opt; this_opt=strtok(NULL, ",")) {
1360                if (!strncmp(this_opt, "pil:", 4)) {
1361                        this_opt+=4;
1362                        pil = simple_strtol(this_opt, NULL, 0);
1363                        if (pil < 0 || pil > 2)
1364                                pil = 0;
1365                        continue;
1366                }
1367                if (!strncmp(this_opt, "rpu:", 4)) {
1368                        this_opt+=4;
1369                        rpu = simple_strtol(this_opt, NULL, 0);
1370                        if (rpu < 0 || rpu > 31)
1371                                rpu = 0;
1372                        continue;
1373                }
1374                if (!strncmp(this_opt, "pdd:", 4)) {
1375                        this_opt+=4;
1376                        pdd = simple_strtol(this_opt, NULL, 0);
1377                        if (pdd < 0 || pdd > 15)
1378                                pdd = 0;
1379                        continue;
1380                }
1381                if (!strncmp(this_opt, "delay:", 6)) {
1382                        this_opt+=6;
1383                        delay = simple_strtol(this_opt, NULL, 0);
1384                        if (delay < 0 || delay > 15)
1385                                delay = 4;
1386                        continue;
1387                }
1388                if (!strncmp(this_opt, "five_wire:", 10)) {
1389                        this_opt+=10;
1390                        five_wire = simple_strtol(this_opt, NULL, 0);
1391                        if (five_wire < 0 || five_wire > 1)
1392                                five_wire = 0;
1393                        continue;
1394                }
1395                if (!strncmp(this_opt, "mode:", 5)) {
1396                        this_opt+=5;
1397                        mode = simple_strtol(this_opt, NULL, 0);
1398                        if (mode < 0 || mode > 2)
1399                                mode = 0;
1400                        continue;
1401                }
1402        }
1403        return 1;
1404}
1405
1406__setup("wm97xx_ts=", wm97xx_ts_setup);
1407
1408#endif /* MODULE */
1409