diff options
Diffstat (limited to 'drivers/input/touchscreen/wm97xx-core.c')
| -rw-r--r-- | drivers/input/touchscreen/wm97xx-core.c | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index d15aa11d705..d0ef91fc87d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -48,6 +48,7 @@ #include <linux/wm97xx.h> #include <linux/uaccess.h> #include <linux/io.h> +#include <linux/slab.h> #define TS_NAME "wm97xx" #define WM_CORE_VERSION "1.00" @@ -124,6 +125,8 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) { int power_adc = 0, auxval; u16 power = 0; + int rc = 0; + int timeout = 0; /* get codec */ mutex_lock(&wm->codec_mutex); @@ -142,7 +145,9 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) /* Turn polling mode on to read AUX ADC */ wm->pen_probably_down = 1; - wm->codec->poll_sample(wm, adcsel, &auxval); + + while (rc != RC_VALID && timeout++ < 5) + rc = wm->codec->poll_sample(wm, adcsel, &auxval); if (power_adc) wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000); @@ -151,8 +156,15 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) wm->pen_probably_down = 0; + if (timeout >= 5) { + dev_err(wm->dev, + "timeout reading auxadc %d, disabling digitiser\n", + adcsel); + wm->codec->dig_enable(wm, false); + } + mutex_unlock(&wm->codec_mutex); - return auxval & 0xfff; + return (rc == RC_VALID ? auxval & 0xfff : -EBUSY); } EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); @@ -199,12 +211,12 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, mutex_lock(&wm->codec_mutex); reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); - if (status & WM97XX_GPIO_HIGH) + if (status == WM97XX_GPIO_HIGH) reg |= gpio; else reg &= ~gpio; - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); else wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); @@ -307,7 +319,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) WM97XX_GPIO_13); } - if (wm->id == WM9712_ID2) + if (wm->id == WM9712_ID2 && wm->variant != WM97xx_WM1613) wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status & ~WM97XX_GPIO_13) << 1); else @@ -323,7 +335,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) */ if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) { if (wm->pen_is_down && !pen_was_down) { - /* Data is not availiable immediately on pen down */ + /* Data is not available immediately on pen down */ queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1); } @@ -342,7 +354,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) * Codec PENDOWN irq handler * * We have to disable the codec interrupt in the handler because it - * can take upto 1ms to clear the interrupt source. We schedule a task + * can take up to 1ms to clear the interrupt source. We schedule a task * in a work queue to do the actual interaction with the chip. The * interrupt is then enabled again in the slow handler when the source * has been cleared. @@ -370,8 +382,7 @@ static int wm97xx_init_pen_irq(struct wm97xx *wm) * provided. */ BUG_ON(!wm->mach_ops->irq_enable); - if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, + if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED, "wm97xx-pen", wm)) { dev_err(wm->dev, "Failed to register pen down interrupt, polling"); @@ -409,6 +420,7 @@ static int wm97xx_read_samples(struct wm97xx *wm) wm->pen_is_down = 0; dev_dbg(wm->dev, "pen up\n"); input_report_abs(wm->input_dev, ABS_PRESSURE, 0); + input_report_key(wm->input_dev, BTN_TOUCH, 0); input_sync(wm->input_dev); } else if (!(rc & RC_AGAIN)) { /* We need high frequency updates only while @@ -430,9 +442,20 @@ static int wm97xx_read_samples(struct wm97xx *wm) "pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n", data.x >> 12, data.x & 0xfff, data.y >> 12, data.y & 0xfff, data.p >> 12, data.p & 0xfff); + + if (abs_x[0] > (data.x & 0xfff) || + abs_x[1] < (data.x & 0xfff) || + abs_y[0] > (data.y & 0xfff) || + abs_y[1] < (data.y & 0xfff)) { + dev_dbg(wm->dev, "Measurement out of range, dropping it\n"); + rc = RC_AGAIN; + goto out; + } + input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff); input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff); + input_report_key(wm->input_dev, BTN_TOUCH, 1); input_sync(wm->input_dev); wm->pen_is_down = 1; wm->ts_reader_interval = wm->ts_reader_min_interval; @@ -442,6 +465,7 @@ static int wm97xx_read_samples(struct wm97xx *wm) wm->ts_reader_interval = wm->ts_reader_min_interval; } +out: mutex_unlock(&wm->codec_mutex); return rc; } @@ -560,6 +584,7 @@ static void wm97xx_ts_input_close(struct input_dev *idev) static int wm97xx_probe(struct device *dev) { struct wm97xx *wm; + struct wm97xx_pdata *pdata = dev_get_platdata(dev); int ret = 0, id = 0; wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL); @@ -568,7 +593,7 @@ static int wm97xx_probe(struct device *dev) mutex_init(&wm->codec_mutex); wm->dev = dev; - dev->driver_data = wm; + dev_set_drvdata(dev, wm); wm->ac97 = to_ac97_t(dev); /* check that we have a supported codec */ @@ -581,6 +606,8 @@ static int wm97xx_probe(struct device *dev) wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2); + wm->variant = WM97xx_GENERIC; + dev_info(wm->dev, "detected a wm97%02x codec\n", wm->id & 0xff); switch (wm->id & 0xff) { @@ -628,18 +655,21 @@ static int wm97xx_probe(struct device *dev) wm->input_dev->phys = "wm97xx"; wm->input_dev->open = wm97xx_ts_input_open; wm->input_dev->close = wm97xx_ts_input_close; - set_bit(EV_ABS, wm->input_dev->evbit); - set_bit(ABS_X, wm->input_dev->absbit); - set_bit(ABS_Y, wm->input_dev->absbit); - set_bit(ABS_PRESSURE, wm->input_dev->absbit); + + __set_bit(EV_ABS, wm->input_dev->evbit); + __set_bit(EV_KEY, wm->input_dev->evbit); + __set_bit(BTN_TOUCH, wm->input_dev->keybit); + input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1], abs_x[2], 0); input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1], abs_y[2], 0); input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1], abs_p[2], 0); + input_set_drvdata(wm->input_dev, wm); wm->input_dev->dev.parent = dev; + ret = input_register_device(wm->input_dev); if (ret < 0) goto dev_alloc_err; @@ -652,6 +682,7 @@ static int wm97xx_probe(struct device *dev) } platform_set_drvdata(wm->battery_dev, wm); wm->battery_dev->dev.parent = dev; + wm->battery_dev->dev.platform_data = pdata; ret = platform_device_add(wm->battery_dev); if (ret < 0) goto batt_reg_err; @@ -665,6 +696,7 @@ static int wm97xx_probe(struct device *dev) } platform_set_drvdata(wm->touch_dev, wm); wm->touch_dev->dev.parent = dev; + wm->touch_dev->dev.platform_data = pdata; ret = platform_device_add(wm->touch_dev); if (ret < 0) goto touch_reg_err; @@ -674,8 +706,7 @@ static int wm97xx_probe(struct device *dev) touch_reg_err: platform_device_put(wm->touch_dev); touch_err: - platform_device_unregister(wm->battery_dev); - wm->battery_dev = NULL; + platform_device_del(wm->battery_dev); batt_reg_err: platform_device_put(wm->battery_dev); batt_err: |
