Commit 1c5ff2ab authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 - new driver for eGalaxTouch serial touchscreen
 - new driver for TS-4800 touchscreen
 - an update for Goodix touchscreen driver
 - PS/2 mouse module was reworked to limit number of protocols we try on
   pass-through ports to speed up their detection time
 - wacom_w8001 touchscreen driver now reports pen and touch via separate
   instances of input devices
 - other driver changes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (42 commits)
  Input: elantech - mark protocols v2 and v3 as semi-mt
  Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE
  Input: gpio-keys - fix check for disabling unsupported keys
  Input: omap-keypad - remove dead check
  Input: ti_am335x_tsc - fix HWPEN interrupt handling
  Input: omap-keypad - set tasklet data earlier
  Input: rohm_bu21023 - fix handling of retrying firmware update
  Input: ALPS - report v3 pinnacle trackstick device only if is present
  Input: ALPS - detect trackstick presence for v7 protocol
  Input: pcap_ts - use to_delayed_work
  Input: bma150 - constify bma150_cfg structure
  Input: i8042 - add Fujitsu Lifebook U745 to the nomux list
  Input: egalax_ts_serial - fix potential NULL dereference on error
  Input: uinput - sanity check on ff_effects_max and EV_FF
  Input: uinput - rework ABS validation
  Input: uinput - add new UINPUT_DEV_SETUP and UI_ABS_SETUP ioctl
  Input: goodix - use "inverted_[xy]" flags instead of "rotated_screen"
  Input: goodix - add axis swapping and axis inversion support
  Input: goodix - use goodix_i2c_write_u8 instead of i2c_master_send
  Input: goodix - add power management support
  ...
