From 00ade0eb5af35213ff44ae02d2d79d173655d7b1 Mon Sep 17 00:00:00 2001 From: Naga Radhesh Date: Mon, 5 Dec 2011 16:58:11 +0530 Subject: [ANDROID]:input:lps001wp_prs:add regulator,sysfs add regulator,sysfs paths and add error handling in all error cases. ST-Ericsson ID: 371766 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: Trivial Change-Id:I9efe9ab97b1a7d051d26e7a803aa7cecccc4d6f4 Signed-off-by: Naga Radhesh Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/41011 Reviewed-by: QATOOLS Reviewed-by: QABUILD Reviewed-by: Srinidhi KASAGAR --- drivers/input/misc/lps001wp_prs.c | 249 +++++++++++++++++++++++++++++++------- 1 file changed, 207 insertions(+), 42 deletions(-) diff --git a/drivers/input/misc/lps001wp_prs.c b/drivers/input/misc/lps001wp_prs.c index 65f9ca7891b..c6c29c34c45 100644 --- a/drivers/input/misc/lps001wp_prs.c +++ b/drivers/input/misc/lps001wp_prs.c @@ -68,7 +68,7 @@ #define OUTDATA_REG 0x28 -#define INDATA_REG 0X30 +#define REF_PRESS_REG 0X30 #define WHOAMI_LPS001WP_PRS 0xBA /* Expctd content for WAI */ @@ -83,7 +83,7 @@ #define PRESS_OUT_L OUTDATA_REG -#define REF_P_L INDATA_REG /* pressure reference */ +#define REF_P_L REF_PRESS_REG /* pressure reference */ #define REF_P_H 0x31 /* pressure reference */ #define THS_P_L 0x32 /* pressure threshold */ #define THS_P_H 0x33 /* pressure threshold */ @@ -144,6 +144,24 @@ static const struct { {1000, LPS001WP_PRS_ODR_7_1 }, }; +/** + * struct lps001wp_prs_data - data structure used by lps001wp_prs driver + * @client: i2c client + * @pdata: lsm303dlh platform data + * @lock: mutex lock for sysfs operations + * @input_work: work queue to read sensor data + * @input_dev: input device + * @regulator: regulator + * @early_suspend: early suspend structure + * @hw_initialized: saves hw initialisation status + * @hw_working: saves hw status + * @diff_enabled: store value of diff enable + * @lpowmode_enabled: flag to set lowpower mode + * @enabled: to store mode of device + * @on_before_suspend: to store status of device during suspend + * @resume_state:store regester values + * @reg_addr: stores reg address to debug + */ struct lps001wp_prs_data { struct i2c_client *client; struct lps001wp_prs_platform_data *pdata; @@ -249,7 +267,7 @@ static int lps001wp_prs_i2c_write(struct lps001wp_prs_data *prs, static int lps001wp_prs_register_write(struct lps001wp_prs_data *prs, u8 *buf, u8 reg_address, u8 new_value) { - int err = -1; + int err = -EINVAL; /* Sets configuration register at reg_address * NOTE: this is a straight overwrite */ @@ -265,7 +283,7 @@ static int lps001wp_prs_register_read(struct lps001wp_prs_data *prs, u8 *buf, u8 reg_address) { - int err = -1; + int err = -EINVAL; buf[0] = (reg_address); err = lps001wp_prs_i2c_read(prs, buf, 1); @@ -275,7 +293,7 @@ static int lps001wp_prs_register_read(struct lps001wp_prs_data *prs, u8 *buf, static int lps001wp_prs_register_update(struct lps001wp_prs_data *prs, u8 *buf, u8 reg_address, u8 mask, u8 new_bit_values) { - int err = -1; + int err = -EINVAL; u8 init_val; u8 updated_val; err = lps001wp_prs_register_read(prs, buf, reg_address); @@ -293,10 +311,11 @@ static int lps001wp_prs_register_update(struct lps001wp_prs_data *prs, u8 *buf, static int lps001wp_prs_hw_init(struct lps001wp_prs_data *prs) { - int err = -1; + int err = -EINVAL; u8 buf[6]; - printk(KERN_DEBUG "%s: hw init start\n", LPS001WP_PRS_DEV_NAME); + dev_dbg(&prs->client->dev, "%s: hw init start\n", + LPS001WP_PRS_DEV_NAME); buf[0] = WHO_AM_I; err = lps001wp_prs_i2c_read(prs, buf, 1); @@ -305,12 +324,12 @@ static int lps001wp_prs_hw_init(struct lps001wp_prs_data *prs) else prs->hw_working = 1; if (buf[0] != WHOAMI_LPS001WP_PRS) { - err = -1; /* TODO:choose the right coded error */ + err = -EINVAL; /* TODO:choose the right coded error */ goto error_unknown_device; } - buf[0] = (I2C_AUTO_INCREMENT | INDATA_REG); + buf[0] = (I2C_AUTO_INCREMENT | REF_PRESS_REG); buf[1] = prs->resume_state[RES_REF_P_L]; buf[2] = prs->resume_state[RES_REF_P_H]; buf[3] = prs->resume_state[RES_THS_P_L]; @@ -335,7 +354,7 @@ static int lps001wp_prs_hw_init(struct lps001wp_prs_data *prs) prs->hw_initialized = 1; - printk(KERN_DEBUG "%s: hw init done\n", LPS001WP_PRS_DEV_NAME); + dev_dbg(&prs->client->dev, "%s: hw init done\n", LPS001WP_PRS_DEV_NAME); return 0; error_firstread: @@ -378,7 +397,7 @@ static void lps001wp_prs_device_power_off(struct lps001wp_prs_data *prs) static int lps001wp_prs_device_power_on(struct lps001wp_prs_data *prs) { - int err = -1; + int err = -EINVAL; /* get the regulator the first time */ if (!prs->regulator) { @@ -412,7 +431,7 @@ static int lps001wp_prs_device_power_on(struct lps001wp_prs_data *prs) int lps001wp_prs_update_odr(struct lps001wp_prs_data *prs, int poll_interval_ms) { - int err = -1; + int err = -EINVAL; int i; u8 buf[2]; @@ -463,12 +482,17 @@ error: static int lps001wp_prs_set_press_reference(struct lps001wp_prs_data *prs, u16 new_reference) { - int err = -1; + int err = -EINVAL; u8 const reg_addressL = REF_P_L; u8 const reg_addressH = REF_P_H; u8 bit_valuesL, bit_valuesH; u8 buf[2]; - + /* + * We need to set new configurations, only if device + * is currently enabled + */ + if (!atomic_read(&prs->enabled)) + return err; bit_valuesL = (u8) (new_reference & 0x00FF); bit_valuesH = (u8)((new_reference & 0xFF00) >> 8); @@ -491,12 +515,17 @@ static int lps001wp_prs_set_press_reference(struct lps001wp_prs_data *prs, static int lps001wp_prs_get_press_reference(struct lps001wp_prs_data *prs, u16 *buf16) { - int err = -1; + int err = -EINVAL; u8 bit_valuesL, bit_valuesH; u8 buf[2] = {0}; u16 temp = 0; - + /* + * We need to read configurations, only if device + * is currently enabled + */ + if (!atomic_read(&prs->enabled)) + return err; err = lps001wp_prs_register_read(prs, buf, REF_P_L); if (err < 0) return err; @@ -514,11 +543,17 @@ static int lps001wp_prs_get_press_reference(struct lps001wp_prs_data *prs, static int lps001wp_prs_lpow_manage(struct lps001wp_prs_data *prs, u8 control) { - int err = -1; + int err = -EINVAL; u8 buf[2] = {0x00, 0x00}; u8 const mask = LPS001WP_PRS_LPOW_MASK; u8 bit_values = LPS001WP_PRS_LPOW_OFF; + /* + * We need to set new configurations, only if device + * is currently enabled + */ + if (!atomic_read(&prs->enabled)) + return err; if (control >= LPS001WP_PRS_LPOWER_EN) { bit_values = LPS001WP_PRS_LPOW_ON; } @@ -539,11 +574,17 @@ static int lps001wp_prs_lpow_manage(struct lps001wp_prs_data *prs, u8 control) static int lps001wp_prs_diffen_manage(struct lps001wp_prs_data *prs, u8 control) { - int err = -1; + int err = -EINVAL; u8 buf[2] = {0x00, 0x00}; u8 const mask = LPS001WP_PRS_DIFF_MASK; u8 bit_values = LPS001WP_PRS_DIFF_OFF; + /* + * We need to set new configurations, only if device + * is currently enabled + */ + if (!atomic_read(&prs->enabled)) + return err; if (control >= LPS001WP_PRS_DIFF_ENABLE) { bit_values = LPS001WP_PRS_DIFF_ON; } @@ -566,7 +607,7 @@ static int lps001wp_prs_diffen_manage(struct lps001wp_prs_data *prs, u8 control) static int lps001wp_prs_get_presstemp_data(struct lps001wp_prs_data *prs, struct outputdata *out) { - int err = -1; + int err = -EINVAL; /* Data bytes from hardware PRESS_OUT_L, PRESS_OUT_H, * TEMP_OUT_L, TEMP_OUT_H, * DELTA_L, DELTA_H */ @@ -589,8 +630,8 @@ static int lps001wp_prs_get_presstemp_data(struct lps001wp_prs_data *prs, abspr = ((((u16) prs_data[1] << 8) | ((u16) prs_data[0]))); temperature = ((s16) (((u16) prs_data[3] << 8) | ((u16)prs_data[2]))); - out->abspress = abspr; - out->temperature = temperature; + out->abspress = (abspr >> SENSITIVITY_P_SHIFT); + out->temperature = (temperature >> SENSITIVITY_T_SHIFT); deltapr = ((s16) (((u16) prs_data[5] << 8) | ((u16)prs_data[4]))); out->deltapress = deltapr; @@ -614,6 +655,8 @@ static int lps001wp_prs_enable(struct lps001wp_prs_data *prs) int err; if (!atomic_cmpxchg(&prs->enabled, 0, 1)) { + if (prs->regulator) + regulator_enable(prs->regulator); err = lps001wp_prs_device_power_on(prs); if (err < 0) { atomic_set(&prs->enabled, 0); @@ -635,6 +678,8 @@ static int lps001wp_prs_disable(struct lps001wp_prs_data *prs) cancel_delayed_work_sync(&prs->input_work); #endif lps001wp_prs_device_power_off(prs); + if (prs->regulator) + regulator_disable(prs->regulator); } return 0; @@ -658,6 +703,7 @@ static ssize_t attr_set_polling_rate(struct device *dev, { struct lps001wp_prs_data *prs = dev_get_drvdata(dev); unsigned long interval_ms; + int err = -EINVAL; if (strict_strtoul(buf, 10, &interval_ms)) return -EINVAL; @@ -665,7 +711,12 @@ static ssize_t attr_set_polling_rate(struct device *dev, return -EINVAL; mutex_lock(&prs->lock); prs->pdata->poll_interval = interval_ms; - lps001wp_prs_update_odr(prs, interval_ms); + err = lps001wp_prs_update_odr(prs, interval_ms); + if (err < 0) { + dev_err(&prs->client->dev, "failed to update odr %ld\n", + interval_ms); + size = err; + } mutex_unlock(&prs->lock); return size; } @@ -688,12 +739,18 @@ static ssize_t attr_set_diff_enable(struct device *dev, { struct lps001wp_prs_data *prs = dev_get_drvdata(dev); unsigned long val; + int err = -EINVAL; if (strict_strtoul(buf, 10, &val)) return -EINVAL; mutex_lock(&prs->lock); - lps001wp_prs_diffen_manage(prs, (u8) val); + err = lps001wp_prs_diffen_manage(prs, (u8) val); + if (err < 0) { + dev_err(&prs->client->dev, "failed to diff enable %ld\n", val); + mutex_unlock(&prs->lock); + return err; + } mutex_unlock(&prs->lock); return size; } @@ -727,15 +784,17 @@ static ssize_t attr_set_enable(struct device *dev, static ssize_t attr_get_press_ref(struct device *dev, struct device_attribute *attr, char *buf) { - int err = -1; + int err = -EINVAL; struct lps001wp_prs_data *prs = dev_get_drvdata(dev); u16 val = 0; mutex_lock(&prs->lock); err = lps001wp_prs_get_press_reference(prs, &val); mutex_unlock(&prs->lock); - if (err < 0) + if (err < 0) { + dev_err(&prs->client->dev, "failed to get ref press\n"); return err; + } return sprintf(buf, "%d\n", val); } @@ -744,7 +803,7 @@ static ssize_t attr_set_press_ref(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int err = -1; + int err = -EINVAL; struct lps001wp_prs_data *prs = dev_get_drvdata(dev); unsigned long val = 0; @@ -757,8 +816,11 @@ static ssize_t attr_set_press_ref(struct device *dev, mutex_lock(&prs->lock); err = lps001wp_prs_set_press_reference(prs, val); mutex_unlock(&prs->lock); - if (err < 0) + if (err < 0) { + dev_err(&prs->client->dev, "failed to set ref press %ld\n", + val); return err; + } return size; } @@ -778,7 +840,7 @@ static ssize_t attr_set_lowpowmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int err = -1; + int err = -EINVAL; struct lps001wp_prs_data *prs = dev_get_drvdata(dev); unsigned long val; @@ -788,12 +850,86 @@ static ssize_t attr_set_lowpowmode(struct device *dev, mutex_lock(&prs->lock); err = lps001wp_prs_lpow_manage(prs, (u8) val); mutex_unlock(&prs->lock); - if (err < 0) + if (err < 0) { + dev_err(&prs->client->dev, "failed to set low powermode\n"); return err; + } return size; } +static ssize_t lps001wp_prs_get_press_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lps001wp_prs_data *prs = dev_get_drvdata(dev); + struct outputdata out; + int err = -EINVAL; + mutex_lock(&prs->lock); + /* + * If device is currently enabled, we need to read + * data from it. + */ + if (!atomic_read(&prs->enabled)) + goto out; + err = lps001wp_prs_get_presstemp_data(prs, &out); + if (err < 0) { + dev_err(&prs->client->dev, "get_pressure_data failed\n"); + goto out; + } + mutex_unlock(&prs->lock); + return sprintf(buf, "%d", out.abspress); +out: + mutex_unlock(&prs->lock); + return err; +} +static ssize_t lps001wp_prs_get_deltapr_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lps001wp_prs_data *prs = dev_get_drvdata(dev); + struct outputdata out; + int err = -EINVAL; + mutex_lock(&prs->lock); + /* + * If device is currently enabled, we need to read + * data from it. + */ + if (!atomic_read(&prs->enabled)) { + mutex_unlock(&prs->lock); + return err; + } + err = lps001wp_prs_get_presstemp_data(prs, &out); + if (err < 0) { + dev_err(&prs->client->dev, "get_deltapress_data failed\n"); + mutex_unlock(&prs->lock); + return err; + } + mutex_unlock(&prs->lock); + return sprintf(buf, "%d", out.deltapress); +} +static ssize_t lps001wp_prs_get_temp_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lps001wp_prs_data *prs = dev_get_drvdata(dev); + struct outputdata out; + int err = -EINVAL; + mutex_lock(&prs->lock); + /* + * If device is currently enabled, we need to read + * data from it. + */ + if (!atomic_read(&prs->enabled)) { + mutex_unlock(&prs->lock); + return err; + } + err = lps001wp_prs_get_presstemp_data(prs, &out); + if (err < 0) { + dev_err(&prs->client->dev, "get_temperature_data failed\n"); + mutex_unlock(&prs->lock); + return err; + } + mutex_unlock(&prs->lock); + return sprintf(buf, "%d", out.temperature); +} #ifdef DEBUG static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -848,14 +984,21 @@ static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr, static struct device_attribute attributes[] = { - __ATTR(pollrate_ms, 0664, attr_get_polling_rate, attr_set_polling_rate), - __ATTR(enable, 0664, attr_get_enable, attr_set_enable), - __ATTR(diff_enable, 0664, attr_get_diff_enable, attr_set_diff_enable), - __ATTR(press_reference, 0664, attr_get_press_ref, attr_set_press_ref), - __ATTR(lowpow_enable, 0664, attr_get_lowpowmode, attr_set_lowpowmode), + __ATTR(pollrate_ms, S_IWUSR | S_IRUGO, attr_get_polling_rate, + attr_set_polling_rate), + __ATTR(enable, S_IWUSR | S_IRUGO, attr_get_enable, attr_set_enable), + __ATTR(diff_enable, S_IWUSR | S_IRUGO, attr_get_diff_enable, + attr_set_diff_enable), + __ATTR(press_reference, S_IWUSR | S_IRUGO, attr_get_press_ref, + attr_set_press_ref), + __ATTR(lowpow_enable, S_IWUSR | S_IRUGO, attr_get_lowpowmode, + attr_set_lowpowmode), + __ATTR(press_data, S_IRUGO, lps001wp_prs_get_press_data, NULL), + __ATTR(temp_data, S_IRUGO, lps001wp_prs_get_temp_data, NULL), + __ATTR(deltapr_data, S_IRUGO, lps001wp_prs_get_deltapr_data, NULL), #ifdef DEBUG - __ATTR(reg_value, 0664, attr_reg_get, attr_reg_set), - __ATTR(reg_addr, 0220, NULL, attr_addr_set), + __ATTR(reg_value, S_IWUSR | S_IRUGO, attr_reg_get, attr_reg_set), + __ATTR(reg_addr, S_IWUSR, NULL, attr_addr_set), #endif }; @@ -992,7 +1135,7 @@ static int lps001wp_prs_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lps001wp_prs_data *prs; - int err = -1; + int err = -EINVAL; int tempvalue; pr_info("%s: probe start.\n", LPS001WP_PRS_DEV_NAME); @@ -1042,23 +1185,31 @@ static int lps001wp_prs_probe(struct i2c_client *client, prs->client = client; i2c_set_clientdata(client, prs); + prs->regulator = regulator_get(&client->dev, "vdd"); + if (IS_ERR(prs->regulator)) { + dev_err(&client->dev, "failed to get regulator\n"); + err = PTR_ERR(prs->regulator); + prs->regulator = NULL; + } + if (prs->regulator) + regulator_enable(prs->regulator); if (i2c_smbus_read_byte(client) < 0) { - printk(KERN_ERR "i2c_smbus_read_byte error!!\n"); + dev_err(&client->dev, "i2c_smbus_read_byte error!!\n"); goto err_mutexunlockfreedata; } else { - printk(KERN_DEBUG "%s Device detected!\n", + dev_dbg(&client->dev, "%s Device detected!\n", LPS001WP_PRS_DEV_NAME); } /* read chip id */ tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); if ((tempvalue & 0x00FF) == WHOAMI_LPS001WP_PRS) { - printk(KERN_DEBUG "%s I2C driver registered!\n", + dev_dbg(&client->dev, "%s I2C driver registered!\n", LPS001WP_PRS_DEV_NAME); } else { prs->client = NULL; - printk(KERN_DEBUG "I2C driver not registered!" + dev_dbg(&client->dev, "I2C driver not registered!" " Device unknown\n"); goto err_mutexunlockfreedata; } @@ -1135,6 +1286,9 @@ static int lps001wp_prs_probe(struct i2c_client *client, lps001wp_prs_device_power_off(prs); + if (prs->regulator) + regulator_disable(prs->regulator); + /* As default, do not report information */ atomic_set(&prs->enabled, 0); @@ -1164,9 +1318,14 @@ exit_kfree_pdata: err_mutexunlockfreedata: mutex_unlock(&prs->lock); kfree(prs); + if (prs->regulator) { + regulator_disable(prs->regulator); + regulator_put(prs->regulator); + } exit_alloc_data_failed: exit_check_functionality_failed: - printk(KERN_ERR "%s: Driver Init failed\n", LPS001WP_PRS_DEV_NAME); + dev_err(&client->dev, "%s: Driver Init failed\n", + LPS001WP_PRS_DEV_NAME); return err; } @@ -1179,6 +1338,12 @@ static int __devexit lps001wp_prs_remove(struct i2c_client *client) #endif lps001wp_prs_device_power_off(prs); remove_sysfs_interfaces(&client->dev); + if (prs->regulator) { + /* Disable the regulator if device is enabled. */ + if (atomic_read(&prs->enabled)) + regulator_disable(prs->regulator); + regulator_put(prs->regulator); + } if (prs->pdata->exit) prs->pdata->exit(); -- cgit v1.2.3