diff options
Diffstat (limited to 'drivers/iio/light/hid-sensor-als.c')
| -rw-r--r-- | drivers/iio/light/hid-sensor-als.c | 78 | 
1 files changed, 55 insertions, 23 deletions
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index e59d00c3139..96e71e103ea 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -22,6 +22,7 @@  #include <linux/interrupt.h>  #include <linux/irq.h>  #include <linux/slab.h> +#include <linux/delay.h>  #include <linux/hid-sensor-hub.h>  #include <linux/iio/iio.h>  #include <linux/iio/sysfs.h> @@ -37,6 +38,10 @@ struct als_state {  	struct hid_sensor_common common_attributes;  	struct hid_sensor_hub_attribute_info als_illum;  	u32 illum; +	int scale_pre_decml; +	int scale_post_decml; +	int scale_precision; +	int value_offset;  };  /* Channel definitions */ @@ -45,6 +50,7 @@ static const struct iio_chan_spec als_channels[] = {  		.type = IIO_INTENSITY,  		.modified = 1,  		.channel2 = IIO_MOD_LIGHT_BOTH, +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),  		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |  		BIT(IIO_CHAN_INFO_SCALE) |  		BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -73,8 +79,8 @@ static int als_read_raw(struct iio_dev *indio_dev,  	struct als_state *als_state = iio_priv(indio_dev);  	int report_id = -1;  	u32 address; -	int ret;  	int ret_type; +	s32 poll_value;  	*val = 0;  	*val2 = 0; @@ -90,35 +96,44 @@ static int als_read_raw(struct iio_dev *indio_dev,  			report_id = -1;  			break;  		} -		if (report_id >= 0) +		if (report_id >= 0) { +			poll_value = hid_sensor_read_poll_value( +						&als_state->common_attributes); +			if (poll_value < 0) +				return -EINVAL; + +			hid_sensor_power_state(&als_state->common_attributes, +						true); +			msleep_interruptible(poll_value * 2); +  			*val = sensor_hub_input_attr_get_raw_value( -				als_state->common_attributes.hsdev, -				HID_USAGE_SENSOR_ALS, address, -				report_id); -		else { +					als_state->common_attributes.hsdev, +					HID_USAGE_SENSOR_ALS, address, +					report_id); +			hid_sensor_power_state(&als_state->common_attributes, +						false); +		} else {  			*val = 0;  			return -EINVAL;  		}  		ret_type = IIO_VAL_INT;  		break;  	case IIO_CHAN_INFO_SCALE: -		*val = als_state->als_illum.units; -		ret_type = IIO_VAL_INT; +		*val = als_state->scale_pre_decml; +		*val2 = als_state->scale_post_decml; +		ret_type = als_state->scale_precision;  		break;  	case IIO_CHAN_INFO_OFFSET: -		*val = hid_sensor_convert_exponent( -				als_state->als_illum.unit_expo); +		*val = als_state->value_offset;  		ret_type = IIO_VAL_INT;  		break;  	case IIO_CHAN_INFO_SAMP_FREQ: -		ret = hid_sensor_read_samp_freq_value( +		ret_type = hid_sensor_read_samp_freq_value(  				&als_state->common_attributes, val, val2); -		ret_type = IIO_VAL_INT_PLUS_MICRO;  		break;  	case IIO_CHAN_INFO_HYSTERESIS: -		ret = hid_sensor_read_raw_hyst_value( +		ret_type = hid_sensor_read_raw_hyst_value(  				&als_state->common_attributes, val, val2); -		ret_type = IIO_VAL_INT_PLUS_MICRO;  		break;  	default:  		ret_type = -EINVAL; @@ -161,10 +176,11 @@ static const struct iio_info als_info = {  };  /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, +					int len)  {  	dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); -	iio_push_to_buffers(indio_dev, (u8 *)data); +	iio_push_to_buffers(indio_dev, data);  }  /* Callback handler to send event after all samples are received and captured */ @@ -175,11 +191,10 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,  	struct iio_dev *indio_dev = platform_get_drvdata(priv);  	struct als_state *als_state = iio_priv(indio_dev); -	dev_dbg(&indio_dev->dev, "als_proc_event [%d]\n", -				als_state->common_attributes.data_ready); -	if (als_state->common_attributes.data_ready) +	dev_dbg(&indio_dev->dev, "als_proc_event\n"); +	if (atomic_read(&als_state->common_attributes.data_ready))  		hid_sensor_push_data(indio_dev, -				(u8 *)&als_state->illum, +				&als_state->illum,  				sizeof(als_state->illum));  	return 0; @@ -228,6 +243,22 @@ static int als_parse_report(struct platform_device *pdev,  	dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,  			st->als_illum.report_id); +	st->scale_precision = hid_sensor_format_scale( +				HID_USAGE_SENSOR_ALS, +				&st->als_illum, +				&st->scale_pre_decml, &st->scale_post_decml); + +	/* Set Sensitivity field ids, when there is no individual modifier */ +	if (st->common_attributes.sensitivity.index < 0) { +		sensor_hub_input_get_attribute_info(hsdev, +			HID_FEATURE_REPORT, usage_id, +			HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | +			HID_USAGE_SENSOR_DATA_LIGHT, +			&st->common_attributes.sensitivity); +		dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", +			st->common_attributes.sensitivity.index, +			st->common_attributes.sensitivity.report_id); +	}  	return ret;  } @@ -284,7 +315,7 @@ static int hid_als_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");  		goto error_free_dev_mem;  	} -	als_state->common_attributes.data_ready = false; +	atomic_set(&als_state->common_attributes.data_ready, 0);  	ret = hid_sensor_setup_trigger(indio_dev, name,  				&als_state->common_attributes);  	if (ret < 0) { @@ -313,7 +344,7 @@ static int hid_als_probe(struct platform_device *pdev)  error_iio_unreg:  	iio_device_unregister(indio_dev);  error_remove_trigger: -	hid_sensor_remove_trigger(indio_dev); +	hid_sensor_remove_trigger(&als_state->common_attributes);  error_unreg_buffer_funcs:  	iio_triggered_buffer_cleanup(indio_dev);  error_free_dev_mem: @@ -326,10 +357,11 @@ static int hid_als_remove(struct platform_device *pdev)  {  	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;  	struct iio_dev *indio_dev = platform_get_drvdata(pdev); +	struct als_state *als_state = iio_priv(indio_dev);  	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);  	iio_device_unregister(indio_dev); -	hid_sensor_remove_trigger(indio_dev); +	hid_sensor_remove_trigger(&als_state->common_attributes);  	iio_triggered_buffer_cleanup(indio_dev);  	kfree(indio_dev->channels);  | 
