OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sound/] [ac97_plugin_wm97xx.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
 */
125
MODULE_PARM(mode,"i");
126
MODULE_PARM_DESC(mode, "Set WM97XX operation mode");
127
static 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
 */
138
MODULE_PARM(rpu,"i");
139
MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
140
static 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
 */
152
MODULE_PARM(pdd,"i");
153
MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
154
static 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
 */
166
MODULE_PARM(pil,"i");
167
MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
168
static 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
 */
175
MODULE_PARM(five_wire,"i");
176
MODULE_PARM_DESC(five_wire, "Set 5 wire touchscreen.");
177
static 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
 */
191
MODULE_PARM(delay,"i");
192
MODULE_PARM_DESC(delay, "Set adc sample delay.");
193
static int delay = 4;
194
 
195
 
196
/* +++++++++++++ Lifted from include/linux/h3600_ts.h ++++++++++++++*/
197
typedef 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
 
204
typedef 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
 
236
typedef 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
 
265
static inline void poll_delay (void);
266
static int __init wm97xx_ts_init_module(void);
267
static int wm97xx_poll_read_adc (wm97xx_ts_t* ts, u16 adcsel, u16* sample);
268
static int wm97xx_coord_read_adc (wm97xx_ts_t* ts, u16* x, u16* y,
269
                                  u16* pressure);
270
static inline int pendown (wm97xx_ts_t *ts);
271
static void wm97xx_acq_timer(unsigned long data);
272
static int wm97xx_fasync(int fd, struct file *filp, int mode);
273
static int wm97xx_ioctl(struct inode * inode, struct file *filp,
274
                            unsigned int cmd, unsigned long arg);
275
static unsigned int wm97xx_poll(struct file * filp, poll_table * wait);
276
static ssize_t wm97xx_read(struct file * filp, char * buf, size_t count,
277
                               loff_t * l);
278
static int wm97xx_open(struct inode * inode, struct file * filp);
279
static int wm97xx_release(struct inode * inode, struct file * filp);
280
static void init_wm97xx_phy(void);
281
static int adc_get (wm97xx_ts_t *ts, unsigned short *value, int id);
282
static int wm97xx_probe(struct ac97_codec *codec, struct ac97_driver *driver);
283
static void wm97xx_remove(struct ac97_codec *codec,  struct ac97_driver *driver);
284
static void wm97xx_ts_cleanup_module(void);
285
static int wm97xx_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
286
static void wm97xx_suspend(void);
287
static void wm97xx_resume(void);
288
static void wm9712_pga_save(wm97xx_ts_t* ts);
289
static void wm9712_pga_restore(wm97xx_ts_t* ts);
290
 
291
/* AC97 registration info */
292
static 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
 
300
static 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 */
309
static wm97xx_ts_t wm97xx_ts;
310
 
311
/*
312
 * ADC sample delay times in uS
313
 */
314
static 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
 
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
 
339
static 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
 
350
static 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
 */
406
static 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
 */
444
static 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
 */
492
static 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
 
503
static 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 */
578
acq_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
 
588
static 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
 
594
static 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
 
675
static 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
 
684
static 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
 
733
static 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
 
772
static 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
 
792
static 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
805
static 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 */
938
static 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
 */
978
static 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
 */
994
static 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
 */
1039
static 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 */
1068
static 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 */
1078
static 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
 
1098
static 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
 
1183
static 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
 
1237
static 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
 
1269
static struct miscdevice wm97xx_misc = {
1270
        minor:  TS_MINOR,
1271
        name:   "touchscreen/wm97xx",
1272
        fops:   &ts_fops,
1273
};
1274
 
1275
static 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
 
1328
static 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 */
1341
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1342
MODULE_DESCRIPTION("WM9705/WM9712 Touch Screen / BMON Driver");
1343
MODULE_LICENSE("GPL");
1344
 
1345
module_init(wm97xx_ts_init_module);
1346
module_exit(wm97xx_ts_cleanup_module);
1347
 
1348
#ifndef MODULE
1349
 
1350
static 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 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.