mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-24 05:29:04 -04:00
Merge branch 'next' into for-linus
This commit is contained in:
commit
aa7eb8e78d
7903 changed files with 475823 additions and 384855 deletions
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
/* Note to the author of this code: did it ever occur to
|
||||
you why the ifdefs are needed? Think about it again. -AK */
|
||||
#ifdef CONFIG_X86_64
|
||||
#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)
|
||||
|
|
|
|||
|
|
@ -154,10 +154,13 @@ static const struct xpad_device {
|
|||
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
|
||||
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
|
||||
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
|
||||
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
|
||||
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
|
||||
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
|
||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
|
||||
|
|
@ -236,9 +239,10 @@ 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 */
|
||||
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 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), /* Rock Band Drums */
|
||||
XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */
|
||||
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
|
||||
{ }
|
||||
};
|
||||
|
|
@ -545,7 +549,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|||
struct usb_endpoint_descriptor *ep_irq_out;
|
||||
int error;
|
||||
|
||||
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
|
||||
if (xpad->xtype == XTYPE_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
|
|
@ -579,13 +583,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
|
|||
|
||||
static void xpad_stop_output(struct usb_xpad *xpad)
|
||||
{
|
||||
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX)
|
||||
if (xpad->xtype != XTYPE_UNKNOWN)
|
||||
usb_kill_urb(xpad->irq_out);
|
||||
}
|
||||
|
||||
static void xpad_deinit_output(struct usb_xpad *xpad)
|
||||
{
|
||||
if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) {
|
||||
if (xpad->xtype != XTYPE_UNKNOWN) {
|
||||
usb_free_urb(xpad->irq_out);
|
||||
usb_free_coherent(xpad->udev, XPAD_PKT_LEN,
|
||||
xpad->odata, xpad->odata_dma);
|
||||
|
|
@ -632,6 +636,23 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
|
|||
|
||||
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
|
||||
case XTYPE_XBOX360W:
|
||||
xpad->odata[0] = 0x00;
|
||||
xpad->odata[1] = 0x01;
|
||||
xpad->odata[2] = 0x0F;
|
||||
xpad->odata[3] = 0xC0;
|
||||
xpad->odata[4] = 0x00;
|
||||
xpad->odata[5] = strong / 256;
|
||||
xpad->odata[6] = weak / 256;
|
||||
xpad->odata[7] = 0x00;
|
||||
xpad->odata[8] = 0x00;
|
||||
xpad->odata[9] = 0x00;
|
||||
xpad->odata[10] = 0x00;
|
||||
xpad->odata[11] = 0x00;
|
||||
xpad->irq_out->transfer_buffer_length = 12;
|
||||
|
||||
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
|
||||
|
||||
default:
|
||||
dbg("%s - rumble command sent to unsupported xpad type: %d",
|
||||
__func__, xpad->xtype);
|
||||
|
|
@ -644,7 +665,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
|
|||
|
||||
static int xpad_init_ff(struct usb_xpad *xpad)
|
||||
{
|
||||
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX)
|
||||
if (xpad->xtype == XTYPE_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
|
||||
|
|
|
|||
|
|
@ -412,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called pxa930_rotary.
|
||||
|
||||
config KEYBOARD_PMIC8XXX
|
||||
tristate "Qualcomm PMIC8XXX keypad support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want to enable the driver for the PMIC8XXX
|
||||
keypad provided as a reference design from Qualcomm. This is intended
|
||||
to support upto 18x8 matrix based keypad design.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called pmic8xxx-keypad.
|
||||
|
||||
config KEYBOARD_SAMSUNG
|
||||
tristate "Samsung keypad support"
|
||||
depends on SAMSUNG_DEV_KEYPAD
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
|
|||
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
|
||||
obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
|||
|
|
@ -223,8 +223,9 @@ static int __init atakbd_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
// need to init core driver if not already done so
|
||||
if (atari_keyb_init())
|
||||
return -ENODEV;
|
||||
error = atari_keyb_init();
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
atakbd_dev = input_allocate_device();
|
||||
if (!atakbd_dev)
|
||||
|
|
|
|||
|
|
@ -1578,14 +1578,14 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id)
|
|||
atkbd_platform_fixup = atkbd_apply_forced_release_keylist;
|
||||
atkbd_platform_fixup_data = id->driver_data;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id)
|
||||
{
|
||||
atkbd_platform_scancode_fixup = id->driver_data;
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
* Driver for keys on GPIO lines capable of generating interrupts.
|
||||
*
|
||||
* Copyright 2005 Phil Blundell
|
||||
* Copyright 2010, 2011 David Jander <david@protonic.nl>
|
||||
*
|
||||
* 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
|
||||
|
|
@ -25,6 +26,8 @@
|
|||
#include <linux/gpio_keys.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
struct gpio_button_data {
|
||||
struct gpio_keys_button *button;
|
||||
|
|
@ -415,7 +418,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
|
|||
if (!button->can_disable)
|
||||
irqflags |= IRQF_SHARED;
|
||||
|
||||
error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata);
|
||||
error = request_threaded_irq(irq, NULL, gpio_keys_isr, irqflags, desc, bdata);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Unable to claim irq %d; error %d\n",
|
||||
irq, error);
|
||||
|
|
@ -445,15 +448,120 @@ static void gpio_keys_close(struct input_dev *input)
|
|||
ddata->disable(input->dev.parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handlers for alternative sources of platform_data
|
||||
*/
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* Translate OpenFirmware node properties into platform_data
|
||||
*/
|
||||
static int gpio_keys_get_devtree_pdata(struct device *dev,
|
||||
struct gpio_keys_platform_data *pdata)
|
||||
{
|
||||
struct device_node *node, *pp;
|
||||
int i;
|
||||
struct gpio_keys_button *buttons;
|
||||
const u32 *reg;
|
||||
int len;
|
||||
|
||||
node = dev->of_node;
|
||||
if (node == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
memset(pdata, 0, sizeof *pdata);
|
||||
|
||||
pdata->rep = !!of_get_property(node, "autorepeat", &len);
|
||||
|
||||
/* First count the subnodes */
|
||||
pdata->nbuttons = 0;
|
||||
pp = NULL;
|
||||
while ((pp = of_get_next_child(node, pp)))
|
||||
pdata->nbuttons++;
|
||||
|
||||
if (pdata->nbuttons == 0)
|
||||
return -ENODEV;
|
||||
|
||||
buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
|
||||
if (!buttons)
|
||||
return -ENODEV;
|
||||
|
||||
pp = NULL;
|
||||
i = 0;
|
||||
while ((pp = of_get_next_child(node, pp))) {
|
||||
enum of_gpio_flags flags;
|
||||
|
||||
if (!of_find_property(pp, "gpios", NULL)) {
|
||||
pdata->nbuttons--;
|
||||
dev_warn(dev, "Found button without gpios\n");
|
||||
continue;
|
||||
}
|
||||
buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
|
||||
buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
|
||||
reg = of_get_property(pp, "linux,code", &len);
|
||||
if (!reg) {
|
||||
dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
|
||||
goto out_fail;
|
||||
}
|
||||
buttons[i].code = be32_to_cpup(reg);
|
||||
|
||||
buttons[i].desc = of_get_property(pp, "label", &len);
|
||||
|
||||
reg = of_get_property(pp, "linux,input-type", &len);
|
||||
buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY;
|
||||
|
||||
buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
|
||||
|
||||
reg = of_get_property(pp, "debounce-interval", &len);
|
||||
buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
pdata->buttons = buttons;
|
||||
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
kfree(buttons);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static struct of_device_id gpio_keys_of_match[] = {
|
||||
{ .compatible = "gpio-keys", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
|
||||
|
||||
#else
|
||||
|
||||
static int gpio_keys_get_devtree_pdata(struct device *dev,
|
||||
struct gpio_keys_platform_data *altp)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define gpio_keys_of_match NULL
|
||||
|
||||
#endif
|
||||
|
||||
static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_keys_drvdata *ddata;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_keys_platform_data alt_pdata;
|
||||
struct input_dev *input;
|
||||
int i, error;
|
||||
int wakeup = 0;
|
||||
|
||||
if (!pdata) {
|
||||
error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
|
||||
if (error)
|
||||
return error;
|
||||
pdata = &alt_pdata;
|
||||
}
|
||||
|
||||
ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
|
||||
pdata->nbuttons * sizeof(struct gpio_button_data),
|
||||
GFP_KERNEL);
|
||||
|
|
@ -544,13 +652,15 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
|||
fail1:
|
||||
input_free_device(input);
|
||||
kfree(ddata);
|
||||
/* If we have no platform_data, we allocated buttons dynamically. */
|
||||
if (!pdev->dev.platform_data)
|
||||
kfree(pdata->buttons);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
|
||||
struct input_dev *input = ddata->input;
|
||||
int i;
|
||||
|
|
@ -559,31 +669,39 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
|
|||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
||||
for (i = 0; i < ddata->n_buttons; i++) {
|
||||
int irq = gpio_to_irq(ddata->data[i].button->gpio);
|
||||
free_irq(irq, &ddata->data[i]);
|
||||
if (ddata->data[i].timer_debounce)
|
||||
del_timer_sync(&ddata->data[i].timer);
|
||||
cancel_work_sync(&ddata->data[i].work);
|
||||
gpio_free(pdata->buttons[i].gpio);
|
||||
gpio_free(ddata->data[i].button->gpio);
|
||||
}
|
||||
|
||||
input_unregister_device(input);
|
||||
|
||||
/*
|
||||
* If we had no platform_data, we allocated buttons dynamically, and
|
||||
* must free them here. ddata->data[0].button is the pointer to the
|
||||
* beginning of the allocated array.
|
||||
*/
|
||||
if (!pdev->dev.platform_data)
|
||||
kfree(ddata->data[0].button);
|
||||
|
||||
kfree(ddata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int gpio_keys_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (device_may_wakeup(&pdev->dev)) {
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
if (device_may_wakeup(dev)) {
|
||||
for (i = 0; i < ddata->n_buttons; i++) {
|
||||
struct gpio_keys_button *button = ddata->data[i].button;
|
||||
if (button->wakeup) {
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
enable_irq_wake(irq);
|
||||
|
|
@ -596,15 +714,13 @@ static int gpio_keys_suspend(struct device *dev)
|
|||
|
||||
static int gpio_keys_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
|
||||
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
for (i = 0; i < ddata->n_buttons; i++) {
|
||||
|
||||
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||
if (button->wakeup && device_may_wakeup(&pdev->dev)) {
|
||||
struct gpio_keys_button *button = ddata->data[i].button;
|
||||
if (button->wakeup && device_may_wakeup(dev)) {
|
||||
int irq = gpio_to_irq(button->gpio);
|
||||
disable_irq_wake(irq);
|
||||
}
|
||||
|
|
@ -615,22 +731,18 @@ static int gpio_keys_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops gpio_keys_pm_ops = {
|
||||
.suspend = gpio_keys_suspend,
|
||||
.resume = gpio_keys_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
|
||||
|
||||
static struct platform_driver gpio_keys_device_driver = {
|
||||
.probe = gpio_keys_probe,
|
||||
.remove = __devexit_p(gpio_keys_remove),
|
||||
.driver = {
|
||||
.name = "gpio-keys",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &gpio_keys_pm_ops,
|
||||
#endif
|
||||
.of_match_table = gpio_keys_of_match,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -644,10 +756,10 @@ static void __exit gpio_keys_exit(void)
|
|||
platform_driver_unregister(&gpio_keys_device_driver);
|
||||
}
|
||||
|
||||
module_init(gpio_keys_init);
|
||||
late_initcall(gpio_keys_init);
|
||||
module_exit(gpio_keys_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
|
||||
MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
|
||||
MODULE_DESCRIPTION("Keyboard driver for GPIOs");
|
||||
MODULE_ALIAS("platform:gpio-keys");
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ struct lm8323_chip {
|
|||
/* device lock */
|
||||
struct mutex lock;
|
||||
struct i2c_client *client;
|
||||
struct work_struct work;
|
||||
struct input_dev *idev;
|
||||
bool kp_enabled;
|
||||
bool pm_suspend;
|
||||
|
|
@ -162,7 +161,6 @@ struct lm8323_chip {
|
|||
|
||||
#define client_to_lm8323(c) container_of(c, struct lm8323_chip, client)
|
||||
#define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev)
|
||||
#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work)
|
||||
#define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev)
|
||||
#define work_to_pwm(w) container_of(w, struct lm8323_pwm, work)
|
||||
|
||||
|
|
@ -375,9 +373,9 @@ static void pwm_done(struct lm8323_pwm *pwm)
|
|||
* Bottom half: handle the interrupt by posting key events, or dealing with
|
||||
* errors appropriately.
|
||||
*/
|
||||
static void lm8323_work(struct work_struct *work)
|
||||
static irqreturn_t lm8323_irq(int irq, void *_lm)
|
||||
{
|
||||
struct lm8323_chip *lm = work_to_lm8323(work);
|
||||
struct lm8323_chip *lm = _lm;
|
||||
u8 ints;
|
||||
int i;
|
||||
|
||||
|
|
@ -409,16 +407,6 @@ static void lm8323_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
mutex_unlock(&lm->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot use I2C in interrupt context, so we just schedule work.
|
||||
*/
|
||||
static irqreturn_t lm8323_irq(int irq, void *data)
|
||||
{
|
||||
struct lm8323_chip *lm = data;
|
||||
|
||||
schedule_work(&lm->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -675,7 +663,6 @@ static int __devinit lm8323_probe(struct i2c_client *client,
|
|||
lm->client = client;
|
||||
lm->idev = idev;
|
||||
mutex_init(&lm->lock);
|
||||
INIT_WORK(&lm->work, lm8323_work);
|
||||
|
||||
lm->size_x = pdata->size_x;
|
||||
lm->size_y = pdata->size_y;
|
||||
|
|
@ -746,9 +733,8 @@ static int __devinit lm8323_probe(struct i2c_client *client,
|
|||
goto fail3;
|
||||
}
|
||||
|
||||
err = request_irq(client->irq, lm8323_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_DISABLED,
|
||||
"lm8323", lm);
|
||||
err = request_threaded_irq(client->irq, NULL, lm8323_irq,
|
||||
IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
|
||||
goto fail4;
|
||||
|
|
@ -783,7 +769,6 @@ static int __devexit lm8323_remove(struct i2c_client *client)
|
|||
|
||||
disable_irq_wake(client->irq);
|
||||
free_irq(client->irq, lm);
|
||||
cancel_work_sync(&lm->work);
|
||||
|
||||
input_unregister_device(lm->idev);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,14 +43,15 @@
|
|||
* enabled capacitance sensing inputs and its run/suspend mode.
|
||||
*/
|
||||
#define ELECTRODE_CONF_ADDR 0x5e
|
||||
#define ELECTRODE_CONF_QUICK_CHARGE 0x80
|
||||
#define AUTO_CONFIG_CTRL_ADDR 0x7b
|
||||
#define AUTO_CONFIG_USL_ADDR 0x7d
|
||||
#define AUTO_CONFIG_LSL_ADDR 0x7e
|
||||
#define AUTO_CONFIG_TL_ADDR 0x7f
|
||||
|
||||
/* Threshold of touch/release trigger */
|
||||
#define TOUCH_THRESHOLD 0x0f
|
||||
#define RELEASE_THRESHOLD 0x0a
|
||||
#define TOUCH_THRESHOLD 0x08
|
||||
#define RELEASE_THRESHOLD 0x05
|
||||
/* Masks for touch and release triggers */
|
||||
#define TOUCH_STATUS_MASK 0xfff
|
||||
/* MPR121 has 12 keys */
|
||||
|
|
@ -127,7 +128,7 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
|
|||
struct i2c_client *client)
|
||||
{
|
||||
const struct mpr121_init_register *reg;
|
||||
unsigned char usl, lsl, tl;
|
||||
unsigned char usl, lsl, tl, eleconf;
|
||||
int i, t, vdd, ret;
|
||||
|
||||
/* Set up touch/release threshold for ele0-ele11 */
|
||||
|
|
@ -163,8 +164,15 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
|
|||
ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
|
||||
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
|
||||
ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
|
||||
|
||||
/*
|
||||
* Quick charge bit will let the capacitive charge to ready
|
||||
* state quickly, or the buttons may not function after system
|
||||
* boot.
|
||||
*/
|
||||
eleconf = mpr121->keycount | ELECTRODE_CONF_QUICK_CHARGE;
|
||||
ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
|
||||
mpr121->keycount);
|
||||
eleconf);
|
||||
if (ret != 0)
|
||||
goto err_i2c_write;
|
||||
|
||||
|
|
|
|||
799
drivers/input/keyboard/pmic8xxx-keypad.c
Normal file
799
drivers/input/keyboard/pmic8xxx-keypad.c
Normal file
|
|
@ -0,0 +1,799 @@
|
|||
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/mfd/pm8xxx/gpio.h>
|
||||
#include <linux/input/pmic8xxx-keypad.h>
|
||||
|
||||
#define PM8XXX_MAX_ROWS 18
|
||||
#define PM8XXX_MAX_COLS 8
|
||||
#define PM8XXX_ROW_SHIFT 3
|
||||
#define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS)
|
||||
|
||||
#define PM8XXX_MIN_ROWS 5
|
||||
#define PM8XXX_MIN_COLS 5
|
||||
|
||||
#define MAX_SCAN_DELAY 128
|
||||
#define MIN_SCAN_DELAY 1
|
||||
|
||||
/* in nanoseconds */
|
||||
#define MAX_ROW_HOLD_DELAY 122000
|
||||
#define MIN_ROW_HOLD_DELAY 30500
|
||||
|
||||
#define MAX_DEBOUNCE_TIME 20
|
||||
#define MIN_DEBOUNCE_TIME 5
|
||||
|
||||
#define KEYP_CTRL 0x148
|
||||
|
||||
#define KEYP_CTRL_EVNTS BIT(0)
|
||||
#define KEYP_CTRL_EVNTS_MASK 0x3
|
||||
|
||||
#define KEYP_CTRL_SCAN_COLS_SHIFT 5
|
||||
#define KEYP_CTRL_SCAN_COLS_MIN 5
|
||||
#define KEYP_CTRL_SCAN_COLS_BITS 0x3
|
||||
|
||||
#define KEYP_CTRL_SCAN_ROWS_SHIFT 2
|
||||
#define KEYP_CTRL_SCAN_ROWS_MIN 5
|
||||
#define KEYP_CTRL_SCAN_ROWS_BITS 0x7
|
||||
|
||||
#define KEYP_CTRL_KEYP_EN BIT(7)
|
||||
|
||||
#define KEYP_SCAN 0x149
|
||||
|
||||
#define KEYP_SCAN_READ_STATE BIT(0)
|
||||
#define KEYP_SCAN_DBOUNCE_SHIFT 1
|
||||
#define KEYP_SCAN_PAUSE_SHIFT 3
|
||||
#define KEYP_SCAN_ROW_HOLD_SHIFT 6
|
||||
|
||||
#define KEYP_TEST 0x14A
|
||||
|
||||
#define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6)
|
||||
#define KEYP_TEST_CLEAR_OLD_SCAN BIT(5)
|
||||
#define KEYP_TEST_READ_RESET BIT(4)
|
||||
#define KEYP_TEST_DTEST_EN BIT(3)
|
||||
#define KEYP_TEST_ABORT_READ BIT(0)
|
||||
|
||||
#define KEYP_TEST_DBG_SELECT_SHIFT 1
|
||||
|
||||
/* bits of these registers represent
|
||||
* '0' for key press
|
||||
* '1' for key release
|
||||
*/
|
||||
#define KEYP_RECENT_DATA 0x14B
|
||||
#define KEYP_OLD_DATA 0x14C
|
||||
|
||||
#define KEYP_CLOCK_FREQ 32768
|
||||
|
||||
/**
|
||||
* struct pmic8xxx_kp - internal keypad data structure
|
||||
* @pdata - keypad platform data pointer
|
||||
* @input - input device pointer for keypad
|
||||
* @key_sense_irq - key press/release irq number
|
||||
* @key_stuck_irq - key stuck notification irq number
|
||||
* @keycodes - array to hold the key codes
|
||||
* @dev - parent device pointer
|
||||
* @keystate - present key press/release state
|
||||
* @stuckstate - present state when key stuck irq
|
||||
* @ctrl_reg - control register value
|
||||
*/
|
||||
struct pmic8xxx_kp {
|
||||
const struct pm8xxx_keypad_platform_data *pdata;
|
||||
struct input_dev *input;
|
||||
int key_sense_irq;
|
||||
int key_stuck_irq;
|
||||
|
||||
unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];
|
||||
|
||||
struct device *dev;
|
||||
u16 keystate[PM8XXX_MAX_ROWS];
|
||||
u16 stuckstate[PM8XXX_MAX_ROWS];
|
||||
|
||||
u8 ctrl_reg;
|
||||
};
|
||||
|
||||
static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
|
||||
u8 data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_writeb(kp->dev->parent, reg, data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
|
||||
u8 *data, u16 reg, unsigned num_bytes)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
|
||||
u8 *data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, data, reg, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
|
||||
{
|
||||
/* all keys pressed on that particular row? */
|
||||
if (col == 0x00)
|
||||
return 1 << kp->pdata->num_cols;
|
||||
else
|
||||
return col & ((1 << kp->pdata->num_cols) - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronous read protocol for RevB0 onwards:
|
||||
*
|
||||
* 1. Write '1' to ReadState bit in KEYP_SCAN register
|
||||
* 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
|
||||
* synchronously
|
||||
* 3. Read rows in old array first if events are more than one
|
||||
* 4. Read rows in recent array
|
||||
* 5. Wait 4*32KHz clocks
|
||||
* 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
|
||||
* synchronously exit read mode.
|
||||
*/
|
||||
static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
u8 scan_val;
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
scan_val |= 0x1;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 2 * 32KHz clocks */
|
||||
udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
|
||||
u16 data_reg, int read_rows)
|
||||
{
|
||||
int rc, row;
|
||||
u8 new_data[PM8XXX_MAX_ROWS];
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
|
||||
new_data[row]);
|
||||
state[row] = pmic8xxx_col_state(kp, new_data[row]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
|
||||
u16 *old_state)
|
||||
{
|
||||
int rc, read_rows;
|
||||
u8 scan_val;
|
||||
|
||||
if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
|
||||
read_rows = PM8XXX_MIN_ROWS;
|
||||
else
|
||||
read_rows = kp->pdata->num_rows;
|
||||
|
||||
pmic8xxx_chk_sync_read(kp);
|
||||
|
||||
if (old_state) {
|
||||
rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA,
|
||||
read_rows);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev,
|
||||
"Error reading KEYP_OLD_DATA, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
|
||||
read_rows);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev,
|
||||
"Error reading KEYP_RECENT_DATA, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 4 * 32KHz clocks */
|
||||
udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
scan_val &= 0xFE;
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
|
||||
u16 *old_state)
|
||||
{
|
||||
int row, col, code;
|
||||
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
int bits_changed = new_state[row] ^ old_state[row];
|
||||
|
||||
if (!bits_changed)
|
||||
continue;
|
||||
|
||||
for (col = 0; col < kp->pdata->num_cols; col++) {
|
||||
if (!(bits_changed & (1 << col)))
|
||||
continue;
|
||||
|
||||
dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
|
||||
!(new_state[row] & (1 << col)) ?
|
||||
"pressed" : "released");
|
||||
|
||||
code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT);
|
||||
|
||||
input_event(kp->input, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(kp->input,
|
||||
kp->keycodes[code],
|
||||
!(new_state[row] & (1 << col)));
|
||||
|
||||
input_sync(kp->input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
|
||||
{
|
||||
int row, found_first = -1;
|
||||
u16 check, row_state;
|
||||
|
||||
check = 0;
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
row_state = (~new_state[row]) &
|
||||
((1 << kp->pdata->num_cols) - 1);
|
||||
|
||||
if (hweight16(row_state) > 1) {
|
||||
if (found_first == -1)
|
||||
found_first = row;
|
||||
if (check & row_state) {
|
||||
dev_dbg(kp->dev, "detected ghost key on row[%d]"
|
||||
" and row[%d]\n", found_first, row);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
check |= row_state;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events)
|
||||
{
|
||||
u16 new_state[PM8XXX_MAX_ROWS];
|
||||
u16 old_state[PM8XXX_MAX_ROWS];
|
||||
int rc;
|
||||
|
||||
switch (events) {
|
||||
case 0x1:
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* detecting ghost key is not an error */
|
||||
if (pmic8xxx_detect_ghost_keys(kp, new_state))
|
||||
return 0;
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
case 0x3: /* two events - eventcounter is gray-coded */
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
case 0x2:
|
||||
dev_dbg(kp->dev, "Some key events were lost\n");
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: We are reading recent and old data registers blindly
|
||||
* whenever key-stuck interrupt happens, because events counter doesn't
|
||||
* get updated when this interrupt happens due to key stuck doesn't get
|
||||
* considered as key state change.
|
||||
*
|
||||
* We are not using old data register contents after they are being read
|
||||
* because it might report the key which was pressed before the key being stuck
|
||||
* as stuck key because it's pressed status is stored in the old data
|
||||
* register.
|
||||
*/
|
||||
static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
|
||||
{
|
||||
u16 new_state[PM8XXX_MAX_ROWS];
|
||||
u16 old_state[PM8XXX_MAX_ROWS];
|
||||
int rc;
|
||||
struct pmic8xxx_kp *kp = data;
|
||||
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "failed to read keypad matrix\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = data;
|
||||
u8 ctrl_val, events;
|
||||
int rc;
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "failed to read keyp_ctrl register\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
|
||||
|
||||
rc = pmic8xxx_kp_scan_matrix(kp, events);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "failed to scan matrix\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int bits, rc, cycles;
|
||||
u8 scan_val = 0, ctrl_val = 0;
|
||||
static const u8 row_bits[] = {
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
|
||||
};
|
||||
|
||||
/* Find column bits */
|
||||
if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
|
||||
bits = 0;
|
||||
else
|
||||
bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
|
||||
ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
|
||||
KEYP_CTRL_SCAN_COLS_SHIFT;
|
||||
|
||||
/* Find row bits */
|
||||
if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
|
||||
bits = 0;
|
||||
else
|
||||
bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
|
||||
|
||||
ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bits = (kp->pdata->debounce_ms / 5) - 1;
|
||||
|
||||
scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
|
||||
|
||||
bits = fls(kp->pdata->scan_delay_ms) - 1;
|
||||
scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
|
||||
|
||||
/* Row hold time is a multiple of 32KHz cycles. */
|
||||
cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
|
||||
|
||||
scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc)
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
|
||||
struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
|
||||
{
|
||||
int rc, i;
|
||||
|
||||
if (gpio_start < 0 || num_gpios < 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num_gpios; i++) {
|
||||
rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
|
||||
if (rc) {
|
||||
dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
|
||||
"for PM GPIO [%d] rc=%d.\n",
|
||||
__func__, gpio_start + i, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_open(struct input_dev *dev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = input_get_drvdata(dev);
|
||||
|
||||
return pmic8xxx_kp_enable(kp);
|
||||
}
|
||||
|
||||
static void pmic8xxx_kp_close(struct input_dev *dev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = input_get_drvdata(dev);
|
||||
|
||||
pmic8xxx_kp_disable(kp);
|
||||
}
|
||||
|
||||
/*
|
||||
* keypad controller should be initialized in the following sequence
|
||||
* only, otherwise it might get into FSM stuck state.
|
||||
*
|
||||
* - Initialize keypad control parameters, like no. of rows, columns,
|
||||
* timing values etc.,
|
||||
* - configure rows and column gpios pull up/down.
|
||||
* - set irq edge type.
|
||||
* - enable the keypad controller.
|
||||
*/
|
||||
static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct pmic8xxx_kp *kp;
|
||||
int rc;
|
||||
u8 ctrl_val;
|
||||
|
||||
struct pm_gpio kypd_drv = {
|
||||
.direction = PM_GPIO_DIR_OUT,
|
||||
.output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
|
||||
.output_value = 0,
|
||||
.pull = PM_GPIO_PULL_NO,
|
||||
.vin_sel = PM_GPIO_VIN_S3,
|
||||
.out_strength = PM_GPIO_STRENGTH_LOW,
|
||||
.function = PM_GPIO_FUNC_1,
|
||||
.inv_int_pol = 1,
|
||||
};
|
||||
|
||||
struct pm_gpio kypd_sns = {
|
||||
.direction = PM_GPIO_DIR_IN,
|
||||
.pull = PM_GPIO_PULL_UP_31P5,
|
||||
.vin_sel = PM_GPIO_VIN_S3,
|
||||
.out_strength = PM_GPIO_STRENGTH_NO,
|
||||
.function = PM_GPIO_FUNC_NORMAL,
|
||||
.inv_int_pol = 1,
|
||||
};
|
||||
|
||||
|
||||
if (!pdata || !pdata->num_cols || !pdata->num_rows ||
|
||||
pdata->num_cols > PM8XXX_MAX_COLS ||
|
||||
pdata->num_rows > PM8XXX_MAX_ROWS ||
|
||||
pdata->num_cols < PM8XXX_MIN_COLS) {
|
||||
dev_err(&pdev->dev, "invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->scan_delay_ms ||
|
||||
pdata->scan_delay_ms > MAX_SCAN_DELAY ||
|
||||
pdata->scan_delay_ms < MIN_SCAN_DELAY ||
|
||||
!is_power_of_2(pdata->scan_delay_ms)) {
|
||||
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->row_hold_ns ||
|
||||
pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
|
||||
pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
|
||||
((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
|
||||
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->debounce_ms ||
|
||||
((pdata->debounce_ms % 5) != 0) ||
|
||||
pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
|
||||
pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
|
||||
dev_err(&pdev->dev, "invalid debounce time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keymap_data = pdata->keymap_data;
|
||||
if (!keymap_data) {
|
||||
dev_err(&pdev->dev, "no keymap data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
|
||||
if (!kp)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
|
||||
kp->pdata = pdata;
|
||||
kp->dev = &pdev->dev;
|
||||
|
||||
kp->input = input_allocate_device();
|
||||
if (!kp->input) {
|
||||
dev_err(&pdev->dev, "unable to allocate input device\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_device;
|
||||
}
|
||||
|
||||
kp->key_sense_irq = platform_get_irq(pdev, 0);
|
||||
if (kp->key_sense_irq < 0) {
|
||||
dev_err(&pdev->dev, "unable to get keypad sense irq\n");
|
||||
rc = -ENXIO;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
kp->key_stuck_irq = platform_get_irq(pdev, 1);
|
||||
if (kp->key_stuck_irq < 0) {
|
||||
dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
|
||||
rc = -ENXIO;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
|
||||
kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
|
||||
|
||||
kp->input->dev.parent = &pdev->dev;
|
||||
|
||||
kp->input->id.bustype = BUS_I2C;
|
||||
kp->input->id.version = 0x0001;
|
||||
kp->input->id.product = 0x0001;
|
||||
kp->input->id.vendor = 0x0001;
|
||||
|
||||
kp->input->evbit[0] = BIT_MASK(EV_KEY);
|
||||
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, kp->input->evbit);
|
||||
|
||||
kp->input->keycode = kp->keycodes;
|
||||
kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE;
|
||||
kp->input->keycodesize = sizeof(kp->keycodes);
|
||||
kp->input->open = pmic8xxx_kp_open;
|
||||
kp->input->close = pmic8xxx_kp_close;
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
|
||||
kp->input->keycode, kp->input->keybit);
|
||||
|
||||
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(kp->input, kp);
|
||||
|
||||
/* initialize keypad state */
|
||||
memset(kp->keystate, 0xff, sizeof(kp->keystate));
|
||||
memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
|
||||
|
||||
rc = pmic8xxx_kpd_init(kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to initialize keypad controller\n");
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
|
||||
pdata->num_cols, kp, &kypd_sns);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
|
||||
goto err_gpio_config;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
|
||||
pdata->num_rows, kp, &kypd_drv);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
|
||||
goto err_gpio_config;
|
||||
}
|
||||
|
||||
rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic-keypad", kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to request keypad sense irq\n");
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
|
||||
goto err_req_stuck_irq;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
|
||||
goto err_pmic_reg_read;
|
||||
}
|
||||
|
||||
kp->ctrl_reg = ctrl_val;
|
||||
|
||||
rc = input_register_device(kp->input);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to register keypad input device\n");
|
||||
goto err_pmic_reg_read;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pmic_reg_read:
|
||||
free_irq(kp->key_stuck_irq, kp);
|
||||
err_req_stuck_irq:
|
||||
free_irq(kp->key_sense_irq, kp);
|
||||
err_gpio_config:
|
||||
err_get_irq:
|
||||
input_free_device(kp->input);
|
||||
err_alloc_device:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(kp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
free_irq(kp->key_stuck_irq, kp);
|
||||
free_irq(kp->key_sense_irq, kp);
|
||||
input_unregister_device(kp->input);
|
||||
kfree(kp);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pmic8xxx_kp_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kp->input;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
enable_irq_wake(kp->key_sense_irq);
|
||||
} else {
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
pmic8xxx_kp_disable(kp);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kp->input;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
disable_irq_wake(kp->key_sense_irq);
|
||||
} else {
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
pmic8xxx_kp_enable(kp);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
|
||||
pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
|
||||
|
||||
static struct platform_driver pmic8xxx_kp_driver = {
|
||||
.probe = pmic8xxx_kp_probe,
|
||||
.remove = __devexit_p(pmic8xxx_kp_remove),
|
||||
.driver = {
|
||||
.name = PM8XXX_KEYPAD_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_kp_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmic8xxx_kp_init(void)
|
||||
{
|
||||
return platform_driver_register(&pmic8xxx_kp_driver);
|
||||
}
|
||||
module_init(pmic8xxx_kp_init);
|
||||
|
||||
static void __exit pmic8xxx_kp_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pmic8xxx_kp_driver);
|
||||
}
|
||||
module_exit(pmic8xxx_kp_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("PMIC8XXX keypad driver");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_ALIAS("platform:pmic8xxx_keypad");
|
||||
MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
|
||||
|
|
@ -239,8 +239,6 @@ static int __devexit qt1070_remove(struct i2c_client *client)
|
|||
input_unregister_device(data->input);
|
||||
kfree(data);
|
||||
|
||||
i2c_set_clientdata(client, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -657,7 +657,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
|||
|
||||
input_set_drvdata(input_dev, kbc);
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
input_dev->keycode = kbc->keycode;
|
||||
|
|
|
|||
|
|
@ -337,5 +337,5 @@ module_exit(keypad_exit);
|
|||
|
||||
MODULE_AUTHOR("Cyril Chemparathy");
|
||||
MODULE_DESCRIPTION("TNETV107X Keypad Driver");
|
||||
MODULE_ALIAS("platform: tnetv107x-keypad");
|
||||
MODULE_ALIAS("platform:tnetv107x-keypad");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -100,6 +100,27 @@ config INPUT_MAX8925_ONKEY
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called max8925_onkey.
|
||||
|
||||
config INPUT_MMA8450
|
||||
tristate "MMA8450 - Freescale's 3-Axis, 8/12-bit Digital Accelerometer"
|
||||
depends on I2C
|
||||
select INPUT_POLLDEV
|
||||
help
|
||||
Say Y here if you want to support Freescale's MMA8450 Accelerometer
|
||||
through I2C interface.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mma8450.
|
||||
|
||||
config INPUT_MPU3050
|
||||
tristate "MPU3050 Triaxial gyroscope sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to support InvenSense MPU3050
|
||||
connected via an I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mpu3050.
|
||||
|
||||
config INPUT_APANEL
|
||||
tristate "Fujitsu Lifebook Application Panel buttons"
|
||||
depends on X86 && I2C && LEDS_CLASS
|
||||
|
|
@ -209,6 +230,23 @@ config INPUT_KEYSPAN_REMOTE
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called keyspan_remote.
|
||||
|
||||
config INPUT_KXTJ9
|
||||
tristate "Kionix KXTJ9 tri-axis digital accelerometer"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to enable support for the Kionix KXTJ9 digital tri-axis
|
||||
accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called kxtj9.
|
||||
|
||||
config INPUT_KXTJ9_POLLED_MODE
|
||||
bool "Enable polling mode support"
|
||||
depends on INPUT_KXTJ9
|
||||
select INPUT_POLLDEV
|
||||
help
|
||||
Say Y here if you need accelerometer to work in polling mode.
|
||||
|
||||
config INPUT_POWERMATE
|
||||
tristate "Griffin PowerMate and Contour Jog support"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
|
|
@ -330,6 +368,17 @@ config INPUT_PWM_BEEPER
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called pwm-beeper.
|
||||
|
||||
config INPUT_PMIC8XXX_PWRKEY
|
||||
tristate "PMIC8XXX power key support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want support for the PMIC8XXX power key.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pmic8xxx-pwrkey.
|
||||
|
||||
config INPUT_GPIO_ROTARY_ENCODER
|
||||
tristate "Rotary encoders connected to GPIO pins"
|
||||
depends on GPIOLIB && GENERIC_GPIO
|
||||
|
|
|
|||
|
|
@ -25,14 +25,18 @@ obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
|
|||
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
||||
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
|
||||
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
||||
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
||||
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
||||
obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o
|
||||
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
||||
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
||||
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
|
||||
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
|
||||
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
|
||||
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
|
||||
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
|
||||
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
|
|
@ -44,4 +48,3 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
|
|||
obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
|
||||
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
|
||||
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
|||
671
drivers/input/misc/kxtj9.c
Normal file
671
drivers/input/misc/kxtj9.c
Normal file
|
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Kionix, Inc.
|
||||
* Written by Chris Hudson <chudson@kionix.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input/kxtj9.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
#define NAME "kxtj9"
|
||||
#define G_MAX 8000
|
||||
/* OUTPUT REGISTERS */
|
||||
#define XOUT_L 0x06
|
||||
#define WHO_AM_I 0x0F
|
||||
/* CONTROL REGISTERS */
|
||||
#define INT_REL 0x1A
|
||||
#define CTRL_REG1 0x1B
|
||||
#define INT_CTRL1 0x1E
|
||||
#define DATA_CTRL 0x21
|
||||
/* CONTROL REGISTER 1 BITS */
|
||||
#define PC1_OFF 0x7F
|
||||
#define PC1_ON (1 << 7)
|
||||
/* Data ready funtion enable bit: set during probe if using irq mode */
|
||||
#define DRDYE (1 << 5)
|
||||
/* INTERRUPT CONTROL REGISTER 1 BITS */
|
||||
/* Set these during probe if using irq mode */
|
||||
#define KXTJ9_IEL (1 << 3)
|
||||
#define KXTJ9_IEA (1 << 4)
|
||||
#define KXTJ9_IEN (1 << 5)
|
||||
/* INPUT_ABS CONSTANTS */
|
||||
#define FUZZ 3
|
||||
#define FLAT 3
|
||||
/* RESUME STATE INDICES */
|
||||
#define RES_DATA_CTRL 0
|
||||
#define RES_CTRL_REG1 1
|
||||
#define RES_INT_CTRL1 2
|
||||
#define RESUME_ENTRIES 3
|
||||
|
||||
/*
|
||||
* The following table lists the maximum appropriate poll interval for each
|
||||
* available output data rate.
|
||||
*/
|
||||
static const struct {
|
||||
unsigned int cutoff;
|
||||
u8 mask;
|
||||
} kxtj9_odr_table[] = {
|
||||
{ 3, ODR800F },
|
||||
{ 5, ODR400F },
|
||||
{ 10, ODR200F },
|
||||
{ 20, ODR100F },
|
||||
{ 40, ODR50F },
|
||||
{ 80, ODR25F },
|
||||
{ 0, ODR12_5F},
|
||||
};
|
||||
|
||||
struct kxtj9_data {
|
||||
struct i2c_client *client;
|
||||
struct kxtj9_platform_data pdata;
|
||||
struct input_dev *input_dev;
|
||||
#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
|
||||
struct input_polled_dev *poll_dev;
|
||||
#endif
|
||||
unsigned int last_poll_interval;
|
||||
u8 shift;
|
||||
u8 ctrl_reg1;
|
||||
u8 data_ctrl;
|
||||
u8 int_ctrl;
|
||||
};
|
||||
|
||||
static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len)
|
||||
{
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = tj9->client->addr,
|
||||
.flags = tj9->client->flags,
|
||||
.len = 1,
|
||||
.buf = &addr,
|
||||
},
|
||||
{
|
||||
.addr = tj9->client->addr,
|
||||
.flags = tj9->client->flags | I2C_M_RD,
|
||||
.len = len,
|
||||
.buf = data,
|
||||
},
|
||||
};
|
||||
|
||||
return i2c_transfer(tj9->client->adapter, msgs, 2);
|
||||
}
|
||||
|
||||
static void kxtj9_report_acceleration_data(struct kxtj9_data *tj9)
|
||||
{
|
||||
s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */
|
||||
s16 x, y, z;
|
||||
int err;
|
||||
|
||||
err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6);
|
||||
if (err < 0)
|
||||
dev_err(&tj9->client->dev, "accelerometer data read failed\n");
|
||||
|
||||
x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]) >> tj9->shift;
|
||||
y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]) >> tj9->shift;
|
||||
z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]) >> tj9->shift;
|
||||
|
||||
input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
|
||||
input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
|
||||
input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z);
|
||||
input_sync(tj9->input_dev);
|
||||
}
|
||||
|
||||
static irqreturn_t kxtj9_isr(int irq, void *dev)
|
||||
{
|
||||
struct kxtj9_data *tj9 = dev;
|
||||
int err;
|
||||
|
||||
/* data ready is the only possible interrupt type */
|
||||
kxtj9_report_acceleration_data(tj9);
|
||||
|
||||
err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
|
||||
if (err < 0)
|
||||
dev_err(&tj9->client->dev,
|
||||
"error clearing interrupt status: %d\n", err);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range)
|
||||
{
|
||||
switch (new_g_range) {
|
||||
case KXTJ9_G_2G:
|
||||
tj9->shift = 4;
|
||||
break;
|
||||
case KXTJ9_G_4G:
|
||||
tj9->shift = 3;
|
||||
break;
|
||||
case KXTJ9_G_8G:
|
||||
tj9->shift = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tj9->ctrl_reg1 &= 0xe7;
|
||||
tj9->ctrl_reg1 |= new_g_range;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
|
||||
/* Use the lowest ODR that can support the requested poll interval */
|
||||
for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) {
|
||||
tj9->data_ctrl = kxtj9_odr_table[i].mask;
|
||||
if (poll_interval < kxtj9_odr_table[i].cutoff)
|
||||
break;
|
||||
}
|
||||
|
||||
err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxtj9_device_power_on(struct kxtj9_data *tj9)
|
||||
{
|
||||
if (tj9->pdata.power_on)
|
||||
return tj9->pdata.power_on();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kxtj9_device_power_off(struct kxtj9_data *tj9)
|
||||
{
|
||||
int err;
|
||||
|
||||
tj9->ctrl_reg1 &= PC1_OFF;
|
||||
err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
|
||||
if (err < 0)
|
||||
dev_err(&tj9->client->dev, "soft power off failed\n");
|
||||
|
||||
if (tj9->pdata.power_off)
|
||||
tj9->pdata.power_off();
|
||||
}
|
||||
|
||||
static int kxtj9_enable(struct kxtj9_data *tj9)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = kxtj9_device_power_on(tj9);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* ensure that PC1 is cleared before updating control registers */
|
||||
err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* only write INT_CTRL_REG1 if in irq mode */
|
||||
if (tj9->client->irq) {
|
||||
err = i2c_smbus_write_byte_data(tj9->client,
|
||||
INT_CTRL1, tj9->int_ctrl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = kxtj9_update_g_range(tj9, tj9->pdata.g_range);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* turn on outputs */
|
||||
tj9->ctrl_reg1 |= PC1_ON;
|
||||
err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = kxtj9_update_odr(tj9, tj9->last_poll_interval);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* clear initial interrupt if in irq mode */
|
||||
if (tj9->client->irq) {
|
||||
err = i2c_smbus_read_byte_data(tj9->client, INT_REL);
|
||||
if (err < 0) {
|
||||
dev_err(&tj9->client->dev,
|
||||
"error clearing interrupt: %d\n", err);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
kxtj9_device_power_off(tj9);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void kxtj9_disable(struct kxtj9_data *tj9)
|
||||
{
|
||||
kxtj9_device_power_off(tj9);
|
||||
}
|
||||
|
||||
static int kxtj9_input_open(struct input_dev *input)
|
||||
{
|
||||
struct kxtj9_data *tj9 = input_get_drvdata(input);
|
||||
|
||||
return kxtj9_enable(tj9);
|
||||
}
|
||||
|
||||
static void kxtj9_input_close(struct input_dev *dev)
|
||||
{
|
||||
struct kxtj9_data *tj9 = input_get_drvdata(dev);
|
||||
|
||||
kxtj9_disable(tj9);
|
||||
}
|
||||
|
||||
static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9,
|
||||
struct input_dev *input_dev)
|
||||
{
|
||||
__set_bit(EV_ABS, input_dev->evbit);
|
||||
input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT);
|
||||
input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT);
|
||||
input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT);
|
||||
|
||||
input_dev->name = "kxtj9_accel";
|
||||
input_dev->id.bustype = BUS_I2C;
|
||||
input_dev->dev.parent = &tj9->client->dev;
|
||||
}
|
||||
|
||||
static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
dev_err(&tj9->client->dev, "input device allocate failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tj9->input_dev = input_dev;
|
||||
|
||||
input_dev->open = kxtj9_input_open;
|
||||
input_dev->close = kxtj9_input_close;
|
||||
input_set_drvdata(input_dev, tj9);
|
||||
|
||||
kxtj9_init_input_device(tj9, input_dev);
|
||||
|
||||
err = input_register_device(tj9->input_dev);
|
||||
if (err) {
|
||||
dev_err(&tj9->client->dev,
|
||||
"unable to register input polled device %s: %d\n",
|
||||
tj9->input_dev->name, err);
|
||||
input_free_device(tj9->input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When IRQ mode is selected, we need to provide an interface to allow the user
|
||||
* to change the output data rate of the part. For consistency, we are using
|
||||
* the set_poll method, which accepts a poll interval in milliseconds, and then
|
||||
* calls update_odr() while passing this value as an argument. In IRQ mode, the
|
||||
* data outputs will not be read AT the requested poll interval, rather, the
|
||||
* lowest ODR that can support the requested interval. The client application
|
||||
* will be responsible for retrieving data from the input node at the desired
|
||||
* interval.
|
||||
*/
|
||||
|
||||
/* Returns currently selected poll interval (in ms) */
|
||||
static ssize_t kxtj9_get_poll(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
|
||||
|
||||
return sprintf(buf, "%d\n", tj9->last_poll_interval);
|
||||
}
|
||||
|
||||
/* Allow users to select a new poll interval (in ms) */
|
||||
static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
|
||||
struct input_dev *input_dev = tj9->input_dev;
|
||||
unsigned int interval;
|
||||
int error;
|
||||
|
||||
error = kstrtouint(buf, 10, &interval);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
/* Lock the device to prevent races with open/close (and itself) */
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
disable_irq(client->irq);
|
||||
|
||||
/*
|
||||
* Set current interval to the greater of the minimum interval or
|
||||
* the requested interval
|
||||
*/
|
||||
tj9->last_poll_interval = max(interval, tj9->pdata.min_interval);
|
||||
|
||||
kxtj9_update_odr(tj9, tj9->last_poll_interval);
|
||||
|
||||
enable_irq(client->irq);
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll);
|
||||
|
||||
static struct attribute *kxtj9_attributes[] = {
|
||||
&dev_attr_poll.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group kxtj9_attribute_group = {
|
||||
.attrs = kxtj9_attributes
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE
|
||||
static void kxtj9_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct kxtj9_data *tj9 = dev->private;
|
||||
unsigned int poll_interval = dev->poll_interval;
|
||||
|
||||
kxtj9_report_acceleration_data(tj9);
|
||||
|
||||
if (poll_interval != tj9->last_poll_interval) {
|
||||
kxtj9_update_odr(tj9, poll_interval);
|
||||
tj9->last_poll_interval = poll_interval;
|
||||
}
|
||||
}
|
||||
|
||||
static void kxtj9_polled_input_open(struct input_polled_dev *dev)
|
||||
{
|
||||
struct kxtj9_data *tj9 = dev->private;
|
||||
|
||||
kxtj9_enable(tj9);
|
||||
}
|
||||
|
||||
static void kxtj9_polled_input_close(struct input_polled_dev *dev)
|
||||
{
|
||||
struct kxtj9_data *tj9 = dev->private;
|
||||
|
||||
kxtj9_disable(tj9);
|
||||
}
|
||||
|
||||
static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9)
|
||||
{
|
||||
int err;
|
||||
struct input_polled_dev *poll_dev;
|
||||
poll_dev = input_allocate_polled_device();
|
||||
|
||||
if (!poll_dev) {
|
||||
dev_err(&tj9->client->dev,
|
||||
"Failed to allocate polled device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tj9->poll_dev = poll_dev;
|
||||
tj9->input_dev = poll_dev->input;
|
||||
|
||||
poll_dev->private = tj9;
|
||||
poll_dev->poll = kxtj9_poll;
|
||||
poll_dev->open = kxtj9_polled_input_open;
|
||||
poll_dev->close = kxtj9_polled_input_close;
|
||||
|
||||
kxtj9_init_input_device(tj9, poll_dev->input);
|
||||
|
||||
err = input_register_polled_device(poll_dev);
|
||||
if (err) {
|
||||
dev_err(&tj9->client->dev,
|
||||
"Unable to register polled device, err=%d\n", err);
|
||||
input_free_polled_device(poll_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
|
||||
{
|
||||
input_unregister_polled_device(tj9->poll_dev);
|
||||
input_free_polled_device(tj9->poll_dev);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int __devinit kxtj9_verify(struct kxtj9_data *tj9)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = kxtj9_device_power_on(tj9);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);
|
||||
if (retval < 0) {
|
||||
dev_err(&tj9->client->dev, "read err int source\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
retval = retval != 0x06 ? -EIO : 0;
|
||||
|
||||
out:
|
||||
kxtj9_device_power_off(tj9);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int __devinit kxtj9_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct kxtj9_platform_data *pdata = client->dev.platform_data;
|
||||
struct kxtj9_data *tj9;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_err(&client->dev, "client is not i2c capable\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "platform data is NULL; exiting\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL);
|
||||
if (!tj9) {
|
||||
dev_err(&client->dev,
|
||||
"failed to allocate memory for module data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tj9->client = client;
|
||||
tj9->pdata = *pdata;
|
||||
|
||||
if (pdata->init) {
|
||||
err = pdata->init();
|
||||
if (err < 0)
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
err = kxtj9_verify(tj9);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "device not recognized\n");
|
||||
goto err_pdata_exit;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, tj9);
|
||||
|
||||
tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
|
||||
tj9->data_ctrl = tj9->pdata.data_odr_init;
|
||||
|
||||
if (client->irq) {
|
||||
/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
|
||||
tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
|
||||
tj9->ctrl_reg1 |= DRDYE;
|
||||
|
||||
err = kxtj9_setup_input_device(tj9);
|
||||
if (err)
|
||||
goto err_pdata_exit;
|
||||
|
||||
err = request_threaded_irq(client->irq, NULL, kxtj9_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"kxtj9-irq", tj9);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "request irq failed: %d\n", err);
|
||||
goto err_destroy_input;
|
||||
}
|
||||
|
||||
err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "sysfs create failed: %d\n", err);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
} else {
|
||||
err = kxtj9_setup_polled_device(tj9);
|
||||
if (err)
|
||||
goto err_pdata_exit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, tj9);
|
||||
err_destroy_input:
|
||||
input_unregister_device(tj9->input_dev);
|
||||
err_pdata_exit:
|
||||
if (tj9->pdata.exit)
|
||||
tj9->pdata.exit();
|
||||
err_free_mem:
|
||||
kfree(tj9);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit kxtj9_remove(struct i2c_client *client)
|
||||
{
|
||||
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
|
||||
|
||||
if (client->irq) {
|
||||
sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group);
|
||||
free_irq(client->irq, tj9);
|
||||
input_unregister_device(tj9->input_dev);
|
||||
} else {
|
||||
kxtj9_teardown_polled_device(tj9);
|
||||
}
|
||||
|
||||
if (tj9->pdata.exit)
|
||||
tj9->pdata.exit();
|
||||
|
||||
kfree(tj9);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int kxtj9_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
|
||||
struct input_dev *input_dev = tj9->input_dev;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
kxtj9_disable(tj9);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxtj9_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
|
||||
struct input_dev *input_dev = tj9->input_dev;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
kxtj9_enable(tj9);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
|
||||
|
||||
static const struct i2c_device_id kxtj9_id[] = {
|
||||
{ NAME, 0 },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, kxtj9_id);
|
||||
|
||||
static struct i2c_driver kxtj9_driver = {
|
||||
.driver = {
|
||||
.name = NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &kxtj9_pm_ops,
|
||||
},
|
||||
.probe = kxtj9_probe,
|
||||
.remove = __devexit_p(kxtj9_remove),
|
||||
.id_table = kxtj9_id,
|
||||
};
|
||||
|
||||
static int __init kxtj9_init(void)
|
||||
{
|
||||
return i2c_add_driver(&kxtj9_driver);
|
||||
}
|
||||
module_init(kxtj9_init);
|
||||
|
||||
static void __exit kxtj9_exit(void)
|
||||
{
|
||||
i2c_del_driver(&kxtj9_driver);
|
||||
}
|
||||
module_exit(kxtj9_exit);
|
||||
|
||||
MODULE_DESCRIPTION("KXTJ9 accelerometer driver");
|
||||
MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
256
drivers/input/misc/mma8450.c
Normal file
256
drivers/input/misc/mma8450.c
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Driver for Freescale's 3-Axis Accelerometer MMA8450
|
||||
*
|
||||
* Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
#define MMA8450_DRV_NAME "mma8450"
|
||||
|
||||
#define MODE_CHANGE_DELAY_MS 100
|
||||
#define POLL_INTERVAL 100
|
||||
#define POLL_INTERVAL_MAX 500
|
||||
|
||||
/* register definitions */
|
||||
#define MMA8450_STATUS 0x00
|
||||
#define MMA8450_STATUS_ZXYDR 0x08
|
||||
|
||||
#define MMA8450_OUT_X8 0x01
|
||||
#define MMA8450_OUT_Y8 0x02
|
||||
#define MMA8450_OUT_Z8 0x03
|
||||
|
||||
#define MMA8450_OUT_X_LSB 0x05
|
||||
#define MMA8450_OUT_X_MSB 0x06
|
||||
#define MMA8450_OUT_Y_LSB 0x07
|
||||
#define MMA8450_OUT_Y_MSB 0x08
|
||||
#define MMA8450_OUT_Z_LSB 0x09
|
||||
#define MMA8450_OUT_Z_MSB 0x0a
|
||||
|
||||
#define MMA8450_XYZ_DATA_CFG 0x16
|
||||
|
||||
#define MMA8450_CTRL_REG1 0x38
|
||||
#define MMA8450_CTRL_REG2 0x39
|
||||
|
||||
/* mma8450 status */
|
||||
struct mma8450 {
|
||||
struct i2c_client *client;
|
||||
struct input_polled_dev *idev;
|
||||
};
|
||||
|
||||
static int mma8450_read(struct mma8450 *m, unsigned off)
|
||||
{
|
||||
struct i2c_client *c = m->client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(c, off);
|
||||
if (ret < 0)
|
||||
dev_err(&c->dev,
|
||||
"failed to read register 0x%02x, error %d\n",
|
||||
off, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mma8450_write(struct mma8450 *m, unsigned off, u8 v)
|
||||
{
|
||||
struct i2c_client *c = m->client;
|
||||
int error;
|
||||
|
||||
error = i2c_smbus_write_byte_data(c, off, v);
|
||||
if (error < 0) {
|
||||
dev_err(&c->dev,
|
||||
"failed to write to register 0x%02x, error %d\n",
|
||||
off, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z)
|
||||
{
|
||||
struct i2c_client *c = m->client;
|
||||
u8 buff[6];
|
||||
int err;
|
||||
|
||||
err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff);
|
||||
if (err < 0) {
|
||||
dev_err(&c->dev,
|
||||
"failed to read block data at 0x%02x, error %d\n",
|
||||
MMA8450_OUT_X_LSB, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
*x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf);
|
||||
*y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf);
|
||||
*z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mma8450_poll(struct input_polled_dev *dev)
|
||||
{
|
||||
struct mma8450 *m = dev->private;
|
||||
int x, y, z;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
ret = mma8450_read(m, MMA8450_STATUS);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (!(ret & MMA8450_STATUS_ZXYDR))
|
||||
return;
|
||||
|
||||
err = mma8450_read_xyz(m, &x, &y, &z);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
input_report_abs(dev->input, ABS_X, x);
|
||||
input_report_abs(dev->input, ABS_Y, y);
|
||||
input_report_abs(dev->input, ABS_Z, z);
|
||||
input_sync(dev->input);
|
||||
}
|
||||
|
||||
/* Initialize the MMA8450 chip */
|
||||
static void mma8450_open(struct input_polled_dev *dev)
|
||||
{
|
||||
struct mma8450 *m = dev->private;
|
||||
int err;
|
||||
|
||||
/* enable all events from X/Y/Z, no FIFO */
|
||||
err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Sleep mode poll rate - 50Hz
|
||||
* System output data rate - 400Hz
|
||||
* Full scale selection - Active, +/- 2G
|
||||
*/
|
||||
err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
msleep(MODE_CHANGE_DELAY_MS);
|
||||
}
|
||||
|
||||
static void mma8450_close(struct input_polled_dev *dev)
|
||||
{
|
||||
struct mma8450 *m = dev->private;
|
||||
|
||||
mma8450_write(m, MMA8450_CTRL_REG1, 0x00);
|
||||
mma8450_write(m, MMA8450_CTRL_REG2, 0x01);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C init/probing/exit functions
|
||||
*/
|
||||
static int __devinit mma8450_probe(struct i2c_client *c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct input_polled_dev *idev;
|
||||
struct mma8450 *m;
|
||||
int err;
|
||||
|
||||
m = kzalloc(sizeof(struct mma8450), GFP_KERNEL);
|
||||
idev = input_allocate_polled_device();
|
||||
if (!m || !idev) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
m->client = c;
|
||||
m->idev = idev;
|
||||
|
||||
idev->private = m;
|
||||
idev->input->name = MMA8450_DRV_NAME;
|
||||
idev->input->id.bustype = BUS_I2C;
|
||||
idev->poll = mma8450_poll;
|
||||
idev->poll_interval = POLL_INTERVAL;
|
||||
idev->poll_interval_max = POLL_INTERVAL_MAX;
|
||||
idev->open = mma8450_open;
|
||||
idev->close = mma8450_close;
|
||||
|
||||
__set_bit(EV_ABS, idev->input->evbit);
|
||||
input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32);
|
||||
input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32);
|
||||
input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32);
|
||||
|
||||
err = input_register_polled_device(idev);
|
||||
if (err) {
|
||||
dev_err(&c->dev, "failed to register polled input device\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_mem:
|
||||
input_free_polled_device(idev);
|
||||
kfree(m);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit mma8450_remove(struct i2c_client *c)
|
||||
{
|
||||
struct mma8450 *m = i2c_get_clientdata(c);
|
||||
struct input_polled_dev *idev = m->idev;
|
||||
|
||||
input_unregister_polled_device(idev);
|
||||
input_free_polled_device(idev);
|
||||
kfree(m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mma8450_id[] = {
|
||||
{ MMA8450_DRV_NAME, 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma8450_id);
|
||||
|
||||
static struct i2c_driver mma8450_driver = {
|
||||
.driver = {
|
||||
.name = MMA8450_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mma8450_probe,
|
||||
.remove = __devexit_p(mma8450_remove),
|
||||
.id_table = mma8450_id,
|
||||
};
|
||||
|
||||
static int __init mma8450_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mma8450_driver);
|
||||
}
|
||||
module_init(mma8450_init);
|
||||
|
||||
static void __exit mma8450_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mma8450_driver);
|
||||
}
|
||||
module_exit(mma8450_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
376
drivers/input/misc/mpu3050.c
Normal file
376
drivers/input/misc/mpu3050.c
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
* MPU3050 Tri-axis gyroscope driver
|
||||
*
|
||||
* Copyright (C) 2011 Wistron Co.Ltd
|
||||
* Joseph Lai <joseph_lai@wistron.com>
|
||||
*
|
||||
* Trimmed down by Alan Cox <alan@linux.intel.com> to produce this version
|
||||
*
|
||||
* This is a 'lite' version of the driver, while we consider the right way
|
||||
* to present the other features to user space. In particular it requires the
|
||||
* device has an IRQ, and it only provides an input interface, so is not much
|
||||
* use for device orientation. A fuller version is available from the Meego
|
||||
* tree.
|
||||
*
|
||||
* This program is based on bma023.c.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define MPU3050_CHIP_ID_REG 0x00
|
||||
#define MPU3050_CHIP_ID 0x69
|
||||
#define MPU3050_XOUT_H 0x1D
|
||||
#define MPU3050_PWR_MGM 0x3E
|
||||
#define MPU3050_PWR_MGM_POS 6
|
||||
#define MPU3050_PWR_MGM_MASK 0x40
|
||||
|
||||
#define MPU3050_AUTO_DELAY 1000
|
||||
|
||||
#define MPU3050_MIN_VALUE -32768
|
||||
#define MPU3050_MAX_VALUE 32767
|
||||
|
||||
struct axis_data {
|
||||
s16 x;
|
||||
s16 y;
|
||||
s16 z;
|
||||
};
|
||||
|
||||
struct mpu3050_sensor {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct input_dev *idev;
|
||||
};
|
||||
|
||||
/**
|
||||
* mpu3050_xyz_read_reg - read the axes values
|
||||
* @buffer: provide register addr and get register
|
||||
* @length: length of register
|
||||
*
|
||||
* Reads the register values in one transaction or returns a negative
|
||||
* error code on failure.
|
||||
*/
|
||||
static int mpu3050_xyz_read_reg(struct i2c_client *client,
|
||||
u8 *buffer, int length)
|
||||
{
|
||||
/*
|
||||
* Annoying we can't make this const because the i2c layer doesn't
|
||||
* declare input buffers const.
|
||||
*/
|
||||
char cmd = MPU3050_XOUT_H;
|
||||
struct i2c_msg msg[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &cmd,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = length,
|
||||
.buf = buffer,
|
||||
},
|
||||
};
|
||||
|
||||
return i2c_transfer(client->adapter, msg, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_read_xyz - get co-ordinates from device
|
||||
* @client: i2c address of sensor
|
||||
* @coords: co-ordinates to update
|
||||
*
|
||||
* Return the converted X Y and Z co-ordinates from the sensor device
|
||||
*/
|
||||
static void mpu3050_read_xyz(struct i2c_client *client,
|
||||
struct axis_data *coords)
|
||||
{
|
||||
u16 buffer[3];
|
||||
|
||||
mpu3050_xyz_read_reg(client, (u8 *)buffer, 6);
|
||||
coords->x = be16_to_cpu(buffer[0]);
|
||||
coords->y = be16_to_cpu(buffer[1]);
|
||||
coords->z = be16_to_cpu(buffer[2]);
|
||||
dev_dbg(&client->dev, "%s: x %d, y %d, z %d\n", __func__,
|
||||
coords->x, coords->y, coords->z);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_set_power_mode - set the power mode
|
||||
* @client: i2c client for the sensor
|
||||
* @val: value to switch on/off of power, 1: normal power, 0: low power
|
||||
*
|
||||
* Put device to normal-power mode or low-power mode.
|
||||
*/
|
||||
static void mpu3050_set_power_mode(struct i2c_client *client, u8 val)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
|
||||
value = (value & ~MPU3050_PWR_MGM_MASK) |
|
||||
(((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
|
||||
MPU3050_PWR_MGM_MASK);
|
||||
i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_input_open - called on input event open
|
||||
* @input: input dev of opened device
|
||||
*
|
||||
* The input layer calls this function when input event is opened. The
|
||||
* function will push the device to resume. Then, the device is ready
|
||||
* to provide data.
|
||||
*/
|
||||
static int mpu3050_input_open(struct input_dev *input)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = input_get_drvdata(input);
|
||||
|
||||
pm_runtime_get(sensor->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_input_close - called on input event close
|
||||
* @input: input dev of closed device
|
||||
*
|
||||
* The input layer calls this function when input event is closed. The
|
||||
* function will push the device to suspend.
|
||||
*/
|
||||
static void mpu3050_input_close(struct input_dev *input)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = input_get_drvdata(input);
|
||||
|
||||
pm_runtime_put(sensor->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_interrupt_thread - handle an IRQ
|
||||
* @irq: interrupt numner
|
||||
* @data: the sensor
|
||||
*
|
||||
* Called by the kernel single threaded after an interrupt occurs. Read
|
||||
* the sensor data and generate an input event for it.
|
||||
*/
|
||||
static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = data;
|
||||
struct axis_data axis;
|
||||
|
||||
mpu3050_read_xyz(sensor->client, &axis);
|
||||
|
||||
input_report_abs(sensor->idev, ABS_X, axis.x);
|
||||
input_report_abs(sensor->idev, ABS_Y, axis.y);
|
||||
input_report_abs(sensor->idev, ABS_Z, axis.z);
|
||||
input_sync(sensor->idev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_probe - device detection callback
|
||||
* @client: i2c client of found device
|
||||
* @id: id match information
|
||||
*
|
||||
* The I2C layer calls us when it believes a sensor is present at this
|
||||
* address. Probe to see if this is correct and to validate the device.
|
||||
*
|
||||
* If present install the relevant sysfs interfaces and input device.
|
||||
*/
|
||||
static int __devinit mpu3050_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct mpu3050_sensor *sensor;
|
||||
struct input_dev *idev;
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
|
||||
idev = input_allocate_device();
|
||||
if (!sensor || !idev) {
|
||||
dev_err(&client->dev, "failed to allocate driver data\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
sensor->client = client;
|
||||
sensor->dev = &client->dev;
|
||||
sensor->idev = idev;
|
||||
|
||||
mpu3050_set_power_mode(client, 1);
|
||||
msleep(10);
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed to detect device\n");
|
||||
error = -ENXIO;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (ret != MPU3050_CHIP_ID) {
|
||||
dev_err(&client->dev, "unsupported chip id\n");
|
||||
error = -ENXIO;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
idev->name = "MPU3050";
|
||||
idev->id.bustype = BUS_I2C;
|
||||
idev->dev.parent = &client->dev;
|
||||
|
||||
idev->open = mpu3050_input_open;
|
||||
idev->close = mpu3050_input_close;
|
||||
|
||||
__set_bit(EV_ABS, idev->evbit);
|
||||
input_set_abs_params(idev, ABS_X,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Y,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
input_set_abs_params(idev, ABS_Z,
|
||||
MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
|
||||
|
||||
input_set_drvdata(idev, sensor);
|
||||
|
||||
pm_runtime_set_active(&client->dev);
|
||||
|
||||
error = request_threaded_irq(client->irq,
|
||||
NULL, mpu3050_interrupt_thread,
|
||||
IRQF_TRIGGER_RISING,
|
||||
"mpu_int", sensor);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"can't get IRQ %d, error %d\n", client->irq, error);
|
||||
goto err_pm_set_suspended;
|
||||
}
|
||||
|
||||
error = input_register_device(idev);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "failed to register input device\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(client->irq, sensor);
|
||||
err_pm_set_suspended:
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
err_free_mem:
|
||||
input_unregister_device(idev);
|
||||
kfree(sensor);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_remove - remove a sensor
|
||||
* @client: i2c client of sensor being removed
|
||||
*
|
||||
* Our sensor is going away, clean up the resources.
|
||||
*/
|
||||
static int __devexit mpu3050_remove(struct i2c_client *client)
|
||||
{
|
||||
struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
||||
free_irq(client->irq, sensor);
|
||||
input_unregister_device(sensor->idev);
|
||||
kfree(sensor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* mpu3050_suspend - called on device suspend
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Put the device into sleep mode before we suspend the machine.
|
||||
*/
|
||||
static int mpu3050_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
mpu3050_set_power_mode(client, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpu3050_resume - called on device resume
|
||||
* @dev: device being resumed
|
||||
*
|
||||
* Put the device into powered mode on resume.
|
||||
*/
|
||||
static int mpu3050_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
mpu3050_set_power_mode(client, 1);
|
||||
msleep(100); /* wait for gyro chip resume */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL);
|
||||
|
||||
static const struct i2c_device_id mpu3050_ids[] = {
|
||||
{ "mpu3050", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpu3050_ids);
|
||||
|
||||
static struct i2c_driver mpu3050_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "mpu3050",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &mpu3050_pm,
|
||||
},
|
||||
.probe = mpu3050_probe,
|
||||
.remove = __devexit_p(mpu3050_remove),
|
||||
.id_table = mpu3050_ids,
|
||||
};
|
||||
|
||||
static int __init mpu3050_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mpu3050_i2c_driver);
|
||||
}
|
||||
module_init(mpu3050_init);
|
||||
|
||||
static void __exit mpu3050_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mpu3050_i2c_driver);
|
||||
}
|
||||
module_exit(mpu3050_exit);
|
||||
|
||||
MODULE_AUTHOR("Wistron Corp.");
|
||||
MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
231
drivers/input/misc/pmic8xxx-pwrkey.c
Normal file
231
drivers/input/misc/pmic8xxx-pwrkey.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/input/pmic8xxx-pwrkey.h>
|
||||
|
||||
#define PON_CNTL_1 0x1C
|
||||
#define PON_CNTL_PULL_UP BIT(7)
|
||||
#define PON_CNTL_TRIG_DELAY_MASK (0x7)
|
||||
|
||||
/**
|
||||
* struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
|
||||
* @key_press_irq: key press irq number
|
||||
*/
|
||||
struct pmic8xxx_pwrkey {
|
||||
struct input_dev *pwr;
|
||||
int key_press_irq;
|
||||
};
|
||||
|
||||
static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
|
||||
|
||||
input_report_key(pwrkey->pwr, KEY_POWER, 1);
|
||||
input_sync(pwrkey->pwr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
|
||||
|
||||
input_report_key(pwrkey->pwr, KEY_POWER, 0);
|
||||
input_sync(pwrkey->pwr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pmic8xxx_pwrkey_suspend(struct device *dev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(pwrkey->key_press_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_pwrkey_resume(struct device *dev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(pwrkey->key_press_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
|
||||
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
|
||||
|
||||
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *pwr;
|
||||
int key_release_irq = platform_get_irq(pdev, 0);
|
||||
int key_press_irq = platform_get_irq(pdev, 1);
|
||||
int err;
|
||||
unsigned int delay;
|
||||
u8 pon_cntl;
|
||||
struct pmic8xxx_pwrkey *pwrkey;
|
||||
const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "power key platform data not supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->kpd_trigger_delay_us > 62500) {
|
||||
dev_err(&pdev->dev, "invalid power key trigger delay\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
|
||||
if (!pwrkey)
|
||||
return -ENOMEM;
|
||||
|
||||
pwr = input_allocate_device();
|
||||
if (!pwr) {
|
||||
dev_dbg(&pdev->dev, "Can't allocate power button\n");
|
||||
err = -ENOMEM;
|
||||
goto free_pwrkey;
|
||||
}
|
||||
|
||||
input_set_capability(pwr, EV_KEY, KEY_POWER);
|
||||
|
||||
pwr->name = "pmic8xxx_pwrkey";
|
||||
pwr->phys = "pmic8xxx_pwrkey/input0";
|
||||
pwr->dev.parent = &pdev->dev;
|
||||
|
||||
delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
|
||||
delay = 1 + ilog2(delay);
|
||||
|
||||
err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
|
||||
pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
|
||||
if (pdata->pull_up)
|
||||
pon_cntl |= PON_CNTL_PULL_UP;
|
||||
else
|
||||
pon_cntl &= ~PON_CNTL_PULL_UP;
|
||||
|
||||
err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
err = input_register_device(pwr);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
pwrkey->key_press_irq = key_press_irq;
|
||||
pwrkey->pwr = pwr;
|
||||
|
||||
platform_set_drvdata(pdev, pwrkey);
|
||||
|
||||
err = request_irq(key_press_irq, pwrkey_press_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
|
||||
if (err < 0) {
|
||||
dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
|
||||
key_press_irq, err);
|
||||
goto unreg_input_dev;
|
||||
}
|
||||
|
||||
err = request_irq(key_release_irq, pwrkey_release_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
|
||||
if (err < 0) {
|
||||
dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
|
||||
key_release_irq, err);
|
||||
|
||||
goto free_press_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
free_press_irq:
|
||||
free_irq(key_press_irq, NULL);
|
||||
unreg_input_dev:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_device(pwr);
|
||||
pwr = NULL;
|
||||
free_input_dev:
|
||||
input_free_device(pwr);
|
||||
free_pwrkey:
|
||||
kfree(pwrkey);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
|
||||
int key_release_irq = platform_get_irq(pdev, 0);
|
||||
int key_press_irq = platform_get_irq(pdev, 1);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
free_irq(key_press_irq, pwrkey);
|
||||
free_irq(key_release_irq, pwrkey);
|
||||
input_unregister_device(pwrkey->pwr);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(pwrkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pmic8xxx_pwrkey_driver = {
|
||||
.probe = pmic8xxx_pwrkey_probe,
|
||||
.remove = __devexit_p(pmic8xxx_pwrkey_remove),
|
||||
.driver = {
|
||||
.name = PM8XXX_PWRKEY_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_pwr_key_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmic8xxx_pwrkey_init(void)
|
||||
{
|
||||
return platform_driver_register(&pmic8xxx_pwrkey_driver);
|
||||
}
|
||||
module_init(pmic8xxx_pwrkey_init);
|
||||
|
||||
static void __exit pmic8xxx_pwrkey_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pmic8xxx_pwrkey_driver);
|
||||
}
|
||||
module_exit(pmic8xxx_pwrkey_exit);
|
||||
|
||||
MODULE_ALIAS("platform:pmic8xxx_pwrkey");
|
||||
MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
|
|||
|
||||
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
|
||||
struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
|
||||
struct vibra_info *info;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ static struct xenbus_driver xenkbd_driver = {
|
|||
|
||||
static int __init xenkbd_init(void)
|
||||
{
|
||||
if (!xen_pv_domain())
|
||||
if (!xen_domain())
|
||||
return -ENODEV;
|
||||
|
||||
/* Nothing to do if running in dom0. */
|
||||
|
|
|
|||
|
|
@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf)
|
|||
#endif
|
||||
|
||||
/* only relative events get here */
|
||||
dx = buf[1];
|
||||
dy = -buf[2];
|
||||
dx = buf[1];
|
||||
dy = buf[2];
|
||||
|
||||
input_report_rel(atamouse_dev, REL_X, dx);
|
||||
input_report_rel(atamouse_dev, REL_Y, dy);
|
||||
|
||||
input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1);
|
||||
input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x4);
|
||||
input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
|
||||
input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4);
|
||||
input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x1);
|
||||
|
||||
input_sync(atamouse_dev);
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev)
|
|||
static void atamouse_close(struct input_dev *dev)
|
||||
{
|
||||
ikbd_mouse_disable();
|
||||
atari_mouse_interrupt_hook = NULL;
|
||||
atari_input_mouse_interrupt_hook = NULL;
|
||||
}
|
||||
|
||||
static int __init atamouse_init(void)
|
||||
|
|
@ -118,8 +118,9 @@ static int __init atamouse_init(void)
|
|||
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
|
||||
return -ENODEV;
|
||||
|
||||
if (!atari_keyb_init())
|
||||
return -ENODEV;
|
||||
error = atari_keyb_init();
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
atamouse_dev = input_allocate_device();
|
||||
if (!atamouse_dev)
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ static void __exit gpio_mouse_exit(void)
|
|||
}
|
||||
module_exit(gpio_mouse_exit);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("GPIO mouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ static const char *desired_serio_phys;
|
|||
static int lifebook_limit_serio3(const struct dmi_system_id *d)
|
||||
{
|
||||
desired_serio_phys = "isa0060/serio3";
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool lifebook_use_6byte_proto;
|
||||
|
|
@ -41,7 +41,7 @@ static bool lifebook_use_6byte_proto;
|
|||
static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
|
||||
{
|
||||
lifebook_use_6byte_proto = true;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id __initconst lifebook_dmi_table[] = {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/libps2.h>
|
||||
|
|
|
|||
|
|
@ -207,27 +207,37 @@ static int synaptics_identify(struct psmouse *psmouse)
|
|||
static int synaptics_resolution(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
unsigned char res[3];
|
||||
unsigned char max[3];
|
||||
unsigned char resp[3];
|
||||
|
||||
if (SYN_ID_MAJOR(priv->identity) < 4)
|
||||
return 0;
|
||||
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) {
|
||||
if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) {
|
||||
priv->x_res = res[0]; /* x resolution in units/mm */
|
||||
priv->y_res = res[2]; /* y resolution in units/mm */
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) {
|
||||
if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) {
|
||||
priv->x_res = resp[0]; /* x resolution in units/mm */
|
||||
priv->y_res = resp[2]; /* y resolution in units/mm */
|
||||
}
|
||||
}
|
||||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
|
||||
SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) {
|
||||
printk(KERN_ERR "Synaptics claims to have dimensions query,"
|
||||
" but I'm not able to read it.\n");
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
|
||||
printk(KERN_ERR "Synaptics claims to have max coordinates"
|
||||
" query, but I'm not able to read it.\n");
|
||||
} else {
|
||||
priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1);
|
||||
priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3);
|
||||
priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
|
||||
priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
|
||||
SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
|
||||
printk(KERN_ERR "Synaptics claims to have min coordinates"
|
||||
" query, but I'm not able to read it.\n");
|
||||
} else {
|
||||
priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
|
||||
priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,26 +416,10 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
memset(hw, 0, sizeof(struct synaptics_hw_state));
|
||||
|
||||
if (SYN_MODEL_NEWABS(priv->model_id)) {
|
||||
hw->x = (((buf[3] & 0x10) << 8) |
|
||||
((buf[1] & 0x0f) << 8) |
|
||||
buf[4]);
|
||||
hw->y = (((buf[3] & 0x20) << 7) |
|
||||
((buf[1] & 0xf0) << 4) |
|
||||
buf[5]);
|
||||
|
||||
hw->z = buf[2];
|
||||
hw->w = (((buf[0] & 0x30) >> 2) |
|
||||
((buf[0] & 0x04) >> 1) |
|
||||
((buf[3] & 0x04) >> 2));
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
|
||||
/* Gesture packet: (x, y, z) at half resolution */
|
||||
priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
|
||||
priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
|
||||
priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||||
|
||||
|
|
@ -448,6 +442,22 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) {
|
||||
/* Gesture packet: (x, y, z) at half resolution */
|
||||
priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
|
||||
priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
|
||||
priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
hw->x = (((buf[3] & 0x10) << 8) |
|
||||
((buf[1] & 0x0f) << 8) |
|
||||
buf[4]);
|
||||
hw->y = (((buf[3] & 0x20) << 7) |
|
||||
((buf[1] & 0xf0) << 4) |
|
||||
buf[5]);
|
||||
hw->z = buf[2];
|
||||
|
||||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
|
||||
((buf[0] ^ buf[3]) & 0x02)) {
|
||||
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
|
||||
|
|
@ -485,7 +495,8 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y)
|
||||
static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
|
||||
bool active, int x, int y)
|
||||
{
|
||||
input_mt_slot(dev, slot);
|
||||
input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
|
||||
|
|
@ -502,14 +513,16 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev,
|
|||
int num_fingers)
|
||||
{
|
||||
if (num_fingers >= 2) {
|
||||
set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y));
|
||||
set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y));
|
||||
synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x),
|
||||
min(a->y, b->y));
|
||||
synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x),
|
||||
max(a->y, b->y));
|
||||
} else if (num_fingers == 1) {
|
||||
set_slot(dev, 0, true, a->x, a->y);
|
||||
set_slot(dev, 1, false, 0, 0);
|
||||
synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y);
|
||||
synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
|
||||
} else {
|
||||
set_slot(dev, 0, false, 0, 0);
|
||||
set_slot(dev, 1, false, 0, 0);
|
||||
synaptics_report_semi_mt_slot(dev, 0, false, 0, 0);
|
||||
synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -684,23 +697,36 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
|
|||
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
||||
{
|
||||
int i;
|
||||
int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
|
||||
SYN_REDUCED_FILTER_FUZZ : 0;
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, dev->propbit);
|
||||
|
||||
__set_bit(EV_ABS, dev->evbit);
|
||||
input_set_abs_params(dev, ABS_X,
|
||||
XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0);
|
||||
priv->x_min ?: XMIN_NOMINAL,
|
||||
priv->x_max ?: XMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
input_set_abs_params(dev, ABS_Y,
|
||||
YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
|
||||
priv->y_min ?: YMIN_NOMINAL,
|
||||
priv->y_max ?: YMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
|
||||
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
|
||||
input_mt_init_slots(dev, 2);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
|
||||
priv->x_max ?: XMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
|
||||
priv->y_max ?: YMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_X,
|
||||
priv->x_min ?: XMIN_NOMINAL,
|
||||
priv->x_max ?: XMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_Y,
|
||||
priv->y_min ?: YMIN_NOMINAL,
|
||||
priv->y_max ?: YMAX_NOMINAL,
|
||||
fuzz, 0);
|
||||
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res);
|
||||
}
|
||||
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
|
|
@ -971,4 +997,3 @@ bool synaptics_supported(void)
|
|||
}
|
||||
|
||||
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
#define SYN_QUE_RESOLUTION 0x08
|
||||
#define SYN_QUE_EXT_CAPAB 0x09
|
||||
#define SYN_QUE_EXT_CAPAB_0C 0x0c
|
||||
#define SYN_QUE_EXT_DIMENSIONS 0x0d
|
||||
#define SYN_QUE_EXT_MAX_COORDS 0x0d
|
||||
#define SYN_QUE_EXT_MIN_COORDS 0x0f
|
||||
|
||||
/* synatics modes */
|
||||
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
|
||||
|
|
@ -66,18 +67,21 @@
|
|||
* 1 0x60 multifinger mode identifies firmware finger counting
|
||||
* (not reporting!) algorithm.
|
||||
* Not particularly meaningful
|
||||
* 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered
|
||||
* 2 0x01 clickpad bit 1 2-button ClickPad
|
||||
* 2 0x02 deluxe LED controls touchpad support LED commands
|
||||
* 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered
|
||||
* 2 0x01 clickpad bit 1 2-button ClickPad
|
||||
* 2 0x02 deluxe LED controls touchpad support LED commands
|
||||
* ala multimedia control bar
|
||||
* 2 0x04 reduced filtering firmware does less filtering on
|
||||
* position data, driver should watch
|
||||
* for noise.
|
||||
* 2 0x20 report min query 0x0f gives min coord reported
|
||||
*/
|
||||
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
|
||||
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
|
||||
#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
|
||||
#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000)
|
||||
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
|
||||
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
||||
|
||||
/* synaptics modes query bits */
|
||||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||||
|
|
@ -104,6 +108,9 @@
|
|||
#define SYN_NEWABS_RELAXED 2
|
||||
#define SYN_OLDABS 3
|
||||
|
||||
/* amount to fuzz position data when touchpad reports reduced filtering */
|
||||
#define SYN_REDUCED_FILTER_FUZZ 8
|
||||
|
||||
/*
|
||||
* A structure to describe the state of the touchpad hardware (buttons and pad)
|
||||
*/
|
||||
|
|
@ -130,7 +137,8 @@ struct synaptics_data {
|
|||
unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
|
||||
unsigned long int identity; /* Identification */
|
||||
unsigned int x_res, y_res; /* X/Y resolution in units/mm */
|
||||
unsigned int x_max, y_max; /* Max dimensions (from FW) */
|
||||
unsigned int x_max, y_max; /* Max coordinates (from FW) */
|
||||
unsigned int x_min, y_min; /* Min coordinates (from FW) */
|
||||
|
||||
unsigned char pkt_type; /* packet type - old, new, etc */
|
||||
unsigned char mode; /* current mode byte */
|
||||
|
|
|
|||
|
|
@ -372,6 +372,6 @@ static void __exit psif_exit(void)
|
|||
module_init(psif_init);
|
||||
module_exit(psif_exit);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -795,7 +795,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
|
|||
|
||||
/************************* Keepalive timer task *********************/
|
||||
|
||||
void hp_sdc_kicker (unsigned long data)
|
||||
static void hp_sdc_kicker(unsigned long data)
|
||||
{
|
||||
tasklet_schedule(&hp_sdc.task);
|
||||
/* Re-insert the periodic task. */
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@
|
|||
/* toolMode codes
|
||||
*/
|
||||
#define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN
|
||||
#define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN
|
||||
#define AIPTEK_TOOL_BUTTON_PENCIL_MODE BTN_TOOL_PENCIL
|
||||
#define AIPTEK_TOOL_BUTTON_BRUSH_MODE BTN_TOOL_BRUSH
|
||||
#define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE BTN_TOOL_AIRBRUSH
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "wacom_wac.h"
|
||||
#include "wacom.h"
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
/* resolution for penabled devices */
|
||||
#define WACOM_PL_RES 20
|
||||
|
|
@ -264,6 +265,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
|
|||
wacom->id[0] = 0;
|
||||
input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */
|
||||
input_report_key(input, wacom->tool[0], prox);
|
||||
input_event(input, EV_MSC, MSC_SERIAL, 1);
|
||||
input_sync(input); /* sync last event */
|
||||
}
|
||||
|
||||
|
|
@ -273,11 +275,10 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
|
|||
prox = data[7] & 0xf8;
|
||||
if (prox || wacom->id[1]) {
|
||||
wacom->id[1] = PAD_DEVICE_ID;
|
||||
input_report_key(input, BTN_0, (data[7] & 0x40));
|
||||
input_report_key(input, BTN_4, (data[7] & 0x80));
|
||||
input_report_key(input, BTN_BACK, (data[7] & 0x40));
|
||||
input_report_key(input, BTN_FORWARD, (data[7] & 0x80));
|
||||
rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
|
||||
input_report_rel(input, REL_WHEEL, rw);
|
||||
input_report_key(input, BTN_TOOL_FINGER, 0xf0);
|
||||
if (!prox)
|
||||
wacom->id[1] = 0;
|
||||
input_report_abs(input, ABS_MISC, wacom->id[1]);
|
||||
|
|
@ -290,18 +291,17 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
|
|||
prox = (data[7] & 0xf8) || data[8];
|
||||
if (prox || wacom->id[1]) {
|
||||
wacom->id[1] = PAD_DEVICE_ID;
|
||||
input_report_key(input, BTN_0, (data[7] & 0x08));
|
||||
input_report_key(input, BTN_1, (data[7] & 0x20));
|
||||
input_report_key(input, BTN_4, (data[7] & 0x10));
|
||||
input_report_key(input, BTN_5, (data[7] & 0x40));
|
||||
input_report_key(input, BTN_BACK, (data[7] & 0x08));
|
||||
input_report_key(input, BTN_LEFT, (data[7] & 0x20));
|
||||
input_report_key(input, BTN_FORWARD, (data[7] & 0x10));
|
||||
input_report_key(input, BTN_RIGHT, (data[7] & 0x40));
|
||||
input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f));
|
||||
input_report_key(input, BTN_TOOL_FINGER, 0xf0);
|
||||
if (!prox)
|
||||
wacom->id[1] = 0;
|
||||
input_report_abs(input, ABS_MISC, wacom->id[1]);
|
||||
input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
|
||||
retval = 1;
|
||||
}
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
exit:
|
||||
|
|
@ -494,10 +494,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
|
|||
|
||||
/* pad packets. Works as a second tool and is always in prox */
|
||||
if (data[0] == WACOM_REPORT_INTUOSPAD) {
|
||||
/* initiate the pad as a device */
|
||||
if (wacom->tool[1] != BTN_TOOL_FINGER)
|
||||
wacom->tool[1] = BTN_TOOL_FINGER;
|
||||
|
||||
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
|
||||
input_report_key(input, BTN_0, (data[2] & 0x01));
|
||||
input_report_key(input, BTN_1, (data[3] & 0x01));
|
||||
|
|
@ -1080,18 +1076,14 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
switch (wacom_wac->features.type) {
|
||||
case WACOM_MO:
|
||||
__set_bit(BTN_1, input_dev->keybit);
|
||||
__set_bit(BTN_5, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
|
||||
/* fall through */
|
||||
|
||||
case WACOM_G4:
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SERIAL);
|
||||
|
||||
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
||||
__set_bit(BTN_0, input_dev->keybit);
|
||||
__set_bit(BTN_4, input_dev->keybit);
|
||||
__set_bit(BTN_BACK, input_dev->keybit);
|
||||
__set_bit(BTN_FORWARD, input_dev->keybit);
|
||||
/* fall through */
|
||||
|
||||
case GRAPHIRE:
|
||||
|
|
@ -1127,10 +1119,12 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
case CINTIQ:
|
||||
for (i = 0; i < 8; i++)
|
||||
__set_bit(BTN_0 + i, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
|
||||
if (wacom_wac->features.type != WACOM_21UX2) {
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
|
||||
}
|
||||
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
wacom_setup_cintiq(wacom_wac);
|
||||
break;
|
||||
|
|
@ -1151,8 +1145,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
__set_bit(BTN_2, input_dev->keybit);
|
||||
__set_bit(BTN_3, input_dev->keybit);
|
||||
|
||||
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
/* fall through */
|
||||
|
|
@ -1170,7 +1162,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
case INTUOS4S:
|
||||
for (i = 0; i < 7; i++)
|
||||
__set_bit(BTN_0 + i, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
|
||||
wacom_setup_intuos(wacom_wac);
|
||||
|
|
@ -1295,6 +1286,12 @@ static const struct wacom_features wacom_features_0x65 =
|
|||
static const struct wacom_features wacom_features_0x69 =
|
||||
{ "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511,
|
||||
63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
|
||||
static const struct wacom_features wacom_features_0x6A =
|
||||
{ "Wacom Bamboo1 4x6", WACOM_PKGLEN_GRAPHIRE, 14760, 9225, 1023,
|
||||
63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x6B =
|
||||
{ "Wacom Bamboo1 5x8", WACOM_PKGLEN_GRAPHIRE, 21648, 13530, 1023,
|
||||
63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x20 =
|
||||
{ "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023,
|
||||
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
|
|
@ -1427,6 +1424,9 @@ static const struct wacom_features wacom_features_0x90 =
|
|||
static const struct wacom_features wacom_features_0x93 =
|
||||
{ "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
|
||||
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x97 =
|
||||
{ "Wacom ISDv4 97", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 511,
|
||||
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0x9A =
|
||||
{ "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
|
||||
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
|
|
@ -1458,7 +1458,7 @@ static const struct wacom_features wacom_features_0xD3 =
|
|||
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD4 =
|
||||
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255,
|
||||
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
|
||||
static const struct wacom_features wacom_features_0xD6 =
|
||||
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
|
||||
|
|
@ -1483,6 +1483,11 @@ static const struct wacom_features wacom_features_0x6004 =
|
|||
USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \
|
||||
.driver_info = (kernel_ulong_t)&wacom_features_##prod
|
||||
|
||||
#define USB_DEVICE_DETAILED(prod, class, sub, proto) \
|
||||
USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \
|
||||
sub, proto), \
|
||||
.driver_info = (kernel_ulong_t)&wacom_features_##prod
|
||||
|
||||
#define USB_DEVICE_LENOVO(prod) \
|
||||
USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \
|
||||
.driver_info = (kernel_ulong_t)&wacom_features_##prod
|
||||
|
|
@ -1506,6 +1511,8 @@ const struct usb_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0x64) },
|
||||
{ USB_DEVICE_WACOM(0x65) },
|
||||
{ USB_DEVICE_WACOM(0x69) },
|
||||
{ USB_DEVICE_WACOM(0x6A) },
|
||||
{ USB_DEVICE_WACOM(0x6B) },
|
||||
{ USB_DEVICE_WACOM(0x20) },
|
||||
{ USB_DEVICE_WACOM(0x21) },
|
||||
{ USB_DEVICE_WACOM(0x22) },
|
||||
|
|
@ -1545,7 +1552,13 @@ const struct usb_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0xC5) },
|
||||
{ USB_DEVICE_WACOM(0xC6) },
|
||||
{ USB_DEVICE_WACOM(0xC7) },
|
||||
{ USB_DEVICE_WACOM(0xCE) },
|
||||
/*
|
||||
* DTU-2231 has two interfaces on the same configuration,
|
||||
* only one is used.
|
||||
*/
|
||||
{ USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID,
|
||||
USB_INTERFACE_SUBCLASS_BOOT,
|
||||
USB_INTERFACE_PROTOCOL_MOUSE) },
|
||||
{ USB_DEVICE_WACOM(0xD0) },
|
||||
{ USB_DEVICE_WACOM(0xD1) },
|
||||
{ USB_DEVICE_WACOM(0xD2) },
|
||||
|
|
@ -1560,6 +1573,7 @@ const struct usb_device_id wacom_ids[] = {
|
|||
{ USB_DEVICE_WACOM(0xCC) },
|
||||
{ USB_DEVICE_WACOM(0x90) },
|
||||
{ USB_DEVICE_WACOM(0x93) },
|
||||
{ USB_DEVICE_WACOM(0x97) },
|
||||
{ USB_DEVICE_WACOM(0x9A) },
|
||||
{ USB_DEVICE_WACOM(0x9F) },
|
||||
{ USB_DEVICE_WACOM(0xE2) },
|
||||
|
|
|
|||
|
|
@ -967,17 +967,12 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
|
|||
ts->get_pendown_state = pdata->get_pendown_state;
|
||||
} else if (gpio_is_valid(pdata->gpio_pendown)) {
|
||||
|
||||
err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
|
||||
err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN,
|
||||
"ads7846_pendown");
|
||||
if (err) {
|
||||
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
|
||||
pdata->gpio_pendown);
|
||||
return err;
|
||||
}
|
||||
err = gpio_direction_input(pdata->gpio_pendown);
|
||||
if (err) {
|
||||
dev_err(&spi->dev, "failed to setup pendown GPIO%d\n",
|
||||
pdata->gpio_pendown);
|
||||
gpio_free(pdata->gpio_pendown);
|
||||
dev_err(&spi->dev,
|
||||
"failed to request/setup pendown GPIO%d: %d\n",
|
||||
pdata->gpio_pendown, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
|
|||
|
||||
data = ac97c_readl(atmel_wm97xx, CBRHR);
|
||||
value = data & 0x0fff;
|
||||
source = data & WM97XX_ADCSRC_MASK;
|
||||
source = data & WM97XX_ADCSEL_MASK;
|
||||
pen_down = (data & WM97XX_PEN_DOWN) >> 8;
|
||||
|
||||
if (source == WM97XX_ADCSEL_X)
|
||||
|
|
@ -442,6 +442,6 @@ static void __exit atmel_wm97xx_exit(void)
|
|||
}
|
||||
module_exit(atmel_wm97xx_exit);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -48,41 +48,47 @@
|
|||
#define MXT_OBJECT_SIZE 6
|
||||
|
||||
/* Object types */
|
||||
#define MXT_DEBUG_DIAGNOSTIC 37
|
||||
#define MXT_GEN_MESSAGE 5
|
||||
#define MXT_GEN_COMMAND 6
|
||||
#define MXT_GEN_POWER 7
|
||||
#define MXT_GEN_ACQUIRE 8
|
||||
#define MXT_TOUCH_MULTI 9
|
||||
#define MXT_TOUCH_KEYARRAY 15
|
||||
#define MXT_TOUCH_PROXIMITY 23
|
||||
#define MXT_PROCI_GRIPFACE 20
|
||||
#define MXT_PROCG_NOISE 22
|
||||
#define MXT_PROCI_ONETOUCH 24
|
||||
#define MXT_PROCI_TWOTOUCH 27
|
||||
#define MXT_PROCI_GRIP 40
|
||||
#define MXT_PROCI_PALM 41
|
||||
#define MXT_SPT_COMMSCONFIG 18
|
||||
#define MXT_SPT_GPIOPWM 19
|
||||
#define MXT_SPT_SELFTEST 25
|
||||
#define MXT_SPT_CTECONFIG 28
|
||||
#define MXT_SPT_USERDATA 38
|
||||
#define MXT_SPT_DIGITIZER 43
|
||||
#define MXT_SPT_MESSAGECOUNT 44
|
||||
#define MXT_DEBUG_DIAGNOSTIC_T37 37
|
||||
#define MXT_GEN_MESSAGE_T5 5
|
||||
#define MXT_GEN_COMMAND_T6 6
|
||||
#define MXT_GEN_POWER_T7 7
|
||||
#define MXT_GEN_ACQUIRE_T8 8
|
||||
#define MXT_GEN_DATASOURCE_T53 53
|
||||
#define MXT_TOUCH_MULTI_T9 9
|
||||
#define MXT_TOUCH_KEYARRAY_T15 15
|
||||
#define MXT_TOUCH_PROXIMITY_T23 23
|
||||
#define MXT_TOUCH_PROXKEY_T52 52
|
||||
#define MXT_PROCI_GRIPFACE_T20 20
|
||||
#define MXT_PROCG_NOISE_T22 22
|
||||
#define MXT_PROCI_ONETOUCH_T24 24
|
||||
#define MXT_PROCI_TWOTOUCH_T27 27
|
||||
#define MXT_PROCI_GRIP_T40 40
|
||||
#define MXT_PROCI_PALM_T41 41
|
||||
#define MXT_PROCI_TOUCHSUPPRESSION_T42 42
|
||||
#define MXT_PROCI_STYLUS_T47 47
|
||||
#define MXT_PROCG_NOISESUPPRESSION_T48 48
|
||||
#define MXT_SPT_COMMSCONFIG_T18 18
|
||||
#define MXT_SPT_GPIOPWM_T19 19
|
||||
#define MXT_SPT_SELFTEST_T25 25
|
||||
#define MXT_SPT_CTECONFIG_T28 28
|
||||
#define MXT_SPT_USERDATA_T38 38
|
||||
#define MXT_SPT_DIGITIZER_T43 43
|
||||
#define MXT_SPT_MESSAGECOUNT_T44 44
|
||||
#define MXT_SPT_CTECONFIG_T46 46
|
||||
|
||||
/* MXT_GEN_COMMAND field */
|
||||
/* MXT_GEN_COMMAND_T6 field */
|
||||
#define MXT_COMMAND_RESET 0
|
||||
#define MXT_COMMAND_BACKUPNV 1
|
||||
#define MXT_COMMAND_CALIBRATE 2
|
||||
#define MXT_COMMAND_REPORTALL 3
|
||||
#define MXT_COMMAND_DIAGNOSTIC 5
|
||||
|
||||
/* MXT_GEN_POWER field */
|
||||
/* MXT_GEN_POWER_T7 field */
|
||||
#define MXT_POWER_IDLEACQINT 0
|
||||
#define MXT_POWER_ACTVACQINT 1
|
||||
#define MXT_POWER_ACTV2IDLETO 2
|
||||
|
||||
/* MXT_GEN_ACQUIRE field */
|
||||
/* MXT_GEN_ACQUIRE_T8 field */
|
||||
#define MXT_ACQUIRE_CHRGTIME 0
|
||||
#define MXT_ACQUIRE_TCHDRIFT 2
|
||||
#define MXT_ACQUIRE_DRIFTST 3
|
||||
|
|
@ -91,7 +97,7 @@
|
|||
#define MXT_ACQUIRE_ATCHCALST 6
|
||||
#define MXT_ACQUIRE_ATCHCALSTHR 7
|
||||
|
||||
/* MXT_TOUCH_MULTI field */
|
||||
/* MXT_TOUCH_MULTI_T9 field */
|
||||
#define MXT_TOUCH_CTRL 0
|
||||
#define MXT_TOUCH_XORIGIN 1
|
||||
#define MXT_TOUCH_YORIGIN 2
|
||||
|
|
@ -121,7 +127,7 @@
|
|||
#define MXT_TOUCH_YEDGEDIST 29
|
||||
#define MXT_TOUCH_JUMPLIMIT 30
|
||||
|
||||
/* MXT_PROCI_GRIPFACE field */
|
||||
/* MXT_PROCI_GRIPFACE_T20 field */
|
||||
#define MXT_GRIPFACE_CTRL 0
|
||||
#define MXT_GRIPFACE_XLOGRIP 1
|
||||
#define MXT_GRIPFACE_XHIGRIP 2
|
||||
|
|
@ -151,11 +157,11 @@
|
|||
#define MXT_NOISE_FREQ4 15
|
||||
#define MXT_NOISE_IDLEGCAFVALID 16
|
||||
|
||||
/* MXT_SPT_COMMSCONFIG */
|
||||
/* MXT_SPT_COMMSCONFIG_T18 */
|
||||
#define MXT_COMMS_CTRL 0
|
||||
#define MXT_COMMS_CMD 1
|
||||
|
||||
/* MXT_SPT_CTECONFIG field */
|
||||
/* MXT_SPT_CTECONFIG_T28 field */
|
||||
#define MXT_CTE_CTRL 0
|
||||
#define MXT_CTE_CMD 1
|
||||
#define MXT_CTE_MODE 2
|
||||
|
|
@ -166,7 +172,7 @@
|
|||
#define MXT_VOLTAGE_DEFAULT 2700000
|
||||
#define MXT_VOLTAGE_STEP 10000
|
||||
|
||||
/* Define for MXT_GEN_COMMAND */
|
||||
/* Define for MXT_GEN_COMMAND_T6 */
|
||||
#define MXT_BOOT_VALUE 0xa5
|
||||
#define MXT_BACKUP_VALUE 0x55
|
||||
#define MXT_BACKUP_TIME 25 /* msec */
|
||||
|
|
@ -256,24 +262,31 @@ struct mxt_data {
|
|||
static bool mxt_object_readable(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case MXT_GEN_MESSAGE:
|
||||
case MXT_GEN_COMMAND:
|
||||
case MXT_GEN_POWER:
|
||||
case MXT_GEN_ACQUIRE:
|
||||
case MXT_TOUCH_MULTI:
|
||||
case MXT_TOUCH_KEYARRAY:
|
||||
case MXT_TOUCH_PROXIMITY:
|
||||
case MXT_PROCI_GRIPFACE:
|
||||
case MXT_PROCG_NOISE:
|
||||
case MXT_PROCI_ONETOUCH:
|
||||
case MXT_PROCI_TWOTOUCH:
|
||||
case MXT_PROCI_GRIP:
|
||||
case MXT_PROCI_PALM:
|
||||
case MXT_SPT_COMMSCONFIG:
|
||||
case MXT_SPT_GPIOPWM:
|
||||
case MXT_SPT_SELFTEST:
|
||||
case MXT_SPT_CTECONFIG:
|
||||
case MXT_SPT_USERDATA:
|
||||
case MXT_GEN_MESSAGE_T5:
|
||||
case MXT_GEN_COMMAND_T6:
|
||||
case MXT_GEN_POWER_T7:
|
||||
case MXT_GEN_ACQUIRE_T8:
|
||||
case MXT_GEN_DATASOURCE_T53:
|
||||
case MXT_TOUCH_MULTI_T9:
|
||||
case MXT_TOUCH_KEYARRAY_T15:
|
||||
case MXT_TOUCH_PROXIMITY_T23:
|
||||
case MXT_TOUCH_PROXKEY_T52:
|
||||
case MXT_PROCI_GRIPFACE_T20:
|
||||
case MXT_PROCG_NOISE_T22:
|
||||
case MXT_PROCI_ONETOUCH_T24:
|
||||
case MXT_PROCI_TWOTOUCH_T27:
|
||||
case MXT_PROCI_GRIP_T40:
|
||||
case MXT_PROCI_PALM_T41:
|
||||
case MXT_PROCI_TOUCHSUPPRESSION_T42:
|
||||
case MXT_PROCI_STYLUS_T47:
|
||||
case MXT_PROCG_NOISESUPPRESSION_T48:
|
||||
case MXT_SPT_COMMSCONFIG_T18:
|
||||
case MXT_SPT_GPIOPWM_T19:
|
||||
case MXT_SPT_SELFTEST_T25:
|
||||
case MXT_SPT_CTECONFIG_T28:
|
||||
case MXT_SPT_USERDATA_T38:
|
||||
case MXT_SPT_DIGITIZER_T43:
|
||||
case MXT_SPT_CTECONFIG_T46:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -283,21 +296,28 @@ static bool mxt_object_readable(unsigned int type)
|
|||
static bool mxt_object_writable(unsigned int type)
|
||||
{
|
||||
switch (type) {
|
||||
case MXT_GEN_COMMAND:
|
||||
case MXT_GEN_POWER:
|
||||
case MXT_GEN_ACQUIRE:
|
||||
case MXT_TOUCH_MULTI:
|
||||
case MXT_TOUCH_KEYARRAY:
|
||||
case MXT_TOUCH_PROXIMITY:
|
||||
case MXT_PROCI_GRIPFACE:
|
||||
case MXT_PROCG_NOISE:
|
||||
case MXT_PROCI_ONETOUCH:
|
||||
case MXT_PROCI_TWOTOUCH:
|
||||
case MXT_PROCI_GRIP:
|
||||
case MXT_PROCI_PALM:
|
||||
case MXT_SPT_GPIOPWM:
|
||||
case MXT_SPT_SELFTEST:
|
||||
case MXT_SPT_CTECONFIG:
|
||||
case MXT_GEN_COMMAND_T6:
|
||||
case MXT_GEN_POWER_T7:
|
||||
case MXT_GEN_ACQUIRE_T8:
|
||||
case MXT_TOUCH_MULTI_T9:
|
||||
case MXT_TOUCH_KEYARRAY_T15:
|
||||
case MXT_TOUCH_PROXIMITY_T23:
|
||||
case MXT_TOUCH_PROXKEY_T52:
|
||||
case MXT_PROCI_GRIPFACE_T20:
|
||||
case MXT_PROCG_NOISE_T22:
|
||||
case MXT_PROCI_ONETOUCH_T24:
|
||||
case MXT_PROCI_TWOTOUCH_T27:
|
||||
case MXT_PROCI_GRIP_T40:
|
||||
case MXT_PROCI_PALM_T41:
|
||||
case MXT_PROCI_TOUCHSUPPRESSION_T42:
|
||||
case MXT_PROCI_STYLUS_T47:
|
||||
case MXT_PROCG_NOISESUPPRESSION_T48:
|
||||
case MXT_SPT_COMMSCONFIG_T18:
|
||||
case MXT_SPT_GPIOPWM_T19:
|
||||
case MXT_SPT_SELFTEST_T25:
|
||||
case MXT_SPT_CTECONFIG_T28:
|
||||
case MXT_SPT_DIGITIZER_T43:
|
||||
case MXT_SPT_CTECONFIG_T46:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -455,7 +475,7 @@ static int mxt_read_message(struct mxt_data *data,
|
|||
struct mxt_object *object;
|
||||
u16 reg;
|
||||
|
||||
object = mxt_get_object(data, MXT_GEN_MESSAGE);
|
||||
object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
|
||||
if (!object)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -597,8 +617,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
|
|||
|
||||
reportid = message.reportid;
|
||||
|
||||
/* whether reportid is thing of MXT_TOUCH_MULTI */
|
||||
object = mxt_get_object(data, MXT_TOUCH_MULTI);
|
||||
/* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
|
||||
object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
|
||||
if (!object)
|
||||
goto end;
|
||||
|
||||
|
|
@ -635,7 +655,9 @@ static int mxt_check_reg_init(struct mxt_data *data)
|
|||
if (!mxt_object_writable(object->type))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < object->size + 1; j++) {
|
||||
for (j = 0;
|
||||
j < (object->size + 1) * (object->instances + 1);
|
||||
j++) {
|
||||
config_offset = index + j;
|
||||
if (config_offset > pdata->config_length) {
|
||||
dev_err(dev, "Not enough config data!\n");
|
||||
|
|
@ -644,7 +666,7 @@ static int mxt_check_reg_init(struct mxt_data *data)
|
|||
mxt_write_object(data, object->type, j,
|
||||
pdata->config[config_offset]);
|
||||
}
|
||||
index += object->size + 1;
|
||||
index += (object->size + 1) * (object->instances + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -678,31 +700,31 @@ static void mxt_handle_pdata(struct mxt_data *data)
|
|||
u8 voltage;
|
||||
|
||||
/* Set touchscreen lines */
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE,
|
||||
pdata->x_line);
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE,
|
||||
pdata->y_line);
|
||||
|
||||
/* Set touchscreen orient */
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT,
|
||||
pdata->orient);
|
||||
|
||||
/* Set touchscreen burst length */
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_BLEN, pdata->blen);
|
||||
|
||||
/* Set touchscreen threshold */
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_TCHTHR, pdata->threshold);
|
||||
|
||||
/* Set touchscreen resolution */
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI,
|
||||
mxt_write_object(data, MXT_TOUCH_MULTI_T9,
|
||||
MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
|
||||
|
||||
/* Set touchscreen voltage */
|
||||
|
|
@ -715,7 +737,7 @@ static void mxt_handle_pdata(struct mxt_data *data)
|
|||
voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) /
|
||||
MXT_VOLTAGE_STEP;
|
||||
|
||||
mxt_write_object(data, MXT_SPT_CTECONFIG,
|
||||
mxt_write_object(data, MXT_SPT_CTECONFIG_T28,
|
||||
MXT_CTE_VOLTAGE, voltage);
|
||||
}
|
||||
}
|
||||
|
|
@ -819,13 +841,13 @@ static int mxt_initialize(struct mxt_data *data)
|
|||
mxt_handle_pdata(data);
|
||||
|
||||
/* Backup to memory */
|
||||
mxt_write_object(data, MXT_GEN_COMMAND,
|
||||
mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
||||
MXT_COMMAND_BACKUPNV,
|
||||
MXT_BACKUP_VALUE);
|
||||
msleep(MXT_BACKUP_TIME);
|
||||
|
||||
/* Soft reset */
|
||||
mxt_write_object(data, MXT_GEN_COMMAND,
|
||||
mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
||||
MXT_COMMAND_RESET, 1);
|
||||
msleep(MXT_RESET_TIME);
|
||||
|
||||
|
|
@ -921,7 +943,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
|
|||
}
|
||||
|
||||
/* Change to the bootloader mode */
|
||||
mxt_write_object(data, MXT_GEN_COMMAND,
|
||||
mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
||||
MXT_COMMAND_RESET, MXT_BOOT_VALUE);
|
||||
msleep(MXT_RESET_TIME);
|
||||
|
||||
|
|
@ -1027,14 +1049,14 @@ static void mxt_start(struct mxt_data *data)
|
|||
{
|
||||
/* Touch enable */
|
||||
mxt_write_object(data,
|
||||
MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83);
|
||||
MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
|
||||
}
|
||||
|
||||
static void mxt_stop(struct mxt_data *data)
|
||||
{
|
||||
/* Touch disable */
|
||||
mxt_write_object(data,
|
||||
MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
|
||||
MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
|
||||
}
|
||||
|
||||
static int mxt_input_open(struct input_dev *dev)
|
||||
|
|
@ -1182,7 +1204,7 @@ static int mxt_resume(struct device *dev)
|
|||
struct input_dev *input_dev = data->input_dev;
|
||||
|
||||
/* Soft reset */
|
||||
mxt_write_object(data, MXT_GEN_COMMAND,
|
||||
mxt_write_object(data, MXT_GEN_COMMAND_T6,
|
||||
MXT_COMMAND_RESET, 1);
|
||||
|
||||
msleep(MXT_RESET_TIME);
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@ static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
|
|||
memcpy(i2c_data + 1, value, len);
|
||||
|
||||
ret = i2c_master_send(client, i2c_data, len + 1);
|
||||
if (ret != 1) {
|
||||
if (ret != len + 1) {
|
||||
dev_err(&client->dev, "i2c write data cmd failed\n");
|
||||
return ret ? ret : -EIO;
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -193,6 +193,8 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client,
|
|||
|
||||
ts->client = client;
|
||||
ts->input = input_dev;
|
||||
ts->reset_pin = pdata->reset_pin;
|
||||
ts->irq_pin = pdata->irq_pin;
|
||||
|
||||
snprintf(ts->phys, sizeof(ts->phys),
|
||||
"%s/input0", dev_name(&client->dev));
|
||||
|
|
@ -328,7 +330,7 @@ static int __devexit cy8ctmg110_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_device_id cy8ctmg110_idtable[] = {
|
||||
static const struct i2c_device_id cy8ctmg110_idtable[] = {
|
||||
{ CY8CTMG110_DRIVER_NAME, 1 },
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -448,15 +448,11 @@ static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
|
|||
*/
|
||||
static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
|
||||
{
|
||||
int err, i, found;
|
||||
int found = 0;
|
||||
int err, i;
|
||||
u8 r8;
|
||||
|
||||
found = -1;
|
||||
|
||||
for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
|
||||
if (found >= 0)
|
||||
break;
|
||||
|
||||
err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -466,16 +462,15 @@ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (found < 0)
|
||||
return 0;
|
||||
|
||||
if (tsdev->vendor == PMIC_VENDOR_FS) {
|
||||
if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
|
||||
if (found > MRSTOUCH_MAX_CHANNELS - 18)
|
||||
return -ENOSPC;
|
||||
} else {
|
||||
if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
|
||||
if (found > MRSTOUCH_MAX_CHANNELS - 4)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,9 +157,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
|
|||
x, y, p);
|
||||
|
||||
/* are samples valid */
|
||||
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
||||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
||||
(p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES)
|
||||
if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
|
||||
(y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
|
||||
(p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
|
||||
goto up;
|
||||
|
||||
/* coordinate is good */
|
||||
|
|
|
|||
|
|
@ -393,5 +393,5 @@ module_exit(tsc_exit);
|
|||
|
||||
MODULE_AUTHOR("Cyril Chemparathy");
|
||||
MODULE_DESCRIPTION("TNETV107X Touchscreen Driver");
|
||||
MODULE_ALIAS("platform: tnetv107x-ts");
|
||||
MODULE_ALIAS("platform:tnetv107x-ts");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -215,8 +215,9 @@ static inline int is_pden(struct wm97xx *wm)
|
|||
static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
||||
{
|
||||
int timeout = 5 * delay;
|
||||
bool wants_pen = adcsel & WM97XX_PEN_DOWN;
|
||||
|
||||
if (!wm->pen_probably_down) {
|
||||
if (wants_pen && !wm->pen_probably_down) {
|
||||
u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
|
||||
if (!(data & WM97XX_PEN_DOWN))
|
||||
return RC_PENUP;
|
||||
|
|
@ -224,13 +225,10 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
}
|
||||
|
||||
/* set up digitiser */
|
||||
if (adcsel & 0x8000)
|
||||
adcsel = ((adcsel & 0x7fff) + 3) << 12;
|
||||
|
||||
if (wm->mach_ops && wm->mach_ops->pre_sample)
|
||||
wm->mach_ops->pre_sample(adcsel);
|
||||
wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
|
||||
adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
|
||||
wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
|
||||
| WM97XX_POLL | WM97XX_DELAY(delay));
|
||||
|
||||
/* wait 3 AC97 time slots + delay for conversion */
|
||||
poll_delay(delay);
|
||||
|
|
@ -256,13 +254,14 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
wm->mach_ops->post_sample(adcsel);
|
||||
|
||||
/* check we have correct sample */
|
||||
if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
|
||||
*sample & WM97XX_ADCSEL_MASK);
|
||||
if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
|
||||
adcsel & WM97XX_ADCSEL_MASK,
|
||||
*sample & WM97XX_ADCSEL_MASK);
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
||||
if (!(*sample & WM97XX_PEN_DOWN)) {
|
||||
if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
|
||||
wm->pen_probably_down = 0;
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
|
@ -277,14 +276,14 @@ static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
|
|||
{
|
||||
int rc;
|
||||
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
if (pil) {
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p);
|
||||
rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -255,8 +255,9 @@ static inline int is_pden(struct wm97xx *wm)
|
|||
static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
||||
{
|
||||
int timeout = 5 * delay;
|
||||
bool wants_pen = adcsel & WM97XX_PEN_DOWN;
|
||||
|
||||
if (!wm->pen_probably_down) {
|
||||
if (wants_pen && !wm->pen_probably_down) {
|
||||
u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
|
||||
if (!(data & WM97XX_PEN_DOWN))
|
||||
return RC_PENUP;
|
||||
|
|
@ -264,13 +265,10 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
}
|
||||
|
||||
/* set up digitiser */
|
||||
if (adcsel & 0x8000)
|
||||
adcsel = ((adcsel & 0x7fff) + 3) << 12;
|
||||
|
||||
if (wm->mach_ops && wm->mach_ops->pre_sample)
|
||||
wm->mach_ops->pre_sample(adcsel);
|
||||
wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
|
||||
adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
|
||||
wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
|
||||
| WM97XX_POLL | WM97XX_DELAY(delay));
|
||||
|
||||
/* wait 3 AC97 time slots + delay for conversion */
|
||||
poll_delay(delay);
|
||||
|
|
@ -296,13 +294,14 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
wm->mach_ops->post_sample(adcsel);
|
||||
|
||||
/* check we have correct sample */
|
||||
if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
|
||||
*sample & WM97XX_ADCSEL_MASK);
|
||||
if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
|
||||
adcsel & WM97XX_ADCSEL_MASK,
|
||||
*sample & WM97XX_ADCSEL_MASK);
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
||||
if (!(*sample & WM97XX_PEN_DOWN)) {
|
||||
if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
|
||||
wm->pen_probably_down = 0;
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
|
@ -387,16 +386,18 @@ static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
|
|||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
} else {
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN,
|
||||
&data->x);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN,
|
||||
&data->y);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
|
||||
if (pil && !five_wire) {
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
|
||||
rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
|
||||
&data->p);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -261,8 +261,9 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
{
|
||||
u16 dig1;
|
||||
int timeout = 5 * delay;
|
||||
bool wants_pen = adcsel & WM97XX_PEN_DOWN;
|
||||
|
||||
if (!wm->pen_probably_down) {
|
||||
if (wants_pen && !wm->pen_probably_down) {
|
||||
u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
|
||||
if (!(data & WM97XX_PEN_DOWN))
|
||||
return RC_PENUP;
|
||||
|
|
@ -270,15 +271,14 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
}
|
||||
|
||||
/* set up digitiser */
|
||||
if (adcsel & 0x8000)
|
||||
adcsel = 1 << ((adcsel & 0x7fff) + 3);
|
||||
|
||||
dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
|
||||
dig1 &= ~WM9713_ADCSEL_MASK;
|
||||
/* WM97XX_ADCSEL_* channels need to be converted to WM9713 format */
|
||||
dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12);
|
||||
|
||||
if (wm->mach_ops && wm->mach_ops->pre_sample)
|
||||
wm->mach_ops->pre_sample(adcsel);
|
||||
wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL);
|
||||
wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL);
|
||||
|
||||
/* wait 3 AC97 time slots + delay for conversion */
|
||||
poll_delay(delay);
|
||||
|
|
@ -304,13 +304,14 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
|
|||
wm->mach_ops->post_sample(adcsel);
|
||||
|
||||
/* check we have correct sample */
|
||||
if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
|
||||
*sample & WM97XX_ADCSRC_MASK);
|
||||
if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
|
||||
dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
|
||||
adcsel & WM97XX_ADCSEL_MASK,
|
||||
*sample & WM97XX_ADCSEL_MASK);
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
||||
if (!(*sample & WM97XX_PEN_DOWN)) {
|
||||
if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
|
||||
wm->pen_probably_down = 0;
|
||||
return RC_PENUP;
|
||||
}
|
||||
|
|
@ -400,14 +401,14 @@ static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
|
|||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
} else {
|
||||
rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x);
|
||||
rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y);
|
||||
rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
if (pil) {
|
||||
rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES,
|
||||
rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
|
||||
&data->p);
|
||||
if (rc != RC_VALID)
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -122,9 +122,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm)
|
|||
x, y, p);
|
||||
|
||||
/* are samples valid */
|
||||
if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X ||
|
||||
(y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y ||
|
||||
(p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES)
|
||||
if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
|
||||
(y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
|
||||
(p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
|
||||
goto up;
|
||||
|
||||
/* coordinate is good */
|
||||
|
|
|
|||
Loading…
Reference in a new issue