Merge branch 'for-linus' into next

Sync up to bring in wacom_w8001 changes to avoid merge conflicts later.
This commit is contained in:
Dmitry Torokhov
2016-07-19 11:02:56 -07:00
10007 changed files with 508889 additions and 249758 deletions

View File

@@ -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))

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View 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");

View File

@@ -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, &reg);
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;
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -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],