Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (53 commits) Input: synaptics - fix reporting of min coordinates Input: tegra-kbc - enable key autorepeat Input: kxtj9 - fix locking typo in kxtj9_set_poll() Input: kxtj9 - fix bug in probe() Input: intel-mid-touch - remove pointless checking for variable 'found' Input: hp_sdc - staticize hp_sdc_kicker() Input: pmic8xxx-keypad - fix a leak of the IRQ during init failure Input: cy8ctmg110_ts - set reset_pin and irq_pin from platform data Input: cy8ctmg110_ts - constify i2c_device_id table Input: cy8ctmg110_ts - fix checking return value of i2c_master_send Input: lifebook - make dmi callback functions return 1 Input: atkbd - make dmi callback functions return 1 Input: gpio_keys - switch to using SIMPLE_DEV_PM_OPS Input: gpio_keys - add support for device-tree platform data Input: aiptek - remove double define Input: synaptics - set minimum coordinates as reported by firmware Input: synaptics - process button bits in AGM packets Input: synaptics - rename set_slot to be more descriptive Input: synaptics - fuzz position for touchpad with reduced filtering Input: synaptics - set resolution for MT_POSITION_X/Y axes ...
This commit is contained in:
commit
70a3eff576
36
Documentation/devicetree/bindings/gpio/gpio_keys.txt
Normal file
36
Documentation/devicetree/bindings/gpio/gpio_keys.txt
Normal file
@ -0,0 +1,36 @@
|
||||
Device-Tree bindings for input/gpio_keys.c keyboard driver
|
||||
|
||||
Required properties:
|
||||
- compatible = "gpio-keys";
|
||||
|
||||
Optional properties:
|
||||
- autorepeat: Boolean, Enable auto repeat feature of Linux input
|
||||
subsystem.
|
||||
|
||||
Each button (key) is represented as a sub-node of "gpio-keys":
|
||||
Subnode properties:
|
||||
|
||||
- gpios: OF devcie-tree gpio specificatin.
|
||||
- label: Descriptive name of the key.
|
||||
- linux,code: Keycode to emit.
|
||||
|
||||
Optional subnode-properties:
|
||||
- linux,input-type: Specify event type this button/key generates.
|
||||
If not specified defaults to <1> == EV_KEY.
|
||||
- debounce-interval: Debouncing interval time in milliseconds.
|
||||
If not specified defaults to 5.
|
||||
- gpio-key,wakeup: Boolean, button can wake-up the system.
|
||||
|
||||
Example nodes:
|
||||
|
||||
gpio_keys {
|
||||
compatible = "gpio-keys";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
autorepeat;
|
||||
button@21 {
|
||||
label = "GPIO Key UP";
|
||||
linux,code = <103>;
|
||||
gpios = <&gpio1 0 1>;
|
||||
};
|
||||
...
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
|
@ -700,9 +700,9 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_pmic_reg_read:
|
||||
free_irq(kp->key_stuck_irq, NULL);
|
||||
free_irq(kp->key_stuck_irq, kp);
|
||||
err_req_stuck_irq:
|
||||
free_irq(kp->key_sense_irq, NULL);
|
||||
free_irq(kp->key_sense_irq, kp);
|
||||
err_gpio_config:
|
||||
err_get_irq:
|
||||
input_free_device(kp->input);
|
||||
@ -717,8 +717,8 @@ 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, NULL);
|
||||
free_irq(kp->key_sense_irq, NULL);
|
||||
free_irq(kp->key_stuck_irq, kp);
|
||||
free_irq(kp->key_sense_irq, kp);
|
||||
input_unregister_device(kp->input);
|
||||
kfree(kp);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sh_keysc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
@ -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
|
||||
|
@ -25,8 +25,11 @@ 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
|
||||
@ -46,4 +49,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");
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -119,9 +119,9 @@ struct input_keymap_entry {
|
||||
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
|
||||
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
|
||||
|
||||
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
|
||||
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
|
||||
#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
|
||||
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */
|
||||
#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */
|
||||
#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */
|
||||
|
||||
#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
|
||||
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
|
||||
|
70
include/linux/input/kxtj9.h
Normal file
70
include/linux/input/kxtj9.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __KXTJ9_H__
|
||||
#define __KXTJ9_H__
|
||||
|
||||
#define KXTJ9_I2C_ADDR 0x0F
|
||||
|
||||
struct kxtj9_platform_data {
|
||||
unsigned int min_interval; /* minimum poll interval (in milli-seconds) */
|
||||
|
||||
/*
|
||||
* By default, x is axis 0, y is axis 1, z is axis 2; these can be
|
||||
* changed to account for sensor orientation within the host device.
|
||||
*/
|
||||
u8 axis_map_x;
|
||||
u8 axis_map_y;
|
||||
u8 axis_map_z;
|
||||
|
||||
/*
|
||||
* Each axis can be negated to account for sensor orientation within
|
||||
* the host device.
|
||||
*/
|
||||
bool negate_x;
|
||||
bool negate_y;
|
||||
bool negate_z;
|
||||
|
||||
/* CTRL_REG1: set resolution, g-range, data ready enable */
|
||||
/* Output resolution: 8-bit valid or 12-bit valid */
|
||||
#define RES_8BIT 0
|
||||
#define RES_12BIT (1 << 6)
|
||||
u8 res_12bit;
|
||||
/* Output g-range: +/-2g, 4g, or 8g */
|
||||
#define KXTJ9_G_2G 0
|
||||
#define KXTJ9_G_4G (1 << 3)
|
||||
#define KXTJ9_G_8G (1 << 4)
|
||||
u8 g_range;
|
||||
|
||||
/* DATA_CTRL_REG: controls the output data rate of the part */
|
||||
#define ODR12_5F 0
|
||||
#define ODR25F 1
|
||||
#define ODR50F 2
|
||||
#define ODR100F 3
|
||||
#define ODR200F 4
|
||||
#define ODR400F 5
|
||||
#define ODR800F 6
|
||||
u8 data_odr_init;
|
||||
|
||||
int (*init)(void);
|
||||
void (*exit)(void);
|
||||
int (*power_on)(void);
|
||||
int (*power_off)(void);
|
||||
};
|
||||
#endif /* __KXTJ9_H__ */
|
@ -38,7 +38,11 @@
|
||||
#define WM97XX_ADCSEL_X 0x1000 /* x coord measurement */
|
||||
#define WM97XX_ADCSEL_Y 0x2000 /* y coord measurement */
|
||||
#define WM97XX_ADCSEL_PRES 0x3000 /* pressure measurement */
|
||||
#define WM97XX_ADCSEL_MASK 0x7000
|
||||
#define WM97XX_AUX_ID1 0x4000
|
||||
#define WM97XX_AUX_ID2 0x5000
|
||||
#define WM97XX_AUX_ID3 0x6000
|
||||
#define WM97XX_AUX_ID4 0x7000
|
||||
#define WM97XX_ADCSEL_MASK 0x7000 /* ADC selection mask */
|
||||
#define WM97XX_COO 0x0800 /* enable coordinate mode */
|
||||
#define WM97XX_CTC 0x0400 /* enable continuous mode */
|
||||
#define WM97XX_CM_RATE_93 0x0000 /* 93.75Hz continuous rate */
|
||||
@ -61,13 +65,6 @@
|
||||
#define WM97XX_PRP_DET_DIG 0xc000 /* setect on, digitise on */
|
||||
#define WM97XX_RPR 0x2000 /* wake up on pen down */
|
||||
#define WM97XX_PEN_DOWN 0x8000 /* pen is down */
|
||||
#define WM97XX_ADCSRC_MASK 0x7000 /* ADC source mask */
|
||||
|
||||
#define WM97XX_AUX_ID1 0x8001
|
||||
#define WM97XX_AUX_ID2 0x8002
|
||||
#define WM97XX_AUX_ID3 0x8003
|
||||
#define WM97XX_AUX_ID4 0x8004
|
||||
|
||||
|
||||
/* WM9712 Bits */
|
||||
#define WM9712_45W 0x1000 /* set for 5-wire touchscreen */
|
||||
|
Loading…
Reference in New Issue
Block a user