Merge "input: pat9125: add support of sending rotating switch events"
This commit is contained in:
commit
a1c6e317af
3 changed files with 112 additions and 6 deletions
|
@ -6,5 +6,24 @@ to the Host processor. The host processor reads the direction and number of
|
||||||
steps over I2C and passes the data to the rest of the system.
|
steps over I2C and passes the data to the rest of the system.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
|
- compatible : should be "pixart,pat9125".
|
||||||
|
- reg : i2c slave address of the device.
|
||||||
|
- interrupt-parent : parent of interrupt.
|
||||||
|
- interrupts : interrupt to indicate motion of the rotating switch.
|
||||||
|
|
||||||
- compatible : should be "pixart,pat9125".
|
Optional properties:
|
||||||
|
- pixart,inverse-x : boolean, use this to invert the x data before sending it to input framework
|
||||||
|
- pixart,inverse-y : boolean, use this to invert the y data before sending it to input framework
|
||||||
|
- pixart,press-enabled : boolean, use this to enable detection of pressing the button
|
||||||
|
|
||||||
|
Required properties if 'pixart,press-enabled' DT property is defined:
|
||||||
|
- pixart,press-keycode : keycode to be sent when press is detected by the driver.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
pixart_pat9125@75 {
|
||||||
|
compatible = "pixart,pat9125";
|
||||||
|
reg = <0x75>;
|
||||||
|
interrupt-parent = <&msm_gpio>;
|
||||||
|
interrupts = <98 0x2008>;
|
||||||
|
pixart,irq-gpio = <&msm_gpio 98 0x2008>;
|
||||||
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include "pixart_ots.h"
|
#include "pixart_ots.h"
|
||||||
|
|
||||||
struct pixart_pat9125_data {
|
struct pixart_pat9125_data {
|
||||||
|
@ -18,6 +19,10 @@ struct pixart_pat9125_data {
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
int irq_gpio;
|
int irq_gpio;
|
||||||
u32 irq_flags;
|
u32 irq_flags;
|
||||||
|
u32 press_keycode;
|
||||||
|
bool press_en;
|
||||||
|
bool inverse_x;
|
||||||
|
bool inverse_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data,
|
static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data,
|
||||||
|
@ -70,7 +75,7 @@ static int pat9125_i2c_read(struct i2c_client *client, u8 reg, u8 *data)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char read_data(struct i2c_client *client, u8 addr)
|
u8 read_data(struct i2c_client *client, u8 addr)
|
||||||
{
|
{
|
||||||
u8 data = 0xff;
|
u8 data = 0xff;
|
||||||
|
|
||||||
|
@ -83,8 +88,55 @@ void write_data(struct i2c_client *client, u8 addr, u8 data)
|
||||||
pat9125_i2c_write(client, addr, &data, 1);
|
pat9125_i2c_write(client, addr, &data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t pixart_pat9125_irq(int irq, void *data)
|
static irqreturn_t pat9125_irq(int irq, void *dev_data)
|
||||||
{
|
{
|
||||||
|
u8 delta_x = 0, delta_y = 0, motion;
|
||||||
|
struct pixart_pat9125_data *data = dev_data;
|
||||||
|
struct input_dev *ipdev = data->input;
|
||||||
|
struct device *dev = &data->client->dev;
|
||||||
|
|
||||||
|
motion = read_data(data->client, PIXART_PAT9125_MOTION_STATUS_REG);
|
||||||
|
do {
|
||||||
|
/* check if MOTION bit is set or not */
|
||||||
|
if (motion & PIXART_PAT9125_VALID_MOTION_DATA) {
|
||||||
|
delta_x = read_data(data->client,
|
||||||
|
PIXART_PAT9125_DELTA_X_LO_REG);
|
||||||
|
delta_y = read_data(data->client,
|
||||||
|
PIXART_PAT9125_DELTA_Y_LO_REG);
|
||||||
|
|
||||||
|
/* Inverse x depending upon the device orientation */
|
||||||
|
delta_x = (data->inverse_x) ? -delta_x : delta_x;
|
||||||
|
/* Inverse y depending upon the device orientation */
|
||||||
|
delta_y = (data->inverse_y) ? -delta_y : delta_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(dev, "motion = %x, delta_x = %x, delta_y = %x\n",
|
||||||
|
motion, delta_x, delta_y);
|
||||||
|
|
||||||
|
if (delta_x != 0) {
|
||||||
|
/* Send delta_x as REL_WHEEL for rotation */
|
||||||
|
input_report_rel(ipdev, REL_WHEEL, (s8) delta_x);
|
||||||
|
input_sync(ipdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->press_en && delta_y != 0) {
|
||||||
|
if ((s8) delta_y > 0) {
|
||||||
|
/* Send DOWN event for press keycode */
|
||||||
|
input_report_key(ipdev, data->press_keycode, 1);
|
||||||
|
input_sync(ipdev);
|
||||||
|
} else {
|
||||||
|
/* Send UP event for press keycode */
|
||||||
|
input_report_key(ipdev, data->press_keycode, 0);
|
||||||
|
input_sync(ipdev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usleep_range(PIXART_SAMPLING_PERIOD_US_MIN,
|
||||||
|
PIXART_SAMPLING_PERIOD_US_MAX);
|
||||||
|
|
||||||
|
motion = read_data(data->client,
|
||||||
|
PIXART_PAT9125_MOTION_STATUS_REG);
|
||||||
|
} while (motion & PIXART_PAT9125_VALID_MOTION_DATA);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,13 +197,36 @@ static struct attribute_group pat9125_attr_grp = {
|
||||||
.attrs = pat9125_attr_list,
|
.attrs = pat9125_attr_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int pat9125_parse_dt(struct device *dev,
|
||||||
|
struct pixart_pat9125_data *data)
|
||||||
|
{
|
||||||
|
struct device_node *np = dev->of_node;
|
||||||
|
u32 temp_val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data->inverse_x = of_property_read_bool(np, "pixart,inverse-x");
|
||||||
|
data->inverse_y = of_property_read_bool(np, "pixart,inverse-y");
|
||||||
|
data->press_en = of_property_read_bool(np, "pixart,press-enabled");
|
||||||
|
if (data->press_en) {
|
||||||
|
ret = of_property_read_u32(np, "pixart,press-keycode",
|
||||||
|
&temp_val);
|
||||||
|
if (!ret) {
|
||||||
|
data->press_keycode = temp_val;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Unable to parse press-keycode\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int pat9125_i2c_probe(struct i2c_client *client,
|
static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct pixart_pat9125_data *data;
|
struct pixart_pat9125_data *data;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct device_node *np;
|
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
|
|
||||||
err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
|
err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
|
||||||
|
@ -165,6 +240,11 @@ static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
err = pat9125_parse_dt(dev, data);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "DT parsing failed, errno:%d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data = client->dev.platform_data;
|
data = client->dev.platform_data;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -180,6 +260,10 @@ static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input_set_capability(input, EV_REL, REL_WHEEL);
|
||||||
|
if (data->press_en)
|
||||||
|
input_set_capability(input, EV_KEY, data->press_keycode);
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
input_set_drvdata(input, data);
|
input_set_drvdata(input, data);
|
||||||
input->name = PAT9125_DEV_NAME;
|
input->name = PAT9125_DEV_NAME;
|
||||||
|
@ -213,8 +297,8 @@ static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
goto err_sensor_init;
|
goto err_sensor_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = devm_request_threaded_irq(dev, client->irq, NULL,
|
err = devm_request_threaded_irq(dev, client->irq, NULL, pat9125_irq,
|
||||||
pixart_pat9125_irq, (unsigned long)data->irq_flags,
|
IRQF_ONESHOT | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW,
|
||||||
"pixart_pat9125_irq", data);
|
"pixart_pat9125_irq", data);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err);
|
dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err);
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
#define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04
|
#define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04
|
||||||
#define PIXART_PAT9125_VALID_MOTION_DATA 0x80
|
#define PIXART_PAT9125_VALID_MOTION_DATA 0x80
|
||||||
|
|
||||||
|
#define PIXART_SAMPLING_PERIOD_US_MIN 4000
|
||||||
|
#define PIXART_SAMPLING_PERIOD_US_MAX 8000
|
||||||
|
|
||||||
/* Export functions */
|
/* Export functions */
|
||||||
bool ots_sensor_init(struct i2c_client *);
|
bool ots_sensor_init(struct i2c_client *);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue