提交 9f7a9b11 编写于 作者: L Linus Torvalds

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()
  ...
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>;
};
* 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 ...@@ -2,7 +2,8 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
Required properties: Required properties:
- compatible : Should be "goodix,gt911" - compatible : Should be "goodix,gt1151"
or "goodix,gt911"
or "goodix,gt9110" or "goodix,gt9110"
or "goodix,gt912" or "goodix,gt912"
or "goodix,gt927" or "goodix,gt927"
......
* 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>;
};
};
* 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 ...@@ -137,6 +137,7 @@ gw Gateworks Corporation
hannstar HannStar Display Corporation hannstar HannStar Display Corporation
haoyu Haoyu Microelectronic Co. Ltd. haoyu Haoyu Microelectronic Co. Ltd.
hardkernel Hardkernel Co., Ltd hardkernel Hardkernel Co., Ltd
hideep HiDeep Inc.
himax Himax Technologies, Inc. himax Himax Technologies, Inc.
hisilicon Hisilicon Limited. hisilicon Hisilicon Limited.
hit Hitachi Ltd. hit Hitachi Ltd.
......
...@@ -412,10 +412,10 @@ static void ml_play_effects(struct ml_device *ml) ...@@ -412,10 +412,10 @@ static void ml_play_effects(struct ml_device *ml)
ml_schedule_timer(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 = from_timer(ml, t, timer);
struct ml_device *ml = dev->ff->private; struct input_dev *dev = ml->dev;
unsigned long flags; unsigned long flags;
pr_debug("timer: updating effects\n"); pr_debug("timer: updating effects\n");
...@@ -526,7 +526,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data, ...@@ -526,7 +526,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
ml->private = data; ml->private = data;
ml->play_effect = play_effect; ml->play_effect = play_effect;
ml->gain = 0xffff; 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); set_bit(FF_GAIN, dev->ffbit);
......
...@@ -76,7 +76,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code) ...@@ -76,7 +76,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
{ {
if (test_bit(EV_REP, dev->evbit) && if (test_bit(EV_REP, dev->evbit) &&
dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
dev->timer.data) { dev->timer.function) {
dev->repeat_key = code; dev->repeat_key = code;
mod_timer(&dev->timer, mod_timer(&dev->timer,
jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
...@@ -179,9 +179,9 @@ static void input_pass_event(struct input_dev *dev, ...@@ -179,9 +179,9 @@ static void input_pass_event(struct input_dev *dev,
* dev->event_lock here to avoid racing with input_event * dev->event_lock here to avoid racing with input_event
* which may cause keys get "stuck". * 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; unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
...@@ -1784,7 +1784,7 @@ struct input_dev *input_allocate_device(void) ...@@ -1784,7 +1784,7 @@ struct input_dev *input_allocate_device(void)
device_initialize(&dev->dev); device_initialize(&dev->dev);
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
spin_lock_init(&dev->event_lock); 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->h_list);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
...@@ -2047,8 +2047,7 @@ static void devm_input_device_unregister(struct device *dev, void *res) ...@@ -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) void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
{ {
dev->timer.data = (unsigned long) dev; dev->timer.function = (TIMER_FUNC_TYPE)input_repeat_key;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = delay; dev->rep[REP_DELAY] = delay;
dev->rep[REP_PERIOD] = period; dev->rep[REP_PERIOD] = period;
} }
......
...@@ -654,6 +654,7 @@ static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type, ...@@ -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_THUMBL, ~data[0] & 0x04);
input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02); input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
/* fall through */
case GC_PSX_NEGCON: case GC_PSX_NEGCON:
case GC_PSX_ANALOG: case GC_PSX_ANALOG:
...@@ -887,6 +888,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) ...@@ -887,6 +888,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
case GC_SNES: case GC_SNES:
for (i = 4; i < 8; i++) for (i = 4; i < 8; i++)
__set_bit(gc_snes_btn[i], input_dev->keybit); __set_bit(gc_snes_btn[i], input_dev->keybit);
/* fall through */
case GC_NES: case GC_NES:
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
__set_bit(gc_snes_btn[i], input_dev->keybit); __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) ...@@ -894,6 +896,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
case GC_MULTI2: case GC_MULTI2:
__set_bit(BTN_THUMB, input_dev->keybit); __set_bit(BTN_THUMB, input_dev->keybit);
/* fall through */
case GC_MULTI: case GC_MULTI:
__set_bit(BTN_TRIGGER, input_dev->keybit); __set_bit(BTN_TRIGGER, input_dev->keybit);
break; break;
......
...@@ -672,16 +672,16 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) ...@@ -672,16 +672,16 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
switch (i * m) { switch (i * m) {
case 60: case 60:
sw->number++; sw->number++; /* fall through */
case 45: /* Ambiguous packet length */ case 45: /* Ambiguous packet length */
if (j <= 40) { /* ID length less or eq 40 -> FSP */ if (j <= 40) { /* ID length less or eq 40 -> FSP */
case 43: case 43:
sw->type = SW_ID_FSP; sw->type = SW_ID_FSP;
break; break;
} }
sw->number++; sw->number++; /* fall through */
case 30: case 30:
sw->number++; sw->number++; /* fall through */
case 15: case 15:
sw->type = SW_ID_GP; sw->type = SW_ID_GP;
break; break;
...@@ -697,9 +697,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) ...@@ -697,9 +697,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
sw->type = SW_ID_PP; sw->type = SW_ID_PP;
break; break;
case 66: case 66:
sw->bits = 3; sw->bits = 3; /* fall through */
case 198: case 198:
sw->length = 22; sw->length = 22; /* fall through */
case 64: case 64:
sw->type = SW_ID_3DP; sw->type = SW_ID_3DP;
if (j == 160) if (j == 160)
......
...@@ -162,6 +162,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio, ...@@ -162,6 +162,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
break; break;
} }
spaceball->escape = 0; spaceball->escape = 0;
/* fall through */
case 'M': case 'M':
case 'Q': case 'Q':
case 'S': case 'S':
...@@ -169,6 +170,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio, ...@@ -169,6 +170,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
spaceball->escape = 0; spaceball->escape = 0;
data &= 0x1f; data &= 0x1f;
} }
/* fall through */
default: default:
if (spaceball->escape) if (spaceball->escape)
spaceball->escape = 0; spaceball->escape = 0;
...@@ -234,11 +236,13 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv) ...@@ -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) | input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
BIT_MASK(BTN_B) | BIT_MASK(BTN_C) | BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
BIT_MASK(BTN_MODE); BIT_MASK(BTN_MODE);
/* fall through */
default: default:
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) | input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
BIT_MASK(BTN_3) | BIT_MASK(BTN_4) | BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
BIT_MASK(BTN_7) | BIT_MASK(BTN_8); BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
/* fall through */
case SPACEBALL_3003C: case SPACEBALL_3003C:
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) | input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
BIT_MASK(BTN_8); BIT_MASK(BTN_8);
......
...@@ -127,10 +127,9 @@ static inline void bfin_kpad_clear_irq(void) ...@@ -127,10 +127,9 @@ static inline void bfin_kpad_clear_irq(void)
bfin_write_KPAD_ROWCOL(0xFFFF); 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 = from_timer(bf54x_kpad, t, timer);
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
if (bfin_kpad_get_keypressed(bf54x_kpad)) { if (bfin_kpad_get_keypressed(bf54x_kpad)) {
/* Try again later */ /* Try again later */
...@@ -298,7 +297,7 @@ static int bfin_kpad_probe(struct platform_device *pdev) ...@@ -298,7 +297,7 @@ static int bfin_kpad_probe(struct platform_device *pdev)
/* Init Keypad Key Up/Release test timer */ /* 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)); 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) ...@@ -419,9 +419,9 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
return IRQ_HANDLED; 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; struct input_dev *input = bdata->input;
unsigned long flags; unsigned long flags;
...@@ -582,8 +582,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -582,8 +582,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
} }
bdata->release_delay = button->debounce_interval; bdata->release_delay = button->debounce_interval;
setup_timer(&bdata->release_timer, timer_setup(&bdata->release_timer, gpio_keys_irq_timer, 0);
gpio_keys_irq_timer, (unsigned long)bdata);
isr = gpio_keys_irq_isr; isr = gpio_keys_irq_isr;
irqflags = 0; irqflags = 0;
......
...@@ -184,9 +184,9 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad, ...@@ -184,9 +184,9 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad,
/* /*
* imx_keypad_check_for_events is the timer handler. * 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 matrix_volatile_state[MAX_MATRIX_KEY_COLS];
unsigned short reg_val; unsigned short reg_val;
bool state_changed, is_zero_matrix; bool state_changed, is_zero_matrix;
...@@ -456,8 +456,8 @@ static int imx_keypad_probe(struct platform_device *pdev) ...@@ -456,8 +456,8 @@ static int imx_keypad_probe(struct platform_device *pdev)
keypad->irq = irq; keypad->irq = irq;
keypad->stable_count = 0; keypad->stable_count = 0;
setup_timer(&keypad->check_matrix_timer, timer_setup(&keypad->check_matrix_timer,
imx_keypad_check_for_events, (unsigned long) keypad); imx_keypad_check_for_events, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -210,9 +210,9 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) ...@@ -210,9 +210,9 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
/* /*
* LoCoMo timer checking for released keys * 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); locomokbd_scankeyboard(locomokbd);
} }
...@@ -264,8 +264,7 @@ static int locomokbd_probe(struct locomo_dev *dev) ...@@ -264,8 +264,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
spin_lock_init(&locomokbd->lock); spin_lock_init(&locomokbd->lock);
setup_timer(&locomokbd->timer, locomokbd_timer_callback, timer_setup(&locomokbd->timer, locomokbd_timer_callback, 0);
(unsigned long)locomokbd);
locomokbd->suspend_jiffies = jiffies; locomokbd->suspend_jiffies = jiffies;
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#undef NEW_BOARD_LEARNING_MODE #undef NEW_BOARD_LEARNING_MODE
static void omap_kp_tasklet(unsigned long); 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 unsigned char keypad_state[8];
static DEFINE_MUTEX(kp_enable_mutex); static DEFINE_MUTEX(kp_enable_mutex);
...@@ -74,7 +74,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) ...@@ -74,7 +74,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void omap_kp_timer(unsigned long data) static void omap_kp_timer(struct timer_list *unused)
{ {
tasklet_schedule(&kp_tasklet); tasklet_schedule(&kp_tasklet);
} }
...@@ -233,7 +233,7 @@ static int omap_kp_probe(struct platform_device *pdev) ...@@ -233,7 +233,7 @@ static int omap_kp_probe(struct platform_device *pdev)
col_idx = 0; col_idx = 0;
row_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*/ /* get the irq and init timer*/
kp_tasklet.data = (unsigned long) omap_kp; kp_tasklet.data = (unsigned long) omap_kp;
......
...@@ -45,9 +45,9 @@ struct pwrkey_drv_data { ...@@ -45,9 +45,9 @@ struct pwrkey_drv_data {
struct input_dev *input; 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; struct input_dev *input = pdata->input;
u32 state; u32 state;
...@@ -134,8 +134,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) ...@@ -134,8 +134,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
/* clear the unexpected interrupt before driver ready */ /* clear the unexpected interrupt before driver ready */
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
setup_timer(&pdata->check_timer, timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
imx_imx_snvs_check_for_events, (unsigned long) pdata);
input = devm_input_allocate_device(&pdev->dev); input = devm_input_allocate_device(&pdev->dev);
if (!input) { if (!input) {
......
...@@ -251,9 +251,9 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) ...@@ -251,9 +251,9 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
writel(val, kbc->mmio + KBC_CONTROL_0); 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; unsigned long flags;
u32 val; u32 val;
unsigned int i; unsigned int i;
...@@ -655,7 +655,7 @@ static int tegra_kbc_probe(struct platform_device *pdev) ...@@ -655,7 +655,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
return -ENOMEM; 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); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
kbc->mmio = devm_ioremap_resource(&pdev->dev, res); kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
......
...@@ -796,7 +796,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, ...@@ -796,7 +796,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
if (pdata->watermark) { if (pdata->watermark) {
ac->int_mask |= 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; ac->pdata.fifo_mode |= FIFO_STREAM;
} else { } else {
ac->int_mask |= DATA_READY; ac->int_mask |= DATA_READY;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
* 0.1 20/06/2002 * 0.1 20/06/2002
* - first public version * - first public version
*/ */
#include <uapi/linux/uinput.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -38,10 +39,47 @@ ...@@ -38,10 +39,47 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/uinput.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include "../input-compat.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, static int uinput_dev_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
...@@ -149,7 +187,11 @@ static int uinput_request_submit(struct uinput_device *udev, ...@@ -149,7 +187,11 @@ static int uinput_request_submit(struct uinput_device *udev,
if (retval) if (retval)
goto out; goto out;
wait_for_completion(&request->done); if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
retval = -ETIMEDOUT;
goto out;
}
retval = request->retval; retval = request->retval;
out: out:
...@@ -320,6 +362,10 @@ static int uinput_create_device(struct uinput_device *udev) ...@@ -320,6 +362,10 @@ static int uinput_create_device(struct uinput_device *udev)
dev->flush = uinput_dev_flush; dev->flush = uinput_dev_flush;
} }
dev->event = uinput_dev_event;
input_set_drvdata(udev->dev, udev);
error = input_register_device(udev->dev); error = input_register_device(udev->dev);
if (error) if (error)
goto fail2; goto fail2;
...@@ -402,18 +448,6 @@ static int uinput_validate_absbits(struct input_dev *dev) ...@@ -402,18 +448,6 @@ static int uinput_validate_absbits(struct input_dev *dev)
return 0; 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, static int uinput_dev_setup(struct uinput_device *udev,
struct uinput_setup __user *arg) struct uinput_setup __user *arg)
{ {
...@@ -489,9 +523,9 @@ static int uinput_setup_device_legacy(struct uinput_device *udev, ...@@ -489,9 +523,9 @@ static int uinput_setup_device_legacy(struct uinput_device *udev,
return -EINVAL; return -EINVAL;
if (!udev->dev) { if (!udev->dev) {
retval = uinput_allocate_device(udev); udev->dev = input_allocate_device();
if (retval) if (!udev->dev)
return retval; return -ENOMEM;
} }
dev = udev->dev; dev = udev->dev;
...@@ -822,15 +856,16 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -822,15 +856,16 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
return retval; return retval;
if (!udev->dev) { if (!udev->dev) {
retval = uinput_allocate_device(udev); udev->dev = input_allocate_device();
if (retval) if (!udev->dev) {
retval = -ENOMEM;
goto out; goto out;
} }
}
switch (cmd) { switch (cmd) {
case UI_GET_VERSION: case UI_GET_VERSION:
if (put_user(UINPUT_VERSION, if (put_user(UINPUT_VERSION, (unsigned int __user *)p))
(unsigned int __user *)p))
retval = -EFAULT; retval = -EFAULT;
goto out; goto out;
......
...@@ -1587,10 +1587,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) ...@@ -1587,10 +1587,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA; 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 = from_timer(priv, t, timer);
struct alps_data *priv = psmouse->private; struct psmouse *psmouse = priv->psmouse;
serio_pause_rx(psmouse->ps2dev.serio); serio_pause_rx(psmouse->ps2dev.serio);
...@@ -2702,7 +2702,7 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2702,7 +2702,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
{ {
psmouse->private = priv; 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->proto_version = protocol->version;
priv->byte0 = protocol->byte0; priv->byte0 = protocol->byte0;
......
...@@ -227,6 +227,7 @@ ...@@ -227,6 +227,7 @@
struct byd_data { struct byd_data {
struct timer_list timer; struct timer_list timer;
struct psmouse *psmouse;
s32 abs_x; s32 abs_x;
s32 abs_y; s32 abs_y;
typeof(jiffies) last_touch_time; typeof(jiffies) last_touch_time;
...@@ -251,10 +252,10 @@ static void byd_report_input(struct psmouse *psmouse) ...@@ -251,10 +252,10 @@ static void byd_report_input(struct psmouse *psmouse)
input_sync(dev); 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 = from_timer(priv, t, timer);
struct byd_data *priv = psmouse->private; struct psmouse *psmouse = priv->psmouse;
serio_pause_rx(psmouse->ps2dev.serio); serio_pause_rx(psmouse->ps2dev.serio);
priv->touch = false; priv->touch = false;
...@@ -478,7 +479,8 @@ int byd_init(struct psmouse *psmouse) ...@@ -478,7 +479,8 @@ int byd_init(struct psmouse *psmouse)
if (!priv) if (!priv)
return -ENOMEM; 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->private = priv;
psmouse->disconnect = byd_disconnect; psmouse->disconnect = byd_disconnect;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -1141,10 +1142,13 @@ static int elan_probe(struct i2c_client *client, ...@@ -1141,10 +1142,13 @@ static int elan_probe(struct i2c_client *client,
return error; return error;
/* /*
* Systems using device tree should set up interrupt via DTS, * Platform code (ACPI, DTS) should normally set up interrupt
* the rest will use the default falling edge interrupts. * 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, error = devm_request_threaded_irq(dev, client->irq, NULL, elan_isr,
irqflags | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
...@@ -1255,7 +1259,6 @@ static const struct acpi_device_id elan_acpi_id[] = { ...@@ -1255,7 +1259,6 @@ static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0602", 0 }, { "ELAN0602", 0 },
{ "ELAN0605", 0 }, { "ELAN0605", 0 },
{ "ELAN0608", 0 }, { "ELAN0608", 0 },
{ "ELAN0605", 0 },
{ "ELAN0609", 0 }, { "ELAN0609", 0 },
{ "ELAN060B", 0 }, { "ELAN060B", 0 },
{ "ELAN060C", 0 }, { "ELAN060C", 0 },
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Driver for simulating a mouse on GPIO lines. * Driver for simulating a mouse on GPIO lines.
* *
* Copyright (C) 2007 Atmel Corporation * 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 * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -11,9 +12,35 @@ ...@@ -11,9 +12,35 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/input-polldev.h> #include <linux/input-polldev.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/gpio_mouse.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. * Timer function which is run every scan_ms ms when the device is opened.
...@@ -21,24 +48,22 @@ ...@@ -21,24 +48,22 @@
*/ */
static void gpio_mouse_scan(struct input_polled_dev *dev) 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; struct input_dev *input = dev->input;
int x, y; int x, y;
if (gpio->bleft >= 0) if (gpio->bleft)
input_report_key(input, BTN_LEFT, input_report_key(input, BTN_LEFT,
gpio_get_value(gpio->bleft) ^ gpio->polarity); gpiod_get_value(gpio->bleft));
if (gpio->bmiddle >= 0) if (gpio->bmiddle)
input_report_key(input, BTN_MIDDLE, input_report_key(input, BTN_MIDDLE,
gpio_get_value(gpio->bmiddle) ^ gpio->polarity); gpiod_get_value(gpio->bmiddle));
if (gpio->bright >= 0) if (gpio->bright)
input_report_key(input, BTN_RIGHT, 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) x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);
- (gpio_get_value(gpio->left) ^ gpio->polarity); y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up);
y = (gpio_get_value(gpio->down) ^ gpio->polarity)
- (gpio_get_value(gpio->up) ^ gpio->polarity);
input_report_rel(input, REL_X, x); input_report_rel(input, REL_X, x);
input_report_rel(input, REL_Y, y); input_report_rel(input, REL_Y, y);
...@@ -47,65 +72,61 @@ static void gpio_mouse_scan(struct input_polled_dev *dev) ...@@ -47,65 +72,61 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
static int gpio_mouse_probe(struct platform_device *pdev) 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_polled_dev *input_poll;
struct input_dev *input; struct input_dev *input;
int pin, i; int ret;
int error;
gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);
if (!pdata) { if (!gmouse)
dev_err(&pdev->dev, "no platform data\n"); return -ENOMEM;
error = -ENXIO;
goto out; /* Assign some default scanning time */
} ret = device_property_read_u32(dev, "scan-interval-ms",
&gmouse->scan_ms);
if (pdata->scan_ms < 0) { if (ret || gmouse->scan_ms == 0) {
dev_err(&pdev->dev, "invalid scan time\n"); dev_warn(dev, "invalid scan time, set to 50 ms\n");
error = -EINVAL; gmouse->scan_ms = 50;
goto out;
} }
for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);
pin = pdata->pins[i]; if (IS_ERR(gmouse->up))
return PTR_ERR(gmouse->up);
if (pin < 0) { gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);
if (IS_ERR(gmouse->down))
if (i <= GPIO_MOUSE_PIN_RIGHT) { return PTR_ERR(gmouse->down);
/* Mouse direction is required. */ gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);
dev_err(&pdev->dev, if (IS_ERR(gmouse->left))
"missing GPIO for directions\n"); return PTR_ERR(gmouse->left);
error = -EINVAL; gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);
goto out_free_gpios; if (IS_ERR(gmouse->right))
} return PTR_ERR(gmouse->right);
if (i == GPIO_MOUSE_PIN_BLEFT) gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);
dev_dbg(&pdev->dev, "no left button defined\n"); if (IS_ERR(gmouse->bleft))
return PTR_ERR(gmouse->bleft);
} else { gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",
error = gpio_request(pin, "gpio_mouse"); GPIOD_IN);
if (error) { if (IS_ERR(gmouse->bmiddle))
dev_err(&pdev->dev, "fail %d pin (%d idx)\n", return PTR_ERR(gmouse->bmiddle);
pin, i); gmouse->bright = devm_gpiod_get_optional(dev, "button-right",
goto out_free_gpios; GPIOD_IN);
} if (IS_ERR(gmouse->bright))
return PTR_ERR(gmouse->bright);
gpio_direction_input(pin);
} input_poll = devm_input_allocate_polled_device(dev);
}
input_poll = input_allocate_polled_device();
if (!input_poll) { if (!input_poll) {
dev_err(&pdev->dev, "not enough memory for input device\n"); dev_err(dev, "not enough memory for input device\n");
error = -ENOMEM; return -ENOMEM;
goto out_free_gpios;
} }
platform_set_drvdata(pdev, input_poll); platform_set_drvdata(pdev, input_poll);
/* set input-polldev handlers */ /* set input-polldev handlers */
input_poll->private = pdata; input_poll->private = gmouse;
input_poll->poll = gpio_mouse_scan; 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 = input_poll->input;
input->name = pdev->name; input->name = pdev->name;
...@@ -114,63 +135,39 @@ static int gpio_mouse_probe(struct platform_device *pdev) ...@@ -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_X);
input_set_capability(input, EV_REL, REL_Y); input_set_capability(input, EV_REL, REL_Y);
if (pdata->bleft >= 0) if (gmouse->bleft)
input_set_capability(input, EV_KEY, BTN_LEFT); input_set_capability(input, EV_KEY, BTN_LEFT);
if (pdata->bmiddle >= 0) if (gmouse->bmiddle)
input_set_capability(input, EV_KEY, BTN_MIDDLE); input_set_capability(input, EV_KEY, BTN_MIDDLE);
if (pdata->bright >= 0) if (gmouse->bright)
input_set_capability(input, EV_KEY, BTN_RIGHT); input_set_capability(input, EV_KEY, BTN_RIGHT);
error = input_register_polled_device(input_poll); ret = input_register_polled_device(input_poll);
if (error) { if (ret) {
dev_err(&pdev->dev, "could not register input device\n"); dev_err(dev, "could not register input device\n");
goto out_free_polldev; return ret;
} }
dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n", dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",
pdata->scan_ms, gmouse->scan_ms,
pdata->bleft < 0 ? "" : "left ", gmouse->bleft ? "" : "left ",
pdata->bmiddle < 0 ? "" : "middle ", gmouse->bmiddle ? "" : "middle ",
pdata->bright < 0 ? "" : "right"); gmouse->bright ? "" : "right");
return 0; 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) static const struct of_device_id gpio_mouse_of_match[] = {
{ { .compatible = "gpio-mouse", },
struct input_polled_dev *input = platform_get_drvdata(pdev); { },
struct gpio_mouse_platform_data *pdata = input->private; };
int pin, i; MODULE_DEVICE_TABLE(of, gpio_mouse_of_match);
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);
}
return 0;
}
static struct platform_driver gpio_mouse_device_driver = { static struct platform_driver gpio_mouse_device_driver = {
.probe = gpio_mouse_probe, .probe = gpio_mouse_probe,
.remove = gpio_mouse_remove,
.driver = { .driver = {
.name = "gpio_mouse", .name = "gpio_mouse",
.of_match_table = gpio_mouse_of_match,
} }
}; };
module_platform_driver(gpio_mouse_device_driver); module_platform_driver(gpio_mouse_device_driver);
...@@ -179,4 +176,3 @@ MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); ...@@ -179,4 +176,3 @@ MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("GPIO mouse driver"); MODULE_DESCRIPTION("GPIO mouse driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */ MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
...@@ -73,7 +73,7 @@ enum rmi_f54_report_type { ...@@ -73,7 +73,7 @@ enum rmi_f54_report_type {
F54_MAX_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_REPORT_NONE] = "Unknown",
[F54_8BIT_IMAGE] = "Normalized 8-Bit Image", [F54_8BIT_IMAGE] = "Normalized 8-Bit Image",
[F54_16BIT_IMAGE] = "Normalized 16-Bit Image", [F54_16BIT_IMAGE] = "Normalized 16-Bit Image",
......
...@@ -784,7 +784,7 @@ static void hil_mlcs_process(unsigned long unused) ...@@ -784,7 +784,7 @@ static void hil_mlcs_process(unsigned long unused)
/************************* Keepalive timer task *********************/ /************************* Keepalive timer task *********************/
static void hil_mlcs_timer(unsigned long data) static void hil_mlcs_timer(struct timer_list *unused)
{ {
hil_mlcs_probe = 1; hil_mlcs_probe = 1;
tasklet_schedule(&hil_mlcs_tasklet); tasklet_schedule(&hil_mlcs_tasklet);
...@@ -998,7 +998,7 @@ int hil_mlc_unregister(hil_mlc *mlc) ...@@ -998,7 +998,7 @@ int hil_mlc_unregister(hil_mlc *mlc)
static int __init hil_mlc_init(void) 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); mod_timer(&hil_mlcs_kicker, jiffies + HZ);
tasklet_enable(&hil_mlcs_tasklet); tasklet_enable(&hil_mlcs_tasklet);
......
...@@ -794,7 +794,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) ...@@ -794,7 +794,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
/************************* Keepalive timer task *********************/ /************************* 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); tasklet_schedule(&hp_sdc.task);
/* Re-insert the periodic task. */ /* Re-insert the periodic task. */
...@@ -909,9 +909,8 @@ static int __init hp_sdc_init(void) ...@@ -909,9 +909,8 @@ static int __init hp_sdc_init(void)
down(&s_sync); /* Wait for t_sync to complete */ down(&s_sync); /* Wait for t_sync to complete */
/* Create the keepalive task */ /* 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.expires = jiffies + HZ;
hp_sdc.kicker.function = &hp_sdc_kicker;
add_timer(&hp_sdc.kicker); add_timer(&hp_sdc.kicker);
hp_sdc.dev_err = 0; hp_sdc.dev_err = 0;
......
...@@ -366,6 +366,7 @@ static int ps2_gpio_probe(struct platform_device *pdev) ...@@ -366,6 +366,7 @@ static int ps2_gpio_probe(struct platform_device *pdev)
gpiod_cansleep(drvdata->gpio_clk)) { gpiod_cansleep(drvdata->gpio_clk)) {
dev_err(dev, "GPIO data or clk are connected via slow bus\n"); dev_err(dev, "GPIO data or clk are connected via slow bus\n");
error = -EINVAL; error = -EINVAL;
goto err_free_serio;
} }
drvdata->irq = platform_get_irq(pdev, 0); drvdata->irq = platform_get_irq(pdev, 0);
......
...@@ -47,6 +47,8 @@ struct ps2if { ...@@ -47,6 +47,8 @@ struct ps2if {
struct serio *io; struct serio *io;
struct sa1111_dev *dev; struct sa1111_dev *dev;
void __iomem *base; void __iomem *base;
int rx_irq;
int tx_irq;
unsigned int open; unsigned int open;
spinlock_t lock; spinlock_t lock;
unsigned int head; unsigned int head;
...@@ -64,22 +66,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id) ...@@ -64,22 +66,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
struct ps2if *ps2if = dev_id; struct ps2if *ps2if = dev_id;
unsigned int scancode, flag, status; unsigned int scancode, flag, status;
status = sa1111_readl(ps2if->base + PS2STAT); status = readl_relaxed(ps2if->base + PS2STAT);
while (status & PS2STAT_RXF) { while (status & PS2STAT_RXF) {
if (status & PS2STAT_STP) 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) | flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
(status & PS2STAT_RXP ? 0 : SERIO_PARITY); (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff; scancode = readl_relaxed(ps2if->base + PS2DATA) & 0xff;
if (hweight8(scancode) & 1) if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY; flag ^= SERIO_PARITY;
serio_interrupt(ps2if->io, scancode, flag); serio_interrupt(ps2if->io, scancode, flag);
status = sa1111_readl(ps2if->base + PS2STAT); status = readl_relaxed(ps2if->base + PS2STAT);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -94,12 +96,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id) ...@@ -94,12 +96,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
unsigned int status; unsigned int status;
spin_lock(&ps2if->lock); spin_lock(&ps2if->lock);
status = sa1111_readl(ps2if->base + PS2STAT); status = readl_relaxed(ps2if->base + PS2STAT);
if (ps2if->head == ps2if->tail) { if (ps2if->head == ps2if->tail) {
disable_irq_nosync(irq); disable_irq_nosync(irq);
/* done */ /* done */
} else if (status & PS2STAT_TXE) { } 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); ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
} }
spin_unlock(&ps2if->lock); spin_unlock(&ps2if->lock);
...@@ -122,11 +124,11 @@ static int ps2_write(struct serio *io, unsigned char val) ...@@ -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 the TX register is empty, we can go straight out.
*/ */
if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) { if (readl_relaxed(ps2if->base + PS2STAT) & PS2STAT_TXE) {
sa1111_writel(val, ps2if->base + PS2DATA); writel_relaxed(val, ps2if->base + PS2DATA);
} else { } else {
if (ps2if->head == ps2if->tail) if (ps2if->head == ps2if->tail)
enable_irq(ps2if->dev->irq[1]); enable_irq(ps2if->tx_irq);
head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1); head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
if (head != ps2if->tail) { if (head != ps2if->tail) {
ps2if->buf[ps2if->head] = val; ps2if->buf[ps2if->head] = val;
...@@ -147,30 +149,30 @@ static int ps2_open(struct serio *io) ...@@ -147,30 +149,30 @@ static int ps2_open(struct serio *io)
if (ret) if (ret)
return 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); SA1111_DRIVER_NAME(ps2if->dev), ps2if);
if (ret) { if (ret) {
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", 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); sa1111_disable_device(ps2if->dev);
return ret; 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); SA1111_DRIVER_NAME(ps2if->dev), ps2if);
if (ret) { if (ret) {
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
ps2if->dev->irq[1], ret); ps2if->tx_irq, ret);
free_irq(ps2if->dev->irq[0], ps2if); free_irq(ps2if->rx_irq, ps2if);
sa1111_disable_device(ps2if->dev); sa1111_disable_device(ps2if->dev);
return ret; return ret;
} }
ps2if->open = 1; 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; return 0;
} }
...@@ -178,14 +180,14 @@ static void ps2_close(struct serio *io) ...@@ -178,14 +180,14 @@ static void ps2_close(struct serio *io)
{ {
struct ps2if *ps2if = io->port_data; 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; ps2if->open = 0;
free_irq(ps2if->dev->irq[1], ps2if); free_irq(ps2if->tx_irq, ps2if);
free_irq(ps2if->dev->irq[0], ps2if); free_irq(ps2if->rx_irq, ps2if);
sa1111_disable_device(ps2if->dev); sa1111_disable_device(ps2if->dev);
} }
...@@ -198,7 +200,7 @@ static void ps2_clear_input(struct ps2if *ps2if) ...@@ -198,7 +200,7 @@ static void ps2_clear_input(struct ps2if *ps2if)
int maxread = 100; int maxread = 100;
while (maxread--) { while (maxread--) {
if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff) if ((readl_relaxed(ps2if->base + PS2DATA) & 0xff) == 0xff)
break; break;
} }
} }
...@@ -208,11 +210,11 @@ static unsigned int ps2_test_one(struct ps2if *ps2if, ...@@ -208,11 +210,11 @@ static unsigned int ps2_test_one(struct ps2if *ps2if,
{ {
unsigned int val; 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); return val & (PS2STAT_KBC | PS2STAT_KBD);
} }
...@@ -243,7 +245,7 @@ static int ps2_test(struct ps2if *ps2if) ...@@ -243,7 +245,7 @@ static int ps2_test(struct ps2if *ps2if)
ret = -ENODEV; ret = -ENODEV;
} }
sa1111_writel(0, ps2if->base + PS2CR); writel_relaxed(0, ps2if->base + PS2CR);
return ret; return ret;
} }
...@@ -264,7 +266,6 @@ static int ps2_probe(struct sa1111_dev *dev) ...@@ -264,7 +266,6 @@ static int ps2_probe(struct sa1111_dev *dev)
goto free; goto free;
} }
serio->id.type = SERIO_8042; serio->id.type = SERIO_8042;
serio->write = ps2_write; serio->write = ps2_write;
serio->open = ps2_open; serio->open = ps2_open;
...@@ -279,6 +280,18 @@ static int ps2_probe(struct sa1111_dev *dev) ...@@ -279,6 +280,18 @@ static int ps2_probe(struct sa1111_dev *dev)
spin_lock_init(&ps2if->lock); 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. * Request the physical region for this PS2 port.
*/ */
...@@ -297,8 +310,8 @@ static int ps2_probe(struct sa1111_dev *dev) ...@@ -297,8 +310,8 @@ static int ps2_probe(struct sa1111_dev *dev)
sa1111_enable_device(ps2if->dev); sa1111_enable_device(ps2if->dev);
/* Incoming clock is 8MHz */ /* Incoming clock is 8MHz */
sa1111_writel(0, ps2if->base + PS2CLKDIV); writel_relaxed(0, ps2if->base + PS2CLKDIV);
sa1111_writel(127, ps2if->base + PS2PRECNT); writel_relaxed(127, ps2if->base + PS2PRECNT);
/* /*
* Flush any pending input. * Flush any pending input.
......
...@@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL ...@@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial. 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 config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen" tristate "Fujitsu serial touchscreen"
select SERIO select SERIO
...@@ -344,6 +354,17 @@ config TOUCHSCREEN_GOODIX ...@@ -344,6 +354,17 @@ config TOUCHSCREEN_GOODIX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called goodix. 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 config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen" tristate "Ilitek ILI210X based touchscreen"
depends on I2C depends on I2C
...@@ -383,6 +404,17 @@ config TOUCHSCREEN_S3C2410 ...@@ -383,6 +404,17 @@ config TOUCHSCREEN_S3C2410
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called s3c2410_ts. 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 config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen" tristate "Gunze AHL-51S touchscreen"
select SERIO select SERIO
...@@ -949,7 +981,7 @@ config TOUCHSCREEN_USB_NEXIO ...@@ -949,7 +981,7 @@ config TOUCHSCREEN_USB_NEXIO
config TOUCHSCREEN_USB_EASYTOUCH config TOUCHSCREEN_USB_EASYTOUCH
default y 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 depends on TOUCHSCREEN_USB_COMPOSITE
help help
Say Y here if you have an EasyTouch USB Touch controller. Say Y here if you have an EasyTouch USB Touch controller.
......
...@@ -38,8 +38,10 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o ...@@ -38,8 +38,10 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.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_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
...@@ -65,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o ...@@ -65,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
......
...@@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) ...@@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
input_sync(input_dev); 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; unsigned long flags;
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
...@@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi) ...@@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi)
ts->spi = spi; ts->spi = spi;
ts->input = input_dev; ts->input = input_dev;
setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts); timer_setup(&ts->timer, ad7877_timer, 0);
mutex_init(&ts->mutex); mutex_init(&ts->mutex);
spin_lock_init(&ts->lock); spin_lock_init(&ts->lock);
......
...@@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts) ...@@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
input_sync(input_dev); 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); ad7879_ts_event_release(ts);
} }
...@@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) ...@@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
return 0; 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 ad7879_probe(struct device *dev, struct regmap *regmap,
int irq, u16 bustype, u8 devid) int irq, u16 bustype, u8 devid)
{ {
...@@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, ...@@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
ts->irq = irq; ts->irq = irq;
ts->regmap = regmap; 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)); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
input_dev->name = "AD7879 Touchscreen"; input_dev->name = "AD7879 Touchscreen";
...@@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, ...@@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
__ad7879_disable(ts); __ad7879_disable(ts);
err = sysfs_create_group(&dev->kobj, &ad7879_attr_group); err = devm_device_add_group(dev, &ad7879_attr_group);
if (err)
return err;
err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts);
if (err) if (err)
return err; return err;
......
...@@ -208,9 +208,12 @@ static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm) ...@@ -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) static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
...@@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev) ...@@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
atmel_wm97xx->gpio_pen = atmel_gpio_line; atmel_wm97xx->gpio_pen = atmel_gpio_line;
atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen); atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen);
setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0);
(unsigned long)wm);
ret = request_irq(atmel_wm97xx->ac97c_irq, ret = request_irq(atmel_wm97xx->ac97c_irq,
atmel_wm97xx_channel_b_interrupt, atmel_wm97xx_channel_b_interrupt,
......
...@@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd) ...@@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
void *p; void *p;
int rc; 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; 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__, dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
si->si_ofs.cydata_size); si->si_ofs.cydata_size);
p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL); p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
if (p == NULL) { 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; return -ENOMEM;
} }
si->si_ptrs.cydata = p; si->si_ptrs.cydata = p;
...@@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd) ...@@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
void *p; void *p;
int rc; 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; 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); p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
if (p == NULL) { 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; return -ENOMEM;
} }
si->si_ptrs.test = p; si->si_ptrs.test = p;
...@@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd) ...@@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
void *p; void *p;
int rc; 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; 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); p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
if (p == NULL) { if (p == NULL) {
rc = -ENOMEM; dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n", __func__);
__func__, rc); return -ENOMEM;
return rc;
} }
si->si_ptrs.pcfg = p; si->si_ptrs.pcfg = p;
...@@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) ...@@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
void *p; void *p;
int rc; 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; 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); p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
if (p == NULL) { if (p == NULL) {
dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__); dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
rc = -ENOMEM; __func__);
goto cyttsp4_si_get_opcfg_data_exit; return -ENOMEM;
} }
si->si_ptrs.opcfg = p; si->si_ptrs.opcfg = p;
...@@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd) ...@@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
if (rc < 0) { if (rc < 0) {
dev_err(cd->dev, "%s: fail read opcfg data r=%d\n", dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
__func__, rc); __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.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_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) ...@@ -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, cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
si->si_ofs.opcfg_size, "sysinfo_opcfg_data"); si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
cyttsp4_si_get_opcfg_data_exit: return 0;
return rc;
} }
static int cyttsp4_si_get_ddata(struct cyttsp4 *cd) static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
...@@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd) ...@@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
del_timer_sync(&cd->watchdog_timer); 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__); dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
...@@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops, ...@@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
} }
/* Setup watchdog timer */ /* Setup watchdog timer */
setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer, timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
(unsigned long)cd);
/* /*
* call startup directly to ensure that the device * call startup directly to ensure that the device
......
...@@ -70,8 +70,10 @@ ...@@ -70,8 +70,10 @@
#define EDT_RAW_DATA_DELAY 1000 /* usec */ #define EDT_RAW_DATA_DELAY 1000 /* usec */
enum edt_ver { enum edt_ver {
M06, EDT_M06,
M09, EDT_M09,
EDT_M12,
GENERIC_FT,
}; };
struct edt_reg_addr { struct edt_reg_addr {
...@@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) ...@@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
int error; int error;
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
cmd = 0xf9; /* tell the controller to send touch data */ cmd = 0xf9; /* tell the controller to send touch data */
offset = 5; /* where the actual touch data starts */ offset = 5; /* where the actual touch data starts */
tplen = 4; /* data comes in so called frames */ tplen = 4; /* data comes in so called frames */
crclen = 1; /* length of the crc data */ crclen = 1; /* length of the crc data */
break; break;
case M09: case EDT_M09:
case EDT_M12:
case GENERIC_FT:
cmd = 0x0; cmd = 0x0;
offset = 3; offset = 3;
tplen = 6; tplen = 6;
...@@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) ...@@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
goto out; goto out;
} }
/* M09 does not send header or CRC */ /* M09/M12 does not send header or CRC */
if (tsdata->version == M06) { if (tsdata->version == EDT_M06) {
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
rdbuf[2] != datalen) { rdbuf[2] != datalen) {
dev_err_ratelimited(dev, dev_err_ratelimited(dev,
...@@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) ...@@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
continue; continue;
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ /* 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; continue;
x = ((buf[0] << 8) | buf[1]) & 0x0fff; x = ((buf[0] << 8) | buf[1]) & 0x0fff;
...@@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, ...@@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
u8 wrbuf[4]; u8 wrbuf[4];
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[2] = value; wrbuf[2] = value;
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
return edt_ft5x06_ts_readwrite(tsdata->client, 4, return edt_ft5x06_ts_readwrite(tsdata->client, 4,
wrbuf, 0, NULL); wrbuf, 0, NULL);
case M09: case EDT_M09:
case EDT_M12:
case GENERIC_FT:
wrbuf[0] = addr; wrbuf[0] = addr;
wrbuf[1] = value; wrbuf[1] = value;
...@@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, ...@@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
int error; int error;
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
...@@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, ...@@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
} }
break; break;
case M09: case EDT_M09:
case EDT_M12:
case GENERIC_FT:
wrbuf[0] = addr; wrbuf[0] = addr;
error = edt_ft5x06_ts_readwrite(tsdata->client, 1, error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
wrbuf, 1, rdbuf); wrbuf, 1, rdbuf);
...@@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, ...@@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
} }
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
addr = attr->addr_m06; addr = attr->addr_m06;
break; break;
case M09: case EDT_M09:
case EDT_M12:
case GENERIC_FT:
addr = attr->addr_m09; addr = attr->addr_m09;
break; break;
...@@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, ...@@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
} }
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
addr = attr->addr_m06; addr = attr->addr_m06;
break; break;
case M09: case EDT_M09:
case EDT_M12:
case GENERIC_FT:
addr = attr->addr_m09; addr = attr->addr_m09;
break; break;
...@@ -466,14 +478,18 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, ...@@ -466,14 +478,18 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
return error ?: count; return error ?: count;
} }
/* m06, m09: range 0-31, m12: range 0-5 */
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
M09_REGISTER_GAIN, 0, 31); 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, static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
M09_REGISTER_OFFSET, 0, 31); 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, 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, 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[] = { static struct attribute *edt_ft5x06_attrs[] = {
&edt_ft5x06_attr_gain.dattr.attr, &edt_ft5x06_attr_gain.dattr.attr,
...@@ -508,7 +524,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) ...@@ -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 */ /* mode register is 0x3c when in the work mode */
if (tsdata->version == M09) if (tsdata->version != EDT_M06)
goto m09_out; goto m09_out;
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); 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) ...@@ -545,7 +561,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
return error; return error;
m09_out: 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; return -EINVAL;
} }
...@@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, ...@@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
* to have garbage in there * to have garbage in there
*/ */
memset(rdbuf, 0, sizeof(rdbuf)); 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); EDT_NAME_LEN - 1, rdbuf);
if (error) if (error)
return error; return error;
/* if we find something consistent, stay with that assumption /* Probe content for something consistent.
* at least M09 won't send 3 bytes here * 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))) { if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
tsdata->version = M06; tsdata->version = EDT_M06;
/* remove last '$' end marker */ /* remove last '$' end marker */
rdbuf[EDT_NAME_LEN - 1] = '\0'; rdbuf[EDT_NAME_LEN - 1] = '\0';
...@@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, ...@@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
*p++ = '\0'; *p++ = '\0';
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
strlcpy(fw_version, p ? p : "", 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 { } else {
/* since there are only two versions around (M06, M09) */ /* If it is not an EDT M06/M12 touchscreen, then the model
tsdata->version = M09; * 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", error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
2, rdbuf); 2, rdbuf);
...@@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, ...@@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
if (error) if (error)
return error; return error;
/* 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", snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
rdbuf[0] >> 4, rdbuf[0] & 0x0F); 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; return 0;
...@@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) ...@@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
if (reg_addr->reg_report_rate != NO_REGISTER) if (reg_addr->reg_report_rate != NO_REGISTER)
tsdata->report_rate = edt_ft5x06_register_read(tsdata, tsdata->report_rate = edt_ft5x06_register_read(tsdata,
reg_addr->reg_report_rate); reg_addr->reg_report_rate);
tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); if (tsdata->version == EDT_M06 ||
tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); 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 static void
...@@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) ...@@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
struct edt_reg_addr *reg_addr = &tsdata->reg_addr; struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
switch (tsdata->version) { switch (tsdata->version) {
case M06: case EDT_M06:
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
reg_addr->reg_gain = WORK_REGISTER_GAIN; reg_addr->reg_gain = WORK_REGISTER_GAIN;
...@@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) ...@@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
break; break;
case M09: case EDT_M09:
case EDT_M12:
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_report_rate = NO_REGISTER;
reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_gain = M09_REGISTER_GAIN;
...@@ -880,6 +955,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) ...@@ -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_x = M09_REGISTER_NUM_X;
reg_addr->reg_num_y = M09_REGISTER_NUM_Y; reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
break; 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, ...@@ -969,10 +1051,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input->id.bustype = BUS_I2C; input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev; input->dev.parent = &client->dev;
if (tsdata->version == EDT_M06 ||
tsdata->version == EDT_M09 ||
tsdata->version == EDT_M12) {
input_set_abs_params(input, ABS_MT_POSITION_X, input_set_abs_params(input, ABS_MT_POSITION_X,
0, tsdata->num_x * 64 - 1, 0, 0); 0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0); 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); touchscreen_parse_properties(input, true, &tsdata->prop);
...@@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error; 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) if (error)
return error; return error;
error = input_register_device(input); error = input_register_device(input);
if (error) if (error)
goto err_remove_attrs; return error;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1); device_init_wakeup(&client->dev, 1);
...@@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, ...@@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
return 0; 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) static int edt_ft5x06_ts_remove(struct i2c_client *client)
...@@ -1027,7 +1115,6 @@ 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); struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
edt_ft5x06_ts_teardown_debugfs(tsdata); edt_ft5x06_ts_teardown_debugfs(tsdata);
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return 0; return 0;
} }
......
...@@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = { ...@@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = {
.attrs = elants_attributes, .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) static int elants_i2c_power_on(struct elants_data *ts)
{ {
int error; int error;
...@@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client, ...@@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client,
if (!client->dev.of_node) if (!client->dev.of_node)
device_init_wakeup(&client->dev, true); 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) { if (error) {
dev_err(&client->dev, "failed to create sysfs attributes: %d\n", dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
error); error);
return 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; return 0;
} }
......
/*
* 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 @@ ...@@ -31,9 +31,18 @@
#include <linux/of.h> #include <linux/of.h>
#include <asm/unaligned.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 goodix_ts_data {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input_dev; struct input_dev *input_dev;
const struct goodix_chip_data *chip;
int abs_x_max; int abs_x_max;
int abs_y_max; int abs_y_max;
bool swapped_x_y; bool swapped_x_y;
...@@ -41,7 +50,6 @@ struct goodix_ts_data { ...@@ -41,7 +50,6 @@ struct goodix_ts_data {
bool inverted_y; bool inverted_y;
unsigned int max_touch_num; unsigned int max_touch_num;
unsigned int int_trigger_type; unsigned int int_trigger_type;
int cfg_len;
struct gpio_desc *gpiod_int; struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst; struct gpio_desc *gpiod_rst;
u16 id; u16 id;
...@@ -69,7 +77,8 @@ struct goodix_ts_data { ...@@ -69,7 +77,8 @@ struct goodix_ts_data {
#define GOODIX_CMD_SCREEN_OFF 0x05 #define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E #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_REG_ID 0x8140
#define GOODIX_BUFFER_STATUS_READY BIT(7) #define GOODIX_BUFFER_STATUS_READY BIT(7)
...@@ -79,6 +88,35 @@ struct goodix_ts_data { ...@@ -79,6 +88,35 @@ struct goodix_ts_data {
#define MAX_CONTACTS_LOC 5 #define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6 #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[] = { static const unsigned long goodix_irq_flags[] = {
IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_EDGE_FALLING,
...@@ -177,22 +215,25 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) ...@@ -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)); 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) { switch (id) {
case 1151:
return &gt1x_chip_data;
case 911: case 911:
case 9271: case 9271:
case 9110: case 9110:
case 927: case 927:
case 928: case 928:
return GOODIX_CONFIG_911_LENGTH; return &gt911_chip_data;
case 912: case 912:
case 967: case 967:
return GOODIX_CONFIG_967_LENGTH; return &gt967_chip_data;
default: default:
return GOODIX_CONFIG_MAX_LENGTH; return &gt9x_chip_data;
} }
} }
...@@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts) ...@@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts)
ts->irq_flags, ts->client->name, ts); ts->irq_flags, ts->client->name, ts);
} }
/** static int goodix_check_cfg_8(struct goodix_ts_data *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) const struct firmware *cfg)
{ {
int i, raw_cfg_len; int i, raw_cfg_len = cfg->size - 2;
u8 check_sum = 0; 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++) for (i = 0; i < raw_cfg_len; i++)
check_sum += cfg->data[i]; check_sum += cfg->data[i];
check_sum = (~check_sum) + 1; check_sum = (~check_sum) + 1;
...@@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, ...@@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts,
return 0; 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 * goodix_send_cfg - Write fw config to device
* *
...@@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts, ...@@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts,
if (error) if (error)
return 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); cfg->size);
if (error) { if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d", 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) ...@@ -511,8 +581,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
u8 config[GOODIX_CONFIG_MAX_LENGTH]; u8 config[GOODIX_CONFIG_MAX_LENGTH];
int error; int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA, error = goodix_i2c_read(ts->client, ts->chip->config_addr,
config, ts->cfg_len); config, ts->chip->config_len);
if (error) { if (error) {
dev_warn(&ts->client->dev, dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n", "Error reading config (%d), using defaults\n",
...@@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client) ...@@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client)
u8 test; u8 test;
while (retry++ < 2) { while (retry++ < 2) {
error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA, error = goodix_i2c_read(client, GOODIX_REG_ID,
&test, 1); &test, 1);
if (!error) if (!error)
return 0; return 0;
...@@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client, ...@@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client,
return error; 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) { if (ts->gpiod_int && ts->gpiod_rst) {
/* update device config */ /* update device config */
...@@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); ...@@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id goodix_of_match[] = { static const struct of_device_id goodix_of_match[] = {
{ .compatible = "goodix,gt1151" },
{ .compatible = "goodix,gt911" }, { .compatible = "goodix,gt911" },
{ .compatible = "goodix,gt9110" }, { .compatible = "goodix,gt9110" },
{ .compatible = "goodix,gt912" }, { .compatible = "goodix,gt912" },
......
此差异已折叠。
...@@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = { ...@@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = {
.attrs = mip4_attrs, .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) static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
struct mip4_ts *ts; struct mip4_ts *ts;
...@@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
return error; return error;
} }
error = sysfs_create_group(&client->dev.kobj, &mip4_attr_group); error = devm_device_add_group(&client->dev, &mip4_attr_group);
if (error) { if (error) {
dev_err(&client->dev, dev_err(&client->dev,
"Failed to create sysfs attribute group: %d\n", error); "Failed to create sysfs attribute group: %d\n", error);
return 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; return 0;
} }
......
...@@ -584,7 +584,7 @@ static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts) ...@@ -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) 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; struct device *dev = ts->dev;
input = devm_input_allocate_device(dev); input = devm_input_allocate_device(dev);
......
...@@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = { ...@@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = {
.attrs = raydium_i2c_attributes, .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) static int raydium_i2c_power_on(struct raydium_data *ts)
{ {
int error; int error;
...@@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client, ...@@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client,
return error; return error;
} }
error = sysfs_create_group(&client->dev.kobj, error = devm_device_add_group(&client->dev,
&raydium_i2c_attribute_group); &raydium_i2c_attribute_group);
if (error) { if (error) {
dev_err(&client->dev, "failed to create sysfs attributes: %d\n", dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
...@@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client, ...@@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client,
return error; 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; return 0;
} }
......
...@@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev) ...@@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev)
ts->initialized = false; 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, static int rohm_bu21023_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client, ...@@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client,
return error; return error;
} }
error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group); error = devm_device_add_group(dev, &rohm_ts_attr_group);
if (error) { if (error) {
dev_err(dev, "failed to create sysfs group: %d\n", error); dev_err(dev, "failed to create sysfs group: %d\n", error);
return 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; return error;
} }
......
/*
* 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 @@ ...@@ -29,7 +29,6 @@
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/platform_data/st1232_pdata.h>
#define ST1232_TS_NAME "st1232-ts" #define ST1232_TS_NAME "st1232-ts"
...@@ -155,7 +154,6 @@ static int st1232_ts_probe(struct i2c_client *client, ...@@ -155,7 +154,6 @@ 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_ts_data *ts;
struct st1232_pdata *pdata = dev_get_platdata(&client->dev);
struct input_dev *input_dev; struct input_dev *input_dev;
int error; int error;
...@@ -180,13 +178,7 @@ static int st1232_ts_probe(struct i2c_client *client, ...@@ -180,13 +178,7 @@ static int st1232_ts_probe(struct i2c_client *client,
ts->client = client; ts->client = client;
ts->input_dev = input_dev; 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); ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
else
ts->reset_gpio = -ENODEV;
if (gpio_is_valid(ts->reset_gpio)) { if (gpio_is_valid(ts->reset_gpio)) {
error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL); error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
if (error) { if (error) {
...@@ -281,13 +273,11 @@ static const struct i2c_device_id st1232_ts_id[] = { ...@@ -281,13 +273,11 @@ static const struct i2c_device_id st1232_ts_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, st1232_ts_id); MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id st1232_ts_dt_ids[] = { static const struct of_device_id st1232_ts_dt_ids[] = {
{ .compatible = "sitronix,st1232", }, { .compatible = "sitronix,st1232", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
#endif
static struct i2c_driver st1232_ts_driver = { static struct i2c_driver st1232_ts_driver = {
.probe = st1232_ts_probe, .probe = st1232_ts_probe,
...@@ -295,7 +285,7 @@ static struct i2c_driver st1232_ts_driver = { ...@@ -295,7 +285,7 @@ static struct i2c_driver st1232_ts_driver = {
.id_table = st1232_ts_id, .id_table = st1232_ts_id,
.driver = { .driver = {
.name = ST1232_TS_NAME, .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, .pm = &st1232_ts_pm_ops,
}, },
}; };
......
...@@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client, ...@@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client,
} }
} }
err = sysfs_create_group(&sdata->client->dev.kobj, err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
&stmfts_attribute_group);
if (err) if (err)
return err; return err;
...@@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client, ...@@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client,
static int stmfts_remove(struct i2c_client *client) static int stmfts_remove(struct i2c_client *client)
{ {
pm_runtime_disable(&client->dev); pm_runtime_disable(&client->dev);
sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group);
return 0; return 0;
} }
......
...@@ -202,9 +202,9 @@ static irqreturn_t tsc200x_irq_thread(int irq, void *_ts) ...@@ -202,9 +202,9 @@ static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
return IRQ_HANDLED; 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; unsigned long flags;
spin_lock_irqsave(&ts->lock, 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, ...@@ -506,7 +506,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
mutex_init(&ts->mutex); mutex_init(&ts->mutex);
spin_lock_init(&ts->lock); 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); INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
......
...@@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) ...@@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; 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; unsigned long flags;
spin_lock_irqsave(&w90p910_ts->lock, flags); spin_lock_irqsave(&w90p910_ts->lock, flags);
...@@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev) ...@@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev)
w90p910_ts->input = input_dev; w90p910_ts->input = input_dev;
w90p910_ts->state = TS_IDLE; w90p910_ts->state = TS_IDLE;
spin_lock_init(&w90p910_ts->lock); spin_lock_init(&w90p910_ts->lock);
setup_timer(&w90p910_ts->timer, w90p910_check_pen_up, timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0);
(unsigned long)w90p910_ts);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
......
...@@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client, ...@@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
return error; return error;
} }
error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group); error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
if (error) { if (error) {
dev_err(&client->dev, "create sysfs failed: %d\n", error); dev_err(&client->dev, "create sysfs failed: %d\n", error);
return error; return error;
...@@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client, ...@@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
return 0; 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) static int __maybe_unused wdt87xx_suspend(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
...@@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id); ...@@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
static struct i2c_driver wdt87xx_driver = { static struct i2c_driver wdt87xx_driver = {
.probe = wdt87xx_ts_probe, .probe = wdt87xx_ts_probe,
.remove = wdt87xx_ts_remove,
.id_table = wdt87xx_dev_id, .id_table = wdt87xx_dev_id,
.driver = { .driver = {
.name = WDT87XX_NAME, .name = WDT87XX_NAME,
......
...@@ -94,7 +94,7 @@ struct infrared { ...@@ -94,7 +94,7 @@ struct infrared {
u8 inversion; u8 inversion;
u16 last_key; u16 last_key;
u16 last_toggle; u16 last_toggle;
u8 delay_timer_finished; bool keypressed;
}; };
......
...@@ -84,15 +84,16 @@ static u16 default_key_map [256] = { ...@@ -84,15 +84,16 @@ static u16 default_key_map [256] = {
/* key-up timer */ /* 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; return;
input_report_key(ir->input_dev, ir->last_key, 0); input_report_key(ir->input_dev, ir->last_key, 0);
input_sync(ir->input_dev); input_sync(ir->input_dev);
ir->keypressed = false;
} }
...@@ -152,29 +153,18 @@ static void av7110_emit_key(unsigned long parm) ...@@ -152,29 +153,18 @@ static void av7110_emit_key(unsigned long parm)
return; return;
} }
if (timer_pending(&ir->keyup_timer)) { if (ir->keypressed &&
del_timer(&ir->keyup_timer); (ir->last_key != keycode || toggle != ir->last_toggle))
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, ir->last_key, 0);
input_event(ir->input_dev, EV_KEY, keycode, 1); input_event(ir->input_dev, EV_KEY, keycode, 1);
input_sync(ir->input_dev); 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);
}
ir->keypressed = true;
ir->last_key = keycode; ir->last_key = keycode;
ir->last_toggle = toggle; ir->last_toggle = toggle;
ir->keyup_timer.expires = jiffies + UP_TIMEOUT; mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT);
add_timer(&ir->keyup_timer);
} }
...@@ -204,16 +194,6 @@ static void input_register_keys(struct infrared *ir) ...@@ -204,16 +194,6 @@ static void input_register_keys(struct infrared *ir)
ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); 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 */ /* check for configuration changes */
int av7110_check_ir_config(struct av7110 *av7110, int force) int av7110_check_ir_config(struct av7110 *av7110, int force)
{ {
...@@ -333,8 +313,7 @@ int av7110_ir_init(struct av7110 *av7110) ...@@ -333,8 +313,7 @@ int av7110_ir_init(struct av7110 *av7110)
av_list[av_cnt++] = av7110; av_list[av_cnt++] = av7110;
av7110_check_ir_config(av7110, true); av7110_check_ir_config(av7110, true);
setup_timer(&av7110->ir.keyup_timer, av7110_emit_keyup, timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0);
(unsigned long)&av7110->ir);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev)
...@@ -365,8 +344,13 @@ int av7110_ir_init(struct av7110 *av7110) ...@@ -365,8 +344,13 @@ int av7110_ir_init(struct av7110 *av7110)
input_free_device(input_dev); input_free_device(input_dev);
return err; 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) { if (av_cnt == 1) {
e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
......
/*
* 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 */
/* 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
/*
* 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_ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册