提交 1c5ff2ab 编写于 作者: 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:
 - 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
  ...
......@@ -13,6 +13,17 @@ Required properties:
- interrupt-parent : Interrupt controller 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:
i2c@00000000 {
......@@ -23,6 +34,9 @@ Example:
reg = <0x5d>;
interrupt-parent = <&gpio>;
interrupts = <0 0>;
irq-gpios = <&gpio1 0 0>;
reset-gpios = <&gpio1 1 0>;
};
/* ... */
......
......@@ -9,7 +9,9 @@ Required properties:
- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
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:
......
* 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)
}
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,
/* Then from plain _CRS GPIOs */
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);
if (IS_ERR(desc))
return desc;
......
......@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info);
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
static inline void acpi_gpiochip_add(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)
{
return -ENODEV;
}
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
return false;
}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
......
......@@ -96,13 +96,29 @@ struct gpio_keys_drvdata {
* Return value of this function can be used to allocate bitmap
* 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);
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
* @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,
const char *buf, unsigned int 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;
ssize_t error;
int i;
......@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
goto out;
/* First validate */
if (!bitmap_subset(bits, bitmap, n_events)) {
error = -EINVAL;
goto out;
}
for (i = 0; i < ddata->pdata->nbuttons; 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,
}
}
if (i == ddata->pdata->nbuttons) {
error = -EINVAL;
goto out;
}
mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) {
......
......@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data)
"pressed" : "released");
#else
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) ||
kp_cur_group == -1))
......@@ -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);
/* get the irq and init timer*/
tasklet_enable(&kp_tasklet);
kp_tasklet.data = (unsigned long) omap_kp;
tasklet_enable(&kp_tasklet);
ret = device_create_file(&pdev->dev, &dev_attr_enable);
if (ret < 0)
......
......@@ -147,7 +147,7 @@ struct bma150_data {
* are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance.
*/
static struct bma150_cfg default_cfg = {
static const struct bma150_cfg default_cfg = {
.any_motion_int = 1,
.hg_int = 1,
.lg_int = 1,
......
......@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
schedule_delayed_work(&onkey->work, 0);
dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
dev_dbg(onkey->dev, "KEY_POWER long press.\n");
} else {
input_report_key(onkey->input, KEY_SLEEP, 1);
input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
input_report_key(onkey->input, KEY_SLEEP, 0);
input_report_key(onkey->input, KEY_POWER, 0);
input_sync(onkey->input);
dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
dev_dbg(onkey->dev, "KEY_POWER short press.\n");
}
return IRQ_HANDLED;
......
......@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = {
.shutdown = sparcspkr_shutdown,
};
static struct platform_driver * const drivers[] = {
&bbc_beep_driver,
&grover_beep_driver,
};
static int __init sparcspkr_init(void)
{
int err = platform_driver_register(&bbc_beep_driver);
if (!err) {
err = platform_driver_register(&grover_beep_driver);
if (err)
platform_driver_unregister(&bbc_beep_driver);
}
return err;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit sparcspkr_exit(void)
{
platform_driver_unregister(&bbc_beep_driver);
platform_driver_unregister(&grover_beep_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sparcspkr_init);
......
......@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev)
{
struct input_dev *dev = udev->dev;
int error;
int error, nslot;
if (udev->state != UIST_SETUP_COMPLETE) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
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) {
error = input_ff_create(dev, udev->ff_effects_max);
if (error)
......@@ -308,10 +324,35 @@ static int uinput_open(struct inode *inode, struct file *file)
return 0;
}
static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
const struct input_absinfo *abs)
{
int min, max;
min = abs->minimum;
max = abs->maximum;
if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, code, min, max);
return -EINVAL;
}
if (abs->flat > max - min) {
printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
UINPUT_NAME, code, abs->flat, min, max);
return -EINVAL;
}
return 0;
}
static int uinput_validate_absbits(struct input_dev *dev)
{
unsigned int cnt;
int nslot;
int error;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
......@@ -321,38 +362,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
int min, max;
min = input_abs_get_min(dev, cnt);
max = input_abs_get_max(dev, cnt);
if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, cnt,
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
if (!dev->absinfo)
return -EINVAL;
}
if (input_abs_get_flat(dev, cnt) >
input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d "
"(min:%d/max:%d)\n",
UINPUT_NAME, cnt,
input_abs_get_flat(dev, cnt),
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL;
}
}
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
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)) {
input_set_events_per_packet(dev, 60);
error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
if (error)
return error;
}
return 0;
......@@ -370,8 +385,71 @@ static int uinput_allocate_device(struct uinput_device *udev)
return 0;
}
static int uinput_setup_device(struct uinput_device *udev,
const char __user *buffer, size_t count)
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)
{
struct uinput_user_dev *user_dev;
struct input_dev *dev;
......@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
retval = udev->state == UIST_CREATED ?
uinput_inject_events(udev, buffer, count) :
uinput_setup_device(udev, buffer, count);
uinput_setup_device_legacy(udev, buffer, count);
mutex_unlock(&udev->mutex);
......@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
uinput_destroy_device(udev);
goto out;
case UI_DEV_SETUP:
retval = uinput_dev_setup(udev, p);
goto out;
/* UI_ABS_SETUP is handled in the variable size ioctls */
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
goto out;
......@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size);
goto out;
case UI_ABS_SETUP & ~IOCSIZE_MASK:
retval = uinput_abs_setup(udev, p, size);
goto out;
}
retval = -EINVAL;
......
......@@ -31,6 +31,7 @@
#define ALPS_CMD_NIBBLE_10 0x01f2
#define ALPS_REG_BASE_RUSHMORE 0xc2c0
#define ALPS_REG_BASE_V7 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
......@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
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;
......@@ -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)
{
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val;
unsigned char param[4];
reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
if (reg_val == -EIO)
goto error;
if (reg_val == 0 &&
if ((priv->flags & ALPS_DUALPOINT) &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error;
......@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_PINNACLE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
case ALPS_PROTO_V3_RUSHMORE:
......@@ -2625,8 +2628,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->x_bits = 16;
priv->y_bits = 12;
if (alps_probe_trackstick_v3(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0)
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
......@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse,
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
case ALPS_PROTO_V8:
......
......@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
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_Y, y_min, y_max, 0, 0);
break;
......
......@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
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
/*
......@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse)
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)
{
focaltech_reset(psmouse);
......@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse)
kfree(priv);
return error;
}
#else /* CONFIG_MOUSE_PS2_FOCALTECH */
int focaltech_init(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
return 0;
}
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
......@@ -18,6 +18,14 @@
#define _FOCALTECH_H
int focaltech_detect(struct psmouse *psmouse, bool set_properties);
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
int focaltech_init(struct psmouse *psmouse);
#else
static inline int focaltech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
#endif
#endif
......@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* 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;
unsigned char param[4];
......
......@@ -12,9 +12,9 @@
#define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, bool set_properties);
int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
#else
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
......
此差异已折叠。
......@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
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 */
.matches = {
......
......@@ -295,6 +295,16 @@ config TOUCHSCREEN_EGALAX
To compile this driver as a module, choose M here: the
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
tristate "FT6236 I2C touchscreen"
depends on I2C
......@@ -324,6 +334,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen"
depends on I2C
depends on GPIOLIB
help
Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your
......@@ -927,6 +938,22 @@ config TOUCHSCREEN_TOUCHIT213
To compile this driver as a module, choose M here: the
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
tristate "TSC-10/25/40 serial touchscreen support"
select SERIO
......
......@@ -35,6 +35,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_FT6236) += ft6236.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
......@@ -68,6 +69,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.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");
......@@ -2,6 +2,7 @@
* Driver for Goodix Touchscreens
*
* Copyright (c) 2014 Red Hat Inc.
* Copyright (c) 2015 K. Merker <merker@debian.org>
*
* This code is based on gt9xx.c authored by andrew@goodix.com:
*
......@@ -16,6 +17,8 @@
#include <linux/kernel.h>
#include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
......@@ -33,11 +36,24 @@ struct goodix_ts_data {
struct input_dev *input_dev;
int abs_x_max;
int abs_y_max;
bool swapped_x_y;
bool inverted_x;
bool inverted_y;
unsigned int max_touch_num;
unsigned int int_trigger_type;
bool rotated_screen;
int cfg_len;
struct gpio_desc *gpiod_int;
struct gpio_desc *gpiod_rst;
u16 id;
u16 version;
const char *cfg_name;
struct completion firmware_loading_complete;
unsigned long irq_flags;
};
#define GOODIX_GPIO_INT_NAME "irq"
#define GOODIX_GPIO_RST_NAME "reset"
#define GOODIX_MAX_HEIGHT 4096
#define GOODIX_MAX_WIDTH 4096
#define GOODIX_INT_TRIGGER 1
......@@ -45,8 +61,13 @@ struct goodix_ts_data {
#define GOODIX_MAX_CONTACTS 10
#define GOODIX_CONFIG_MAX_LENGTH 240
#define GOODIX_CONFIG_911_LENGTH 186
#define GOODIX_CONFIG_967_LENGTH 228
/* Register defines */
#define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140
......@@ -115,6 +136,63 @@ static int goodix_i2c_read(struct i2c_client *client,
return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
}
/**
* goodix_i2c_write - write data to a register of the i2c slave device.
*
* @client: i2c device.
* @reg: the register to write to.
* @buf: raw data buffer to write.
* @len: length of the buffer to write
*/
static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
unsigned len)
{
u8 *addr_buf;
struct i2c_msg msg;
int ret;
addr_buf = kmalloc(len + 2, GFP_KERNEL);
if (!addr_buf)
return -ENOMEM;
addr_buf[0] = reg >> 8;
addr_buf[1] = reg & 0xFF;
memcpy(&addr_buf[2], buf, len);
msg.flags = 0;
msg.addr = client->addr;
msg.buf = addr_buf;
msg.len = len + 2;
ret = i2c_transfer(client->adapter, &msg, 1);
kfree(addr_buf);
return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
}
static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
{
return goodix_i2c_write(client, reg, &value, sizeof(value));
}
static int goodix_get_cfg_len(u16 id)
{
switch (id) {
case 911:
case 9271:
case 9110:
case 927:
case 928:
return GOODIX_CONFIG_911_LENGTH;
case 912:
case 967:
return GOODIX_CONFIG_967_LENGTH;
default:
return GOODIX_CONFIG_MAX_LENGTH;
}
}
static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
int touch_num;
......@@ -155,10 +233,13 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
int input_y = get_unaligned_le16(&coor_data[3]);
int input_w = get_unaligned_le16(&coor_data[5]);
if (ts->rotated_screen) {
/* Inversions have to happen before axis swapping */
if (ts->inverted_x)
input_x = ts->abs_x_max - input_x;
if (ts->inverted_y)
input_y = ts->abs_y_max - input_y;
}
if (ts->swapped_x_y)
swap(input_x, input_y);
input_mt_slot(ts->input_dev, id);
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
......@@ -202,21 +283,195 @@ static void goodix_process_events(struct goodix_ts_data *ts)
*/
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
static const u8 end_cmd[] = {
GOODIX_READ_COOR_ADDR >> 8,
GOODIX_READ_COOR_ADDR & 0xff,
0
};
struct goodix_ts_data *ts = dev_id;
goodix_process_events(ts);
if (i2c_master_send(ts->client, end_cmd, sizeof(end_cmd)) < 0)
if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
dev_err(&ts->client->dev, "I2C write end_cmd error\n");
return IRQ_HANDLED;
}
static void goodix_free_irq(struct goodix_ts_data *ts)
{
devm_free_irq(&ts->client->dev, ts->client->irq, ts);
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
}
/**
* goodix_check_cfg - Checks if config fw is valid
*
* @ts: goodix_ts_data pointer
* @cfg: firmware config data
*/
static int goodix_check_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int i, raw_cfg_len;
u8 check_sum = 0;
if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
dev_err(&ts->client->dev,
"The length of the config fw is not correct");
return -EINVAL;
}
raw_cfg_len = cfg->size - 2;
for (i = 0; i < raw_cfg_len; i++)
check_sum += cfg->data[i];
check_sum = (~check_sum) + 1;
if (check_sum != 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 + 1] != 1) {
dev_err(&ts->client->dev,
"Config fw must have Config_Fresh register set");
return -EINVAL;
}
return 0;
}
/**
* goodix_send_cfg - Write fw config to device
*
* @ts: goodix_ts_data pointer
* @cfg: config firmware to write to device
*/
static int goodix_send_cfg(struct goodix_ts_data *ts,
const struct firmware *cfg)
{
int error;
error = goodix_check_cfg(ts, cfg);
if (error)
return error;
error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
cfg->size);
if (error) {
dev_err(&ts->client->dev, "Failed to write config data: %d",
error);
return error;
}
dev_dbg(&ts->client->dev, "Config sent successfully.");
/* Let the firmware reconfigure itself, so sleep for 10ms */
usleep_range(10000, 11000);
return 0;
}
static int goodix_int_sync(struct goodix_ts_data *ts)
{
int error;
error = gpiod_direction_output(ts->gpiod_int, 0);
if (error)
return error;
msleep(50); /* T5: 50ms */
error = gpiod_direction_input(ts->gpiod_int);
if (error)
return error;
return 0;
}
/**
* goodix_reset - Reset device during power on
*
* @ts: goodix_ts_data pointer
*/
static int goodix_reset(struct goodix_ts_data *ts)
{
int error;
/* begin select I2C slave addr */
error = gpiod_direction_output(ts->gpiod_rst, 0);
if (error)
return error;
msleep(20); /* T2: > 10ms */
/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
error = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14);
if (error)
return error;
usleep_range(100, 2000); /* T3: > 100us */
error = gpiod_direction_output(ts->gpiod_rst, 1);
if (error)
return error;
usleep_range(6000, 10000); /* T4: > 5ms */
/* end select I2C slave addr */
error = gpiod_direction_input(ts->gpiod_rst);
if (error)
return error;
error = goodix_int_sync(ts);
if (error)
return error;
return 0;
}
/**
* goodix_get_gpio_config - Get GPIO config from ACPI/DT
*
* @ts: goodix_ts_data pointer
*/
static int goodix_get_gpio_config(struct goodix_ts_data *ts)
{
int error;
struct device *dev;
struct gpio_desc *gpiod;
if (!ts->client)
return -EINVAL;
dev = &ts->client->dev;
/* Get the interrupt GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
if (IS_ERR(gpiod)) {
error = PTR_ERR(gpiod);
if (error != -EPROBE_DEFER)
dev_dbg(dev, "Failed to get %s GPIO: %d\n",
GOODIX_GPIO_INT_NAME, error);
return error;
}
ts->gpiod_int = gpiod;
/* Get the reset line GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
if (IS_ERR(gpiod)) {
error = PTR_ERR(gpiod);
if (error != -EPROBE_DEFER)
dev_dbg(dev, "Failed to get %s GPIO: %d\n",
GOODIX_GPIO_RST_NAME, error);
return error;
}
ts->gpiod_rst = gpiod;
return 0;
}
/**
* goodix_read_config - Read the embedded configuration of the panel
*
......@@ -230,14 +485,15 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int error;
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
config,
GOODIX_CONFIG_MAX_LENGTH);
config, ts->cfg_len);
if (error) {
dev_warn(&ts->client->dev,
"Error reading config (%d), using defaults\n",
error);
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
......@@ -245,6 +501,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
ts->abs_x_max = get_unaligned_le16(&config[RESOLUTION_LOC]);
ts->abs_y_max = get_unaligned_le16(&config[RESOLUTION_LOC + 2]);
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->int_trigger_type = config[TRIGGER_LOC] & 0x03;
ts->max_touch_num = config[MAX_CONTACTS_LOC] & 0x0f;
if (!ts->abs_x_max || !ts->abs_y_max || !ts->max_touch_num) {
......@@ -252,42 +510,45 @@ static void goodix_read_config(struct goodix_ts_data *ts)
"Invalid config, using defaults\n");
ts->abs_x_max = GOODIX_MAX_WIDTH;
ts->abs_y_max = GOODIX_MAX_HEIGHT;
if (ts->swapped_x_y)
swap(ts->abs_x_max, ts->abs_y_max);
ts->max_touch_num = GOODIX_MAX_CONTACTS;
}
ts->rotated_screen = dmi_check_system(rotated_screen);
if (ts->rotated_screen)
if (dmi_check_system(rotated_screen)) {
ts->inverted_x = true;
ts->inverted_y = true;
dev_dbg(&ts->client->dev,
"Applying '180 degrees rotated screen' quirk\n");
}
}
/**
* goodix_read_version - Read goodix touchscreen version
*
* @client: the i2c client
* @version: output buffer containing the version on success
* @id: output buffer containing the id on success
* @ts: our goodix_ts_data pointer
*/
static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
static int goodix_read_version(struct goodix_ts_data *ts)
{
int error;
u8 buf[6];
char id_str[5];
error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf));
error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
if (error) {
dev_err(&client->dev, "read version failed: %d\n", error);
dev_err(&ts->client->dev, "read version failed: %d\n", error);
return error;
}
memcpy(id_str, buf, 4);
id_str[4] = 0;
if (kstrtou16(id_str, 10, id))
*id = 0x1001;
if (kstrtou16(id_str, 10, &ts->id))
ts->id = 0x1001;
*version = get_unaligned_le16(&buf[4]);
ts->version = get_unaligned_le16(&buf[4]);
dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
dev_info(&ts->client->dev, "ID %d, version: %04x\n", ts->id,
ts->version);
return 0;
}
......@@ -321,13 +582,10 @@ static int goodix_i2c_test(struct i2c_client *client)
* goodix_request_input_dev - Allocate, populate and register the input device
*
* @ts: our goodix_ts_data pointer
* @version: device firmware version
* @id: device ID
*
* Must be called during probe
*/
static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
u16 id)
static int goodix_request_input_dev(struct goodix_ts_data *ts)
{
int error;
......@@ -351,8 +609,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
ts->input_dev->phys = "input/ts";
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0x0416;
ts->input_dev->id.product = id;
ts->input_dev->id.version = version;
ts->input_dev->id.product = ts->id;
ts->input_dev->id.version = ts->version;
error = input_register_device(ts->input_dev);
if (error) {
......@@ -364,13 +622,75 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
return 0;
}
/**
* goodix_configure_dev - Finish device initialization
*
* @ts: our goodix_ts_data pointer
*
* Must be called from probe to finish initialization of the device.
* Contains the common initialization code for both devices that
* declare gpio pins and devices that do not. It is either called
* directly from probe or from request_firmware_wait callback.
*/
static int goodix_configure_dev(struct goodix_ts_data *ts)
{
int error;
ts->swapped_x_y = device_property_read_bool(&ts->client->dev,
"touchscreen-swapped-x-y");
ts->inverted_x = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-x");
ts->inverted_y = device_property_read_bool(&ts->client->dev,
"touchscreen-inverted-y");
goodix_read_config(ts);
error = goodix_request_input_dev(ts);
if (error)
return error;
ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
error = goodix_request_irq(ts);
if (error) {
dev_err(&ts->client->dev, "request IRQ failed: %d\n", error);
return error;
}
return 0;
}
/**
* goodix_config_cb - Callback to finish device init
*
* @ts: our goodix_ts_data pointer
*
* request_firmware_wait callback that finishes
* initialization of the device.
*/
static void goodix_config_cb(const struct firmware *cfg, void *ctx)
{
struct goodix_ts_data *ts = ctx;
int error;
if (cfg) {
/* send device configuration to the firmware */
error = goodix_send_cfg(ts, cfg);
if (error)
goto err_release_cfg;
}
goodix_configure_dev(ts);
err_release_cfg:
release_firmware(cfg);
complete_all(&ts->firmware_loading_complete);
}
static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
unsigned long irq_flags;
int error;
u16 version_info, id_info;
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
......@@ -385,6 +705,20 @@ static int goodix_ts_probe(struct i2c_client *client,
ts->client = client;
i2c_set_clientdata(client, ts);
init_completion(&ts->firmware_loading_complete);
error = goodix_get_gpio_config(ts);
if (error)
return error;
if (ts->gpiod_int && ts->gpiod_rst) {
/* reset the controller */
error = goodix_reset(ts);
if (error) {
dev_err(&client->dev, "Controller reset failed.\n");
return error;
}
}
error = goodix_i2c_test(client);
if (error) {
......@@ -392,30 +726,125 @@ static int goodix_ts_probe(struct i2c_client *client,
return error;
}
error = goodix_read_version(client, &version_info, &id_info);
error = goodix_read_version(ts);
if (error) {
dev_err(&client->dev, "Read version failed.\n");
return error;
}
goodix_read_config(ts);
ts->cfg_len = goodix_get_cfg_len(ts->id);
if (ts->gpiod_int && ts->gpiod_rst) {
/* update device config */
ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
"goodix_%d_cfg.bin", ts->id);
if (!ts->cfg_name)
return -ENOMEM;
error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
&client->dev, GFP_KERNEL, ts,
goodix_config_cb);
if (error) {
dev_err(&client->dev,
"Failed to invoke firmware loader: %d\n",
error);
return error;
}
error = goodix_request_input_dev(ts, version_info, id_info);
if (error)
return error;
return 0;
} else {
error = goodix_configure_dev(ts);
if (error)
return error;
}
return 0;
}
static int goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->gpiod_int && ts->gpiod_rst)
wait_for_completion(&ts->firmware_loading_complete);
return 0;
}
static int __maybe_unused goodix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
error = devm_request_threaded_irq(&ts->client->dev, client->irq,
NULL, goodix_ts_irq_handler,
irq_flags, client->name, ts);
/* We need gpio pins to suspend/resume */
if (!ts->gpiod_int || !ts->gpiod_rst)
return 0;
wait_for_completion(&ts->firmware_loading_complete);
/* Free IRQ as IRQ pin is used as output in the suspend sequence */
goodix_free_irq(ts);
/* Output LOW on the INT pin for 5 ms */
error = gpiod_direction_output(ts->gpiod_int, 0);
if (error) {
dev_err(&client->dev, "request IRQ failed: %d\n", error);
goodix_request_irq(ts);
return error;
}
usleep_range(5000, 6000);
error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
GOODIX_CMD_SCREEN_OFF);
if (error) {
dev_err(&ts->client->dev, "Screen off command failed\n");
gpiod_direction_input(ts->gpiod_int);
goodix_request_irq(ts);
return -EAGAIN;
}
/*
* The datasheet specifies that the interval between sending screen-off
* command and wake-up should be longer than 58 ms. To avoid waking up
* sooner, delay 58ms here.
*/
msleep(58);
return 0;
}
static int __maybe_unused goodix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
if (!ts->gpiod_int || !ts->gpiod_rst)
return 0;
/*
* Exit sleep mode by outputting HIGH level to INT pin
* for 2ms~5ms.
*/
error = gpiod_direction_output(ts->gpiod_int, 1);
if (error)
return error;
usleep_range(2000, 5000);
error = goodix_int_sync(ts);
if (error)
return error;
error = goodix_request_irq(ts);
if (error)
return error;
return 0;
}
static SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
static const struct i2c_device_id goodix_ts_id[] = {
{ "GDIX1001:00", 0 },
{ }
......@@ -446,11 +875,13 @@ MODULE_DEVICE_TABLE(of, goodix_of_match);
static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id,
.driver = {
.name = "Goodix-TS",
.acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match),
.pm = &goodix_pm_ops,
},
};
module_i2c_driver(goodix_ts_driver);
......
......@@ -87,7 +87,7 @@ static void pcap_ts_read_xy(void *data, u16 res[2])
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);
u8 ch[2];
......
......@@ -38,6 +38,8 @@ struct pixcir_i2c_ts_data {
struct input_dev *input;
struct gpio_desc *gpio_attb;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_enable;
struct gpio_desc *gpio_wake;
const struct pixcir_i2c_chip_data *chip;
int max_fingers; /* Max fingers supported in this instance */
bool running;
......@@ -208,6 +210,11 @@ static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
struct device *dev = &ts->client->dev;
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);
if (ret < 0) {
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,
return ret;
}
if (mode == PIXCIR_POWER_HALT) {
if (ts->gpio_wake)
gpiod_set_value_cansleep(ts->gpio_wake, 0);
}
return 0;
}
......@@ -302,6 +314,11 @@ static int pixcir_start(struct pixcir_i2c_ts_data *ts)
struct device *dev = &ts->client->dev;
int error;
if (ts->gpio_enable) {
gpiod_set_value_cansleep(ts->gpio_enable, 1);
msleep(100);
}
/* LEVEL_TOUCH interrupt with active low polarity */
error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
if (error) {
......@@ -343,6 +360,9 @@ static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
/* Wait till running ISR is complete */
synchronize_irq(ts->client->irq);
if (ts->gpio_enable)
gpiod_set_value_cansleep(ts->gpio_enable, 0);
return 0;
}
......@@ -534,6 +554,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
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,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
......
......@@ -725,7 +725,7 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
break;
error = -EIO;
} while (++retry >= FIRMWARE_RETRY_MAX);
} while (++retry <= FIRMWARE_RETRY_MAX);
out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
......
......@@ -273,8 +273,6 @@ static irqreturn_t titsc_irq(int irq, void *dev)
status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
if (status & IRQENB_HW_PEN) {
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;
}
......
/*
* 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");
......@@ -80,7 +80,8 @@ struct w8001_touch_query {
*/
struct w8001 {
struct input_dev *dev;
struct input_dev *pen_dev;
struct input_dev *touch_dev;
struct serio *serio;
struct completion cmd_done;
int id;
......@@ -95,7 +96,10 @@ struct w8001 {
u16 max_touch_y;
u16 max_pen_x;
u16 max_pen_y;
char name[64];
char pen_name[64];
char touch_name[64];
int open_count;
struct mutex mutex;
};
static void parse_pen_data(u8 *data, struct w8001_coord *coord)
......@@ -141,7 +145,7 @@ static void scale_touch_coordinates(struct w8001 *w8001,
static void parse_multi_touch(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
struct input_dev *dev = w8001->touch_dev;
unsigned char *data = w8001->data;
unsigned int x, y;
int i;
......@@ -151,7 +155,6 @@ static void parse_multi_touch(struct w8001 *w8001)
bool touch = data[0] & (1 << i);
input_mt_slot(dev, i);
input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
if (touch) {
x = (data[6 * i + 1] << 7) | data[6 * i + 2];
y = (data[6 * i + 3] << 7) | data[6 * i + 4];
......@@ -207,7 +210,7 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query)
static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
{
struct input_dev *dev = w8001->dev;
struct input_dev *dev = w8001->pen_dev;
/*
* We have 1 bit for proximity (rdy) and 3 bits for tip, side,
......@@ -233,11 +236,6 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
break;
case BTN_TOOL_FINGER:
input_report_key(dev, BTN_TOUCH, 0);
input_report_key(dev, BTN_TOOL_FINGER, 0);
input_sync(dev);
/* fall through */
case KEY_RESERVED:
w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
break;
......@@ -261,7 +259,7 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord)
static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
{
struct input_dev *dev = w8001->dev;
struct input_dev *dev = w8001->touch_dev;
unsigned int x = coord->x;
unsigned int y = coord->y;
......@@ -271,7 +269,6 @@ static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord)
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_key(dev, BTN_TOUCH, coord->tsw);
input_report_key(dev, BTN_TOOL_FINGER, coord->tsw);
input_sync(dev);
......@@ -369,22 +366,36 @@ static int w8001_command(struct w8001 *w8001, unsigned char command,
static int w8001_open(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
int err;
return w8001_command(w8001, W8001_CMD_START, false);
err = mutex_lock_interruptible(&w8001->mutex);
if (err)
return err;
if (w8001->open_count++ == 0) {
err = w8001_command(w8001, W8001_CMD_START, false);
if (err)
w8001->open_count--;
}
mutex_unlock(&w8001->mutex);
return err;
}
static void w8001_close(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
w8001_command(w8001, W8001_CMD_STOP, false);
mutex_lock(&w8001->mutex);
if (--w8001->open_count == 0)
w8001_command(w8001, W8001_CMD_STOP, false);
mutex_unlock(&w8001->mutex);
}
static int w8001_setup(struct w8001 *w8001)
static int w8001_detect(struct w8001 *w8001)
{
struct input_dev *dev = w8001->dev;
struct w8001_coord coord;
struct w8001_touch_query touch;
int error;
error = w8001_command(w8001, W8001_CMD_STOP, false);
......@@ -393,105 +404,145 @@ static int w8001_setup(struct w8001 *w8001)
msleep(250); /* wait 250ms before querying the device */
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name));
return 0;
}
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
static int w8001_setup_pen(struct w8001 *w8001, char *basename,
size_t basename_sz)
{
struct input_dev *dev = w8001->pen_dev;
struct w8001_coord coord;
int error;
/* penabled? */
error = w8001_command(w8001, W8001_CMD_QUERY, true);
if (!error) {
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_PEN, dev->keybit);
__set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit);
parse_pen_data(w8001->response, &coord);
w8001->max_pen_x = coord.x;
w8001->max_pen_y = coord.y;
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
if (coord.tilt_x && coord.tilt_y) {
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
w8001->id = 0x90;
strlcat(w8001->name, " Penabled", sizeof(w8001->name));
if (error)
return error;
__set_bit(EV_KEY, dev->evbit);
__set_bit(EV_ABS, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_PEN, dev->keybit);
__set_bit(BTN_TOOL_RUBBER, dev->keybit);
__set_bit(BTN_STYLUS, dev->keybit);
__set_bit(BTN_STYLUS2, dev->keybit);
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
parse_pen_data(w8001->response, &coord);
w8001->max_pen_x = coord.x;
w8001->max_pen_y = coord.y;
input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0);
input_abs_set_res(dev, ABS_X, W8001_PEN_RESOLUTION);
input_abs_set_res(dev, ABS_Y, W8001_PEN_RESOLUTION);
input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0);
if (coord.tilt_x && coord.tilt_y) {
input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0);
input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0);
}
w8001->id = 0x90;
strlcat(basename, " Penabled", basename_sz);
return 0;
}
static int w8001_setup_touch(struct w8001 *w8001, char *basename,
size_t basename_sz)
{
struct input_dev *dev = w8001->touch_dev;
struct w8001_touch_query touch;
int error;
/* Touch enabled? */
error = w8001_command(w8001, W8001_CMD_TOUCHQUERY, true);
if (error)
return error;
/*
* Some non-touch devices may reply to the touch query. But their
* second byte is empty, which indicates touch is not supported.
*/
if (!error && w8001->response[1]) {
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(BTN_TOOL_FINGER, dev->keybit);
parse_touchquery(w8001->response, &touch);
w8001->max_touch_x = touch.x;
w8001->max_touch_y = touch.y;
if (w8001->max_pen_x && w8001->max_pen_y) {
/* if pen is supported scale to pen maximum */
touch.x = w8001->max_pen_x;
touch.y = w8001->max_pen_y;
touch.panel_res = W8001_PEN_RESOLUTION;
}
if (!w8001->response[1])
return -ENXIO;
input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
input_abs_set_res(dev, ABS_X, touch.panel_res);
input_abs_set_res(dev, ABS_Y, touch.panel_res);
switch (touch.sensor_id) {
case 0:
case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93;
w8001->id = 0x93;
strlcat(w8001->name, " 1FG", sizeof(w8001->name));
break;
__set_bit(EV_KEY, dev->evbit);
__set_bit(EV_ABS, dev->evbit);
__set_bit(BTN_TOUCH, dev->keybit);
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
case 1:
case 3:
case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A;
strlcat(w8001->name, " 1FG", sizeof(w8001->name));
w8001->id = 0x9a;
break;
parse_touchquery(w8001->response, &touch);
w8001->max_touch_x = touch.x;
w8001->max_touch_y = touch.y;
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
strlcat(w8001->name, " 2FG", sizeof(w8001->name));
if (w8001->max_pen_x && w8001->max_pen_y)
w8001->id = 0xE3;
else
w8001->id = 0xE2;
break;
}
if (w8001->max_pen_x && w8001->max_pen_y) {
/* if pen is supported scale to pen maximum */
touch.x = w8001->max_pen_x;
touch.y = w8001->max_pen_y;
touch.panel_res = W8001_PEN_RESOLUTION;
}
input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0);
input_abs_set_res(dev, ABS_X, touch.panel_res);
input_abs_set_res(dev, ABS_Y, touch.panel_res);
switch (touch.sensor_id) {
case 0:
case 2:
w8001->pktlen = W8001_PKTLEN_TOUCH93;
w8001->id = 0x93;
strlcat(basename, " 1FG", basename_sz);
break;
case 1:
case 3:
case 4:
w8001->pktlen = W8001_PKTLEN_TOUCH9A;
strlcat(basename, " 1FG", basename_sz);
w8001->id = 0x9a;
break;
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
input_mt_init_slots(dev, 2, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0);
strlcat(basename, " 2FG", basename_sz);
if (w8001->max_pen_x && w8001->max_pen_y)
w8001->id = 0xE3;
else
w8001->id = 0xE2;
break;
}
strlcat(w8001->name, " Touchscreen", sizeof(w8001->name));
strlcat(basename, " Touchscreen", basename_sz);
return 0;
}
static void w8001_set_devdata(struct input_dev *dev, struct w8001 *w8001,
struct serio *serio)
{
dev->phys = w8001->phys;
dev->id.bustype = BUS_RS232;
dev->id.product = w8001->id;
dev->id.vendor = 0x056a;
dev->id.version = 0x0100;
dev->open = w8001_open;
dev->close = w8001_close;
dev->dev.parent = &serio->dev;
input_set_drvdata(dev, w8001);
}
/*
* w8001_disconnect() is the opposite of w8001_connect()
*/
......@@ -502,7 +553,10 @@ static void w8001_disconnect(struct serio *serio)
serio_close(serio);
input_unregister_device(w8001->dev);
if (w8001->pen_dev)
input_unregister_device(w8001->pen_dev);
if (w8001->touch_dev)
input_unregister_device(w8001->touch_dev);
kfree(w8001);
serio_set_drvdata(serio, NULL);
......@@ -517,18 +571,23 @@ static void w8001_disconnect(struct serio *serio)
static int w8001_connect(struct serio *serio, struct serio_driver *drv)
{
struct w8001 *w8001;
struct input_dev *input_dev;
int err;
struct input_dev *input_dev_pen;
struct input_dev *input_dev_touch;
char basename[64];
int err, err_pen, err_touch;
w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
input_dev = input_allocate_device();
if (!w8001 || !input_dev) {
input_dev_pen = input_allocate_device();
input_dev_touch = input_allocate_device();
if (!w8001 || !input_dev_pen || !input_dev_touch) {
err = -ENOMEM;
goto fail1;
}
w8001->serio = serio;
w8001->dev = input_dev;
w8001->pen_dev = input_dev_pen;
w8001->touch_dev = input_dev_touch;
mutex_init(&w8001->mutex);
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);
......@@ -537,35 +596,67 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
if (err)
goto fail2;
err = w8001_setup(w8001);
err = w8001_detect(w8001);
if (err)
goto fail3;
input_dev->name = w8001->name;
input_dev->phys = w8001->phys;
input_dev->id.product = w8001->id;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = 0x056a;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
/* For backwards-compatibility we compose the basename based on
* capabilities and then just append the tool type
*/
strlcpy(basename, "Wacom Serial", sizeof(basename));
err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
if (err_pen && err_touch) {
err = -ENXIO;
goto fail3;
}
if (!err_pen) {
strlcpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
input_dev_pen->name = w8001->pen_name;
input_dev->open = w8001_open;
input_dev->close = w8001_close;
w8001_set_devdata(input_dev_pen, w8001, serio);
input_set_drvdata(input_dev, w8001);
err = input_register_device(w8001->pen_dev);
if (err)
goto fail3;
} else {
input_free_device(input_dev_pen);
input_dev_pen = NULL;
w8001->pen_dev = NULL;
}
err = input_register_device(w8001->dev);
if (err)
goto fail3;
if (!err_touch) {
strlcpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
strlcat(w8001->touch_name, " Finger",
sizeof(w8001->touch_name));
input_dev_touch->name = w8001->touch_name;
w8001_set_devdata(input_dev_touch, w8001, serio);
err = input_register_device(w8001->touch_dev);
if (err)
goto fail4;
} else {
input_free_device(input_dev_touch);
input_dev_touch = NULL;
w8001->touch_dev = NULL;
}
return 0;
fail4:
if (w8001->pen_dev)
input_unregister_device(w8001->pen_dev);
fail3:
serio_close(serio);
fail2:
serio_set_drvdata(serio, NULL);
fail1:
input_free_device(input_dev);
input_free_device(input_dev_pen);
input_free_device(input_dev_touch);
kfree(w8001);
return err;
}
......
......@@ -20,6 +20,11 @@
* 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>)
......
......@@ -77,5 +77,6 @@
#define SERIO_PS2MULT 0x3c
#define SERIO_TSC40 0x3d
#define SERIO_WACOM_IV 0x3e
#define SERIO_EGALAX 0x3f
#endif /* _UAPI_SERIO_H */
......@@ -20,6 +20,11 @@
* 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>)
......@@ -37,8 +42,8 @@
#include <linux/types.h>
#include <linux/input.h>
#define UINPUT_VERSION 4
#define UINPUT_VERSION 5
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_ff_upload {
__u32 request_id;
......@@ -58,6 +63,76 @@ struct uinput_ff_erase {
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#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_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
......@@ -144,7 +219,6 @@ struct uinput_ff_erase {
#define UI_FF_UPLOAD 1
#define UI_FF_ERASE 2
#define UINPUT_MAX_NAME_SIZE 80
struct uinput_user_dev {
char name[UINPUT_MAX_NAME_SIZE];
struct input_id id;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册