input: joystick: Adding Austria Microsystem AS5011 joystick driver (fourth version)
Subsystems (2)
PATCH 1/1 input: joystick: Adding Austria Microsystem AS5011 joystick driver (fourth version)
Driver for EasyPoint AS5011 2 axis joystick chip. This chip is plugged on an I2C bus. It has been tested on ARM processor (i.MX27).
--- drivers/input/joystick/Kconfig | 9 + drivers/input/joystick/Makefile | 1 + drivers/input/joystick/as5011.c | 414 +++++++++++++++++++++++++++++++++++++++ include/linux/input/as5011.h | 24 +++ 4 files changed, 448 insertions(+), 0 deletions(-) create mode 100644 drivers/input/joystick/as5011.c create mode 100644 include/linux/input/as5011.h
drivers/input/joystick/Kconfig +9 -0
@@ -255,6 +255,15 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. +config JOYSTICK_AS5011 + tristate "Austria Microsystem AS5011 joystick" + depends on I2C + help + Say Y here if you have an AS5011 digital joystick. + + To compile this driver as a module, choose M here: the + module will be called as5011. + config JOYSTICK_JOYDUMP tristate "Gameport data dumper" select GAMEPORT
drivers/input/joystick/Makefile +1 -0
@@ -7,6 +7,7 @@ obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o +obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o
drivers/input/joystick/as5011.c new file +414 -0
414 lines not on this page · raw message
include/linux/input/as5011.h new file +24 -0
@@ -0,0 +1,24 @@ +#ifndef _AS5011_H +#define _AS5011_H + +/* +* Copyright (c) 2010, 2011 Fabien Marteau <[email protected]> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 as published by +* the Free Software Foundation. +*/ + +#include <linux/mutex.h> + +#define AS5011_MAX_NAME_LENGTH 64 + +struct as5011_platform_data { +int button_gpio; +int int_irq;/* irq number */ +int int_edge;/* irq edge IRQ_TYPE_EDGE_[FALLING,RISING,BOTH] */ +char xp, xn;/* threshold for x axis */ +char yp, yn;/* threshold for y axis */ +}; + +#endif /* _AS5011_H */
Signature · 1 line
1.7.0.4
Dmitry Torokhov
maintainerHi Fabien,
Quoted 4 lines · Fabien Marteau
Driver for EasyPoint AS5011 2 axis joystick chip. This chip is plugged on an I2C bus. It has been tested on ARM processor (i.MX27).
Some more comments and a patch for you to try...
Review
Quoted 4 lines
(quoted diff) +4
-0+ +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mutex.h>
Not needed anymore.
Review
Quoted 6 lines
(quoted diff) +6
-0+ +struct as5011_device { + int button_irq; + struct input_dev *input_dev; + struct i2c_client *i2c_client; + char name[AS5011_MAX_NAME_LENGTH];
Name is not used.
Quoted 10 lines
(quoted diff) +10
-0+ +static int as5011_i2c_read(struct i2c_client *client, + uint8_t aregaddr, signed char *value) +{ + int ret; + uint8_t data[2]; + struct i2c_msg msg_set[2]; + struct i2c_msg msg1 = { client->addr, + I2C_M_REV_DIR_ADDR, + 1,
Review
Quoted 10 lines
(quoted diff) +10
-0+ (uint8_t *)data}; + struct i2c_msg msg2 = { client->addr, + I2C_M_RD|I2C_M_NOSTART, + 1, + (uint8_t *)data}; + + data[0] = aregaddr; + msg_set[0] = msg1; + msg_set[1] = msg2; +
You do not need both the array and individual variables.
Quoted 8 lines
(quoted diff) +8
-0+ ret = i2c_transfer(client->adapter, msg_set, 2); + if (ret < 0) + return ret; + + if (data[0] & 0x80) { + *value = -1*(1+(~data[0])); + return 0; + } else {
Review
Quoted 10 lines
(quoted diff) +10
-0+ *value = data[0]; + return 0; + } +} + +static irqreturn_t button_interrupt(int irq, void *dev_id) +{ + struct as5011_device *dev = dev_id; + struct as5011_platform_data *plat_dat = + dev->i2c_client->dev.platform_data;
Looks like indented with spaces.
Review
Quoted 3 lines
(quoted diff) +3
-0+ int ret; + + ret = gpio_get_value(plat_dat->button_gpio);
We should call gpio_get_value_cansleep() to avoid warnings if gpio operations require sleep - we can sleep here since we are using threaded interrupt.
Quoted 24 lines
(quoted diff) +24
-0+ if (ret) + input_report_key(dev->input_dev, BTN_JOYSTICK, 0); + else + input_report_key(dev->input_dev, BTN_JOYSTICK, 1); + input_sync(dev->input_dev); + + return IRQ_HANDLED; +} + +static int as5011_update_axes(struct as5011_device *dev) +{ + int ret; + signed char x, y; + + ret = as5011_i2c_read(dev->i2c_client, AS5011_X_RES_INT, &x); + if (ret < 0) + return ret; + ret = as5011_i2c_read(dev->i2c_client, AS5011_Y_RES_INT, &y); + if (ret < 0) + return ret; + input_report_abs(dev->input_dev, ABS_X, x); + input_report_abs(dev->input_dev, ABS_Y, y); + input_sync(dev->input_dev); + return 0;
Review
Quoted 10 lines
(quoted diff) +10
-0+} + +static irqreturn_t as5011_int_interrupt(int irq, void *dev_id) +{ + int ret; + struct as5011_device *dev = dev_id; + + ret = as5011_update_axes(dev); + if (ret < 0) + return ret;
Negative result is not a valid irqreturn_t value, we should not try to return it here.
Review
Quoted 9 lines
(quoted diff) +9
-0+ + return IRQ_HANDLED; +} + +static int __devinit as5011_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct as5011_device *dev; + struct as5011_platform_data *plat_dat = client->dev.platform_data;
Platform data should be const.
Review
Quoted 1 line
(quoted diff) +1
-0+ int retval = 0;
Do not initialize error codes like this - it quite often masks problem like forgetting to update to proper error code in error handling branch and unintentionally returning success.
Quoted 21 lines
(quoted diff) +21
-0+ signed char value; + + if (plat_dat == NULL) + return -EINVAL; + + dev = kmalloc(sizeof(struct as5011_device), GFP_KERNEL); + if (dev == NULL) { + dev_err(&client->dev, + "Can't allocate memory for device structure\n"); + goto err_out; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_PROTOCOL_MANGLING)) { + dev_err(&client->dev, + "i2c bus does not support protocol mangling, as5011 can't work\n"); + retval = -ENODEV; + goto err_free_device_structure; + } + dev->i2c_client = client; +
Review
Quoted 10 lines
(quoted diff) +10
-0+ dev->input_dev = input_allocate_device(); + if (dev->input_dev == NULL) { + dev_err(&client->dev, + "not enough memory for input devices structure\n"); + retval = -ENOMEM; + goto err_free_device_structure; + } + + dev->input_dev->name = "Austria Microsystem as5011 joystick"; + dev->input_dev->id.bustype = BUS_I2C;
You also should be setting input_dev->dev.parent = &client->dev to ensure that the input device gets placed in proper place in sysfs tree.
Quoted 27 lines
(quoted diff) +27
-0+ __set_bit(EV_KEY, dev->input_dev->evbit); + __set_bit(EV_ABS, dev->input_dev->evbit); + __set_bit(BTN_JOYSTICK, dev->input_dev->keybit); + + input_set_abs_params(dev->input_dev, + ABS_X, + AS5011_MIN_AXIS, + AS5011_MAX_AXIS, + AS5011_FUZZ, + AS5011_FLAT); + input_set_abs_params(dev->input_dev, + ABS_Y, + AS5011_MIN_AXIS, + AS5011_MAX_AXIS, + AS5011_FUZZ, + AS5011_FLAT); + + retval = gpio_request(plat_dat->button_gpio, "AS5011 button"); + if (retval < 0) { + dev_err(&client->dev, "Failed to request button gpio\n"); + goto err_input_free_device; + } + + + dev->button_irq = gpio_to_irq(plat_dat->button_gpio); + if (dev->button_irq < 0) { + dev_err(&client->dev,
Review
Quoted 10 lines
(quoted diff) +10
-0+ "Failed to get irq number for button gpio\n"); + goto err_free_button_gpio; + } + + set_irq_type(dev->button_irq, IRQ_TYPE_EDGE_BOTH); + + retval = request_threaded_irq(dev->button_irq, + NULL, button_interrupt, + 0, "as5011_button", + dev);
Normally you just supply IRQF_TRIGGER_XXX flags to request_irq instead of calling set_irq_type().
Review
Quoted 13 lines
(quoted diff) +13
-0+ + retval = input_register_device(dev->input_dev); + if (retval) { + dev_err(&client->dev, "Failed to register device\n"); + goto err_free_irq_int; + } + i2c_set_clientdata(client, dev); + + return 0; + + /* Error management */ +err_free_irq_int: + set_irq_type(plat_dat->int_irq, IRQ_TYPE_NONE);
I do not believe you need to reset IRQ type here, free_irq() should suffice.
Review
Quoted 8 lines
(quoted diff) +8
-0+ free_irq(plat_dat->int_irq, dev); +err_free_irq_button_interrupt: + set_irq_type(dev->button_irq, IRQ_TYPE_NONE); + free_irq(dev->button_irq, dev); +err_free_button_gpio: + gpio_free(plat_dat->button_gpio); +err_input_free_device: + input_unregister_device(dev->input_dev);
Unregistered devices should be freed with call to input_free_device() instead of input_unregister_device().
Review
Quoted 7 lines
(quoted diff) +7
-0+err_free_device_structure: + kfree(dev); +err_out: + return retval; +} +static int as5011_remove(struct i2c_client *client) +{
__devexit
Quoted 8 lines
(quoted diff) +8
-0+ struct as5011_device *dev; + struct as5011_platform_data *plat_dat = client->dev.platform_data; + + dev = i2c_get_clientdata(client); + + set_irq_type(plat_dat->int_irq, IRQ_TYPE_NONE); + free_irq(plat_dat->int_irq, dev); + set_irq_type(dev->button_irq, IRQ_TYPE_NONE);
Review
Quoted 10 lines
(quoted diff) +10
-0+ free_irq(dev->button_irq, dev); + gpio_free(plat_dat->button_gpio); + input_unregister_device(dev->input_dev); + kfree(dev); + return 0; +} +static const struct i2c_device_id as5011_id[] = { + { MODULE_DEVICE_ALIAS, 0 }, + { } +};
Also needs MODULE_DEVICE_TABLE(i2c, as5011_id);
Quoted 30 lines
(quoted diff) +22
-0+ +static struct i2c_driver as5011_driver = { + .driver = { + .name = "as5011", + }, + .probe = as5011_probe, + .remove = __devexit_p(as5011_remove), + .id_table = as5011_id, +}; + +static int __init as5011_init(void) +{ + return i2c_add_driver(&as5011_driver); +} +module_init(as5011_init); + +static void __exit as5011_exit(void) +{ + i2c_del_driver(&as5011_driver); +} +module_exit(as5011_exit); +include/linux/input/as5011.h new file +2
-0@@ -0,0 +1,24 @@ +#ifndef _AS5011_H +#define _AS5011_H
include/linux/input/as5011.h line 12
Quoted 10 lines
include/linux/input/as5011.h new file +10
-0+ +/* +* Copyright (c) 2010, 2011 Fabien Marteau <[email protected]> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 as published by +* the Free Software Foundation. +*/ + +#include <linux/mutex.h>
Not needed.
include/linux/input/as5011.h line 14
Quoted 2 lines
include/linux/input/as5011.h new file +2
-0+ +#define AS5011_MAX_NAME_LENGTH 64
Not needed.
Quoted 13 lines
include/linux/input/as5011.h new file +10
-0+ +struct as5011_platform_data { +int button_gpio; +int int_irq;/* irq number */ +int int_edge;/* irq edge IRQ_TYPE_EDGE_[FALLING,RISING,BOTH] */ +char xp, xn;/* threshold for x axis */ +char yp, yn;/* threshold for y axis */ +}; + +#endif /* _AS5011_H */ Signature · 1 line
1.7.0.4
Does the patch below work for you or did I break it horribly?
Thanks,
Signature · 23 lines
Dmitry Input: add Austria Microsystem AS5011 joystick driver From: Fabien Marteau <[email protected]> This is driver for EasyPoint AS5011 2 axis joystick chip. This chip is plugged on an I2C bus. Tested on ARM processor (i.MX27). Signed-off-by: Fabien Marteau <[email protected]> Signed-off-by: Dmitry Torokhov <[email protected]> --- drivers/input/joystick/Kconfig | 10 + drivers/input/joystick/Makefile | 1 drivers/input/joystick/as5011.c | 367 +++++++++++++++++++++++++++++++++++++++ include/linux/input/as5011.h | 20 ++ 4 files changed, 398 insertions(+), 0 deletions(-) create mode 100644 drivers/input/joystick/as5011.c create mode 100644 include/linux/input/as5011.h
drivers/input/joystick/Kconfig +10 -0
@@ -255,6 +255,16 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. +config JOYSTICK_AS5011 + tristate "Austria Microsystem AS5011 joystick" + depends on I2C + help + Say Y here if you have an AS5011 digital joystick connected to your + system. + + To compile this driver as a module, choose M here: the + module will be called as5011. + config JOYSTICK_JOYDUMP tristate "Gameport data dumper" select GAMEPORT
drivers/input/joystick/Makefile +1 -0
@@ -7,6 +7,7 @@ obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o +obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o
drivers/input/joystick/as5011.c new file +367 -0
367 lines not on this page · raw message
include/linux/input/as5011.h new file +20 -0
@@ -0,0 +1,20 @@ +#ifndef _AS5011_H +#define _AS5011_H + +/* +* Copyright (c) 2010, 2011 Fabien Marteau <[email protected]> +* +* 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. +*/ + +struct as5011_platform_data { +unsigned int button_gpio; +unsigned int axis_irq;/* irq number */ +unsigned long axis_irqflags; +char xp, xn;/* threshold for x axis */ +char yp, yn;/* threshold for y axis */ +}; + +#endif /* _AS5011_H */
Hi Dmitry,
Thanks for the patch, I tested it on my platform and there is a little bug in irq request for the button :
+ error = request_threaded_irq(as5011->button_irq,
+ NULL, as5011_button_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_RISING, + "as5011_button", as5011);
Should be :
+ error = request_threaded_irq(as5011->button_irq,
+ NULL, as5011_button_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "as5011_button", as5011);
With this modification the patch is ok.
Thanks
Fabien M
ps: The patch :
Driver for EasyPoint AS5011 2 axis joystick chip. This chip is plugged on an I2C bus.
Tested on ARM processor (i.MX27).
--- drivers/input/joystick/Kconfig | 9 + drivers/input/joystick/Makefile | 1 + drivers/input/joystick/as5011.c | 368 +++++++++++++++++++++++++++++++++++++++ include/linux/input/as5011.h | 20 ++ 4 files changed, 398 insertions(+), 0 deletions(-) create mode 100644 drivers/input/joystick/as5011.c create mode 100644 include/linux/input/as5011.h
drivers/input/joystick/Kconfig +9 -0
@@ -255,6 +255,15 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. +config JOYSTICK_AS5011 + tristate "Austria Microsystem AS5011 joystick" + depends on I2C + help + Say Y here if you have an AS5011 digital joystick. + + To compile this driver as a module, choose M here: the + module will be called as5011. + config JOYSTICK_JOYDUMP tristate "Gameport data dumper" select GAMEPORT
drivers/input/joystick/Makefile +1 -0
@@ -7,6 +7,7 @@ obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o +obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o
drivers/input/joystick/as5011.c new file +368 -0
368 lines not on this page · raw message
include/linux/input/as5011.h new file +20 -0
@@ -0,0 +1,20 @@ +#ifndef _AS5011_H +#define _AS5011_H + +/* +* Copyright (c) 2010, 2011 Fabien Marteau <[email protected]> +* +* 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. +*/ + +struct as5011_platform_data { +unsigned int button_gpio; +unsigned int axis_irq;/* irq number */ +unsigned long axis_irqflags; +char xp, xn;/* threshold for x axis */ +char yp, yn;/* threshold for y axis */ +}; + +#endif /* _AS5011_H */
Signature · 1 line
1.7.0.4
Dmitry Torokhov
maintainerQuoted 16 lines · Fabien Marteau
Hi Dmitry,
Thanks for the patch, I tested it on my platform and there is a little bug in irq request for the button :
drivers/input/joystick/as5011.c new file +4
-0+ error =request_threaded_irq (as5011->button_irq, +NULL , as5011_button_interrupt, +IRQF_TRIGGER_RISING |IRQF_TRIGGER_RISING , +"as5011_button" , as5011);Should be :
drivers/input/joystick/as5011.c new file +4
-0+ error =request_threaded_irq (as5011->button_irq, +NULL , as5011_button_interrupt, +IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING , +"as5011_button" , as5011);
Quoted 2 lines
With this modification the patch is ok.
Great, I applied it.
Thanks.
Signature · 1 line
Dmitry