From ced918eb748ce30b3aace549fd17540e40ffdca0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 17 Feb 2010 16:47:10 +0000 Subject: i8253: Convert i8253_lock to raw_spinlock i8253_lock needs to be a real spinlock in preempt-rt, i.e. it can not be converted to a sleeping lock. Convert it to raw_spinlock and fix up all users. Signed-off-by: Thomas Gleixner Acked-by: Ralf Baechle Acked-by: Dmitry Torokhov Acked-by: Takashi Iwai Cc: Jens Axboe LKML-Reference: <20100217163751.030764372@linutronix.de> --- drivers/input/misc/pcspkr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index ea4e1fd12651..f080dd31499b 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -30,7 +30,7 @@ MODULE_ALIAS("platform:pcspkr"); #include #else #include -static DEFINE_SPINLOCK(i8253_lock); +static DEFINE_RAW_SPINLOCK(i8253_lock); #endif static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -50,7 +50,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c if (value > 20 && value < 32767) count = PIT_TICK_RATE / value; - spin_lock_irqsave(&i8253_lock, flags); + raw_spin_lock_irqsave(&i8253_lock, flags); if (count) { /* set command for counter 2, 2 byte write */ @@ -65,7 +65,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c outb(inb_p(0x61) & 0xFC, 0x61); } - spin_unlock_irqrestore(&i8253_lock, flags); + raw_spin_unlock_irqrestore(&i8253_lock, flags); return 0; } -- cgit v1.2.1 From b91c4be730668e801aa6a2ea95f467cd9a1e0983 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Fri, 19 Mar 2010 22:18:15 -0700 Subject: Input: add PCF8574 I2C keypad input device driver Signed-off-by: Bryan Wu Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/pcf8574_keypad.c | 227 ++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 drivers/input/misc/pcf8574_keypad.c (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23140a3bb8e0..54a9c2d0ba1c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -277,6 +277,16 @@ config INPUT_PCF50633_PMU Say Y to include support for delivering PMU events via input layer on NXP PCF50633. +config INPUT_PCF8574 + tristate "PCF8574 Keypad input device" + depends on I2C && EXPERIMENTAL + help + Say Y here if you want to support a keypad connetced via I2C + with a PCF8574. + + To compile this driver as a module, choose M here: the + module will be called pcf8574_keypad. + config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" depends on GPIOLIB && GENERIC_GPIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 7e95a5d474dc..a662df21bf57 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o +obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c new file mode 100644 index 000000000000..5c3ac4e0b055 --- /dev/null +++ b/drivers/input/misc/pcf8574_keypad.c @@ -0,0 +1,227 @@ +/* + * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander + * + * Copyright 2005-2008 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pcf8574_keypad" + +static const unsigned char pcf8574_kp_btncode[] = { + [0] = KEY_RESERVED, + [1] = KEY_ENTER, + [2] = KEY_BACKSLASH, + [3] = KEY_0, + [4] = KEY_RIGHTBRACE, + [5] = KEY_C, + [6] = KEY_9, + [7] = KEY_8, + [8] = KEY_7, + [9] = KEY_B, + [10] = KEY_6, + [11] = KEY_5, + [12] = KEY_4, + [13] = KEY_A, + [14] = KEY_3, + [15] = KEY_2, + [16] = KEY_1 +}; + +struct kp_data { + unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)]; + struct input_dev *idev; + struct i2c_client *client; + char name[64]; + char phys[32]; + unsigned char laststate; +}; + +static short read_state(struct kp_data *lp) +{ + unsigned char x, y, a, b; + + i2c_smbus_write_byte(lp->client, 240); + x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4)); + + i2c_smbus_write_byte(lp->client, 15); + y = 0xF & (~i2c_smbus_read_byte(lp->client)); + + for (a = 0; x > 0; a++) + x = x >> 1; + for (b = 0; y > 0; b++) + y = y >> 1; + + return ((a - 1) * 4) + b; +} + +static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id) +{ + struct kp_data *lp = dev_id; + unsigned char nextstate = read_state(lp); + + if (lp->laststate != nextstate) { + int key_down = nextstate <= ARRAY_SIZE(lp->btncode); + unsigned short keycode = key_down ? + lp->btncode[nextstate] : lp->btncode[lp->laststate]; + + input_report_key(lp->idev, keycode, key_down); + input_sync(lp->idev); + + lp->laststate = nextstate; + } + + return IRQ_HANDLED; +} + +static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int i, ret; + struct input_dev *idev; + struct kp_data *lp; + + if (i2c_smbus_write_byte(client, 240) < 0) { + dev_err(&client->dev, "probe: write fail\n"); + return -ENODEV; + } + + lp = kzalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + idev = input_allocate_device(); + if (!idev) { + dev_err(&client->dev, "Can't allocate input device\n"); + ret = -ENOMEM; + goto fail_allocate; + } + + lp->idev = idev; + lp->client = client; + + idev->evbit[0] = BIT_MASK(EV_KEY); + idev->keycode = lp->btncode; + idev->keycodesize = sizeof(lp->btncode[0]); + idev->keycodemax = ARRAY_SIZE(lp->btncode); + + for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { + lp->btncode[i] = pcf8574_kp_btncode[i]; + __set_bit(lp->btncode[i] & KEY_MAX, idev->keybit); + } + + sprintf(lp->name, DRV_NAME); + sprintf(lp->phys, "kp_data/input0"); + + idev->name = lp->name; + idev->phys = lp->phys; + idev->id.bustype = BUS_I2C; + idev->id.vendor = 0x0001; + idev->id.product = 0x0001; + idev->id.version = 0x0100; + + input_set_drvdata(idev, lp); + + ret = input_register_device(idev); + if (ret) { + dev_err(&client->dev, "input_register_device() failed\n"); + goto fail_register; + } + + lp->laststate = read_state(lp); + + ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + DRV_NAME, lp); + if (ret) { + dev_err(&client->dev, "IRQ %d is not free\n", client->irq); + goto fail_irq; + } + + i2c_set_clientdata(client, lp); + return 0; + + fail_irq: + input_unregister_device(idev); + fail_register: + input_set_drvdata(idev, NULL); + input_free_device(idev); + fail_allocate: + kfree(lp); + + return ret; +} + +static int __devexit pcf8574_kp_remove(struct i2c_client *client) +{ + struct kp_data *lp = i2c_get_clientdata(client); + + free_irq(client->irq, lp); + + input_unregister_device(lp->idev); + kfree(lp); + + i2c_set_clientdata(client, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int pcf8574_kp_resume(struct i2c_client *client) +{ + enable_irq(client->irq); + + return 0; +} + +static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg) +{ + disable_irq(client->irq); + + return 0; +} +#else +# define pcf8574_kp_resume NULL +# define pcf8574_kp_suspend NULL +#endif + +static const struct i2c_device_id pcf8574_kp_id[] = { + { DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); + +static struct i2c_driver pcf8574_kp_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = pcf8574_kp_probe, + .remove = __devexit_p(pcf8574_kp_remove), + .suspend = pcf8574_kp_suspend, + .resume = pcf8574_kp_resume, + .id_table = pcf8574_kp_id, +}; + +static int __init pcf8574_kp_init(void) +{ + return i2c_add_driver(&pcf8574_kp_driver); +} +module_init(pcf8574_kp_init); + +static void __exit pcf8574_kp_exit(void) +{ + i2c_del_driver(&pcf8574_kp_driver); +} +module_exit(pcf8574_kp_exit); + +MODULE_AUTHOR("Michael Hennerich"); +MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574"); +MODULE_LICENSE("GPL"); -- cgit v1.2.1 From 31a6296333b94964e9a073649840bb34d4603369 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Sun, 21 Mar 2010 23:23:24 -0700 Subject: Input: add Analog Devices AD714x captouch input driver AD7142 and AD7147 are integrated capacitance-to-digital converters (CDCs) with on-chip environmental calibration for use in systems requiring a novel user input method. The AD7142 and AD7147 can interface to external capacitance sensors implementing functions such as buttons, scrollwheels, sliders, touchpads and so on. The chips don't restrict the specific usage. Depending on the hardware connection, one special target board can include one or several these components. The platform_data for the device's "struct device" holds these information. The data-struct defined in head file descript the hardware feature of button/scrollwheel/slider/touchpad components on target boards, which need be filled in the arch/mach-/. As the result, the driver is independent of boards. It gets the components layout from the platform_data, registers related devices, fullfills the algorithms and state machines for these components and report related input events to up level. Signed-off-by: Bryan Wu Signed-off-by: Michael Hennerich Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 30 + drivers/input/misc/Makefile | 3 + drivers/input/misc/ad714x-i2c.c | 137 ++++ drivers/input/misc/ad714x-spi.c | 103 +++ drivers/input/misc/ad714x.c | 1331 +++++++++++++++++++++++++++++++++++++++ drivers/input/misc/ad714x.h | 26 + 6 files changed, 1630 insertions(+) create mode 100644 drivers/input/misc/ad714x-i2c.c create mode 100644 drivers/input/misc/ad714x-spi.c create mode 100644 drivers/input/misc/ad714x.c create mode 100644 drivers/input/misc/ad714x.h (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 54a9c2d0ba1c..a4b9dc5cf456 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY To compile this driver as a module, choose M here: the module will be called 88pm860x_onkey. +config INPUT_AD714X + tristate "Analog Devices AD714x Capacitance Touch Sensor" + help + Say Y here if you want to support an AD7142/AD7147 touch sensor. + + You should select a bus connection too. + + To compile this driver as a module, choose M here: the + module will be called ad714x. + +config INPUT_AD714X_I2C + tristate "support I2C bus connection" + depends on INPUT_AD714X && I2C + default y + help + Say Y here if you have AD7142/AD7147 hooked to an I2C bus. + + To compile this driver as a module, choose M here: the + module will be called ad714x-i2c. + +config INPUT_AD714X_SPI + tristate "support SPI bus connection" + depends on INPUT_AD714X && SPI + default y + help + Say Y here if you have AD7142/AD7147 hooked to a SPI bus. + + To compile this driver as a module, choose M here: the + module will be called ad714x-spi. + config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a662df21bf57..f9f577031e06 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -5,6 +5,9 @@ # Each configuration option enables a list of files. obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o +obj-$(CONFIG_INPUT_AD714X) += ad714x.o +obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o +obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c new file mode 100644 index 000000000000..a2cb6b426dc7 --- /dev/null +++ b/drivers/input/misc/ad714x-i2c.c @@ -0,0 +1,137 @@ +/* + * AD714X CapTouch Programmable Controller driver (I2C bus) + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include /* BUS_I2C */ +#include +#include +#include +#include "ad714x.h" + +#ifdef CONFIG_PM +static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message) +{ + return ad714x_disable(i2c_get_clientdata(client)); +} + +static int ad714x_i2c_resume(struct i2c_client *client) +{ + return ad714x_enable(i2c_get_clientdata(client)); +} +#else +# define ad714x_i2c_suspend NULL +# define ad714x_i2c_resume NULL +#endif + +static int ad714x_i2c_write(struct device *dev, unsigned short reg, + unsigned short data) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret = 0; + u8 *_reg = (u8 *)® + u8 *_data = (u8 *)&data; + + u8 tx[4] = { + _reg[1], + _reg[0], + _data[1], + _data[0] + }; + + ret = i2c_master_send(client, tx, 4); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad714x_i2c_read(struct device *dev, unsigned short reg, + unsigned short *data) +{ + struct i2c_client *client = to_i2c_client(dev); + int ret = 0; + u8 *_reg = (u8 *)® + u8 *_data = (u8 *)data; + + u8 tx[2] = { + _reg[1], + _reg[0] + }; + u8 rx[2]; + + ret = i2c_master_send(client, tx, 2); + if (ret >= 0) + ret = i2c_master_recv(client, rx, 2); + + if (unlikely(ret < 0)) { + dev_err(&client->dev, "I2C read error\n"); + } else { + _data[0] = rx[1]; + _data[1] = rx[0]; + } + + return ret; +} + +static int __devinit ad714x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ad714x_chip *chip; + + chip = ad714x_probe(&client->dev, BUS_I2C, client->irq, + ad714x_i2c_read, ad714x_i2c_write); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + i2c_set_clientdata(client, chip); + + return 0; +} + +static int __devexit ad714x_i2c_remove(struct i2c_client *client) +{ + struct ad714x_chip *chip = i2c_get_clientdata(client); + + ad714x_remove(chip); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id ad714x_id[] = { + { "ad7142_captouch", 0 }, + { "ad7147_captouch", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ad714x_id); + +static struct i2c_driver ad714x_i2c_driver = { + .driver = { + .name = "ad714x_captouch", + }, + .probe = ad714x_i2c_probe, + .remove = __devexit_p(ad714x_i2c_remove), + .suspend = ad714x_i2c_suspend, + .resume = ad714x_i2c_resume, + .id_table = ad714x_id, +}; + +static __init int ad714x_i2c_init(void) +{ + return i2c_add_driver(&ad714x_i2c_driver); +} +module_init(ad714x_i2c_init); + +static __exit void ad714x_i2c_exit(void) +{ + i2c_del_driver(&ad714x_i2c_driver); +} +module_exit(ad714x_i2c_exit); + +MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c new file mode 100644 index 000000000000..7f8dedfd1bfe --- /dev/null +++ b/drivers/input/misc/ad714x-spi.c @@ -0,0 +1,103 @@ +/* + * AD714X CapTouch Programmable Controller driver (SPI bus) + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include /* BUS_I2C */ +#include +#include +#include +#include "ad714x.h" + +#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */ +#define AD714x_SPI_READ BIT(10) + +#ifdef CONFIG_PM +static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message) +{ + return ad714x_disable(spi_get_drvdata(spi)); +} + +static int ad714x_spi_resume(struct spi_device *spi) +{ + return ad714x_enable(spi_get_drvdata(spi)); +} +#else +# define ad714x_spi_suspend NULL +# define ad714x_spi_resume NULL +#endif + +static int ad714x_spi_read(struct device *dev, unsigned short reg, + unsigned short *data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg; + + return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2); +} + +static int ad714x_spi_write(struct device *dev, unsigned short reg, + unsigned short data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned short tx[2] = { + AD714x_SPI_CMD_PREFIX | reg, + data + }; + + return spi_write(spi, (u8 *)tx, 4); +} + +static int __devinit ad714x_spi_probe(struct spi_device *spi) +{ + struct ad714x_chip *chip; + + chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq, + ad714x_spi_read, ad714x_spi_write); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + spi_set_drvdata(spi, chip); + + return 0; +} + +static int __devexit ad714x_spi_remove(struct spi_device *spi) +{ + struct ad714x_chip *chip = spi_get_drvdata(spi); + + ad714x_remove(chip); + spi_set_drvdata(spi, NULL); + + return 0; +} + +static struct spi_driver ad714x_spi_driver = { + .driver = { + .name = "ad714x_captouch", + .owner = THIS_MODULE, + }, + .probe = ad714x_spi_probe, + .remove = __devexit_p(ad714x_spi_remove), + .suspend = ad714x_spi_suspend, + .resume = ad714x_spi_resume, +}; + +static __init int ad714x_spi_init(void) +{ + return spi_register_driver(&ad714x_spi_driver); +} +module_init(ad714x_spi_init); + +static __exit void ad714x_spi_exit(void) +{ + spi_unregister_driver(&ad714x_spi_driver); +} +module_exit(ad714x_spi_exit); + +MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c new file mode 100644 index 000000000000..691b1d37331f --- /dev/null +++ b/drivers/input/misc/ad714x.c @@ -0,0 +1,1331 @@ +/* + * AD714X CapTouch Programmable Controller driver + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include "ad714x.h" + +#define AD714X_PWR_CTRL 0x0 +#define AD714X_STG_CAL_EN_REG 0x1 +#define AD714X_AMB_COMP_CTRL0_REG 0x2 +#define AD714X_PARTID_REG 0x17 +#define AD7147_PARTID 0x1470 +#define AD7142_PARTID 0xE620 +#define AD714X_STAGECFG_REG 0x80 +#define AD714X_SYSCFG_REG 0x0 + +#define STG_LOW_INT_EN_REG 0x5 +#define STG_HIGH_INT_EN_REG 0x6 +#define STG_COM_INT_EN_REG 0x7 +#define STG_LOW_INT_STA_REG 0x8 +#define STG_HIGH_INT_STA_REG 0x9 +#define STG_COM_INT_STA_REG 0xA + +#define CDC_RESULT_S0 0xB +#define CDC_RESULT_S1 0xC +#define CDC_RESULT_S2 0xD +#define CDC_RESULT_S3 0xE +#define CDC_RESULT_S4 0xF +#define CDC_RESULT_S5 0x10 +#define CDC_RESULT_S6 0x11 +#define CDC_RESULT_S7 0x12 +#define CDC_RESULT_S8 0x13 +#define CDC_RESULT_S9 0x14 +#define CDC_RESULT_S10 0x15 +#define CDC_RESULT_S11 0x16 + +#define STAGE0_AMBIENT 0xF1 +#define STAGE1_AMBIENT 0x115 +#define STAGE2_AMBIENT 0x139 +#define STAGE3_AMBIENT 0x15D +#define STAGE4_AMBIENT 0x181 +#define STAGE5_AMBIENT 0x1A5 +#define STAGE6_AMBIENT 0x1C9 +#define STAGE7_AMBIENT 0x1ED +#define STAGE8_AMBIENT 0x211 +#define STAGE9_AMBIENT 0x234 +#define STAGE10_AMBIENT 0x259 +#define STAGE11_AMBIENT 0x27D + +#define PER_STAGE_REG_NUM 36 +#define STAGE_NUM 12 +#define STAGE_CFGREG_NUM 8 +#define SYS_CFGREG_NUM 8 + +/* + * driver information which will be used to maintain the software flow + */ +enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE }; + +struct ad714x_slider_drv { + int highest_stage; + int abs_pos; + int flt_pos; + enum ad714x_device_state state; + struct input_dev *input; +}; + +struct ad714x_wheel_drv { + int abs_pos; + int flt_pos; + int pre_mean_value; + int pre_highest_stage; + int pre_mean_value_no_offset; + int mean_value; + int mean_value_no_offset; + int pos_offset; + int pos_ratio; + int highest_stage; + enum ad714x_device_state state; + struct input_dev *input; +}; + +struct ad714x_touchpad_drv { + int x_highest_stage; + int x_flt_pos; + int x_abs_pos; + int y_highest_stage; + int y_flt_pos; + int y_abs_pos; + int left_ep; + int left_ep_val; + int right_ep; + int right_ep_val; + int top_ep; + int top_ep_val; + int bottom_ep; + int bottom_ep_val; + enum ad714x_device_state state; + struct input_dev *input; +}; + +struct ad714x_button_drv { + enum ad714x_device_state state; + /* + * Unlike slider/wheel/touchpad, all buttons point to + * same input_dev instance + */ + struct input_dev *input; +}; + +struct ad714x_driver_data { + struct ad714x_slider_drv *slider; + struct ad714x_wheel_drv *wheel; + struct ad714x_touchpad_drv *touchpad; + struct ad714x_button_drv *button; +}; + +/* + * information to integrate all things which will be private data + * of spi/i2c device + */ +struct ad714x_chip { + unsigned short h_state; + unsigned short l_state; + unsigned short c_state; + unsigned short adc_reg[STAGE_NUM]; + unsigned short amb_reg[STAGE_NUM]; + unsigned short sensor_val[STAGE_NUM]; + + struct ad714x_platform_data *hw; + struct ad714x_driver_data *sw; + + int irq; + struct device *dev; + ad714x_read_t read; + ad714x_write_t write; + + struct mutex mutex; + + unsigned product; + unsigned version; +}; + +static void ad714x_use_com_int(struct ad714x_chip *ad714x, + int start_stage, int end_stage) +{ + unsigned short data; + unsigned short mask; + + mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); + + ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); + data |= 1 << start_stage; + ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); + + ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); + data &= ~mask; + ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); +} + +static void ad714x_use_thr_int(struct ad714x_chip *ad714x, + int start_stage, int end_stage) +{ + unsigned short data; + unsigned short mask; + + mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); + + ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); + data &= ~(1 << start_stage); + ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); + + ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); + data |= mask; + ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); +} + +static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x, + int start_stage, int end_stage) +{ + int max_res = 0; + int max_idx = 0; + int i; + + for (i = start_stage; i <= end_stage; i++) { + if (ad714x->sensor_val[i] > max_res) { + max_res = ad714x->sensor_val[i]; + max_idx = i; + } + } + + return max_idx; +} + +static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x, + int start_stage, int end_stage, + int highest_stage, int max_coord) +{ + int a_param, b_param; + + if (highest_stage == start_stage) { + a_param = ad714x->sensor_val[start_stage + 1]; + b_param = ad714x->sensor_val[start_stage] + + ad714x->sensor_val[start_stage + 1]; + } else if (highest_stage == end_stage) { + a_param = ad714x->sensor_val[end_stage] * + (end_stage - start_stage) + + ad714x->sensor_val[end_stage - 1] * + (end_stage - start_stage - 1); + b_param = ad714x->sensor_val[end_stage] + + ad714x->sensor_val[end_stage - 1]; + } else { + a_param = ad714x->sensor_val[highest_stage] * + (highest_stage - start_stage) + + ad714x->sensor_val[highest_stage - 1] * + (highest_stage - start_stage - 1) + + ad714x->sensor_val[highest_stage + 1] * + (highest_stage - start_stage + 1); + b_param = ad714x->sensor_val[highest_stage] + + ad714x->sensor_val[highest_stage - 1] + + ad714x->sensor_val[highest_stage + 1]; + } + + return (max_coord / (end_stage - start_stage)) * a_param / b_param; +} + +/* + * One button can connect to multi positive and negative of CDCs + * Multi-buttons can connect to same positive/negative of one CDC + */ +static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_button_plat *hw = &ad714x->hw->button[idx]; + struct ad714x_button_drv *sw = &ad714x->sw->button[idx]; + + switch (sw->state) { + case IDLE: + if (((ad714x->h_state & hw->h_mask) == hw->h_mask) && + ((ad714x->l_state & hw->l_mask) == hw->l_mask)) { + dev_dbg(ad714x->dev, "button %d touched\n", idx); + input_report_key(sw->input, hw->keycode, 1); + input_sync(sw->input); + sw->state = ACTIVE; + } + break; + + case ACTIVE: + if (((ad714x->h_state & hw->h_mask) != hw->h_mask) || + ((ad714x->l_state & hw->l_mask) != hw->l_mask)) { + dev_dbg(ad714x->dev, "button %d released\n", idx); + input_report_key(sw->input, hw->keycode, 0); + input_sync(sw->input); + sw->state = IDLE; + } + break; + + default: + break; + } +} + +/* + * The response of a sensor is defined by the absolute number of codes + * between the current CDC value and the ambient value. + */ +static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + int i; + + for (i = hw->start_stage; i <= hw->end_stage; i++) { + ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, + &ad714x->adc_reg[i]); + ad714x->read(ad714x->dev, + STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, + &ad714x->amb_reg[i]); + + ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] - + ad714x->amb_reg[i]); + } +} + +static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; + + sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, + hw->end_stage); + + dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx, + sw->highest_stage); +} + +/* + * The formulae are very straight forward. It uses the sensor with the + * highest response and the 2 adjacent ones. + * When Sensor 0 has the highest response, only sensor 0 and sensor 1 + * are used in the calculations. Similarly when the last sensor has the + * highest response, only the last sensor and the second last sensors + * are used in the calculations. + * + * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1 + * v += Sensor response(i)*i + * w += Sensor response(i) + * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w) + */ +static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; + + sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage, + sw->highest_stage, hw->max_coord); + + dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx, + sw->abs_pos); +} + +/* + * To minimise the Impact of the noise on the algorithm, ADI developed a + * routine that filters the CDC results after they have been read by the + * host processor. + * The filter used is an Infinite Input Response(IIR) filter implemented + * in firmware and attenuates the noise on the CDC results after they've + * been read by the host processor. + * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) + + * Latest_CDC_result * Coefficient)/10 + */ +static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; + + sw->flt_pos = (sw->flt_pos * (10 - 4) + + sw->abs_pos * 4)/10; + + dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx, + sw->flt_pos); +} + +static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + + ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); +} + +static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + + ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); +} + +static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; + struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; + unsigned short h_state, c_state; + unsigned short mask; + + mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); + + h_state = ad714x->h_state & mask; + c_state = ad714x->c_state & mask; + + switch (sw->state) { + case IDLE: + if (h_state) { + sw->state = JITTER; + /* In End of Conversion interrupt mode, the AD714X + * continuously generates hardware interrupts. + */ + ad714x_slider_use_com_int(ad714x, idx); + dev_dbg(ad714x->dev, "slider %d touched\n", idx); + } + break; + + case JITTER: + if (c_state == mask) { + ad714x_slider_cal_sensor_val(ad714x, idx); + ad714x_slider_cal_highest_stage(ad714x, idx); + ad714x_slider_cal_abs_pos(ad714x, idx); + sw->flt_pos = sw->abs_pos; + sw->state = ACTIVE; + } + break; + + case ACTIVE: + if (c_state == mask) { + if (h_state) { + ad714x_slider_cal_sensor_val(ad714x, idx); + ad714x_slider_cal_highest_stage(ad714x, idx); + ad714x_slider_cal_abs_pos(ad714x, idx); + ad714x_slider_cal_flt_pos(ad714x, idx); + + input_report_abs(sw->input, ABS_X, sw->flt_pos); + input_report_key(sw->input, BTN_TOUCH, 1); + } else { + /* When the user lifts off the sensor, configure + * the AD714X back to threshold interrupt mode. + */ + ad714x_slider_use_thr_int(ad714x, idx); + sw->state = IDLE; + input_report_key(sw->input, BTN_TOUCH, 0); + dev_dbg(ad714x->dev, "slider %d released\n", + idx); + } + input_sync(sw->input); + } + break; + + default: + break; + } +} + +/* + * When the scroll wheel is activated, we compute the absolute position based + * on the sensor values. To calculate the position, we first determine the + * sensor that has the greatest response among the 8 sensors that constitutes + * the scrollwheel. Then we determined the 2 sensors on either sides of the + * sensor with the highest response and we apply weights to these sensors. + */ +static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; + + sw->pre_highest_stage = sw->highest_stage; + sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, + hw->end_stage); + + dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx, + sw->highest_stage); +} + +static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + int i; + + for (i = hw->start_stage; i <= hw->end_stage; i++) { + ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, + &ad714x->adc_reg[i]); + ad714x->read(ad714x->dev, + STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, + &ad714x->amb_reg[i]); + if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) + ad714x->sensor_val[i] = ad714x->adc_reg[i] - + ad714x->amb_reg[i]; + else + ad714x->sensor_val[i] = 0; + } +} + +/* + * When the scroll wheel is activated, we compute the absolute position based + * on the sensor values. To calculate the position, we first determine the + * sensor that has the greatest response among the 8 sensors that constitutes + * the scrollwheel. Then we determined the 2 sensors on either sides of the + * sensor with the highest response and we apply weights to these sensors. The + * result of this computation gives us the mean value which defined by the + * following formula: + * For i= second_before_highest_stage to i= second_after_highest_stage + * v += Sensor response(i)*WEIGHT*(i+3) + * w += Sensor response(i) + * Mean_Value=v/w + * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio + */ + +#define WEIGHT_FACTOR 30 +/* This constant prevents the "PositionOffset" from reaching a big value */ +#define OFFSET_POSITION_CLAMP 120 +static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; + int stage_num = hw->end_stage - hw->start_stage + 1; + int second_before, first_before, highest, first_after, second_after; + int a_param, b_param; + + /* Calculate Mean value */ + + second_before = (sw->highest_stage + stage_num - 2) % stage_num; + first_before = (sw->highest_stage + stage_num - 1) % stage_num; + highest = sw->highest_stage; + first_after = (sw->highest_stage + stage_num + 1) % stage_num; + second_after = (sw->highest_stage + stage_num + 2) % stage_num; + + if (((sw->highest_stage - hw->start_stage) > 1) && + ((hw->end_stage - sw->highest_stage) > 1)) { + a_param = ad714x->sensor_val[second_before] * + (second_before - hw->start_stage + 3) + + ad714x->sensor_val[first_before] * + (second_before - hw->start_stage + 3) + + ad714x->sensor_val[highest] * + (second_before - hw->start_stage + 3) + + ad714x->sensor_val[first_after] * + (first_after - hw->start_stage + 3) + + ad714x->sensor_val[second_after] * + (second_after - hw->start_stage + 3); + } else { + a_param = ad714x->sensor_val[second_before] * + (second_before - hw->start_stage + 1) + + ad714x->sensor_val[first_before] * + (second_before - hw->start_stage + 2) + + ad714x->sensor_val[highest] * + (second_before - hw->start_stage + 3) + + ad714x->sensor_val[first_after] * + (first_after - hw->start_stage + 4) + + ad714x->sensor_val[second_after] * + (second_after - hw->start_stage + 5); + } + a_param *= WEIGHT_FACTOR; + + b_param = ad714x->sensor_val[second_before] + + ad714x->sensor_val[first_before] + + ad714x->sensor_val[highest] + + ad714x->sensor_val[first_after] + + ad714x->sensor_val[second_after]; + + sw->pre_mean_value = sw->mean_value; + sw->mean_value = a_param / b_param; + + /* Calculate the offset */ + + if ((sw->pre_highest_stage == hw->end_stage) && + (sw->highest_stage == hw->start_stage)) + sw->pos_offset = sw->mean_value; + else if ((sw->pre_highest_stage == hw->start_stage) && + (sw->highest_stage == hw->end_stage)) + sw->pos_offset = sw->pre_mean_value; + + if (sw->pos_offset > OFFSET_POSITION_CLAMP) + sw->pos_offset = OFFSET_POSITION_CLAMP; + + /* Calculate the mean value without the offset */ + + sw->pre_mean_value_no_offset = sw->mean_value_no_offset; + sw->mean_value_no_offset = sw->mean_value - sw->pos_offset; + if (sw->mean_value_no_offset < 0) + sw->mean_value_no_offset = 0; + + /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */ + + if ((sw->pre_highest_stage == hw->end_stage) && + (sw->highest_stage == hw->start_stage)) + sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) / + hw->max_coord; + else if ((sw->pre_highest_stage == hw->start_stage) && + (sw->highest_stage == hw->end_stage)) + sw->pos_ratio = (sw->mean_value_no_offset * 100) / + hw->max_coord; + sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio; + if (sw->abs_pos > hw->max_coord) + sw->abs_pos = hw->max_coord; +} + +static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; + if (((sw->pre_highest_stage == hw->end_stage) && + (sw->highest_stage == hw->start_stage)) || + ((sw->pre_highest_stage == hw->start_stage) && + (sw->highest_stage == hw->end_stage))) + sw->flt_pos = sw->abs_pos; + else + sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100; + + if (sw->flt_pos > hw->max_coord) + sw->flt_pos = hw->max_coord; +} + +static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + + ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); +} + +static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + + ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); +} + +static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; + struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; + unsigned short h_state, c_state; + unsigned short mask; + + mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); + + h_state = ad714x->h_state & mask; + c_state = ad714x->c_state & mask; + + switch (sw->state) { + case IDLE: + if (h_state) { + sw->state = JITTER; + /* In End of Conversion interrupt mode, the AD714X + * continuously generates hardware interrupts. + */ + ad714x_wheel_use_com_int(ad714x, idx); + dev_dbg(ad714x->dev, "wheel %d touched\n", idx); + } + break; + + case JITTER: + if (c_state == mask) { + ad714x_wheel_cal_sensor_val(ad714x, idx); + ad714x_wheel_cal_highest_stage(ad714x, idx); + ad714x_wheel_cal_abs_pos(ad714x, idx); + sw->flt_pos = sw->abs_pos; + sw->state = ACTIVE; + } + break; + + case ACTIVE: + if (c_state == mask) { + if (h_state) { + ad714x_wheel_cal_sensor_val(ad714x, idx); + ad714x_wheel_cal_highest_stage(ad714x, idx); + ad714x_wheel_cal_abs_pos(ad714x, idx); + ad714x_wheel_cal_flt_pos(ad714x, idx); + + input_report_abs(sw->input, ABS_WHEEL, + sw->abs_pos); + input_report_key(sw->input, BTN_TOUCH, 1); + } else { + /* When the user lifts off the sensor, configure + * the AD714X back to threshold interrupt mode. + */ + ad714x_wheel_use_thr_int(ad714x, idx); + sw->state = IDLE; + input_report_key(sw->input, BTN_TOUCH, 0); + + dev_dbg(ad714x->dev, "wheel %d released\n", + idx); + } + input_sync(sw->input); + } + break; + + default: + break; + } +} + +static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + int i; + + for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) { + ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, + &ad714x->adc_reg[i]); + ad714x->read(ad714x->dev, + STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, + &ad714x->amb_reg[i]); + if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) + ad714x->sensor_val[i] = ad714x->adc_reg[i] - + ad714x->amb_reg[i]; + else + ad714x->sensor_val[i] = 0; + } +} + +static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + + sw->x_highest_stage = ad714x_cal_highest_stage(ad714x, + hw->x_start_stage, hw->x_end_stage); + sw->y_highest_stage = ad714x_cal_highest_stage(ad714x, + hw->y_start_stage, hw->y_end_stage); + + dev_dbg(ad714x->dev, + "touchpad %d x_highest_stage:%d, y_highest_stage:%d\n", + idx, sw->x_highest_stage, sw->y_highest_stage); +} + +/* + * If 2 fingers are touching the sensor then 2 peaks can be observed in the + * distribution. + * The arithmetic doesn't support to get absolute coordinates for multi-touch + * yet. + */ +static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + int i; + + for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) { + if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) + > (ad714x->sensor_val[i + 1] / 10)) + return 1; + } + + for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) { + if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) + > (ad714x->sensor_val[i] / 10)) + return 1; + } + + for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) { + if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) + > (ad714x->sensor_val[i + 1] / 10)) + return 1; + } + + for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) { + if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) + > (ad714x->sensor_val[i] / 10)) + return 1; + } + + return 0; +} + +/* + * If only one finger is used to activate the touch pad then only 1 peak will be + * registered in the distribution. This peak and the 2 adjacent sensors will be + * used in the calculation of the absolute position. This will prevent hand + * shadows to affect the absolute position calculation. + */ +static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + + sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage, + hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord); + sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage, + hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord); + + dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx, + sw->x_abs_pos, sw->y_abs_pos); +} + +static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + + sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) + + sw->x_abs_pos * 4)/10; + sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) + + sw->y_abs_pos * 4)/10; + + dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n", + idx, sw->x_flt_pos, sw->y_flt_pos); +} + +/* + * To prevent distortion from showing in the absolute position, it is + * necessary to detect the end points. When endpoints are detected, the + * driver stops updating the status variables with absolute positions. + * End points are detected on the 4 edges of the touchpad sensor. The + * method to detect them is the same for all 4. + * To detect the end points, the firmware computes the difference in + * percent between the sensor on the edge and the adjacent one. The + * difference is calculated in percent in order to make the end point + * detection independent of the pressure. + */ + +#define LEFT_END_POINT_DETECTION_LEVEL 550 +#define RIGHT_END_POINT_DETECTION_LEVEL 750 +#define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL 850 +#define TOP_END_POINT_DETECTION_LEVEL 550 +#define BOTTOM_END_POINT_DETECTION_LEVEL 950 +#define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL 700 +static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + int percent_sensor_diff; + + /* left endpoint detect */ + percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] - + ad714x->sensor_val[hw->x_start_stage + 1]) * 100 / + ad714x->sensor_val[hw->x_start_stage + 1]; + if (!sw->left_ep) { + if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL) { + sw->left_ep = 1; + sw->left_ep_val = + ad714x->sensor_val[hw->x_start_stage + 1]; + } + } else { + if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) && + (ad714x->sensor_val[hw->x_start_stage + 1] > + LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val)) + sw->left_ep = 0; + } + + /* right endpoint detect */ + percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] - + ad714x->sensor_val[hw->x_end_stage - 1]) * 100 / + ad714x->sensor_val[hw->x_end_stage - 1]; + if (!sw->right_ep) { + if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL) { + sw->right_ep = 1; + sw->right_ep_val = + ad714x->sensor_val[hw->x_end_stage - 1]; + } + } else { + if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) && + (ad714x->sensor_val[hw->x_end_stage - 1] > + LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val)) + sw->right_ep = 0; + } + + /* top endpoint detect */ + percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] - + ad714x->sensor_val[hw->y_start_stage + 1]) * 100 / + ad714x->sensor_val[hw->y_start_stage + 1]; + if (!sw->top_ep) { + if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL) { + sw->top_ep = 1; + sw->top_ep_val = + ad714x->sensor_val[hw->y_start_stage + 1]; + } + } else { + if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) && + (ad714x->sensor_val[hw->y_start_stage + 1] > + TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val)) + sw->top_ep = 0; + } + + /* bottom endpoint detect */ + percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] - + ad714x->sensor_val[hw->y_end_stage - 1]) * 100 / + ad714x->sensor_val[hw->y_end_stage - 1]; + if (!sw->bottom_ep) { + if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL) { + sw->bottom_ep = 1; + sw->bottom_ep_val = + ad714x->sensor_val[hw->y_end_stage - 1]; + } + } else { + if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) && + (ad714x->sensor_val[hw->y_end_stage - 1] > + TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val)) + sw->bottom_ep = 0; + } + + return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep; +} + +static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + + ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage); +} + +static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + + ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage); + ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage); +} + +static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx) +{ + struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; + struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; + unsigned short h_state, c_state; + unsigned short mask; + + mask = (((1 << (hw->x_end_stage + 1)) - 1) - + ((1 << hw->x_start_stage) - 1)) + + (((1 << (hw->y_end_stage + 1)) - 1) - + ((1 << hw->y_start_stage) - 1)); + + h_state = ad714x->h_state & mask; + c_state = ad714x->c_state & mask; + + switch (sw->state) { + case IDLE: + if (h_state) { + sw->state = JITTER; + /* In End of Conversion interrupt mode, the AD714X + * continuously generates hardware interrupts. + */ + touchpad_use_com_int(ad714x, idx); + dev_dbg(ad714x->dev, "touchpad %d touched\n", idx); + } + break; + + case JITTER: + if (c_state == mask) { + touchpad_cal_sensor_val(ad714x, idx); + touchpad_cal_highest_stage(ad714x, idx); + if ((!touchpad_check_second_peak(ad714x, idx)) && + (!touchpad_check_endpoint(ad714x, idx))) { + dev_dbg(ad714x->dev, + "touchpad%d, 2 fingers or endpoint\n", + idx); + touchpad_cal_abs_pos(ad714x, idx); + sw->x_flt_pos = sw->x_abs_pos; + sw->y_flt_pos = sw->y_abs_pos; + sw->state = ACTIVE; + } + } + break; + + case ACTIVE: + if (c_state == mask) { + if (h_state) { + touchpad_cal_sensor_val(ad714x, idx); + touchpad_cal_highest_stage(ad714x, idx); + if ((!touchpad_check_second_peak(ad714x, idx)) + && (!touchpad_check_endpoint(ad714x, idx))) { + touchpad_cal_abs_pos(ad714x, idx); + touchpad_cal_flt_pos(ad714x, idx); + input_report_abs(sw->input, ABS_X, + sw->x_flt_pos); + input_report_abs(sw->input, ABS_Y, + sw->y_flt_pos); + input_report_key(sw->input, BTN_TOUCH, + 1); + } + } else { + /* When the user lifts off the sensor, configure + * the AD714X back to threshold interrupt mode. + */ + touchpad_use_thr_int(ad714x, idx); + sw->state = IDLE; + input_report_key(sw->input, BTN_TOUCH, 0); + dev_dbg(ad714x->dev, "touchpad %d released\n", + idx); + } + input_sync(sw->input); + } + break; + + default: + break; + } +} + +static int ad714x_hw_detect(struct ad714x_chip *ad714x) +{ + unsigned short data; + + ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data); + switch (data & 0xFFF0) { + case AD7147_PARTID: + ad714x->product = 0x7147; + ad714x->version = data & 0xF; + dev_info(ad714x->dev, "found AD7147 captouch, rev:%d\n", + ad714x->version); + return 0; + + case AD7142_PARTID: + ad714x->product = 0x7142; + ad714x->version = data & 0xF; + dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n", + ad714x->version); + return 0; + + default: + dev_err(ad714x->dev, + "fail to detect AD714X captouch, read ID is %04x\n", + data); + return -ENODEV; + } +} + +static void ad714x_hw_init(struct ad714x_chip *ad714x) +{ + int i, j; + unsigned short reg_base; + unsigned short data; + + /* configuration CDC and interrupts */ + + for (i = 0; i < STAGE_NUM; i++) { + reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM; + for (j = 0; j < STAGE_CFGREG_NUM; j++) + ad714x->write(ad714x->dev, reg_base + j, + ad714x->hw->stage_cfg_reg[i][j]); + } + + for (i = 0; i < SYS_CFGREG_NUM; i++) + ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i, + ad714x->hw->sys_cfg_reg[i]); + for (i = 0; i < SYS_CFGREG_NUM; i++) + ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i, + &data); + + ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF); + + /* clear all interrupts */ + ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); + ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); + ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); +} + +static irqreturn_t ad714x_interrupt_thread(int irq, void *data) +{ + struct ad714x_chip *ad714x = data; + int i; + + mutex_lock(&ad714x->mutex); + + ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state); + ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state); + ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state); + + for (i = 0; i < ad714x->hw->button_num; i++) + ad714x_button_state_machine(ad714x, i); + for (i = 0; i < ad714x->hw->slider_num; i++) + ad714x_slider_state_machine(ad714x, i); + for (i = 0; i < ad714x->hw->wheel_num; i++) + ad714x_wheel_state_machine(ad714x, i); + for (i = 0; i < ad714x->hw->touchpad_num; i++) + ad714x_touchpad_state_machine(ad714x, i); + + mutex_unlock(&ad714x->mutex); + + return IRQ_HANDLED; +} + +#define MAX_DEVICE_NUM 8 +struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, + ad714x_read_t read, ad714x_write_t write) +{ + int i, alloc_idx; + int error; + struct input_dev *input[MAX_DEVICE_NUM]; + + struct ad714x_platform_data *plat_data = dev->platform_data; + struct ad714x_chip *ad714x; + void *drv_mem; + + struct ad714x_button_drv *bt_drv; + struct ad714x_slider_drv *sd_drv; + struct ad714x_wheel_drv *wl_drv; + struct ad714x_touchpad_drv *tp_drv; + + + if (irq <= 0) { + dev_err(dev, "IRQ not configured!\n"); + error = -EINVAL; + goto err_out; + } + + if (dev->platform_data == NULL) { + dev_err(dev, "platform data for ad714x doesn't exist\n"); + error = -EINVAL; + goto err_out; + } + + ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) + + sizeof(*sd_drv) * plat_data->slider_num + + sizeof(*wl_drv) * plat_data->wheel_num + + sizeof(*tp_drv) * plat_data->touchpad_num + + sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL); + if (!ad714x) { + error = -ENOMEM; + goto err_out; + } + + ad714x->hw = plat_data; + + drv_mem = ad714x + 1; + ad714x->sw = drv_mem; + drv_mem += sizeof(*ad714x->sw); + ad714x->sw->slider = sd_drv = drv_mem; + drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num; + ad714x->sw->wheel = wl_drv = drv_mem; + drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num; + ad714x->sw->touchpad = tp_drv = drv_mem; + drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num; + ad714x->sw->button = bt_drv = drv_mem; + drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num; + + ad714x->read = read; + ad714x->write = write; + ad714x->irq = irq; + ad714x->dev = dev; + + error = ad714x_hw_detect(ad714x); + if (error) + goto err_free_mem; + + /* initilize and request sw/hw resources */ + + ad714x_hw_init(ad714x); + mutex_init(&ad714x->mutex); + + /* + * Allocate and register AD714X input device + */ + alloc_idx = 0; + + /* a slider uses one input_dev instance */ + if (ad714x->hw->slider_num > 0) { + struct ad714x_slider_plat *sd_plat = ad714x->hw->slider; + + for (i = 0; i < ad714x->hw->slider_num; i++) { + sd_drv[i].input = input[alloc_idx] = input_allocate_device(); + if (!input[alloc_idx]) { + error = -ENOMEM; + goto err_free_dev; + } + + __set_bit(EV_ABS, input[alloc_idx]->evbit); + __set_bit(EV_KEY, input[alloc_idx]->evbit); + __set_bit(ABS_X, input[alloc_idx]->absbit); + __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); + input_set_abs_params(input[alloc_idx], + ABS_X, 0, sd_plat->max_coord, 0, 0); + + input[alloc_idx]->id.bustype = bus_type; + input[alloc_idx]->id.product = ad714x->product; + input[alloc_idx]->id.version = ad714x->version; + + error = input_register_device(input[alloc_idx]); + if (error) + goto err_free_dev; + + alloc_idx++; + } + } + + /* a wheel uses one input_dev instance */ + if (ad714x->hw->wheel_num > 0) { + struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel; + + for (i = 0; i < ad714x->hw->wheel_num; i++) { + wl_drv[i].input = input[alloc_idx] = input_allocate_device(); + if (!input[alloc_idx]) { + error = -ENOMEM; + goto err_free_dev; + } + + __set_bit(EV_KEY, input[alloc_idx]->evbit); + __set_bit(EV_ABS, input[alloc_idx]->evbit); + __set_bit(ABS_WHEEL, input[alloc_idx]->absbit); + __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); + input_set_abs_params(input[alloc_idx], + ABS_WHEEL, 0, wl_plat->max_coord, 0, 0); + + input[alloc_idx]->id.bustype = bus_type; + input[alloc_idx]->id.product = ad714x->product; + input[alloc_idx]->id.version = ad714x->version; + + error = input_register_device(input[alloc_idx]); + if (error) + goto err_free_dev; + + alloc_idx++; + } + } + + /* a touchpad uses one input_dev instance */ + if (ad714x->hw->touchpad_num > 0) { + struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad; + + for (i = 0; i < ad714x->hw->touchpad_num; i++) { + tp_drv[i].input = input[alloc_idx] = input_allocate_device(); + if (!input[alloc_idx]) { + error = -ENOMEM; + goto err_free_dev; + } + + __set_bit(EV_ABS, input[alloc_idx]->evbit); + __set_bit(EV_KEY, input[alloc_idx]->evbit); + __set_bit(ABS_X, input[alloc_idx]->absbit); + __set_bit(ABS_Y, input[alloc_idx]->absbit); + __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); + input_set_abs_params(input[alloc_idx], + ABS_X, 0, tp_plat->x_max_coord, 0, 0); + input_set_abs_params(input[alloc_idx], + ABS_Y, 0, tp_plat->y_max_coord, 0, 0); + + input[alloc_idx]->id.bustype = bus_type; + input[alloc_idx]->id.product = ad714x->product; + input[alloc_idx]->id.version = ad714x->version; + + error = input_register_device(input[alloc_idx]); + if (error) + goto err_free_dev; + + alloc_idx++; + } + } + + /* all buttons use one input node */ + if (ad714x->hw->button_num > 0) { + struct ad714x_button_plat *bt_plat = ad714x->hw->button; + + input[alloc_idx] = input_allocate_device(); + if (!input[alloc_idx]) { + error = -ENOMEM; + goto err_free_dev; + } + + __set_bit(EV_KEY, input[alloc_idx]->evbit); + for (i = 0; i < ad714x->hw->button_num; i++) { + bt_drv[i].input = input[alloc_idx]; + __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit); + } + + input[alloc_idx]->id.bustype = bus_type; + input[alloc_idx]->id.product = ad714x->product; + input[alloc_idx]->id.version = ad714x->version; + + error = input_register_device(input[alloc_idx]); + if (error) + goto err_free_dev; + + alloc_idx++; + } + + error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread, + IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x); + if (error) { + dev_err(dev, "can't allocate irq %d\n", ad714x->irq); + goto err_unreg_dev; + } + + return ad714x; + + err_free_dev: + dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx); + input_free_device(input[alloc_idx]); + err_unreg_dev: + while (--alloc_idx >= 0) + input_unregister_device(input[alloc_idx]); + err_free_mem: + kfree(ad714x); + err_out: + return ERR_PTR(error); +} +EXPORT_SYMBOL(ad714x_probe); + +void ad714x_remove(struct ad714x_chip *ad714x) +{ + struct ad714x_platform_data *hw = ad714x->hw; + struct ad714x_driver_data *sw = ad714x->sw; + int i; + + free_irq(ad714x->irq, ad714x); + + /* unregister and free all input devices */ + + for (i = 0; i < hw->slider_num; i++) + input_unregister_device(sw->slider[i].input); + + for (i = 0; i < hw->wheel_num; i++) + input_unregister_device(sw->wheel[i].input); + + for (i = 0; i < hw->touchpad_num; i++) + input_unregister_device(sw->touchpad[i].input); + + if (hw->button_num) + input_unregister_device(sw->button[0].input); + + kfree(ad714x); +} +EXPORT_SYMBOL(ad714x_remove); + +#ifdef CONFIG_PM +int ad714x_disable(struct ad714x_chip *ad714x) +{ + unsigned short data; + + dev_dbg(ad714x->dev, "%s enter\n", __func__); + + mutex_lock(&ad714x->mutex); + + data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3; + ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data); + + mutex_unlock(&ad714x->mutex); + + return 0; +} +EXPORT_SYMBOL(ad714x_disable); + +int ad714x_enable(struct ad714x_chip *ad714x) +{ + unsigned short data; + + dev_dbg(ad714x->dev, "%s enter\n", __func__); + + mutex_lock(&ad714x->mutex); + + /* resume to non-shutdown mode */ + + ad714x->write(ad714x->dev, AD714X_PWR_CTRL, + ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]); + + /* make sure the interrupt output line is not low level after resume, + * otherwise we will get no chance to enter falling-edge irq again + */ + + ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); + ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); + ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); + + mutex_unlock(&ad714x->mutex); + + return 0; +} +EXPORT_SYMBOL(ad714x_enable); +#endif + +MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h new file mode 100644 index 000000000000..45c54fb13f07 --- /dev/null +++ b/drivers/input/misc/ad714x.h @@ -0,0 +1,26 @@ +/* + * AD714X CapTouch Programmable Controller driver (bus interfaces) + * + * Copyright 2009 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _AD714X_H_ +#define _AD714X_H_ + +#include + +struct device; +struct ad714x_chip; + +typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *); +typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short); + +int ad714x_disable(struct ad714x_chip *ad714x); +int ad714x_enable(struct ad714x_chip *ad714x); +struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, + ad714x_read_t read, ad714x_write_t write); +void ad714x_remove(struct ad714x_chip *ad714x); + +#endif -- cgit v1.2.1 From 6c04d7b3cf50a393f07f22a661d05d15db5dc6f6 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Sun, 21 Mar 2010 23:23:29 -0700 Subject: Input: ad714x - add support for the AD7143/8/7A parts Signed-off-by: Barry Song Signed-off-by: Mike Frysinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 2 +- drivers/input/misc/ad714x-i2c.c | 3 +++ drivers/input/misc/ad714x.c | 28 ++++++++++++++++++++++------ 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index a4b9dc5cf456..48cdabec372a 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -25,7 +25,7 @@ config INPUT_88PM860X_ONKEY config INPUT_AD714X tristate "Analog Devices AD714x Capacitance Touch Sensor" help - Say Y here if you want to support an AD7142/AD7147 touch sensor. + Say Y here if you want to support an AD7142/3/7/8/7A touch sensor. You should select a bus connection too. diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index a2cb6b426dc7..e9adbe49f6a4 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -104,7 +104,10 @@ static int __devexit ad714x_i2c_remove(struct i2c_client *client) static const struct i2c_device_id ad714x_id[] = { { "ad7142_captouch", 0 }, + { "ad7143_captouch", 0 }, { "ad7147_captouch", 0 }, + { "ad7147a_captouch", 0 }, + { "ad7148_captouch", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ad714x_id); diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index 691b1d37331f..0fe27baf5e72 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -1,5 +1,5 @@ /* - * AD714X CapTouch Programmable Controller driver + * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A * * Copyright 2009 Analog Devices Inc. * @@ -18,8 +18,10 @@ #define AD714X_STG_CAL_EN_REG 0x1 #define AD714X_AMB_COMP_CTRL0_REG 0x2 #define AD714X_PARTID_REG 0x17 -#define AD7147_PARTID 0x1470 #define AD7142_PARTID 0xE620 +#define AD7143_PARTID 0xE630 +#define AD7147_PARTID 0x1470 +#define AD7148_PARTID 0x1480 #define AD714X_STAGECFG_REG 0x80 #define AD714X_SYSCFG_REG 0x0 @@ -962,17 +964,31 @@ static int ad714x_hw_detect(struct ad714x_chip *ad714x) ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data); switch (data & 0xFFF0) { + case AD7142_PARTID: + ad714x->product = 0x7142; + ad714x->version = data & 0xF; + dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n", + ad714x->version); + return 0; + + case AD7143_PARTID: + ad714x->product = 0x7143; + ad714x->version = data & 0xF; + dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n", + ad714x->version); + return 0; + case AD7147_PARTID: ad714x->product = 0x7147; ad714x->version = data & 0xF; - dev_info(ad714x->dev, "found AD7147 captouch, rev:%d\n", + dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n", ad714x->version); return 0; - case AD7142_PARTID: - ad714x->product = 0x7142; + case AD7148_PARTID: + ad714x->product = 0x7148; ad714x->version = data & 0xF; - dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n", + dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n", ad714x->version); return 0; -- cgit v1.2.1 From 5132088697fbfd1330facf723499091182f6ef91 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 3 May 2010 23:30:32 -0700 Subject: Input: ati_remote - add some missing devices from lirc_atiusb The (out-of-tree) lirc_atiusb driver has a much longer list of devices it supports. Some of them look like they may just be guesses at possible device IDs, but a few are definitely confirmed devices. This adds the nVidia-branded RF receiver and the X10 Lola Wireless Video Sender device (which contains an RF receiver) to the list of devices in ati_remote. Signed-off-by: Jarod Wilson Signed-off-by: Andrew Morton Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ati_remote.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index 614b65d78fe9..e8bbc619f6df 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -98,10 +98,12 @@ * Module and Version Information, Module Parameters */ -#define ATI_REMOTE_VENDOR_ID 0x0bc7 -#define ATI_REMOTE_PRODUCT_ID 0x004 -#define LOLA_REMOTE_PRODUCT_ID 0x002 -#define MEDION_REMOTE_PRODUCT_ID 0x006 +#define ATI_REMOTE_VENDOR_ID 0x0bc7 +#define LOLA_REMOTE_PRODUCT_ID 0x0002 +#define LOLA2_REMOTE_PRODUCT_ID 0x0003 +#define ATI_REMOTE_PRODUCT_ID 0x0004 +#define NVIDIA_REMOTE_PRODUCT_ID 0x0005 +#define MEDION_REMOTE_PRODUCT_ID 0x0006 #define DRIVER_VERSION "2.2.1" #define DRIVER_AUTHOR "Torrey Hoffman " @@ -142,8 +144,10 @@ MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec #define err(format, arg...) printk(KERN_ERR format , ## arg) static struct usb_device_id ati_remote_table[] = { - { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) }, + { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) }, { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) }, {} /* Terminating entry */ }; -- cgit v1.2.1 From ee6e54e2ae56734a96fd7b66cf46b756d0f25ca3 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 19 May 2010 10:11:13 -0700 Subject: Input: 88pm860x_onkey - remove invalid irq number assignment Irq number of onkey is assigned twice. The second assignment is wrong. Signed-off-by: Haojian Zhuang Signed-off-by: Dmitry Torokhov --- drivers/input/misc/88pm860x_onkey.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 40dabd8487b5..4cc82826ea6b 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -87,7 +87,6 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev) info->idev->phys = "88pm860x_on/input0"; info->idev->id.bustype = BUS_I2C; info->idev->dev.parent = &pdev->dev; - info->irq = irq; info->idev->evbit[0] = BIT_MASK(EV_KEY); info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); -- cgit v1.2.1 From f8300ab8c3e0bea42c82bbdcdff7b791b795d58f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 19 May 2010 10:11:14 -0700 Subject: Input: wistron_btns - switch to using kmemdup() Use kmemdup when some other buffer is immediately copied into the allocated region. Signed-off-by: Julia Lawall Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 04d5a4a3181f..4dac8b79fcd4 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -983,11 +983,11 @@ static int __init copy_keymap(void) for (key = keymap; key->type != KE_END; key++) length++; - new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL); + new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), + GFP_KERNEL); if (!new_keymap) return -ENOMEM; - memcpy(new_keymap, keymap, length * sizeof(struct key_entry)); keymap = new_keymap; return 0; -- cgit v1.2.1 From 0ede76fcec5415ef82a423a95120286895822e2d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 5 Mar 2010 15:10:17 -0500 Subject: USB: remove uses of URB_NO_SETUP_DMA_MAP This patch (as1350) removes all usages of coherent buffers for USB control-request setup-packet buffers. There's no good reason to reserve coherent memory for these things; control requests are hardly ever used in large quantity (the major exception is firmware transfers, and they aren't time-critical). Furthermore, only seven drivers used it. We might as well always use streaming DMA mappings for setup-packet buffers, and remove some extra complexity from usbcore. The DMA-mapping portion of hcd.c is currently in flux. A separate patch will be submitted to remove support for URB_NO_SETUP_DMA_MAP after everything else settles down. The removal should go smoothly, as by then nobody will be using it. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/cm109.c | 12 +++--------- drivers/input/misc/powermate.c | 9 ++------- drivers/input/misc/yealink.c | 11 +++-------- 3 files changed, 8 insertions(+), 24 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 86457feccfc4..8d2d291ee508 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -102,7 +102,6 @@ struct cm109_dev { struct cm109_ctl_packet *ctl_data; dma_addr_t ctl_dma; struct usb_ctrlrequest *ctl_req; - dma_addr_t ctl_req_dma; struct urb *urb_ctl; /* * The 3 bitfields below are protected by ctl_submit_lock. @@ -629,9 +628,7 @@ static const struct usb_device_id cm109_usb_table[] = { static void cm109_usb_cleanup(struct cm109_dev *dev) { - if (dev->ctl_req) - usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)), - dev->ctl_req, dev->ctl_req_dma); + kfree(dev->ctl_req); if (dev->ctl_data) usb_buffer_free(dev->udev, USB_PKT_LEN, dev->ctl_data, dev->ctl_dma); @@ -696,8 +693,7 @@ static int cm109_usb_probe(struct usb_interface *intf, if (!dev->ctl_data) goto err_out; - dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)), - GFP_KERNEL, &dev->ctl_req_dma); + dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL); if (!dev->ctl_req) goto err_out; @@ -735,10 +731,8 @@ static int cm109_usb_probe(struct usb_interface *intf, usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0), (void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN, cm109_urb_ctl_callback, dev); - dev->urb_ctl->setup_dma = dev->ctl_req_dma; dev->urb_ctl->transfer_dma = dev->ctl_dma; - dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP | - URB_NO_TRANSFER_DMA_MAP; + dev->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; dev->urb_ctl->dev = udev; /* find out the physical bus location */ diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 668913d12044..7ba4b5f53fc2 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -64,7 +64,6 @@ struct powermate_device { dma_addr_t data_dma; struct urb *irq, *config; struct usb_ctrlrequest *configcr; - dma_addr_t configcr_dma; struct usb_device *udev; struct input_dev *input; spinlock_t lock; @@ -182,8 +181,6 @@ static void powermate_sync_state(struct powermate_device *pm) usb_fill_control_urb(pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), (void *) pm->configcr, NULL, 0, powermate_config_complete, pm); - pm->config->setup_dma = pm->configcr_dma; - pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP; if (usb_submit_urb(pm->config, GFP_ATOMIC)) printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); @@ -281,8 +278,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev if (!pm->data) return -1; - pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), - GFP_ATOMIC, &pm->configcr_dma); + pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL); if (!pm->configcr) return -1; @@ -293,8 +289,7 @@ static void powermate_free_buffers(struct usb_device *udev, struct powermate_dev { usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX, pm->data, pm->data_dma); - usb_buffer_free(udev, sizeof(*(pm->configcr)), - pm->configcr, pm->configcr_dma); + kfree(pm->configcr); } /* Called whenever a USB device matching one in our supported devices table is connected */ diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 93a22ac0f88c..2828328e9dd0 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -111,7 +111,6 @@ struct yealink_dev { struct yld_ctl_packet *ctl_data; dma_addr_t ctl_dma; struct usb_ctrlrequest *ctl_req; - dma_addr_t ctl_req_dma; struct urb *urb_ctl; char phys[64]; /* physical device path */ @@ -836,8 +835,7 @@ static int usb_cleanup(struct yealink_dev *yld, int err) usb_free_urb(yld->urb_irq); usb_free_urb(yld->urb_ctl); - usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)), - yld->ctl_req, yld->ctl_req_dma); + kfree(yld->ctl_req); usb_buffer_free(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma); usb_buffer_free(yld->udev, USB_PKT_LEN, @@ -896,8 +894,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!yld->ctl_data) return usb_cleanup(yld, -ENOMEM); - yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)), - GFP_ATOMIC, &yld->ctl_req_dma); + yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL); if (yld->ctl_req == NULL) return usb_cleanup(yld, -ENOMEM); @@ -936,10 +933,8 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_fill_control_urb(yld->urb_ctl, udev, usb_sndctrlpipe(udev, 0), (void *)yld->ctl_req, yld->ctl_data, USB_PKT_LEN, urb_ctl_callback, yld); - yld->urb_ctl->setup_dma = yld->ctl_req_dma; yld->urb_ctl->transfer_dma = yld->ctl_dma; - yld->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP | - URB_NO_TRANSFER_DMA_MAP; + yld->urb_ctl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; yld->urb_ctl->dev = udev; /* find out the physical bus location */ -- cgit v1.2.1 From 997ea58eb92f9970b8af7aae48800d0ef43b9423 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 12 Apr 2010 13:17:25 +0200 Subject: USB: rename usb_buffer_alloc() and usb_buffer_free() users For more clearance what the functions actually do, usb_buffer_alloc() is renamed to usb_alloc_coherent() usb_buffer_free() is renamed to usb_free_coherent() They should only be used in code which really needs DMA coherency. All call sites have been changed accordingly, except for staging drivers. Signed-off-by: Daniel Mack Cc: Alan Stern Cc: Pedro Ribeiro Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/ati_remote.c | 12 ++++++------ drivers/input/misc/ati_remote2.c | 4 ++-- drivers/input/misc/cm109.c | 16 ++++++++-------- drivers/input/misc/keyspan_remote.c | 6 +++--- drivers/input/misc/powermate.c | 8 ++++---- drivers/input/misc/yealink.c | 14 ++++++-------- 6 files changed, 29 insertions(+), 31 deletions(-) (limited to 'drivers/input/misc') diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c index e8bbc619f6df..bce57129afba 100644 --- a/drivers/input/misc/ati_remote.c +++ b/drivers/input/misc/ati_remote.c @@ -624,13 +624,13 @@ static void ati_remote_irq_in(struct urb *urb) static int ati_remote_alloc_buffers(struct usb_device *udev, struct ati_remote *ati_remote) { - ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, - &ati_remote->inbuf_dma); + ati_remote->inbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->inbuf_dma); if (!ati_remote->inbuf) return -1; - ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, - &ati_remote->outbuf_dma); + ati_remote->outbuf = usb_alloc_coherent(udev, DATA_BUFSIZE, GFP_ATOMIC, + &ati_remote->outbuf_dma); if (!ati_remote->outbuf) return -1; @@ -653,10 +653,10 @@ static void ati_remote_free_buffers(struct ati_remote *ati_remote) usb_free_urb(ati_remote->irq_urb); usb_free_urb(ati_remote->out_urb); - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, ati_remote->inbuf, ati_remote->inbuf_dma); - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + usb_free_coherent(ati_remote->udev, DATA_BUFSIZE, ati_remote->outbuf, ati_remote->outbuf_dma); } diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 2124b99378bb..e148749b5851 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -589,7 +589,7 @@ static int ati_remote2_urb_init(struct ati_remote2 *ar2) int i, pipe, maxp; for (i = 0; i < 2; i++) { - ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]); + ar2->buf[i] = usb_alloc_coherent(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]); if (!ar2->buf[i]) return -ENOMEM; @@ -617,7 +617,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2) for (i = 0; i < 2; i++) { usb_free_urb(ar2->urb[i]); - usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); + usb_free_coherent(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); } } diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 8d2d291ee508..2b0eba6619bd 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -630,11 +630,11 @@ static void cm109_usb_cleanup(struct cm109_dev *dev) { kfree(dev->ctl_req); if (dev->ctl_data) - usb_buffer_free(dev->udev, USB_PKT_LEN, - dev->ctl_data, dev->ctl_dma); + usb_free_coherent(dev->udev, USB_PKT_LEN, + dev->ctl_data, dev->ctl_dma); if (dev->irq_data) - usb_buffer_free(dev->udev, USB_PKT_LEN, - dev->irq_data, dev->irq_dma); + usb_free_coherent(dev->udev, USB_PKT_LEN, + dev->irq_data, dev->irq_dma); usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */ usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */ @@ -683,13 +683,13 @@ static int cm109_usb_probe(struct usb_interface *intf, goto err_out; /* allocate usb buffers */ - dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, - GFP_KERNEL, &dev->irq_dma); + dev->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN, + GFP_KERNEL, &dev->irq_dma); if (!dev->irq_data) goto err_out; - dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN, - GFP_KERNEL, &dev->ctl_dma); + dev->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN, + GFP_KERNEL, &dev->ctl_dma); if (!dev->ctl_data) goto err_out; diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index 86afdd1fdf9d..a93c525475c6 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -464,7 +464,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->in_endpoint = endpoint; remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ - remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); + remote->in_buffer = usb_alloc_coherent(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); if (!remote->in_buffer) { error = -ENOMEM; goto fail1; @@ -543,7 +543,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic return 0; fail3: usb_free_urb(remote->irq_urb); - fail2: usb_buffer_free(udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + fail2: usb_free_coherent(udev, RECV_SIZE, remote->in_buffer, remote->in_dma); fail1: kfree(remote); input_free_device(input_dev); @@ -564,7 +564,7 @@ static void keyspan_disconnect(struct usb_interface *interface) input_unregister_device(remote->input); usb_kill_urb(remote->irq_urb); usb_free_urb(remote->irq_urb); - usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); + usb_free_coherent(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma); kfree(remote); } } diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 7ba4b5f53fc2..bf170f6b4422 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -273,8 +273,8 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) { - pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX, - GFP_ATOMIC, &pm->data_dma); + pm->data = usb_alloc_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX, + GFP_ATOMIC, &pm->data_dma); if (!pm->data) return -1; @@ -287,8 +287,8 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm) { - usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX, - pm->data, pm->data_dma); + usb_free_coherent(udev, POWERMATE_PAYLOAD_SIZE_MAX, + pm->data, pm->data_dma); kfree(pm->configcr); } diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 2828328e9dd0..41201c6b5e68 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -836,10 +836,8 @@ static int usb_cleanup(struct yealink_dev *yld, int err) usb_free_urb(yld->urb_ctl); kfree(yld->ctl_req); - usb_buffer_free(yld->udev, USB_PKT_LEN, - yld->ctl_data, yld->ctl_dma); - usb_buffer_free(yld->udev, USB_PKT_LEN, - yld->irq_data, yld->irq_dma); + usb_free_coherent(yld->udev, USB_PKT_LEN, yld->ctl_data, yld->ctl_dma); + usb_free_coherent(yld->udev, USB_PKT_LEN, yld->irq_data, yld->irq_dma); kfree(yld); return err; @@ -884,13 +882,13 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) return usb_cleanup(yld, -ENOMEM); /* allocate usb buffers */ - yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, - GFP_ATOMIC, &yld->irq_dma); + yld->irq_data = usb_alloc_coherent(udev, USB_PKT_LEN, + GFP_ATOMIC, &yld->irq_dma); if (yld->irq_data == NULL) return usb_cleanup(yld, -ENOMEM); - yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN, - GFP_ATOMIC, &yld->ctl_dma); + yld->ctl_data = usb_alloc_coherent(udev, USB_PKT_LEN, + GFP_ATOMIC, &yld->ctl_dma); if (!yld->ctl_data) return usb_cleanup(yld, -ENOMEM); -- cgit v1.2.1