parents d6a32277 009f7738
...@@ -13,6 +13,17 @@ Required properties: ...@@ -13,6 +13,17 @@ Required properties:
- interrupt-parent : Interrupt controller to which the chip is connected - interrupt-parent : Interrupt controller to which the chip is connected
- interrupts : Interrupt to which the chip is connected - interrupts : Interrupt to which the chip is connected
Optional properties:
- irq-gpios : GPIO pin used for IRQ. The driver uses the
interrupt gpio pin as output to reset the device.
- reset-gpios : GPIO pin used for reset
- touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
(swapping is done after inverting the axis)
Example: Example:
i2c@00000000 { i2c@00000000 {
...@@ -23,6 +34,9 @@ Example: ...@@ -23,6 +34,9 @@ Example:
reg = <0x5d>; reg = <0x5d>;
interrupt-parent = <&gpio>; interrupt-parent = <&gpio>;
interrupts = <0 0>; interrupts = <0 0>;
irq-gpios = <&gpio1 0 0>;
reset-gpios = <&gpio1 1 0>;
}; };
/* ... */ /* ... */
......
...@@ -9,7 +9,9 @@ Required properties: ...@@ -9,7 +9,9 @@ Required properties:
- touchscreen-size-y: vertical resolution of touchscreen (in pixels) - touchscreen-size-y: vertical resolution of touchscreen (in pixels)
Optional properties: Optional properties:
- reset-gpio: GPIO connected to the RESET line of the chip - reset-gpios: GPIO connected to the RESET line of the chip
- enable-gpios: GPIO connected to the ENABLE line of the chip
- wake-gpios: GPIO connected to the WAKE line of the chip
Example: Example:
......
* TS-4800 Touchscreen bindings
Required properties:
- compatible: must be "technologic,ts4800-ts"
- reg: physical base address of the controller and length of memory mapped
region.
- syscon: phandle / integers array that points to the syscon node which
describes the FPGA's syscon registers.
- phandle to FPGA's syscon
- offset to the touchscreen register
- offset to the touchscreen enable bit
...@@ -943,3 +943,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id) ...@@ -943,3 +943,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
} }
return count; return count;
} }
struct acpi_crs_lookup {
struct list_head node;
struct acpi_device *adev;
const char *con_id;
};
static DEFINE_MUTEX(acpi_crs_lookup_lock);
static LIST_HEAD(acpi_crs_lookup_list);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
{
struct acpi_crs_lookup *l, *lookup = NULL;
/* Never allow fallback if the device has properties */
if (adev->data.properties || adev->driver_gpios)
return false;
mutex_lock(&acpi_crs_lookup_lock);
list_for_each_entry(l, &acpi_crs_lookup_list, node) {
if (l->adev == adev) {
lookup = l;
break;
}
}
if (!lookup) {
lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
if (lookup) {
lookup->adev = adev;
lookup->con_id = con_id;
list_add_tail(&lookup->node, &acpi_crs_lookup_list);
}
}
mutex_unlock(&acpi_crs_lookup_lock);
return lookup &&
((!lookup->con_id && !con_id) ||
(lookup->con_id && con_id &&
strcmp(lookup->con_id, con_id) == 0));
}
...@@ -1874,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, ...@@ -1874,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */ /* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) { if (IS_ERR(desc)) {
if (!acpi_can_fallback_to_crs(adev, con_id))
return ERR_PTR(-ENOENT);
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info); desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc)) if (IS_ERR(desc))
return desc; return desc;
......
...@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode, ...@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info); struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id); int acpi_gpio_count(struct device *dev, const char *con_id);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else #else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { } static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { } static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
...@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id) ...@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{ {
return -ENODEV; return -ENODEV;
} }
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
return false;
}
#endif #endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
......
...@@ -96,13 +96,29 @@ struct gpio_keys_drvdata { ...@@ -96,13 +96,29 @@ struct gpio_keys_drvdata {
* Return value of this function can be used to allocate bitmap * Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type. * large enough to hold all bits for given type.
*/ */
static inline int get_n_events_by_type(int type) static int get_n_events_by_type(int type)
{ {
BUG_ON(type != EV_SW && type != EV_KEY); BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? KEY_CNT : SW_CNT; return (type == EV_KEY) ? KEY_CNT : SW_CNT;
} }
/**
* get_bm_events_by_type() - returns bitmap of supported events per @type
* @input: input device from which bitmap is retrieved
* @type: type of button (%EV_KEY, %EV_SW)
*
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? dev->keybit : dev->swbit;
}
/** /**
* gpio_keys_disable_button() - disables given GPIO button * gpio_keys_disable_button() - disables given GPIO button
* @bdata: button data for button to be disabled * @bdata: button data for button to be disabled
...@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
const char *buf, unsigned int type) const char *buf, unsigned int type)
{ {
int n_events = get_n_events_by_type(type); int n_events = get_n_events_by_type(type);
const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
unsigned long *bits; unsigned long *bits;
ssize_t error; ssize_t error;
int i; int i;
...@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
goto out; goto out;
/* First validate */ /* First validate */
if (!bitmap_subset(bits, bitmap, n_events)) {
error = -EINVAL;
goto out;
}
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
...@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
} }
} }
if (i == ddata->pdata->nbuttons) {
error = -EINVAL;
goto out;
}
mutex_lock(&ddata->disable_lock); mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
......
...@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data) ...@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data)
"pressed" : "released"); "pressed" : "released");
#else #else
key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)]; key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
if (key < 0) {
printk(KERN_WARNING
"omap-keypad: Spurious key event %d-%d\n",
col, row);
/* We scan again after a couple of seconds */
spurious = 1;
continue;
}
if (!(kp_cur_group == (key & GROUP_MASK) || if (!(kp_cur_group == (key & GROUP_MASK) ||
kp_cur_group == -1)) kp_cur_group == -1))
...@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev) ...@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev)
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp); setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
/* get the irq and init timer*/ /* get the irq and init timer*/
tasklet_enable(&kp_tasklet);
kp_tasklet.data = (unsigned long) omap_kp; kp_tasklet.data = (unsigned long) omap_kp;
tasklet_enable(&kp_tasklet);
ret = device_create_file(&pdev->dev, &dev_attr_enable); ret = device_create_file(&pdev->dev, &dev_attr_enable);
if (ret < 0) if (ret < 0)
......
...@@ -147,7 +147,7 @@ struct bma150_data { ...@@ -147,7 +147,7 @@ struct bma150_data {
* are stated and verified by Bosch Sensortec where they are configured * are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance. * to provide a generic sensitivity performance.
*/ */
static struct bma150_cfg default_cfg = { static const struct bma150_cfg default_cfg = {
.any_motion_int = 1, .any_motion_int = 1,
.hg_int = 1, .hg_int = 1,
.lg_int = 1, .lg_int = 1,
......
...@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) ...@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
input_report_key(onkey->input, KEY_POWER, 1); input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input); input_sync(onkey->input);
schedule_delayed_work(&onkey->work, 0); schedule_delayed_work(&onkey->work, 0);
dev_dbg(onkey->dev, "KEY_POWER pressed.\n"); dev_dbg(onkey->dev, "KEY_POWER long press.\n");
} else { } else {
input_report_key(onkey->input, KEY_SLEEP, 1); input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input); input_sync(onkey->input);
input_report_key(onkey->input, KEY_SLEEP, 0); input_report_key(onkey->input, KEY_POWER, 0);
input_sync(onkey->input); input_sync(onkey->input);
dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n"); dev_dbg(onkey->dev, "KEY_POWER short press.\n");
} }
return IRQ_HANDLED; return IRQ_HANDLED;
......
...@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = { ...@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = {
.shutdown = sparcspkr_shutdown, .shutdown = sparcspkr_shutdown,
}; };
static struct platform_driver * const drivers[] = {
&bbc_beep_driver,
&grover_beep_driver,
};
static int __init sparcspkr_init(void) static int __init sparcspkr_init(void)
{ {
int err = platform_driver_register(&bbc_beep_driver); return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (!err) {
err = platform_driver_register(&grover_beep_driver);
if (err)
platform_driver_unregister(&bbc_beep_driver);
}
return err;
} }
static void __exit sparcspkr_exit(void) static void __exit sparcspkr_exit(void)
{ {
platform_driver_unregister(&bbc_beep_driver); platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
platform_driver_unregister(&grover_beep_driver);
} }
module_init(sparcspkr_init); module_init(sparcspkr_init);
......
...@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev) ...@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev) static int uinput_create_device(struct uinput_device *udev)
{ {
struct input_dev *dev = udev->dev; struct input_dev *dev = udev->dev;
int error; int error, nslot;
if (udev->state != UIST_SETUP_COMPLETE) { if (udev->state != UIST_SETUP_COMPLETE) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
return -EINVAL; return -EINVAL;
} }
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
error = input_mt_init_slots(dev, nslot, 0);
if (error)
goto fail1;
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
UINPUT_NAME);
error = -EINVAL;
goto fail1;
}
if (udev->ff_effects_max) { if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max); error = input_ff_create(dev, udev->ff_effects_max);
if (error) if (error)
...@@ -308,51 +324,50 @@ static int uinput_open(struct inode *inode, struct file *file) ...@@ -308,51 +324,50 @@ static int uinput_open(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int uinput_validate_absbits(struct input_dev *dev) static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
const struct input_absinfo *abs)
{ {
unsigned int cnt;
int nslot;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
/*
* Check if absmin/absmax/absfuzz/absflat are sane.
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
int min, max; int min, max;
min = input_abs_get_min(dev, cnt); min = abs->minimum;
max = input_abs_get_max(dev, cnt); max = abs->maximum;
if ((min != 0 || max != 0) && max <= min) { if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n", "%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, cnt, UINPUT_NAME, code, min, max);
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL; return -EINVAL;
} }
if (input_abs_get_flat(dev, cnt) > if (abs->flat > max - min) {
input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d " "%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
"(min:%d/max:%d)\n", UINPUT_NAME, code, abs->flat, min, max);
UINPUT_NAME, cnt,
input_abs_get_flat(dev, cnt),
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL; return -EINVAL;
} }
}
if (test_bit(ABS_MT_SLOT, dev->absbit)) { return 0;
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; }
input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { static int uinput_validate_absbits(struct input_dev *dev)
input_set_events_per_packet(dev, 60); {
unsigned int cnt;
int error;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
/*
* Check if absmin/absmax/absfuzz/absflat are sane.
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
if (!dev->absinfo)
return -EINVAL;
error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
if (error)
return error;
} }
return 0; return 0;
...@@ -370,7 +385,70 @@ static int uinput_allocate_device(struct uinput_device *udev) ...@@ -370,7 +385,70 @@ static int uinput_allocate_device(struct uinput_device *udev)
return 0; return 0;
} }
static int uinput_setup_device(struct uinput_device *udev, static int uinput_dev_setup(struct uinput_device *udev,
struct uinput_setup __user *arg)
{
struct uinput_setup setup;
struct input_dev *dev;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, sizeof(setup)))
return -EFAULT;
if (!setup.name[0])
return -EINVAL;
dev = udev->dev;
dev->id = setup.id;
udev->ff_effects_max = setup.ff_effects_max;
kfree(dev->name);
dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
if (!dev->name)
return -ENOMEM;
udev->state = UIST_SETUP_COMPLETE;
return 0;
}
static int uinput_abs_setup(struct uinput_device *udev,
struct uinput_setup __user *arg, size_t size)
{
struct uinput_abs_setup setup = {};
struct input_dev *dev;
int error;
if (size > sizeof(setup))
return -E2BIG;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, size))
return -EFAULT;
if (setup.code > ABS_MAX)
return -ERANGE;
dev = udev->dev;
error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
if (error)
return error;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return -ENOMEM;
set_bit(setup.code, dev->absbit);
dev->absinfo[setup.code] = setup.absinfo;
return 0;
}
/* legacy setup via write() */
static int uinput_setup_device_legacy(struct uinput_device *udev,
const char __user *buffer, size_t count) const char __user *buffer, size_t count)
{ {
struct uinput_user_dev *user_dev; struct uinput_user_dev *user_dev;
...@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, ...@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
retval = udev->state == UIST_CREATED ? retval = udev->state == UIST_CREATED ?
uinput_inject_events(udev, buffer, count) : uinput_inject_events(udev, buffer, count) :
uinput_setup_device(udev, buffer, count); uinput_setup_device_legacy(udev, buffer, count);
mutex_unlock(&udev->mutex); mutex_unlock(&udev->mutex);
...@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
uinput_destroy_device(udev); uinput_destroy_device(udev);
goto out; goto out;
case UI_DEV_SETUP:
retval = uinput_dev_setup(udev, p);
goto out;
/* UI_ABS_SETUP is handled in the variable size ioctls */
case UI_SET_EVBIT: case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX); retval = uinput_set_bit(arg, evbit, EV_MAX);
goto out; goto out;
...@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
name = dev_name(&udev->dev->dev); name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size); retval = uinput_str_to_user(p, name, size);
goto out; goto out;
case UI_ABS_SETUP & ~IOCSIZE_MASK:
retval = uinput_abs_setup(udev, p, size);
goto out;
} }
retval = -EINVAL; retval = -EINVAL;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define ALPS_CMD_NIBBLE_10 0x01f2 #define ALPS_CMD_NIBBLE_10 0x01f2
#define ALPS_REG_BASE_RUSHMORE 0xc2c0 #define ALPS_REG_BASE_RUSHMORE 0xc2c0
#define ALPS_REG_BASE_V7 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000 #define ALPS_REG_BASE_PINNACLE 0x0000
static const struct alps_nibble_commands alps_v3_nibble_commands[] = { static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
...@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse) ...@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
return 0; return 0;
} }
static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base) static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base)
{ {
int ret = -EIO, reg_val; int ret = -EIO, reg_val;
...@@ -2128,15 +2129,12 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) ...@@ -2128,15 +2129,12 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
static int alps_hw_init_v3(struct psmouse *psmouse) static int alps_hw_init_v3(struct psmouse *psmouse)
{ {
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val; int reg_val;
unsigned char param[4]; unsigned char param[4];
reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE); if ((priv->flags & ALPS_DUALPOINT) &&
if (reg_val == -EIO)
goto error;
if (reg_val == 0 &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error; goto error;
...@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->decode_fields = alps_decode_pinnacle; priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands; priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP; priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_PINNACLE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break; break;
case ALPS_PROTO_V3_RUSHMORE: case ALPS_PROTO_V3_RUSHMORE:
...@@ -2625,7 +2628,7 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2625,7 +2628,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->x_bits = 16; priv->x_bits = 16;
priv->y_bits = 12; priv->y_bits = 12;
if (alps_probe_trackstick_v3(psmouse, if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0) ALPS_REG_BASE_RUSHMORE) < 0)
priv->flags &= ~ALPS_DUALPOINT; priv->flags &= ~ALPS_DUALPOINT;
...@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse, ...@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse,
if (priv->fw_ver[1] != 0xba) if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD; priv->flags |= ALPS_BUTTONPAD;
if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break; break;
case ALPS_PROTO_V8: case ALPS_PROTO_V8:
......
...@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) ...@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2, input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0); ETP_WMAX_V2, 0, 0);
} }
input_mt_init_slots(dev, 2, 0); input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0); input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break; break;
......
...@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
return 0; return 0;
} }
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
#ifdef CONFIG_MOUSE_PS2_FOCALTECH #ifdef CONFIG_MOUSE_PS2_FOCALTECH
/* /*
...@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse) ...@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse)
return 0; return 0;
} }
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
static void focaltech_disconnect(struct psmouse *psmouse) static void focaltech_disconnect(struct psmouse *psmouse)
{ {
focaltech_reset(psmouse); focaltech_reset(psmouse);
...@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse) ...@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse)
kfree(priv); kfree(priv);
return error; return error;
} }
#else /* CONFIG_MOUSE_PS2_FOCALTECH */
int focaltech_init(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
return 0;
}
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ #endif /* CONFIG_MOUSE_PS2_FOCALTECH */
...@@ -18,6 +18,14 @@ ...@@ -18,6 +18,14 @@
#define _FOCALTECH_H #define _FOCALTECH_H
int focaltech_detect(struct psmouse *psmouse, bool set_properties); int focaltech_detect(struct psmouse *psmouse, bool set_properties);
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
int focaltech_init(struct psmouse *psmouse); int focaltech_init(struct psmouse *psmouse);
#else
static inline int focaltech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
#endif
#endif #endif
...@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, ...@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* that support it. * that support it.
*/ */
int ps2pp_init(struct psmouse *psmouse, bool set_properties) int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#define _LOGIPS2PP_H #define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, bool set_properties); int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
#else #else
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties) static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{ {
return -ENOSYS; return -ENOSYS;
} }
......
This diff is collapsed.
...@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { ...@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
}, },
}, },
{
/* Fujitsu Lifebook U745 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
},
},
{ {
/* Fujitsu T70H */ /* Fujitsu T70H */
.matches = { .matches = {
......
...@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX ...@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX
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. module will be called egalax_ts.
config TOUCHSCREEN_EGALAX_SERIAL
tristate "EETI eGalax serial touchscreen"
select SERIO
help
Say Y here to enable support for serial connected EETI
eGalax touch panels.
To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial.
config TOUCHSCREEN_FT6236 config TOUCHSCREEN_FT6236
tristate "FT6236 I2C touchscreen" tristate "FT6236 I2C touchscreen"
depends on I2C depends on I2C
...@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU ...@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen" tristate "Goodix I2C touchscreen"
depends on I2C depends on I2C
depends on GPIOLIB
help help
Say Y here if you have the Goodix touchscreen (such as one Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your installed in Onda v975w tablets) connected to your
...@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213 ...@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213
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 touchit213. module will be called touchit213.
config TOUCHSCREEN_TS4800
tristate "TS-4800 touchscreen"
depends on HAS_IOMEM && OF
select MFD_SYSCON
select INPUT_POLLDEV
help
Say Y here if you have a touchscreen on a TS-4800 board.
On TS-4800, the touchscreen is not handled directly by Linux but by
a companion FPGA.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ts4800_ts.
config TOUCHSCREEN_TSC_SERIO config TOUCHSCREEN_TSC_SERIO
tristate "TSC-10/25/40 serial touchscreen support" tristate "TSC-10/25/40 serial touchscreen support"
select SERIO select SERIO
......
...@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o ...@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o 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_FT6236) += ft6236.o obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.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
...@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o ...@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
......
/*
* EETI Egalax serial touchscreen driver
*
* Copyright (c) 2015 Zoltán Böszörményi <zboszor@pr.hu>
*
* based on the
*
* Hampshire serial touchscreen driver (Copyright (c) 2010 Adam Bennett)
*/
/*
* 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/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#define DRIVER_DESC "EETI Egalax serial touchscreen driver"
/*
* Definitions & global arrays.
*/
#define EGALAX_FORMAT_MAX_LENGTH 6
#define EGALAX_FORMAT_START_BIT BIT(7)
#define EGALAX_FORMAT_PRESSURE_BIT BIT(6)
#define EGALAX_FORMAT_TOUCH_BIT BIT(0)
#define EGALAX_FORMAT_RESOLUTION_MASK 0x06
#define EGALAX_MIN_XC 0
#define EGALAX_MAX_XC 0x4000
#define EGALAX_MIN_YC 0
#define EGALAX_MAX_YC 0x4000
/*
* Per-touchscreen data.
*/
struct egalax {
struct input_dev *input;
struct serio *serio;
int idx;
u8 data[EGALAX_FORMAT_MAX_LENGTH];
char phys[32];
};
static void egalax_process_data(struct egalax *egalax)
{
struct input_dev *dev = egalax->input;
u8 *data = egalax->data;
u16 x, y;
u8 shift;
u8 mask;
shift = 3 - ((data[0] & EGALAX_FORMAT_RESOLUTION_MASK) >> 1);
mask = 0xff >> (shift + 1);
x = (((u16)(data[1] & mask) << 7) | (data[2] & 0x7f)) << shift;
y = (((u16)(data[3] & mask) << 7) | (data[4] & 0x7f)) << shift;
input_report_key(dev, BTN_TOUCH, data[0] & EGALAX_FORMAT_TOUCH_BIT);
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_sync(dev);
}
static irqreturn_t egalax_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct egalax *egalax = serio_get_drvdata(serio);
int pkt_len;
egalax->data[egalax->idx++] = data;
if (likely(egalax->data[0] & EGALAX_FORMAT_START_BIT)) {
pkt_len = egalax->data[0] & EGALAX_FORMAT_PRESSURE_BIT ? 6 : 5;
if (pkt_len == egalax->idx) {
egalax_process_data(egalax);
egalax->idx = 0;
}
} else {
dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n",
egalax->data[0]);
egalax->idx = 0;
}
return IRQ_HANDLED;
}
/*
* egalax_connect() is the routine that is called when someone adds a
* new serio device that supports egalax protocol and registers it as
* an input device. This is usually accomplished using inputattach.
*/
static int egalax_connect(struct serio *serio, struct serio_driver *drv)
{
struct egalax *egalax;
struct input_dev *input_dev;
int error;
egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!egalax || !input_dev) {
error = -ENOMEM;
goto err_free_mem;
}
egalax->serio = serio;
egalax->input = input_dev;
snprintf(egalax->phys, sizeof(egalax->phys),
"%s/input0", serio->phys);
input_dev->name = "EETI eGalaxTouch Serial TouchScreen";
input_dev->phys = egalax->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_EGALAX;
input_dev->id.product = 0;
input_dev->id.version = 0x0001;
input_dev->dev.parent = &serio->dev;
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
EGALAX_MIN_XC, EGALAX_MAX_XC, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
EGALAX_MIN_YC, EGALAX_MAX_YC, 0, 0);
serio_set_drvdata(serio, egalax);
error = serio_open(serio, drv);
if (error)
goto err_reset_drvdata;
error = input_register_device(input_dev);
if (error)
goto err_close_serio;
return 0;
err_close_serio:
serio_close(serio);
err_reset_drvdata:
serio_set_drvdata(serio, NULL);
err_free_mem:
input_free_device(input_dev);
kfree(egalax);
return error;
}
static void egalax_disconnect(struct serio *serio)
{
struct egalax *egalax = serio_get_drvdata(serio);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_unregister_device(egalax->input);
kfree(egalax);
}
/*
* The serio driver structure.
*/
static const struct serio_device_id egalax_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_EGALAX,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, egalax_serio_ids);
static struct serio_driver egalax_drv = {
.driver = {
.name = "egalax",
},
.description = DRIVER_DESC,
.id_table = egalax_serio_ids,
.interrupt = egalax_interrupt,
.connect = egalax_connect,
.disconnect = egalax_disconnect,
};
module_serio_driver(egalax_drv);
MODULE_AUTHOR("Zoltán Böszörményi <zboszor@pr.hu>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL v2");
This diff is collapsed.
...@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2]) ...@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2])
static void pcap_ts_work(struct work_struct *work) static void pcap_ts_work(struct work_struct *work)
{ {
struct delayed_work *dw = container_of(work, struct delayed_work, work); struct delayed_work *dw = to_delayed_work(work);
struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work); struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
u8 ch[2]; u8 ch[2];
......
...@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data { ...@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data {
struct input_dev *input; struct input_dev *input;
struct gpio_desc *gpio_attb; struct gpio_desc *gpio_attb;
struct gpio_desc *gpio_reset; struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_enable;
struct gpio_desc *gpio_wake;
const struct pixcir_i2c_chip_data *chip; const struct pixcir_i2c_chip_data *chip;
int max_fingers; /* Max fingers supported in this instance */ int max_fingers; /* Max fingers supported in this instance */
bool running; bool running;
...@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ...@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
int ret; int ret;
if (mode == PIXCIR_POWER_ACTIVE || mode == PIXCIR_POWER_IDLE) {
if (ts->gpio_wake)
gpiod_set_value_cansleep(ts->gpio_wake, 1);
}
ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: can't read reg 0x%x : %d\n", dev_err(dev, "%s: can't read reg 0x%x : %d\n",
...@@ -228,6 +235,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, ...@@ -228,6 +235,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
return ret; return ret;
} }
if (mode == PIXCIR_POWER_HALT) {
if (ts->gpio_wake)
gpiod_set_value_cansleep(ts->gpio_wake, 0);
}
return 0; return 0;
} }
...@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts) ...@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts)
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
int error; int error;
if (ts->gpio_enable) {
gpiod_set_value_cansleep(ts->gpio_enable, 1);
msleep(100);
}
/* LEVEL_TOUCH interrupt with active low polarity */ /* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) { if (error) {
...@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts) ...@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
/* Wait till running ISR is complete */ /* Wait till running ISR is complete */
synchronize_irq(ts->client->irq); synchronize_irq(ts->client->irq);
if (ts->gpio_enable)
gpiod_set_value_cansleep(ts->gpio_enable, 0);
return 0; return 0;
} }
...@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, ...@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
return error; return error;
} }
tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake",
GPIOD_OUT_HIGH);
if (IS_ERR(tsdata->gpio_wake)) {
error = PTR_ERR(tsdata->gpio_wake);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to get wake gpio: %d\n", error);
return error;
}
tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(tsdata->gpio_enable)) {
error = PTR_ERR(tsdata->gpio_enable);
if (error != -EPROBE_DEFER)
dev_err(dev, "Failed to get enable gpio: %d\n", error);
return error;
}
if (tsdata->gpio_enable)
msleep(100);
error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata); client->name, tsdata);
......
...@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client, ...@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
break; break;
error = -EIO; error = -EIO;
} while (++retry >= FIRMWARE_RETRY_MAX); } while (++retry <= FIRMWARE_RETRY_MAX);
out: out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL); error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
......
...@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev) ...@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev)
status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
if (status & IRQENB_HW_PEN) { if (status & IRQENB_HW_PEN) {
ts_dev->pen_down = true; ts_dev->pen_down = true;
titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
irqclr |= IRQENB_HW_PEN; irqclr |= IRQENB_HW_PEN;
} }
......
/*
* Touchscreen driver for the TS-4800 board
*
* Copyright (c) 2015 - Savoir-faire Linux
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/bitops.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* polling interval in ms */
#define POLL_INTERVAL 3
#define DEBOUNCE_COUNT 1
/* sensor values are 12-bit wide */
#define MAX_12BIT ((1 << 12) - 1)
#define PENDOWN_MASK 0x1
#define X_OFFSET 0x0
#define Y_OFFSET 0x2
struct ts4800_ts {
struct input_polled_dev *poll_dev;
struct device *dev;
char phys[32];
void __iomem *base;
struct regmap *regmap;
unsigned int reg;
unsigned int bit;
bool pendown;
int debounce;
};
static void ts4800_ts_open(struct input_polled_dev *dev)
{
struct ts4800_ts *ts = dev->private;
int ret;
ts->pendown = false;
ts->debounce = DEBOUNCE_COUNT;
ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit);
if (ret)
dev_warn(ts->dev, "Failed to enable touchscreen\n");
}
static void ts4800_ts_close(struct input_polled_dev *dev)
{
struct ts4800_ts *ts = dev->private;
int ret;
ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0);
if (ret)
dev_warn(ts->dev, "Failed to disable touchscreen\n");
}
static void ts4800_ts_poll(struct input_polled_dev *dev)
{
struct input_dev *input_dev = dev->input;
struct ts4800_ts *ts = dev->private;
u16 last_x = readw(ts->base + X_OFFSET);
u16 last_y = readw(ts->base + Y_OFFSET);
bool pendown = last_x & PENDOWN_MASK;
if (pendown) {
if (ts->debounce) {
ts->debounce--;
return;
}
if (!ts->pendown) {
input_report_key(input_dev, BTN_TOUCH, 1);
ts->pendown = true;
}
last_x = ((~last_x) >> 4) & MAX_12BIT;
last_y = ((~last_y) >> 4) & MAX_12BIT;
input_report_abs(input_dev, ABS_X, last_x);
input_report_abs(input_dev, ABS_Y, last_y);
input_sync(input_dev);
} else if (ts->pendown) {
ts->pendown = false;
ts->debounce = DEBOUNCE_COUNT;
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
}
}
static int ts4800_parse_dt(struct platform_device *pdev,
struct ts4800_ts *ts)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *syscon_np;
u32 reg, bit;
int error;
syscon_np = of_parse_phandle(np, "syscon", 0);
if (!syscon_np) {
dev_err(dev, "no syscon property\n");
return -ENODEV;
}
error = of_property_read_u32_index(np, "syscon", 1, &reg);
if (error < 0) {
dev_err(dev, "no offset in syscon\n");
return error;
}
ts->reg = reg;
error = of_property_read_u32_index(np, "syscon", 2, &bit);
if (error < 0) {
dev_err(dev, "no bit in syscon\n");
return error;
}
ts->bit = BIT(bit);
ts->regmap = syscon_node_to_regmap(syscon_np);
if (IS_ERR(ts->regmap)) {
dev_err(dev, "cannot get parent's regmap\n");
return PTR_ERR(ts->regmap);
}
return 0;
}
static int ts4800_ts_probe(struct platform_device *pdev)
{
struct input_polled_dev *poll_dev;
struct ts4800_ts *ts;
struct resource *res;
int error;
ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
error = ts4800_parse_dt(pdev, ts);
if (error)
return error;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ts->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ts->base))
return PTR_ERR(ts->base);
poll_dev = devm_input_allocate_polled_device(&pdev->dev);
if (!poll_dev)
return -ENOMEM;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev));
ts->poll_dev = poll_dev;
ts->dev = &pdev->dev;
poll_dev->private = ts;
poll_dev->poll_interval = POLL_INTERVAL;
poll_dev->open = ts4800_ts_open;
poll_dev->close = ts4800_ts_close;
poll_dev->poll = ts4800_ts_poll;
poll_dev->input->name = "TS-4800 Touchscreen";
poll_dev->input->phys = ts->phys;
input_set_capability(poll_dev->input, EV_KEY, BTN_TOUCH);
input_set_abs_params(poll_dev->input, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(poll_dev->input, ABS_Y, 0, MAX_12BIT, 0, 0);
error = input_register_polled_device(poll_dev);
if (error) {
dev_err(&pdev->dev,
"Unabled to register polled input device (%d)\n",
error);
return error;
}
return 0;
}
static const struct of_device_id ts4800_ts_of_match[] = {
{ .compatible = "technologic,ts4800-ts", },
{ },
};
MODULE_DEVICE_TABLE(of, ts4800_ts_of_match);
static struct platform_driver ts4800_ts_driver = {
.driver = {
.name = "ts4800-ts",
.of_match_table = ts4800_ts_of_match,
},
.probe = ts4800_ts_probe,
};
module_platform_driver(ts4800_ts_driver);
MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
MODULE_DESCRIPTION("TS-4800 Touchscreen Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:ts4800_ts");
This diff is collapsed.
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
* *
* Changes/Revisions: * 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>) * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl * - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
......
...@@ -77,5 +77,6 @@ ...@@ -77,5 +77,6 @@
#define SERIO_PS2MULT 0x3c #define SERIO_PS2MULT 0x3c
#define SERIO_TSC40 0x3d #define SERIO_TSC40 0x3d
#define SERIO_WACOM_IV 0x3e #define SERIO_WACOM_IV 0x3e
#define SERIO_EGALAX 0x3f
#endif /* _UAPI_SERIO_H */ #endif /* _UAPI_SERIO_H */
...@@ -20,6 +20,11 @@ ...@@ -20,6 +20,11 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
* *
* Changes/Revisions: * 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>) * 0.4 01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
* - add UI_GET_SYSNAME ioctl * - add UI_GET_SYSNAME ioctl
* 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>) * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
...@@ -37,8 +42,8 @@ ...@@ -37,8 +42,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/input.h> #include <linux/input.h>
#define UINPUT_VERSION 4 #define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload { struct uinput_ff_upload {
__u32 request_id; __u32 request_id;
...@@ -58,6 +63,76 @@ struct uinput_ff_erase { ...@@ -58,6 +63,76 @@ struct uinput_ff_erase {
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
struct uinput_setup {
struct input_id id;
char name[UINPUT_MAX_NAME_SIZE];
__u32 ff_effects_max;
};
/**
* UI_DEV_SETUP - Set device parameters for setup
*
* This ioctl sets parameters for the input device to be created. It
* supersedes the old "struct uinput_user_dev" method, which wrote this data
* via write(). To actually set the absolute axes UI_ABS_SETUP should be
* used.
*
* The ioctl takes a "struct uinput_setup" object as argument. The fields of
* this object are as follows:
* id: See the description of "struct input_id". This field is
* copied unchanged into the new device.
* name: This is used unchanged as name for the new device.
* ff_effects_max: This limits the maximum numbers of force-feedback effects.
* See below for a description of FF with uinput.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
struct uinput_abs_setup {
__u16 code; /* axis code */
/* __u16 filler; */
struct input_absinfo absinfo;
};
/**
* UI_ABS_SETUP - Set absolute axis information for the device to setup
*
* This ioctl sets one absolute axis information for the input device to be
* created. It supersedes the old "struct uinput_user_dev" method, which wrote
* part of this data and the content of UI_DEV_SETUP via write().
*
* The ioctl takes a "struct uinput_abs_setup" object as argument. The fields
* of this object are as follows:
* code: The corresponding input code associated with this axis
* (ABS_X, ABS_Y, etc...)
* absinfo: See "struct input_absinfo" for a description of this field.
* This field is copied unchanged into the kernel for the
* specified axis. If the axis is not enabled via
* UI_SET_ABSBIT, this ioctl will enable it.
*
* This ioctl can be called multiple times and will overwrite previous values.
* If this ioctl fails with -EINVAL, it is recommended to use the old
* "uinput_user_dev" method via write() as a fallback, in case you run on an
* old kernel that does not support this ioctl.
*
* This ioctl may fail with -EINVAL if it is not supported or if you passed
* incorrect values, -ENOMEM if the kernel runs out of memory or -EFAULT if the
* passed uinput_setup object cannot be read/written.
* If this call fails, partial data may have already been applied to the
* internal device.
*/
#define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
...@@ -144,7 +219,6 @@ struct uinput_ff_erase { ...@@ -144,7 +219,6 @@ struct uinput_ff_erase {
#define UI_FF_UPLOAD 1 #define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2 #define UI_FF_ERASE 2
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_user_dev { struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE]; char name[UINPUT_MAX_NAME_SIZE];
struct input_id id; struct input_id id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment