diff options
Diffstat (limited to 'drivers/iio/common')
| -rw-r--r-- | drivers/iio/common/hid-sensors/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-attributes.c | 151 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 68 | ||||
| -rw-r--r-- | drivers/iio/common/hid-sensors/hid-sensor-trigger.h | 3 | ||||
| -rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_buffer.c | 7 | ||||
| -rw-r--r-- | drivers/iio/common/st_sensors/st_sensors_core.c | 105 | 
6 files changed, 281 insertions, 62 deletions
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig index 1178121b55b..39188b72cd3 100644 --- a/drivers/iio/common/hid-sensors/Kconfig +++ b/drivers/iio/common/hid-sensors/Kconfig @@ -25,13 +25,4 @@ config HID_SENSOR_IIO_TRIGGER  	  If this driver is compiled as a module, it will be named  	  hid-sensor-trigger. -config HID_SENSOR_ENUM_BASE_QUIRKS -	bool "ENUM base quirks for HID Sensor IIO drivers" -	depends on HID_SENSOR_IIO_COMMON -	help -	  Say yes here to build support for sensor hub FW using -	  enumeration, which is using 1 as base instead of 0. -	  Since logical minimum is still set 0 instead of 1, -	  there is no easy way to differentiate. -  endmenu diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 75b54730a96..403dd3d8986 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -26,6 +26,40 @@  #include <linux/iio/iio.h>  #include <linux/iio/sysfs.h> +struct { +	u32 usage_id; +	int unit; /* 0 for default others from HID sensor spec */ +	int scale_val0; /* scale, whole number */ +	int scale_val1; /* scale, fraction in micros */ +} static unit_conversion[] = { +	{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650}, +	{HID_USAGE_SENSOR_ACCEL_3D, +		HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0}, +	{HID_USAGE_SENSOR_ACCEL_3D, +		HID_USAGE_SENSOR_UNITS_G, 9, 806650}, + +	{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453}, +	{HID_USAGE_SENSOR_GYRO_3D, +		HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, +	{HID_USAGE_SENSOR_GYRO_3D, +		HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND, 0, 17453}, + +	{HID_USAGE_SENSOR_COMPASS_3D, 0, 0, 1000}, +	{HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_UNITS_GAUSS, 1, 0}, + +	{HID_USAGE_SENSOR_INCLINOMETER_3D, 0, 0, 17453}, +	{HID_USAGE_SENSOR_INCLINOMETER_3D, +		HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453}, +	{HID_USAGE_SENSOR_INCLINOMETER_3D, +		HID_USAGE_SENSOR_UNITS_RADIANS, 1, 0}, + +	{HID_USAGE_SENSOR_ALS, 0, 1, 0}, +	{HID_USAGE_SENSOR_ALS, HID_USAGE_SENSOR_UNITS_LUX, 1, 0}, + +	{HID_USAGE_SENSOR_PRESSURE, 0, 100000, 0}, +	{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 1, 0}, +}; +  static int pow_10(unsigned power)  {  	int i; @@ -113,6 +147,26 @@ static u32 convert_to_vtf_format(int size, int exp, int val1, int val2)  	return value;  } +s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) +{ +	s32 value = 0; +	int ret; + +	ret = sensor_hub_get_feature(st->hsdev, +		st->poll.report_id, +		st->poll.index, &value); + +	if (ret < 0 || value < 0) { +		return -EINVAL; +	} else { +		if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) +			value = value * 1000; +	} + +	return value; +} +EXPORT_SYMBOL(hid_sensor_read_poll_value); +  int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,  				int *val1, int *val2)  { @@ -209,15 +263,108 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,  }  EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); -int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, +/* + * This fuction applies the unit exponent to the scale. + * For example: + * 9.806650 ->exp:2-> val0[980]val1[665000] + * 9.000806 ->exp:2-> val0[900]val1[80600] + * 0.174535 ->exp:2-> val0[17]val1[453500] + * 1.001745 ->exp:0-> val0[1]val1[1745] + * 1.001745 ->exp:2-> val0[100]val1[174500] + * 1.001745 ->exp:4-> val0[10017]val1[450000] + * 9.806650 ->exp:-2-> val0[0]val1[98066] + */ +static void adjust_exponent_micro(int *val0, int *val1, int scale0, +				  int scale1, int exp) +{ +	int i; +	int x; +	int res; +	int rem; + +	if (exp > 0) { +		*val0 = scale0 * pow_10(exp); +		res = 0; +		if (exp > 6) { +			*val1 = 0; +			return; +		} +		for (i = 0; i < exp; ++i) { +			x = scale1 / pow_10(5 - i); +			res += (pow_10(exp - 1 - i) * x); +			scale1 = scale1 % pow_10(5 - i); +		} +		*val0 += res; +			*val1 = scale1 * pow_10(exp); +	} else if (exp < 0) { +		exp = abs(exp); +		if (exp > 6) { +			*val0 = *val1 = 0; +			return; +		} +		*val0 = scale0 / pow_10(exp); +		rem = scale0 % pow_10(exp); +		res = 0; +		for (i = 0; i < (6 - exp); ++i) { +			x = scale1 / pow_10(5 - i); +			res += (pow_10(5 - exp - i) * x); +			scale1 = scale1 % pow_10(5 - i); +		} +		*val1 = rem * pow_10(6 - exp) + res; +	} else { +		*val0 = scale0; +		*val1 = scale1; +	} +} + +int hid_sensor_format_scale(u32 usage_id, +			struct hid_sensor_hub_attribute_info *attr_info, +			int *val0, int *val1) +{ +	int i; +	int exp; + +	*val0 = 1; +	*val1 = 0; + +	for (i = 0; i < ARRAY_SIZE(unit_conversion); ++i) { +		if (unit_conversion[i].usage_id == usage_id && +			unit_conversion[i].unit == attr_info->units) { +			exp  = hid_sensor_convert_exponent( +						attr_info->unit_expo); +			adjust_exponent_micro(val0, val1, +					unit_conversion[i].scale_val0, +					unit_conversion[i].scale_val1, exp); +			break; +		} +	} + +	return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_format_scale); + +int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,  					u32 usage_id,  					struct hid_sensor_common *st)  { -  	sensor_hub_input_get_attribute_info(hsdev,  					HID_FEATURE_REPORT, usage_id,  					HID_USAGE_SENSOR_PROP_REPORT_INTERVAL,  					&st->poll); +	/* Default unit of measure is milliseconds */ +	if (st->poll.units == 0) +		st->poll.units = HID_USAGE_SENSOR_UNITS_MILLISECOND; +	return 0; + +} + +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, +					u32 usage_id, +					struct hid_sensor_common *st) +{ + + +	hid_sensor_get_reporting_interval(hsdev, usage_id, st);  	sensor_hub_input_get_attribute_info(hsdev,  					HID_FEATURE_REPORT, usage_id, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 87419c41b99..a3109a6f4d8 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -28,32 +28,70 @@  #include <linux/iio/sysfs.h>  #include "hid-sensor-trigger.h" -static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, -						bool state) +int hid_sensor_power_state(struct hid_sensor_common *st, bool state)  { -	struct hid_sensor_common *st = iio_trigger_get_drvdata(trig);  	int state_val; +	int report_val; + +	if (state) { +		if (sensor_hub_device_open(st->hsdev)) +			return -EIO; + +		atomic_inc(&st->data_ready); -	state_val = state ? 1 : 0; -	if (IS_ENABLED(CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS)) -		++state_val; -	st->data_ready = state; -	sensor_hub_set_feature(st->hsdev, st->power_state.report_id, +		state_val = hid_sensor_get_usage_index(st->hsdev, +			st->power_state.report_id, +			st->power_state.index, +			HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM); +		report_val = hid_sensor_get_usage_index(st->hsdev, +			st->report_state.report_id, +			st->report_state.index, +			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM); +	} else { +		if (!atomic_dec_and_test(&st->data_ready)) +			return 0; +		sensor_hub_device_close(st->hsdev); +		state_val = hid_sensor_get_usage_index(st->hsdev, +			st->power_state.report_id, +			st->power_state.index, +			HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM); +		report_val = hid_sensor_get_usage_index(st->hsdev, +			st->report_state.report_id, +			st->report_state.index, +			HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM); +	} + +	if (state_val >= 0) { +		state_val += st->power_state.logical_minimum; +		sensor_hub_set_feature(st->hsdev, st->power_state.report_id,  					st->power_state.index,  					(s32)state_val); +	} -	sensor_hub_set_feature(st->hsdev, st->report_state.report_id, +	if (report_val >= 0) { +		report_val += st->report_state.logical_minimum; +		sensor_hub_set_feature(st->hsdev, st->report_state.report_id,  					st->report_state.index, -					(s32)state_val); +					(s32)report_val); +	} +	sensor_hub_get_feature(st->hsdev, st->power_state.report_id, +					st->power_state.index, +					&state_val);  	return 0;  } +EXPORT_SYMBOL(hid_sensor_power_state); + +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, +						bool state) +{ +	return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); +} -void hid_sensor_remove_trigger(struct iio_dev *indio_dev) +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)  { -	iio_trigger_unregister(indio_dev->trig); -	iio_trigger_free(indio_dev->trig); -	indio_dev->trig = NULL; +	iio_trigger_unregister(attrb->trigger); +	iio_trigger_free(attrb->trigger);  }  EXPORT_SYMBOL(hid_sensor_remove_trigger); @@ -84,7 +122,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,  		dev_err(&indio_dev->dev, "Trigger Register Failed\n");  		goto error_free_trig;  	} -	indio_dev->trig = trig; +	indio_dev->trig = attrb->trigger = trig;  	return ret; diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h index 9a8731478ed..0f8e78c249d 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -21,6 +21,7 @@  int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,  				struct hid_sensor_common *attrb); -void hid_sensor_remove_trigger(struct iio_dev *indio_dev); +void hid_sensor_remove_trigger(struct hid_sensor_common *attrb); +int hid_sensor_power_state(struct hid_sensor_common *st, bool state);  #endif diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index 71a2c5f63b9..1665c8e4b62 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -113,11 +113,8 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)  	if (len < 0)  		goto st_sensors_get_buffer_element_error; -	if (indio_dev->scan_timestamp) -		*(s64 *)((u8 *)sdata->buffer_data + -				ALIGN(len, sizeof(s64))) = pf->timestamp; - -	iio_push_to_buffers(indio_dev, sdata->buffer_data); +	iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data, +		pf->timestamp);  st_sensors_get_buffer_element_error:  	iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 965ee22d3ac..e8b932fed70 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -13,6 +13,7 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/iio/iio.h> +#include <linux/regulator/consumer.h>  #include <asm/unaligned.h>  #include <linux/iio/common/st_sensors.h> @@ -198,21 +199,53 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)  }  EXPORT_SYMBOL(st_sensors_set_axis_enable); -int st_sensors_init_sensor(struct iio_dev *indio_dev, -					struct st_sensors_platform_data *pdata) +void st_sensors_power_enable(struct iio_dev *indio_dev)  { +	struct st_sensor_data *pdata = iio_priv(indio_dev);  	int err; -	struct st_sensor_data *sdata = iio_priv(indio_dev); -	mutex_init(&sdata->tb.buf_lock); +	/* Regulators not mandatory, but if requested we should enable them. */ +	pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); +	if (!IS_ERR(pdata->vdd)) { +		err = regulator_enable(pdata->vdd); +		if (err != 0) +			dev_warn(&indio_dev->dev, +				 "Failed to enable specified Vdd supply\n"); +	} + +	pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); +	if (!IS_ERR(pdata->vdd_io)) { +		err = regulator_enable(pdata->vdd_io); +		if (err != 0) +			dev_warn(&indio_dev->dev, +				 "Failed to enable specified Vdd_IO supply\n"); +	} +} +EXPORT_SYMBOL(st_sensors_power_enable); + +void st_sensors_power_disable(struct iio_dev *indio_dev) +{ +	struct st_sensor_data *pdata = iio_priv(indio_dev); + +	if (!IS_ERR(pdata->vdd)) +		regulator_disable(pdata->vdd); + +	if (!IS_ERR(pdata->vdd_io)) +		regulator_disable(pdata->vdd_io); +} +EXPORT_SYMBOL(st_sensors_power_disable); + +static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, +				       struct st_sensors_platform_data *pdata) +{ +	struct st_sensor_data *sdata = iio_priv(indio_dev);  	switch (pdata->drdy_int_pin) {  	case 1:  		if (sdata->sensor->drdy_irq.mask_int1 == 0) {  			dev_err(&indio_dev->dev,  					"DRDY on INT1 not available.\n"); -			err = -EINVAL; -			goto init_error; +			return -EINVAL;  		}  		sdata->drdy_int_pin = 1;  		break; @@ -220,39 +253,53 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,  		if (sdata->sensor->drdy_irq.mask_int2 == 0) {  			dev_err(&indio_dev->dev,  					"DRDY on INT2 not available.\n"); -			err = -EINVAL; -			goto init_error; +			return -EINVAL;  		}  		sdata->drdy_int_pin = 2;  		break;  	default:  		dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n"); -		err = -EINVAL; -		goto init_error; +		return -EINVAL;  	} +	return 0; +} + +int st_sensors_init_sensor(struct iio_dev *indio_dev, +					struct st_sensors_platform_data *pdata) +{ +	struct st_sensor_data *sdata = iio_priv(indio_dev); +	int err = 0; + +	mutex_init(&sdata->tb.buf_lock); + +	if (pdata) +		err = st_sensors_set_drdy_int_pin(indio_dev, pdata); +  	err = st_sensors_set_enable(indio_dev, false);  	if (err < 0) -		goto init_error; +		return err; -	err = st_sensors_set_fullscale(indio_dev, -						sdata->current_fullscale->num); -	if (err < 0) -		goto init_error; +	if (sdata->current_fullscale) { +		err = st_sensors_set_fullscale(indio_dev, +					       sdata->current_fullscale->num); +		if (err < 0) +			return err; +	} else +		dev_info(&indio_dev->dev, "Full-scale not possible\n");  	err = st_sensors_set_odr(indio_dev, sdata->odr);  	if (err < 0) -		goto init_error; +		return err;  	/* set BDU */  	err = st_sensors_write_data_with_mask(indio_dev,  			sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);  	if (err < 0) -		goto init_error; +		return err;  	err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); -init_error:  	return err;  }  EXPORT_SYMBOL(st_sensors_init_sensor); @@ -263,6 +310,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)  	u8 drdy_mask;  	struct st_sensor_data *sdata = iio_priv(indio_dev); +	if (!sdata->sensor->drdy_irq.addr) +		return 0; +  	/* Enable/Disable the interrupt generator 1. */  	if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {  		err = st_sensors_write_data_with_mask(indio_dev, @@ -318,10 +368,8 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,  	unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;  	outdata = kmalloc(byte_for_channel, GFP_KERNEL); -	if (!outdata) { -		err = -EINVAL; -		goto st_sensors_read_axis_data_error; -	} +	if (!outdata) +		return -ENOMEM;  	err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,  				ch->address, byte_for_channel, @@ -336,7 +384,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,  st_sensors_free_memory:  	kfree(outdata); -st_sensors_read_axis_data_error: +  	return err;  } @@ -349,28 +397,25 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,  	mutex_lock(&indio_dev->mlock);  	if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {  		err = -EBUSY; -		goto read_error; +		goto out;  	} else {  		err = st_sensors_set_enable(indio_dev, true);  		if (err < 0) -			goto read_error; +			goto out;  		msleep((sdata->sensor->bootime * 1000) / sdata->odr);  		err = st_sensors_read_axis_data(indio_dev, ch, val);  		if (err < 0) -			goto read_error; +			goto out;  		*val = *val >> ch->scan_type.shift;  		err = st_sensors_set_enable(indio_dev, false);  	} +out:  	mutex_unlock(&indio_dev->mlock);  	return err; - -read_error: -	mutex_unlock(&indio_dev->mlock); -	return err;  }  EXPORT_SYMBOL(st_sensors_read_info_raw);  | 
