Merge "input: misc: pat9125: add gpio configuration and pinctrl support"
This commit is contained in:
commit
1f47d424c4
3 changed files with 139 additions and 26 deletions
|
@ -15,6 +15,25 @@ Optional properties:
|
||||||
- pixart,inverse-x : boolean, use this to invert the x data before sending it to input framework
|
- 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,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
|
- pixart,press-enabled : boolean, use this to enable detection of pressing the button
|
||||||
|
- pinctrl-names : This should be defined if a target uses pinctrl framework.
|
||||||
|
See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt
|
||||||
|
It should specify the names of the configs that pinctrl can
|
||||||
|
install in driver.
|
||||||
|
Following are the pinctrl configs that can be installed:
|
||||||
|
"pmx_rot_switch_active" : Active configuration of pins,
|
||||||
|
it should specify active config
|
||||||
|
defined in pin groups of
|
||||||
|
interrupt gpio.
|
||||||
|
"pmx_rot_switch_suspend" : Disabled configuration of
|
||||||
|
pins, it should specify sleep
|
||||||
|
config defined in pin groups
|
||||||
|
of interrupt gpio.
|
||||||
|
"pmx_rot_switch_release" : Release configuration of
|
||||||
|
pins, it should specify release
|
||||||
|
config defined in pin groups of
|
||||||
|
interrupt gpio.
|
||||||
|
- pixart,irq-gpio : This should be defined if a target doesn't use pinctrl framework.
|
||||||
|
irq gpio, which is to provide interrupts to host, same as "interrupts" node.
|
||||||
|
|
||||||
Required properties if 'pixart,press-enabled' DT property is defined:
|
Required properties if 'pixart,press-enabled' DT property is defined:
|
||||||
- pixart,press-keycode : keycode to be sent when press is detected by the driver.
|
- pixart,press-keycode : keycode to be sent when press is detected by the driver.
|
||||||
|
@ -26,4 +45,10 @@ Example:
|
||||||
interrupt-parent = <&msm_gpio>;
|
interrupt-parent = <&msm_gpio>;
|
||||||
interrupts = <98 0x2008>;
|
interrupts = <98 0x2008>;
|
||||||
pixart,irq-gpio = <&msm_gpio 98 0x2008>;
|
pixart,irq-gpio = <&msm_gpio 98 0x2008>;
|
||||||
|
pinctrl-names = "pmx_rot_switch_active",
|
||||||
|
"pmx_rot_switch_suspend",
|
||||||
|
"pmx_rot_switch_release";
|
||||||
|
pinctrl-0 = <&pix_int_active>;
|
||||||
|
pinctrl-1 = <&pix_int_suspend>;
|
||||||
|
pinctrl-2 = <&pix_release>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,11 +18,14 @@ struct pixart_pat9125_data {
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
int irq_gpio;
|
int irq_gpio;
|
||||||
u32 irq_flags;
|
|
||||||
u32 press_keycode;
|
u32 press_keycode;
|
||||||
bool press_en;
|
bool press_en;
|
||||||
bool inverse_x;
|
bool inverse_x;
|
||||||
bool inverse_y;
|
bool inverse_y;
|
||||||
|
struct pinctrl *pinctrl;
|
||||||
|
struct pinctrl_state *pinctrl_state_active;
|
||||||
|
struct pinctrl_state *pinctrl_state_suspend;
|
||||||
|
struct pinctrl_state *pinctrl_state_release;
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
||||||
|
@ -197,6 +200,44 @@ static struct attribute_group pat9125_attr_grp = {
|
||||||
.attrs = pat9125_attr_list,
|
.attrs = pat9125_attr_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int pixart_pinctrl_init(struct pixart_pat9125_data *data)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct device *dev = &data->client->dev;
|
||||||
|
|
||||||
|
data->pinctrl = devm_pinctrl_get(&(data->client->dev));
|
||||||
|
if (IS_ERR_OR_NULL(data->pinctrl)) {
|
||||||
|
err = PTR_ERR(data->pinctrl);
|
||||||
|
dev_err(dev, "Target does not use pinctrl %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->pinctrl_state_active = pinctrl_lookup_state(data->pinctrl,
|
||||||
|
PINCTRL_STATE_ACTIVE);
|
||||||
|
if (IS_ERR_OR_NULL(data->pinctrl_state_active)) {
|
||||||
|
err = PTR_ERR(data->pinctrl_state_active);
|
||||||
|
dev_err(dev, "Can not lookup active pinctrl state %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->pinctrl_state_suspend = pinctrl_lookup_state(data->pinctrl,
|
||||||
|
PINCTRL_STATE_SUSPEND);
|
||||||
|
if (IS_ERR_OR_NULL(data->pinctrl_state_suspend)) {
|
||||||
|
err = PTR_ERR(data->pinctrl_state_suspend);
|
||||||
|
dev_err(dev, "Can not lookup suspend pinctrl state %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->pinctrl_state_release = pinctrl_lookup_state(data->pinctrl,
|
||||||
|
PINCTRL_STATE_RELEASE);
|
||||||
|
if (IS_ERR_OR_NULL(data->pinctrl_state_release)) {
|
||||||
|
err = PTR_ERR(data->pinctrl_state_release);
|
||||||
|
dev_err(dev, "Can not lookup release pinctrl state %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int pat9125_parse_dt(struct device *dev,
|
static int pat9125_parse_dt(struct device *dev,
|
||||||
struct pixart_pat9125_data *data)
|
struct pixart_pat9125_data *data)
|
||||||
{
|
{
|
||||||
|
@ -218,6 +259,9 @@ static int pat9125_parse_dt(struct device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->irq_gpio = of_get_named_gpio_flags(np, "pixart,irq-gpio",
|
||||||
|
0, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,24 +316,39 @@ static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
err = input_register_device(data->input);
|
err = input_register_device(data->input);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(dev, "Failed to register input device\n");
|
dev_err(dev, "Failed to register input device\n");
|
||||||
goto err_register_input_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gpio_is_valid(data->irq_gpio)) {
|
|
||||||
dev_err(dev, "invalid irq_gpio: %d\n", data->irq_gpio);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = gpio_request(data->irq_gpio, "pixart_pat9125_irq_gpio");
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "unable to request gpio %d\n", data->irq_gpio);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gpio_direction_input(data->irq_gpio);
|
err = pixart_pinctrl_init(data);
|
||||||
if (err) {
|
if (!err && data->pinctrl) {
|
||||||
dev_err(dev, "unable to set dir for gpio %d\n", data->irq_gpio);
|
/*
|
||||||
goto free_gpio;
|
* Pinctrl handle is optional. If pinctrl handle is found
|
||||||
|
* let pins to be configured in active state. If not
|
||||||
|
* found continue further without error.
|
||||||
|
*/
|
||||||
|
err = pinctrl_select_state(data->pinctrl,
|
||||||
|
data->pinctrl_state_active);
|
||||||
|
if (err < 0)
|
||||||
|
dev_err(dev, "Could not set pin to active state %d\n",
|
||||||
|
err);
|
||||||
|
} else {
|
||||||
|
if (gpio_is_valid(data->irq_gpio)) {
|
||||||
|
err = devm_gpio_request(dev, data->irq_gpio,
|
||||||
|
"pixart_pat9125_irq_gpio");
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Couldn't request gpio %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = gpio_direction_input(data->irq_gpio);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Couldn't set dir for gpio %d\n",
|
||||||
|
err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Invalid gpio %d\n", data->irq_gpio);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ots_sensor_init(client)) {
|
if (!ots_sensor_init(client)) {
|
||||||
|
@ -316,33 +375,59 @@ static int pat9125_i2c_probe(struct i2c_client *client,
|
||||||
err_sysfs_create:
|
err_sysfs_create:
|
||||||
err_request_threaded_irq:
|
err_request_threaded_irq:
|
||||||
err_sensor_init:
|
err_sensor_init:
|
||||||
free_gpio:
|
if (data->pinctrl)
|
||||||
gpio_free(data->irq_gpio);
|
if (pinctrl_select_state(data->pinctrl,
|
||||||
err_register_input_device:
|
data->pinctrl_state_release) < 0)
|
||||||
input_free_device(data->input);
|
dev_err(dev, "Couldn't set pin to release state\n");
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pat9125_i2c_remove(struct i2c_client *client)
|
static int pat9125_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct pixart_pat9125_data *data = i2c_get_clientdata(client);
|
struct pixart_pat9125_data *data = i2c_get_clientdata(client);
|
||||||
|
struct device *dev = &data->client->dev;
|
||||||
|
|
||||||
devm_free_irq(&client->dev, client->irq, data);
|
if (data->pinctrl)
|
||||||
if (gpio_is_valid(data->irq_gpio))
|
if (pinctrl_select_state(data->pinctrl,
|
||||||
gpio_free(data->irq_gpio);
|
data->pinctrl_state_release) < 0)
|
||||||
input_unregister_device(data->input);
|
dev_err(dev, "Couldn't set pin to release state\n");
|
||||||
devm_kfree(&client->dev, data);
|
|
||||||
data = NULL;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pat9125_suspend(struct device *dev)
|
static int pat9125_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
struct pixart_pat9125_data *data =
|
||||||
|
(struct pixart_pat9125_data *)dev->driver_data;
|
||||||
|
|
||||||
|
disable_irq(data->client->irq);
|
||||||
|
if (data->pinctrl) {
|
||||||
|
rc = pinctrl_select_state(data->pinctrl,
|
||||||
|
data->pinctrl_state_suspend);
|
||||||
|
if (rc < 0)
|
||||||
|
dev_err(dev, "Could not set pin to suspend state %d\n",
|
||||||
|
rc);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pat9125_resume(struct device *dev)
|
static int pat9125_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
struct pixart_pat9125_data *data =
|
||||||
|
(struct pixart_pat9125_data *)dev->driver_data;
|
||||||
|
|
||||||
|
if (data->pinctrl) {
|
||||||
|
rc = pinctrl_select_state(data->pinctrl,
|
||||||
|
data->pinctrl_state_active);
|
||||||
|
if (rc < 0)
|
||||||
|
dev_err(dev, "Could not set pin to active state %d\n",
|
||||||
|
rc);
|
||||||
|
}
|
||||||
|
enable_irq(data->client->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#define PAT9125_DEV_NAME "pixart_pat9125"
|
#define PAT9125_DEV_NAME "pixart_pat9125"
|
||||||
#define MAX_BUF_SIZE 20
|
#define MAX_BUF_SIZE 20
|
||||||
#define RESET_DELAY_US 1000
|
#define RESET_DELAY_US 1000
|
||||||
|
#define PINCTRL_STATE_ACTIVE "pmx_rot_switch_active"
|
||||||
|
#define PINCTRL_STATE_SUSPEND "pmx_rot_switch_suspend"
|
||||||
|
#define PINCTRL_STATE_RELEASE "pmx_rot_switch_release"
|
||||||
|
|
||||||
/* Register addresses */
|
/* Register addresses */
|
||||||
#define PIXART_PAT9125_PRODUCT_ID1_REG 0x00
|
#define PIXART_PAT9125_PRODUCT_ID1_REG 0x00
|
||||||
|
|
Loading…
Add table
Reference in a new issue