Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - three new touchscreen drivers: EETI EXC3000, HiDeep, and Samsung S6SY761 - the timer API conversion (setup_timer() -> timer_setup()) - a few drivers swiytched to using managed API for creating custom device attributes - other assorted fixed and cleanups. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (50 commits) Input: gamecon - mark expected switch fall-throughs Input: sidewinder - mark expected switch fall-throughs Input: spaceball - mark expected switch fall-throughs Input: uinput - unlock on allocation failure in ioctl Input: add support for the Samsung S6SY761 touchscreen Input: add support for HiDeep touchscreen Input: st1232 - remove obsolete platform device support Input: convert autorepeat timer to use timer_setup() media: ttpci: remove autorepeat handling and use timer_setup Input: cyttsp4 - avoid overflows when calculating memory sizes Input: mxs-lradc - remove redundant assignment to pointer input Input: add I2C attached EETI EXC3000 multi touch driver Input: goodix - support gt1151 touchpanel Input: ps2-gpio - actually abort probe when connected to sleeping GPIOs Input: hil_mlc - convert to using timer_setup() Input: hp_sdc - convert to using timer_setup() Input: touchsceen - convert timers to use timer_setup() Input: keyboard - convert timers to use timer_setup() Input: uinput - fold header into the driver proper Input: uinput - remove uinput_allocate_device() ...
This commit is contained in:
commit
9f7a9b1191
32
Documentation/devicetree/bindings/input/gpio-mouse.txt
Normal file
32
Documentation/devicetree/bindings/input/gpio-mouse.txt
Normal file
@ -0,0 +1,32 @@
|
||||
Device-Tree bindings for GPIO attached mice
|
||||
|
||||
This simply uses standard GPIO handles to define a simple mouse connected
|
||||
to 5-7 GPIO lines.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "gpio-mouse"
|
||||
- scan-interval-ms: The scanning interval in milliseconds
|
||||
- up-gpios: GPIO line phandle to the line indicating "up"
|
||||
- down-gpios: GPIO line phandle to the line indicating "down"
|
||||
- left-gpios: GPIO line phandle to the line indicating "left"
|
||||
- right-gpios: GPIO line phandle to the line indicating "right"
|
||||
|
||||
Optional properties:
|
||||
- button-left-gpios: GPIO line handle to the left mouse button
|
||||
- button-middle-gpios: GPIO line handle to the middle mouse button
|
||||
- button-right-gpios: GPIO line handle to the right mouse button
|
||||
Example:
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
gpio-mouse {
|
||||
compatible = "gpio-mouse";
|
||||
scan-interval-ms = <50>;
|
||||
up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||
down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||
left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
|
||||
right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
|
||||
button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
|
||||
button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
|
||||
button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
* EETI EXC3000 Multiple Touch Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "eeti,exc3000"
|
||||
- reg: i2c slave address
|
||||
- interrupt-parent: the phandle for the interrupt controller
|
||||
- interrupts: touch controller interrupt
|
||||
- touchscreen-size-x: See touchscreen.txt
|
||||
- touchscreen-size-y: See touchscreen.txt
|
||||
|
||||
Optional properties:
|
||||
- touchscreen-inverted-x: See touchscreen.txt
|
||||
- touchscreen-inverted-y: See touchscreen.txt
|
||||
- touchscreen-swapped-x-y: See touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
touchscreen@2a {
|
||||
compatible = "eeti,exc3000";
|
||||
reg = <0x2a>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
|
||||
touchscreen-size-x = <4096>;
|
||||
touchscreen-size-y = <4096>;
|
||||
touchscreen-inverted-x;
|
||||
touchscreen-swapped-x-y;
|
||||
};
|
@ -2,7 +2,8 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be "goodix,gt911"
|
||||
- compatible : Should be "goodix,gt1151"
|
||||
or "goodix,gt911"
|
||||
or "goodix,gt9110"
|
||||
or "goodix,gt912"
|
||||
or "goodix,gt927"
|
||||
|
@ -0,0 +1,42 @@
|
||||
* HiDeep Finger and Stylus touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "hideep,hideep-ts"
|
||||
- reg : I2C slave address, (e.g. 0x6C).
|
||||
- interrupt-parent : Interrupt controller to which the chip is connected.
|
||||
- interrupts : Interrupt to which the chip is connected.
|
||||
|
||||
Optional properties:
|
||||
- vdd-supply : It is the controller supply for controlling
|
||||
main voltage(3.3V) through the regulator.
|
||||
- vid-supply : It is the controller supply for controlling
|
||||
IO voltage(1.8V) through the regulator.
|
||||
- reset-gpios : Define for reset gpio pin.
|
||||
It is to use for reset IC.
|
||||
- touchscreen-size-x : X axis size of touchscreen
|
||||
- touchscreen-size-y : Y axis size of touchscreen
|
||||
- linux,keycodes : Specifies an array of numeric keycode values to
|
||||
be used for reporting button presses. The array can
|
||||
contain up to 3 entries.
|
||||
|
||||
Example:
|
||||
|
||||
#include "dt-bindings/input/input.h"
|
||||
|
||||
i2c@00000000 {
|
||||
|
||||
/* ... */
|
||||
|
||||
touchscreen@6c {
|
||||
compatible = "hideep,hideep-ts";
|
||||
reg = <0x6c>;
|
||||
interrupt-parent = <&gpx1>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
|
||||
vdd-supply = <&ldo15_reg>";
|
||||
vid-supply = <&ldo18_reg>;
|
||||
reset-gpios = <&gpx1 5 0>;
|
||||
touchscreen-size-x = <1080>;
|
||||
touchscreen-size-y = <1920>;
|
||||
linux,keycodes = <KEY_HOME>, <KEY_MENU>, <KEY_BACK>;
|
||||
};
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
* Samsung S6SY761 touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "samsung,s6sy761"
|
||||
- reg : I2C slave address, (e.g. 0x48)
|
||||
- interrupt-parent : the phandle to the interrupt controller which provides
|
||||
the interrupt
|
||||
- interrupts : interrupt specification
|
||||
- avdd-supply : analogic power supply
|
||||
- vdd-supply : power supply
|
||||
|
||||
Optional properties:
|
||||
- touchscreen-size-x : see touchscreen.txt. This property is embedded in the
|
||||
device. If defined it forces a different x resolution.
|
||||
- touchscreen-size-y : see touchscreen.txt. This property is embedded in the
|
||||
device. If defined it forces a different y resolution.
|
||||
|
||||
Example:
|
||||
|
||||
i2c@00000000 {
|
||||
|
||||
/* ... */
|
||||
|
||||
touchscreen@48 {
|
||||
compatible = "samsung,s6sy761";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpa1>;
|
||||
interrupts = <1 IRQ_TYPE_NONE>;
|
||||
avdd-supply = <&ldo30_reg>;
|
||||
vdd-supply = <&ldo31_reg>;
|
||||
touchscreen-size-x = <4096>;
|
||||
touchscreen-size-y = <4096>;
|
||||
};
|
||||
};
|
@ -137,6 +137,7 @@ gw Gateworks Corporation
|
||||
hannstar HannStar Display Corporation
|
||||
haoyu Haoyu Microelectronic Co. Ltd.
|
||||
hardkernel Hardkernel Co., Ltd
|
||||
hideep HiDeep Inc.
|
||||
himax Himax Technologies, Inc.
|
||||
hisilicon Hisilicon Limited.
|
||||
hit Hitachi Ltd.
|
||||
|
@ -412,10 +412,10 @@ static void ml_play_effects(struct ml_device *ml)
|
||||
ml_schedule_timer(ml);
|
||||
}
|
||||
|
||||
static void ml_effect_timer(unsigned long timer_data)
|
||||
static void ml_effect_timer(struct timer_list *t)
|
||||
{
|
||||
struct input_dev *dev = (struct input_dev *)timer_data;
|
||||
struct ml_device *ml = dev->ff->private;
|
||||
struct ml_device *ml = from_timer(ml, t, timer);
|
||||
struct input_dev *dev = ml->dev;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("timer: updating effects\n");
|
||||
@ -526,7 +526,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
|
||||
ml->private = data;
|
||||
ml->play_effect = play_effect;
|
||||
ml->gain = 0xffff;
|
||||
setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
|
||||
timer_setup(&ml->timer, ml_effect_timer, 0);
|
||||
|
||||
set_bit(FF_GAIN, dev->ffbit);
|
||||
|
||||
|
@ -76,7 +76,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
|
||||
{
|
||||
if (test_bit(EV_REP, dev->evbit) &&
|
||||
dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
|
||||
dev->timer.data) {
|
||||
dev->timer.function) {
|
||||
dev->repeat_key = code;
|
||||
mod_timer(&dev->timer,
|
||||
jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
|
||||
@ -179,9 +179,9 @@ static void input_pass_event(struct input_dev *dev,
|
||||
* dev->event_lock here to avoid racing with input_event
|
||||
* which may cause keys get "stuck".
|
||||
*/
|
||||
static void input_repeat_key(unsigned long data)
|
||||
static void input_repeat_key(struct timer_list *t)
|
||||
{
|
||||
struct input_dev *dev = (void *) data;
|
||||
struct input_dev *dev = from_timer(dev, t, timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
@ -1784,7 +1784,7 @@ struct input_dev *input_allocate_device(void)
|
||||
device_initialize(&dev->dev);
|
||||
mutex_init(&dev->mutex);
|
||||
spin_lock_init(&dev->event_lock);
|
||||
init_timer(&dev->timer);
|
||||
timer_setup(&dev->timer, NULL, 0);
|
||||
INIT_LIST_HEAD(&dev->h_list);
|
||||
INIT_LIST_HEAD(&dev->node);
|
||||
|
||||
@ -2047,8 +2047,7 @@ static void devm_input_device_unregister(struct device *dev, void *res)
|
||||
*/
|
||||
void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
|
||||
{
|
||||
dev->timer.data = (unsigned long) dev;
|
||||
dev->timer.function = input_repeat_key;
|
||||
dev->timer.function = (TIMER_FUNC_TYPE)input_repeat_key;
|
||||
dev->rep[REP_DELAY] = delay;
|
||||
dev->rep[REP_PERIOD] = period;
|
||||
}
|
||||
|
@ -654,6 +654,7 @@ static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
|
||||
|
||||
input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
|
||||
input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
|
||||
/* fall through */
|
||||
|
||||
case GC_PSX_NEGCON:
|
||||
case GC_PSX_ANALOG:
|
||||
@ -887,6 +888,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||
case GC_SNES:
|
||||
for (i = 4; i < 8; i++)
|
||||
__set_bit(gc_snes_btn[i], input_dev->keybit);
|
||||
/* fall through */
|
||||
case GC_NES:
|
||||
for (i = 0; i < 4; i++)
|
||||
__set_bit(gc_snes_btn[i], input_dev->keybit);
|
||||
@ -894,6 +896,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||
|
||||
case GC_MULTI2:
|
||||
__set_bit(BTN_THUMB, input_dev->keybit);
|
||||
/* fall through */
|
||||
case GC_MULTI:
|
||||
__set_bit(BTN_TRIGGER, input_dev->keybit);
|
||||
break;
|
||||
|
@ -672,16 +672,16 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||
|
||||
switch (i * m) {
|
||||
case 60:
|
||||
sw->number++;
|
||||
sw->number++; /* fall through */
|
||||
case 45: /* Ambiguous packet length */
|
||||
if (j <= 40) { /* ID length less or eq 40 -> FSP */
|
||||
case 43:
|
||||
sw->type = SW_ID_FSP;
|
||||
break;
|
||||
}
|
||||
sw->number++;
|
||||
sw->number++; /* fall through */
|
||||
case 30:
|
||||
sw->number++;
|
||||
sw->number++; /* fall through */
|
||||
case 15:
|
||||
sw->type = SW_ID_GP;
|
||||
break;
|
||||
@ -697,9 +697,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||
sw->type = SW_ID_PP;
|
||||
break;
|
||||
case 66:
|
||||
sw->bits = 3;
|
||||
sw->bits = 3; /* fall through */
|
||||
case 198:
|
||||
sw->length = 22;
|
||||
sw->length = 22; /* fall through */
|
||||
case 64:
|
||||
sw->type = SW_ID_3DP;
|
||||
if (j == 160)
|
||||
|
@ -162,6 +162,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
|
||||
break;
|
||||
}
|
||||
spaceball->escape = 0;
|
||||
/* fall through */
|
||||
case 'M':
|
||||
case 'Q':
|
||||
case 'S':
|
||||
@ -169,6 +170,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
|
||||
spaceball->escape = 0;
|
||||
data &= 0x1f;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (spaceball->escape)
|
||||
spaceball->escape = 0;
|
||||
@ -234,11 +236,13 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
|
||||
input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
|
||||
BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
|
||||
BIT_MASK(BTN_MODE);
|
||||
/* fall through */
|
||||
default:
|
||||
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
|
||||
BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
|
||||
BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
|
||||
BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
|
||||
/* fall through */
|
||||
case SPACEBALL_3003C:
|
||||
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
|
||||
BIT_MASK(BTN_8);
|
||||
|
@ -127,10 +127,9 @@ static inline void bfin_kpad_clear_irq(void)
|
||||
bfin_write_KPAD_ROWCOL(0xFFFF);
|
||||
}
|
||||
|
||||
static void bfin_kpad_timer(unsigned long data)
|
||||
static void bfin_kpad_timer(struct timer_list *t)
|
||||
{
|
||||
struct platform_device *pdev = (struct platform_device *) data;
|
||||
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
|
||||
struct bf54x_kpad *bf54x_kpad = from_timer(bf54x_kpad, t, timer);
|
||||
|
||||
if (bfin_kpad_get_keypressed(bf54x_kpad)) {
|
||||
/* Try again later */
|
||||
@ -298,7 +297,7 @@ static int bfin_kpad_probe(struct platform_device *pdev)
|
||||
|
||||
/* Init Keypad Key Up/Release test timer */
|
||||
|
||||
setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev);
|
||||
timer_setup(&bf54x_kpad->timer, bfin_kpad_timer, 0);
|
||||
|
||||
bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
|
||||
|
||||
|
@ -419,9 +419,9 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void gpio_keys_irq_timer(unsigned long _data)
|
||||
static void gpio_keys_irq_timer(struct timer_list *t)
|
||||
{
|
||||
struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
|
||||
struct gpio_button_data *bdata = from_timer(bdata, t, release_timer);
|
||||
struct input_dev *input = bdata->input;
|
||||
unsigned long flags;
|
||||
|
||||
@ -582,8 +582,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
bdata->release_delay = button->debounce_interval;
|
||||
setup_timer(&bdata->release_timer,
|
||||
gpio_keys_irq_timer, (unsigned long)bdata);
|
||||
timer_setup(&bdata->release_timer, gpio_keys_irq_timer, 0);
|
||||
|
||||
isr = gpio_keys_irq_isr;
|
||||
irqflags = 0;
|
||||
|
@ -184,9 +184,9 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad,
|
||||
/*
|
||||
* imx_keypad_check_for_events is the timer handler.
|
||||
*/
|
||||
static void imx_keypad_check_for_events(unsigned long data)
|
||||
static void imx_keypad_check_for_events(struct timer_list *t)
|
||||
{
|
||||
struct imx_keypad *keypad = (struct imx_keypad *) data;
|
||||
struct imx_keypad *keypad = from_timer(keypad, t, check_matrix_timer);
|
||||
unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
|
||||
unsigned short reg_val;
|
||||
bool state_changed, is_zero_matrix;
|
||||
@ -456,8 +456,8 @@ static int imx_keypad_probe(struct platform_device *pdev)
|
||||
keypad->irq = irq;
|
||||
keypad->stable_count = 0;
|
||||
|
||||
setup_timer(&keypad->check_matrix_timer,
|
||||
imx_keypad_check_for_events, (unsigned long) keypad);
|
||||
timer_setup(&keypad->check_matrix_timer,
|
||||
imx_keypad_check_for_events, 0);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
@ -210,9 +210,9 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
|
||||
/*
|
||||
* LoCoMo timer checking for released keys
|
||||
*/
|
||||
static void locomokbd_timer_callback(unsigned long data)
|
||||
static void locomokbd_timer_callback(struct timer_list *t)
|
||||
{
|
||||
struct locomokbd *locomokbd = (struct locomokbd *) data;
|
||||
struct locomokbd *locomokbd = from_timer(locomokbd, t, timer);
|
||||
|
||||
locomokbd_scankeyboard(locomokbd);
|
||||
}
|
||||
@ -264,8 +264,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
|
||||
|
||||
spin_lock_init(&locomokbd->lock);
|
||||
|
||||
setup_timer(&locomokbd->timer, locomokbd_timer_callback,
|
||||
(unsigned long)locomokbd);
|
||||
timer_setup(&locomokbd->timer, locomokbd_timer_callback, 0);
|
||||
|
||||
locomokbd->suspend_jiffies = jiffies;
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#undef NEW_BOARD_LEARNING_MODE
|
||||
|
||||
static void omap_kp_tasklet(unsigned long);
|
||||
static void omap_kp_timer(unsigned long);
|
||||
static void omap_kp_timer(struct timer_list *);
|
||||
|
||||
static unsigned char keypad_state[8];
|
||||
static DEFINE_MUTEX(kp_enable_mutex);
|
||||
@ -74,7 +74,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void omap_kp_timer(unsigned long data)
|
||||
static void omap_kp_timer(struct timer_list *unused)
|
||||
{
|
||||
tasklet_schedule(&kp_tasklet);
|
||||
}
|
||||
@ -233,7 +233,7 @@ static int omap_kp_probe(struct platform_device *pdev)
|
||||
col_idx = 0;
|
||||
row_idx = 0;
|
||||
|
||||
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
|
||||
timer_setup(&omap_kp->timer, omap_kp_timer, 0);
|
||||
|
||||
/* get the irq and init timer*/
|
||||
kp_tasklet.data = (unsigned long) omap_kp;
|
||||
|
@ -45,9 +45,9 @@ struct pwrkey_drv_data {
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
static void imx_imx_snvs_check_for_events(unsigned long data)
|
||||
static void imx_imx_snvs_check_for_events(struct timer_list *t)
|
||||
{
|
||||
struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
|
||||
struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer);
|
||||
struct input_dev *input = pdata->input;
|
||||
u32 state;
|
||||
|
||||
@ -134,8 +134,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
|
||||
/* clear the unexpected interrupt before driver ready */
|
||||
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
|
||||
|
||||
setup_timer(&pdata->check_timer,
|
||||
imx_imx_snvs_check_for_events, (unsigned long) pdata);
|
||||
timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input) {
|
||||
|
@ -251,9 +251,9 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
|
||||
writel(val, kbc->mmio + KBC_CONTROL_0);
|
||||
}
|
||||
|
||||
static void tegra_kbc_keypress_timer(unsigned long data)
|
||||
static void tegra_kbc_keypress_timer(struct timer_list *t)
|
||||
{
|
||||
struct tegra_kbc *kbc = (struct tegra_kbc *)data;
|
||||
struct tegra_kbc *kbc = from_timer(kbc, t, timer);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
unsigned int i;
|
||||
@ -655,7 +655,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
|
||||
timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
@ -796,7 +796,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
|
||||
|
||||
if (pdata->watermark) {
|
||||
ac->int_mask |= WATERMARK;
|
||||
if (!FIFO_MODE(pdata->fifo_mode))
|
||||
if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
|
||||
ac->pdata.fifo_mode |= FIFO_STREAM;
|
||||
} else {
|
||||
ac->int_mask |= DATA_READY;
|
||||
|
@ -31,6 +31,7 @@
|
||||
* 0.1 20/06/2002
|
||||
* - first public version
|
||||
*/
|
||||
#include <uapi/linux/uinput.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
@ -38,10 +39,47 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include "../input-compat.h"
|
||||
|
||||
#define UINPUT_NAME "uinput"
|
||||
#define UINPUT_BUFFER_SIZE 16
|
||||
#define UINPUT_NUM_REQUESTS 16
|
||||
|
||||
enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
|
||||
|
||||
struct uinput_request {
|
||||
unsigned int id;
|
||||
unsigned int code; /* UI_FF_UPLOAD, UI_FF_ERASE */
|
||||
|
||||
int retval;
|
||||
struct completion done;
|
||||
|
||||
union {
|
||||
unsigned int effect_id;
|
||||
struct {
|
||||
struct ff_effect *effect;
|
||||
struct ff_effect *old;
|
||||
} upload;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct uinput_device {
|
||||
struct input_dev *dev;
|
||||
struct mutex mutex;
|
||||
enum uinput_state state;
|
||||
wait_queue_head_t waitq;
|
||||
unsigned char ready;
|
||||
unsigned char head;
|
||||
unsigned char tail;
|
||||
struct input_event buff[UINPUT_BUFFER_SIZE];
|
||||
unsigned int ff_effects_max;
|
||||
|
||||
struct uinput_request *requests[UINPUT_NUM_REQUESTS];
|
||||
wait_queue_head_t requests_waitq;
|
||||
spinlock_t requests_lock;
|
||||
};
|
||||
|
||||
static int uinput_dev_event(struct input_dev *dev,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
@ -149,7 +187,11 @@ static int uinput_request_submit(struct uinput_device *udev,
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
wait_for_completion(&request->done);
|
||||
if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
|
||||
retval = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = request->retval;
|
||||
|
||||
out:
|
||||
@ -320,6 +362,10 @@ static int uinput_create_device(struct uinput_device *udev)
|
||||
dev->flush = uinput_dev_flush;
|
||||
}
|
||||
|
||||
dev->event = uinput_dev_event;
|
||||
|
||||
input_set_drvdata(udev->dev, udev);
|
||||
|
||||
error = input_register_device(udev->dev);
|
||||
if (error)
|
||||
goto fail2;
|
||||
@ -402,18 +448,6 @@ static int uinput_validate_absbits(struct input_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_allocate_device(struct uinput_device *udev)
|
||||
{
|
||||
udev->dev = input_allocate_device();
|
||||
if (!udev->dev)
|
||||
return -ENOMEM;
|
||||
|
||||
udev->dev->event = uinput_dev_event;
|
||||
input_set_drvdata(udev->dev, udev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_dev_setup(struct uinput_device *udev,
|
||||
struct uinput_setup __user *arg)
|
||||
{
|
||||
@ -489,9 +523,9 @@ static int uinput_setup_device_legacy(struct uinput_device *udev,
|
||||
return -EINVAL;
|
||||
|
||||
if (!udev->dev) {
|
||||
retval = uinput_allocate_device(udev);
|
||||
if (retval)
|
||||
return retval;
|
||||
udev->dev = input_allocate_device();
|
||||
if (!udev->dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev = udev->dev;
|
||||
@ -822,162 +856,163 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
|
||||
return retval;
|
||||
|
||||
if (!udev->dev) {
|
||||
retval = uinput_allocate_device(udev);
|
||||
if (retval)
|
||||
udev->dev = input_allocate_device();
|
||||
if (!udev->dev) {
|
||||
retval = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case UI_GET_VERSION:
|
||||
if (put_user(UINPUT_VERSION,
|
||||
(unsigned int __user *)p))
|
||||
retval = -EFAULT;
|
||||
case UI_GET_VERSION:
|
||||
if (put_user(UINPUT_VERSION, (unsigned int __user *)p))
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
|
||||
case UI_DEV_CREATE:
|
||||
retval = uinput_create_device(udev);
|
||||
goto out;
|
||||
|
||||
case UI_DEV_DESTROY:
|
||||
uinput_destroy_device(udev);
|
||||
goto out;
|
||||
|
||||
case UI_DEV_SETUP:
|
||||
retval = uinput_dev_setup(udev, p);
|
||||
goto out;
|
||||
|
||||
/* UI_ABS_SETUP is handled in the variable size ioctls */
|
||||
|
||||
case UI_SET_EVBIT:
|
||||
retval = uinput_set_bit(arg, evbit, EV_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_KEYBIT:
|
||||
retval = uinput_set_bit(arg, keybit, KEY_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_RELBIT:
|
||||
retval = uinput_set_bit(arg, relbit, REL_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_ABSBIT:
|
||||
retval = uinput_set_bit(arg, absbit, ABS_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_MSCBIT:
|
||||
retval = uinput_set_bit(arg, mscbit, MSC_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_LEDBIT:
|
||||
retval = uinput_set_bit(arg, ledbit, LED_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_SNDBIT:
|
||||
retval = uinput_set_bit(arg, sndbit, SND_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_FFBIT:
|
||||
retval = uinput_set_bit(arg, ffbit, FF_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_SWBIT:
|
||||
retval = uinput_set_bit(arg, swbit, SW_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_PROPBIT:
|
||||
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_PHYS:
|
||||
if (udev->state == UIST_CREATED) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phys = strndup_user(p, 1024);
|
||||
if (IS_ERR(phys)) {
|
||||
retval = PTR_ERR(phys);
|
||||
goto out;
|
||||
}
|
||||
|
||||
kfree(udev->dev->phys);
|
||||
udev->dev->phys = phys;
|
||||
goto out;
|
||||
|
||||
case UI_BEGIN_FF_UPLOAD:
|
||||
retval = uinput_ff_upload_from_user(p, &ff_up);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
case UI_DEV_CREATE:
|
||||
retval = uinput_create_device(udev);
|
||||
req = uinput_request_find(udev, ff_up.request_id);
|
||||
if (!req || req->code != UI_FF_UPLOAD ||
|
||||
!req->u.upload.effect) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ff_up.retval = 0;
|
||||
ff_up.effect = *req->u.upload.effect;
|
||||
if (req->u.upload.old)
|
||||
ff_up.old = *req->u.upload.old;
|
||||
else
|
||||
memset(&ff_up.old, 0, sizeof(struct ff_effect));
|
||||
|
||||
retval = uinput_ff_upload_to_user(p, &ff_up);
|
||||
goto out;
|
||||
|
||||
case UI_BEGIN_FF_ERASE:
|
||||
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req = uinput_request_find(udev, ff_erase.request_id);
|
||||
if (!req || req->code != UI_FF_ERASE) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ff_erase.retval = 0;
|
||||
ff_erase.effect_id = req->u.effect_id;
|
||||
if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
case UI_END_FF_UPLOAD:
|
||||
retval = uinput_ff_upload_from_user(p, &ff_up);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
case UI_DEV_DESTROY:
|
||||
uinput_destroy_device(udev);
|
||||
req = uinput_request_find(udev, ff_up.request_id);
|
||||
if (!req || req->code != UI_FF_UPLOAD ||
|
||||
!req->u.upload.effect) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
case UI_DEV_SETUP:
|
||||
retval = uinput_dev_setup(udev, p);
|
||||
req->retval = ff_up.retval;
|
||||
complete(&req->done);
|
||||
goto out;
|
||||
|
||||
case UI_END_FF_ERASE:
|
||||
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* UI_ABS_SETUP is handled in the variable size ioctls */
|
||||
|
||||
case UI_SET_EVBIT:
|
||||
retval = uinput_set_bit(arg, evbit, EV_MAX);
|
||||
req = uinput_request_find(udev, ff_erase.request_id);
|
||||
if (!req || req->code != UI_FF_ERASE) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
case UI_SET_KEYBIT:
|
||||
retval = uinput_set_bit(arg, keybit, KEY_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_RELBIT:
|
||||
retval = uinput_set_bit(arg, relbit, REL_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_ABSBIT:
|
||||
retval = uinput_set_bit(arg, absbit, ABS_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_MSCBIT:
|
||||
retval = uinput_set_bit(arg, mscbit, MSC_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_LEDBIT:
|
||||
retval = uinput_set_bit(arg, ledbit, LED_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_SNDBIT:
|
||||
retval = uinput_set_bit(arg, sndbit, SND_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_FFBIT:
|
||||
retval = uinput_set_bit(arg, ffbit, FF_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_SWBIT:
|
||||
retval = uinput_set_bit(arg, swbit, SW_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_PROPBIT:
|
||||
retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
|
||||
goto out;
|
||||
|
||||
case UI_SET_PHYS:
|
||||
if (udev->state == UIST_CREATED) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
phys = strndup_user(p, 1024);
|
||||
if (IS_ERR(phys)) {
|
||||
retval = PTR_ERR(phys);
|
||||
goto out;
|
||||
}
|
||||
|
||||
kfree(udev->dev->phys);
|
||||
udev->dev->phys = phys;
|
||||
goto out;
|
||||
|
||||
case UI_BEGIN_FF_UPLOAD:
|
||||
retval = uinput_ff_upload_from_user(p, &ff_up);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
req = uinput_request_find(udev, ff_up.request_id);
|
||||
if (!req || req->code != UI_FF_UPLOAD ||
|
||||
!req->u.upload.effect) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ff_up.retval = 0;
|
||||
ff_up.effect = *req->u.upload.effect;
|
||||
if (req->u.upload.old)
|
||||
ff_up.old = *req->u.upload.old;
|
||||
else
|
||||
memset(&ff_up.old, 0, sizeof(struct ff_effect));
|
||||
|
||||
retval = uinput_ff_upload_to_user(p, &ff_up);
|
||||
goto out;
|
||||
|
||||
case UI_BEGIN_FF_ERASE:
|
||||
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req = uinput_request_find(udev, ff_erase.request_id);
|
||||
if (!req || req->code != UI_FF_ERASE) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ff_erase.retval = 0;
|
||||
ff_erase.effect_id = req->u.effect_id;
|
||||
if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
case UI_END_FF_UPLOAD:
|
||||
retval = uinput_ff_upload_from_user(p, &ff_up);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
req = uinput_request_find(udev, ff_up.request_id);
|
||||
if (!req || req->code != UI_FF_UPLOAD ||
|
||||
!req->u.upload.effect) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req->retval = ff_up.retval;
|
||||
complete(&req->done);
|
||||
goto out;
|
||||
|
||||
case UI_END_FF_ERASE:
|
||||
if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req = uinput_request_find(udev, ff_erase.request_id);
|
||||
if (!req || req->code != UI_FF_ERASE) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req->retval = ff_erase.retval;
|
||||
complete(&req->done);
|
||||
goto out;
|
||||
req->retval = ff_erase.retval;
|
||||
complete(&req->done);
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = _IOC_SIZE(cmd);
|
||||
|
@ -1587,10 +1587,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
}
|
||||
|
||||
static void alps_flush_packet(unsigned long data)
|
||||
static void alps_flush_packet(struct timer_list *t)
|
||||
{
|
||||
struct psmouse *psmouse = (struct psmouse *)data;
|
||||
struct alps_data *priv = psmouse->private;
|
||||
struct alps_data *priv = from_timer(priv, t, timer);
|
||||
struct psmouse *psmouse = priv->psmouse;
|
||||
|
||||
serio_pause_rx(psmouse->ps2dev.serio);
|
||||
|
||||
@ -2702,7 +2702,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
{
|
||||
psmouse->private = priv;
|
||||
|
||||
setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
|
||||
timer_setup(&priv->timer, alps_flush_packet, 0);
|
||||
|
||||
priv->proto_version = protocol->version;
|
||||
priv->byte0 = protocol->byte0;
|
||||
|
@ -227,6 +227,7 @@
|
||||
|
||||
struct byd_data {
|
||||
struct timer_list timer;
|
||||
struct psmouse *psmouse;
|
||||
s32 abs_x;
|
||||
s32 abs_y;
|
||||
typeof(jiffies) last_touch_time;
|
||||
@ -251,10 +252,10 @@ static void byd_report_input(struct psmouse *psmouse)
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static void byd_clear_touch(unsigned long data)
|
||||
static void byd_clear_touch(struct timer_list *t)
|
||||
{
|
||||
struct psmouse *psmouse = (struct psmouse *)data;
|
||||
struct byd_data *priv = psmouse->private;
|
||||
struct byd_data *priv = from_timer(priv, t, timer);
|
||||
struct psmouse *psmouse = priv->psmouse;
|
||||
|
||||
serio_pause_rx(psmouse->ps2dev.serio);
|
||||
priv->touch = false;
|
||||
@ -478,7 +479,8 @@ int byd_init(struct psmouse *psmouse)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse);
|
||||
priv->psmouse = psmouse;
|
||||
timer_setup(&priv->timer, byd_clear_touch, 0);
|
||||
|
||||
psmouse->private = priv;
|
||||
psmouse->disconnect = byd_disconnect;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -1141,10 +1142,13 @@ static int elan_probe(struct i2c_client *client,
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Systems using device tree should set up interrupt via DTS,
|
||||
* the rest will use the default falling edge interrupts.
|
||||
* Platform code (ACPI, DTS) should normally set up interrupt
|
||||
* for us, but in case it did not let's fall back to using falling
|
||||
* edge to be compatible with older Chromebooks.
|
||||
*/
|
||||
irqflags = dev->of_node ? 0 : IRQF_TRIGGER_FALLING;
|
||||
irqflags = irq_get_trigger_type(client->irq);
|
||||
if (!irqflags)
|
||||
irqflags = IRQF_TRIGGER_FALLING;
|
||||
|
||||
error = devm_request_threaded_irq(dev, client->irq, NULL, elan_isr,
|
||||
irqflags | IRQF_ONESHOT,
|
||||
@ -1255,7 +1259,6 @@ static const struct acpi_device_id elan_acpi_id[] = {
|
||||
{ "ELAN0602", 0 },
|
||||
{ "ELAN0605", 0 },
|
||||
{ "ELAN0608", 0 },
|
||||
{ "ELAN0605", 0 },
|
||||
{ "ELAN0609", 0 },
|
||||
{ "ELAN060B", 0 },
|
||||
{ "ELAN060C", 0 },
|
||||
|
@ -2,6 +2,7 @@
|
||||
* Driver for simulating a mouse on GPIO lines.
|
||||
*
|
||||
* Copyright (C) 2007 Atmel Corporation
|
||||
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -11,9 +12,35 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_mouse.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/**
|
||||
* struct gpio_mouse
|
||||
* @scan_ms: the scan interval in milliseconds.
|
||||
* @up: GPIO line for up value.
|
||||
* @down: GPIO line for down value.
|
||||
* @left: GPIO line for left value.
|
||||
* @right: GPIO line for right value.
|
||||
* @bleft: GPIO line for left button.
|
||||
* @bmiddle: GPIO line for middle button.
|
||||
* @bright: GPIO line for right button.
|
||||
*
|
||||
* This struct must be added to the platform_device in the board code.
|
||||
* It is used by the gpio_mouse driver to setup GPIO lines and to
|
||||
* calculate mouse movement.
|
||||
*/
|
||||
struct gpio_mouse {
|
||||
u32 scan_ms;
|
||||
struct gpio_desc *up;
|
||||
struct gpio_desc *down;
|
||||
struct gpio_desc *left;
|
||||
struct gpio_desc *right;
|
||||
struct gpio_desc *bleft;
|
||||
struct gpio_desc *bmiddle;
|
||||
struct gpio_desc *bright;
|
||||
};
|
||||
|
||||
/*
|
||||
* Timer function which is run every scan_ms ms when the device is opened.
|
||||
@ -21,24 +48,22 @@
|
||||
*/
|
||||
static void gpio_mouse_scan(struct input_polled_dev *dev)
|
||||
{
|
||||
struct gpio_mouse_platform_data *gpio = dev->private;
|
||||
struct gpio_mouse *gpio = dev->private;
|
||||
struct input_dev *input = dev->input;
|
||||
int x, y;
|
||||
|
||||
if (gpio->bleft >= 0)
|
||||
if (gpio->bleft)
|
||||
input_report_key(input, BTN_LEFT,
|
||||
gpio_get_value(gpio->bleft) ^ gpio->polarity);
|
||||
if (gpio->bmiddle >= 0)
|
||||
gpiod_get_value(gpio->bleft));
|
||||
if (gpio->bmiddle)
|
||||
input_report_key(input, BTN_MIDDLE,
|
||||
gpio_get_value(gpio->bmiddle) ^ gpio->polarity);
|
||||
if (gpio->bright >= 0)
|
||||
gpiod_get_value(gpio->bmiddle));
|
||||
if (gpio->bright)
|
||||
input_report_key(input, BTN_RIGHT,
|
||||
gpio_get_value(gpio->bright) ^ gpio->polarity);
|
||||
gpiod_get_value(gpio->bright));
|
||||
|
||||
x = (gpio_get_value(gpio->right) ^ gpio->polarity)
|
||||
- (gpio_get_value(gpio->left) ^ gpio->polarity);
|
||||
y = (gpio_get_value(gpio->down) ^ gpio->polarity)
|
||||
- (gpio_get_value(gpio->up) ^ gpio->polarity);
|
||||
x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);
|
||||
y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up);
|
||||
|
||||
input_report_rel(input, REL_X, x);
|
||||
input_report_rel(input, REL_Y, y);
|
||||
@ -47,65 +72,61 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
|
||||
|
||||
static int gpio_mouse_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_mouse_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_mouse *gmouse;
|
||||
struct input_polled_dev *input_poll;
|
||||
struct input_dev *input;
|
||||
int pin, i;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data\n");
|
||||
error = -ENXIO;
|
||||
goto out;
|
||||
gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);
|
||||
if (!gmouse)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assign some default scanning time */
|
||||
ret = device_property_read_u32(dev, "scan-interval-ms",
|
||||
&gmouse->scan_ms);
|
||||
if (ret || gmouse->scan_ms == 0) {
|
||||
dev_warn(dev, "invalid scan time, set to 50 ms\n");
|
||||
gmouse->scan_ms = 50;
|
||||
}
|
||||
|
||||
if (pdata->scan_ms < 0) {
|
||||
dev_err(&pdev->dev, "invalid scan time\n");
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);
|
||||
if (IS_ERR(gmouse->up))
|
||||
return PTR_ERR(gmouse->up);
|
||||
gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);
|
||||
if (IS_ERR(gmouse->down))
|
||||
return PTR_ERR(gmouse->down);
|
||||
gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);
|
||||
if (IS_ERR(gmouse->left))
|
||||
return PTR_ERR(gmouse->left);
|
||||
gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);
|
||||
if (IS_ERR(gmouse->right))
|
||||
return PTR_ERR(gmouse->right);
|
||||
|
||||
for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
|
||||
pin = pdata->pins[i];
|
||||
gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);
|
||||
if (IS_ERR(gmouse->bleft))
|
||||
return PTR_ERR(gmouse->bleft);
|
||||
gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(gmouse->bmiddle))
|
||||
return PTR_ERR(gmouse->bmiddle);
|
||||
gmouse->bright = devm_gpiod_get_optional(dev, "button-right",
|
||||
GPIOD_IN);
|
||||
if (IS_ERR(gmouse->bright))
|
||||
return PTR_ERR(gmouse->bright);
|
||||
|
||||
if (pin < 0) {
|
||||
|
||||
if (i <= GPIO_MOUSE_PIN_RIGHT) {
|
||||
/* Mouse direction is required. */
|
||||
dev_err(&pdev->dev,
|
||||
"missing GPIO for directions\n");
|
||||
error = -EINVAL;
|
||||
goto out_free_gpios;
|
||||
}
|
||||
|
||||
if (i == GPIO_MOUSE_PIN_BLEFT)
|
||||
dev_dbg(&pdev->dev, "no left button defined\n");
|
||||
|
||||
} else {
|
||||
error = gpio_request(pin, "gpio_mouse");
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "fail %d pin (%d idx)\n",
|
||||
pin, i);
|
||||
goto out_free_gpios;
|
||||
}
|
||||
|
||||
gpio_direction_input(pin);
|
||||
}
|
||||
}
|
||||
|
||||
input_poll = input_allocate_polled_device();
|
||||
input_poll = devm_input_allocate_polled_device(dev);
|
||||
if (!input_poll) {
|
||||
dev_err(&pdev->dev, "not enough memory for input device\n");
|
||||
error = -ENOMEM;
|
||||
goto out_free_gpios;
|
||||
dev_err(dev, "not enough memory for input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, input_poll);
|
||||
|
||||
/* set input-polldev handlers */
|
||||
input_poll->private = pdata;
|
||||
input_poll->private = gmouse;
|
||||
input_poll->poll = gpio_mouse_scan;
|
||||
input_poll->poll_interval = pdata->scan_ms;
|
||||
input_poll->poll_interval = gmouse->scan_ms;
|
||||
|
||||
input = input_poll->input;
|
||||
input->name = pdev->name;
|
||||
@ -114,63 +135,39 @@ static int gpio_mouse_probe(struct platform_device *pdev)
|
||||
|
||||
input_set_capability(input, EV_REL, REL_X);
|
||||
input_set_capability(input, EV_REL, REL_Y);
|
||||
if (pdata->bleft >= 0)
|
||||
if (gmouse->bleft)
|
||||
input_set_capability(input, EV_KEY, BTN_LEFT);
|
||||
if (pdata->bmiddle >= 0)
|
||||
if (gmouse->bmiddle)
|
||||
input_set_capability(input, EV_KEY, BTN_MIDDLE);
|
||||
if (pdata->bright >= 0)
|
||||
if (gmouse->bright)
|
||||
input_set_capability(input, EV_KEY, BTN_RIGHT);
|
||||
|
||||
error = input_register_polled_device(input_poll);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "could not register input device\n");
|
||||
goto out_free_polldev;
|
||||
ret = input_register_polled_device(input_poll);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not register input device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n",
|
||||
pdata->scan_ms,
|
||||
pdata->bleft < 0 ? "" : "left ",
|
||||
pdata->bmiddle < 0 ? "" : "middle ",
|
||||
pdata->bright < 0 ? "" : "right");
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_polldev:
|
||||
input_free_polled_device(input_poll);
|
||||
|
||||
out_free_gpios:
|
||||
while (--i >= 0) {
|
||||
pin = pdata->pins[i];
|
||||
if (pin)
|
||||
gpio_free(pin);
|
||||
}
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gpio_mouse_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct input_polled_dev *input = platform_get_drvdata(pdev);
|
||||
struct gpio_mouse_platform_data *pdata = input->private;
|
||||
int pin, i;
|
||||
|
||||
input_unregister_polled_device(input);
|
||||
input_free_polled_device(input);
|
||||
|
||||
for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
|
||||
pin = pdata->pins[i];
|
||||
if (pin >= 0)
|
||||
gpio_free(pin);
|
||||
}
|
||||
dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",
|
||||
gmouse->scan_ms,
|
||||
gmouse->bleft ? "" : "left ",
|
||||
gmouse->bmiddle ? "" : "middle ",
|
||||
gmouse->bright ? "" : "right");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gpio_mouse_of_match[] = {
|
||||
{ .compatible = "gpio-mouse", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_mouse_of_match);
|
||||
|
||||
static struct platform_driver gpio_mouse_device_driver = {
|
||||
.probe = gpio_mouse_probe,
|
||||
.remove = gpio_mouse_remove,
|
||||
.driver = {
|
||||
.name = "gpio_mouse",
|
||||
.of_match_table = gpio_mouse_of_match,
|
||||
}
|
||||
};
|
||||
module_platform_driver(gpio_mouse_device_driver);
|
||||
@ -179,4 +176,3 @@ MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("GPIO mouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
|
||||
|
||||
|
@ -73,7 +73,7 @@ enum rmi_f54_report_type {
|
||||
F54_MAX_REPORT_TYPE,
|
||||
};
|
||||
|
||||
const char *rmi_f54_report_type_names[] = {
|
||||
static const char * const rmi_f54_report_type_names[] = {
|
||||
[F54_REPORT_NONE] = "Unknown",
|
||||
[F54_8BIT_IMAGE] = "Normalized 8-Bit Image",
|
||||
[F54_16BIT_IMAGE] = "Normalized 16-Bit Image",
|
||||
|
@ -784,7 +784,7 @@ static void hil_mlcs_process(unsigned long unused)
|
||||
|
||||
/************************* Keepalive timer task *********************/
|
||||
|
||||
static void hil_mlcs_timer(unsigned long data)
|
||||
static void hil_mlcs_timer(struct timer_list *unused)
|
||||
{
|
||||
hil_mlcs_probe = 1;
|
||||
tasklet_schedule(&hil_mlcs_tasklet);
|
||||
@ -998,7 +998,7 @@ int hil_mlc_unregister(hil_mlc *mlc)
|
||||
|
||||
static int __init hil_mlc_init(void)
|
||||
{
|
||||
setup_timer(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
|
||||
timer_setup(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
|
||||
mod_timer(&hil_mlcs_kicker, jiffies + HZ);
|
||||
|
||||
tasklet_enable(&hil_mlcs_tasklet);
|
||||
|
@ -794,7 +794,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
|
||||
|
||||
/************************* Keepalive timer task *********************/
|
||||
|
||||
static void hp_sdc_kicker(unsigned long data)
|
||||
static void hp_sdc_kicker(struct timer_list *unused)
|
||||
{
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
/* Re-insert the periodic task. */
|
||||
@ -909,9 +909,8 @@ static int __init hp_sdc_init(void)
|
||||
down(&s_sync); /* Wait for t_sync to complete */
|
||||
|
||||
/* Create the keepalive task */
|
||||
init_timer(&hp_sdc.kicker);
|
||||
timer_setup(&hp_sdc.kicker, hp_sdc_kicker, 0);
|
||||
hp_sdc.kicker.expires = jiffies + HZ;
|
||||
hp_sdc.kicker.function = &hp_sdc_kicker;
|
||||
add_timer(&hp_sdc.kicker);
|
||||
|
||||
hp_sdc.dev_err = 0;
|
||||
|
@ -366,6 +366,7 @@ static int ps2_gpio_probe(struct platform_device *pdev)
|
||||
gpiod_cansleep(drvdata->gpio_clk)) {
|
||||
dev_err(dev, "GPIO data or clk are connected via slow bus\n");
|
||||
error = -EINVAL;
|
||||
goto err_free_serio;
|
||||
}
|
||||
|
||||
drvdata->irq = platform_get_irq(pdev, 0);
|
||||
|
@ -47,6 +47,8 @@ struct ps2if {
|
||||
struct serio *io;
|
||||
struct sa1111_dev *dev;
|
||||
void __iomem *base;
|
||||
int rx_irq;
|
||||
int tx_irq;
|
||||
unsigned int open;
|
||||
spinlock_t lock;
|
||||
unsigned int head;
|
||||
@ -64,22 +66,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
|
||||
struct ps2if *ps2if = dev_id;
|
||||
unsigned int scancode, flag, status;
|
||||
|
||||
status = sa1111_readl(ps2if->base + PS2STAT);
|
||||
status = readl_relaxed(ps2if->base + PS2STAT);
|
||||
while (status & PS2STAT_RXF) {
|
||||
if (status & PS2STAT_STP)
|
||||
sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
|
||||
writel_relaxed(PS2STAT_STP, ps2if->base + PS2STAT);
|
||||
|
||||
flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
|
||||
(status & PS2STAT_RXP ? 0 : SERIO_PARITY);
|
||||
|
||||
scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
|
||||
scancode = readl_relaxed(ps2if->base + PS2DATA) & 0xff;
|
||||
|
||||
if (hweight8(scancode) & 1)
|
||||
flag ^= SERIO_PARITY;
|
||||
|
||||
serio_interrupt(ps2if->io, scancode, flag);
|
||||
|
||||
status = sa1111_readl(ps2if->base + PS2STAT);
|
||||
status = readl_relaxed(ps2if->base + PS2STAT);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -94,12 +96,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
|
||||
unsigned int status;
|
||||
|
||||
spin_lock(&ps2if->lock);
|
||||
status = sa1111_readl(ps2if->base + PS2STAT);
|
||||
status = readl_relaxed(ps2if->base + PS2STAT);
|
||||
if (ps2if->head == ps2if->tail) {
|
||||
disable_irq_nosync(irq);
|
||||
/* done */
|
||||
} else if (status & PS2STAT_TXE) {
|
||||
sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
|
||||
writel_relaxed(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
|
||||
ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
|
||||
}
|
||||
spin_unlock(&ps2if->lock);
|
||||
@ -122,11 +124,11 @@ static int ps2_write(struct serio *io, unsigned char val)
|
||||
/*
|
||||
* If the TX register is empty, we can go straight out.
|
||||
*/
|
||||
if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
|
||||
sa1111_writel(val, ps2if->base + PS2DATA);
|
||||
if (readl_relaxed(ps2if->base + PS2STAT) & PS2STAT_TXE) {
|
||||
writel_relaxed(val, ps2if->base + PS2DATA);
|
||||
} else {
|
||||
if (ps2if->head == ps2if->tail)
|
||||
enable_irq(ps2if->dev->irq[1]);
|
||||
enable_irq(ps2if->tx_irq);
|
||||
head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
|
||||
if (head != ps2if->tail) {
|
||||
ps2if->buf[ps2if->head] = val;
|
||||
@ -147,30 +149,30 @@ static int ps2_open(struct serio *io)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
|
||||
ret = request_irq(ps2if->rx_irq, ps2_rxint, 0,
|
||||
SA1111_DRIVER_NAME(ps2if->dev), ps2if);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
|
||||
ps2if->dev->irq[0], ret);
|
||||
ps2if->rx_irq, ret);
|
||||
sa1111_disable_device(ps2if->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
|
||||
ret = request_irq(ps2if->tx_irq, ps2_txint, 0,
|
||||
SA1111_DRIVER_NAME(ps2if->dev), ps2if);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
|
||||
ps2if->dev->irq[1], ret);
|
||||
free_irq(ps2if->dev->irq[0], ps2if);
|
||||
ps2if->tx_irq, ret);
|
||||
free_irq(ps2if->rx_irq, ps2if);
|
||||
sa1111_disable_device(ps2if->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ps2if->open = 1;
|
||||
|
||||
enable_irq_wake(ps2if->dev->irq[0]);
|
||||
enable_irq_wake(ps2if->rx_irq);
|
||||
|
||||
sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
|
||||
writel_relaxed(PS2CR_ENA, ps2if->base + PS2CR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -178,14 +180,14 @@ static void ps2_close(struct serio *io)
|
||||
{
|
||||
struct ps2if *ps2if = io->port_data;
|
||||
|
||||
sa1111_writel(0, ps2if->base + PS2CR);
|
||||
writel_relaxed(0, ps2if->base + PS2CR);
|
||||
|
||||
disable_irq_wake(ps2if->dev->irq[0]);
|
||||
disable_irq_wake(ps2if->rx_irq);
|
||||
|
||||
ps2if->open = 0;
|
||||
|
||||
free_irq(ps2if->dev->irq[1], ps2if);
|
||||
free_irq(ps2if->dev->irq[0], ps2if);
|
||||
free_irq(ps2if->tx_irq, ps2if);
|
||||
free_irq(ps2if->rx_irq, ps2if);
|
||||
|
||||
sa1111_disable_device(ps2if->dev);
|
||||
}
|
||||
@ -198,7 +200,7 @@ static void ps2_clear_input(struct ps2if *ps2if)
|
||||
int maxread = 100;
|
||||
|
||||
while (maxread--) {
|
||||
if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
|
||||
if ((readl_relaxed(ps2if->base + PS2DATA) & 0xff) == 0xff)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -208,11 +210,11 @@ static unsigned int ps2_test_one(struct ps2if *ps2if,
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
|
||||
writel_relaxed(PS2CR_ENA | mask, ps2if->base + PS2CR);
|
||||
|
||||
udelay(2);
|
||||
udelay(10);
|
||||
|
||||
val = sa1111_readl(ps2if->base + PS2STAT);
|
||||
val = readl_relaxed(ps2if->base + PS2STAT);
|
||||
return val & (PS2STAT_KBC | PS2STAT_KBD);
|
||||
}
|
||||
|
||||
@ -243,7 +245,7 @@ static int ps2_test(struct ps2if *ps2if)
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
sa1111_writel(0, ps2if->base + PS2CR);
|
||||
writel_relaxed(0, ps2if->base + PS2CR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -264,7 +266,6 @@ static int ps2_probe(struct sa1111_dev *dev)
|
||||
goto free;
|
||||
}
|
||||
|
||||
|
||||
serio->id.type = SERIO_8042;
|
||||
serio->write = ps2_write;
|
||||
serio->open = ps2_open;
|
||||
@ -279,6 +280,18 @@ static int ps2_probe(struct sa1111_dev *dev)
|
||||
|
||||
spin_lock_init(&ps2if->lock);
|
||||
|
||||
ps2if->rx_irq = sa1111_get_irq(dev, 0);
|
||||
if (ps2if->rx_irq <= 0) {
|
||||
ret = ps2if->rx_irq ? : -ENXIO;
|
||||
goto free;
|
||||
}
|
||||
|
||||
ps2if->tx_irq = sa1111_get_irq(dev, 1);
|
||||
if (ps2if->tx_irq <= 0) {
|
||||
ret = ps2if->tx_irq ? : -ENXIO;
|
||||
goto free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request the physical region for this PS2 port.
|
||||
*/
|
||||
@ -297,8 +310,8 @@ static int ps2_probe(struct sa1111_dev *dev)
|
||||
sa1111_enable_device(ps2if->dev);
|
||||
|
||||
/* Incoming clock is 8MHz */
|
||||
sa1111_writel(0, ps2if->base + PS2CLKDIV);
|
||||
sa1111_writel(127, ps2if->base + PS2PRECNT);
|
||||
writel_relaxed(0, ps2if->base + PS2CLKDIV);
|
||||
writel_relaxed(127, ps2if->base + PS2PRECNT);
|
||||
|
||||
/*
|
||||
* Flush any pending input.
|
||||
|
@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called egalax_ts_serial.
|
||||
|
||||
config TOUCHSCREEN_EXC3000
|
||||
tristate "EETI EXC3000 multi-touch panel support"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to enable support for I2C connected EETI
|
||||
EXC3000 multi-touch panels.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called exc3000.
|
||||
|
||||
config TOUCHSCREEN_FUJITSU
|
||||
tristate "Fujitsu serial touchscreen"
|
||||
select SERIO
|
||||
@ -344,6 +354,17 @@ config TOUCHSCREEN_GOODIX
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called goodix.
|
||||
|
||||
config TOUCHSCREEN_HIDEEP
|
||||
tristate "HiDeep Touch IC"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have a touchscreen using HiDeep.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a moudle, choose M here : the
|
||||
module will be called hideep_ts.
|
||||
|
||||
config TOUCHSCREEN_ILI210X
|
||||
tristate "Ilitek ILI210X based touchscreen"
|
||||
depends on I2C
|
||||
@ -383,6 +404,17 @@ config TOUCHSCREEN_S3C2410
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called s3c2410_ts.
|
||||
|
||||
config TOUCHSCREEN_S6SY761
|
||||
tristate "Samsung S6SY761 Touchscreen driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y if you have the Samsung S6SY761 driver
|
||||
|
||||
If unsure, say N
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called s6sy761.
|
||||
|
||||
config TOUCHSCREEN_GUNZE
|
||||
tristate "Gunze AHL-51S touchscreen"
|
||||
select SERIO
|
||||
@ -949,7 +981,7 @@ config TOUCHSCREEN_USB_NEXIO
|
||||
|
||||
config TOUCHSCREEN_USB_EASYTOUCH
|
||||
default y
|
||||
bool "EasyTouch USB Touch controller device support" if EMBEDDED
|
||||
bool "EasyTouch USB Touch controller device support" if EXPERT
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
help
|
||||
Say Y here if you have an EasyTouch USB Touch controller.
|
||||
|
@ -38,8 +38,10 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
|
||||
@ -65,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
|
||||
|
@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static void ad7877_timer(unsigned long handle)
|
||||
static void ad7877_timer(struct timer_list *t)
|
||||
{
|
||||
struct ad7877 *ts = (void *)handle;
|
||||
struct ad7877 *ts = from_timer(ts, t, timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ts->lock, flags);
|
||||
@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi)
|
||||
ts->spi = spi;
|
||||
ts->input = input_dev;
|
||||
|
||||
setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts);
|
||||
timer_setup(&ts->timer, ad7877_timer, 0);
|
||||
mutex_init(&ts->mutex);
|
||||
spin_lock_init(&ts->lock);
|
||||
|
||||
|
@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static void ad7879_timer(unsigned long handle)
|
||||
static void ad7879_timer(struct timer_list *t)
|
||||
{
|
||||
struct ad7879 *ts = (void *)handle;
|
||||
struct ad7879 *ts = from_timer(ts, t, timer);
|
||||
|
||||
ad7879_ts_event_release(ts);
|
||||
}
|
||||
@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad7879_cleanup_sysfs(void *_ts)
|
||||
{
|
||||
struct ad7879 *ts = _ts;
|
||||
|
||||
sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
|
||||
}
|
||||
|
||||
int ad7879_probe(struct device *dev, struct regmap *regmap,
|
||||
int irq, u16 bustype, u8 devid)
|
||||
{
|
||||
@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
|
||||
ts->irq = irq;
|
||||
ts->regmap = regmap;
|
||||
|
||||
setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
|
||||
timer_setup(&ts->timer, ad7879_timer, 0);
|
||||
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
|
||||
|
||||
input_dev->name = "AD7879 Touchscreen";
|
||||
@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
|
||||
|
||||
__ad7879_disable(ts);
|
||||
|
||||
err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts);
|
||||
err = devm_device_add_group(dev, &ad7879_attr_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -208,9 +208,12 @@ static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
|
||||
}
|
||||
}
|
||||
|
||||
static void atmel_wm97xx_pen_timer(unsigned long data)
|
||||
static void atmel_wm97xx_pen_timer(struct timer_list *t)
|
||||
{
|
||||
atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
|
||||
struct atmel_wm97xx *atmel_wm97xx = from_timer(atmel_wm97xx, t,
|
||||
pen_timer);
|
||||
|
||||
atmel_wm97xx_acc_pen_up(atmel_wm97xx->wm);
|
||||
}
|
||||
|
||||
static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
|
||||
@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
|
||||
atmel_wm97xx->gpio_pen = atmel_gpio_line;
|
||||
atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
|
||||
|
||||
setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
|
||||
(unsigned long)wm);
|
||||
timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0);
|
||||
|
||||
ret = request_irq(atmel_wm97xx->ac97c_irq,
|
||||
atmel_wm97xx_channel_b_interrupt,
|
||||
|
@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
|
||||
dev_err(cd->dev,
|
||||
"%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
|
||||
__func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
|
||||
dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
|
||||
si->si_ofs.cydata_size);
|
||||
|
||||
p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__);
|
||||
dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
si->si_ptrs.cydata = p;
|
||||
@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
|
||||
dev_err(cd->dev,
|
||||
"%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
|
||||
__func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
|
||||
|
||||
p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(cd->dev, "%s: fail alloc test memory\n", __func__);
|
||||
dev_err(cd->dev, "%s: failed to allocate test memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
si->si_ptrs.test = p;
|
||||
@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
|
||||
dev_err(cd->dev,
|
||||
"%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
|
||||
__func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
|
||||
|
||||
p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
rc = -ENOMEM;
|
||||
dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n",
|
||||
__func__, rc);
|
||||
return rc;
|
||||
dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
si->si_ptrs.pcfg = p;
|
||||
|
||||
@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
|
||||
void *p;
|
||||
int rc;
|
||||
|
||||
if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
|
||||
dev_err(cd->dev,
|
||||
"%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
|
||||
__func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
|
||||
|
||||
p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto cyttsp4_si_get_opcfg_data_exit;
|
||||
dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
si->si_ptrs.opcfg = p;
|
||||
|
||||
@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
|
||||
if (rc < 0) {
|
||||
dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
|
||||
__func__, rc);
|
||||
goto cyttsp4_si_get_opcfg_data_exit;
|
||||
return rc;
|
||||
}
|
||||
si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
|
||||
si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
|
||||
@ -447,8 +476,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
|
||||
cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
|
||||
si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
|
||||
|
||||
cyttsp4_si_get_opcfg_data_exit:
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
|
||||
@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
|
||||
del_timer_sync(&cd->watchdog_timer);
|
||||
}
|
||||
|
||||
static void cyttsp4_watchdog_timer(unsigned long handle)
|
||||
static void cyttsp4_watchdog_timer(struct timer_list *t)
|
||||
{
|
||||
struct cyttsp4 *cd = (struct cyttsp4 *)handle;
|
||||
struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
|
||||
|
||||
dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
|
||||
|
||||
@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
|
||||
}
|
||||
|
||||
/* Setup watchdog timer */
|
||||
setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer,
|
||||
(unsigned long)cd);
|
||||
timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
|
||||
|
||||
/*
|
||||
* call startup directly to ensure that the device
|
||||
|
@ -70,8 +70,10 @@
|
||||
#define EDT_RAW_DATA_DELAY 1000 /* usec */
|
||||
|
||||
enum edt_ver {
|
||||
M06,
|
||||
M09,
|
||||
EDT_M06,
|
||||
EDT_M09,
|
||||
EDT_M12,
|
||||
GENERIC_FT,
|
||||
};
|
||||
|
||||
struct edt_reg_addr {
|
||||
@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
||||
int error;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
cmd = 0xf9; /* tell the controller to send touch data */
|
||||
offset = 5; /* where the actual touch data starts */
|
||||
tplen = 4; /* data comes in so called frames */
|
||||
crclen = 1; /* length of the crc data */
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
cmd = 0x0;
|
||||
offset = 3;
|
||||
tplen = 6;
|
||||
@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* M09 does not send header or CRC */
|
||||
if (tsdata->version == M06) {
|
||||
/* M09/M12 does not send header or CRC */
|
||||
if (tsdata->version == EDT_M06) {
|
||||
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
|
||||
rdbuf[2] != datalen) {
|
||||
dev_err_ratelimited(dev,
|
||||
@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
||||
continue;
|
||||
|
||||
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
|
||||
if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
|
||||
if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
|
||||
continue;
|
||||
|
||||
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
|
||||
@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
|
||||
u8 wrbuf[4];
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
|
||||
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
|
||||
wrbuf[2] = value;
|
||||
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
|
||||
return edt_ft5x06_ts_readwrite(tsdata->client, 4,
|
||||
wrbuf, 0, NULL);
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
wrbuf[1] = value;
|
||||
|
||||
@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
|
||||
int error;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
|
||||
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
|
||||
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
|
||||
@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
|
||||
}
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
|
||||
wrbuf, 1, rdbuf);
|
||||
@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
|
||||
}
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
addr = attr->addr_m06;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
addr = attr->addr_m09;
|
||||
break;
|
||||
|
||||
@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
|
||||
}
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
addr = attr->addr_m06;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
case GENERIC_FT:
|
||||
addr = attr->addr_m09;
|
||||
break;
|
||||
|
||||
@ -466,14 +478,18 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
|
||||
return error ?: count;
|
||||
}
|
||||
|
||||
/* m06, m09: range 0-31, m12: range 0-5 */
|
||||
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
|
||||
M09_REGISTER_GAIN, 0, 31);
|
||||
/* m06, m09: range 0-31, m12: range 0-16 */
|
||||
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
|
||||
M09_REGISTER_OFFSET, 0, 31);
|
||||
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
|
||||
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
|
||||
M09_REGISTER_THRESHOLD, 0, 80);
|
||||
M09_REGISTER_THRESHOLD, 0, 255);
|
||||
/* m06: range 3 to 14, m12: (0x64: 100Hz) */
|
||||
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
|
||||
NO_REGISTER, 3, 14);
|
||||
NO_REGISTER, 0, 255);
|
||||
|
||||
static struct attribute *edt_ft5x06_attrs[] = {
|
||||
&edt_ft5x06_attr_gain.dattr.attr,
|
||||
@ -508,7 +524,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
||||
}
|
||||
|
||||
/* mode register is 0x3c when in the work mode */
|
||||
if (tsdata->version == M09)
|
||||
if (tsdata->version != EDT_M06)
|
||||
goto m09_out;
|
||||
|
||||
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
|
||||
@ -545,7 +561,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
||||
return error;
|
||||
|
||||
m09_out:
|
||||
dev_err(&client->dev, "No factory mode support for M09\n");
|
||||
dev_err(&client->dev, "No factory mode support for M09/M12/GENERIC_FT\n");
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
||||
* to have garbage in there
|
||||
*/
|
||||
memset(rdbuf, 0, sizeof(rdbuf));
|
||||
error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
|
||||
error = edt_ft5x06_ts_readwrite(client, 1, "\xBB",
|
||||
EDT_NAME_LEN - 1, rdbuf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* if we find something consistent, stay with that assumption
|
||||
* at least M09 won't send 3 bytes here
|
||||
/* Probe content for something consistent.
|
||||
* M06 starts with a response byte, M12 gives the data directly.
|
||||
* M09/Generic does not provide model number information.
|
||||
*/
|
||||
if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
|
||||
tsdata->version = M06;
|
||||
if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
|
||||
tsdata->version = EDT_M06;
|
||||
|
||||
/* remove last '$' end marker */
|
||||
rdbuf[EDT_NAME_LEN - 1] = '\0';
|
||||
@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
||||
*p++ = '\0';
|
||||
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
|
||||
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
||||
} else if (!strncasecmp(rdbuf, "EP0", 3)) {
|
||||
tsdata->version = EDT_M12;
|
||||
|
||||
/* remove last '$' end marker */
|
||||
rdbuf[EDT_NAME_LEN - 2] = '\0';
|
||||
if (rdbuf[EDT_NAME_LEN - 3] == '$')
|
||||
rdbuf[EDT_NAME_LEN - 3] = '\0';
|
||||
|
||||
/* look for Model/Version separator */
|
||||
p = strchr(rdbuf, '*');
|
||||
if (p)
|
||||
*p++ = '\0';
|
||||
strlcpy(model_name, rdbuf, EDT_NAME_LEN);
|
||||
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
||||
} else {
|
||||
/* since there are only two versions around (M06, M09) */
|
||||
tsdata->version = M09;
|
||||
/* If it is not an EDT M06/M12 touchscreen, then the model
|
||||
* detection is a bit hairy. The different ft5x06
|
||||
* firmares around don't reliably implement the
|
||||
* identification registers. Well, we'll take a shot.
|
||||
*
|
||||
* The main difference between generic focaltec based
|
||||
* touches and EDT M09 is that we know how to retrieve
|
||||
* the max coordinates for the latter.
|
||||
*/
|
||||
tsdata->version = GENERIC_FT;
|
||||
|
||||
error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
|
||||
2, rdbuf);
|
||||
@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
/* This "model identification" is not exact. Unfortunately
|
||||
* not all firmwares for the ft5x06 put useful values in
|
||||
* the identification registers.
|
||||
*/
|
||||
switch (rdbuf[0]) {
|
||||
case 0x35: /* EDT EP0350M09 */
|
||||
case 0x43: /* EDT EP0430M09 */
|
||||
case 0x50: /* EDT EP0500M09 */
|
||||
case 0x57: /* EDT EP0570M09 */
|
||||
case 0x70: /* EDT EP0700M09 */
|
||||
tsdata->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0xa1: /* EDT EP1010ML00 */
|
||||
tsdata->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0x5a: /* Solomon Goldentek Display */
|
||||
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
|
||||
break;
|
||||
default:
|
||||
snprintf(model_name, EDT_NAME_LEN,
|
||||
"generic ft5x06 (%02x)",
|
||||
rdbuf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
|
||||
if (reg_addr->reg_report_rate != NO_REGISTER)
|
||||
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_report_rate);
|
||||
tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
|
||||
tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
|
||||
if (tsdata->version == EDT_M06 ||
|
||||
tsdata->version == EDT_M09 ||
|
||||
tsdata->version == EDT_M12) {
|
||||
tsdata->num_x = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_num_x);
|
||||
tsdata->num_y = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_num_y);
|
||||
} else {
|
||||
tsdata->num_x = -1;
|
||||
tsdata->num_y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
||||
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
|
||||
reg_addr->reg_gain = WORK_REGISTER_GAIN;
|
||||
@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
||||
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case EDT_M12:
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = NO_REGISTER;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
@ -880,6 +955,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
||||
reg_addr->reg_num_x = M09_REGISTER_NUM_X;
|
||||
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case GENERIC_FT:
|
||||
/* this is a guesswork */
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
reg_addr->reg_offset = M09_REGISTER_OFFSET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -969,10 +1051,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->dev.parent = &client->dev;
|
||||
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, tsdata->num_x * 64 - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, tsdata->num_y * 64 - 1, 0, 0);
|
||||
if (tsdata->version == EDT_M06 ||
|
||||
tsdata->version == EDT_M09 ||
|
||||
tsdata->version == EDT_M12) {
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, tsdata->num_x * 64 - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, tsdata->num_y * 64 - 1, 0, 0);
|
||||
} else {
|
||||
/* Unknown maximum values. Specify via devicetree */
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, 65535, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, 65535, 0, 0);
|
||||
}
|
||||
|
||||
touchscreen_parse_properties(input, true, &tsdata->prop);
|
||||
|
||||
@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
|
||||
error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
goto err_remove_attrs;
|
||||
return error;
|
||||
|
||||
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
|
||||
device_init_wakeup(&client->dev, 1);
|
||||
@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
||||
tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_attrs:
|
||||
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int edt_ft5x06_ts_remove(struct i2c_client *client)
|
||||
@ -1027,7 +1115,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
|
||||
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
|
||||
|
||||
edt_ft5x06_ts_teardown_debugfs(tsdata);
|
||||
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = {
|
||||
.attrs = elants_attributes,
|
||||
};
|
||||
|
||||
static void elants_i2c_remove_sysfs_group(void *_data)
|
||||
{
|
||||
struct elants_data *ts = _data;
|
||||
|
||||
sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group);
|
||||
}
|
||||
|
||||
static int elants_i2c_power_on(struct elants_data *ts)
|
||||
{
|
||||
int error;
|
||||
@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client,
|
||||
if (!client->dev.of_node)
|
||||
device_init_wakeup(&client->dev, true);
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group);
|
||||
error = devm_device_add_group(&client->dev, &elants_attribute_group);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(&client->dev,
|
||||
elants_i2c_remove_sysfs_group, ts);
|
||||
if (error) {
|
||||
elants_i2c_remove_sysfs_group(ts);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
223
drivers/input/touchscreen/exc3000.c
Normal file
223
drivers/input/touchscreen/exc3000.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Driver for I2C connected EETI EXC3000 multiple touch controller
|
||||
*
|
||||
* Copyright (C) 2017 Ahmet Inan <inan@distec.de>
|
||||
*
|
||||
* minimal implementation based on egalax_ts.c and egalax_i2c.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define EXC3000_NUM_SLOTS 10
|
||||
#define EXC3000_SLOTS_PER_FRAME 5
|
||||
#define EXC3000_LEN_FRAME 66
|
||||
#define EXC3000_LEN_POINT 10
|
||||
#define EXC3000_MT_EVENT 6
|
||||
#define EXC3000_TIMEOUT_MS 100
|
||||
|
||||
struct exc3000_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct touchscreen_properties prop;
|
||||
struct timer_list timer;
|
||||
u8 buf[2 * EXC3000_LEN_FRAME];
|
||||
};
|
||||
|
||||
static void exc3000_report_slots(struct input_dev *input,
|
||||
struct touchscreen_properties *prop,
|
||||
const u8 *buf, int num)
|
||||
{
|
||||
for (; num--; buf += EXC3000_LEN_POINT) {
|
||||
if (buf[0] & BIT(0)) {
|
||||
input_mt_slot(input, buf[1]);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
|
||||
touchscreen_report_pos(input, prop,
|
||||
get_unaligned_le16(buf + 2),
|
||||
get_unaligned_le16(buf + 4),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void exc3000_timer(struct timer_list *t)
|
||||
{
|
||||
struct exc3000_data *data = from_timer(data, t, timer);
|
||||
|
||||
input_mt_sync_frame(data->input);
|
||||
input_sync(data->input);
|
||||
}
|
||||
|
||||
static int exc3000_read_frame(struct i2c_client *client, u8 *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_master_send(client, "'", 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != 2)
|
||||
return -EIO;
|
||||
|
||||
ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != EXC3000_LEN_FRAME)
|
||||
return -EIO;
|
||||
|
||||
if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME ||
|
||||
buf[2] != EXC3000_MT_EVENT)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exc3000_read_data(struct i2c_client *client,
|
||||
u8 *buf, int *n_slots)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = exc3000_read_frame(client, buf);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
*n_slots = buf[3];
|
||||
if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS)
|
||||
return -EINVAL;
|
||||
|
||||
if (*n_slots > EXC3000_SLOTS_PER_FRAME) {
|
||||
/* Read 2nd frame to get the rest of the contacts. */
|
||||
error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* 2nd chunk must have number of contacts set to 0. */
|
||||
if (buf[EXC3000_LEN_FRAME + 3] != 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct exc3000_data *data = dev_id;
|
||||
struct input_dev *input = data->input;
|
||||
u8 *buf = data->buf;
|
||||
int slots, total_slots;
|
||||
int error;
|
||||
|
||||
error = exc3000_read_data(data->client, buf, &total_slots);
|
||||
if (error) {
|
||||
/* Schedule a timer to release "stuck" contacts */
|
||||
mod_timer(&data->timer,
|
||||
jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We read full state successfully, no contacts will be "stuck".
|
||||
*/
|
||||
del_timer_sync(&data->timer);
|
||||
|
||||
while (total_slots > 0) {
|
||||
slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
|
||||
exc3000_report_slots(input, &data->prop, buf + 4, slots);
|
||||
total_slots -= slots;
|
||||
buf += EXC3000_LEN_FRAME;
|
||||
}
|
||||
|
||||
input_mt_sync_frame(input);
|
||||
input_sync(input);
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int exc3000_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct exc3000_data *data;
|
||||
struct input_dev *input;
|
||||
int error;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
timer_setup(&data->timer, exc3000_timer, 0);
|
||||
|
||||
input = devm_input_allocate_device(&client->dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
data->input = input;
|
||||
|
||||
input->name = "EETI EXC3000 Touch Screen";
|
||||
input->id.bustype = BUS_I2C;
|
||||
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
|
||||
touchscreen_parse_properties(input, true, &data->prop);
|
||||
|
||||
error = input_mt_init_slots(input, EXC3000_NUM_SLOTS,
|
||||
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, exc3000_interrupt, IRQF_ONESHOT,
|
||||
client->name, data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id exc3000_id[] = {
|
||||
{ "exc3000", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, exc3000_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id exc3000_of_match[] = {
|
||||
{ .compatible = "eeti,exc3000" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exc3000_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver exc3000_driver = {
|
||||
.driver = {
|
||||
.name = "exc3000",
|
||||
.of_match_table = of_match_ptr(exc3000_of_match),
|
||||
},
|
||||
.id_table = exc3000_id,
|
||||
.probe = exc3000_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(exc3000_driver);
|
||||
|
||||
MODULE_AUTHOR("Ahmet Inan <inan@distec.de>");
|
||||
MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -31,9 +31,18 @@
|
||||
#include <linux/of.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
struct goodix_ts_data;
|
||||
|
||||
struct goodix_chip_data {
|
||||
u16 config_addr;
|
||||
int config_len;
|
||||
int (*check_config)(struct goodix_ts_data *, const struct firmware *);
|
||||
};
|
||||
|
||||
struct goodix_ts_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
const struct goodix_chip_data *chip;
|
||||
int abs_x_max;
|
||||
int abs_y_max;
|
||||
bool swapped_x_y;
|
||||
@ -41,7 +50,6 @@ struct goodix_ts_data {
|
||||
bool inverted_y;
|
||||
unsigned int max_touch_num;
|
||||
unsigned int int_trigger_type;
|
||||
int cfg_len;
|
||||
struct gpio_desc *gpiod_int;
|
||||
struct gpio_desc *gpiod_rst;
|
||||
u16 id;
|
||||
@ -69,7 +77,8 @@ struct goodix_ts_data {
|
||||
#define GOODIX_CMD_SCREEN_OFF 0x05
|
||||
|
||||
#define GOODIX_READ_COOR_ADDR 0x814E
|
||||
#define GOODIX_REG_CONFIG_DATA 0x8047
|
||||
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
|
||||
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
|
||||
#define GOODIX_REG_ID 0x8140
|
||||
|
||||
#define GOODIX_BUFFER_STATUS_READY BIT(7)
|
||||
@ -79,6 +88,35 @@ struct goodix_ts_data {
|
||||
#define MAX_CONTACTS_LOC 5
|
||||
#define TRIGGER_LOC 6
|
||||
|
||||
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg);
|
||||
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg);
|
||||
|
||||
static const struct goodix_chip_data gt1x_chip_data = {
|
||||
.config_addr = GOODIX_GT1X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
.check_config = goodix_check_cfg_16,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt911_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_911_LENGTH,
|
||||
.check_config = goodix_check_cfg_8,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt967_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_967_LENGTH,
|
||||
.check_config = goodix_check_cfg_8,
|
||||
};
|
||||
|
||||
static const struct goodix_chip_data gt9x_chip_data = {
|
||||
.config_addr = GOODIX_GT9X_REG_CONFIG_DATA,
|
||||
.config_len = GOODIX_CONFIG_MAX_LENGTH,
|
||||
.check_config = goodix_check_cfg_8,
|
||||
};
|
||||
|
||||
static const unsigned long goodix_irq_flags[] = {
|
||||
IRQ_TYPE_EDGE_RISING,
|
||||
IRQ_TYPE_EDGE_FALLING,
|
||||
@ -177,22 +215,25 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
|
||||
return goodix_i2c_write(client, reg, &value, sizeof(value));
|
||||
}
|
||||
|
||||
static int goodix_get_cfg_len(u16 id)
|
||||
static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
|
||||
{
|
||||
switch (id) {
|
||||
case 1151:
|
||||
return >1x_chip_data;
|
||||
|
||||
case 911:
|
||||
case 9271:
|
||||
case 9110:
|
||||
case 927:
|
||||
case 928:
|
||||
return GOODIX_CONFIG_911_LENGTH;
|
||||
return >911_chip_data;
|
||||
|
||||
case 912:
|
||||
case 967:
|
||||
return GOODIX_CONFIG_967_LENGTH;
|
||||
return >967_chip_data;
|
||||
|
||||
default:
|
||||
return GOODIX_CONFIG_MAX_LENGTH;
|
||||
return >9x_chip_data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts)
|
||||
ts->irq_flags, ts->client->name, ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_check_cfg - Checks if config fw is valid
|
||||
*
|
||||
* @ts: goodix_ts_data pointer
|
||||
* @cfg: firmware config data
|
||||
*/
|
||||
static int goodix_check_cfg(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg)
|
||||
static int goodix_check_cfg_8(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg)
|
||||
{
|
||||
int i, raw_cfg_len;
|
||||
int i, raw_cfg_len = cfg->size - 2;
|
||||
u8 check_sum = 0;
|
||||
|
||||
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
|
||||
dev_err(&ts->client->dev,
|
||||
"The length of the config fw is not correct");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
raw_cfg_len = cfg->size - 2;
|
||||
for (i = 0; i < raw_cfg_len; i++)
|
||||
check_sum += cfg->data[i];
|
||||
check_sum = (~check_sum) + 1;
|
||||
@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int goodix_check_cfg_16(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg)
|
||||
{
|
||||
int i, raw_cfg_len = cfg->size - 3;
|
||||
u16 check_sum = 0;
|
||||
|
||||
for (i = 0; i < raw_cfg_len; i += 2)
|
||||
check_sum += get_unaligned_be16(&cfg->data[i]);
|
||||
check_sum = (~check_sum) + 1;
|
||||
if (check_sum != get_unaligned_be16(&cfg->data[raw_cfg_len])) {
|
||||
dev_err(&ts->client->dev,
|
||||
"The checksum of the config fw is not correct");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg->data[raw_cfg_len + 2] != 1) {
|
||||
dev_err(&ts->client->dev,
|
||||
"Config fw must have Config_Fresh register set");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_check_cfg - Checks if config fw is valid
|
||||
*
|
||||
* @ts: goodix_ts_data pointer
|
||||
* @cfg: firmware config data
|
||||
*/
|
||||
static int goodix_check_cfg(struct goodix_ts_data *ts,
|
||||
const struct firmware *cfg)
|
||||
{
|
||||
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
|
||||
dev_err(&ts->client->dev,
|
||||
"The length of the config fw is not correct");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ts->chip->check_config(ts, cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_send_cfg - Write fw config to device
|
||||
*
|
||||
@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
|
||||
error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg->data,
|
||||
cfg->size);
|
||||
if (error) {
|
||||
dev_err(&ts->client->dev, "Failed to write config data: %d",
|
||||
@ -511,8 +581,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
|
||||
u8 config[GOODIX_CONFIG_MAX_LENGTH];
|
||||
int error;
|
||||
|
||||
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
|
||||
config, ts->cfg_len);
|
||||
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
|
||||
config, ts->chip->config_len);
|
||||
if (error) {
|
||||
dev_warn(&ts->client->dev,
|
||||
"Error reading config (%d), using defaults\n",
|
||||
@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client)
|
||||
u8 test;
|
||||
|
||||
while (retry++ < 2) {
|
||||
error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA,
|
||||
error = goodix_i2c_read(client, GOODIX_REG_ID,
|
||||
&test, 1);
|
||||
if (!error)
|
||||
return 0;
|
||||
@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
ts->cfg_len = goodix_get_cfg_len(ts->id);
|
||||
ts->chip = goodix_get_chip_data(ts->id);
|
||||
|
||||
if (ts->gpiod_int && ts->gpiod_rst) {
|
||||
/* update device config */
|
||||
@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id goodix_of_match[] = {
|
||||
{ .compatible = "goodix,gt1151" },
|
||||
{ .compatible = "goodix,gt911" },
|
||||
{ .compatible = "goodix,gt9110" },
|
||||
{ .compatible = "goodix,gt912" },
|
||||
|
1120
drivers/input/touchscreen/hideep.c
Normal file
1120
drivers/input/touchscreen/hideep.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = {
|
||||
.attrs = mip4_attrs,
|
||||
};
|
||||
|
||||
static void mip4_sysfs_remove(void *_data)
|
||||
{
|
||||
struct mip4_ts *ts = _data;
|
||||
|
||||
sysfs_remove_group(&ts->client->dev.kobj, &mip4_attr_group);
|
||||
}
|
||||
|
||||
static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct mip4_ts *ts;
|
||||
@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj, &mip4_attr_group);
|
||||
error = devm_device_add_group(&client->dev, &mip4_attr_group);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to create sysfs attribute group: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(&client->dev, mip4_sysfs_remove, ts);
|
||||
if (error) {
|
||||
mip4_sysfs_remove(ts);
|
||||
dev_err(&client->dev,
|
||||
"Failed to install sysfs remoce action: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -584,7 +584,7 @@ static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts)
|
||||
|
||||
static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
|
||||
{
|
||||
struct input_dev *input = ts->ts_input;
|
||||
struct input_dev *input;
|
||||
struct device *dev = ts->dev;
|
||||
|
||||
input = devm_input_allocate_device(dev);
|
||||
|
@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = {
|
||||
.attrs = raydium_i2c_attributes,
|
||||
};
|
||||
|
||||
static void raydium_i2c_remove_sysfs_group(void *_data)
|
||||
{
|
||||
struct raydium_data *ts = _data;
|
||||
|
||||
sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group);
|
||||
}
|
||||
|
||||
static int raydium_i2c_power_on(struct raydium_data *ts)
|
||||
{
|
||||
int error;
|
||||
@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj,
|
||||
error = devm_device_add_group(&client->dev,
|
||||
&raydium_i2c_attribute_group);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
|
||||
@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(&client->dev,
|
||||
raydium_i2c_remove_sysfs_group, ts);
|
||||
if (error) {
|
||||
raydium_i2c_remove_sysfs_group(ts);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev)
|
||||
ts->initialized = false;
|
||||
}
|
||||
|
||||
static void rohm_ts_remove_sysfs_group(void *_dev)
|
||||
{
|
||||
struct device *dev = _dev;
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group);
|
||||
}
|
||||
|
||||
static int rohm_bu21023_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group);
|
||||
error = devm_device_add_group(dev, &rohm_ts_attr_group);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to create sysfs group: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev);
|
||||
if (error) {
|
||||
rohm_ts_remove_sysfs_group(dev);
|
||||
dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
559
drivers/input/touchscreen/s6sy761.c
Normal file
559
drivers/input/touchscreen/s6sy761.c
Normal file
@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||||
* Author: Andi Shyti <andi.shyti@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Samsung S6SY761 Touchscreen device driver
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* commands */
|
||||
#define S6SY761_SENSE_ON 0x10
|
||||
#define S6SY761_SENSE_OFF 0x11
|
||||
#define S6SY761_TOUCH_FUNCTION 0x30 /* R/W for get/set */
|
||||
#define S6SY761_FIRMWARE_INTEGRITY 0x21
|
||||
#define S6SY761_PANEL_INFO 0x23
|
||||
#define S6SY761_DEVICE_ID 0x52
|
||||
#define S6SY761_BOOT_STATUS 0x55
|
||||
#define S6SY761_READ_ONE_EVENT 0x60
|
||||
#define S6SY761_READ_ALL_EVENT 0x61
|
||||
#define S6SY761_CLEAR_EVENT_STACK 0x62
|
||||
#define S6SY761_APPLICATION_MODE 0xe4
|
||||
|
||||
/* events */
|
||||
#define S6SY761_EVENT_INFO 0x02
|
||||
#define S6SY761_EVENT_VENDOR_INFO 0x07
|
||||
|
||||
/* info */
|
||||
#define S6SY761_INFO_BOOT_COMPLETE 0x00
|
||||
|
||||
/* firmware status */
|
||||
#define S6SY761_FW_OK 0x80
|
||||
|
||||
/*
|
||||
* the functionalities are put as a reference
|
||||
* as in the device I am using none of them
|
||||
* works therefore not used in this driver yet.
|
||||
*/
|
||||
/* touchscreen functionalities */
|
||||
#define S6SY761_MASK_TOUCH BIT(0)
|
||||
#define S6SY761_MASK_HOVER BIT(1)
|
||||
#define S6SY761_MASK_COVER BIT(2)
|
||||
#define S6SY761_MASK_GLOVE BIT(3)
|
||||
#define S6SY761_MASK_STYLUS BIT(4)
|
||||
#define S6SY761_MASK_PALM BIT(5)
|
||||
#define S6SY761_MASK_WET BIT(6)
|
||||
#define S6SY761_MASK_PROXIMITY BIT(7)
|
||||
|
||||
/* boot status (BS) */
|
||||
#define S6SY761_BS_BOOT_LOADER 0x10
|
||||
#define S6SY761_BS_APPLICATION 0x20
|
||||
|
||||
/* event id */
|
||||
#define S6SY761_EVENT_ID_COORDINATE 0x00
|
||||
#define S6SY761_EVENT_ID_STATUS 0x01
|
||||
|
||||
/* event register masks */
|
||||
#define S6SY761_MASK_TOUCH_STATE 0xc0 /* byte 0 */
|
||||
#define S6SY761_MASK_TID 0x3c
|
||||
#define S6SY761_MASK_EID 0x03
|
||||
#define S6SY761_MASK_X 0xf0 /* byte 3 */
|
||||
#define S6SY761_MASK_Y 0x0f
|
||||
#define S6SY761_MASK_Z 0x3f /* byte 6 */
|
||||
#define S6SY761_MASK_LEFT_EVENTS 0x3f /* byte 7 */
|
||||
#define S6SY761_MASK_TOUCH_TYPE 0xc0 /* MSB in byte 6, LSB in byte 7 */
|
||||
|
||||
/* event touch state values */
|
||||
#define S6SY761_TS_NONE 0x00
|
||||
#define S6SY761_TS_PRESS 0x01
|
||||
#define S6SY761_TS_MOVE 0x02
|
||||
#define S6SY761_TS_RELEASE 0x03
|
||||
|
||||
/* application modes */
|
||||
#define S6SY761_APP_NORMAL 0x0
|
||||
#define S6SY761_APP_LOW_POWER 0x1
|
||||
#define S6SY761_APP_TEST 0x2
|
||||
#define S6SY761_APP_FLASH 0x3
|
||||
#define S6SY761_APP_SLEEP 0x4
|
||||
|
||||
#define S6SY761_EVENT_SIZE 8
|
||||
#define S6SY761_EVENT_COUNT 32
|
||||
#define S6SY761_DEVID_SIZE 3
|
||||
#define S6SY761_PANEL_ID_SIZE 11
|
||||
#define S6SY761_TS_STATUS_SIZE 5
|
||||
#define S6SY761_MAX_FINGERS 10
|
||||
|
||||
#define S6SY761_DEV_NAME "s6sy761"
|
||||
|
||||
enum s6sy761_regulators {
|
||||
S6SY761_REGULATOR_VDD,
|
||||
S6SY761_REGULATOR_AVDD,
|
||||
};
|
||||
|
||||
struct s6sy761_data {
|
||||
struct i2c_client *client;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct input_dev *input;
|
||||
struct touchscreen_properties prop;
|
||||
|
||||
u8 data[S6SY761_EVENT_SIZE * S6SY761_EVENT_COUNT];
|
||||
|
||||
u16 devid;
|
||||
u8 tx_channel;
|
||||
};
|
||||
|
||||
/*
|
||||
* We can't simply use i2c_smbus_read_i2c_block_data because we
|
||||
* need to read more than 255 bytes
|
||||
*/
|
||||
static int s6sy761_read_events(struct s6sy761_data *sdata, u16 n_events)
|
||||
{
|
||||
u8 cmd = S6SY761_READ_ALL_EVENT;
|
||||
struct i2c_msg msgs[2] = {
|
||||
{
|
||||
.addr = sdata->client->addr,
|
||||
.len = 1,
|
||||
.buf = &cmd,
|
||||
},
|
||||
{
|
||||
.addr = sdata->client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = (n_events * S6SY761_EVENT_SIZE),
|
||||
.buf = sdata->data + S6SY761_EVENT_SIZE,
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static void s6sy761_report_coordinates(struct s6sy761_data *sdata,
|
||||
u8 *event, u8 tid)
|
||||
{
|
||||
u8 major = event[4];
|
||||
u8 minor = event[5];
|
||||
u8 z = event[6] & S6SY761_MASK_Z;
|
||||
u16 x = (event[1] << 3) | ((event[3] & S6SY761_MASK_X) >> 4);
|
||||
u16 y = (event[2] << 3) | (event[3] & S6SY761_MASK_Y);
|
||||
|
||||
input_mt_slot(sdata->input, tid);
|
||||
|
||||
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
|
||||
input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
|
||||
input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, major);
|
||||
input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, minor);
|
||||
input_report_abs(sdata->input, ABS_MT_PRESSURE, z);
|
||||
|
||||
input_sync(sdata->input);
|
||||
}
|
||||
|
||||
static void s6sy761_report_release(struct s6sy761_data *sdata,
|
||||
u8 *event, u8 tid)
|
||||
{
|
||||
input_mt_slot(sdata->input, tid);
|
||||
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false);
|
||||
|
||||
input_sync(sdata->input);
|
||||
}
|
||||
|
||||
static void s6sy761_handle_coordinates(struct s6sy761_data *sdata, u8 *event)
|
||||
{
|
||||
u8 tid;
|
||||
u8 touch_state;
|
||||
|
||||
if (unlikely(!(event[0] & S6SY761_MASK_TID)))
|
||||
return;
|
||||
|
||||
tid = ((event[0] & S6SY761_MASK_TID) >> 2) - 1;
|
||||
touch_state = (event[0] & S6SY761_MASK_TOUCH_STATE) >> 6;
|
||||
|
||||
switch (touch_state) {
|
||||
|
||||
case S6SY761_TS_NONE:
|
||||
break;
|
||||
case S6SY761_TS_RELEASE:
|
||||
s6sy761_report_release(sdata, event, tid);
|
||||
break;
|
||||
case S6SY761_TS_PRESS:
|
||||
case S6SY761_TS_MOVE:
|
||||
s6sy761_report_coordinates(sdata, event, tid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void s6sy761_handle_events(struct s6sy761_data *sdata, u8 n_events)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_events; i++) {
|
||||
u8 *event = &sdata->data[i * S6SY761_EVENT_SIZE];
|
||||
u8 event_id = event[0] & S6SY761_MASK_EID;
|
||||
|
||||
if (!event[0])
|
||||
return;
|
||||
|
||||
switch (event_id) {
|
||||
|
||||
case S6SY761_EVENT_ID_COORDINATE:
|
||||
s6sy761_handle_coordinates(sdata, event);
|
||||
break;
|
||||
|
||||
case S6SY761_EVENT_ID_STATUS:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t s6sy761_irq_handler(int irq, void *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev;
|
||||
int ret;
|
||||
u8 n_events;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(sdata->client,
|
||||
S6SY761_READ_ONE_EVENT,
|
||||
S6SY761_EVENT_SIZE,
|
||||
sdata->data);
|
||||
if (ret < 0) {
|
||||
dev_err(&sdata->client->dev, "failed to read events\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (!sdata->data[0])
|
||||
return IRQ_HANDLED;
|
||||
|
||||
n_events = sdata->data[7] & S6SY761_MASK_LEFT_EVENTS;
|
||||
if (unlikely(n_events > S6SY761_EVENT_COUNT - 1))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (n_events) {
|
||||
ret = s6sy761_read_events(sdata, n_events);
|
||||
if (ret < 0) {
|
||||
dev_err(&sdata->client->dev, "failed to read events\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
s6sy761_handle_events(sdata, n_events + 1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int s6sy761_input_open(struct input_dev *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = input_get_drvdata(dev);
|
||||
|
||||
return i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON);
|
||||
}
|
||||
|
||||
static void s6sy761_input_close(struct input_dev *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = input_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_OFF);
|
||||
if (ret)
|
||||
dev_err(&sdata->client->dev, "failed to turn off sensing\n");
|
||||
}
|
||||
|
||||
static ssize_t s6sy761_sysfs_devid(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%#x\n", sdata->devid);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(devid, 0444, s6sy761_sysfs_devid, NULL);
|
||||
|
||||
static struct attribute *s6sy761_sysfs_attrs[] = {
|
||||
&dev_attr_devid.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group s6sy761_attribute_group = {
|
||||
.attrs = s6sy761_sysfs_attrs
|
||||
};
|
||||
|
||||
static int s6sy761_power_on(struct s6sy761_data *sdata)
|
||||
{
|
||||
u8 buffer[S6SY761_EVENT_SIZE];
|
||||
u8 event;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(140);
|
||||
|
||||
/* double check whether the touch is functional */
|
||||
ret = i2c_smbus_read_i2c_block_data(sdata->client,
|
||||
S6SY761_READ_ONE_EVENT,
|
||||
S6SY761_EVENT_SIZE,
|
||||
buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
event = (buffer[0] >> 2) & 0xf;
|
||||
|
||||
if ((event != S6SY761_EVENT_INFO &&
|
||||
event != S6SY761_EVENT_VENDOR_INFO) ||
|
||||
buffer[1] != S6SY761_INFO_BOOT_COMPLETE) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(sdata->client, S6SY761_BOOT_STATUS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* for some reasons the device might be stuck in the bootloader */
|
||||
if (ret != S6SY761_BS_APPLICATION)
|
||||
return -ENODEV;
|
||||
|
||||
/* enable touch functionality */
|
||||
ret = i2c_smbus_write_word_data(sdata->client,
|
||||
S6SY761_TOUCH_FUNCTION,
|
||||
S6SY761_MASK_TOUCH);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6sy761_hw_init(struct s6sy761_data *sdata,
|
||||
unsigned int *max_x, unsigned int *max_y)
|
||||
{
|
||||
u8 buffer[S6SY761_PANEL_ID_SIZE]; /* larger read size */
|
||||
int ret;
|
||||
|
||||
ret = s6sy761_power_on(sdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(sdata->client,
|
||||
S6SY761_DEVICE_ID,
|
||||
S6SY761_DEVID_SIZE,
|
||||
buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
sdata->devid = get_unaligned_be16(buffer + 1);
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(sdata->client,
|
||||
S6SY761_PANEL_INFO,
|
||||
S6SY761_PANEL_ID_SIZE,
|
||||
buffer);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*max_x = get_unaligned_be16(buffer);
|
||||
*max_y = get_unaligned_be16(buffer + 2);
|
||||
|
||||
/* if no tx channels defined, at least keep one */
|
||||
sdata->tx_channel = max_t(u8, buffer[8], 1);
|
||||
|
||||
ret = i2c_smbus_read_byte_data(sdata->client,
|
||||
S6SY761_FIRMWARE_INTEGRITY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != S6SY761_FW_OK)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s6sy761_power_off(void *data)
|
||||
{
|
||||
struct s6sy761_data *sdata = data;
|
||||
|
||||
disable_irq(sdata->client->irq);
|
||||
regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
}
|
||||
|
||||
static int s6sy761_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct s6sy761_data *sdata;
|
||||
unsigned int max_x, max_y;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
|
||||
sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
|
||||
if (!sdata)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, sdata);
|
||||
sdata->client = client;
|
||||
|
||||
sdata->regulators[S6SY761_REGULATOR_VDD].supply = "vdd";
|
||||
sdata->regulators[S6SY761_REGULATOR_AVDD].supply = "avdd";
|
||||
err = devm_regulator_bulk_get(&client->dev,
|
||||
ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(&client->dev, s6sy761_power_off, sdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = s6sy761_hw_init(sdata, &max_x, &max_y);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sdata->input = devm_input_allocate_device(&client->dev);
|
||||
if (!sdata->input)
|
||||
return -ENOMEM;
|
||||
|
||||
sdata->input->name = S6SY761_DEV_NAME;
|
||||
sdata->input->id.bustype = BUS_I2C;
|
||||
sdata->input->open = s6sy761_input_open;
|
||||
sdata->input->close = s6sy761_input_close;
|
||||
|
||||
input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
touchscreen_parse_properties(sdata->input, true, &sdata->prop);
|
||||
|
||||
if (!input_abs_get_max(sdata->input, ABS_X) ||
|
||||
!input_abs_get_max(sdata->input, ABS_Y)) {
|
||||
dev_warn(&client->dev, "the axis have not been set\n");
|
||||
}
|
||||
|
||||
err = input_mt_init_slots(sdata->input, sdata->tx_channel,
|
||||
INPUT_MT_DIRECT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
input_set_drvdata(sdata->input, sdata);
|
||||
|
||||
err = input_register_device(sdata->input);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
s6sy761_irq_handler,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"s6sy761_irq", sdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_device_add_group(&client->dev, &s6sy761_attribute_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6sy761_remove(struct i2c_client *client)
|
||||
{
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
return i2c_smbus_write_byte_data(sdata->client,
|
||||
S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP);
|
||||
}
|
||||
|
||||
static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
return i2c_smbus_write_byte_data(sdata->client,
|
||||
S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL);
|
||||
}
|
||||
|
||||
static int __maybe_unused s6sy761_suspend(struct device *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
s6sy761_power_off(sdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused s6sy761_resume(struct device *dev)
|
||||
{
|
||||
struct s6sy761_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
enable_irq(sdata->client->irq);
|
||||
|
||||
return s6sy761_power_on(sdata);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops s6sy761_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
|
||||
SET_RUNTIME_PM_OPS(s6sy761_runtime_suspend,
|
||||
s6sy761_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s6sy761_of_match[] = {
|
||||
{ .compatible = "samsung,s6sy761", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s6sy761_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id s6sy761_id[] = {
|
||||
{ "s6sy761", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, s6sy761_id);
|
||||
|
||||
static struct i2c_driver s6sy761_driver = {
|
||||
.driver = {
|
||||
.name = S6SY761_DEV_NAME,
|
||||
.of_match_table = of_match_ptr(s6sy761_of_match),
|
||||
.pm = &s6sy761_pm_ops,
|
||||
},
|
||||
.probe = s6sy761_probe,
|
||||
.remove = s6sy761_remove,
|
||||
.id_table = s6sy761_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(s6sy761_driver);
|
||||
|
||||
MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -29,7 +29,6 @@
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_data/st1232_pdata.h>
|
||||
|
||||
#define ST1232_TS_NAME "st1232-ts"
|
||||
|
||||
@ -152,10 +151,9 @@ static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron)
|
||||
}
|
||||
|
||||
static int st1232_ts_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct st1232_ts_data *ts;
|
||||
struct st1232_pdata *pdata = dev_get_platdata(&client->dev);
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
@ -180,13 +178,7 @@ static int st1232_ts_probe(struct i2c_client *client,
|
||||
ts->client = client;
|
||||
ts->input_dev = input_dev;
|
||||
|
||||
if (pdata)
|
||||
ts->reset_gpio = pdata->reset_gpio;
|
||||
else if (client->dev.of_node)
|
||||
ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
|
||||
else
|
||||
ts->reset_gpio = -ENODEV;
|
||||
|
||||
ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
|
||||
if (gpio_is_valid(ts->reset_gpio)) {
|
||||
error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
|
||||
if (error) {
|
||||
@ -281,13 +273,11 @@ static const struct i2c_device_id st1232_ts_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st1232_ts_dt_ids[] = {
|
||||
{ .compatible = "sitronix,st1232", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver st1232_ts_driver = {
|
||||
.probe = st1232_ts_probe,
|
||||
@ -295,7 +285,7 @@ static struct i2c_driver st1232_ts_driver = {
|
||||
.id_table = st1232_ts_id,
|
||||
.driver = {
|
||||
.name = ST1232_TS_NAME,
|
||||
.of_match_table = of_match_ptr(st1232_ts_dt_ids),
|
||||
.of_match_table = st1232_ts_dt_ids,
|
||||
.pm = &st1232_ts_pm_ops,
|
||||
},
|
||||
};
|
||||
|
@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
err = sysfs_create_group(&sdata->client->dev.kobj,
|
||||
&stmfts_attribute_group);
|
||||
err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client,
|
||||
static int stmfts_remove(struct i2c_client *client)
|
||||
{
|
||||
pm_runtime_disable(&client->dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -202,9 +202,9 @@ static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tsc200x_penup_timer(unsigned long data)
|
||||
static void tsc200x_penup_timer(struct timer_list *t)
|
||||
{
|
||||
struct tsc200x *ts = (struct tsc200x *)data;
|
||||
struct tsc200x *ts = from_timer(ts, t, penup_timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ts->lock, flags);
|
||||
@ -506,7 +506,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
|
||||
mutex_init(&ts->mutex);
|
||||
|
||||
spin_lock_init(&ts->lock);
|
||||
setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts);
|
||||
timer_setup(&ts->penup_timer, tsc200x_penup_timer, 0);
|
||||
|
||||
INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
|
||||
|
||||
|
@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void w90p910_check_pen_up(unsigned long data)
|
||||
static void w90p910_check_pen_up(struct timer_list *t)
|
||||
{
|
||||
struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
|
||||
struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&w90p910_ts->lock, flags);
|
||||
@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev)
|
||||
w90p910_ts->input = input_dev;
|
||||
w90p910_ts->state = TS_IDLE;
|
||||
spin_lock_init(&w90p910_ts->lock);
|
||||
setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
|
||||
(unsigned long)w90p910_ts);
|
||||
timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
|
@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group);
|
||||
error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "create sysfs failed: %d\n", error);
|
||||
return error;
|
||||
@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt87xx_ts_remove(struct i2c_client *client)
|
||||
{
|
||||
sysfs_remove_group(&client->dev.kobj, &wdt87xx_attr_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused wdt87xx_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
|
||||
|
||||
static struct i2c_driver wdt87xx_driver = {
|
||||
.probe = wdt87xx_ts_probe,
|
||||
.remove = wdt87xx_ts_remove,
|
||||
.id_table = wdt87xx_dev_id,
|
||||
.driver = {
|
||||
.name = WDT87XX_NAME,
|
||||
|
@ -94,7 +94,7 @@ struct infrared {
|
||||
u8 inversion;
|
||||
u16 last_key;
|
||||
u16 last_toggle;
|
||||
u8 delay_timer_finished;
|
||||
bool keypressed;
|
||||
};
|
||||
|
||||
|
||||
|
@ -84,15 +84,16 @@ static u16 default_key_map [256] = {
|
||||
|
||||
|
||||
/* key-up timer */
|
||||
static void av7110_emit_keyup(unsigned long parm)
|
||||
static void av7110_emit_keyup(struct timer_list *t)
|
||||
{
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
struct infrared *ir = from_timer(ir, t, keyup_timer);
|
||||
|
||||
if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
|
||||
if (!ir || !ir->keypressed)
|
||||
return;
|
||||
|
||||
input_report_key(ir->input_dev, ir->last_key, 0);
|
||||
input_sync(ir->input_dev);
|
||||
ir->keypressed = false;
|
||||
}
|
||||
|
||||
|
||||
@ -152,29 +153,18 @@ static void av7110_emit_key(unsigned long parm)
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer_pending(&ir->keyup_timer)) {
|
||||
del_timer(&ir->keyup_timer);
|
||||
if (ir->last_key != keycode || toggle != ir->last_toggle) {
|
||||
ir->delay_timer_finished = 0;
|
||||
input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
} else if (ir->delay_timer_finished) {
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 2);
|
||||
input_sync(ir->input_dev);
|
||||
}
|
||||
} else {
|
||||
ir->delay_timer_finished = 0;
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
}
|
||||
if (ir->keypressed &&
|
||||
(ir->last_key != keycode || toggle != ir->last_toggle))
|
||||
input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
|
||||
|
||||
input_event(ir->input_dev, EV_KEY, keycode, 1);
|
||||
input_sync(ir->input_dev);
|
||||
|
||||
ir->keypressed = true;
|
||||
ir->last_key = keycode;
|
||||
ir->last_toggle = toggle;
|
||||
|
||||
ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
|
||||
add_timer(&ir->keyup_timer);
|
||||
|
||||
mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
@ -204,16 +194,6 @@ static void input_register_keys(struct infrared *ir)
|
||||
ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
|
||||
}
|
||||
|
||||
|
||||
/* called by the input driver after rep[REP_DELAY] ms */
|
||||
static void input_repeat_key(unsigned long parm)
|
||||
{
|
||||
struct infrared *ir = (struct infrared *) parm;
|
||||
|
||||
ir->delay_timer_finished = 1;
|
||||
}
|
||||
|
||||
|
||||
/* check for configuration changes */
|
||||
int av7110_check_ir_config(struct av7110 *av7110, int force)
|
||||
{
|
||||
@ -333,8 +313,7 @@ int av7110_ir_init(struct av7110 *av7110)
|
||||
av_list[av_cnt++] = av7110;
|
||||
av7110_check_ir_config(av7110, true);
|
||||
|
||||
setup_timer(&av7110->ir.keyup_timer, av7110_emit_keyup,
|
||||
(unsigned long)&av7110->ir);
|
||||
timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0);
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
@ -365,8 +344,13 @@ int av7110_ir_init(struct av7110 *av7110)
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
input_dev->timer.function = input_repeat_key;
|
||||
input_dev->timer.data = (unsigned long) &av7110->ir;
|
||||
|
||||
/*
|
||||
* Input core's default autorepeat is 33 cps with 250 msec
|
||||
* delay, let's adjust to numbers more suitable for remote
|
||||
* control.
|
||||
*/
|
||||
input_enable_softrepeat(input_dev, 250, 125);
|
||||
|
||||
if (av_cnt == 1) {
|
||||
e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Driver for simulating a mouse on GPIO lines.
|
||||
*
|
||||
* Copyright (C) 2007 Atmel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _GPIO_MOUSE_H
|
||||
#define _GPIO_MOUSE_H
|
||||
|
||||
#define GPIO_MOUSE_POLARITY_ACT_HIGH 0x00
|
||||
#define GPIO_MOUSE_POLARITY_ACT_LOW 0x01
|
||||
|
||||
#define GPIO_MOUSE_PIN_UP 0
|
||||
#define GPIO_MOUSE_PIN_DOWN 1
|
||||
#define GPIO_MOUSE_PIN_LEFT 2
|
||||
#define GPIO_MOUSE_PIN_RIGHT 3
|
||||
#define GPIO_MOUSE_PIN_BLEFT 4
|
||||
#define GPIO_MOUSE_PIN_BMIDDLE 5
|
||||
#define GPIO_MOUSE_PIN_BRIGHT 6
|
||||
#define GPIO_MOUSE_PIN_MAX 7
|
||||
|
||||
/**
|
||||
* struct gpio_mouse_platform_data
|
||||
* @scan_ms: integer in ms specifying the scan periode.
|
||||
* @polarity: Pin polarity, active high or low.
|
||||
* @up: GPIO line for up value.
|
||||
* @down: GPIO line for down value.
|
||||
* @left: GPIO line for left value.
|
||||
* @right: GPIO line for right value.
|
||||
* @bleft: GPIO line for left button.
|
||||
* @bmiddle: GPIO line for middle button.
|
||||
* @bright: GPIO line for right button.
|
||||
*
|
||||
* This struct must be added to the platform_device in the board code.
|
||||
* It is used by the gpio_mouse driver to setup GPIO lines and to
|
||||
* calculate mouse movement.
|
||||
*/
|
||||
struct gpio_mouse_platform_data {
|
||||
int scan_ms;
|
||||
int polarity;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int up;
|
||||
int down;
|
||||
int left;
|
||||
int right;
|
||||
|
||||
int bleft;
|
||||
int bmiddle;
|
||||
int bright;
|
||||
};
|
||||
int pins[GPIO_MOUSE_PIN_MAX];
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _GPIO_MOUSE_H */
|
@ -1,14 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_ST1232_PDATA_H
|
||||
#define _LINUX_ST1232_PDATA_H
|
||||
|
||||
/*
|
||||
* Optional platform data
|
||||
*
|
||||
* Use this if you want the driver to drive the reset pin.
|
||||
*/
|
||||
struct st1232_pdata {
|
||||
int reset_gpio;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* User level driver support for input subsystem
|
||||
*
|
||||
* Heavily based on evdev.c by Vojtech Pavlik
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
|
||||
*
|
||||
* Changes/Revisions:
|
||||
* 0.5 08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
|
||||
* Benjamin Tissoires <benjamin.tissoires@redhat.com>)
|
||||
* - add UI_DEV_SETUP ioctl
|
||||
* - add UI_ABS_SETUP ioctl
|
||||
* - add UI_GET_VERSION ioctl
|
||||
* 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
|
||||
* - add UI_GET_SYSNAME ioctl
|
||||
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
|
||||
* - update ff support for the changes in kernel interface
|
||||
* - add UINPUT_VERSION
|
||||
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
|
||||
* - added force feedback support
|
||||
* - added UI_SET_PHYS
|
||||
* 0.1 20/06/2002
|
||||
* - first public version
|
||||
*/
|
||||
#ifndef __UINPUT_H_
|
||||
#define __UINPUT_H_
|
||||
|
||||
#include <uapi/linux/uinput.h>
|
||||
|
||||
#define UINPUT_NAME "uinput"
|
||||
#define UINPUT_BUFFER_SIZE 16
|
||||
#define UINPUT_NUM_REQUESTS 16
|
||||
|
||||
enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
|
||||
|
||||
struct uinput_request {
|
||||
unsigned int id;
|
||||
unsigned int code; /* UI_FF_UPLOAD, UI_FF_ERASE */
|
||||
|
||||
int retval;
|
||||
struct completion done;
|
||||
|
||||
union {
|
||||
unsigned int effect_id;
|
||||
struct {
|
||||
struct ff_effect *effect;
|
||||
struct ff_effect *old;
|
||||
} upload;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct uinput_device {
|
||||
struct input_dev *dev;
|
||||
struct mutex mutex;
|
||||
enum uinput_state state;
|
||||
wait_queue_head_t waitq;
|
||||
unsigned char ready;
|
||||
unsigned char head;
|
||||
unsigned char tail;
|
||||
struct input_event buff[UINPUT_BUFFER_SIZE];
|
||||
unsigned int ff_effects_max;
|
||||
|
||||
struct uinput_request *requests[UINPUT_NUM_REQUESTS];
|
||||
wait_queue_head_t requests_waitq;
|
||||
spinlock_t requests_lock;
|
||||
};
|
||||
#endif /* __UINPUT_H_ */
|
Loading…
Reference in New Issue
Block a user