X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Ftouchscreen%2Fads7846.c;fp=drivers%2Finput%2Ftouchscreen%2Fads7846.c;h=8c12a974b411a75093c2f65319b4c88761bc5dd7;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=66e411badf70c9f2752a2a557d973587aa5c074b;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 66e411bad..8c12a974b 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -2,8 +2,6 @@ * ADS7846 based touchscreen and sensor driver * * Copyright (c) 2005 David Brownell - * Copyright (c) 2006 Nokia Corporation - * Various changes: Imre Deak * * Using code from: * - corgi_ts.c @@ -25,7 +23,6 @@ #include #include #include -#include #ifdef CONFIG_ARM #include @@ -36,22 +33,17 @@ /* - * This code has been heavily tested on a Nokia 770, and lightly - * tested on other ads7846 devices (OSK/Mistral, Lubbock). + * This code has been lightly tested on an ads7846. * Support for ads7843 and ads7845 has only been stubbed in. * - * IRQ handling needs a workaround because of a shortcoming in handling - * edge triggered IRQs on some platforms like the OMAP1/2. These - * platforms don't handle the ARM lazy IRQ disabling properly, thus we - * have to maintain our own SW IRQ disabled status. This should be - * removed as soon as the affected platform's IRQ handling is fixed. + * Not yet done: investigate the values reported. Are x/y/pressure + * event values sane enough for X11? How accurate are the temperature + * and voltage readings? (System-specific calibration should support + * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) * * app note sbaa036 talks in more detail about accurate sampling... * that ought to help in situations like LCDs inducing noise (which * can also be helped by using synch signals) and more generally. - * This driver tries to utilize the measures described in the app - * note. The strength of filtering can be set in the board-* specific - * files. */ #define TS_POLL_PERIOD msecs_to_jiffies(10) @@ -68,7 +60,6 @@ struct ts_event { __be16 x; __be16 y; __be16 z1, z2; - int ignore; }; struct ads7846 { @@ -79,23 +70,12 @@ struct ads7846 { u16 model; u16 vref_delay_usecs; u16 x_plate_ohms; - u16 pressure_max; - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ + u8 read_x, read_y, read_z1, read_z2; struct ts_event tc; - struct spi_transfer xfer[10]; - struct spi_message msg[5]; - struct spi_message *last_msg; - int msg_idx; - int read_cnt; - int read_rep; - int last_read; - - u16 debounce_max; - u16 debounce_tol; - u16 debounce_rep; + struct spi_transfer xfer[8]; + struct spi_message msg; spinlock_t lock; struct timer_list timer; /* P: lock */ @@ -103,9 +83,6 @@ struct ads7846 { unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ - unsigned disabled:1; - - int (*get_pendown_state)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -147,9 +124,7 @@ struct ads7846 { #define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) #define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON) #define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON) - -#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) -#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ +#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) /* LAST */ /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -176,15 +151,6 @@ struct ser_req { struct spi_transfer xfer[6]; }; -static void ads7846_enable(struct ads7846 *ts); -static void ads7846_disable(struct ads7846 *ts); - -static int device_suspended(struct device *dev) -{ - struct ads7846 *ts = dev_get_drvdata(dev); - return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; -} - static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); @@ -197,7 +163,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) if (!req) return -ENOMEM; - spi_message_init(&req->msg); + INIT_LIST_HEAD(&req->msg.transfers); /* activate reference, so it has time to settle; */ req->ref_on = REF_ON; @@ -237,21 +203,16 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) for (i = 0; i < 6; i++) spi_message_add_tail(&req->xfer[i], &req->msg); - ts->irq_disabled = 1; disable_irq(spi->irq); status = spi_sync(spi, &req->msg); - ts->irq_disabled = 0; enable_irq(spi->irq); if (req->msg.status) status = req->msg.status; - - /* on-wire is a must-ignore bit, a BE12 value, then padding */ sample = be16_to_cpu(req->sample); - sample = sample >> 3; - sample &= 0x0fff; - + sample = sample >> 4; kfree(req); + return status ? status : sample; } @@ -271,52 +232,6 @@ SHOW(temp1) SHOW(vaux) SHOW(vbatt) -static int is_pen_down(struct device *dev) -{ - struct ads7846 *ts = dev_get_drvdata(dev); - - return ts->pendown; -} - -static ssize_t ads7846_pen_down_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", is_pen_down(dev)); -} - -static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); - -static ssize_t ads7846_disable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ads7846 *ts = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", ts->disabled); -} - -static ssize_t ads7846_disable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ads7846 *ts = dev_get_drvdata(dev); - char *endp; - int i; - - i = simple_strtoul(buf, &endp, 10); - spin_lock_irq(&ts->lock); - - if (i) - ads7846_disable(ts); - else - ads7846_enable(ts); - - spin_unlock_irq(&ts->lock); - - return count; -} - -static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); - /*--------------------------------------------------------------------------*/ /* @@ -336,19 +251,19 @@ static void ads7846_rx(void *ads) u16 x, y, z1, z2; unsigned long flags; - /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; - * built from two 8 bit values written msb-first. + /* adjust: 12 bit samples (left aligned), built from + * two 8 bit values writen msb-first. */ - x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff; - y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff; - z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff; - z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff; + x = be16_to_cpu(ts->tc.x) >> 4; + y = be16_to_cpu(ts->tc.y) >> 4; + z1 = be16_to_cpu(ts->tc.z1) >> 4; + z2 = be16_to_cpu(ts->tc.z2) >> 4; /* range filtering */ if (x == MAX_12BIT) x = 0; - if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { + if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -359,14 +274,6 @@ static void ads7846_rx(void *ads) } else Rt = 0; - /* Sample found inconsistent by debouncing or pressure is beyond - * the maximum. Don't report it to user space, repeat at least - * once more the measurement */ - if (ts->tc.ignore || Rt > ts->pressure_max) { - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); - return; - } - /* NOTE: "pendown" is inferred from pressure; we don't rely on * being able to check nPENIRQ status, or "friendly" trigger modes * (both-edges is much better than just-falling or low-level). @@ -388,13 +295,11 @@ static void ads7846_rx(void *ads) if (Rt) { input_report_abs(input_dev, ABS_X, x); input_report_abs(input_dev, ABS_Y, y); + input_report_abs(input_dev, ABS_PRESSURE, Rt); sync = 1; } - - if (sync) { - input_report_abs(input_dev, ABS_PRESSURE, Rt); + if (sync) input_sync(input_dev); - } #ifdef VERBOSE if (Rt || ts->pendown) @@ -402,137 +307,80 @@ static void ads7846_rx(void *ads) x, y, Rt, Rt ? "" : " UP"); #endif + /* don't retrigger while we're suspended */ spin_lock_irqsave(&ts->lock, flags); ts->pendown = (Rt != 0); - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); - - spin_unlock_irqrestore(&ts->lock, flags); -} - -static void ads7846_debounce(void *ads) -{ - struct ads7846 *ts = ads; - struct spi_message *m; - struct spi_transfer *t; - int val; - int status; - - m = &ts->msg[ts->msg_idx]; - t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff; - if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { - /* Repeat it, if this was the first read or the read - * wasn't consistent enough. */ - if (ts->read_cnt < ts->debounce_max) { - ts->last_read = val; - ts->read_cnt++; - } else { - /* Maximum number of debouncing reached and still - * not enough number of consistent readings. Abort - * the whole sample, repeat it in the next sampling - * period. - */ - ts->tc.ignore = 1; - ts->read_cnt = 0; - /* Last message will contain ads7846_rx() as the - * completion function. - */ - m = ts->last_msg; - } - /* Start over collecting consistent readings. */ - ts->read_rep = 0; - } else { - if (++ts->read_rep > ts->debounce_rep) { - /* Got a good reading for this coordinate, - * go for the next one. */ - ts->tc.ignore = 0; - ts->msg_idx++; - ts->read_cnt = 0; - ts->read_rep = 0; - m++; - } else - /* Read more values that are consistent. */ - ts->read_cnt++; - } - status = spi_async(ts->spi, m); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", - status); -} - -static void ads7846_timer(unsigned long handle) -{ - struct ads7846 *ts = (void *)handle; - int status = 0; - - spin_lock_irq(&ts->lock); + ts->pending = 0; - if (unlikely(ts->msg_idx && !ts->pendown)) { - /* measurement cycle ended */ - if (!device_suspended(&ts->spi->dev)) { + if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) { + if (ts->pendown) + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + else if (ts->irq_disabled) { ts->irq_disabled = 0; enable_irq(ts->spi->irq); } - ts->pending = 0; - ts->msg_idx = 0; - } else { - /* pen is still down, continue with the measurement */ - ts->msg_idx = 0; - status = spi_async(ts->spi, &ts->msg[0]); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", status); } - spin_unlock_irq(&ts->lock); + spin_unlock_irqrestore(&ts->lock, flags); } -static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) +static void ads7846_timer(unsigned long handle) { - struct ads7846 *ts = handle; - unsigned long flags; + struct ads7846 *ts = (void *)handle; + int status = 0; + unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (likely(ts->get_pendown_state())) { + if (!ts->pending) { + ts->pending = 1; if (!ts->irq_disabled) { - /* The ARM do_simple_IRQ() dispatcher doesn't act - * like the other dispatchers: it will report IRQs - * even after they've been disabled. We work around - * that here. (The "generic irq" framework may help...) - */ ts->irq_disabled = 1; disable_irq(ts->spi->irq); - ts->pending = 1; - mod_timer(&ts->timer, jiffies); } + status = spi_async(ts->spi, &ts->msg); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", + status); } spin_unlock_irqrestore(&ts->lock, flags); +} +static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) +{ + ads7846_timer((unsigned long) handle); return IRQ_HANDLED; } /*--------------------------------------------------------------------------*/ -/* Must be called with ts->lock held */ -static void ads7846_disable(struct ads7846 *ts) +static int +ads7846_suspend(struct spi_device *spi, pm_message_t message) { - if (ts->disabled) - return; + struct ads7846 *ts = dev_get_drvdata(&spi->dev); + unsigned long flags; - ts->disabled = 1; + spin_lock_irqsave(&ts->lock, flags); + + spi->dev.power.power_state = message; /* are we waiting for IRQ, or polling? */ - if (!ts->pending) { - ts->irq_disabled = 1; - disable_irq(ts->spi->irq); + if (!ts->pendown) { + if (!ts->irq_disabled) { + ts->irq_disabled = 1; + disable_irq(ts->spi->irq); + } } else { - /* the timer will run at least once more, and - * leave everything in a clean state, IRQ disabled + /* polling; force a final SPI completion; + * that will clean things up neatly */ - while (ts->pending) { - spin_unlock_irq(&ts->lock); - msleep(1); - spin_lock_irq(&ts->lock); + if (!ts->pending) + mod_timer(&ts->timer, jiffies); + + while (ts->pendown || ts->pending) { + spin_unlock_irqrestore(&ts->lock, flags); + udelay(10); + spin_lock_irqsave(&ts->lock, flags); } } @@ -540,45 +388,17 @@ static void ads7846_disable(struct ads7846 *ts) * leave it that way after every request */ -} - -/* Must be called with ts->lock held */ -static void ads7846_enable(struct ads7846 *ts) -{ - if (!ts->disabled) - return; - - ts->disabled = 0; - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); -} - -static int ads7846_suspend(struct spi_device *spi, pm_message_t message) -{ - struct ads7846 *ts = dev_get_drvdata(&spi->dev); - - spin_lock_irq(&ts->lock); - - spi->dev.power.power_state = message; - ads7846_disable(ts); - - spin_unlock_irq(&ts->lock); - + spin_unlock_irqrestore(&ts->lock, flags); return 0; - } static int ads7846_resume(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - spin_lock_irq(&ts->lock); - + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); spi->dev.power.power_state = PMSG_ON; - ads7846_enable(ts); - - spin_unlock_irq(&ts->lock); - return 0; } @@ -587,7 +407,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) struct ads7846 *ts; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; - struct spi_message *m; struct spi_transfer *x; int err; @@ -608,20 +427,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) return -EINVAL; } - /* REVISIT when the irq can be triggered active-low, or if for some - * reason the touchscreen isn't hooked up, we don't need to access - * the pendown state. + /* We'd set the wordsize to 12 bits ... except that some controllers + * will then treat the 8 bit command words as 12 bits (and drop the + * four MSBs of the 12 bit result). Result: inputs must be shifted + * to discard the four garbage LSBs. */ - if (pdata->get_pendown_state == NULL) { - dev_dbg(&spi->dev, "no get_pendown_state function?\n"); - return -EINVAL; - } - - /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except - * that even if the hardware can do that, the SPI controller driver - * may not. So we stick to very-portable 8 bit words, both RX and TX. - */ - spi->bits_per_word = 8; ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); input_dev = input_allocate_device(); @@ -640,21 +450,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->timer.data = (unsigned long) ts; ts->timer.function = ads7846_timer; - spin_lock_init(&ts->lock); - ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; - ts->pressure_max = pdata->pressure_max ? : ~0; - if (pdata->debounce_max) { - ts->debounce_max = pdata->debounce_max; - ts->debounce_tol = pdata->debounce_tol; - ts->debounce_rep = pdata->debounce_rep; - if (ts->debounce_rep > ts->debounce_max + 1) - ts->debounce_rep = ts->debounce_max - 1; - } else - ts->debounce_tol = ~0; - ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -678,103 +476,64 @@ static int __devinit ads7846_probe(struct spi_device *spi) /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ - m = &ts->msg[0]; + INIT_LIST_HEAD(&ts->msg.transfers); x = ts->xfer; - spi_message_init(m); - /* y- still on; turn on only y+ (and ADC) */ ts->read_y = READ_Y; x->tx_buf = &ts->read_y; x->len = 1; - spi_message_add_tail(x, m); + spi_message_add_tail(x, &ts->msg); x++; x->rx_buf = &ts->tc.y; x->len = 2; - spi_message_add_tail(x, m); - - m->complete = ads7846_debounce; - m->context = ts; - - m++; - spi_message_init(m); - - /* turn y- off, x+ on, then leave in lowpower */ - x++; - ts->read_x = READ_X; - x->tx_buf = &ts->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &ts->tc.x; - x->len = 2; - spi_message_add_tail(x, m); - - m->complete = ads7846_debounce; - m->context = ts; + spi_message_add_tail(x, &ts->msg); /* turn y+ off, x- on; we'll use formula #2 */ if (ts->model == 7846) { - m++; - spi_message_init(m); - x++; ts->read_z1 = READ_Z1; x->tx_buf = &ts->read_z1; x->len = 1; - spi_message_add_tail(x, m); + spi_message_add_tail(x, &ts->msg); x++; x->rx_buf = &ts->tc.z1; x->len = 2; - spi_message_add_tail(x, m); - - m->complete = ads7846_debounce; - m->context = ts; - - m++; - spi_message_init(m); + spi_message_add_tail(x, &ts->msg); x++; ts->read_z2 = READ_Z2; x->tx_buf = &ts->read_z2; x->len = 1; - spi_message_add_tail(x, m); + spi_message_add_tail(x, &ts->msg); x++; x->rx_buf = &ts->tc.z2; x->len = 2; - spi_message_add_tail(x, m); - - m->complete = ads7846_debounce; - m->context = ts; + spi_message_add_tail(x, &ts->msg); } - /* power down */ - m++; - spi_message_init(m); - + /* turn y- off, x+ on, then leave in lowpower */ x++; - ts->pwrdown = PWRDOWN; - x->tx_buf = &ts->pwrdown; + ts->read_x = READ_X; + x->tx_buf = &ts->read_x; x->len = 1; - spi_message_add_tail(x, m); + spi_message_add_tail(x, &ts->msg); x++; - x->rx_buf = &ts->dummy; + x->rx_buf = &ts->tc.x; x->len = 2; CS_CHANGE(*x); - spi_message_add_tail(x, m); - - m->complete = ads7846_rx; - m->context = ts; + spi_message_add_tail(x, &ts->msg); - ts->last_msg = m; + ts->msg.complete = ads7846_rx; + ts->msg.context = ts; - if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, - spi->dev.driver->name, ts)) { + if (request_irq(spi->irq, ads7846_irq, + SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, + spi->dev.bus_id, ts)) { dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); err = -EBUSY; goto err_free_mem; @@ -799,27 +558,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) device_create_file(&spi->dev, &dev_attr_vbatt); device_create_file(&spi->dev, &dev_attr_vaux); - device_create_file(&spi->dev, &dev_attr_pen_down); - - device_create_file(&spi->dev, &dev_attr_disable); - err = input_register_device(input_dev); if (err) - goto err_remove_attr; + goto err_free_irq; return 0; - err_remove_attr: - device_remove_file(&spi->dev, &dev_attr_disable); - device_remove_file(&spi->dev, &dev_attr_pen_down); - if (ts->model == 7846) { - device_remove_file(&spi->dev, &dev_attr_temp1); - device_remove_file(&spi->dev, &dev_attr_temp0); - } - if (ts->model != 7845) - device_remove_file(&spi->dev, &dev_attr_vbatt); - device_remove_file(&spi->dev, &dev_attr_vaux); - + err_free_irq: free_irq(spi->irq, ts); err_free_mem: input_free_device(input_dev); @@ -831,24 +576,20 @@ static int __devexit ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - input_unregister_device(ts->input); - ads7846_suspend(spi, PMSG_SUSPEND); + free_irq(ts->spi->irq, ts); + if (ts->irq_disabled) + enable_irq(ts->spi->irq); - device_remove_file(&spi->dev, &dev_attr_disable); - device_remove_file(&spi->dev, &dev_attr_pen_down); if (ts->model == 7846) { - device_remove_file(&spi->dev, &dev_attr_temp1); device_remove_file(&spi->dev, &dev_attr_temp0); + device_remove_file(&spi->dev, &dev_attr_temp1); } if (ts->model != 7845) device_remove_file(&spi->dev, &dev_attr_vbatt); device_remove_file(&spi->dev, &dev_attr_vaux); - free_irq(ts->spi->irq, ts); - /* suspend left the IRQ disabled */ - enable_irq(ts->spi->irq); - + input_unregister_device(ts->input); kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n");