Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * wm9705.c  --  Codec driver for Wolfson WM9705 AC97 Codec.
0004  *
0005  * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
0006  * Author: Liam Girdwood <lrg@slimlogic.co.uk>
0007  * Parts Copyright : Ian Molton <spyro@f2s.com>
0008  *                   Andrew Zabolotny <zap@homelink.ru>
0009  *                   Russell King <rmk@arm.linux.org.uk>
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/kernel.h>
0015 #include <linux/input.h>
0016 #include <linux/delay.h>
0017 #include <linux/bitops.h>
0018 #include <linux/wm97xx.h>
0019 
0020 #define TS_NAME         "wm97xx"
0021 #define WM9705_VERSION      "1.00"
0022 #define DEFAULT_PRESSURE    0xb0c0
0023 
0024 /*
0025  * Module parameters
0026  */
0027 
0028 /*
0029  * Set current used for pressure measurement.
0030  *
0031  * Set pil = 2 to use 400uA
0032  *     pil = 1 to use 200uA and
0033  *     pil = 0 to disable pressure measurement.
0034  *
0035  * This is used to increase the range of values returned by the adc
0036  * when measureing touchpanel pressure.
0037  */
0038 static int pil;
0039 module_param(pil, int, 0);
0040 MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
0041 
0042 /*
0043  * Set threshold for pressure measurement.
0044  *
0045  * Pen down pressure below threshold is ignored.
0046  */
0047 static int pressure = DEFAULT_PRESSURE & 0xfff;
0048 module_param(pressure, int, 0);
0049 MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
0050 
0051 /*
0052  * Set adc sample delay.
0053  *
0054  * For accurate touchpanel measurements, some settling time may be
0055  * required between the switch matrix applying a voltage across the
0056  * touchpanel plate and the ADC sampling the signal.
0057  *
0058  * This delay can be set by setting delay = n, where n is the array
0059  * position of the delay in the array delay_table below.
0060  * Long delays > 1ms are supported for completeness, but are not
0061  * recommended.
0062  */
0063 static int delay = 4;
0064 module_param(delay, int, 0);
0065 MODULE_PARM_DESC(delay, "Set adc sample delay.");
0066 
0067 /*
0068  * Pen detect comparator threshold.
0069  *
0070  * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
0071  * i.e. 1 =  Vmid/15 threshold
0072  *      15 =  Vmid/1 threshold
0073  *
0074  * Adjust this value if you are having problems with pen detect not
0075  * detecting any down events.
0076  */
0077 static int pdd = 8;
0078 module_param(pdd, int, 0);
0079 MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
0080 
0081 /*
0082  * Set adc mask function.
0083  *
0084  * Sources of glitch noise, such as signals driving an LCD display, may feed
0085  * through to the touch screen plates and affect measurement accuracy. In
0086  * order to minimise this, a signal may be applied to the MASK pin to delay or
0087  * synchronise the sampling.
0088  *
0089  * 0 = No delay or sync
0090  * 1 = High on pin stops conversions
0091  * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
0092  * 3 = Edge triggered, edge on pin starts conversion after delay param
0093  */
0094 static int mask;
0095 module_param(mask, int, 0);
0096 MODULE_PARM_DESC(mask, "Set adc mask function.");
0097 
0098 /*
0099  * ADC sample delay times in uS
0100  */
0101 static const int delay_table[] = {
0102     21,    /* 1 AC97 Link frames */
0103     42,    /* 2                  */
0104     84,    /* 4                  */
0105     167,   /* 8                  */
0106     333,   /* 16                 */
0107     667,   /* 32                 */
0108     1000,  /* 48                 */
0109     1333,  /* 64                 */
0110     2000,  /* 96                 */
0111     2667,  /* 128                */
0112     3333,  /* 160                */
0113     4000,  /* 192                */
0114     4667,  /* 224                */
0115     5333,  /* 256                */
0116     6000,  /* 288                */
0117     0      /* No delay, switch matrix always on */
0118 };
0119 
0120 /*
0121  * Delay after issuing a POLL command.
0122  *
0123  * The delay is 3 AC97 link frames + the touchpanel settling delay
0124  */
0125 static inline void poll_delay(int d)
0126 {
0127     udelay(3 * AC97_LINK_FRAME + delay_table[d]);
0128 }
0129 
0130 /*
0131  * set up the physical settings of the WM9705
0132  */
0133 static void wm9705_phy_init(struct wm97xx *wm)
0134 {
0135     u16 dig1 = 0, dig2 = WM97XX_RPR;
0136 
0137     /*
0138     * mute VIDEO and AUX as they share X and Y touchscreen
0139     * inputs on the WM9705
0140     */
0141     wm97xx_reg_write(wm, AC97_AUX, 0x8000);
0142     wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
0143 
0144     /* touchpanel pressure current*/
0145     if (pil == 2) {
0146         dig2 |= WM9705_PIL;
0147         dev_dbg(wm->dev,
0148             "setting pressure measurement current to 400uA.");
0149     } else if (pil)
0150         dev_dbg(wm->dev,
0151             "setting pressure measurement current to 200uA.");
0152     if (!pil)
0153         pressure = 0;
0154 
0155     /* polling mode sample settling delay */
0156     if (delay != 4) {
0157         if (delay < 0 || delay > 15) {
0158             dev_dbg(wm->dev, "supplied delay out of range.");
0159             delay = 4;
0160         }
0161     }
0162     dig1 &= 0xff0f;
0163     dig1 |= WM97XX_DELAY(delay);
0164     dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
0165         delay_table[delay]);
0166 
0167     /* WM9705 pdd */
0168     dig2 |= (pdd & 0x000f);
0169     dev_dbg(wm->dev, "setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
0170 
0171     /* mask */
0172     dig2 |= ((mask & 0x3) << 4);
0173 
0174     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
0175     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
0176 }
0177 
0178 static void wm9705_dig_enable(struct wm97xx *wm, int enable)
0179 {
0180     if (enable) {
0181         wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
0182                  wm->dig[2] | WM97XX_PRP_DET_DIG);
0183         wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
0184     } else
0185         wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
0186                  wm->dig[2] & ~WM97XX_PRP_DET_DIG);
0187 }
0188 
0189 static void wm9705_aux_prepare(struct wm97xx *wm)
0190 {
0191     memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
0192     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
0193     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
0194 }
0195 
0196 static void wm9705_dig_restore(struct wm97xx *wm)
0197 {
0198     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
0199     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
0200 }
0201 
0202 static inline int is_pden(struct wm97xx *wm)
0203 {
0204     return wm->dig[2] & WM9705_PDEN;
0205 }
0206 
0207 /*
0208  * Read a sample from the WM9705 adc in polling mode.
0209  */
0210 static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
0211 {
0212     int timeout = 5 * delay;
0213     bool wants_pen = adcsel & WM97XX_PEN_DOWN;
0214 
0215     if (wants_pen && !wm->pen_probably_down) {
0216         u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0217         if (!(data & WM97XX_PEN_DOWN))
0218             return RC_PENUP;
0219         wm->pen_probably_down = 1;
0220     }
0221 
0222     /* set up digitiser */
0223     if (wm->mach_ops && wm->mach_ops->pre_sample)
0224         wm->mach_ops->pre_sample(adcsel);
0225     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
0226                 | WM97XX_POLL | WM97XX_DELAY(delay));
0227 
0228     /* wait 3 AC97 time slots + delay for conversion */
0229     poll_delay(delay);
0230 
0231     /* wait for POLL to go low */
0232     while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
0233            && timeout) {
0234         udelay(AC97_LINK_FRAME);
0235         timeout--;
0236     }
0237 
0238     if (timeout == 0) {
0239         /* If PDEN is set, we can get a timeout when pen goes up */
0240         if (is_pden(wm))
0241             wm->pen_probably_down = 0;
0242         else
0243             dev_dbg(wm->dev, "adc sample timeout");
0244         return RC_PENUP;
0245     }
0246 
0247     *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0248     if (wm->mach_ops && wm->mach_ops->post_sample)
0249         wm->mach_ops->post_sample(adcsel);
0250 
0251     /* check we have correct sample */
0252     if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
0253         dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
0254             adcsel & WM97XX_ADCSEL_MASK,
0255             *sample & WM97XX_ADCSEL_MASK);
0256         return RC_PENUP;
0257     }
0258 
0259     if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
0260         wm->pen_probably_down = 0;
0261         return RC_PENUP;
0262     }
0263 
0264     return RC_VALID;
0265 }
0266 
0267 /*
0268  * Sample the WM9705 touchscreen in polling mode
0269  */
0270 static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
0271 {
0272     int rc;
0273 
0274     rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
0275     if (rc != RC_VALID)
0276         return rc;
0277     rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
0278     if (rc != RC_VALID)
0279         return rc;
0280     if (pil) {
0281         rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p);
0282         if (rc != RC_VALID)
0283             return rc;
0284     } else
0285         data->p = DEFAULT_PRESSURE;
0286 
0287     return RC_VALID;
0288 }
0289 
0290 /*
0291  * Enable WM9705 continuous mode, i.e. touch data is streamed across
0292  * an AC97 slot
0293  */
0294 static int wm9705_acc_enable(struct wm97xx *wm, int enable)
0295 {
0296     u16 dig1, dig2;
0297     int ret = 0;
0298 
0299     dig1 = wm->dig[1];
0300     dig2 = wm->dig[2];
0301 
0302     if (enable) {
0303         /* continuous mode */
0304         if (wm->mach_ops->acc_startup &&
0305             (ret = wm->mach_ops->acc_startup(wm)) < 0)
0306             return ret;
0307         dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
0308               WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
0309         dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
0310             WM97XX_DELAY(delay) |
0311             WM97XX_SLT(wm->acc_slot) |
0312             WM97XX_RATE(wm->acc_rate);
0313         if (pil)
0314             dig1 |= WM97XX_ADCSEL_PRES;
0315         dig2 |= WM9705_PDEN;
0316     } else {
0317         dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
0318         dig2 &= ~WM9705_PDEN;
0319         if (wm->mach_ops->acc_shutdown)
0320             wm->mach_ops->acc_shutdown(wm);
0321     }
0322 
0323     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
0324     wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
0325 
0326     return ret;
0327 }
0328 
0329 struct wm97xx_codec_drv wm9705_codec = {
0330     .id = WM9705_ID2,
0331     .name = "wm9705",
0332     .poll_sample = wm9705_poll_sample,
0333     .poll_touch = wm9705_poll_touch,
0334     .acc_enable = wm9705_acc_enable,
0335     .phy_init = wm9705_phy_init,
0336     .dig_enable = wm9705_dig_enable,
0337     .dig_restore = wm9705_dig_restore,
0338     .aux_prepare = wm9705_aux_prepare,
0339 };
0340 EXPORT_SYMBOL_GPL(wm9705_codec);
0341 
0342 /* Module information */
0343 MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
0344 MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
0345 MODULE_LICENSE("GPL");