diff options
author | Chen Jian <jackchen@nvidia.com> | 2014-01-02 15:39:24 +0800 |
---|---|---|
committer | Martin Chi <mchi@nvidia.com> | 2014-01-04 08:32:09 -0800 |
commit | ffdc176f384d4347d33bc4b01e28898fa31f166a (patch) | |
tree | 92b750f11cccf6e5e89bb8fea1435032c52974ef /drivers | |
parent | e20298c5e4aebaaf59fa0d5b457efba149b2d819 (diff) |
RM:tegra:tn7c:Update LTR659PS drv with TN7C
- Add PS parameters.
- Add sysfs node: ps_data and enable
- Update interrupt routine.
- Initialize sensor with default paramters.
- Update suspend/resume routine.
- Add voice call proceding.
Bug 1410904
Change-Id: I1569e5bae3c1dbc5c3b65c47d1725bf0f45f06fa
Signed-off-by: Chen Jian <jackchen@nvidia.com>
Reviewed-on: http://git-master/r/351242
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Martin Chi <mchi@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/iio/light/ltr659ps.c | 322 |
1 files changed, 258 insertions, 64 deletions
diff --git a/drivers/staging/iio/light/ltr659ps.c b/drivers/staging/iio/light/ltr659ps.c index 97c95c70aaad..e21ab9f2b72d 100644 --- a/drivers/staging/iio/light/ltr659ps.c +++ b/drivers/staging/iio/light/ltr659ps.c @@ -25,6 +25,9 @@ #include <linux/slab.h> #include <linux/input.h> #include <linux/gpio.h> +#include <linux/tegra_audio.h> +#include <linux/regulator/consumer.h> + #include <linux/ltr659ps.h> @@ -121,17 +124,32 @@ MODULE_DEVICE_TABLE(i2c, ltr659ps_id); struct ltr659ps_data { struct workqueue_struct *prox_wq; + struct regulator *reg; + struct i2c_client *client; struct input_dev *ps_input_dev; struct delayed_work work; - uint16_t default_ps_lowthresh; - uint16_t default_ps_highthresh; + uint16_t ps_lowthresh; + uint16_t ps_highthresh; + int interrupt_mode; + int intr_polarity; + int led_pulse_freq; + int ps_gain; + int ps_meas_time; + int ps_persist; + int ps_offset; + int led_pulse_count; + int led_drv_peak_current; + int led_duty_cycle; + int enable; + + int init; + int suspend; int irq; int gpio; - int enable; struct mutex prox_mtx; }; @@ -153,7 +171,6 @@ static s32 ltr659ps_masked_write_reg( u8 data = i2c_smbus_read_byte_data(client, command); data = (data & ~mask) | (value & mask); - return i2c_smbus_write_byte_data(client, command, data); } @@ -211,7 +228,8 @@ static ssize_t store_ps_gain( else value = 0x00; ltr659ps_masked_write_reg( - data->client, LTR659PS_REG_PS_CONTR, value, 0x0c); + data->client, LTR659PS_REG_PS_CONTR, value<<2, 0x0c); + data->ps_gain = value; } mutex_unlock(&data->prox_mtx); @@ -266,6 +284,7 @@ static ssize_t store_led_pulse_mod_freq( value = (value - 30) / 10; else value = (60 - 30) / 10; + data->led_pulse_freq = value; value <<= 5; ltr659ps_masked_write_reg( data->client, LTR659PS_REG_PS_LED, value, 0xe0); @@ -321,6 +340,7 @@ static ssize_t store_led_current_duty( value = (value / 25) - 1; else value = (100 / 25) - 1; + data->led_duty_cycle = value; value <<= 3; ltr659ps_masked_write_reg( data->client, LTR659PS_REG_PS_LED, value, 0x18); @@ -383,6 +403,7 @@ static ssize_t store_led_current( value = 0x03; else value = 0x04; + data->led_drv_peak_current = value; ltr659ps_masked_write_reg( data->client, LTR659PS_REG_PS_LED, value, 0x07); } @@ -437,6 +458,7 @@ static ssize_t store_ps_number_of_led_pulse( value = value; else value = 0x01; + data->led_pulse_count = value; ltr659ps_write_reg( data->client, LTR659PS_REG_PS_N_PULSES, value); } @@ -511,6 +533,7 @@ static ssize_t store_ps_measurement_rate( value = 0x08; else value = 0x02; + data->ps_meas_time = value; ltr659ps_write_reg( data->client, LTR659PS_REG_PS_MEAS_RATE, value); } @@ -562,11 +585,12 @@ static ssize_t store_interrupt_polarity( mutex_lock(&data->prox_mtx); if (data->enable) { if (value == 1) - value = 1 << 2; + value = 1; else value = 0; - ltr659ps_masked_write_reg( - data->client, LTR659PS_REG_INTERRUPT, value, (1<<2)); + data->intr_polarity = value; + ltr659ps_masked_write_reg(data->client + , LTR659PS_REG_INTERRUPT, (value<<2), (1<<2)); } mutex_unlock(&data->prox_mtx); @@ -618,6 +642,7 @@ static ssize_t store_interrupt_mode( if (data->enable) { if (value != 1) value = 0; + data->interrupt_mode = value; ltr659ps_masked_write_reg( data->client, LTR659PS_REG_INTERRUPT, value, 0x01); } @@ -679,6 +704,8 @@ static ssize_t store_ps_threashold( if (data->enable) { int hvalue = (value >> 16) & 0x3ff; int lvalue = value & 0x3ff; + data->ps_highthresh = hvalue; + data->ps_lowthresh = lvalue; ltr659ps_write_reg(data->client , LTR659PS_REG_PS_THRES_UP_0, hvalue & 0xff); ltr659ps_write_reg(data->client @@ -736,6 +763,7 @@ static ssize_t store_ps_offset( mutex_lock(&data->prox_mtx); if (data->enable) { + data->ps_offset = value; ltr659ps_write_reg( data->client , LTR659PS_REG_PS_OFFSET_1 @@ -793,6 +821,7 @@ static ssize_t store_interrupt_persist( mutex_lock(&data->prox_mtx); if (data->enable) { value &= 0xf; + data->ps_persist = value; ltr659ps_write_reg( data->client , LTR659PS_REG_INTERRUPT_PERSIST @@ -803,6 +832,67 @@ static ssize_t store_interrupt_persist( return strnlen(buf, count); } +static ssize_t show_ps_data( + struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr659ps_data *data = iio_priv(indio_dev); + int value, l_value, h_value; + int ret = 0; + + mutex_lock(&data->prox_mtx); + l_value = ltr659ps_read_reg(data->client, LTR659PS_REG_PS_DATA_0); + h_value = ltr659ps_read_reg(data->client, LTR659PS_REG_PS_DATA_1); + value = h_value << 8 | l_value; + mutex_unlock(&data->prox_mtx); + + ret = sprintf(buf, "%d\n", value); + + return ret; +} + +static ssize_t store_enable( + struct device *dev + , struct device_attribute *attr + , const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr659ps_data *data = iio_priv(indio_dev); + long value; + + PROX_DEBUG("\n"); + + if (kstrtol(buf, 16, &value)) { + PROX_ERROR("valid enable : 0 : disable; 1 : enable;\n"); + return -EINVAL; + } + + mutex_lock(&data->prox_mtx); + if (value == 1) + ltr659ps_enable_sensor(data->client, 1); + else + ltr659ps_enable_sensor(data->client, 0); + mutex_unlock(&data->prox_mtx); + + return strnlen(buf, count); +} + +static ssize_t show_enable( + struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr659ps_data *data = iio_priv(indio_dev); + int ret = 0; + + PROX_DEBUG("\n"); + + mutex_lock(&data->prox_mtx); + ret = sprintf(buf, "%s\n", ((data->enable) ? ("en") : ("dis"))); + mutex_unlock(&data->prox_mtx); + + return ret; +} + static ssize_t show_dump_reg( struct device *dev, struct device_attribute *devattr, char *buf) { @@ -836,11 +926,9 @@ static ssize_t show_dump_gpio( value = gpio_get_value(data->gpio); mutex_unlock(&data->prox_mtx); - PROX_DEBUG("GPIO (%d) level %s\n" + ret = sprintf(buf, "GPIO (%d) level %s\nDone\n" , data->gpio, ((value) ? ("high") : ("low"))); - ret = sprintf(buf, "Done\n"); - return ret; } @@ -863,6 +951,8 @@ IIO_DEVICE_ATTR(ps_threashold, 0644 IIO_DEVICE_ATTR(ps_offset, 0644, show_ps_offset, store_ps_offset, 0); IIO_DEVICE_ATTR(interrupt_persist, 0644 , show_interrupt_persist, store_interrupt_persist, 0); +IIO_DEVICE_ATTR(ps_data, 0444, show_ps_data, NULL, 0); +IIO_DEVICE_ATTR(enable, 0666, show_enable, store_enable, 0); IIO_DEVICE_ATTR(dump_reg, 0444, show_dump_reg, NULL, 0); IIO_DEVICE_ATTR(dump_gpio, 0444, show_dump_gpio, NULL, 0); @@ -878,6 +968,8 @@ static struct attribute *ltr659ps_attr[] = { &iio_dev_attr_ps_threashold.dev_attr.attr, &iio_dev_attr_ps_offset.dev_attr.attr, &iio_dev_attr_interrupt_persist.dev_attr.attr, + &iio_dev_attr_ps_data.dev_attr.attr, + &iio_dev_attr_enable.dev_attr.attr, &iio_dev_attr_dump_reg.dev_attr.attr, &iio_dev_attr_dump_gpio.dev_attr.attr, NULL @@ -887,9 +979,52 @@ static const struct attribute_group ltr659ps_group = { .attrs = ltr659ps_attr, }; -static void ltr659ps_report_input_event(struct ltr659ps_data *prox) +static void ltr659ps_report_input_event(struct ltr659ps_data *data) { - /* TODO */ + int l_value, h_value, value; + + l_value = ltr659ps_read_reg(data->client, LTR659PS_REG_PS_DATA_0); + h_value = ltr659ps_read_reg(data->client, LTR659PS_REG_PS_DATA_1); + value = h_value << 8 | l_value; + + PROX_DEBUG("ltr659ps_report_input_event %d\n", value); + + if (value > data->ps_highthresh) { + /* set low threshold to trigger far event */ + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_UP_0, 0xff); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_UP_1, 0x07); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_0 + , data->ps_lowthresh & 0xff); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_1 + , data->ps_lowthresh >> 8); + } else if (value < data->ps_lowthresh) { + /* set high threshold to trigger near event */ + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_UP_0 + , data->ps_highthresh & 0xff); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_UP_1 + , data->ps_highthresh >> 8); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_0, 0x00); + ltr659ps_write_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_1, 0x00); + } else { + h_value = (ltr659ps_read_reg(data->client + , LTR659PS_REG_PS_THRES_UP_1) << 8) | + ltr659ps_read_reg(data->client + , LTR659PS_REG_PS_THRES_UP_0); + l_value = (ltr659ps_read_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_1) << 8) | + ltr659ps_read_reg(data->client + , LTR659PS_REG_PS_THRES_LOW_0); + PROX_ERROR("Unexpected interrupt: (data %d) ", value); + PROX_ERROR("(high thr %d) (low thr %d)", l_value, h_value); + } return; } @@ -951,46 +1086,43 @@ static int ltr659ps_setup(struct ltr659ps_data *prox) static int ltr659ps_init_sensor(struct i2c_client *client) { + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ltr659ps_data *data = iio_priv(indio_dev); int ret = 0; - int i; - u8 reg, val; - u8 reg_init[] = { - /* SW_RESET Register reset = 1 */ - LTR659PS_REG_SW_RESET, 0x02, - /* PS_CONTR register Gain = 16 */ - LTR659PS_REG_PS_CONTR, 0x03, - /* PS_LED Pulse Freq = 30kHz duty cyc 100% peak curr 100mA */ - LTR659PS_REG_PS_LED, 0x1f, - /* PS_MEAS_RATE Meas rate = 50ms */ - LTR659PS_REG_PS_MEAS_RATE, 0x00, - /* Interrupt Register Interrupt is Active Low, PS trigger */ - LTR659PS_REG_INTERRUPT, 0x01, - /* PS Upper Threshold Low Byte Register 1000 */ - LTR659PS_REG_PS_THRES_UP_0, 1000 & 0xff, - /* PS Upper Threshold High Byte Register 1000 */ - LTR659PS_REG_PS_THRES_UP_1, 1000 >> 8, - /* PS Lower Threshold Low Byte Register 200 */ - LTR659PS_REG_PS_THRES_LOW_0, 200 & 0xff, - /* PS Lower Threshold High Byte Register 200 */ - LTR659PS_REG_PS_THRES_LOW_1, 200 >> 8, - /* SW_RESET Register reset = 0 */ - LTR659PS_REG_SW_RESET, 0x00, - 0xff, 0xff, - }; - - i = 0; - while (reg_init[i] != 0xff) { - reg = reg_init[i++]; - val = reg_init[i++]; - ltr659ps_write_reg(client, reg, val); - } + ltr659ps_masked_write_reg(client + , LTR659PS_REG_PS_LED, (data->led_duty_cycle << 3), 0x18); + ltr659ps_masked_write_reg(client + , LTR659PS_REG_PS_LED, data->led_drv_peak_current, 0x07); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_N_PULSES, data->led_pulse_count); + ltr659ps_write_reg(client + , LTR659PS_REG_INTERRUPT_PERSIST, (data->ps_persist << 4)); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_MEAS_RATE, data->ps_meas_time); + ltr659ps_masked_write_reg(client + , LTR659PS_REG_PS_CONTR, (data->ps_gain << 2), 0x0c); + ltr659ps_masked_write_reg(client + , LTR659PS_REG_PS_LED, (data->led_pulse_freq << 5), 0xe0); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_THRES_UP_0, data->ps_highthresh & 0xff); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_THRES_UP_1, data->ps_highthresh >> 8); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_THRES_LOW_0, 0); + ltr659ps_write_reg(client + , LTR659PS_REG_PS_THRES_LOW_1, 0); + ltr659ps_masked_write_reg(client + , LTR659PS_REG_INTERRUPT, (data->intr_polarity << 2), (1<<2)); + ltr659ps_masked_write_reg(client + , LTR659PS_REG_INTERRUPT, data->interrupt_mode, 0x01); return ret; } static irqreturn_t ltr659ps_interrupt_handler(int irq, void *dev) { - struct ltr659ps_data *data = i2c_get_clientdata(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(dev); + struct ltr659ps_data *data = iio_priv(indio_dev); disable_irq_nosync(data->irq); @@ -1001,19 +1133,21 @@ static irqreturn_t ltr659ps_interrupt_handler(int irq, void *dev) static void ltr659ps_enable_sensor(struct i2c_client *client, int enable) { - struct ltr659ps_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ltr659ps_data *data = iio_priv(indio_dev); if (data->enable != enable) { if (enable) { + if (!data->init) { + ltr659ps_init_sensor(data->client); + data->init = 1; + } queue_delayed_work(data->prox_wq, &data->work , msecs_to_jiffies(200)); - /* TODO enable irq */ - /* enable_irq(client->irq); */ ltr659ps_masked_write_reg(client - , LTR659PS_REG_PS_CONTR, 0x10, 0x03); + , LTR659PS_REG_PS_CONTR, 0x03, 0x03); } else { - /* TODO disable irq */ - /* disable_irq(client->irq); */ + disable_irq(client->irq); ltr659ps_masked_write_reg(client , LTR659PS_REG_PS_CONTR, 0x00, 0x03); cancel_delayed_work_sync(&data->work); @@ -1028,12 +1162,12 @@ static void ltr659ps_enable_sensor(struct i2c_client *client, int enable) static int ltr659ps_config_irq(struct i2c_client *client) { - struct ltr659ps_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ltr659ps_data *data = iio_priv(indio_dev); int rc = 0; const char *label = "ltr659ps_irq"; data->irq = client->irq; - /* TODO disable interrupt for debug */ rc = request_irq(client->irq, ltr659ps_interrupt_handler, IRQF_TRIGGER_LOW | IRQF_DISABLED, @@ -1042,6 +1176,7 @@ static int ltr659ps_config_irq(struct i2c_client *client) if (rc) PROX_ERROR("request_irq fail irq = %d\n", client->irq); + disable_irq(client->irq); return rc; } @@ -1110,6 +1245,18 @@ static int __devinit ltr659ps_probe(struct i2c_client *client goto err_gpio_direction_input; } + prox_data->reg = regulator_get(&client->dev, "va_sns_hv"); + if (IS_ERR(prox_data->reg)) { + PROX_ERROR("regulator_get failed!\n"); + goto err_regulator_get; + } + + rc = regulator_enable(prox_data->reg); + if (rc) { + PROX_ERROR("regulator_enable failed!\n"); + goto err_regulator_enable; + } + rc = ltr659ps_check_id(prox_data->client); if (rc) { PROX_ERROR("ltr659ps_check_id failed!\n"); @@ -1135,10 +1282,30 @@ static int __devinit ltr659ps_probe(struct i2c_client *client goto err_config_irq_failed; } - prox_data->enable = 1; - /* TODO check the threshold, the following values come from datasheet */ - prox_data->default_ps_lowthresh = pdata->default_ps_lowthreshold; - prox_data->default_ps_highthresh = pdata->default_ps_highthreshold; + prox_data->enable = 0; + prox_data->init = 0; + /* TODO Correct threshold in right ME */ + prox_data->ps_lowthresh = pdata->default_ps_lowthreshold; + prox_data->ps_highthresh = pdata->default_ps_highthreshold; + /* default configuration */ + /* interrupt mode : enabled */ + prox_data->interrupt_mode = 1; + /* interrupt polarity : low active */ + prox_data->intr_polarity = 0; + /* LED pulse frequency : 60k Hz */ + prox_data->led_pulse_freq = 3; + /* PS gain x16 */ + prox_data->ps_gain = 0; + /* PS measurement time 100ms */ + prox_data->ps_meas_time = 2; + /* PS persist 0 */ + prox_data->ps_persist = 0; + /* LED pulse count 1 */ + prox_data->led_pulse_count = 1; + /* LED driving peak current 100mA */ + prox_data->led_drv_peak_current = 4; + /* LED duty cycle 100% */ + prox_data->led_duty_cycle = 3; indio_dev->info = <r659ps_info; indio_dev->dev.parent = &client->dev; @@ -1162,6 +1329,10 @@ err_init_sensor_failed: input_free_device(prox_data->ps_input_dev); err_setup_failed: err_check_id_failed: + regulator_disable(prox_data->reg); +err_regulator_enable: + regulator_put(prox_data->reg); +err_regulator_get: err_gpio_direction_input: gpio_free(pdata->gpio); err_gpio_request: @@ -1182,6 +1353,8 @@ static int __devexit ltr659ps_remove(struct i2c_client *client) free_irq(client->irq, client); input_unregister_device(data->ps_input_dev); input_free_device(data->ps_input_dev); + regulator_disable(data->reg); + regulator_put(data->reg); gpio_free(data->gpio); cancel_delayed_work(&data->work); destroy_workqueue(data->prox_wq); @@ -1195,9 +1368,21 @@ static int ltr659ps_suspend(struct i2c_client *client, pm_message_t mesg) struct ltr659ps_data *data = iio_priv(indio_dev); PROX_DEBUG("+\n"); - mutex_lock(&data->prox_mtx); - ltr659ps_enable_sensor(client, 0); - mutex_unlock(&data->prox_mtx); + /* in voice call mode, do not suspend PS */ + if (tegra_is_voice_call_active()) { + mutex_lock(&data->prox_mtx); + enable_irq_wake(client->irq); + data->suspend = 0; + mutex_unlock(&data->prox_mtx); + } else { + mutex_lock(&data->prox_mtx); + ltr659ps_enable_sensor(client, 0); + regulator_disable(data->reg); + regulator_put(data->reg); + data->init = 0; + data->suspend = 1; + mutex_unlock(&data->prox_mtx); + } PROX_DEBUG("-\n"); return 0; } @@ -1208,9 +1393,18 @@ static int ltr659ps_resume(struct i2c_client *client) struct ltr659ps_data *data = iio_priv(indio_dev); PROX_DEBUG("+\n"); - mutex_lock(&data->prox_mtx); - ltr659ps_enable_sensor(client, 1); - mutex_unlock(&data->prox_mtx); + /* in voice call mode, do not suspend PS */ + if (data->suspend == 0) { + mutex_lock(&data->prox_mtx); + disable_irq_wake(client->irq); + mutex_unlock(&data->prox_mtx); + } else { + mutex_lock(&data->prox_mtx); + data->reg = regulator_get(&client->dev, "va_sns_hv"); + regulator_enable(data->reg); + ltr659ps_enable_sensor(client, 1); + mutex_unlock(&data->prox_mtx); + } PROX_DEBUG("-\n"); return 0; } |