diff options
author | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-15 15:53:51 -0500 |
---|---|---|
committer | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-15 15:53:51 -0500 |
commit | dfdbf3f6e2d279f2a46ed95614cb4bf07657394d (patch) | |
tree | 2cc05669c5d3e47f7d4b28e31076b6dc6e771f36 /drivers/input | |
parent | effff5718c380983788fe6c380671c18e15ac7c2 (diff) |
Digi del-5.6 Complete2.6.31-digi-201102151558
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/keyboard/atkbd.c | 9 | ||||
-rw-r--r-- | drivers/input/keyboard/mxc_keyb.c | 237 | ||||
-rw-r--r-- | drivers/input/misc/mma7455l.c | 2 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 252 | ||||
-rw-r--r-- | drivers/input/mouse/alps.h | 1 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 1157 | ||||
-rw-r--r-- | drivers/input/touchscreen/mxc_ts.c | 3 |
8 files changed, 966 insertions, 705 deletions
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 6c6a09b1c0fe..abc314f93ff3 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1608,6 +1608,15 @@ static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = { .driver_data = atkbd_samsung_forced_release_keys, }, { + .ident = "Samsung R59P/R60P/R61P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"), + }, + .callback = atkbd_setup_forced_release, + .driver_data = atkbd_samsung_forced_release_keys, + }, + { .ident = "Fujitsu Amilo PA 1510", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), diff --git a/drivers/input/keyboard/mxc_keyb.c b/drivers/input/keyboard/mxc_keyb.c index 99dd7cf51cb5..033713cbdfdf 100644 --- a/drivers/input/keyboard/mxc_keyb.c +++ b/drivers/input/keyboard/mxc_keyb.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -58,12 +58,168 @@ #include <linux/clk.h> #include <asm/mach/keypad.h> +/*! + * Keypad Module Name + */ +#define MOD_NAME "mxckpd" + +/*! + * XLATE mode selection + */ +#define KEYPAD_XLATE 0 + +/*! + * RAW mode selection + */ +#define KEYPAD_RAW 1 + +/*! + * Maximum number of keys. + */ +#define MAXROW 8 +#define MAXCOL 8 +#define MXC_MAXKEY (MAXROW * MAXCOL) + +/*! + * This define indicates break scancode for every key release. A constant + * of 128 is added to the key press scancode. + */ +#define MXC_KEYRELEASE 128 + +/* + * _reg_KPP_KPCR _reg_KPP_KPSR _reg_KPP_KDDR _reg_KPP_KPDR + * The offset of Keypad Control Register Address + */ +#define KPCR 0x00 + +/* + * The offset of Keypad Status Register Address + */ +#define KPSR 0x02 + +/* + * The offset of Keypad Data Direction Address + */ +#define KDDR 0x04 + +/* + * The offset of Keypad Data Register + */ +#define KPDR 0x06 + +/* + * Key Press Interrupt Status bit + */ +#define KBD_STAT_KPKD 0x01 + +/* + * Key Release Interrupt Status bit + */ +#define KBD_STAT_KPKR 0x02 + +/* + * Key Depress Synchronizer Chain Status bit + */ +#define KBD_STAT_KDSC 0x04 + +/* + * Key Release Synchronizer Status bit + */ +#define KBD_STAT_KRSS 0x08 + +/* + * Key Depress Interrupt Enable Status bit + */ +#define KBD_STAT_KDIE 0x100 + /* - * Module header file + * Key Release Interrupt Enable */ -#include "mxc_keyb.h" +#define KBD_STAT_KRIE 0x200 + +/* + * Keypad Clock Enable + */ +#define KBD_STAT_KPPEN 0x400 + +/*! + * Buffer size of keypad queue. Should be a power of 2. + */ +#define KPP_BUF_SIZE 128 + +/*! + * Test whether bit is set for integer c + */ +#define TEST_BIT(c, n) ((c) & (0x1 << (n))) + +/*! + * Set nth bit in the integer c + */ +#define BITSET(c, n) ((c) | (1 << (n))) + +/*! + * Reset nth bit in the integer c + */ +#define BITRESET(c, n) ((c) & ~(1 << (n))) + +/*! + * This enum represents the keypad state machine to maintain debounce logic + * for key press/release. + */ +enum KeyState { + + /*! + * Key press state. + */ + KStateUp, + + /*! + * Key press debounce state. + */ + KStateFirstDown, + + /*! + * Key release state. + */ + KStateDown, + + /*! + * Key release debounce state. + */ + KStateFirstUp +}; /*! + * Keypad Private Data Structure + */ +struct keypad_priv { + + /*! + * Keypad state machine. + */ + enum KeyState iKeyState; + + /*! + * Number of rows configured in the keypad matrix + */ + unsigned long kpp_rows; + + /*! + * Number of Columns configured in the keypad matrix + */ + unsigned long kpp_cols; + + /*! + * Timer used for Keypad polling. + */ + struct timer_list poll_timer; + + /*! + * The base address + */ + void __iomem *base; +}; +/*! * This structure holds the keypad private data structure. */ static struct keypad_priv kpp_dev; @@ -269,26 +425,26 @@ static int mxc_kpp_scan_matrix(void) for (col = 0; col < kpp_dev.kpp_cols; col++) { /* Col */ /* 2. Write 1.s to KPDR[15:8] setting column data to 1.s */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val |= 0xff00; - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* * 3. Configure columns as totem pole outputs(for quick * discharging of keypad capacitance) */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val &= 0x00ff; - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); udelay(2); /* * 4. Configure columns as open-drain */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val |= ((1 << kpp_dev.kpp_cols) - 1) << 8; - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); /* * 5. Write a single column to 0, others to 1. @@ -298,9 +454,9 @@ static int mxc_kpp_scan_matrix(void) */ /* Col bit starts at 8th bit in KPDR */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val &= ~(1 << (8 + col)); - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* Delay added to avoid propagating the 0 from column to row * when scanning. */ @@ -308,7 +464,7 @@ static int mxc_kpp_scan_matrix(void) udelay(5); /* Read row input */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); for (row = 0; row < kpp_dev.kpp_rows; row++) { /* sample row */ if (TEST_BIT(reg_val, row) == 0) { cur_rcmap[row] = BITSET(cur_rcmap[row], col); @@ -324,12 +480,12 @@ static int mxc_kpp_scan_matrix(void) * clear the KPKD synchronizer chain by writing "1" to KDSC register */ reg_val = 0x00; - __raw_writew(reg_val, KPDR); - reg_val = __raw_readw(KPDR); - reg_val = __raw_readw(KPSR); + __raw_writew(reg_val, kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= KBD_STAT_KPKD | KBD_STAT_KPKR | KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); /* Check key press status change */ @@ -558,14 +714,14 @@ static void mxc_kpp_handle_timer(unsigned long data) * Stop scanning and wait for interrupt. * Enable press interrupt and disable release interrupt. */ - __raw_writew(0x00FF, KPDR); - reg_val = __raw_readw(KPSR); + __raw_writew(0x00FF, kpp_dev.base + KPDR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= (KBD_STAT_KPKR | KBD_STAT_KPKD); reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); /* * No more keys pressed... make sure unwanted key codes are @@ -613,7 +769,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id) /* Delete the polling timer */ del_timer(&kpp_dev.poll_timer); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); /* Check if it is key press interrupt */ if (reg_val & KBD_STAT_KPKD) { @@ -621,7 +777,7 @@ static irqreturn_t mxc_kpp_interrupt(int irq, void *dev_id) * Disable key press(KDIE status bit) interrupt */ reg_val &= ~KBD_STAT_KDIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); } else { /* spurious interrupt */ return IRQ_RETVAL(0); @@ -767,6 +923,7 @@ static int mxc_kpp_probe(struct platform_device *pdev) int i, irq; int retval; unsigned int reg_val; + struct resource *res; keypad = (struct keypad_data *)pdev->dev.platform_data; @@ -774,6 +931,14 @@ static int mxc_kpp_probe(struct platform_device *pdev) kpp_dev.kpp_rows = keypad->rowmax; key_pad_enabled = 0; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + kpp_dev.base = ioremap(res->start, res->end - res->start + 1); + if (!kpp_dev.base) + return -ENOMEM; + irq = platform_get_irq(pdev, 0); keypad->irq = irq; @@ -793,30 +958,30 @@ static int mxc_kpp_probe(struct platform_device *pdev) * LSB nibble in KPP is for 8 rows * MSB nibble in KPP is for 8 cols */ - reg_val = __raw_readw(KPCR); + reg_val = __raw_readw(kpp_dev.base + KPCR); reg_val |= (1 << keypad->rowmax) - 1; /* LSB */ reg_val |= ((1 << keypad->colmax) - 1) << 8; /* MSB */ - __raw_writew(reg_val, KPCR); + __raw_writew(reg_val, kpp_dev.base + KPCR); /* Write 0's to KPDR[15:8] */ - reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(kpp_dev.base + KPDR); reg_val &= 0x00ff; - __raw_writew(reg_val, KPDR); + __raw_writew(reg_val, kpp_dev.base + KPDR); /* Configure columns as output, rows as input (KDDR[15:0]) */ - reg_val = __raw_readw(KDDR); + reg_val = __raw_readw(kpp_dev.base + KDDR); reg_val |= 0xff00; reg_val &= 0xff00; - __raw_writew(reg_val, KDDR); + __raw_writew(reg_val, kpp_dev.base + KDDR); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val &= ~(KBD_STAT_KPKR | KBD_STAT_KPKD); reg_val |= KBD_STAT_KPKD; reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); has_leaning_key = keypad->learning; mxckpd_keycodes = keypad->matrix; @@ -950,16 +1115,16 @@ static int mxc_kpp_remove(struct platform_device *pdev) * Set KDIE control bit, clear KRIE control bit (avoid false release * events. Disable the keypad GPIO pins. */ - __raw_writew(0x00, KPCR); - __raw_writew(0x00, KPDR); - __raw_writew(0x00, KDDR); + __raw_writew(0x00, kpp_dev.base + KPCR); + __raw_writew(0x00, kpp_dev.base + KPDR); + __raw_writew(0x00, kpp_dev.base + KDDR); - reg_val = __raw_readw(KPSR); + reg_val = __raw_readw(kpp_dev.base + KPSR); reg_val |= KBD_STAT_KPKD; reg_val &= ~KBD_STAT_KRSS; reg_val |= KBD_STAT_KDIE; reg_val &= ~KBD_STAT_KRIE; - __raw_writew(reg_val, KPSR); + __raw_writew(reg_val, kpp_dev.base + KPSR); gpio_keypad_inactive(); clk_disable(kpp_clk); diff --git a/drivers/input/misc/mma7455l.c b/drivers/input/misc/mma7455l.c index 1cee2d1add04..48dca60d2cfe 100644 --- a/drivers/input/misc/mma7455l.c +++ b/drivers/input/misc/mma7455l.c @@ -583,6 +583,8 @@ static int __devexit mma7455l_remove(struct i2c_client *client) { struct mma7455l_info *mma = dev_get_drvdata(&client->dev); + free_irq(client->irq, mma); + sysfs_remove_group(&client->dev.kobj, &mma7455l_attr_group); input_unregister_device(mma->input_dev); dev_set_drvdata(&client->dev, NULL); diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 5547e2429fbe..b172bef75910 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -5,6 +5,7 @@ * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net> * * ALPS detection, tap switching and status querying info is taken from * tpconfig utility (by C. Scott Ananian and Bruce Kall). @@ -35,6 +36,8 @@ #define ALPS_OLDPROTO 0x10 #define ALPS_PASS 0x20 #define ALPS_FW_BK_2 0x40 +#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with + 6-byte ALPS packet */ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ @@ -55,7 +58,9 @@ static const struct alps_model_info alps_model_data[] = { { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ - { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ + /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ }; @@ -66,20 +71,88 @@ static const struct alps_model_info alps_model_data[] = { */ /* - * ALPS abolute Mode - new format + * PS/2 packet format + * + * byte 0: 0 0 YSGN XSGN 1 M R L + * byte 1: X7 X6 X5 X4 X3 X2 X1 X0 + * byte 2: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * + * Note that the device never signals overflow condition. + * + * ALPS absolute Mode - new format * * byte 0: 1 ? ? ? 1 ? ? ? * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 - * byte 2: 0 x10 x9 x8 x7 ? fin ges + * byte 2: 0 x10 x9 x8 x7 ? fin ges * byte 3: 0 y9 y8 y7 1 M R L * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 * + * Dualpoint device -- interleaved packet format + * + * byte 0: 1 1 0 0 1 1 1 1 + * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 + * byte 2: 0 x10 x9 x8 x7 0 fin ges + * byte 3: 0 0 YSGN XSGN 1 1 1 1 + * byte 4: X7 X6 X5 X4 X3 X2 X1 X0 + * byte 5: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + * byte 6: 0 y9 y8 y7 1 m r l + * byte 7: 0 y6 y5 y4 y3 y2 y1 y0 + * byte 8: 0 z6 z5 z4 z3 z2 z1 z0 + * + * CAPITALS = stick, miniscules = touchpad + * * ?'s can have different meanings on different models, * such as wheel rotation, extra buttons, stick buttons * on a dualpoint, etc. */ +static bool alps_is_valid_first_byte(const struct alps_model_info *model, + unsigned char data) +{ + return (data & model->mask0) == model->byte0; +} + +static void alps_report_buttons(struct psmouse *psmouse, + struct input_dev *dev1, struct input_dev *dev2, + int left, int right, int middle) +{ + struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; + + if (model->flags & ALPS_PS2_INTERLEAVED) { + struct input_dev *dev; + + /* + * If shared button has already been reported on the + * other device (dev2) then this event should be also + * sent through that device. + */ + dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_LEFT, left); + + dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_RIGHT, right); + + dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1; + input_report_key(dev, BTN_MIDDLE, middle); + + /* + * Sync the _other_ device now, we'll do the first + * device later once we report the rest of the events. + */ + input_sync(dev2); + } else { + /* + * For devices with non-interleaved packets we know what + * device buttons belong to so we can simply report them. + */ + input_report_key(dev1, BTN_LEFT, left); + input_report_key(dev1, BTN_RIGHT, right); + input_report_key(dev1, BTN_MIDDLE, middle); + } +} + static void alps_process_packet(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; @@ -89,18 +162,6 @@ static void alps_process_packet(struct psmouse *psmouse) int x, y, z, ges, fin, left, right, middle; int back = 0, forward = 0; - if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */ - input_report_key(dev2, BTN_LEFT, packet[0] & 1); - input_report_key(dev2, BTN_RIGHT, packet[0] & 2); - input_report_key(dev2, BTN_MIDDLE, packet[0] & 4); - input_report_rel(dev2, REL_X, - packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev2, REL_Y, - packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); - input_sync(dev2); - return; - } - if (priv->i->flags & ALPS_OLDPROTO) { left = packet[2] & 0x10; right = packet[2] & 0x08; @@ -136,18 +197,13 @@ static void alps_process_packet(struct psmouse *psmouse) input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); + alps_report_buttons(psmouse, dev2, dev, left, right, middle); - input_sync(dev); input_sync(dev2); return; } - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - input_report_key(dev, BTN_MIDDLE, middle); + alps_report_buttons(psmouse, dev, dev2, left, right, middle); /* Convert hardware tap to a reasonable Z value */ if (ges && !fin) z = 40; @@ -188,25 +244,168 @@ static void alps_process_packet(struct psmouse *psmouse) input_sync(dev); } +static void alps_report_bare_ps2_packet(struct psmouse *psmouse, + unsigned char packet[], + bool report_buttons) +{ + struct alps_data *priv = psmouse->private; + struct input_dev *dev2 = priv->dev2; + + if (report_buttons) + alps_report_buttons(psmouse, dev2, psmouse->dev, + packet[0] & 1, packet[0] & 2, packet[0] & 4); + + input_report_rel(dev2, REL_X, + packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); + input_report_rel(dev2, REL_Y, + packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); + + input_sync(dev2); +} + +static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) +{ + struct alps_data *priv = psmouse->private; + + if (psmouse->pktcnt < 6) + return PSMOUSE_GOOD_DATA; + + if (psmouse->pktcnt == 6) { + /* + * Start a timer to flush the packet if it ends up last + * 6-byte packet in the stream. Timer needs to fire + * psmouse core times out itself. 20 ms should be enough + * to decide if we are getting more data or not. + */ + mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); + return PSMOUSE_GOOD_DATA; + } + + del_timer(&priv->timer); + + if (psmouse->packet[6] & 0x80) { + + /* + * Highest bit is set - that means we either had + * complete ALPS packet and this is start of the + * next packet or we got garbage. + */ + + if (((psmouse->packet[3] | + psmouse->packet[4] | + psmouse->packet[5]) & 0x80) || + (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) { + dbg("refusing packet %x %x %x %x " + "(suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5], psmouse->packet[6]); + return PSMOUSE_BAD_DATA; + } + + alps_process_packet(psmouse); + + /* Continue with the next packet */ + psmouse->packet[0] = psmouse->packet[6]; + psmouse->pktcnt = 1; + + } else { + + /* + * High bit is 0 - that means that we indeed got a PS/2 + * packet in the middle of ALPS packet. + * + * There is also possibility that we got 6-byte ALPS + * packet followed by 3-byte packet from trackpoint. We + * can not distinguish between these 2 scenarios but + * becase the latter is unlikely to happen in course of + * normal operation (user would need to press all + * buttons on the pad and start moving trackpoint + * without touching the pad surface) we assume former. + * Even if we are wrong the wost thing that would happen + * the cursor would jump but we should not get protocol + * desynchronization. + */ + + alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], + false); + + /* + * Continue with the standard ALPS protocol handling, + * but make sure we won't process it as an interleaved + * packet again, which may happen if all buttons are + * pressed. To avoid this let's reset the 4th bit which + * is normally 1. + */ + psmouse->packet[3] = psmouse->packet[6] & 0xf7; + psmouse->pktcnt = 4; + } + + return PSMOUSE_GOOD_DATA; +} + +static void alps_flush_packet(unsigned long data) +{ + struct psmouse *psmouse = (struct psmouse *)data; + + serio_pause_rx(psmouse->ps2dev.serio); + + if (psmouse->pktcnt == 6) { + + /* + * We did not any more data in reasonable amount of time. + * Validate the last 3 bytes and process as a standard + * ALPS packet. + */ + if ((psmouse->packet[3] | + psmouse->packet[4] | + psmouse->packet[5]) & 0x80) { + dbg("refusing packet %x %x %x " + "(suspected interleaved ps/2)\n", + psmouse->packet[3], psmouse->packet[4], + psmouse->packet[5]); + } else { + alps_process_packet(psmouse); + } + psmouse->pktcnt = 0; + } + + serio_continue_rx(psmouse->ps2dev.serio); +} + static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; + const struct alps_model_info *model = priv->i; if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */ if (psmouse->pktcnt == 3) { - alps_process_packet(psmouse); + alps_report_bare_ps2_packet(psmouse, psmouse->packet, + true); return PSMOUSE_FULL_PACKET; } return PSMOUSE_GOOD_DATA; } - if ((psmouse->packet[0] & priv->i->mask0) != priv->i->byte0) + /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ + + if ((model->flags & ALPS_PS2_INTERLEAVED) && + psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { + return alps_handle_interleaved_ps2(psmouse); + } + + if (!alps_is_valid_first_byte(model, psmouse->packet[0])) { + dbg("refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", + psmouse->packet[0], model->mask0, model->byte0); return PSMOUSE_BAD_DATA; + } /* Bytes 2 - 6 should have 0 in the highest bit */ if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= 6 && - (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) + (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { + dbg("refusing packet[%i] = %x\n", + psmouse->pktcnt - 1, psmouse->packet[psmouse->pktcnt - 1]); return PSMOUSE_BAD_DATA; + } if (psmouse->pktcnt == 6) { alps_process_packet(psmouse); @@ -441,6 +640,7 @@ static void alps_disconnect(struct psmouse *psmouse) struct alps_data *priv = psmouse->private; psmouse_reset(psmouse); + del_timer_sync(&priv->timer); input_unregister_device(priv->dev2); kfree(priv); } @@ -457,6 +657,8 @@ int alps_init(struct psmouse *psmouse) goto init_fail; priv->dev2 = dev2; + setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); + psmouse->private = priv; if (alps_hw_init(psmouse, &version)) diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 4bbddc99962b..4b6024163d3c 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -23,6 +23,7 @@ struct alps_data { char phys[32]; /* Phys */ const struct alps_model_info *i;/* Info */ int prev_fin; /* Finger bit from previous packet */ + struct timer_list timer; }; #ifdef CONFIG_MOUSE_PS2_ALPS diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 19984bf06cad..c65e24510494 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -652,6 +652,16 @@ static const struct dmi_system_id toshiba_dmi_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), }, + + }, + { + .ident = "Toshiba Portege M300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ba9d38c3f412..0f74aeee2aea 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -17,14 +17,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include <linux/hwmon.h> +#include <linux/device.h> #include <linux/init.h> -#include <linux/err.h> #include <linux/delay.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> #include <asm/irq.h> @@ -33,9 +30,7 @@ /* * This code has been heavily tested on a Nokia 770, and lightly * tested on other ads7846 devices (OSK/Mistral, Lubbock). - * TSC2046 is just newer ads7846 silicon. - * Support for ads7843 tested on Atmel at91sam926x-EK. - * Support for ads7845 has only been stubbed in. + * 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 @@ -51,8 +46,7 @@ * files. */ -#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */ -#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */ +#define TS_POLL_PERIOD msecs_to_jiffies(10) /* this driver doesn't aim at the peak continuous sample rate */ #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) @@ -61,77 +55,57 @@ struct ts_event { /* For portability, we can't read 12 bit values using SPI (which * would make the controller deliver them as native byteorder u16 * with msbs zeroed). Instead, we read them as two 8-bit values, - * *** WHICH NEED BYTESWAPPING *** and range adjustment. + * which need byteswapping then range adjustment. */ - u16 x; - u16 y; - u16 z1, z2; - int ignore; -}; - -/* - * We allocate this separately to avoid cache line sharing issues when - * driver is used with DMA-based SPI controllers (like atmel_spi) on - * systems where main memory is not DMA-coherent (most non-x86 boards). - */ -struct ads7846_packet { - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ - struct ts_event tc; + __be16 x; + __be16 y; + __be16 z1, z2; + int ignore; }; struct ads7846 { struct input_dev *input; char phys[32]; - char name[32]; - struct spi_device *spi; - -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) - struct attribute_group *attr_group; - struct device *hwmon; -#endif + u32 *txbuf; + u32 *rxbuf; + u8 buflen; + u8 skip_samples; + u16 rotate; + struct spi_device *spi; u16 model; - u16 vref_mv; u16 vref_delay_usecs; u16 x_plate_ohms; u16 pressure_max; - bool swap_xy; - - struct ads7846_packet *packet; + u8 read_x, read_y, read_z1, read_z2, pwrdown; + u16 zerro; /* to send zerros while receiving */ + u16 dummy; /* for the pwrdown read */ + struct ts_event tc; - struct spi_transfer xfer[18]; + 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; + int skip_this_sample; u16 debounce_max; u16 debounce_tol; u16 debounce_rep; - u16 penirq_recheck_delay_usecs; - spinlock_t lock; - struct hrtimer timer; + struct timer_list timer; /* P: lock */ unsigned pendown:1; /* P: lock */ unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ unsigned disabled:1; - unsigned is_suspended:1; - int (*filter)(void *data, int data_idx, int *val); - void *filter_data; - void (*filter_cleanup)(void *data); int (*get_pendown_state)(void); - int gpio_pendown; - - void (*wait_for_sync)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -141,6 +115,7 @@ struct ads7846 { #define CS_CHANGE(xfer) ((xfer).cs_change = 0) #endif + /*--------------------------------------------------------------------------*/ /* The ADS7846 has touchscreen and other sensors. @@ -167,16 +142,19 @@ struct ads7846 { #define MAX_12BIT ((1<<12)-1) /* leave ADC powered up (disables penirq) between differential samples */ -#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \ - | ADS_12_BIT | ADS_DFR | \ - (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0)) +#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \ + | ADS_12_BIT | ADS_DFR) + +#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_Y(vref) (READ_12BIT_DFR(y, 1, vref)) -#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) -#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) +#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) +#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ -#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) -#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ +/* alternate ads7843 commands */ +#define ALT_READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ALL_ON) +#define ALT_READ_X (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON) /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -184,15 +162,21 @@ struct ads7846 { #define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \ | ADS_12_BIT | ADS_SER) -#define REF_ON (READ_12BIT_DFR(x, 1, 1)) -#define REF_OFF (READ_12BIT_DFR(y, 0, 0)) +#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON) +#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) + +#define MAX_BUF_SAMPLE_LEN (20) +/* Following configuration should be done in the platform configuration */ +#define SCREEN_LANDSCAPE 1 +#undef SCREEN_PORTRAIT +#define MAX_DIFF_BETWEEN_SAMPLES_X 100 +#define MAX_DIFF_BETWEEN_SAMPLES_Y 100 + /*--------------------------------------------------------------------------*/ /* * Non-touchscreen sensors only use single-ended conversions. - * The range is GND..vREF. The ads7843 and ads7835 must use external vREF; - * ads7846 lets that pin be unconnected, to use internal vREF. */ struct ser_req { @@ -200,6 +184,7 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; + u16 zerro; __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; @@ -211,247 +196,132 @@ static void ads7846_disable(struct ads7846 *ts); static int device_suspended(struct device *dev) { struct ads7846 *ts = dev_get_drvdata(dev); - return ts->is_suspended || ts->disabled; + return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; } +static int ads7843_setup_buffers(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + int i; + + ts->txbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL); + if (!ts->txbuf) + return -ENOMEM; + + ts->rxbuf = kzalloc(sizeof(u32) * ts->buflen * 3, GFP_KERNEL); + if (!ts->rxbuf) { + kfree(ts->txbuf); + return -ENOMEM; + } + for (i = 0; i < ((ts->buflen * 3) / 2); i++) +#if defined( SCREEN_LANDSCAPE ) + ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8; +#else + ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8; +#endif + for (; i < ts->buflen * 3; i++) +#if defined( SCREEN_LANDSCAPE ) + ts->txbuf[i] = (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) << 8; +#else + ts->txbuf[i] = (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) << 8; +#endif + return 0; +} + + static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); struct ads7846 *ts = dev_get_drvdata(dev); struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL); int status; - int use_internal; + int sample; + int i; if (!req) return -ENOMEM; spi_message_init(&req->msg); - /* FIXME boards with ads7846 might use external vref instead ... */ - use_internal = (ts->model == 7846); - - /* maybe turn on internal vREF, and let it settle */ - if (use_internal) { - req->ref_on = REF_ON; - req->xfer[0].tx_buf = &req->ref_on; - req->xfer[0].len = 1; - spi_message_add_tail(&req->xfer[0], &req->msg); - - req->xfer[1].rx_buf = &req->scratch; - req->xfer[1].len = 2; - - /* for 1uF, settle for 800 usec; no cap, 100 usec. */ - req->xfer[1].delay_usecs = ts->vref_delay_usecs; - spi_message_add_tail(&req->xfer[1], &req->msg); - } + /* activate reference, so it has time to settle; */ + req->ref_on = REF_ON; + req->xfer[0].tx_buf = &req->ref_on; + req->xfer[0].len = 1; + req->xfer[1].tx_buf = &req->zerro; + req->xfer[1].rx_buf = &req->scratch; + req->xfer[1].len = 2; + + /* + * for external VREF, 0 usec (and assume it's always on); + * for 1uF, use 800 usec; + * no cap, 100 usec. + */ + req->xfer[1].delay_usecs = ts->vref_delay_usecs; /* take sample */ req->command = (u8) command; req->xfer[2].tx_buf = &req->command; req->xfer[2].len = 1; - spi_message_add_tail(&req->xfer[2], &req->msg); - + req->xfer[3].tx_buf = &req->zerro; req->xfer[3].rx_buf = &req->sample; req->xfer[3].len = 2; - spi_message_add_tail(&req->xfer[3], &req->msg); /* REVISIT: take a few more samples, and compare ... */ - /* converter in low power mode & enable PENIRQ */ - req->ref_off = PWRDOWN; + /* turn off reference */ + req->ref_off = REF_OFF; req->xfer[4].tx_buf = &req->ref_off; req->xfer[4].len = 1; - spi_message_add_tail(&req->xfer[4], &req->msg); - + // TODO req->xfer[3].tx_buf = &req->zerro; + req->xfer[5].tx_buf = &req->zerro; req->xfer[5].rx_buf = &req->scratch; req->xfer[5].len = 2; + CS_CHANGE(req->xfer[5]); - spi_message_add_tail(&req->xfer[5], &req->msg); + + /* group all the transfers together, so we can't interfere with + * reading touchscreen state; disable penirq while sampling + */ + for (i = 0; i < 6; i++) + spi_message_add_tail(&req->xfer[i], &req->msg); ts->irq_disabled = 1; - disable_irq(spi->irq); + disable_irq_nosync(spi->irq); status = spi_sync(spi, &req->msg); ts->irq_disabled = 0; enable_irq(spi->irq); - if (status == 0) { - /* on-wire is a must-ignore bit, a BE12 value, then padding */ - status = be16_to_cpu(req->sample); - status = status >> 3; - status &= 0x0fff; - } + 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; kfree(req); - return status; + return status ? status : sample; } -#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE) - -#define SHOW(name, var, adjust) static ssize_t \ +#define SHOW(name) static ssize_t \ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ - struct ads7846 *ts = dev_get_drvdata(dev); \ ssize_t v = ads7846_read12_ser(dev, \ - READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \ + READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \ if (v < 0) \ return v; \ - return sprintf(buf, "%u\n", adjust(ts, v)); \ + return sprintf(buf, "%u\n", (unsigned) v); \ } \ static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL); - -/* Sysfs conventions report temperatures in millidegrees Celsius. - * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high - * accuracy scheme without calibration data. For now we won't try either; - * userspace sees raw sensor values, and must scale/calibrate appropriately. - */ -static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v) -{ - return v; -} - -SHOW(temp0, temp0, null_adjust) /* temp1_input */ -SHOW(temp1, temp1, null_adjust) /* temp2_input */ - - -/* sysfs conventions report voltages in millivolts. We can convert voltages - * if we know vREF. userspace may need to scale vAUX to match the board's - * external resistors; we assume that vBATT only uses the internal ones. - */ -static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v) -{ - unsigned retval = v; - - /* external resistors may scale vAUX into 0..vREF */ - retval *= ts->vref_mv; - retval = retval >> 12; - return retval; -} - -static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v) -{ - unsigned retval = vaux_adjust(ts, v); - - /* ads7846 has a resistor ladder to scale this signal down */ - if (ts->model == 7846) - retval *= 4; - return retval; -} - -SHOW(in0_input, vaux, vaux_adjust) -SHOW(in1_input, vbatt, vbatt_adjust) - - -static struct attribute *ads7846_attributes[] = { - &dev_attr_temp0.attr, - &dev_attr_temp1.attr, - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - NULL, -}; - -static struct attribute_group ads7846_attr_group = { - .attrs = ads7846_attributes, -}; - -static struct attribute *ads7843_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - NULL, -}; - -static struct attribute_group ads7843_attr_group = { - .attrs = ads7843_attributes, -}; - -static struct attribute *ads7845_attributes[] = { - &dev_attr_in0_input.attr, - NULL, -}; - -static struct attribute_group ads7845_attr_group = { - .attrs = ads7845_attributes, -}; - -static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts) -{ - struct device *hwmon; - int err; - - /* hwmon sensors need a reference voltage */ - switch (ts->model) { - case 7846: - if (!ts->vref_mv) { - dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n"); - ts->vref_mv = 2500; - } - break; - case 7845: - case 7843: - if (!ts->vref_mv) { - dev_warn(&spi->dev, - "external vREF for ADS%d not specified\n", - ts->model); - return 0; - } - break; - } - - /* different chips have different sensor groups */ - switch (ts->model) { - case 7846: - ts->attr_group = &ads7846_attr_group; - break; - case 7845: - ts->attr_group = &ads7845_attr_group; - break; - case 7843: - ts->attr_group = &ads7843_attr_group; - break; - default: - dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model); - return 0; - } - - err = sysfs_create_group(&spi->dev.kobj, ts->attr_group); - if (err) - return err; - - hwmon = hwmon_device_register(&spi->dev); - if (IS_ERR(hwmon)) { - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); - return PTR_ERR(hwmon); - } - - ts->hwmon = hwmon; - return 0; -} - -static void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ - if (ts->hwmon) { - sysfs_remove_group(&spi->dev.kobj, ts->attr_group); - hwmon_device_unregister(ts->hwmon); - } -} - -#else -static inline int ads784x_hwmon_register(struct spi_device *spi, - struct ads7846 *ts) -{ - return 0; -} - -static inline void ads784x_hwmon_unregister(struct spi_device *spi, - struct ads7846 *ts) -{ -} -#endif +SHOW(temp0) +SHOW(temp1) +SHOW(vaux) +SHOW(vbatt) static int is_pen_down(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(dev); + struct ads7846 *ts = dev_get_drvdata(dev); return ts->pendown; } @@ -477,11 +347,10 @@ static ssize_t ads7846_disable_store(struct device *dev, const char *buf, size_t count) { struct ads7846 *ts = dev_get_drvdata(dev); - unsigned long i; - - if (strict_strtoul(buf, 10, &i)) - return -EINVAL; + char *endp; + int i; + i = simple_strtoul(buf, &endp, 10); spin_lock_irq(&ts->lock); if (i) @@ -496,30 +365,8 @@ static ssize_t ads7846_disable_store(struct device *dev, static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); -static struct attribute *ads784x_attributes[] = { - &dev_attr_pen_down.attr, - &dev_attr_disable.attr, - NULL, -}; - -static struct attribute_group ads784x_attr_group = { - .attrs = ads784x_attributes, -}; - /*--------------------------------------------------------------------------*/ -static int get_pendown_state(struct ads7846 *ts) -{ - if (ts->get_pendown_state) - return ts->get_pendown_state(); - - return !gpio_get_value(ts->gpio_pendown); -} - -static void null_wait_for_sync(void) -{ -} - /* * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * to retrieve touchscreen status. @@ -531,25 +378,25 @@ static void null_wait_for_sync(void) static void ads7846_rx(void *ads) { struct ads7846 *ts = ads; - struct ads7846_packet *packet = ts->packet; + struct input_dev *input_dev = ts->input; unsigned Rt; + unsigned sync = 0; u16 x, y, z1, z2; + unsigned long flags; - /* ads7846_rx_val() did in-place conversion (including byteswap) from - * on-the-wire format as part of debouncing to get stable readings. + /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; + * built from two 8 bit values written msb-first. */ - x = packet->tc.x; - y = packet->tc.y; - z1 = packet->tc.z1; - z2 = packet->tc.z2; + 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; /* range filtering */ if (x == MAX_12BIT) x = 0; - if (ts->model == 7843) { - Rt = ts->pressure_max / 2; - } else if (likely(x && z1)) { + if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -557,194 +404,281 @@ static void ads7846_rx(void *ads) Rt *= ts->x_plate_ohms; Rt /= z1; Rt = (Rt + 2047) >> 12; - } else { + } 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 (packet->tc.ignore || Rt > ts->pressure_max) { -#ifdef VERBOSE - pr_debug("%s: ignored %d pressure %d\n", - dev_name(&ts->spi->dev), packet->tc.ignore, Rt); -#endif - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + * 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; } - /* Maybe check the pendown state before reporting. This discards - * false readings when the pen is lifted. + /* 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). + * + * REVISIT: some boards may require reading nPENIRQ; it's + * needed on 7843. and 7845 reads pressure differently... + * + * REVISIT: the touchscreen might not be connected; this code + * won't notice that, even if nPENIRQ never fires ... */ - if (ts->penirq_recheck_delay_usecs) { - udelay(ts->penirq_recheck_delay_usecs); - if (!get_pendown_state(ts)) - Rt = 0; + if (!ts->pendown && Rt != 0) { + input_report_key(input_dev, BTN_TOUCH, 1); + sync = 1; + } else if (ts->pendown && Rt == 0) { + input_report_key(input_dev, BTN_TOUCH, 0); + sync = 1; } - /* NOTE: We can't rely on the pressure to determine the pen down - * state, even this controller has a pressure sensor. The pressure - * value can fluctuate for quite a while after lifting the pen and - * in some cases may not even settle at the expected value. - * - * The only safe way to check for the pen up condition is in the - * timer by reading the pen signal state (it's a GPIO _and_ IRQ). - */ if (Rt) { - struct input_dev *input = ts->input; + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + sync = 1; + } - if (!ts->pendown) { - input_report_key(input, BTN_TOUCH, 1); - ts->pendown = 1; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "DOWN\n"); + if (sync) { + input_report_abs(input_dev, ABS_PRESSURE, Rt); + input_sync(input_dev); + } + +#ifdef VERBOSE + if (Rt || ts->pendown) + pr_debug("%s: %d/%d/%d%s\n", dev_name(&ts->spi->dev), + x, y, Rt, Rt ? "" : " UP"); #endif + + 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 inline u16 ad7843_get_sample_val(u32 sample) +{ + return (((((sample & 0x00ff0000) >> 8) | (sample >> 24)) >> 3) & 0x0fff); +} + +static u32 ad7843_get_better_values(struct ads7846 *ts, int index, int skiplimit) +{ + u32 diff12, diff23, diff31; + u32 vals[3]; + int i; + + for (i = 0; i < 3; i++) { + vals[i] = ad7843_get_sample_val(ts->rxbuf[index+i]); + if (vals[i] == 0x0fff || vals[i] == 0) { + ts->skip_this_sample = 1; + return 0; } + } - if (ts->swap_xy) - swap(x, y); + diff12 = (vals[0] > vals[1]) ? vals[0] - vals[1] : vals[1] - vals[0]; + if (diff12 > skiplimit) { + ts->skip_this_sample = 1; + return 0; + } - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_PRESSURE, Rt); + diff23 = (vals[1] > vals[2]) ? vals[1] - vals[2] : vals[2] - vals[1]; + if (diff23 > skiplimit) { + ts->skip_this_sample = 1; + return 0; + } - input_sync(input); -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt); -#endif + diff31 = (vals[2] > vals[0]) ? vals[2] - vals[0] : vals[0] - vals[2]; + if (diff31 > skiplimit) { + ts->skip_this_sample = 1; + return 0; } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_MODE_REL); + if (diff12 < diff23 && diff12 < diff31) + return (vals[0] + vals[1]) / 2; + if (diff23 < diff12 && diff23 < diff31) + return (vals[1] + vals[2]) / 2; + + return (vals[0] + vals[2]) / 2; } -static int ads7846_debounce(void *ads, int data_idx, int *val) +static void ads7843_rx_average(void *ads) +{ + struct ads7846 *ts = ads; + struct input_dev *input_dev = ts->input; + u16 x, y, temp; + unsigned long flags; + int i, sample_count; + + dev_dbg(&ts->spi->dev, "%s\n", __FUNCTION__); + + for (i = 0, y = 0, x = 0, sample_count = 0; i < (ts->buflen * 3 / 2); i+=3) { + if (i >= ts->skip_samples*3) { + temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_Y); + if (!ts->skip_this_sample) { + if (ts->rotate == 180) { + y += MAX_12BIT - temp; + } else if (ts->rotate == 0) { + y += temp; + } else { + dev_info(&ts->spi->dev, + "Rotate mode %d, not implemented yet\n", + ts->rotate); + } + sample_count++; + } + } + ts->skip_this_sample = 0; + } + + if (!sample_count) + goto sample_taken; + + y /= sample_count; + + for (sample_count = 0; i < (ts->buflen * 3); i+=3) { + if (i >= (ts->skip_samples + ts->buflen / 2)*3) { + temp = ad7843_get_better_values(ts, i, MAX_DIFF_BETWEEN_SAMPLES_X); + if (!ts->skip_this_sample) { + if (ts->rotate == 180) { + x += MAX_12BIT - temp; + } else if (ts->rotate == 0) { + x += temp; + } else { + dev_info(&ts->spi->dev, + "Rotate mode %d, not implemented yet\n", + ts->rotate); + } + sample_count++; + } + } + ts->skip_this_sample = 0; + } + + if (!sample_count) + goto sample_taken; + + x /= sample_count; + + if (ts->pendown) { + + input_report_key(input_dev, BTN_TOUCH, 1); + input_report_abs(input_dev, ABS_PRESSURE, ts->pressure_max / 2); + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + } else { + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + } + + input_sync(input_dev); + dev_dbg(&ts->spi->dev, "%d/%d %s\n", x, y, ts->pendown ? "" : " UP"); + +sample_taken: + if (ts->pendown) { + spin_lock_irqsave(&ts->lock, flags); + 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; - if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) { - /* Start over collecting consistent readings. */ - ts->read_rep = 0; + 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->last_read = val; ts->read_cnt++; - return ADS7846_FILTER_REPEAT; } 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; - return ADS7846_FILTER_IGNORE; + /* 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; - return ADS7846_FILTER_OK; - } else { + m++; + } else /* Read more values that are consistent. */ ts->read_cnt++; - return ADS7846_FILTER_REPEAT; - } } -} - -static int ads7846_no_filter(void *ads, int data_idx, int *val) -{ - return ADS7846_FILTER_OK; -} - -static void ads7846_rx_val(void *ads) -{ - struct ads7846 *ts = ads; - struct ads7846_packet *packet = ts->packet; - struct spi_message *m; - struct spi_transfer *t; - int val; - int action; - int status; - - m = &ts->msg[ts->msg_idx]; - t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); - - /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; - * built from two 8 bit values written msb-first. - */ - val = be16_to_cpup((__be16 *)t->rx_buf) >> 3; - - action = ts->filter(ts->filter_data, ts->msg_idx, &val); - switch (action) { - case ADS7846_FILTER_REPEAT: - break; - case ADS7846_FILTER_IGNORE: - packet->tc.ignore = 1; - /* Last message will contain ads7846_rx() as the - * completion function. - */ - m = ts->last_msg; - break; - case ADS7846_FILTER_OK: - *(u16 *)t->rx_buf = val; - packet->tc.ignore = 0; - m = &ts->msg[++ts->msg_idx]; - break; - default: - BUG(); - } - ts->wait_for_sync(); status = spi_async(ts->spi, m); if (status) dev_err(&ts->spi->dev, "spi_async --> %d\n", status); } -static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) +static void ads7846_timer(unsigned long handle) { - struct ads7846 *ts = container_of(handle, struct ads7846, timer); - int status = 0; + struct ads7846 *ts = (void *)handle; + struct input_dev *input_dev = ts->input; + int status = 0; - spin_lock(&ts->lock); - - if (unlikely(!get_pendown_state(ts) || - device_suspended(&ts->spi->dev))) { - if (ts->pendown) { - struct input_dev *input = ts->input; - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); + /* get sample */ + ts->pendown = ts->get_pendown_state(); + spin_lock_irq(&ts->lock); + if (ts->model == 7843) { + ts->pending = 0; + if (unlikely(!ts->pendown)) { - ts->pendown = 0; -#ifdef VERBOSE - dev_dbg(&ts->spi->dev, "UP\n"); -#endif - } + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_sync(input_dev); - /* measurement cycle ended */ - if (!device_suspended(&ts->spi->dev)) { - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); + if (!device_suspended(&ts->spi->dev)) { + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); + } + } else { + /* pen is still down, continue with the measurement */ + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); } - ts->pending = 0; } else { - /* pen is still down, continue with the measurement */ - ts->msg_idx = 0; - ts->wait_for_sync(); - status = spi_async(ts->spi, &ts->msg[0]); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + if (unlikely(ts->msg_idx && !ts->pendown)) { + /* measurement cycle ended */ + if (!device_suspended(&ts->spi->dev)) { + 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(&ts->lock); - return HRTIMER_NORESTART; + spin_unlock_irq(&ts->lock); } static irqreturn_t ads7846_irq(int irq, void *handle) @@ -753,7 +687,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle) unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (likely(get_pendown_state(ts))) { + + if (likely(ts->get_pendown_state())) { if (!ts->irq_disabled) { /* The ARM do_simple_IRQ() dispatcher doesn't act * like the other dispatchers: it will report IRQs @@ -763,8 +698,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) ts->irq_disabled = 1; disable_irq_nosync(ts->spi->irq); ts->pending = 1; - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_MODE_REL); + mod_timer(&ts->timer, jiffies); } } spin_unlock_irqrestore(&ts->lock, flags); @@ -785,7 +719,7 @@ static void ads7846_disable(struct ads7846 *ts) /* are we waiting for IRQ, or polling? */ if (!ts->pending) { ts->irq_disabled = 1; - disable_irq(ts->spi->irq); + disable_irq_nosync(ts->spi->irq); } else { /* the timer will run at least once more, and * leave everything in a clean state, IRQ disabled @@ -800,6 +734,7 @@ static void ads7846_disable(struct ads7846 *ts) /* we know the chip's in lowpower mode since we always * leave it that way after every request */ + } /* Must be called with ts->lock held */ @@ -819,7 +754,7 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message) spin_lock_irq(&ts->lock); - ts->is_suspended = 1; + spi->dev.power.power_state = message; ads7846_disable(ts); spin_unlock_irq(&ts->lock); @@ -834,7 +769,7 @@ static int ads7846_resume(struct spi_device *spi) spin_lock_irq(&ts->lock); - ts->is_suspended = 0; + spi->dev.power.power_state = PMSG_ON; ads7846_enable(ts); spin_unlock_irq(&ts->lock); @@ -842,45 +777,13 @@ static int ads7846_resume(struct spi_device *spi) return 0; } -static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) -{ - struct ads7846_platform_data *pdata = spi->dev.platform_data; - int err; - - /* 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. - */ - if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { - dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); - return -EINVAL; - } - - if (pdata->get_pendown_state) { - ts->get_pendown_state = pdata->get_pendown_state; - return 0; - } - - err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); - if (err) { - dev_err(&spi->dev, "failed to request pendown GPIO%d\n", - pdata->gpio_pendown); - return err; - } - - ts->gpio_pendown = pdata->gpio_pendown; - return 0; -} - static int __devinit ads7846_probe(struct spi_device *spi) { struct ads7846 *ts; - struct ads7846_packet *packet; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; struct spi_message *m; struct spi_transfer *x; - int vref; int err; if (!spi->irq) { @@ -900,33 +803,46 @@ 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. + */ + 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; - spi->mode = SPI_MODE_0; - err = spi_setup(spi); - if (err < 0) - return err; ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); - packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL); input_dev = input_allocate_device(); - if (!ts || !packet || !input_dev) { + if (!ts || !input_dev) { err = -ENOMEM; goto err_free_mem; } dev_set_drvdata(&spi->dev, ts); - ts->packet = packet; + spi->dev.power.power_state = PMSG_ON; + ts->spi = spi; ts->input = input_dev; - ts->vref_mv = pdata->vref_mv; - ts->swap_xy = pdata->swap_xy; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->buflen = pdata->buflen ? : MAX_BUF_SAMPLE_LEN; + ts->buflen = ts->buflen & ~0x1; /* must be even */ + + if (ads7843_setup_buffers(&spi->dev)) { + dev_dbg(&spi->dev, "error allocating memory for sample buffers\n"); + err = -ENOMEM; + goto err_free_mem; + } + + init_timer(&ts->timer); + ts->timer.data = (unsigned long) ts; ts->timer.function = ads7846_timer; spin_lock_init(&ts->lock); @@ -935,40 +851,22 @@ static int __devinit ads7846_probe(struct spi_device *spi) 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; + ts->skip_samples = pdata->skip_samples ? : 0; + ts->rotate = pdata->rotate ? : 0; - if (pdata->filter != NULL) { - if (pdata->filter_init != NULL) { - err = pdata->filter_init(pdata, &ts->filter_data); - if (err < 0) - goto err_free_mem; - } - ts->filter = pdata->filter; - ts->filter_cleanup = pdata->filter_cleanup; - } else if (pdata->debounce_max) { + if (pdata->debounce_max) { ts->debounce_max = pdata->debounce_max; - if (ts->debounce_max < 2) - ts->debounce_max = 2; ts->debounce_tol = pdata->debounce_tol; ts->debounce_rep = pdata->debounce_rep; - ts->filter = ads7846_debounce; - ts->filter_data = ts; + if (ts->debounce_rep > ts->debounce_max + 1) + ts->debounce_rep = ts->debounce_max - 1; } else - ts->filter = ads7846_no_filter; - - err = setup_pendown(spi, ts); - if (err) - goto err_cleanup_filter; - - if (pdata->penirq_recheck_delay_usecs) - ts->penirq_recheck_delay_usecs = - pdata->penirq_recheck_delay_usecs; - - ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; + ts->debounce_tol = ~0; + ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); - snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); - input_dev->name = ts->name; + input_dev->name = "ADS784x Touchscreen"; input_dev->phys = ts->phys; input_dev->dev.parent = &spi->dev; @@ -983,9 +881,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) pdata->y_max ? : MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_PRESSURE, - pdata->pressure_min, pdata->pressure_max, 0, 0); - - vref = pdata->keep_vref_on; + pdata->pressure_min ? : 0, + pdata->pressure_max ? : 1, 0, 0); /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. @@ -995,209 +892,176 @@ static int __devinit ads7846_probe(struct spi_device *spi) spi_message_init(m); - /* y- still on; turn on only y+ (and ADC) */ - packet->read_y = READ_Y(vref); - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - - /* the first sample after switching drivers can be low quality; - * optionally discard it, using a second one after the signals - * have had enough time to stabilize. - */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; - - x++; - x->tx_buf = &packet->read_y; - x->len = 1; + if (ts->model == 7843) { + x->tx_buf = ts->txbuf; + x->rx_buf = ts->rxbuf; + x->len = ts->buflen * sizeof(u32) * 3; /* For every sample we take 3 samples and choose the better 2 */ spi_message_add_tail(x, m); - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - } - - m->complete = ads7846_rx_val; - m->context = ts; - - m++; - spi_message_init(m); - - /* turn y- off, x+ on, then leave in lowpower */ - x++; - packet->read_x = READ_X(vref); - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.x; - x->len = 2; - spi_message_add_tail(x, m); - - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m->complete = ads7843_rx_average; + m->context = ts; - x++; - x->tx_buf = &packet->read_x; + ts->last_msg = m; + } else { + /* 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); x++; - x->rx_buf = &packet->tc.x; + x->rx_buf = &ts->tc.y; x->len = 2; spi_message_add_tail(x, m); - } - m->complete = ads7846_rx_val; - m->context = ts; + m->complete = ads7846_debounce; + m->context = ts; - /* turn y+ off, x- on; we'll use formula #2 */ - if (ts->model == 7846) { m++; spi_message_init(m); + /* turn y- off, x+ on, then leave in lowpower */ x++; - packet->read_z1 = READ_Z1(vref); - x->tx_buf = &packet->read_z1; + ts->read_x = READ_X; + x->tx_buf = &ts->read_x; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z1; + x->rx_buf = &ts->tc.x; x->len = 2; spi_message_add_tail(x, m); - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m->complete = ads7846_debounce; + m->context = ts; + + /* turn y+ off, x- on; we'll use formula #2 */ + if (ts->model == 7846) { + m++; + spi_message_init(m); x++; - x->tx_buf = &packet->read_z1; + ts->read_z1 = READ_Z1; + x->tx_buf = &ts->read_z1; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z1; + x->rx_buf = &ts->tc.z1; x->len = 2; spi_message_add_tail(x, m); - } - - m->complete = ads7846_rx_val; - m->context = ts; - - m++; - spi_message_init(m); - x++; - packet->read_z2 = READ_Z2(vref); - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.z2; - x->len = 2; - spi_message_add_tail(x, m); + m->complete = ads7846_debounce; + m->context = ts; - /* ... maybe discard first sample ... */ - if (pdata->settle_delay_usecs) { - x->delay_usecs = pdata->settle_delay_usecs; + m++; + spi_message_init(m); x++; - x->tx_buf = &packet->read_z2; + ts->read_z2 = READ_Z2; + x->tx_buf = &ts->read_z2; x->len = 1; spi_message_add_tail(x, m); x++; - x->rx_buf = &packet->tc.z2; + x->rx_buf = &ts->tc.z2; x->len = 2; spi_message_add_tail(x, m); - } - m->complete = ads7846_rx_val; - m->context = ts; - } + m->complete = ads7846_debounce; + m->context = ts; + } - /* power down */ - m++; - spi_message_init(m); + /* power down */ + m++; + spi_message_init(m); - x++; - packet->pwrdown = PWRDOWN; - x->tx_buf = &packet->pwrdown; - x->len = 1; - spi_message_add_tail(x, m); + x++; + ts->pwrdown = PWRDOWN; + x->tx_buf = &ts->pwrdown; + x->len = 1; + spi_message_add_tail(x, m); - x++; - x->rx_buf = &packet->dummy; - x->len = 2; - CS_CHANGE(*x); - spi_message_add_tail(x, m); + x++; + x->rx_buf = &ts->dummy; + x->len = 2; + CS_CHANGE(*x); + spi_message_add_tail(x, m); - m->complete = ads7846_rx; - m->context = ts; + m->complete = ads7846_rx; + m->context = ts; - ts->last_msg = m; + ts->last_msg = m; + } if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts)) { - dev_info(&spi->dev, - "trying pin change workaround on irq %d\n", spi->irq); - err = request_irq(spi->irq, ads7846_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - spi->dev.driver->name, ts); - if (err) { - dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); - goto err_free_gpio; - } + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + err = -EBUSY; + goto err_free_buf; } - err = ads784x_hwmon_register(spi, ts); - if (err) - goto err_free_irq; - dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); - /* take a first sample, leaving nPENIRQ active and vREF off; avoid + /* take a first sample, leaving nPENIRQ active; avoid * the touchscreen, in case it's not connected. */ - (void) ads7846_read12_ser(&spi->dev, - READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); + if (ts->model != 7843) { + /* take a first sample, leaving nPENIRQ active; avoid + * the touchscreen, in case it's not connected. + */ + (void) ads7846_read12_ser(&spi->dev, + READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON); + } - err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group); - if (err) - goto err_remove_hwmon; + /* ads7843/7845 don't have temperature sensors, and + * use the other sensors a bit differently too + */ + if (ts->model == 7846) { + device_create_file(&spi->dev, &dev_attr_temp0); + device_create_file(&spi->dev, &dev_attr_temp1); + } + + if (ts->model != 7845 && ts->model != 7843) + device_create_file(&spi->dev, &dev_attr_vbatt); + + if (ts->model != 7843) { + 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_group; + goto err_remove_attr; return 0; - err_remove_attr_group: - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); - err_remove_hwmon: - ads784x_hwmon_unregister(spi, ts); - err_free_irq: + 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 && ts->model != 7843) + device_remove_file(&spi->dev, &dev_attr_vbatt); + + if (ts->model != 7843) { + device_remove_file(&spi->dev, &dev_attr_vaux); + } + free_irq(spi->irq, ts); - err_free_gpio: - if (ts->gpio_pendown != -1) - gpio_free(ts->gpio_pendown); - err_cleanup_filter: - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); + + err_free_buf: + if (ts->txbuf) + kfree(ts->txbuf); + if (ts->rxbuf) + kfree(ts->rxbuf); err_free_mem: input_free_device(input_dev); - kfree(packet); kfree(ts); return err; } @@ -1206,24 +1070,33 @@ static int __devexit ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - ads784x_hwmon_unregister(spi, ts); input_unregister_device(ts->input); ads7846_suspend(spi, PMSG_SUSPEND); - sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group); + if (ts->txbuf) + kfree(ts->txbuf); + if (ts->rxbuf) + kfree(ts->rxbuf); - free_irq(ts->spi->irq, ts); - /* suspend left the 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); + } + + if (ts->model != 7845 && ts->model != 7843) + device_remove_file(&spi->dev, &dev_attr_vbatt); - if (ts->gpio_pendown != -1) - gpio_free(ts->gpio_pendown); + if (ts->model != 7843) { + device_remove_file(&spi->dev, &dev_attr_vaux); + } - if (ts->filter_cleanup) - ts->filter_cleanup(ts->filter_data); + free_irq(ts->spi->irq, ts); + /* suspend left the IRQ disabled */ + disable_irq_nosync(ts->spi->irq); - kfree(ts->packet); kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); diff --git a/drivers/input/touchscreen/mxc_ts.c b/drivers/input/touchscreen/mxc_ts.c index 610f31e65778..6146b27f01da 100644 --- a/drivers/input/touchscreen/mxc_ts.c +++ b/drivers/input/touchscreen/mxc_ts.c @@ -76,8 +76,7 @@ static int ts_thread(void *arg) msleep(20); continue; } - if (!(ts_sample.contact_resistance || wait)) - { + if (!(ts_sample.contact_resistance || wait)) { msleep(20); continue; } |