Merge branch 'for-linus' into next
Sync up to bring in wacom_w8001 changes to avoid merge conflicts later.
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
int input_event_from_user(const char __user *buffer,
|
||||
struct input_event *event)
|
||||
{
|
||||
if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
|
||||
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
|
||||
struct input_event_compat compat_event;
|
||||
|
||||
if (copy_from_user(&compat_event, buffer,
|
||||
@@ -41,7 +41,7 @@ int input_event_from_user(const char __user *buffer,
|
||||
int input_event_to_user(char __user *buffer,
|
||||
const struct input_event *event)
|
||||
{
|
||||
if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
|
||||
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
|
||||
struct input_event_compat compat_event;
|
||||
|
||||
compat_event.time.tv_sec = event->time.tv_sec;
|
||||
@@ -65,7 +65,7 @@ int input_event_to_user(char __user *buffer,
|
||||
int input_ff_effect_from_user(const char __user *buffer, size_t size,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
if (INPUT_COMPAT_TEST) {
|
||||
if (in_compat_syscall()) {
|
||||
struct ff_effect_compat *compat_effect;
|
||||
|
||||
if (size != sizeof(struct ff_effect_compat))
|
||||
|
@@ -17,18 +17,6 @@
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
/* Note to the author of this code: did it ever occur to
|
||||
you why the ifdefs are needed? Think about it again. -AK */
|
||||
#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)
|
||||
# define INPUT_COMPAT_TEST is_compat_task()
|
||||
#elif defined(CONFIG_S390)
|
||||
# define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
|
||||
#elif defined(CONFIG_MIPS)
|
||||
# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
|
||||
#else
|
||||
# define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT)
|
||||
#endif
|
||||
|
||||
struct input_event_compat {
|
||||
struct compat_timeval time;
|
||||
__u16 type;
|
||||
@@ -67,7 +55,7 @@ struct ff_effect_compat {
|
||||
|
||||
static inline size_t input_event_size(void)
|
||||
{
|
||||
return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ?
|
||||
return (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) ?
|
||||
sizeof(struct input_event_compat) : sizeof(struct input_event);
|
||||
}
|
||||
|
||||
|
@@ -1014,7 +1014,7 @@ static int input_bits_to_string(char *buf, int buf_size,
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (INPUT_COMPAT_TEST) {
|
||||
if (in_compat_syscall()) {
|
||||
u32 dword = bits >> 32;
|
||||
if (dword || !skip_empty)
|
||||
len += snprintf(buf, buf_size, "%x ", dword);
|
||||
|
@@ -87,7 +87,7 @@
|
||||
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
|
||||
#define DRIVER_DESC "X-Box pad driver"
|
||||
|
||||
#define XPAD_PKT_LEN 32
|
||||
#define XPAD_PKT_LEN 64
|
||||
|
||||
/* xbox d-pads should map to buttons, as is required for DDR pads
|
||||
but we map them to axes when possible to simplify things */
|
||||
@@ -129,6 +129,7 @@ static const struct xpad_device {
|
||||
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
|
||||
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
|
||||
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
|
||||
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
|
||||
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
||||
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
|
||||
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
|
||||
@@ -153,6 +154,7 @@ static const struct xpad_device {
|
||||
{ 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 },
|
||||
{ 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
|
||||
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||
{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 },
|
||||
{ 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
|
||||
@@ -172,9 +174,11 @@ static const struct xpad_device {
|
||||
{ 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
|
||||
{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
|
||||
{ 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
|
||||
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
|
||||
@@ -182,6 +186,7 @@ static const struct xpad_device {
|
||||
{ 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE },
|
||||
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
|
||||
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
|
||||
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
|
||||
@@ -198,6 +203,7 @@ static const struct xpad_device {
|
||||
{ 0x162e, 0xbeef, "Joytech Neo-Se Take2", 0, XTYPE_XBOX360 },
|
||||
{ 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 },
|
||||
{ 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x542a, "Xbox ONE spectra", 0, XTYPE_XBOXONE },
|
||||
{ 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
@@ -211,6 +217,8 @@ static const struct xpad_device {
|
||||
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE },
|
||||
{ 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE },
|
||||
{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 },
|
||||
{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 },
|
||||
@@ -304,14 +312,18 @@ static struct usb_device_id xpad_table[] = {
|
||||
XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
|
||||
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
|
||||
{ USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
|
||||
XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */
|
||||
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */
|
||||
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
|
||||
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
||||
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
|
||||
XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
|
||||
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
|
||||
XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */
|
||||
XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */
|
||||
@@ -455,6 +467,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
|
||||
static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
|
||||
u16 cmd, unsigned char *data)
|
||||
{
|
||||
/* valid pad data */
|
||||
if (data[0] != 0x00)
|
||||
return;
|
||||
|
||||
/* digital pad */
|
||||
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
|
||||
/* dpad as buttons (left, right, up, down) */
|
||||
@@ -754,6 +770,7 @@ static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad)
|
||||
if (packet) {
|
||||
memcpy(xpad->odata, packet->data, packet->len);
|
||||
xpad->irq_out->transfer_buffer_length = packet->len;
|
||||
packet->pending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -795,7 +812,6 @@ static void xpad_irq_out(struct urb *urb)
|
||||
switch (status) {
|
||||
case 0:
|
||||
/* success */
|
||||
xpad->out_packets[xpad->last_out_packet].pending = false;
|
||||
xpad->irq_out_active = xpad_prepare_next_out_packet(xpad);
|
||||
break;
|
||||
|
||||
@@ -1015,17 +1031,17 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
|
||||
|
||||
case XTYPE_XBOXONE:
|
||||
packet->data[0] = 0x09; /* activate rumble */
|
||||
packet->data[1] = 0x08;
|
||||
packet->data[1] = 0x00;
|
||||
packet->data[2] = xpad->odata_serial++;
|
||||
packet->data[3] = 0x08; /* continuous effect */
|
||||
packet->data[4] = 0x00; /* simple rumble mode */
|
||||
packet->data[5] = 0x03; /* L and R actuator only */
|
||||
packet->data[6] = 0x00; /* TODO: LT actuator */
|
||||
packet->data[7] = 0x00; /* TODO: RT actuator */
|
||||
packet->data[3] = 0x09;
|
||||
packet->data[4] = 0x00;
|
||||
packet->data[5] = 0x0F;
|
||||
packet->data[6] = 0x00;
|
||||
packet->data[7] = 0x00;
|
||||
packet->data[8] = strong / 512; /* left actuator */
|
||||
packet->data[9] = weak / 512; /* right actuator */
|
||||
packet->data[10] = 0x80; /* length of pulse */
|
||||
packet->data[11] = 0x00; /* stop period of pulse */
|
||||
packet->data[10] = 0xFF;
|
||||
packet->data[11] = 0x00;
|
||||
packet->data[12] = 0x00;
|
||||
packet->len = 13;
|
||||
packet->pending = true;
|
||||
@@ -1415,22 +1431,15 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
int ep_irq_in_idx;
|
||||
int i, error;
|
||||
|
||||
if (intf->cur_altsetting->desc.bNumEndpoints != 2)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; xpad_device[i].idVendor; i++) {
|
||||
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
|
||||
(le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
|
||||
break;
|
||||
}
|
||||
|
||||
if (xpad_device[i].xtype == XTYPE_XBOXONE &&
|
||||
intf->cur_altsetting->desc.bInterfaceNumber != 0) {
|
||||
/*
|
||||
* The Xbox One controller lists three interfaces all with the
|
||||
* same interface class, subclass and protocol. Differentiate by
|
||||
* interface number.
|
||||
*/
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
|
||||
if (!xpad)
|
||||
return -ENOMEM;
|
||||
@@ -1462,6 +1471,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
|
||||
if (intf->cur_altsetting->desc.bInterfaceProtocol == 129)
|
||||
xpad->xtype = XTYPE_XBOX360W;
|
||||
else if (intf->cur_altsetting->desc.bInterfaceProtocol == 208)
|
||||
xpad->xtype = XTYPE_XBOXONE;
|
||||
else
|
||||
xpad->xtype = XTYPE_XBOX360;
|
||||
} else {
|
||||
@@ -1476,6 +1487,17 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||||
xpad->mapping |= MAP_STICKS_TO_NULL;
|
||||
}
|
||||
|
||||
if (xpad->xtype == XTYPE_XBOXONE &&
|
||||
intf->cur_altsetting->desc.bInterfaceNumber != 0) {
|
||||
/*
|
||||
* The Xbox One controller lists three interfaces all with the
|
||||
* same interface class, subclass and protocol. Differentiate by
|
||||
* interface number.
|
||||
*/
|
||||
error = -ENODEV;
|
||||
goto err_free_in_urb;
|
||||
}
|
||||
|
||||
error = xpad_init_output(intf, xpad);
|
||||
if (error)
|
||||
goto err_free_in_urb;
|
||||
|
@@ -178,7 +178,6 @@ static int arizona_haptics_probe(struct platform_device *pdev)
|
||||
input_set_drvdata(haptics->input_dev, haptics);
|
||||
|
||||
haptics->input_dev->name = "arizona:haptics";
|
||||
haptics->input_dev->dev.parent = pdev->dev.parent;
|
||||
haptics->input_dev->close = arizona_haptics_close;
|
||||
__set_bit(FF_RUMBLE, haptics->input_dev->ffbit);
|
||||
|
||||
|
@@ -255,12 +255,14 @@ static int max8997_haptic_probe(struct platform_device *pdev)
|
||||
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
const struct max8997_platform_data *pdata =
|
||||
dev_get_platdata(iodev->dev);
|
||||
const struct max8997_haptic_platform_data *haptic_pdata =
|
||||
pdata->haptic_pdata;
|
||||
const struct max8997_haptic_platform_data *haptic_pdata = NULL;
|
||||
struct max8997_haptic *chip;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
if (pdata)
|
||||
haptic_pdata = pdata->haptic_pdata;
|
||||
|
||||
if (!haptic_pdata) {
|
||||
dev_err(&pdev->dev, "no haptic platform data\n");
|
||||
return -EINVAL;
|
||||
|
@@ -353,7 +353,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
||||
if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
|
||||
kpd_delay = 15625;
|
||||
|
||||
if (kpd_delay > 62500 || kpd_delay == 0) {
|
||||
/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
|
||||
if (kpd_delay > USEC_PER_SEC * 2 || kpd_delay < USEC_PER_SEC / 64) {
|
||||
dev_err(&pdev->dev, "invalid power key trigger delay\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -385,8 +386,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
||||
pwr->name = "pmic8xxx_pwrkey";
|
||||
pwr->phys = "pmic8xxx_pwrkey/input0";
|
||||
|
||||
delay = (kpd_delay << 10) / USEC_PER_SEC;
|
||||
delay = 1 + ilog2(delay);
|
||||
delay = (kpd_delay << 6) / USEC_PER_SEC;
|
||||
delay = ilog2(delay);
|
||||
|
||||
err = regmap_read(regmap, PON_CNTL_1, &pon_cntl);
|
||||
if (err < 0) {
|
||||
|
@@ -20,21 +20,40 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct pwm_beeper {
|
||||
struct input_dev *input;
|
||||
struct pwm_device *pwm;
|
||||
struct work_struct work;
|
||||
unsigned long period;
|
||||
};
|
||||
|
||||
#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
|
||||
|
||||
static void __pwm_beeper_set(struct pwm_beeper *beeper)
|
||||
{
|
||||
unsigned long period = beeper->period;
|
||||
|
||||
if (period) {
|
||||
pwm_config(beeper->pwm, period / 2, period);
|
||||
pwm_enable(beeper->pwm);
|
||||
} else
|
||||
pwm_disable(beeper->pwm);
|
||||
}
|
||||
|
||||
static void pwm_beeper_work(struct work_struct *work)
|
||||
{
|
||||
struct pwm_beeper *beeper =
|
||||
container_of(work, struct pwm_beeper, work);
|
||||
|
||||
__pwm_beeper_set(beeper);
|
||||
}
|
||||
|
||||
static int pwm_beeper_event(struct input_dev *input,
|
||||
unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pwm_beeper *beeper = input_get_drvdata(input);
|
||||
unsigned long period;
|
||||
|
||||
if (type != EV_SND || value < 0)
|
||||
return -EINVAL;
|
||||
@@ -49,22 +68,31 @@ static int pwm_beeper_event(struct input_dev *input,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value == 0) {
|
||||
pwm_disable(beeper->pwm);
|
||||
} else {
|
||||
period = HZ_TO_NANOSECONDS(value);
|
||||
ret = pwm_config(beeper->pwm, period / 2, period);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pwm_enable(beeper->pwm);
|
||||
if (ret)
|
||||
return ret;
|
||||
beeper->period = period;
|
||||
}
|
||||
if (value == 0)
|
||||
beeper->period = 0;
|
||||
else
|
||||
beeper->period = HZ_TO_NANOSECONDS(value);
|
||||
|
||||
schedule_work(&beeper->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_beeper_stop(struct pwm_beeper *beeper)
|
||||
{
|
||||
cancel_work_sync(&beeper->work);
|
||||
|
||||
if (beeper->period)
|
||||
pwm_disable(beeper->pwm);
|
||||
}
|
||||
|
||||
static void pwm_beeper_close(struct input_dev *input)
|
||||
{
|
||||
struct pwm_beeper *beeper = input_get_drvdata(input);
|
||||
|
||||
pwm_beeper_stop(beeper);
|
||||
}
|
||||
|
||||
static int pwm_beeper_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned long pwm_id = (unsigned long)dev_get_platdata(&pdev->dev);
|
||||
@@ -87,6 +115,8 @@ static int pwm_beeper_probe(struct platform_device *pdev)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
INIT_WORK(&beeper->work, pwm_beeper_work);
|
||||
|
||||
beeper->input = input_allocate_device();
|
||||
if (!beeper->input) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device\n");
|
||||
@@ -106,6 +136,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
|
||||
beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
|
||||
|
||||
beeper->input->event = pwm_beeper_event;
|
||||
beeper->input->close = pwm_beeper_close;
|
||||
|
||||
input_set_drvdata(beeper->input, beeper);
|
||||
|
||||
@@ -135,7 +166,6 @@ static int pwm_beeper_remove(struct platform_device *pdev)
|
||||
|
||||
input_unregister_device(beeper->input);
|
||||
|
||||
pwm_disable(beeper->pwm);
|
||||
pwm_free(beeper->pwm);
|
||||
|
||||
kfree(beeper);
|
||||
@@ -147,8 +177,7 @@ static int __maybe_unused pwm_beeper_suspend(struct device *dev)
|
||||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
if (beeper->period)
|
||||
pwm_disable(beeper->pwm);
|
||||
pwm_beeper_stop(beeper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -157,10 +186,8 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
|
||||
{
|
||||
struct pwm_beeper *beeper = dev_get_drvdata(dev);
|
||||
|
||||
if (beeper->period) {
|
||||
pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
|
||||
pwm_enable(beeper->pwm);
|
||||
}
|
||||
if (beeper->period)
|
||||
__pwm_beeper_set(beeper);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -222,7 +222,6 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
|
||||
|
||||
info->input_dev->name = "twl4030:vibrator";
|
||||
info->input_dev->id.version = 1;
|
||||
info->input_dev->dev.parent = pdev->dev.parent;
|
||||
info->input_dev->close = twl4030_vibra_close;
|
||||
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
|
||||
|
||||
|
@@ -45,7 +45,6 @@
|
||||
struct vibra_info {
|
||||
struct device *dev;
|
||||
struct input_dev *input_dev;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct play_work;
|
||||
|
||||
int irq;
|
||||
@@ -182,6 +181,14 @@ static void vibra_play_work(struct work_struct *work)
|
||||
{
|
||||
struct vibra_info *info = container_of(work,
|
||||
struct vibra_info, play_work);
|
||||
int ret;
|
||||
|
||||
/* Do not allow effect, while the routing is set to use audio */
|
||||
ret = twl6040_get_vibralr_status(info->twl6040);
|
||||
if (ret & TWL6040_VIBSEL) {
|
||||
dev_info(info->dev, "Vibra is configured for audio\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->weak_speed || info->strong_speed) {
|
||||
if (!info->enabled)
|
||||
@@ -197,24 +204,12 @@ static int vibra_play(struct input_dev *input, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct vibra_info *info = input_get_drvdata(input);
|
||||
int ret;
|
||||
|
||||
/* Do not allow effect, while the routing is set to use audio */
|
||||
ret = twl6040_get_vibralr_status(info->twl6040);
|
||||
if (ret & TWL6040_VIBSEL) {
|
||||
dev_info(&input->dev, "Vibra is configured for audio\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
info->weak_speed = effect->u.rumble.weak_magnitude;
|
||||
info->strong_speed = effect->u.rumble.strong_magnitude;
|
||||
info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
|
||||
|
||||
ret = queue_work(info->workqueue, &info->play_work);
|
||||
if (!ret) {
|
||||
dev_info(&input->dev, "work is already on queue\n");
|
||||
return ret;
|
||||
}
|
||||
schedule_work(&info->play_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -253,6 +248,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
int vddvibr_uV = 0;
|
||||
int error;
|
||||
|
||||
of_node_get(twl6040_core_dev->of_node);
|
||||
twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
|
||||
"vibra");
|
||||
if (!twl6040_core_node) {
|
||||
@@ -351,7 +347,6 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
||||
|
||||
info->input_dev->name = "twl6040:vibrator";
|
||||
info->input_dev->id.version = 1;
|
||||
info->input_dev->dev.parent = pdev->dev.parent;
|
||||
info->input_dev->close = twl6040_vibra_close;
|
||||
__set_bit(FF_RUMBLE, info->input_dev->ffbit);
|
||||
|
||||
|
@@ -664,7 +664,7 @@ struct uinput_ff_upload_compat {
|
||||
static int uinput_ff_upload_to_user(char __user *buffer,
|
||||
const struct uinput_ff_upload *ff_up)
|
||||
{
|
||||
if (INPUT_COMPAT_TEST) {
|
||||
if (in_compat_syscall()) {
|
||||
struct uinput_ff_upload_compat ff_up_compat;
|
||||
|
||||
ff_up_compat.request_id = ff_up->request_id;
|
||||
@@ -695,7 +695,7 @@ static int uinput_ff_upload_to_user(char __user *buffer,
|
||||
static int uinput_ff_upload_from_user(const char __user *buffer,
|
||||
struct uinput_ff_upload *ff_up)
|
||||
{
|
||||
if (INPUT_COMPAT_TEST) {
|
||||
if (in_compat_syscall()) {
|
||||
struct uinput_ff_upload_compat ff_up_compat;
|
||||
|
||||
if (copy_from_user(&ff_up_compat, buffer,
|
||||
@@ -981,9 +981,15 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
#define UI_SET_PHYS_COMPAT _IOW(UINPUT_IOCTL_BASE, 108, compat_uptr_t)
|
||||
|
||||
static long uinput_compat_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (cmd == UI_SET_PHYS_COMPAT)
|
||||
cmd = UI_SET_PHYS;
|
||||
|
||||
return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
|
||||
}
|
||||
#endif
|
||||
|
@@ -2,6 +2,10 @@
|
||||
* BYD TouchPad PS/2 mouse driver
|
||||
*
|
||||
* Copyright (C) 2015 Chris Diamand <chris@diamand.org>
|
||||
* Copyright (C) 2015 Richard Pospesel
|
||||
* Copyright (C) 2015 Tai Chi Minh Ralph Eastwood
|
||||
* Copyright (C) 2015 Martin Wimpress
|
||||
* Copyright (C) 2015 Jay Kuri
|
||||
*
|
||||
* 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
|
||||
|
@@ -1568,13 +1568,7 @@ static int elantech_set_properties(struct elantech_data *etd)
|
||||
case 5:
|
||||
etd->hw_version = 3;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 13:
|
||||
case 14:
|
||||
case 6 ... 14:
|
||||
etd->hw_version = 4;
|
||||
break;
|
||||
default:
|
||||
|
@@ -355,18 +355,11 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
|
||||
psmouse_dbg(psmouse, "VMMouse port in use.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Check if the device is present */
|
||||
response = ~VMMOUSE_PROTO_MAGIC;
|
||||
VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
|
||||
if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU) {
|
||||
release_region(VMMOUSE_PROTO_PORT, 4);
|
||||
if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = VMMOUSE_VENDOR;
|
||||
@@ -374,8 +367,6 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
|
||||
psmouse->model = version;
|
||||
}
|
||||
|
||||
release_region(VMMOUSE_PROTO_PORT, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -394,7 +385,6 @@ static void vmmouse_disconnect(struct psmouse *psmouse)
|
||||
psmouse_reset(psmouse);
|
||||
input_unregister_device(priv->abs_dev);
|
||||
kfree(priv);
|
||||
release_region(VMMOUSE_PROTO_PORT, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -438,15 +428,10 @@ int vmmouse_init(struct psmouse *psmouse)
|
||||
struct input_dev *rel_dev = psmouse->dev, *abs_dev;
|
||||
int error;
|
||||
|
||||
if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) {
|
||||
psmouse_dbg(psmouse, "VMMouse port in use.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
error = vmmouse_enable(psmouse);
|
||||
if (error)
|
||||
goto release_region;
|
||||
return error;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
abs_dev = input_allocate_device();
|
||||
@@ -502,8 +487,5 @@ init_fail:
|
||||
kfree(priv);
|
||||
psmouse->private = NULL;
|
||||
|
||||
release_region:
|
||||
release_region(VMMOUSE_PROTO_PORT, 4);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@@ -157,11 +157,11 @@ static int rmi_function_match(struct device *dev, struct device_driver *drv)
|
||||
static void rmi_function_of_probe(struct rmi_function *fn)
|
||||
{
|
||||
char of_name[9];
|
||||
struct device_node *node = fn->rmi_dev->xport->dev->of_node;
|
||||
|
||||
snprintf(of_name, sizeof(of_name), "rmi4-f%02x",
|
||||
fn->fd.function_number);
|
||||
fn->dev.of_node = of_find_node_by_name(
|
||||
fn->rmi_dev->xport->dev->of_node, of_name);
|
||||
fn->dev.of_node = of_get_child_by_name(node, of_name);
|
||||
}
|
||||
#else
|
||||
static inline void rmi_function_of_probe(struct rmi_function *fn)
|
||||
|
@@ -857,6 +857,14 @@ static int gtco_probe(struct usb_interface *usbinterface,
|
||||
goto err_free_buf;
|
||||
}
|
||||
|
||||
/* Sanity check that a device has an endpoint */
|
||||
if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) {
|
||||
dev_err(&usbinterface->dev,
|
||||
"Invalid number of endpoints\n");
|
||||
error = -EINVAL;
|
||||
goto err_free_urb;
|
||||
}
|
||||
|
||||
/*
|
||||
* The endpoint is always altsetting 0, we know this since we know
|
||||
* this device only has one interrupt endpoint
|
||||
@@ -878,7 +886,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
|
||||
* HID report descriptor
|
||||
*/
|
||||
if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
|
||||
HID_DEVICE_TYPE, &hid_desc) != 0){
|
||||
HID_DEVICE_TYPE, &hid_desc) != 0) {
|
||||
dev_err(&usbinterface->dev,
|
||||
"Can't retrieve exta USB descriptor to get hid report descriptor length\n");
|
||||
error = -EIO;
|
||||
|
@@ -833,6 +833,15 @@ config TOUCHSCREEN_USB_COMPOSITE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called usbtouchscreen.
|
||||
|
||||
config TOUCHSCREEN_MX25
|
||||
tristate "Freescale i.MX25 touchscreen input driver"
|
||||
depends on MFD_MX25_TSADC
|
||||
help
|
||||
Enable support for touchscreen connected to your i.MX25.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called fsl-imx25-tcq.
|
||||
|
||||
config TOUCHSCREEN_MC13783
|
||||
tristate "Freescale MC13783 touchscreen input driver"
|
||||
depends on MFD_MC13XXX
|
||||
|
@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o
|
||||
|
@@ -1093,6 +1093,19 @@ static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxt_acquire_irq(struct mxt_data *data)
|
||||
{
|
||||
int error;
|
||||
|
||||
enable_irq(data->irq);
|
||||
|
||||
error = mxt_process_messages_until_invalid(data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxt_soft_reset(struct mxt_data *data)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
@@ -1111,7 +1124,7 @@ static int mxt_soft_reset(struct mxt_data *data)
|
||||
/* Ignore CHG line for 100ms after reset */
|
||||
msleep(100);
|
||||
|
||||
enable_irq(data->irq);
|
||||
mxt_acquire_irq(data);
|
||||
|
||||
ret = mxt_wait_for_completion(data, &data->reset_completion,
|
||||
MXT_RESET_TIMEOUT);
|
||||
@@ -1466,19 +1479,6 @@ release_mem:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxt_acquire_irq(struct mxt_data *data)
|
||||
{
|
||||
int error;
|
||||
|
||||
enable_irq(data->irq);
|
||||
|
||||
error = mxt_process_messages_until_invalid(data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxt_get_info(struct mxt_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
|
596
drivers/input/touchscreen/fsl-imx25-tcq.c
Normal file
596
drivers/input/touchscreen/fsl-imx25-tcq.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Based on driver from 2011:
|
||||
* Juergen Beisert, Pengutronix <kernel@pengutronix.de>
|
||||
*
|
||||
* This is the driver for the imx25 TCQ (Touchscreen Conversion Queue)
|
||||
* connected to the imx25 ADC.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/imx25-tsadc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static const char mx25_tcq_name[] = "mx25-tcq";
|
||||
|
||||
enum mx25_tcq_mode {
|
||||
MX25_TS_4WIRE,
|
||||
};
|
||||
|
||||
struct mx25_tcq_priv {
|
||||
struct regmap *regs;
|
||||
struct regmap *core_regs;
|
||||
struct input_dev *idev;
|
||||
enum mx25_tcq_mode mode;
|
||||
unsigned int pen_threshold;
|
||||
unsigned int sample_count;
|
||||
unsigned int expected_samples;
|
||||
unsigned int pen_debounce;
|
||||
unsigned int settling_time;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static struct regmap_config mx25_tcq_regconfig = {
|
||||
.fast_io = true,
|
||||
.max_register = 0x5c,
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static const struct of_device_id mx25_tcq_ids[] = {
|
||||
{ .compatible = "fsl,imx25-tcq", },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
#define TSC_4WIRE_PRE_INDEX 0
|
||||
#define TSC_4WIRE_X_INDEX 1
|
||||
#define TSC_4WIRE_Y_INDEX 2
|
||||
#define TSC_4WIRE_POST_INDEX 3
|
||||
#define TSC_4WIRE_LEAVE 4
|
||||
|
||||
#define MX25_TSC_DEF_THRESHOLD 80
|
||||
#define TSC_MAX_SAMPLES 16
|
||||
|
||||
#define MX25_TSC_REPEAT_WAIT 14
|
||||
|
||||
enum mx25_adc_configurations {
|
||||
MX25_CFG_PRECHARGE = 0,
|
||||
MX25_CFG_TOUCH_DETECT,
|
||||
MX25_CFG_X_MEASUREMENT,
|
||||
MX25_CFG_Y_MEASUREMENT,
|
||||
};
|
||||
|
||||
#define MX25_PRECHARGE_VALUE (\
|
||||
MX25_ADCQ_CFG_YPLL_OFF | \
|
||||
MX25_ADCQ_CFG_XNUR_OFF | \
|
||||
MX25_ADCQ_CFG_XPUL_HIGH | \
|
||||
MX25_ADCQ_CFG_REFP_INT | \
|
||||
MX25_ADCQ_CFG_IN_XP | \
|
||||
MX25_ADCQ_CFG_REFN_NGND2 | \
|
||||
MX25_ADCQ_CFG_IGS)
|
||||
|
||||
#define MX25_TOUCH_DETECT_VALUE (\
|
||||
MX25_ADCQ_CFG_YNLR | \
|
||||
MX25_ADCQ_CFG_YPLL_OFF | \
|
||||
MX25_ADCQ_CFG_XNUR_OFF | \
|
||||
MX25_ADCQ_CFG_XPUL_OFF | \
|
||||
MX25_ADCQ_CFG_REFP_INT | \
|
||||
MX25_ADCQ_CFG_IN_XP | \
|
||||
MX25_ADCQ_CFG_REFN_NGND2 | \
|
||||
MX25_ADCQ_CFG_PENIACK)
|
||||
|
||||
static void imx25_setup_queue_cfgs(struct mx25_tcq_priv *priv,
|
||||
unsigned int settling_cnt)
|
||||
{
|
||||
u32 precharge_cfg =
|
||||
MX25_PRECHARGE_VALUE |
|
||||
MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt);
|
||||
u32 touch_detect_cfg =
|
||||
MX25_TOUCH_DETECT_VALUE |
|
||||
MX25_ADCQ_CFG_NOS(1) |
|
||||
MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt);
|
||||
|
||||
regmap_write(priv->core_regs, MX25_TSC_TICR, precharge_cfg);
|
||||
|
||||
/* PRECHARGE */
|
||||
regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_PRECHARGE),
|
||||
precharge_cfg);
|
||||
|
||||
/* TOUCH_DETECT */
|
||||
regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_TOUCH_DETECT),
|
||||
touch_detect_cfg);
|
||||
|
||||
/* X Measurement */
|
||||
regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_X_MEASUREMENT),
|
||||
MX25_ADCQ_CFG_YPLL_OFF |
|
||||
MX25_ADCQ_CFG_XNUR_LOW |
|
||||
MX25_ADCQ_CFG_XPUL_HIGH |
|
||||
MX25_ADCQ_CFG_REFP_XP |
|
||||
MX25_ADCQ_CFG_IN_YP |
|
||||
MX25_ADCQ_CFG_REFN_XN |
|
||||
MX25_ADCQ_CFG_NOS(priv->sample_count) |
|
||||
MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt));
|
||||
|
||||
/* Y Measurement */
|
||||
regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_Y_MEASUREMENT),
|
||||
MX25_ADCQ_CFG_YNLR |
|
||||
MX25_ADCQ_CFG_YPLL_HIGH |
|
||||
MX25_ADCQ_CFG_XNUR_OFF |
|
||||
MX25_ADCQ_CFG_XPUL_OFF |
|
||||
MX25_ADCQ_CFG_REFP_YP |
|
||||
MX25_ADCQ_CFG_IN_XP |
|
||||
MX25_ADCQ_CFG_REFN_YN |
|
||||
MX25_ADCQ_CFG_NOS(priv->sample_count) |
|
||||
MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt));
|
||||
|
||||
/* Enable the touch detection right now */
|
||||
regmap_write(priv->core_regs, MX25_TSC_TICR, touch_detect_cfg |
|
||||
MX25_ADCQ_CFG_IGS);
|
||||
}
|
||||
|
||||
static int imx25_setup_queue_4wire(struct mx25_tcq_priv *priv,
|
||||
unsigned settling_cnt, int *items)
|
||||
{
|
||||
imx25_setup_queue_cfgs(priv, settling_cnt);
|
||||
|
||||
/* Setup the conversion queue */
|
||||
regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
|
||||
MX25_ADCQ_ITEM(0, MX25_CFG_PRECHARGE) |
|
||||
MX25_ADCQ_ITEM(1, MX25_CFG_TOUCH_DETECT) |
|
||||
MX25_ADCQ_ITEM(2, MX25_CFG_X_MEASUREMENT) |
|
||||
MX25_ADCQ_ITEM(3, MX25_CFG_Y_MEASUREMENT) |
|
||||
MX25_ADCQ_ITEM(4, MX25_CFG_PRECHARGE) |
|
||||
MX25_ADCQ_ITEM(5, MX25_CFG_TOUCH_DETECT));
|
||||
|
||||
/*
|
||||
* We measure X/Y with 'sample_count' number of samples and execute a
|
||||
* touch detection twice, with 1 sample each
|
||||
*/
|
||||
priv->expected_samples = priv->sample_count * 2 + 2;
|
||||
*items = 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mx25_tcq_disable_touch_irq(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK,
|
||||
MX25_ADCQ_CR_PDMSK);
|
||||
}
|
||||
|
||||
static void mx25_tcq_enable_touch_irq(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK, 0);
|
||||
}
|
||||
|
||||
static void mx25_tcq_disable_fifo_irq(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ,
|
||||
MX25_ADCQ_MR_FDRY_IRQ);
|
||||
}
|
||||
|
||||
static void mx25_tcq_enable_fifo_irq(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ, 0);
|
||||
}
|
||||
|
||||
static void mx25_tcq_force_queue_start(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_FQS,
|
||||
MX25_ADCQ_CR_FQS);
|
||||
}
|
||||
|
||||
static void mx25_tcq_force_queue_stop(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_FQS, 0);
|
||||
}
|
||||
|
||||
static void mx25_tcq_fifo_reset(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
u32 tcqcr;
|
||||
|
||||
regmap_read(priv->regs, MX25_ADCQ_CR, &tcqcr);
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST,
|
||||
MX25_ADCQ_CR_FRST);
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST, 0);
|
||||
regmap_write(priv->regs, MX25_ADCQ_CR, tcqcr);
|
||||
}
|
||||
|
||||
static void mx25_tcq_re_enable_touch_detection(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
/* stop the queue from looping */
|
||||
mx25_tcq_force_queue_stop(priv);
|
||||
|
||||
/* for a clean touch detection, preload the X plane */
|
||||
regmap_write(priv->core_regs, MX25_TSC_TICR, MX25_PRECHARGE_VALUE);
|
||||
|
||||
/* waste some time now to pre-load the X plate to high voltage */
|
||||
mx25_tcq_fifo_reset(priv);
|
||||
|
||||
/* re-enable the detection right now */
|
||||
regmap_write(priv->core_regs, MX25_TSC_TICR,
|
||||
MX25_TOUCH_DETECT_VALUE | MX25_ADCQ_CFG_IGS);
|
||||
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_PD,
|
||||
MX25_ADCQ_SR_PD);
|
||||
|
||||
/* enable the pen down event to be a source for the interrupt */
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_PD_IRQ, 0);
|
||||
|
||||
/* lets fire the next IRQ if someone touches the touchscreen */
|
||||
mx25_tcq_enable_touch_irq(priv);
|
||||
}
|
||||
|
||||
static void mx25_tcq_create_event_for_4wire(struct mx25_tcq_priv *priv,
|
||||
u32 *sample_buf,
|
||||
unsigned int samples)
|
||||
{
|
||||
unsigned int x_pos = 0;
|
||||
unsigned int y_pos = 0;
|
||||
unsigned int touch_pre = 0;
|
||||
unsigned int touch_post = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
unsigned int index = MX25_ADCQ_FIFO_ID(sample_buf[i]);
|
||||
unsigned int val = MX25_ADCQ_FIFO_DATA(sample_buf[i]);
|
||||
|
||||
switch (index) {
|
||||
case 1:
|
||||
touch_pre = val;
|
||||
break;
|
||||
case 2:
|
||||
x_pos = val;
|
||||
break;
|
||||
case 3:
|
||||
y_pos = val;
|
||||
break;
|
||||
case 5:
|
||||
touch_post = val;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(priv->dev, "Dropped samples because of invalid index %d\n",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (samples != 0) {
|
||||
/*
|
||||
* only if both touch measures are below a threshold,
|
||||
* the position is valid
|
||||
*/
|
||||
if (touch_pre < priv->pen_threshold &&
|
||||
touch_post < priv->pen_threshold) {
|
||||
/* valid samples, generate a report */
|
||||
x_pos /= priv->sample_count;
|
||||
y_pos /= priv->sample_count;
|
||||
input_report_abs(priv->idev, ABS_X, x_pos);
|
||||
input_report_abs(priv->idev, ABS_Y, y_pos);
|
||||
input_report_key(priv->idev, BTN_TOUCH, 1);
|
||||
input_sync(priv->idev);
|
||||
|
||||
/* get next sample */
|
||||
mx25_tcq_enable_fifo_irq(priv);
|
||||
} else if (touch_pre >= priv->pen_threshold &&
|
||||
touch_post >= priv->pen_threshold) {
|
||||
/*
|
||||
* if both samples are invalid,
|
||||
* generate a release report
|
||||
*/
|
||||
input_report_key(priv->idev, BTN_TOUCH, 0);
|
||||
input_sync(priv->idev);
|
||||
mx25_tcq_re_enable_touch_detection(priv);
|
||||
} else {
|
||||
/*
|
||||
* if only one of both touch measurements are
|
||||
* below the threshold, still some bouncing
|
||||
* happens. Take additional samples in this
|
||||
* case to be sure
|
||||
*/
|
||||
mx25_tcq_enable_fifo_irq(priv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t mx25_tcq_irq_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct mx25_tcq_priv *priv = dev_id;
|
||||
u32 sample_buf[TSC_MAX_SAMPLES];
|
||||
unsigned int samples;
|
||||
u32 stats;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Check how many samples are available. We always have to read exactly
|
||||
* sample_count samples from the fifo, or a multiple of sample_count.
|
||||
* Otherwise we mixup samples into different touch events.
|
||||
*/
|
||||
regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
|
||||
samples = MX25_ADCQ_SR_FDN(stats);
|
||||
samples -= samples % priv->sample_count;
|
||||
|
||||
if (!samples)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
for (i = 0; i != samples; ++i)
|
||||
regmap_read(priv->regs, MX25_ADCQ_FIFO, &sample_buf[i]);
|
||||
|
||||
mx25_tcq_create_event_for_4wire(priv, sample_buf, samples);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mx25_tcq_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct mx25_tcq_priv *priv = dev_id;
|
||||
u32 stat;
|
||||
int ret = IRQ_HANDLED;
|
||||
|
||||
regmap_read(priv->regs, MX25_ADCQ_SR, &stat);
|
||||
|
||||
if (stat & (MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR))
|
||||
mx25_tcq_re_enable_touch_detection(priv);
|
||||
|
||||
if (stat & MX25_ADCQ_SR_PD) {
|
||||
mx25_tcq_disable_touch_irq(priv);
|
||||
mx25_tcq_force_queue_start(priv);
|
||||
mx25_tcq_enable_fifo_irq(priv);
|
||||
}
|
||||
|
||||
if (stat & MX25_ADCQ_SR_FDRY) {
|
||||
mx25_tcq_disable_fifo_irq(priv);
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
|
||||
MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
|
||||
MX25_ADCQ_SR_PD,
|
||||
MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR |
|
||||
MX25_ADCQ_SR_FOR | MX25_ADCQ_SR_PD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* configure the state machine for a 4-wire touchscreen */
|
||||
static int mx25_tcq_init(struct mx25_tcq_priv *priv)
|
||||
{
|
||||
u32 tgcr;
|
||||
unsigned int ipg_div;
|
||||
unsigned int adc_period;
|
||||
unsigned int debounce_cnt;
|
||||
unsigned int settling_cnt;
|
||||
int itemct;
|
||||
int error;
|
||||
|
||||
regmap_read(priv->core_regs, MX25_TSC_TGCR, &tgcr);
|
||||
ipg_div = max_t(unsigned int, 4, MX25_TGCR_GET_ADCCLK(tgcr));
|
||||
adc_period = USEC_PER_SEC * ipg_div * 2 + 2;
|
||||
adc_period /= clk_get_rate(priv->clk) / 1000 + 1;
|
||||
debounce_cnt = DIV_ROUND_UP(priv->pen_debounce, adc_period * 8) - 1;
|
||||
settling_cnt = DIV_ROUND_UP(priv->settling_time, adc_period * 8) - 1;
|
||||
|
||||
/* Reset */
|
||||
regmap_write(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST);
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST, 0);
|
||||
|
||||
/* up to 128 * 8 ADC clocks are possible */
|
||||
if (debounce_cnt > 127)
|
||||
debounce_cnt = 127;
|
||||
|
||||
/* up to 255 * 8 ADC clocks are possible */
|
||||
if (settling_cnt > 255)
|
||||
settling_cnt = 255;
|
||||
|
||||
error = imx25_setup_queue_4wire(priv, settling_cnt, &itemct);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_LITEMID_MASK | MX25_ADCQ_CR_WMRK_MASK,
|
||||
MX25_ADCQ_CR_LITEMID(itemct - 1) |
|
||||
MX25_ADCQ_CR_WMRK(priv->expected_samples - 1));
|
||||
|
||||
/* setup debounce count */
|
||||
regmap_update_bits(priv->core_regs, MX25_TSC_TGCR,
|
||||
MX25_TGCR_PDBTIME_MASK,
|
||||
MX25_TGCR_PDBTIME(debounce_cnt));
|
||||
|
||||
/* enable debounce */
|
||||
regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDBEN,
|
||||
MX25_TGCR_PDBEN);
|
||||
regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDEN,
|
||||
MX25_TGCR_PDEN);
|
||||
|
||||
/* enable the engine on demand */
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QSM_MASK,
|
||||
MX25_ADCQ_CR_QSM_FQS);
|
||||
|
||||
/* Enable repeat and repeat wait */
|
||||
regmap_update_bits(priv->regs, MX25_ADCQ_CR,
|
||||
MX25_ADCQ_CR_RPT | MX25_ADCQ_CR_RWAIT_MASK,
|
||||
MX25_ADCQ_CR_RPT |
|
||||
MX25_ADCQ_CR_RWAIT(MX25_TSC_REPEAT_WAIT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mx25_tcq_parse_dt(struct platform_device *pdev,
|
||||
struct mx25_tcq_priv *priv)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 wires;
|
||||
int error;
|
||||
|
||||
/* Setup defaults */
|
||||
priv->pen_threshold = 500;
|
||||
priv->sample_count = 3;
|
||||
priv->pen_debounce = 1000000;
|
||||
priv->settling_time = 250000;
|
||||
|
||||
error = of_property_read_u32(np, "fsl,wires", &wires);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Failed to find fsl,wires properties\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (wires == 4) {
|
||||
priv->mode = MX25_TS_4WIRE;
|
||||
} else {
|
||||
dev_err(&pdev->dev, "%u-wire mode not supported\n", wires);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* These are optional, we don't care about the return values */
|
||||
of_property_read_u32(np, "fsl,pen-threshold", &priv->pen_threshold);
|
||||
of_property_read_u32(np, "fsl,settling-time-ns", &priv->settling_time);
|
||||
of_property_read_u32(np, "fsl,pen-debounce-ns", &priv->pen_debounce);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mx25_tcq_open(struct input_dev *idev)
|
||||
{
|
||||
struct device *dev = &idev->dev;
|
||||
struct mx25_tcq_priv *priv = dev_get_drvdata(dev);
|
||||
int error;
|
||||
|
||||
error = clk_prepare_enable(priv->clk);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to enable ipg clock\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = mx25_tcq_init(priv);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to init tcq\n");
|
||||
clk_disable_unprepare(priv->clk);
|
||||
return error;
|
||||
}
|
||||
|
||||
mx25_tcq_re_enable_touch_detection(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mx25_tcq_close(struct input_dev *idev)
|
||||
{
|
||||
struct mx25_tcq_priv *priv = input_get_drvdata(idev);
|
||||
|
||||
mx25_tcq_force_queue_stop(priv);
|
||||
mx25_tcq_disable_touch_irq(priv);
|
||||
mx25_tcq_disable_fifo_irq(priv);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
static int mx25_tcq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct input_dev *idev;
|
||||
struct mx25_tcq_priv *priv;
|
||||
struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent);
|
||||
struct resource *res;
|
||||
void __iomem *mem;
|
||||
int error;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mem = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(mem))
|
||||
return PTR_ERR(mem);
|
||||
|
||||
error = mx25_tcq_parse_dt(pdev, priv);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_tcq_regconfig);
|
||||
if (IS_ERR(priv->regs)) {
|
||||
dev_err(dev, "Failed to initialize regmap\n");
|
||||
return PTR_ERR(priv->regs);
|
||||
}
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq <= 0) {
|
||||
dev_err(dev, "Failed to get IRQ\n");
|
||||
return priv->irq;
|
||||
}
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev) {
|
||||
dev_err(dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
idev->name = mx25_tcq_name;
|
||||
input_set_capability(idev, EV_KEY, BTN_TOUCH);
|
||||
input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
|
||||
|
||||
idev->id.bustype = BUS_HOST;
|
||||
idev->open = mx25_tcq_open;
|
||||
idev->close = mx25_tcq_close;
|
||||
|
||||
priv->idev = idev;
|
||||
input_set_drvdata(idev, priv);
|
||||
|
||||
priv->core_regs = tsadc->regs;
|
||||
if (!priv->core_regs)
|
||||
return -EINVAL;
|
||||
|
||||
priv->clk = tsadc->clk;
|
||||
if (!priv->clk)
|
||||
return -EINVAL;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
error = devm_request_threaded_irq(dev, priv->irq, mx25_tcq_irq,
|
||||
mx25_tcq_irq_thread, 0, pdev->name,
|
||||
priv);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed requesting IRQ\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to register input device\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mx25_tcq_driver = {
|
||||
.driver = {
|
||||
.name = "mx25-tcq",
|
||||
.of_match_table = mx25_tcq_ids,
|
||||
},
|
||||
.probe = mx25_tcq_probe,
|
||||
};
|
||||
module_platform_driver(mx25_tcq_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TS input driver for Freescale mx25");
|
||||
MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -118,6 +118,13 @@ static int ts4800_parse_dt(struct platform_device *pdev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ts->regmap = syscon_node_to_regmap(syscon_np);
|
||||
of_node_put(syscon_np);
|
||||
if (IS_ERR(ts->regmap)) {
|
||||
dev_err(dev, "cannot get parent's regmap\n");
|
||||
return PTR_ERR(ts->regmap);
|
||||
}
|
||||
|
||||
error = of_property_read_u32_index(np, "syscon", 1, ®);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "no offset in syscon\n");
|
||||
@@ -134,12 +141,6 @@ static int ts4800_parse_dt(struct platform_device *pdev,
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,7 @@ MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define W8001_MAX_LENGTH 11
|
||||
#define W8001_MAX_LENGTH 13
|
||||
#define W8001_LEAD_MASK 0x80
|
||||
#define W8001_LEAD_BYTE 0x80
|
||||
#define W8001_TAB_MASK 0x40
|
||||
@@ -155,6 +155,7 @@ 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];
|
||||
@@ -339,6 +340,15 @@ static irqreturn_t w8001_interrupt(struct serio *serio,
|
||||
w8001->idx = 0;
|
||||
parse_multi_touch(w8001);
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* ThinkPad X60 Tablet PC (pen only device) sometimes
|
||||
* sends invalid data packets that are larger than
|
||||
* W8001_PKTLEN_TPCPEN. Let's start over again.
|
||||
*/
|
||||
if (!w8001->touch_dev && w8001->idx > W8001_PKTLEN_TPCPEN - 1)
|
||||
w8001->idx = 0;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -513,6 +523,8 @@ static int w8001_setup_touch(struct w8001 *w8001, char *basename,
|
||||
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(basename, " 2FG", basename_sz);
|
||||
if (w8001->max_pen_x && w8001->max_pen_y)
|
||||
|
@@ -848,7 +848,7 @@ static int wdt87xx_do_update_firmware(struct i2c_client *client,
|
||||
error = wdt87xx_get_sysparam(client, &wdt->param);
|
||||
if (error)
|
||||
dev_err(&client->dev,
|
||||
"failed to refresh system paramaters: %d\n", error);
|
||||
"failed to refresh system parameters: %d\n", error);
|
||||
out:
|
||||
enable_irq(client->irq);
|
||||
mutex_unlock(&wdt->fw_mutex);
|
||||
|
@@ -370,8 +370,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
|
||||
point.coord_x = point.coord_y = 0;
|
||||
}
|
||||
|
||||
point.state = payload[9 * i + 5] & 0x03;
|
||||
point.id = (payload[9 * i + 5] & 0xfc) >> 2;
|
||||
point.state = payload[9 * i + 5] & 0x0f;
|
||||
point.id = (payload[9 * i + 5] & 0xf0) >> 4;
|
||||
|
||||
/* determine touch major, minor and orientation */
|
||||
point.area_major = max(payload[9 * i + 6],
|
||||
|
Reference in New Issue
Block a user