lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <53C2D2C8.2010609@kernel.org>
Date:	Sun, 13 Jul 2014 19:41:12 +0100
From:	Jonathan Cameron <jic23@...nel.org>
To:	Josef Gajdusek <atx@...lax.net>, linux-iio@...r.kernel.org
CC:	devel@...verdev.osuosl.org, gregkh@...uxfoundation.org,
	linux-kernel@...r.kernel.org, pmeerw@...erw.net,
	dan.carpenter@...cle.com
Subject: Re: [PATCH v3 2/5] staging:iio:hmc5843: Split hmc5843.c to multiple
 files

On 08/07/14 14:39, Josef Gajdusek wrote:
> This patch splits hmc5843.c to multiple files - the interface-agnostic
> hmc5843_core.c, i2c specific hmc5843_i2c.c and header file hmc5843.h. This is
> another step to add support of SPI-enabled hmc5983.
>
> Signed-off-by: Josef Gajdusek <atx@....name>
Something rather odd is going on when I try to apply this patch to my tree.
It simply refuses to apply and patch -p1  thinks part of it has already
happened. I'm too confused to figure it out at this time on a Sunday.
For now I'm backing out patch 1 as well.

Jonathan
> ---
>   drivers/staging/iio/magnetometer/Kconfig        |  16 +-
>   drivers/staging/iio/magnetometer/Makefile       |   3 +-
>   drivers/staging/iio/magnetometer/hmc5843.c      | 702 ------------------------
>   drivers/staging/iio/magnetometer/hmc5843.h      |  75 +++
>   drivers/staging/iio/magnetometer/hmc5843_core.c | 598 ++++++++++++++++++++
>   drivers/staging/iio/magnetometer/hmc5843_i2c.c  | 106 ++++
>   6 files changed, 793 insertions(+), 707 deletions(-)
>   delete mode 100644 drivers/staging/iio/magnetometer/hmc5843.c
>   create mode 100644 drivers/staging/iio/magnetometer/hmc5843.h
>   create mode 100644 drivers/staging/iio/magnetometer/hmc5843_core.c
>   create mode 100644 drivers/staging/iio/magnetometer/hmc5843_i2c.c
>
> diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
> index ad88d61..28c2612 100644
> --- a/drivers/staging/iio/magnetometer/Kconfig
> +++ b/drivers/staging/iio/magnetometer/Kconfig
> @@ -5,15 +5,23 @@ menu "Magnetometer sensors"
>
>   config SENSORS_HMC5843
>   	tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
> -	depends on I2C
> +	depends on (I2C || SPI_MASTER)
>   	select IIO_BUFFER
>   	select IIO_TRIGGERED_BUFFER
> -	select REGMAP_I2C
> +	select SENSORS_HMC5843_I2C if (I2C)
>   	help
>   	  Say Y here to add support for the Honeywell HMC5843, HMC5883 and
>   	  HMC5883L 3-Axis Magnetometer (digital compass).
>
> -	  To compile this driver as a module, choose M here: the module
> -	  will be called hmc5843.
> +	  This driver can also be compiled as a set of modules.
> +	  If so, these modules will be created:
> +	  - hmc5843_core (core functions)
> +	  - hmc5843_i2c (support for HMC5843, HMC5883 and HMC5883L)
> +
> +config SENSORS_HMC5843_I2C
> +	tristate
> +	depends on I2C
> +	depends on SENSORS_HMC5843
> +	select REGMAP_I2C
>
>   endmenu
> diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
> index f9bfb2e..65baf1c 100644
> --- a/drivers/staging/iio/magnetometer/Makefile
> +++ b/drivers/staging/iio/magnetometer/Makefile
> @@ -2,4 +2,5 @@
>   # Makefile for industrial I/O Magnetometer sensors
>   #
>
> -obj-$(CONFIG_SENSORS_HMC5843)	+= hmc5843.o
> +obj-$(CONFIG_SENSORS_HMC5843)		+= hmc5843_core.o
> +obj-$(CONFIG_SENSORS_HMC5843_I2C)	+= hmc5843_i2c.o
> diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
> deleted file mode 100644
> index a458160..0000000
> --- a/drivers/staging/iio/magnetometer/hmc5843.c
> +++ /dev/null
> @@ -1,702 +0,0 @@
> -/*  Copyright (C) 2010 Texas Instruments
> -    Author: Shubhrajyoti Datta <shubhrajyoti@...com>
> -    Acknowledgement: Jonathan Cameron <jic23@...nel.org> for valuable inputs.
> -
> -    Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@...erw.net>.
> -
> -    This program is free software; you can redistribute it and/or modify
> -    it under the terms of the GNU General Public License as published by
> -    the Free Software Foundation; either version 2 of the License, or
> -    (at your option) any later version.
> -
> -    This program is distributed in the hope that it will be useful,
> -    but WITHOUT ANY WARRANTY; without even the implied warranty of
> -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -    GNU General Public License for more details.
> -
> -    You should have received a copy of the GNU General Public License
> -    along with this program; if not, write to the Free Software
> -    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> -*/
> -
> -#include <linux/module.h>
> -#include <linux/i2c.h>
> -#include <linux/regmap.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 HMC5843_CONFIG_REG_A			0x00
> -#define HMC5843_CONFIG_REG_B			0x01
> -#define HMC5843_MODE_REG			0x02
> -#define HMC5843_DATA_OUT_MSB_REGS		0x03
> -#define HMC5843_STATUS_REG			0x09
> -#define HMC5843_ID_REG				0x0a
> -#define HMC5843_ID_END				0x0c
> -
> -enum hmc5843_ids {
> -	HMC5843_ID,
> -	HMC5883_ID,
> -	HMC5883L_ID,
> -};
> -
> -/*
> - * Range gain settings in (+-)Ga
> - * Beware: HMC5843 and HMC5883 have different recommended sensor field
> - * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
> - */
> -#define HMC5843_RANGE_GAIN_OFFSET		0x05
> -#define HMC5843_RANGE_GAIN_DEFAULT		0x01
> -#define HMC5843_RANGE_GAINS			8
> -#define HMC5843_RANGE_GAIN_MASK		0xe0
> -
> -/* Device status */
> -#define HMC5843_DATA_READY			0x01
> -#define HMC5843_DATA_OUTPUT_LOCK		0x02
> -
> -/* Mode register configuration */
> -#define HMC5843_MODE_CONVERSION_CONTINUOUS	0x00
> -#define HMC5843_MODE_CONVERSION_SINGLE		0x01
> -#define HMC5843_MODE_IDLE			0x02
> -#define HMC5843_MODE_SLEEP			0x03
> -#define HMC5843_MODE_MASK			0x03
> -
> -/*
> - * HMC5843: Minimum data output rate
> - * HMC5883: Typical data output rate
> - */
> -#define HMC5843_RATE_OFFSET			0x02
> -#define HMC5843_RATE_DEFAULT			0x04
> -#define HMC5843_RATES				7
> -#define HMC5843_RATE_MASK		0x1c
> -
> -/* Device measurement configuration */
> -#define HMC5843_MEAS_CONF_NORMAL		0x00
> -#define HMC5843_MEAS_CONF_POSITIVE_BIAS		0x01
> -#define HMC5843_MEAS_CONF_NEGATIVE_BIAS		0x02
> -#define HMC5843_MEAS_CONF_MASK			0x03
> -
> -/* Scaling factors: 10000000/Gain */
> -static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> -	6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
> -};
> -
> -static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> -	7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
> -};
> -
> -static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> -	7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
> -};
> -
> -/*
> - * From the datasheet:
> - * Value	| HMC5843		| HMC5883/HMC5883L
> - *		| Data output rate (Hz)	| Data output rate (Hz)
> - * 0		| 0.5			| 0.75
> - * 1		| 1			| 1.5
> - * 2		| 2			| 3
> - * 3		| 5			| 7.5
> - * 4		| 10 (default)		| 15
> - * 5		| 20			| 30
> - * 6		| 50			| 75
> - * 7		| Not used		| Not used
> - */
> -static const int hmc5843_regval_to_samp_freq[7][2] = {
> -	{0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0}
> -};
> -
> -static const int hmc5883_regval_to_samp_freq[7][2] = {
> -	{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
> -	{75, 0}
> -};
> -
> -/* Describe chip variants */
> -struct hmc5843_chip_info {
> -	const struct iio_chan_spec *channels;
> -	const int (*regval_to_samp_freq)[2];
> -	const int *regval_to_nanoscale;
> -};
> -
> -/* Each client has this additional data */
> -struct hmc5843_data {
> -	struct i2c_client *client;
> -	struct mutex lock;
> -	struct regmap *regmap;
> -	const struct hmc5843_chip_info *variant;
> -	__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
> -};
> -
> -/* The lower two bits contain the current conversion mode */
> -static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
> -{
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = regmap_update_bits(data->regmap, HMC5843_MODE_REG,
> -			HMC5843_MODE_MASK, operating_mode);
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int hmc5843_wait_measurement(struct hmc5843_data *data)
> -{
> -	int tries = 150;
> -	int val;
> -	int ret;
> -
> -	while (tries-- > 0) {
> -		ret = regmap_read(data->regmap, HMC5843_STATUS_REG, &val);
> -		if (ret < 0)
> -			return ret;
> -		if (val & HMC5843_DATA_READY)
> -			break;
> -		msleep(20);
> -	}
> -
> -	if (tries < 0) {
> -		dev_err(&data->client->dev, "data not ready\n");
> -		return -EIO;
> -	}
> -
> -	return 0;
> -}
> -
> -/* Return the measurement value from the specified channel */
> -static int hmc5843_read_measurement(struct hmc5843_data *data,
> -				    int idx, int *val)
> -{
> -	__be16 values[3];
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = hmc5843_wait_measurement(data);
> -	if (ret < 0) {
> -		mutex_unlock(&data->lock);
> -		return ret;
> -	}
> -	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
> -			values, sizeof(values));
> -	mutex_unlock(&data->lock);
> -	if (ret < 0)
> -		return ret;
> -
> -	*val = sign_extend32(be16_to_cpu(values[idx]), 15);
> -	return IIO_VAL_INT;
> -}
> -
> -/*
> - * API for setting the measurement configuration to
> - * Normal, Positive bias and Negative bias
> - *
> - * From the datasheet:
> - * 0 - Normal measurement configuration (default): In normal measurement
> - *     configuration the device follows normal measurement flow. Pins BP
> - *     and BN are left floating and high impedance.
> - *
> - * 1 - Positive bias configuration: In positive bias configuration, a
> - *     positive current is forced across the resistive load on pins BP
> - *     and BN.
> - *
> - * 2 - Negative bias configuration. In negative bias configuration, a
> - *     negative current is forced across the resistive load on pins BP
> - *     and BN.
> - *
> - */
> -static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
> -{
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
> -			HMC5843_MEAS_CONF_MASK, meas_conf);
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
> -						struct device_attribute *attr,
> -						char *buf)
> -{
> -	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> -	int val;
> -	int ret;
> -
> -	ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val);
> -	if (ret)
> -		return ret;
> -	val &= HMC5843_MEAS_CONF_MASK;
> -
> -	return sprintf(buf, "%d\n", val);
> -}
> -
> -static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
> -						struct device_attribute *attr,
> -						const char *buf,
> -						size_t count)
> -{
> -	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> -	unsigned long meas_conf = 0;
> -	int ret;
> -
> -	ret = kstrtoul(buf, 10, &meas_conf);
> -	if (ret)
> -		return ret;
> -	if (meas_conf >= HMC5843_MEAS_CONF_MASK)
> -		return -EINVAL;
> -
> -	ret = hmc5843_set_meas_conf(data, meas_conf);
> -
> -	return (ret < 0) ? ret : count;
> -}
> -
> -static IIO_DEVICE_ATTR(meas_conf,
> -			S_IWUSR | S_IRUGO,
> -			hmc5843_show_measurement_configuration,
> -			hmc5843_set_measurement_configuration,
> -			0);
> -
> -static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
> -				struct device_attribute *attr, char *buf)
> -{
> -	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> -	size_t len = 0;
> -	int i;
> -
> -	for (i = 0; i < HMC5843_RATES; i++)
> -		len += scnprintf(buf + len, PAGE_SIZE - len,
> -			"%d.%d ", data->variant->regval_to_samp_freq[i][0],
> -			data->variant->regval_to_samp_freq[i][1]);
> -
> -	/* replace trailing space by newline */
> -	buf[len - 1] = '\n';
> -
> -	return len;
> -}
> -
> -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail);
> -
> -static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate)
> -{
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
> -			HMC5843_RATE_MASK, rate << HMC5843_RATE_OFFSET);
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static int hmc5843_get_samp_freq_index(struct hmc5843_data *data,
> -				   int val, int val2)
> -{
> -	int i;
> -
> -	for (i = 0; i < HMC5843_RATES; i++)
> -		if (val == data->variant->regval_to_samp_freq[i][0] &&
> -			val2 == data->variant->regval_to_samp_freq[i][1])
> -			return i;
> -
> -	return -EINVAL;
> -}
> -
> -static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range)
> -{
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_B,
> -			HMC5843_RANGE_GAIN_MASK,
> -			range << HMC5843_RANGE_GAIN_OFFSET);
> -	mutex_unlock(&data->lock);
> -
> -	return ret;
> -}
> -
> -static ssize_t hmc5843_show_scale_avail(struct device *dev,
> -				struct device_attribute *attr, char *buf)
> -{
> -	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> -
> -	size_t len = 0;
> -	int i;
> -
> -	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
> -		len += scnprintf(buf + len, PAGE_SIZE - len,
> -			"0.%09d ", data->variant->regval_to_nanoscale[i]);
> -
> -	/* replace trailing space by newline */
> -	buf[len - 1] = '\n';
> -
> -	return len;
> -}
> -
> -static IIO_DEVICE_ATTR(scale_available, S_IRUGO,
> -	hmc5843_show_scale_avail, NULL, 0);
> -
> -static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
> -{
> -	int i;
> -
> -	if (val != 0)
> -		return -EINVAL;
> -
> -	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
> -		if (val2 == data->variant->regval_to_nanoscale[i])
> -			return i;
> -
> -	return -EINVAL;
> -}
> -
> -static int hmc5843_read_raw(struct iio_dev *indio_dev,
> -			    struct iio_chan_spec const *chan,
> -			    int *val, int *val2, long mask)
> -{
> -	struct hmc5843_data *data = iio_priv(indio_dev);
> -	int rval;
> -	int ret;
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_RAW:
> -		return hmc5843_read_measurement(data, chan->scan_index, val);
> -	case IIO_CHAN_INFO_SCALE:
> -		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_B, &rval);
> -		if (ret < 0)
> -			return ret;
> -		rval >>= HMC5843_RANGE_GAIN_OFFSET;
> -		*val = 0;
> -		*val2 = data->variant->regval_to_nanoscale[rval];
> -		return IIO_VAL_INT_PLUS_NANO;
> -	case IIO_CHAN_INFO_SAMP_FREQ:
> -		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &rval);
> -		if (ret < 0)
> -			return ret;
> -		rval >>= HMC5843_RATE_OFFSET;
> -		*val = data->variant->regval_to_samp_freq[rval][0];
> -		*val2 = data->variant->regval_to_samp_freq[rval][1];
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	}
> -	return -EINVAL;
> -}
> -
> -static int hmc5843_write_raw(struct iio_dev *indio_dev,
> -			     struct iio_chan_spec const *chan,
> -			     int val, int val2, long mask)
> -{
> -	struct hmc5843_data *data = iio_priv(indio_dev);
> -	int rate, range;
> -
> -	switch (mask) {
> -	case IIO_CHAN_INFO_SAMP_FREQ:
> -		rate = hmc5843_get_samp_freq_index(data, val, val2);
> -		if (rate < 0)
> -			return -EINVAL;
> -
> -		return hmc5843_set_samp_freq(data, rate);
> -	case IIO_CHAN_INFO_SCALE:
> -		range = hmc5843_get_scale_index(data, val, val2);
> -		if (range < 0)
> -			return -EINVAL;
> -
> -		return hmc5843_set_range_gain(data, range);
> -	default:
> -		return -EINVAL;
> -	}
> -}
> -
> -static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev,
> -			       struct iio_chan_spec const *chan, long mask)
> -{
> -	switch (mask) {
> -	case IIO_CHAN_INFO_SAMP_FREQ:
> -		return IIO_VAL_INT_PLUS_MICRO;
> -	case IIO_CHAN_INFO_SCALE:
> -		return IIO_VAL_INT_PLUS_NANO;
> -	default:
> -		return -EINVAL;
> -	}
> -}
> -
> -static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
> -{
> -	struct iio_poll_func *pf = p;
> -	struct iio_dev *indio_dev = pf->indio_dev;
> -	struct hmc5843_data *data = iio_priv(indio_dev);
> -	int ret;
> -
> -	mutex_lock(&data->lock);
> -	ret = hmc5843_wait_measurement(data);
> -	if (ret < 0) {
> -		mutex_unlock(&data->lock);
> -		goto done;
> -	}
> -
> -	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
> -			data->buffer, 3 * sizeof(__be16));
> -
> -	mutex_unlock(&data->lock);
> -	if (ret < 0)
> -		goto done;
> -
> -	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
> -		iio_get_time_ns());
> -
> -done:
> -	iio_trigger_notify_done(indio_dev->trig);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -#define HMC5843_CHANNEL(axis, idx)					\
> -	{								\
> -		.type = IIO_MAGN,					\
> -		.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_SAMP_FREQ),			\
> -		.scan_index = idx,					\
> -		.scan_type = {						\
> -			.sign = 's',					\
> -			.realbits = 16,					\
> -			.storagebits = 16,				\
> -			.endianness = IIO_BE,				\
> -		},							\
> -	}
> -
> -static const struct iio_chan_spec hmc5843_channels[] = {
> -	HMC5843_CHANNEL(X, 0),
> -	HMC5843_CHANNEL(Y, 1),
> -	HMC5843_CHANNEL(Z, 2),
> -	IIO_CHAN_SOFT_TIMESTAMP(3),
> -};
> -
> -/* Beware: Y and Z are exchanged on HMC5883 */
> -static const struct iio_chan_spec hmc5883_channels[] = {
> -	HMC5843_CHANNEL(X, 0),
> -	HMC5843_CHANNEL(Z, 1),
> -	HMC5843_CHANNEL(Y, 2),
> -	IIO_CHAN_SOFT_TIMESTAMP(3),
> -};
> -
> -static struct attribute *hmc5843_attributes[] = {
> -	&iio_dev_attr_meas_conf.dev_attr.attr,
> -	&iio_dev_attr_scale_available.dev_attr.attr,
> -	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> -	NULL
> -};
> -
> -static const struct attribute_group hmc5843_group = {
> -	.attrs = hmc5843_attributes,
> -};
> -
> -static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
> -	[HMC5843_ID] = {
> -		.channels = hmc5843_channels,
> -		.regval_to_samp_freq = hmc5843_regval_to_samp_freq,
> -		.regval_to_nanoscale = hmc5843_regval_to_nanoscale,
> -	},
> -	[HMC5883_ID] = {
> -		.channels = hmc5883_channels,
> -		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
> -		.regval_to_nanoscale = hmc5883_regval_to_nanoscale,
> -	},
> -	[HMC5883L_ID] = {
> -		.channels = hmc5883_channels,
> -		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
> -		.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
> -	},
> -};
> -
> -static int hmc5843_init(struct hmc5843_data *data)
> -{
> -	int ret;
> -	u8 id[3];
> -
> -	ret = regmap_bulk_read(data->regmap, HMC5843_ID_REG,
> -			id, ARRAY_SIZE(id));
> -	if (ret < 0)
> -		return ret;
> -	if (id[0] != 'H' || id[1] != '4' || id[2] != '3') {
> -		dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n");
> -		return -ENODEV;
> -	}
> -
> -	ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL);
> -	if (ret < 0)
> -		return ret;
> -	ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT);
> -	if (ret < 0)
> -		return ret;
> -	ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT);
> -	if (ret < 0)
> -		return ret;
> -	return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
> -}
> -
> -static const struct iio_info hmc5843_info = {
> -	.attrs = &hmc5843_group,
> -	.read_raw = &hmc5843_read_raw,
> -	.write_raw = &hmc5843_write_raw,
> -	.write_raw_get_fmt = &hmc5843_write_raw_get_fmt,
> -	.driver_module = THIS_MODULE,
> -};
> -
> -static const unsigned long hmc5843_scan_masks[] = {0x7, 0};
> -
> -static const struct regmap_range hmc5843_readable_ranges[] = {
> -		regmap_reg_range(0, HMC5843_ID_END),
> -};
> -
> -static struct regmap_access_table hmc5843_readable_table = {
> -		.yes_ranges = hmc5843_readable_ranges,
> -		.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
> -};
> -
> -static const struct regmap_range hmc5843_writable_ranges[] = {
> -		regmap_reg_range(0, HMC5843_MODE_REG),
> -};
> -
> -static struct regmap_access_table hmc5843_writable_table = {
> -		.yes_ranges = hmc5843_writable_ranges,
> -		.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
> -};
> -
> -static const struct regmap_range hmc5843_volatile_ranges[] = {
> -		regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
> -};
> -
> -static struct regmap_access_table hmc5843_volatile_table = {
> -		.yes_ranges = hmc5843_volatile_ranges,
> -		.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
> -};
> -
> -static struct regmap_config hmc5843_regmap_config = {
> -		.reg_bits = 8,
> -		.val_bits = 8,
> -
> -		.rd_table = &hmc5843_readable_table,
> -		.wr_table = &hmc5843_writable_table,
> -		.volatile_table = &hmc5843_volatile_table,
> -
> -		.cache_type = REGCACHE_RBTREE,
> -};
> -
> -static int hmc5843_probe(struct i2c_client *client,
> -			 const struct i2c_device_id *id)
> -{
> -	struct hmc5843_data *data;
> -	struct iio_dev *indio_dev;
> -	int ret;
> -
> -	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> -	if (indio_dev == NULL)
> -		return -ENOMEM;
> -
> -	/* default settings at probe */
> -	data = iio_priv(indio_dev);
> -	data->client = client;
> -	data->variant = &hmc5843_chip_info_tbl[id->driver_data];
> -	data->regmap = devm_regmap_init_i2c(client, &hmc5843_regmap_config);
> -	mutex_init(&data->lock);
> -
> -	i2c_set_clientdata(client, indio_dev);
> -	indio_dev->info = &hmc5843_info;
> -	indio_dev->name = id->name;
> -	indio_dev->dev.parent = &client->dev;
> -	indio_dev->modes = INDIO_DIRECT_MODE;
> -	indio_dev->channels = data->variant->channels;
> -	indio_dev->num_channels = 4;
> -	indio_dev->available_scan_masks = hmc5843_scan_masks;
> -
> -	ret = hmc5843_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = iio_triggered_buffer_setup(indio_dev, NULL,
> -		hmc5843_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 hmc5843_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);
> -
> -	/*  sleep mode to save power */
> -	hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
> -
> -	return 0;
> -}
> -
> -#ifdef CONFIG_PM_SLEEP
> -static int hmc5843_suspend(struct device *dev)
> -{
> -	struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
> -		to_i2c_client(dev)));
> -
> -	return hmc5843_set_mode(data, HMC5843_MODE_SLEEP);
> -}
> -
> -static int hmc5843_resume(struct device *dev)
> -{
> -	struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
> -		to_i2c_client(dev)));
> -
> -	return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
> -}
> -
> -static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
> -#define HMC5843_PM_OPS (&hmc5843_pm_ops)
> -#else
> -#define HMC5843_PM_OPS NULL
> -#endif
> -
> -static const struct i2c_device_id hmc5843_id[] = {
> -	{ "hmc5843", HMC5843_ID },
> -	{ "hmc5883", HMC5883_ID },
> -	{ "hmc5883l", HMC5883L_ID },
> -	{ }
> -};
> -MODULE_DEVICE_TABLE(i2c, hmc5843_id);
> -
> -static const struct of_device_id hmc5843_of_match[] = {
> -	{ .compatible = "honeywell,hmc5843" },
> -	{}
> -};
> -MODULE_DEVICE_TABLE(of, hmc5843_of_match);
> -
> -static struct i2c_driver hmc5843_driver = {
> -	.driver = {
> -		.name	= "hmc5843",
> -		.pm	= HMC5843_PM_OPS,
> -		.of_match_table = hmc5843_of_match,
> -	},
> -	.id_table	= hmc5843_id,
> -	.probe		= hmc5843_probe,
> -	.remove		= hmc5843_remove,
> -};
> -module_i2c_driver(hmc5843_driver);
> -
> -MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@...com>");
> -MODULE_DESCRIPTION("HMC5843/5883/5883L driver");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/magnetometer/hmc5843.h b/drivers/staging/iio/magnetometer/hmc5843.h
> new file mode 100644
> index 0000000..4e3cce3
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/hmc5843.h
> @@ -0,0 +1,75 @@
> +/*
> + * Header file for hmc5843 driver
> + *
> + * Split from hmc5843.c
> + * Copyright (C) Josef Gajdusek <atx@....name>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * */
> +
> +
> +#ifndef HMC5843_CORE_H
> +#define HMC5843_CORE_H
> +
> +#include <linux/regmap.h>
> +#include <linux/iio/iio.h>
> +
> +#define HMC5843_CONFIG_REG_A			0x00
> +#define HMC5843_CONFIG_REG_B			0x01
> +#define HMC5843_MODE_REG			0x02
> +#define HMC5843_DATA_OUT_MSB_REGS		0x03
> +#define HMC5843_STATUS_REG			0x09
> +#define HMC5843_ID_REG				0x0a
> +#define HMC5843_ID_END				0x0c
> +
> +enum hmc5843_ids {
> +	HMC5843_ID,
> +	HMC5883_ID,
> +	HMC5883L_ID,
> +};
> +
> +struct hmc5843_data {
> +	struct device *dev;
> +	struct mutex lock;
> +	struct regmap *regmap;
> +	const struct hmc5843_chip_info *variant;
> +	__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
> +};
> +
> +int hmc5843_common_probe(struct iio_dev *indio_dev, enum hmc5843_ids id);
> +int hmc5843_common_remove(struct iio_dev *indio_dev);
> +
> +int hmc5843_common_suspend(struct iio_dev *indio_dev);
> +int hmc5843_common_resume(struct iio_dev *indio_dev);
> +
> +static const struct regmap_range hmc5843_readable_ranges[] = {
> +		regmap_reg_range(0, HMC5843_ID_END),
> +};
> +
> +static struct regmap_access_table hmc5843_readable_table = {
> +		.yes_ranges = hmc5843_readable_ranges,
> +		.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
> +};
> +
> +static const struct regmap_range hmc5843_writable_ranges[] = {
> +		regmap_reg_range(0, HMC5843_MODE_REG),
> +};
> +
> +static struct regmap_access_table hmc5843_writable_table = {
> +		.yes_ranges = hmc5843_writable_ranges,
> +		.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
> +};
> +
> +static const struct regmap_range hmc5843_volatile_ranges[] = {
> +		regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
> +};
> +
> +static struct regmap_access_table hmc5843_volatile_table = {
> +		.yes_ranges = hmc5843_volatile_ranges,
> +		.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
> +};
> +
> +#endif /* HMC5843_CORE_H */
> diff --git a/drivers/staging/iio/magnetometer/hmc5843_core.c b/drivers/staging/iio/magnetometer/hmc5843_core.c
> new file mode 100644
> index 0000000..d9695e3
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/hmc5843_core.c
> @@ -0,0 +1,598 @@
> +/*  Copyright (C) 2010 Texas Instruments
> +    Author: Shubhrajyoti Datta <shubhrajyoti@...com>
> +    Acknowledgement: Jonathan Cameron <jic23@...nel.org> for valuable inputs.
> +
> +    Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@...erw.net>.
> +
> +    Split to multiple files by Josef Gajdusek <atx@....name> - 2014
> +
> +    This program is free software; you can redistribute it and/or modify
> +    it under the terms of the GNU General Public License as published by
> +    the Free Software Foundation; either version 2 of the License, or
> +    (at your option) any later version.
> +
> +    This program is distributed in the hope that it will be useful,
> +    but WITHOUT ANY WARRANTY; without even the implied warranty of
> +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +    GNU General Public License for more details.
> +
> +    You should have received a copy of the GNU General Public License
> +    along with this program; if not, write to the Free Software
> +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> +*/
> +
> +#include <linux/module.h>
> +#include <linux/regmap.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>
> +
> +#include "hmc5843.h"
> +
> +/*
> + * Range gain settings in (+-)Ga
> + * Beware: HMC5843 and HMC5883 have different recommended sensor field
> + * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
> + */
> +#define HMC5843_RANGE_GAIN_OFFSET		0x05
> +#define HMC5843_RANGE_GAIN_DEFAULT		0x01
> +#define HMC5843_RANGE_GAINS			8
> +#define HMC5843_RANGE_GAIN_MASK		0xe0
> +
> +/* Device status */
> +#define HMC5843_DATA_READY			0x01
> +#define HMC5843_DATA_OUTPUT_LOCK		0x02
> +
> +/* Mode register configuration */
> +#define HMC5843_MODE_CONVERSION_CONTINUOUS	0x00
> +#define HMC5843_MODE_CONVERSION_SINGLE		0x01
> +#define HMC5843_MODE_IDLE			0x02
> +#define HMC5843_MODE_SLEEP			0x03
> +#define HMC5843_MODE_MASK			0x03
> +
> +/*
> + * HMC5843: Minimum data output rate
> + * HMC5883: Typical data output rate
> + */
> +#define HMC5843_RATE_OFFSET			0x02
> +#define HMC5843_RATE_DEFAULT			0x04
> +#define HMC5843_RATES				7
> +#define HMC5843_RATE_MASK		0x1c
> +
> +/* Device measurement configuration */
> +#define HMC5843_MEAS_CONF_NORMAL		0x00
> +#define HMC5843_MEAS_CONF_POSITIVE_BIAS		0x01
> +#define HMC5843_MEAS_CONF_NEGATIVE_BIAS		0x02
> +#define HMC5843_MEAS_CONF_MASK			0x03
> +
> +/* Scaling factors: 10000000/Gain */
> +static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> +	6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
> +};
> +
> +static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> +	7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
> +};
> +
> +static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
> +	7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
> +};
> +
> +/*
> + * From the datasheet:
> + * Value	| HMC5843		| HMC5883/HMC5883L
> + *		| Data output rate (Hz)	| Data output rate (Hz)
> + * 0		| 0.5			| 0.75
> + * 1		| 1			| 1.5
> + * 2		| 2			| 3
> + * 3		| 5			| 7.5
> + * 4		| 10 (default)		| 15
> + * 5		| 20			| 30
> + * 6		| 50			| 75
> + * 7		| Not used		| Not used
> + */
> +static const int hmc5843_regval_to_samp_freq[7][2] = {
> +	{0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0}
> +};
> +
> +static const int hmc5883_regval_to_samp_freq[7][2] = {
> +	{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
> +	{75, 0}
> +};
> +
> +/* Describe chip variants */
> +struct hmc5843_chip_info {
> +	const struct iio_chan_spec *channels;
> +	const int (*regval_to_samp_freq)[2];
> +	const int *regval_to_nanoscale;
> +};
> +
> +/* The lower two bits contain the current conversion mode */
> +static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
> +{
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = regmap_update_bits(data->regmap, HMC5843_MODE_REG,
> +			HMC5843_MODE_MASK, operating_mode);
> +	mutex_unlock(&data->lock);
> +
> +	return ret;
> +}
> +
> +static int hmc5843_wait_measurement(struct hmc5843_data *data)
> +{
> +	int tries = 150;
> +	int val;
> +	int ret;
> +
> +	while (tries-- > 0) {
> +		ret = regmap_read(data->regmap, HMC5843_STATUS_REG, &val);
> +		if (ret < 0)
> +			return ret;
> +		if (val & HMC5843_DATA_READY)
> +			break;
> +		msleep(20);
> +	}
> +
> +	if (tries < 0) {
> +		dev_err(data->dev, "data not ready\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Return the measurement value from the specified channel */
> +static int hmc5843_read_measurement(struct hmc5843_data *data,
> +				    int idx, int *val)
> +{
> +	__be16 values[3];
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = hmc5843_wait_measurement(data);
> +	if (ret < 0) {
> +		mutex_unlock(&data->lock);
> +		return ret;
> +	}
> +	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
> +			values, sizeof(values));
> +	mutex_unlock(&data->lock);
> +	if (ret < 0)
> +		return ret;
> +
> +	*val = sign_extend32(be16_to_cpu(values[idx]), 15);
> +	return IIO_VAL_INT;
> +}
> +
> +/*
> + * API for setting the measurement configuration to
> + * Normal, Positive bias and Negative bias
> + *
> + * From the datasheet:
> + * 0 - Normal measurement configuration (default): In normal measurement
> + *     configuration the device follows normal measurement flow. Pins BP
> + *     and BN are left floating and high impedance.
> + *
> + * 1 - Positive bias configuration: In positive bias configuration, a
> + *     positive current is forced across the resistive load on pins BP
> + *     and BN.
> + *
> + * 2 - Negative bias configuration. In negative bias configuration, a
> + *     negative current is forced across the resistive load on pins BP
> + *     and BN.
> + *
> + */
> +static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
> +{
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
> +			HMC5843_MEAS_CONF_MASK, meas_conf);
> +	mutex_unlock(&data->lock);
> +
> +	return ret;
> +}
> +
> +static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
> +						struct device_attribute *attr,
> +						char *buf)
> +{
> +	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> +	int val;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val);
> +	if (ret)
> +		return ret;
> +	val &= HMC5843_MEAS_CONF_MASK;
> +
> +	return sprintf(buf, "%d\n", val);
> +}
> +
> +static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
> +						struct device_attribute *attr,
> +						const char *buf,
> +						size_t count)
> +{
> +	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> +	unsigned long meas_conf = 0;
> +	int ret;
> +
> +	ret = kstrtoul(buf, 10, &meas_conf);
> +	if (ret)
> +		return ret;
> +	if (meas_conf >= HMC5843_MEAS_CONF_MASK)
> +		return -EINVAL;
> +
> +	ret = hmc5843_set_meas_conf(data, meas_conf);
> +
> +	return (ret < 0) ? ret : count;
> +}
> +
> +static IIO_DEVICE_ATTR(meas_conf,
> +			S_IWUSR | S_IRUGO,
> +			hmc5843_show_measurement_configuration,
> +			hmc5843_set_measurement_configuration,
> +			0);
> +
> +static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> +	size_t len = 0;
> +	int i;
> +
> +	for (i = 0; i < HMC5843_RATES; i++)
> +		len += scnprintf(buf + len, PAGE_SIZE - len,
> +			"%d.%d ", data->variant->regval_to_samp_freq[i][0],
> +			data->variant->regval_to_samp_freq[i][1]);
> +
> +	/* replace trailing space by newline */
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail);
> +
> +static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate)
> +{
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
> +			HMC5843_RATE_MASK, rate << HMC5843_RATE_OFFSET);
> +	mutex_unlock(&data->lock);
> +
> +	return ret;
> +}
> +
> +static int hmc5843_get_samp_freq_index(struct hmc5843_data *data,
> +				   int val, int val2)
> +{
> +	int i;
> +
> +	for (i = 0; i < HMC5843_RATES; i++)
> +		if (val == data->variant->regval_to_samp_freq[i][0] &&
> +			val2 == data->variant->regval_to_samp_freq[i][1])
> +			return i;
> +
> +	return -EINVAL;
> +}
> +
> +static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range)
> +{
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_B,
> +			HMC5843_RANGE_GAIN_MASK,
> +			range << HMC5843_RANGE_GAIN_OFFSET);
> +	mutex_unlock(&data->lock);
> +
> +	return ret;
> +}
> +
> +static ssize_t hmc5843_show_scale_avail(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
> +
> +	size_t len = 0;
> +	int i;
> +
> +	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
> +		len += scnprintf(buf + len, PAGE_SIZE - len,
> +			"0.%09d ", data->variant->regval_to_nanoscale[i]);
> +
> +	/* replace trailing space by newline */
> +	buf[len - 1] = '\n';
> +
> +	return len;
> +}
> +
> +static IIO_DEVICE_ATTR(scale_available, S_IRUGO,
> +	hmc5843_show_scale_avail, NULL, 0);
> +
> +static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
> +{
> +	int i;
> +
> +	if (val != 0)
> +		return -EINVAL;
> +
> +	for (i = 0; i < HMC5843_RANGE_GAINS; i++)
> +		if (val2 == data->variant->regval_to_nanoscale[i])
> +			return i;
> +
> +	return -EINVAL;
> +}
> +
> +static int hmc5843_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan,
> +			    int *val, int *val2, long mask)
> +{
> +	struct hmc5843_data *data = iio_priv(indio_dev);
> +	int rval;
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		return hmc5843_read_measurement(data, chan->scan_index, val);
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_B, &rval);
> +		if (ret < 0)
> +			return ret;
> +		rval >>= HMC5843_RANGE_GAIN_OFFSET;
> +		*val = 0;
> +		*val2 = data->variant->regval_to_nanoscale[rval];
> +		return IIO_VAL_INT_PLUS_NANO;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &rval);
> +		if (ret < 0)
> +			return ret;
> +		rval >>= HMC5843_RATE_OFFSET;
> +		*val = data->variant->regval_to_samp_freq[rval][0];
> +		*val2 = data->variant->regval_to_samp_freq[rval][1];
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	}
> +	return -EINVAL;
> +}
> +
> +static int hmc5843_write_raw(struct iio_dev *indio_dev,
> +			     struct iio_chan_spec const *chan,
> +			     int val, int val2, long mask)
> +{
> +	struct hmc5843_data *data = iio_priv(indio_dev);
> +	int rate, range;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		rate = hmc5843_get_samp_freq_index(data, val, val2);
> +		if (rate < 0)
> +			return -EINVAL;
> +
> +		return hmc5843_set_samp_freq(data, rate);
> +	case IIO_CHAN_INFO_SCALE:
> +		range = hmc5843_get_scale_index(data, val, val2);
> +		if (range < 0)
> +			return -EINVAL;
> +
> +		return hmc5843_set_range_gain(data, range);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev,
> +			       struct iio_chan_spec const *chan, long mask)
> +{
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		return IIO_VAL_INT_PLUS_MICRO;
> +	case IIO_CHAN_INFO_SCALE:
> +		return IIO_VAL_INT_PLUS_NANO;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
> +{
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct hmc5843_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	mutex_lock(&data->lock);
> +	ret = hmc5843_wait_measurement(data);
> +	if (ret < 0) {
> +		mutex_unlock(&data->lock);
> +		goto done;
> +	}
> +
> +	ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
> +			data->buffer, 3 * sizeof(__be16));
> +
> +	mutex_unlock(&data->lock);
> +	if (ret < 0)
> +		goto done;
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
> +		iio_get_time_ns());
> +
> +done:
> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +#define HMC5843_CHANNEL(axis, idx)					\
> +	{								\
> +		.type = IIO_MAGN,					\
> +		.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_SAMP_FREQ),			\
> +		.scan_index = idx,					\
> +		.scan_type = {						\
> +			.sign = 's',					\
> +			.realbits = 16,					\
> +			.storagebits = 16,				\
> +			.endianness = IIO_BE,				\
> +		},							\
> +	}
> +
> +static const struct iio_chan_spec hmc5843_channels[] = {
> +	HMC5843_CHANNEL(X, 0),
> +	HMC5843_CHANNEL(Y, 1),
> +	HMC5843_CHANNEL(Z, 2),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
> +};
> +
> +/* Beware: Y and Z are exchanged on HMC5883 */
> +static const struct iio_chan_spec hmc5883_channels[] = {
> +	HMC5843_CHANNEL(X, 0),
> +	HMC5843_CHANNEL(Z, 1),
> +	HMC5843_CHANNEL(Y, 2),
> +	IIO_CHAN_SOFT_TIMESTAMP(3),
> +};
> +
> +static struct attribute *hmc5843_attributes[] = {
> +	&iio_dev_attr_meas_conf.dev_attr.attr,
> +	&iio_dev_attr_scale_available.dev_attr.attr,
> +	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group hmc5843_group = {
> +	.attrs = hmc5843_attributes,
> +};
> +
> +static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
> +	[HMC5843_ID] = {
> +		.channels = hmc5843_channels,
> +		.regval_to_samp_freq = hmc5843_regval_to_samp_freq,
> +		.regval_to_nanoscale = hmc5843_regval_to_nanoscale,
> +	},
> +	[HMC5883_ID] = {
> +		.channels = hmc5883_channels,
> +		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
> +		.regval_to_nanoscale = hmc5883_regval_to_nanoscale,
> +	},
> +	[HMC5883L_ID] = {
> +		.channels = hmc5883_channels,
> +		.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
> +		.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
> +	},
> +};
> +
> +static int hmc5843_init(struct hmc5843_data *data)
> +{
> +	int ret;
> +	u8 id[3];
> +
> +	ret = regmap_bulk_read(data->regmap, HMC5843_ID_REG,
> +			id, ARRAY_SIZE(id));
> +	if (ret < 0)
> +		return ret;
> +	if (id[0] != 'H' || id[1] != '4' || id[2] != '3') {
> +		dev_err(data->dev, "no HMC5843/5883/5883L sensor\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL);
> +	if (ret < 0)
> +		return ret;
> +	ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT);
> +	if (ret < 0)
> +		return ret;
> +	ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT);
> +	if (ret < 0)
> +		return ret;
> +	return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
> +}
> +
> +static const struct iio_info hmc5843_info = {
> +	.attrs = &hmc5843_group,
> +	.read_raw = &hmc5843_read_raw,
> +	.write_raw = &hmc5843_write_raw,
> +	.write_raw_get_fmt = &hmc5843_write_raw_get_fmt,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static const unsigned long hmc5843_scan_masks[] = {0x7, 0};
> +
> +
> +int hmc5843_common_suspend(struct iio_dev *indio_dev)
> +{
> +	return hmc5843_set_mode(iio_priv(indio_dev),
> +			HMC5843_MODE_CONVERSION_CONTINUOUS);
> +}
> +EXPORT_SYMBOL(hmc5843_common_suspend);
> +
> +int hmc5843_common_resume(struct iio_dev *indio_dev)
> +{
> +	return hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
> +}
> +EXPORT_SYMBOL(hmc5843_common_resume);
> +
> +int hmc5843_common_probe(struct iio_dev *indio_dev, enum hmc5843_ids id)
> +{
> +	struct hmc5843_data *data;
> +	int ret;
> +
> +	/* default settings at probe */
> +	data = iio_priv(indio_dev);
> +	data->variant = &hmc5843_chip_info_tbl[id];
> +	mutex_init(&data->lock);
> +
> +	indio_dev->info = &hmc5843_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = data->variant->channels;
> +	indio_dev->num_channels = 4;
> +	indio_dev->available_scan_masks = hmc5843_scan_masks;
> +
> +	ret = hmc5843_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = iio_triggered_buffer_setup(indio_dev, NULL,
> +		hmc5843_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;
> +}
> +EXPORT_SYMBOL(hmc5843_common_probe);
> +
> +int hmc5843_common_remove(struct iio_dev *indio_dev)
> +{
> +	iio_device_unregister(indio_dev);
> +	iio_triggered_buffer_cleanup(indio_dev);
> +
> +	/*  sleep mode to save power */
> +	hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(hmc5843_common_remove);
> +
> +MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@...com>");
> +MODULE_DESCRIPTION("HMC5843/5883/5883L core driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
> new file mode 100644
> index 0000000..b3c92d9
> --- /dev/null
> +++ b/drivers/staging/iio/magnetometer/hmc5843_i2c.c
> @@ -0,0 +1,106 @@
> +/*
> + * i2c driver for hmc5843/5843/5883/5883l
> + *
> + * Split from hmc5843.c
> + * Copyright (C) Josef Gajdusek <atx@....name>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * */
> +
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/triggered_buffer.h>
> +
> +#include "hmc5843.h"
> +
> +struct regmap_config hmc5843_i2c_regmap_config = {
> +		.reg_bits = 8,
> +		.val_bits = 8,
> +
> +		.rd_table = &hmc5843_readable_table,
> +		.wr_table = &hmc5843_writable_table,
> +		.volatile_table = &hmc5843_volatile_table,
> +
> +		.cache_type = REGCACHE_RBTREE,
> +};
> +
> +static int hmc5843_i2c_probe(struct i2c_client *client,
> +			 const struct i2c_device_id *id)
> +{
> +	struct hmc5843_data *data;
> +	struct iio_dev *indio_dev;
> +
> +	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
> +	if (indio_dev == NULL)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(client, indio_dev);
> +
> +	data = iio_priv(indio_dev);
> +	data->dev = &client->dev;
> +	data->regmap = devm_regmap_init_i2c(client, &hmc5843_i2c_regmap_config);
> +
> +	indio_dev->name = id->name;
> +	indio_dev->dev.parent = &client->dev;
> +
> +	return hmc5843_common_probe(indio_dev, id->driver_data);
> +}
> +
> +static int hmc5843_i2c_remove(struct i2c_client *client)
> +{
> +	struct iio_dev *indio_dev = i2c_get_clientdata(client);
> +	return hmc5843_common_remove(indio_dev);
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int hmc5843_i2c_suspend(struct device *dev)
> +{
> +	return hmc5843_common_suspend(i2c_get_clientdata(to_i2c_client(dev)));
> +}
> +
> +static int hmc5843_i2c_resume(struct device *dev)
> +{
> +	return hmc5843_common_resume(i2c_get_clientdata(to_i2c_client(dev)));
> +}
> +
> +static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops,
> +		hmc5843_i2c_suspend, hmc5843_i2c_resume);
> +#define HMC5843_PM_OPS (&hmc5843_pm_ops)
> +#else
> +#define HMC5843_PM_OPS NULL
> +#endif
> +
> +static const struct i2c_device_id hmc5843_id[] = {
> +	{ "hmc5843", HMC5843_ID },
> +	{ "hmc5883", HMC5883_ID },
> +	{ "hmc5883l", HMC5883L_ID },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, hmc5843_id);
> +
> +static const struct of_device_id hmc5843_of_match[] = {
> +	{ .compatible = "honeywell,hmc5843" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, hmc5843_of_match);
> +
> +static struct i2c_driver hmc5843_driver = {
> +	.driver = {
> +		.name	= "hmc5843",
> +		.pm	= HMC5843_PM_OPS,
> +		.of_match_table = hmc5843_of_match,
> +	},
> +	.id_table	= hmc5843_id,
> +	.probe		= hmc5843_i2c_probe,
> +	.remove		= hmc5843_i2c_remove,
> +};
> +module_i2c_driver(hmc5843_driver);
> +
> +MODULE_AUTHOR("Josef Gajdusek <atx@....name>");
> +MODULE_DESCRIPTION("HMC5843/5883/5883L i2c driver");
> +MODULE_LICENSE("GPL");
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