diff options
Diffstat (limited to 'drivers/iio/accel')
| -rw-r--r-- | drivers/iio/accel/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/iio/accel/Makefile | 1 | ||||
| -rw-r--r-- | drivers/iio/accel/bma180.c | 42 | ||||
| -rw-r--r-- | drivers/iio/accel/hid-sensor-accel-3d.c | 76 | ||||
| -rw-r--r-- | drivers/iio/accel/kxsd9.c | 14 | ||||
| -rw-r--r-- | drivers/iio/accel/mma8452.c | 445 | ||||
| -rw-r--r-- | drivers/iio/accel/st_accel_buffer.c | 11 | ||||
| -rw-r--r-- | drivers/iio/accel/st_accel_core.c | 37 | 
8 files changed, 564 insertions, 74 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index e23e5085065..1e120fa1e15 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -65,4 +65,16 @@ config KXSD9  	  Say yes here to build support for the Kionix KXSD9 accelerometer.  	  Currently this only supports the device via an SPI interface. +config MMA8452 +	tristate "Freescale MMA8452Q Accelerometer Driver" +	depends on I2C +	select IIO_BUFFER +	select IIO_TRIGGERED_BUFFER +	help +	  Say yes here to build support for the Freescale MMA8452Q 3-axis +	  accelerometer. + +	  To compile this driver as a module, choose M here: the module +	  will be called mma8452. +  endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index c48d15f2561..dc0e379c259 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -6,6 +6,7 @@  obj-$(CONFIG_BMA180) += bma180.o  obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o  obj-$(CONFIG_KXSD9)	+= kxsd9.o +obj-$(CONFIG_MMA8452)	+= mma8452.o  obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o  st_accel-y := st_accel_core.o diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 81e3dc26099..a077cc86421 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -68,13 +68,13 @@  /* Defaults values */  #define BMA180_DEF_PMODE	0  #define BMA180_DEF_BW		20 -#define BMA180_DEF_SCALE	250 +#define BMA180_DEF_SCALE	2452  /* Available values for sysfs */  #define BMA180_FLP_FREQ_AVAILABLE \  	"10 20 40 75 150 300"  #define BMA180_SCALE_AVAILABLE \ -	"0.000130 0.000190 0.000250 0.000380 0.000500 0.000990 0.001980" +	"0.001275 0.001863 0.002452 0.003727 0.004903 0.009709 0.019417"  struct bma180_data {  	struct i2c_client *client; @@ -94,7 +94,7 @@ enum bma180_axis {  };  static int bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ -static int scale_table[] = { 130, 190, 250, 380, 500, 990, 1980 }; +static int scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };  static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis)  { @@ -376,6 +376,8 @@ static int bma180_write_raw(struct iio_dev *indio_dev,  		mutex_unlock(&data->mutex);  		return ret;  	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: +		if (val2) +			return -EINVAL;  		mutex_lock(&data->mutex);  		ret = bma180_set_bw(data, val);  		mutex_unlock(&data->mutex); @@ -447,23 +449,28 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {  	{ },  }; -#define BMA180_CHANNEL(_index) {					\ +#define BMA180_CHANNEL(_axis) {					\  	.type = IIO_ACCEL,						\ -	.indexed = 1,							\ -	.channel = (_index),						\ -	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\ +	.modified = 1,							\ +	.channel2 = IIO_MOD_##_axis,					\ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),			\ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\  		BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),	\ -	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\ -	.scan_index = (_index),						\ -	.scan_type = IIO_ST('s', 14, 16, 2),				\ +	.scan_index = AXIS_##_axis,					\ +	.scan_type = {							\ +		.sign = 's',						\ +		.realbits = 14,						\ +		.storagebits = 16,					\ +		.shift = 2,						\ +	},								\  	.ext_info = bma180_ext_info,					\  }  static const struct iio_chan_spec bma180_channels[] = { -	BMA180_CHANNEL(AXIS_X), -	BMA180_CHANNEL(AXIS_Y), -	BMA180_CHANNEL(AXIS_Z), -	IIO_CHAN_SOFT_TIMESTAMP(4), +	BMA180_CHANNEL(X), +	BMA180_CHANNEL(Y), +	BMA180_CHANNEL(Z), +	IIO_CHAN_SOFT_TIMESTAMP(3),  };  static irqreturn_t bma180_trigger_handler(int irq, void *p) @@ -471,13 +478,10 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)  	struct iio_poll_func *pf = p;  	struct iio_dev *indio_dev = pf->indio_dev;  	struct bma180_data *data = iio_priv(indio_dev); +	int64_t time_ns = iio_get_time_ns();  	int bit, ret, i = 0;  	mutex_lock(&data->mutex); -	if (indio_dev->scan_timestamp) { -		ret = indio_dev->scan_bytes / sizeof(s64) - 1; -		((s64 *)data->buff)[ret] = iio_get_time_ns(); -	}  	for_each_set_bit(bit, indio_dev->buffer->scan_mask,  			 indio_dev->masklength) { @@ -490,7 +494,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)  	}  	mutex_unlock(&data->mutex); -	iio_push_to_buffers(indio_dev, (u8 *)data->buff); +	iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);  err:  	iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 46d22f3fb1a..54e464e4bb7 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.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> @@ -42,6 +43,10 @@ struct accel_3d_state {  	struct hid_sensor_common common_attributes;  	struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];  	u32 accel_val[ACCEL_3D_CHANNEL_MAX]; +	int scale_pre_decml; +	int scale_post_decml; +	int scale_precision; +	int value_offset;  };  static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = { @@ -56,6 +61,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {  		.type = IIO_ACCEL,  		.modified = 1,  		.channel2 = IIO_MOD_X, +		.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) | @@ -65,6 +71,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {  		.type = IIO_ACCEL,  		.modified = 1,  		.channel2 = IIO_MOD_Y, +		.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) | @@ -74,6 +81,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {  		.type = IIO_ACCEL,  		.modified = 1,  		.channel2 = IIO_MOD_Z, +		.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) | @@ -102,44 +110,52 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,  	struct accel_3d_state *accel_state = iio_priv(indio_dev);  	int report_id = -1;  	u32 address; -	int ret;  	int ret_type; +	s32 poll_value;  	*val = 0;  	*val2 = 0;  	switch (mask) {  	case 0: +		poll_value = hid_sensor_read_poll_value( +					&accel_state->common_attributes); +		if (poll_value < 0) +			return -EINVAL; + +		hid_sensor_power_state(&accel_state->common_attributes, true); +		msleep_interruptible(poll_value * 2);  		report_id = accel_state->accel[chan->scan_index].report_id;  		address = accel_3d_addresses[chan->scan_index];  		if (report_id >= 0)  			*val = sensor_hub_input_attr_get_raw_value( -				accel_state->common_attributes.hsdev, -				HID_USAGE_SENSOR_ACCEL_3D, address, -				report_id); +					accel_state->common_attributes.hsdev, +					HID_USAGE_SENSOR_ACCEL_3D, address, +					report_id);  		else {  			*val = 0; +			hid_sensor_power_state(&accel_state->common_attributes, +						 false);  			return -EINVAL;  		} +		hid_sensor_power_state(&accel_state->common_attributes, false);  		ret_type = IIO_VAL_INT;  		break;  	case IIO_CHAN_INFO_SCALE: -		*val = accel_state->accel[CHANNEL_SCAN_INDEX_X].units; -		ret_type = IIO_VAL_INT; +		*val = accel_state->scale_pre_decml; +		*val2 = accel_state->scale_post_decml; +		ret_type = accel_state->scale_precision;  		break;  	case IIO_CHAN_INFO_OFFSET: -		*val = hid_sensor_convert_exponent( -			accel_state->accel[CHANNEL_SCAN_INDEX_X].unit_expo); +		*val = accel_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(  			&accel_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(  			&accel_state->common_attributes, val, val2); -		ret_type = IIO_VAL_INT_PLUS_MICRO;  		break;  	default:  		ret_type = -EINVAL; @@ -182,10 +198,11 @@ static const struct iio_info accel_3d_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 */ @@ -196,11 +213,10 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,  	struct iio_dev *indio_dev = platform_get_drvdata(priv);  	struct accel_3d_state *accel_state = iio_priv(indio_dev); -	dev_dbg(&indio_dev->dev, "accel_3d_proc_event [%d]\n", -				accel_state->common_attributes.data_ready); -	if (accel_state->common_attributes.data_ready) +	dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n"); +	if (atomic_read(&accel_state->common_attributes.data_ready))  		hid_sensor_push_data(indio_dev, -				(u8 *)accel_state->accel_val, +				accel_state->accel_val,  				sizeof(accel_state->accel_val));  	return 0; @@ -261,6 +277,23 @@ static int accel_3d_parse_report(struct platform_device *pdev,  			st->accel[1].index, st->accel[1].report_id,  			st->accel[2].index, st->accel[2].report_id); +	st->scale_precision = hid_sensor_format_scale( +				HID_USAGE_SENSOR_ACCEL_3D, +				&st->accel[CHANNEL_SCAN_INDEX_X], +				&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_ACCELERATION, +			&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;  } @@ -320,7 +353,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "failed to initialize trigger buffer\n");  		goto error_free_dev_mem;  	} -	accel_state->common_attributes.data_ready = false; +	atomic_set(&accel_state->common_attributes.data_ready, 0);  	ret = hid_sensor_setup_trigger(indio_dev, name,  					&accel_state->common_attributes);  	if (ret < 0) { @@ -349,7 +382,7 @@ static int hid_accel_3d_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(&accel_state->common_attributes);  error_unreg_buffer_funcs:  	iio_triggered_buffer_cleanup(indio_dev);  error_free_dev_mem: @@ -362,10 +395,11 @@ static int hid_accel_3d_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 accel_3d_state *accel_state = iio_priv(indio_dev);  	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);  	iio_device_unregister(indio_dev); -	hid_sensor_remove_trigger(indio_dev); +	hid_sensor_remove_trigger(&accel_state->common_attributes);  	iio_triggered_buffer_cleanup(indio_dev);  	kfree(indio_dev->channels); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 709c13259f1..98ba761cbb9 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -112,9 +112,10 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address)  	mutex_lock(&st->buf_lock);  	st->tx[0] = KXSD9_READ(address);  	ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); -	if (ret) -		return ret; -	return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); +	if (!ret) +		ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); +	mutex_unlock(&st->buf_lock); +	return ret;  }  static IIO_CONST_ATTR(accel_scale_available, @@ -222,7 +223,6 @@ static int kxsd9_probe(struct spi_device *spi)  {  	struct iio_dev *indio_dev;  	struct kxsd9_state *st; -	int ret;  	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));  	if (!indio_dev) @@ -244,11 +244,7 @@ static int kxsd9_probe(struct spi_device *spi)  	spi_setup(spi);  	kxsd9_power_up(st); -	ret = iio_device_register(indio_dev); -	if (ret) -		return ret; - -	return 0; +	return iio_device_register(indio_dev);  }  static int kxsd9_remove(struct spi_device *spi) diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c new file mode 100644 index 00000000000..2a5fa9a436e --- /dev/null +++ b/drivers/iio/accel/mma8452.c @@ -0,0 +1,445 @@ +/* + * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer + * + * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License.  See the file COPYING in the main + * directory of this archive for more details. + * + * 7-bit I2C slave address 0x1c/0x1d (pin selectable) + * + * TODO: interrupt, thresholding, orientation / freefall events, autosleep + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/delay.h> + +#define MMA8452_STATUS 0x00 +#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit  */ +#define MMA8452_OUT_Y 0x03 +#define MMA8452_OUT_Z 0x05 +#define MMA8452_WHO_AM_I 0x0d +#define MMA8452_DATA_CFG 0x0e +#define MMA8452_OFF_X 0x2f +#define MMA8452_OFF_Y 0x30 +#define MMA8452_OFF_Z 0x31 +#define MMA8452_CTRL_REG1 0x2a +#define MMA8452_CTRL_REG2 0x2b + +#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) + +#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3)) +#define MMA8452_CTRL_DR_SHIFT 3 +#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ +#define MMA8452_CTRL_ACTIVE BIT(0) + +#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0)) +#define MMA8452_DATA_CFG_FS_2G 0 +#define MMA8452_DATA_CFG_FS_4G 1 +#define MMA8452_DATA_CFG_FS_8G 2 + +#define MMA8452_DEVICE_ID 0x2a + +struct mma8452_data { +	struct i2c_client *client; +	struct mutex lock; +	u8 ctrl_reg1; +	u8 data_cfg; +}; + +static int mma8452_drdy(struct mma8452_data *data) +{ +	int tries = 150; + +	while (tries-- > 0) { +		int ret = i2c_smbus_read_byte_data(data->client, +			MMA8452_STATUS); +		if (ret < 0) +			return ret; +		if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) +			return 0; +		msleep(20); +	} + +	dev_err(&data->client->dev, "data not ready\n"); +	return -EIO; +} + +static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) +{ +	int ret = mma8452_drdy(data); +	if (ret < 0) +		return ret; +	return i2c_smbus_read_i2c_block_data(data->client, +		MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); +} + +static ssize_t mma8452_show_int_plus_micros(char *buf, +	const int (*vals)[2], int n) +{ +	size_t len = 0; + +	while (n-- > 0) +		len += scnprintf(buf + len, PAGE_SIZE - len, +			"%d.%06d ", vals[n][0], vals[n][1]); + +	/* replace trailing space by newline */ +	buf[len - 1] = '\n'; + +	return len; +} + +static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, +					int val, int val2) +{ +	while (n-- > 0) +		if (val == vals[n][0] && val2 == vals[n][1]) +			return n; + +	return -EINVAL; +} + +static const int mma8452_samp_freq[8][2] = { +	{800, 0}, {400, 0}, {200, 0}, {100, 0}, {50, 0}, {12, 500000}, +	{6, 250000}, {1, 560000} +}; + +/*  + * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 + * The userspace interface uses m/s^2 and we declare micro units + * So scale factor is given by: + * 	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + */ +static const int mma8452_scales[3][2] = { +	{0, 9577}, {0, 19154}, {0, 38307} +}; + +static ssize_t mma8452_show_samp_freq_avail(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, +		ARRAY_SIZE(mma8452_samp_freq)); +} + +static ssize_t mma8452_show_scale_avail(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	return mma8452_show_int_plus_micros(buf, mma8452_scales, +		ARRAY_SIZE(mma8452_scales)); +} + +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); +static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, +	mma8452_show_scale_avail, NULL, 0); + +static int mma8452_get_samp_freq_index(struct mma8452_data *data, +	int val, int val2) +{ +	return mma8452_get_int_plus_micros_index(mma8452_samp_freq, +		ARRAY_SIZE(mma8452_samp_freq), val, val2); +} + +static int mma8452_get_scale_index(struct mma8452_data *data, +	int val, int val2) +{ +	return mma8452_get_int_plus_micros_index(mma8452_scales, +		ARRAY_SIZE(mma8452_scales), val, val2); +} + +static int mma8452_read_raw(struct iio_dev *indio_dev, +			    struct iio_chan_spec const *chan, +			    int *val, int *val2, long mask) +{ +	struct mma8452_data *data = iio_priv(indio_dev); +	__be16 buffer[3]; +	int i, ret; + +	switch (mask) { +	case IIO_CHAN_INFO_RAW: +		if (iio_buffer_enabled(indio_dev)) +			return -EBUSY; + +		mutex_lock(&data->lock); +		ret = mma8452_read(data, buffer); +		mutex_unlock(&data->lock); +		if (ret < 0) +			return ret; +		*val = sign_extend32( +			be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); +		return IIO_VAL_INT; +	case IIO_CHAN_INFO_SCALE: +		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; +		*val = mma8452_scales[i][0]; +		*val2 = mma8452_scales[i][1]; +		return IIO_VAL_INT_PLUS_MICRO; +	case IIO_CHAN_INFO_SAMP_FREQ: +		i = (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >> +			MMA8452_CTRL_DR_SHIFT; +		*val = mma8452_samp_freq[i][0]; +		*val2 = mma8452_samp_freq[i][1]; +		return IIO_VAL_INT_PLUS_MICRO; +	case IIO_CHAN_INFO_CALIBBIAS: +		ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + +			chan->scan_index); +		if (ret < 0) +			return ret; +		*val = sign_extend32(ret, 7); +		return IIO_VAL_INT; +	} +	return -EINVAL; +} + +static int mma8452_standby(struct mma8452_data *data) +{ +	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, +		data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); +} + +static int mma8452_active(struct mma8452_data *data) +{ +	return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, +		data->ctrl_reg1); +} + +static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) +{ +	int ret; + +	mutex_lock(&data->lock); + +	/* config can only be changed when in standby */ +	ret = mma8452_standby(data); +	if (ret < 0) +		goto fail; + +	ret = i2c_smbus_write_byte_data(data->client, reg, val); +	if (ret < 0) +		goto fail; + +	ret = mma8452_active(data); +	if (ret < 0) +		goto fail; + +	ret = 0; +fail: +	mutex_unlock(&data->lock); +	return ret; +} + +static int mma8452_write_raw(struct iio_dev *indio_dev, +			     struct iio_chan_spec const *chan, +			     int val, int val2, long mask) +{ +	struct mma8452_data *data = iio_priv(indio_dev); +	int i; + +	if (iio_buffer_enabled(indio_dev)) +		return -EBUSY; + +	switch (mask) { +	case IIO_CHAN_INFO_SAMP_FREQ: +		i = mma8452_get_samp_freq_index(data, val, val2); +		if (i < 0) +			return -EINVAL; + +		data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; +		data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; +		return mma8452_change_config(data, MMA8452_CTRL_REG1, +			data->ctrl_reg1); +	case IIO_CHAN_INFO_SCALE: +		i = mma8452_get_scale_index(data, val, val2); +		if (i < 0) +			return -EINVAL; +		data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; +		data->data_cfg |= i; +		return mma8452_change_config(data, MMA8452_DATA_CFG, +			data->data_cfg); +	case IIO_CHAN_INFO_CALIBBIAS: +		if (val < -128 || val > 127) +			return -EINVAL; +		return mma8452_change_config(data, MMA8452_OFF_X + +			chan->scan_index, val); +	default: +		return -EINVAL; +	} +} + +static irqreturn_t mma8452_trigger_handler(int irq, void *p) +{ +	struct iio_poll_func *pf = p; +	struct iio_dev *indio_dev = pf->indio_dev; +	struct mma8452_data *data = iio_priv(indio_dev); +	u8 buffer[16]; /* 3 16-bit channels + padding + ts */ +	int ret; + +	ret = mma8452_read(data, (__be16 *) buffer); +	if (ret < 0) +		goto done; + +	iio_push_to_buffers_with_timestamp(indio_dev, buffer, +		iio_get_time_ns()); + +done: +	iio_trigger_notify_done(indio_dev->trig); +	return IRQ_HANDLED; +} + +#define MMA8452_CHANNEL(axis, idx) { \ +	.type = IIO_ACCEL, \ +	.modified = 1, \ +	.channel2 = IIO_MOD_##axis, \ +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ +		BIT(IIO_CHAN_INFO_CALIBBIAS), \ +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ +		BIT(IIO_CHAN_INFO_SCALE), \ +	.scan_index = idx, \ +	.scan_type = { \ +		.sign = 's', \ +		.realbits = 12, \ +		.storagebits = 16, \ +		.shift = 4, \ +		.endianness = IIO_BE, \ +	}, \ +} + +static const struct iio_chan_spec mma8452_channels[] = { +	MMA8452_CHANNEL(X, 0), +	MMA8452_CHANNEL(Y, 1), +	MMA8452_CHANNEL(Z, 2), +	IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static struct attribute *mma8452_attributes[] = { +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr, +	&iio_dev_attr_in_accel_scale_available.dev_attr.attr, +	NULL +}; + +static const struct attribute_group mma8452_group = { +	.attrs = mma8452_attributes, +}; + +static const struct iio_info mma8452_info = { +	.attrs = &mma8452_group, +	.read_raw = &mma8452_read_raw, +	.write_raw = &mma8452_write_raw, +	.driver_module = THIS_MODULE, +}; + +static const unsigned long mma8452_scan_masks[] = {0x7, 0}; + +static int mma8452_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct mma8452_data *data; +	struct iio_dev *indio_dev; +	int ret; + +	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); +	if (ret < 0) +		return ret; +	if (ret != MMA8452_DEVICE_ID) +		return -ENODEV; + +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); +	if (!indio_dev) +		return -ENOMEM; + +	data = iio_priv(indio_dev); +	data->client = client; +	mutex_init(&data->lock); + +	i2c_set_clientdata(client, indio_dev); +	indio_dev->info = &mma8452_info; +	indio_dev->name = id->name; +	indio_dev->dev.parent = &client->dev; +	indio_dev->modes = INDIO_DIRECT_MODE; +	indio_dev->channels = mma8452_channels; +	indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); +	indio_dev->available_scan_masks = mma8452_scan_masks; + +	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | +		(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); +	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, +		data->ctrl_reg1); +	if (ret < 0) +		return ret; + +	data->data_cfg = MMA8452_DATA_CFG_FS_2G; +	ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, +		data->data_cfg); +	if (ret < 0) +		return ret; + +	ret = iio_triggered_buffer_setup(indio_dev, NULL, +		mma8452_trigger_handler, NULL); +	if (ret < 0) +		return ret; + +	ret = iio_device_register(indio_dev); +	if (ret < 0) +		goto buffer_cleanup; +	return 0; + +buffer_cleanup: +	iio_triggered_buffer_cleanup(indio_dev); +	return ret; +} + +static int mma8452_remove(struct i2c_client *client) +{ +	struct iio_dev *indio_dev = i2c_get_clientdata(client); + +	iio_device_unregister(indio_dev); +	iio_triggered_buffer_cleanup(indio_dev); +	mma8452_standby(iio_priv(indio_dev)); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mma8452_suspend(struct device *dev) +{ +	return mma8452_standby(iio_priv(i2c_get_clientdata( +		to_i2c_client(dev)))); +} + +static int mma8452_resume(struct device *dev) +{ +	return mma8452_active(iio_priv(i2c_get_clientdata( +		to_i2c_client(dev)))); +} + +static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); +#define MMA8452_PM_OPS (&mma8452_pm_ops) +#else +#define MMA8452_PM_OPS NULL +#endif + +static const struct i2c_device_id mma8452_id[] = { +	{ "mma8452", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, mma8452_id); + +static struct i2c_driver mma8452_driver = { +	.driver = { +		.name	= "mma8452", +		.pm	= MMA8452_PM_OPS, +	}, +	.probe = mma8452_probe, +	.remove = mma8452_remove, +	.id_table = mma8452_id, +}; +module_i2c_driver(mma8452_driver); + +MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); +MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index d9b350756f9..a1e642ee13d 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -32,16 +32,7 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state)  static int st_accel_buffer_preenable(struct iio_dev *indio_dev)  { -	int err; - -	err = st_sensors_set_enable(indio_dev, true); -	if (err < 0) -		goto st_accel_set_enable_error; - -	err = iio_sw_buffer_preenable(indio_dev); - -st_accel_set_enable_error: -	return err; +	return st_sensors_set_enable(indio_dev, true);  }  static int st_accel_buffer_postenable(struct iio_dev *indio_dev) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 1458343f6f3..a2abf7c2ce3 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -452,16 +452,19 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {  int st_accel_common_probe(struct iio_dev *indio_dev,  				struct st_sensors_platform_data *plat_data)  { -	int err;  	struct st_sensor_data *adata = iio_priv(indio_dev); +	int irq = adata->get_irq_data_ready(indio_dev); +	int err;  	indio_dev->modes = INDIO_DIRECT_MODE;  	indio_dev->info = &accel_info; +	st_sensors_power_enable(indio_dev); +  	err = st_sensors_check_device_support(indio_dev,  				ARRAY_SIZE(st_accel_sensors), st_accel_sensors);  	if (err < 0) -		goto st_accel_common_probe_error; +		return err;  	adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;  	adata->multiread_bit = adata->sensor->multi_read_bit; @@ -478,13 +481,13 @@ int st_accel_common_probe(struct iio_dev *indio_dev,  	err = st_sensors_init_sensor(indio_dev, plat_data);  	if (err < 0) -		goto st_accel_common_probe_error; +		return err; -	if (adata->get_irq_data_ready(indio_dev) > 0) { -		err = st_accel_allocate_ring(indio_dev); -		if (err < 0) -			goto st_accel_common_probe_error; +	err = st_accel_allocate_ring(indio_dev); +	if (err < 0) +		return err; +	if (irq > 0) {  		err = st_sensors_allocate_trigger(indio_dev,  						 ST_ACCEL_TRIGGER_OPS);  		if (err < 0) @@ -495,15 +498,17 @@ int st_accel_common_probe(struct iio_dev *indio_dev,  	if (err)  		goto st_accel_device_register_error; -	return err; +	dev_info(&indio_dev->dev, "registered accelerometer %s\n", +		 indio_dev->name); + +	return 0;  st_accel_device_register_error: -	if (adata->get_irq_data_ready(indio_dev) > 0) +	if (irq > 0)  		st_sensors_deallocate_trigger(indio_dev);  st_accel_probe_trigger_error: -	if (adata->get_irq_data_ready(indio_dev) > 0) -		st_accel_deallocate_ring(indio_dev); -st_accel_common_probe_error: +	st_accel_deallocate_ring(indio_dev); +  	return err;  }  EXPORT_SYMBOL(st_accel_common_probe); @@ -512,11 +517,13 @@ void st_accel_common_remove(struct iio_dev *indio_dev)  {  	struct st_sensor_data *adata = iio_priv(indio_dev); +	st_sensors_power_disable(indio_dev); +  	iio_device_unregister(indio_dev); -	if (adata->get_irq_data_ready(indio_dev) > 0) { +	if (adata->get_irq_data_ready(indio_dev) > 0)  		st_sensors_deallocate_trigger(indio_dev); -		st_accel_deallocate_ring(indio_dev); -	} + +	st_accel_deallocate_ring(indio_dev);  }  EXPORT_SYMBOL(st_accel_common_remove);  | 
