From 9c7c453db9cd04dc75bfeafc8f679d0f7a7ddada Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 9 Aug 2011 19:10:12 +0530 Subject: [PATCH] input: atmel-mxt-ts: Add regulator support and init. callbacks Signed-off-by: Anirudh Ghayal --- drivers/input/touchscreen/atmel_mxt_ts.c | 183 ++++++++++++++++++++++- include/linux/i2c/atmel_mxt_ts.h | 4 + 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 19d4ea65ea0..4a0e9cdb764 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -20,6 +20,7 @@ #include #include #include +#include /* Version */ #define MXT_VER_20 20 @@ -172,6 +173,14 @@ #define MXT_VOLTAGE_DEFAULT 2700000 #define MXT_VOLTAGE_STEP 10000 +#define MXT_VTG_MIN_UV 2700000 +#define MXT_VTG_MAX_UV 3300000 +#define MXT_ACTIVE_LOAD_UA 15000 + +#define MXT_I2C_VTG_MIN_UV 1800000 +#define MXT_I2C_VTG_MAX_UV 1800000 +#define MXT_I2C_LOAD_UA 10000 + /* Define for MXT_GEN_COMMAND_T6 */ #define MXT_BOOT_VALUE 0xa5 #define MXT_BACKUP_VALUE 0x55 @@ -258,6 +267,8 @@ struct mxt_data { unsigned int irq; unsigned int max_x; unsigned int max_y; + struct regulator *vcc; + struct regulator *vcc_i2c; }; static bool mxt_object_readable(unsigned int type) @@ -1092,6 +1103,135 @@ static void mxt_input_close(struct input_dev *dev) mxt_stop(data); } +static int mxt_power_on(struct mxt_data *data, bool on) +{ + int rc; + + if (on == false) + goto power_off; + + rc = regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA); + if (rc < 0) { + dev_err(&data->client->dev, "Regulator set_opt failed rc=%d\n", + rc); + return rc; + } + + rc = regulator_enable(data->vcc); + if (rc) { + dev_err(&data->client->dev, "Regulator enable failed rc=%d\n", + rc); + goto error_reg_en_vcc; + } + + if (data->pdata->i2c_pull_up) { + rc = regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA); + if (rc < 0) { + dev_err(&data->client->dev, + "Regulator set_opt failed rc=%d\n", rc); + goto error_reg_opt_i2c; + } + + rc = regulator_enable(data->vcc_i2c); + if (rc) { + dev_err(&data->client->dev, + "Regulator enable failed rc=%d\n", rc); + goto error_reg_en_vcc_i2c; + } + } + + msleep(50); + + return 0; + +error_reg_en_vcc_i2c: + if (data->pdata->i2c_pull_up) + regulator_set_optimum_mode(data->vcc_i2c, 0); +error_reg_opt_i2c: + regulator_disable(data->vcc); +error_reg_en_vcc: + regulator_set_optimum_mode(data->vcc, 0); + return rc; + +power_off: + regulator_set_optimum_mode(data->vcc, 0); + regulator_disable(data->vcc); + if (data->pdata->i2c_pull_up) { + regulator_set_optimum_mode(data->vcc_i2c, 0); + regulator_disable(data->vcc_i2c); + } + msleep(50); + return 0; +} + +static int mxt_regulator_configure(struct mxt_data *data, bool on) +{ + int rc; + + if (on == false) + goto hw_shutdown; + + data->vcc = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vcc)) { + rc = PTR_ERR(data->vcc); + dev_err(&data->client->dev, "Regulator get failed rc=%d\n", + rc); + return rc; + } + + if (regulator_count_voltages(data->vcc) > 0) { + rc = regulator_set_voltage(data->vcc, MXT_VTG_MIN_UV, + MXT_VTG_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_vcc; + } + } + + if (data->pdata->i2c_pull_up) { + data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c"); + if (IS_ERR(data->vcc_i2c)) { + rc = PTR_ERR(data->vcc_i2c); + dev_err(&data->client->dev, + "Regulator get failed rc=%d\n", rc); + goto error_get_vtg_i2c; + } + if (regulator_count_voltages(data->vcc_i2c) > 0) { + rc = regulator_set_voltage(data->vcc_i2c, + MXT_I2C_VTG_MIN_UV, MXT_I2C_VTG_MAX_UV); + if (rc) { + dev_err(&data->client->dev, + "regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_i2c; + } + } + } + + return 0; + +error_set_vtg_i2c: + regulator_put(data->vcc_i2c); +error_get_vtg_i2c: + if (regulator_count_voltages(data->vcc) > 0) + regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV); +error_set_vtg_vcc: + regulator_put(data->vcc); + return rc; + +hw_shutdown: + if (regulator_count_voltages(data->vcc) > 0) + regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV); + regulator_put(data->vcc); + if (data->pdata->i2c_pull_up) { + if (regulator_count_voltages(data->vcc_i2c) > 0) + regulator_set_voltage(data->vcc_i2c, 0, + MXT_I2C_VTG_MAX_UV); + regulator_put(data->vcc_i2c); + } + return 0; +} + static int __devinit mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1150,15 +1290,33 @@ static int __devinit mxt_probe(struct i2c_client *client, input_set_drvdata(input_dev, data); i2c_set_clientdata(client, data); + if (pdata->init_hw) + error = pdata->init_hw(true); + else + error = mxt_regulator_configure(data, true); + if (error) { + dev_err(&client->dev, "Failed to intialize hardware\n"); + goto err_free_object; + } + + if (pdata->power_on) + error = pdata->power_on(true); + else + error = mxt_power_on(data, true); + if (error) { + dev_err(&client->dev, "Failed to power on hardware\n"); + goto err_regulator_on; + } + error = mxt_initialize(data); if (error) - goto err_free_object; + goto err_power_on; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, pdata->irqflags, client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_object; + goto err_power_on; } error = mxt_make_highchg(data); @@ -1180,6 +1338,16 @@ err_unregister_device: input_dev = NULL; err_free_irq: free_irq(client->irq, data); +err_power_on: + if (pdata->power_on) + pdata->power_on(false); + else + mxt_power_on(data, false); +err_regulator_on: + if (pdata->init_hw) + pdata->init_hw(false); + else + mxt_regulator_configure(data, false); err_free_object: kfree(data->object_table); err_free_mem: @@ -1195,6 +1363,17 @@ static int __devexit mxt_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); free_irq(data->irq, data); input_unregister_device(data->input_dev); + + if (data->pdata->power_on) + data->pdata->power_on(false); + else + mxt_power_on(data, false); + + if (data->pdata->init_hw) + data->pdata->init_hw(false); + else + mxt_regulator_configure(data, false); + kfree(data->object_table); kfree(data); diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h index f027f7a6351..b0cb4342358 100644 --- a/include/linux/i2c/atmel_mxt_ts.h +++ b/include/linux/i2c/atmel_mxt_ts.h @@ -39,6 +39,10 @@ struct mxt_platform_data { unsigned int voltage; unsigned char orient; unsigned long irqflags; + bool i2c_pull_up; + + int (*init_hw) (bool); + int (*power_on) (bool); }; #endif /* __LINUX_ATMEL_MXT_TS_H */