Loading Documentation/devicetree/bindings/input/pixart-pat9125-switch.txt +20 −1 Original line number Diff line number Diff line Loading @@ -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. 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. 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>; }; drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +89 −5 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/of_gpio.h> #include <linux/delay.h> #include "pixart_ots.h" struct pixart_pat9125_data { Loading @@ -18,6 +19,10 @@ struct pixart_pat9125_data { struct input_dev *input; int irq_gpio; 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, Loading Loading @@ -70,7 +75,7 @@ static int pat9125_i2c_read(struct i2c_client *client, u8 reg, u8 *data) return ret; } unsigned char read_data(struct i2c_client *client, u8 addr) u8 read_data(struct i2c_client *client, u8 addr) { u8 data = 0xff; Loading @@ -83,8 +88,55 @@ void write_data(struct i2c_client *client, u8 addr, u8 data) 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; } Loading Loading @@ -145,13 +197,36 @@ static struct attribute_group pat9125_attr_grp = { .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, const struct i2c_device_id *id) { int err = 0; struct pixart_pat9125_data *data; struct input_dev *input; struct device_node *np; struct device *dev = &client->dev; err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); Loading @@ -165,6 +240,11 @@ static int pat9125_i2c_probe(struct i2c_client *client, GFP_KERNEL); if (!data) return -ENOMEM; err = pat9125_parse_dt(dev, data); if (err) { dev_err(dev, "DT parsing failed, errno:%d\n", err); return err; } } else { data = client->dev.platform_data; if (!data) { Loading @@ -180,6 +260,10 @@ static int pat9125_i2c_probe(struct i2c_client *client, 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); input_set_drvdata(input, data); input->name = PAT9125_DEV_NAME; Loading Loading @@ -213,8 +297,8 @@ static int pat9125_i2c_probe(struct i2c_client *client, goto err_sensor_init; } err = devm_request_threaded_irq(dev, client->irq, NULL, pixart_pat9125_irq, (unsigned long)data->irq_flags, err = devm_request_threaded_irq(dev, client->irq, NULL, pat9125_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW, "pixart_pat9125_irq", data); if (err) { dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err); Loading drivers/input/misc/ots_pat9125/pixart_ots.h +3 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,9 @@ #define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04 #define PIXART_PAT9125_VALID_MOTION_DATA 0x80 #define PIXART_SAMPLING_PERIOD_US_MIN 4000 #define PIXART_SAMPLING_PERIOD_US_MAX 8000 /* Export functions */ bool ots_sensor_init(struct i2c_client *); Loading Loading
Documentation/devicetree/bindings/input/pixart-pat9125-switch.txt +20 −1 Original line number Diff line number Diff line Loading @@ -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. 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. 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>; };
drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +89 −5 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/of_gpio.h> #include <linux/delay.h> #include "pixart_ots.h" struct pixart_pat9125_data { Loading @@ -18,6 +19,10 @@ struct pixart_pat9125_data { struct input_dev *input; int irq_gpio; 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, Loading Loading @@ -70,7 +75,7 @@ static int pat9125_i2c_read(struct i2c_client *client, u8 reg, u8 *data) return ret; } unsigned char read_data(struct i2c_client *client, u8 addr) u8 read_data(struct i2c_client *client, u8 addr) { u8 data = 0xff; Loading @@ -83,8 +88,55 @@ void write_data(struct i2c_client *client, u8 addr, u8 data) 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; } Loading Loading @@ -145,13 +197,36 @@ static struct attribute_group pat9125_attr_grp = { .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, const struct i2c_device_id *id) { int err = 0; struct pixart_pat9125_data *data; struct input_dev *input; struct device_node *np; struct device *dev = &client->dev; err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); Loading @@ -165,6 +240,11 @@ static int pat9125_i2c_probe(struct i2c_client *client, GFP_KERNEL); if (!data) return -ENOMEM; err = pat9125_parse_dt(dev, data); if (err) { dev_err(dev, "DT parsing failed, errno:%d\n", err); return err; } } else { data = client->dev.platform_data; if (!data) { Loading @@ -180,6 +260,10 @@ static int pat9125_i2c_probe(struct i2c_client *client, 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); input_set_drvdata(input, data); input->name = PAT9125_DEV_NAME; Loading Loading @@ -213,8 +297,8 @@ static int pat9125_i2c_probe(struct i2c_client *client, goto err_sensor_init; } err = devm_request_threaded_irq(dev, client->irq, NULL, pixart_pat9125_irq, (unsigned long)data->irq_flags, err = devm_request_threaded_irq(dev, client->irq, NULL, pat9125_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW, "pixart_pat9125_irq", data); if (err) { dev_err(dev, "Req irq %d failed, errno:%d\n", client->irq, err); Loading
drivers/input/misc/ots_pat9125/pixart_ots.h +3 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,9 @@ #define PIXART_PAT9125_LOW_VOLTAGE_SEGMENT 0x04 #define PIXART_PAT9125_VALID_MOTION_DATA 0x80 #define PIXART_SAMPLING_PERIOD_US_MIN 4000 #define PIXART_SAMPLING_PERIOD_US_MAX 8000 /* Export functions */ bool ots_sensor_init(struct i2c_client *); Loading