Merge "input: misc: pat9125: add gpio configuration and pinctrl support"

This commit is contained in:
Linux Build Service Account 2016-10-15 07:37:46 -07:00 committed by Gerrit - the friendly Code Review server
commit 1f47d424c4
3 changed files with 139 additions and 26 deletions

View file

@ -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-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
- 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:
- pixart,press-keycode : keycode to be sent when press is detected by the driver.
@ -26,4 +45,10 @@ Example:
interrupt-parent = <&msm_gpio>;
interrupts = <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>;
};

View file

@ -18,11 +18,14 @@ struct pixart_pat9125_data {
struct i2c_client *client;
struct input_dev *input;
int irq_gpio;
u32 irq_flags;
u32 press_keycode;
bool press_en;
bool inverse_x;
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,
@ -197,6 +200,44 @@ static struct attribute_group pat9125_attr_grp = {
.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,
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;
}
@ -272,24 +316,39 @@ static int pat9125_i2c_probe(struct i2c_client *client,
err = input_register_device(data->input);
if (err < 0) {
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;
}
err = gpio_direction_input(data->irq_gpio);
if (err) {
dev_err(dev, "unable to set dir for gpio %d\n", data->irq_gpio);
goto free_gpio;
err = pixart_pinctrl_init(data);
if (!err && data->pinctrl) {
/*
* 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)) {
@ -316,33 +375,59 @@ static int pat9125_i2c_probe(struct i2c_client *client,
err_sysfs_create:
err_request_threaded_irq:
err_sensor_init:
free_gpio:
gpio_free(data->irq_gpio);
err_register_input_device:
input_free_device(data->input);
if (data->pinctrl)
if (pinctrl_select_state(data->pinctrl,
data->pinctrl_state_release) < 0)
dev_err(dev, "Couldn't set pin to release state\n");
return err;
}
static int pat9125_i2c_remove(struct i2c_client *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 (gpio_is_valid(data->irq_gpio))
gpio_free(data->irq_gpio);
input_unregister_device(data->input);
devm_kfree(&client->dev, data);
data = NULL;
if (data->pinctrl)
if (pinctrl_select_state(data->pinctrl,
data->pinctrl_state_release) < 0)
dev_err(dev, "Couldn't set pin to release state\n");
return 0;
}
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;
}
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;
}

View file

@ -10,6 +10,9 @@
#define PAT9125_DEV_NAME "pixart_pat9125"
#define MAX_BUF_SIZE 20
#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 */
#define PIXART_PAT9125_PRODUCT_ID1_REG 0x00