From 1c7be4c260e52deeb2ec3cb22d57e5c997932fc2 Mon Sep 17 00:00:00 2001 From: Cristina Moraru Date: Mon, 15 Feb 2016 00:37:37 +0200 Subject: iio: hmc5843: Add attributes for measurement config of bias current Change static attribute meas_conf for bias current configuration to channel attribute in_magn_meas_conf and also add in_magn_meas_conf_available attribute to view available configurations. This patch solves functionality bug: driver was using same function hmc5843_set_measurement_configuration for setting bias current config for all device types but the function was returning -EINVAL for any setting >= 0x03 although, for sensor HMC5983, value 3 is valid. API for setting bias measurement configuration: normal - Normal measurement configuration (default): In normal measurement configuration the device follows normal measurement flow. Pins BP and BN are left floating and high impedance. positivebias - Positive bias configuration: In positive bias configuration, a positive current is forced across the resistive load on pins BP and BN. negativebias - Negative bias configuration. In negative bias configuration, a negative current is forced across the resistive load on pins BP and BN. disabled - Only available on HMC5983. Magnetic sensor is disabled. Temperature sensor is enabled. Signed-off-by: Cristina Moraru Cc: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/staging/iio/magnetometer/hmc5843_core.c | 133 ++++++++++++++++-------- 1 file changed, 87 insertions(+), 46 deletions(-) (limited to 'drivers/staging/iio') diff --git a/drivers/staging/iio/magnetometer/hmc5843_core.c b/drivers/staging/iio/magnetometer/hmc5843_core.c index 9ee9a421a8b7..ebc22b19c60d 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_core.c +++ b/drivers/staging/iio/magnetometer/hmc5843_core.c @@ -66,6 +66,33 @@ #define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02 #define HMC5843_MEAS_CONF_MASK 0x03 +/* + * 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. + * + * 3 - Only available on HMC5983. Magnetic sensor is disabled. + * Temperature sensor is enabled. + */ + +static const char *const hmc5843_meas_conf_modes[] = {"normal", "positivebias", + "negativebias"}; + +static const char *const hmc5983_meas_conf_modes[] = {"normal", "positivebias", + "negativebias", + "disabled"}; /* Scaling factors: 10000000/Gain */ static const int hmc5843_regval_to_nanoscale[] = { 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 @@ -174,24 +201,6 @@ static int hmc5843_read_measurement(struct hmc5843_data *data, 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; @@ -205,48 +214,55 @@ static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf) } static -ssize_t hmc5843_show_measurement_configuration(struct device *dev, - struct device_attribute *attr, - char *buf) +int hmc5843_show_measurement_configuration(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) { - struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); + struct hmc5843_data *data = iio_priv(indio_dev); unsigned 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); + return val & HMC5843_MEAS_CONF_MASK; } static -ssize_t hmc5843_set_measurement_configuration(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int meas_conf) { - struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); - unsigned long meas_conf = 0; - int ret; + struct hmc5843_data *data = iio_priv(indio_dev); - ret = kstrtoul(buf, 10, &meas_conf); - if (ret) - return ret; - if (meas_conf >= HMC5843_MEAS_CONF_MASK) - return -EINVAL; + return hmc5843_set_meas_conf(data, meas_conf); +} - ret = hmc5843_set_meas_conf(data, meas_conf); +static const struct iio_enum hmc5843_meas_conf_enum = { + .items = hmc5843_meas_conf_modes, + .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), + .get = hmc5843_show_measurement_configuration, + .set = hmc5843_set_measurement_configuration, +}; - return (ret < 0) ? ret : count; -} +static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { + IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), + IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), + { }, +}; -static IIO_DEVICE_ATTR(meas_conf, - S_IWUSR | S_IRUGO, - hmc5843_show_measurement_configuration, - hmc5843_set_measurement_configuration, - 0); +static const struct iio_enum hmc5983_meas_conf_enum = { + .items = hmc5983_meas_conf_modes, + .num_items = ARRAY_SIZE(hmc5983_meas_conf_modes), + .get = hmc5843_show_measurement_configuration, + .set = hmc5843_set_measurement_configuration, +}; + +static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { + IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), + IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), + { }, +}; static ssize_t hmc5843_show_samp_freq_avail(struct device *dev, @@ -459,6 +475,25 @@ done: .storagebits = 16, \ .endianness = IIO_BE, \ }, \ + .ext_info = hmc5843_ext_info, \ + } + +#define HMC5983_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, \ + }, \ + .ext_info = hmc5983_ext_info, \ } static const struct iio_chan_spec hmc5843_channels[] = { @@ -476,8 +511,14 @@ static const struct iio_chan_spec hmc5883_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec hmc5983_channels[] = { + HMC5983_CHANNEL(X, 0), + HMC5983_CHANNEL(Z, 1), + HMC5983_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 @@ -516,7 +557,7 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { ARRAY_SIZE(hmc5883l_regval_to_nanoscale), }, [HMC5983_ID] = { - .channels = hmc5883_channels, + .channels = hmc5983_channels, .regval_to_samp_freq = hmc5983_regval_to_samp_freq, .n_regval_to_samp_freq = ARRAY_SIZE(hmc5983_regval_to_samp_freq), -- cgit v1.2.3 From 7247645f686584552ec0f8ade7267bf7a4907624 Mon Sep 17 00:00:00 2001 From: Cristina Moraru Date: Mon, 15 Feb 2016 00:37:39 +0200 Subject: iio: hmc5843: Move hmc5843 out of staging This patch moves hmc5843 driver from staging/iio/magnetometer to iio/magnetometer, updates the corresponding Makefiles and moves the hmc5843* entries to the 'Industrial I/O support -> Magnetometer sensors' menu. Signed-off-by: Cristina Moraru Cc: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/Kconfig | 33 ++ drivers/iio/magnetometer/Makefile | 4 + drivers/iio/magnetometer/hmc5843.h | 65 +++ drivers/iio/magnetometer/hmc5843_core.c | 686 +++++++++++++++++++++++ drivers/iio/magnetometer/hmc5843_i2c.c | 103 ++++ drivers/iio/magnetometer/hmc5843_spi.c | 100 ++++ drivers/staging/iio/Kconfig | 1 - drivers/staging/iio/Makefile | 1 - drivers/staging/iio/magnetometer/Kconfig | 40 -- drivers/staging/iio/magnetometer/Makefile | 7 - drivers/staging/iio/magnetometer/hmc5843.h | 65 --- drivers/staging/iio/magnetometer/hmc5843_core.c | 687 ------------------------ drivers/staging/iio/magnetometer/hmc5843_i2c.c | 103 ---- drivers/staging/iio/magnetometer/hmc5843_spi.c | 100 ---- 14 files changed, 991 insertions(+), 1004 deletions(-) create mode 100644 drivers/iio/magnetometer/hmc5843.h create mode 100644 drivers/iio/magnetometer/hmc5843_core.c create mode 100644 drivers/iio/magnetometer/hmc5843_i2c.c create mode 100644 drivers/iio/magnetometer/hmc5843_spi.c delete mode 100644 drivers/staging/iio/magnetometer/Kconfig delete mode 100644 drivers/staging/iio/magnetometer/Makefile delete mode 100644 drivers/staging/iio/magnetometer/hmc5843.h delete mode 100644 drivers/staging/iio/magnetometer/hmc5843_core.c delete mode 100644 drivers/staging/iio/magnetometer/hmc5843_i2c.c delete mode 100644 drivers/staging/iio/magnetometer/hmc5843_spi.c (limited to 'drivers/staging/iio') diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 868abada3409..021dc5361f53 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -105,4 +105,37 @@ config IIO_ST_MAGN_SPI_3AXIS depends on IIO_ST_MAGN_3AXIS depends on IIO_ST_SENSORS_SPI +config SENSORS_HMC5843 + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + +config SENSORS_HMC5843_I2C + tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)" + depends on I2C + select SENSORS_HMC5843 + select REGMAP_I2C + help + Say Y here to add support for the Honeywell HMC5843, HMC5883 and + HMC5883L 3-Axis Magnetometer (digital compass). + + 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, HMC5883L and HMC5983) + +config SENSORS_HMC5843_SPI + tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)" + depends on SPI_MASTER + select SENSORS_HMC5843 + select REGMAP_SPI + help + Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer + (digital compass). + + This driver can also be compiled as a set of modules. + If so, these modules will be created: + - hmc5843_core (core functions) + - hmc5843_spi (support for HMC5983) + endmenu diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 2c72df458ec2..dd03fe524481 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -15,3 +15,7 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o + +obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o +obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o +obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/iio/magnetometer/hmc5843.h b/drivers/iio/magnetometer/hmc5843.h new file mode 100644 index 000000000000..76a5d7484d8d --- /dev/null +++ b/drivers/iio/magnetometer/hmc5843.h @@ -0,0 +1,65 @@ +/* + * Header file for hmc5843 driver + * + * Split from hmc5843.c + * Copyright (C) Josef Gajdusek + * + * 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 +#include + +#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, + HMC5983_ID, +}; + +/** + * struct hcm5843_data - device specific data + * @dev: actual device + * @lock: update and read regmap data + * @regmap: hardware access register maps + * @variant: describe chip variants + * @buffer: 3x 16-bit channels + padding + 64-bit timestamp + */ +struct hmc5843_data { + struct device *dev; + struct mutex lock; + struct regmap *regmap; + const struct hmc5843_chip_info *variant; + __be16 buffer[8]; +}; + +int hmc5843_common_probe(struct device *dev, struct regmap *regmap, + enum hmc5843_ids id, const char *name); +int hmc5843_common_remove(struct device *dev); + +int hmc5843_common_suspend(struct device *dev); +int hmc5843_common_resume(struct device *dev); + +#ifdef CONFIG_PM_SLEEP +static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, + hmc5843_common_suspend, + hmc5843_common_resume); +#define HMC5843_PM_OPS (&hmc5843_pm_ops) +#else +#define HMC5843_PM_OPS NULL +#endif + +#endif /* HMC5843_CORE_H */ diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c new file mode 100644 index 000000000000..77882b466e0f --- /dev/null +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -0,0 +1,686 @@ +/* + * Device driver for the the HMC5843 multi-chip module designed + * for low field magnetic sensing. + * + * Copyright (C) 2010 Texas Instruments + * + * Author: Shubhrajyoti Datta + * Acknowledgment: Jonathan Cameron for valuable inputs. + * Support for HMC5883 and HMC5883L by Peter Meerwald . + * Split to multiple files by Josef Gajdusek - 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_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_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 + +/* + * 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. + * + * 3 - Only available on HMC5983. Magnetic sensor is disabled. + * Temperature sensor is enabled. + */ + +static const char *const hmc5843_meas_conf_modes[] = {"normal", "positivebias", + "negativebias"}; + +static const char *const hmc5983_meas_conf_modes[] = {"normal", "positivebias", + "negativebias", + "disabled"}; +/* Scaling factors: 10000000/Gain */ +static const int hmc5843_regval_to_nanoscale[] = { + 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 +}; + +static const int hmc5883_regval_to_nanoscale[] = { + 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 +}; + +static const int hmc5883l_regval_to_nanoscale[] = { + 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[][2] = { + {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} +}; + +static const int hmc5883_regval_to_samp_freq[][2] = { + {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, + {75, 0} +}; + +static const int hmc5983_regval_to_samp_freq[][2] = { + {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, + {75, 0}, {220, 0} +}; + +/* Describe chip variants */ +struct hmc5843_chip_info { + const struct iio_chan_spec *channels; + const int (*regval_to_samp_freq)[2]; + const int n_regval_to_samp_freq; + const int *regval_to_nanoscale; + const int n_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; + unsigned 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; +} + +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 +int hmc5843_show_measurement_configuration(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct hmc5843_data *data = iio_priv(indio_dev); + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val); + if (ret) + return ret; + + return val & HMC5843_MEAS_CONF_MASK; +} + +static +int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int meas_conf) +{ + struct hmc5843_data *data = iio_priv(indio_dev); + + return hmc5843_set_meas_conf(data, meas_conf); +} + +static const struct iio_enum hmc5843_meas_conf_enum = { + .items = hmc5843_meas_conf_modes, + .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), + .get = hmc5843_show_measurement_configuration, + .set = hmc5843_set_measurement_configuration, +}; + +static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { + IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), + IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), + { }, +}; + +static const struct iio_enum hmc5983_meas_conf_enum = { + .items = hmc5983_meas_conf_modes, + .num_items = ARRAY_SIZE(hmc5983_meas_conf_modes), + .get = hmc5843_show_measurement_configuration, + .set = hmc5843_set_measurement_configuration, +}; + +static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { + IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), + IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), + { }, +}; + +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 < data->variant->n_regval_to_samp_freq; 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 < data->variant->n_regval_to_samp_freq; 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 < data->variant->n_regval_to_nanoscale; 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) + return -EINVAL; + + for (i = 0; i < data->variant->n_regval_to_nanoscale; 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); + unsigned 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, \ + }, \ + .ext_info = hmc5843_ext_info, \ + } + +#define HMC5983_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, \ + }, \ + .ext_info = hmc5983_ext_info, \ + } + +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 and 5983 */ +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 const struct iio_chan_spec hmc5983_channels[] = { + HMC5983_CHANNEL(X, 0), + HMC5983_CHANNEL(Z, 1), + HMC5983_CHANNEL(Y, 2), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static struct attribute *hmc5843_attributes[] = { + &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, + .n_regval_to_samp_freq = + ARRAY_SIZE(hmc5843_regval_to_samp_freq), + .regval_to_nanoscale = hmc5843_regval_to_nanoscale, + .n_regval_to_nanoscale = + ARRAY_SIZE(hmc5843_regval_to_nanoscale), + }, + [HMC5883_ID] = { + .channels = hmc5883_channels, + .regval_to_samp_freq = hmc5883_regval_to_samp_freq, + .n_regval_to_samp_freq = + ARRAY_SIZE(hmc5883_regval_to_samp_freq), + .regval_to_nanoscale = hmc5883_regval_to_nanoscale, + .n_regval_to_nanoscale = + ARRAY_SIZE(hmc5883_regval_to_nanoscale), + }, + [HMC5883L_ID] = { + .channels = hmc5883_channels, + .regval_to_samp_freq = hmc5883_regval_to_samp_freq, + .n_regval_to_samp_freq = + ARRAY_SIZE(hmc5883_regval_to_samp_freq), + .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, + .n_regval_to_nanoscale = + ARRAY_SIZE(hmc5883l_regval_to_nanoscale), + }, + [HMC5983_ID] = { + .channels = hmc5983_channels, + .regval_to_samp_freq = hmc5983_regval_to_samp_freq, + .n_regval_to_samp_freq = + ARRAY_SIZE(hmc5983_regval_to_samp_freq), + .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, + .n_regval_to_nanoscale = + ARRAY_SIZE(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/5983 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 device *dev) +{ + return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), + HMC5843_MODE_SLEEP); +} +EXPORT_SYMBOL(hmc5843_common_suspend); + +int hmc5843_common_resume(struct device *dev) +{ + return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), + HMC5843_MODE_CONVERSION_CONTINUOUS); +} +EXPORT_SYMBOL(hmc5843_common_resume); + +int hmc5843_common_probe(struct device *dev, struct regmap *regmap, + enum hmc5843_ids id, const char *name) +{ + struct hmc5843_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + dev_set_drvdata(dev, indio_dev); + + /* default settings at probe */ + data = iio_priv(indio_dev); + data->dev = dev; + data->regmap = regmap; + data->variant = &hmc5843_chip_info_tbl[id]; + mutex_init(&data->lock); + + indio_dev->dev.parent = dev; + indio_dev->name = name; + 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) + goto buffer_setup_err; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto buffer_cleanup; + + return 0; + +buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +buffer_setup_err: + hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); + return ret; +} +EXPORT_SYMBOL(hmc5843_common_probe); + +int hmc5843_common_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(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 "); +MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c new file mode 100644 index 000000000000..3de7f4426ac4 --- /dev/null +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -0,0 +1,103 @@ +/* + * i2c driver for hmc5843/5843/5883/5883l/5983 + * + * Split from hmc5843.c + * Copyright (C) Josef Gajdusek + * + * 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 +#include +#include +#include +#include + +#include "hmc5843.h" + +static const struct regmap_range hmc5843_readable_ranges[] = { + regmap_reg_range(0, HMC5843_ID_END), +}; + +static const 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 const 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 const struct regmap_access_table hmc5843_volatile_table = { + .yes_ranges = hmc5843_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), +}; + +static const 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 *cli, + const struct i2c_device_id *id) +{ + return hmc5843_common_probe(&cli->dev, + devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config), + id->driver_data, id->name); +} + +static int hmc5843_i2c_remove(struct i2c_client *client) +{ + return hmc5843_common_remove(&client->dev); +} + +static const struct i2c_device_id hmc5843_id[] = { + { "hmc5843", HMC5843_ID }, + { "hmc5883", HMC5883_ID }, + { "hmc5883l", HMC5883L_ID }, + { "hmc5983", HMC5983_ID }, + { } +}; +MODULE_DEVICE_TABLE(i2c, hmc5843_id); + +static const struct of_device_id hmc5843_of_match[] = { + { .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID }, + { .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID }, + { .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID }, + { .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID }, + {} +}; +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 "); +MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c new file mode 100644 index 000000000000..535f03a70d63 --- /dev/null +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -0,0 +1,100 @@ +/* + * SPI driver for hmc5983 + * + * Copyright (C) Josef Gajdusek + * + * 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 +#include +#include + +#include "hmc5843.h" + +static const struct regmap_range hmc5843_readable_ranges[] = { + regmap_reg_range(0, HMC5843_ID_END), +}; + +static const 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 const 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 const struct regmap_access_table hmc5843_volatile_table = { + .yes_ranges = hmc5843_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), +}; + +static const struct regmap_config hmc5843_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .rd_table = &hmc5843_readable_table, + .wr_table = &hmc5843_writable_table, + .volatile_table = &hmc5843_volatile_table, + + /* Autoincrement address pointer */ + .read_flag_mask = 0xc0, + + .cache_type = REGCACHE_RBTREE, +}; + +static int hmc5843_spi_probe(struct spi_device *spi) +{ + int ret; + const struct spi_device_id *id = spi_get_device_id(spi); + + spi->mode = SPI_MODE_3; + spi->max_speed_hz = 8000000; + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret) + return ret; + + return hmc5843_common_probe(&spi->dev, + devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config), + id->driver_data, id->name); +} + +static int hmc5843_spi_remove(struct spi_device *spi) +{ + return hmc5843_common_remove(&spi->dev); +} + +static const struct spi_device_id hmc5843_id[] = { + { "hmc5983", HMC5983_ID }, + { } +}; +MODULE_DEVICE_TABLE(spi, hmc5843_id); + +static struct spi_driver hmc5843_driver = { + .driver = { + .name = "hmc5843", + .pm = HMC5843_PM_OPS, + }, + .id_table = hmc5843_id, + .probe = hmc5843_spi_probe, + .remove = hmc5843_spi_remove, +}; + +module_spi_driver(hmc5843_driver); + +MODULE_AUTHOR("Josef Gajdusek "); +MODULE_DESCRIPTION("HMC5983 SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 0e044cb0def8..8abc1ab3c0c7 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -12,7 +12,6 @@ source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" source "drivers/staging/iio/light/Kconfig" -source "drivers/staging/iio/magnetometer/Kconfig" source "drivers/staging/iio/meter/Kconfig" source "drivers/staging/iio/resolver/Kconfig" source "drivers/staging/iio/trigger/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 3e616b4437f5..0cfd05d5bf49 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -10,7 +10,6 @@ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ obj-y += light/ -obj-y += magnetometer/ obj-y += meter/ obj-y += resolver/ obj-y += trigger/ diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig deleted file mode 100644 index dec814a7a073..000000000000 --- a/drivers/staging/iio/magnetometer/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# Magnetometer sensors -# -menu "Magnetometer sensors" - -config SENSORS_HMC5843 - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config SENSORS_HMC5843_I2C - tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)" - depends on I2C - select SENSORS_HMC5843 - select REGMAP_I2C - help - Say Y here to add support for the Honeywell HMC5843, HMC5883 and - HMC5883L 3-Axis Magnetometer (digital compass). - - 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, HMC5883L and HMC5983) - -config SENSORS_HMC5843_SPI - tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)" - depends on SPI_MASTER - select SENSORS_HMC5843 - select REGMAP_SPI - help - Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer - (digital compass). - - This driver can also be compiled as a set of modules. - If so, these modules will be created: - - hmc5843_core (core functions) - - hmc5843_spi (support for HMC5983) - - -endmenu diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile deleted file mode 100644 index 33761a19a956..000000000000 --- a/drivers/staging/iio/magnetometer/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for industrial I/O Magnetometer sensors -# - -obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o -obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o -obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/staging/iio/magnetometer/hmc5843.h b/drivers/staging/iio/magnetometer/hmc5843.h deleted file mode 100644 index 76a5d7484d8d..000000000000 --- a/drivers/staging/iio/magnetometer/hmc5843.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Header file for hmc5843 driver - * - * Split from hmc5843.c - * Copyright (C) Josef Gajdusek - * - * 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 -#include - -#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, - HMC5983_ID, -}; - -/** - * struct hcm5843_data - device specific data - * @dev: actual device - * @lock: update and read regmap data - * @regmap: hardware access register maps - * @variant: describe chip variants - * @buffer: 3x 16-bit channels + padding + 64-bit timestamp - */ -struct hmc5843_data { - struct device *dev; - struct mutex lock; - struct regmap *regmap; - const struct hmc5843_chip_info *variant; - __be16 buffer[8]; -}; - -int hmc5843_common_probe(struct device *dev, struct regmap *regmap, - enum hmc5843_ids id, const char *name); -int hmc5843_common_remove(struct device *dev); - -int hmc5843_common_suspend(struct device *dev); -int hmc5843_common_resume(struct device *dev); - -#ifdef CONFIG_PM_SLEEP -static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, - hmc5843_common_suspend, - hmc5843_common_resume); -#define HMC5843_PM_OPS (&hmc5843_pm_ops) -#else -#define HMC5843_PM_OPS NULL -#endif - -#endif /* HMC5843_CORE_H */ diff --git a/drivers/staging/iio/magnetometer/hmc5843_core.c b/drivers/staging/iio/magnetometer/hmc5843_core.c deleted file mode 100644 index ebc22b19c60d..000000000000 --- a/drivers/staging/iio/magnetometer/hmc5843_core.c +++ /dev/null @@ -1,687 +0,0 @@ -/* - * Device driver for the the HMC5843 multi-chip module designed - * for low field magnetic sensing. - * - * Copyright (C) 2010 Texas Instruments - * - * Author: Shubhrajyoti Datta - * Acknowledgment: Jonathan Cameron for valuable inputs. - * Support for HMC5883 and HMC5883L by Peter Meerwald . - * Split to multiple files by Josef Gajdusek - 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#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_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_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 - -/* - * 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. - * - * 3 - Only available on HMC5983. Magnetic sensor is disabled. - * Temperature sensor is enabled. - */ - -static const char *const hmc5843_meas_conf_modes[] = {"normal", "positivebias", - "negativebias"}; - -static const char *const hmc5983_meas_conf_modes[] = {"normal", "positivebias", - "negativebias", - "disabled"}; -/* Scaling factors: 10000000/Gain */ -static const int hmc5843_regval_to_nanoscale[] = { - 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 -}; - -static const int hmc5883_regval_to_nanoscale[] = { - 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 -}; - -static const int hmc5883l_regval_to_nanoscale[] = { - 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[][2] = { - {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} -}; - -static const int hmc5883_regval_to_samp_freq[][2] = { - {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, - {75, 0} -}; - -static const int hmc5983_regval_to_samp_freq[][2] = { - {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, - {75, 0}, {220, 0} -}; - -/* Describe chip variants */ -struct hmc5843_chip_info { - const struct iio_chan_spec *channels; - const int (*regval_to_samp_freq)[2]; - const int n_regval_to_samp_freq; - const int *regval_to_nanoscale; - const int n_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; - unsigned 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; -} - -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 -int hmc5843_show_measurement_configuration(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct hmc5843_data *data = iio_priv(indio_dev); - unsigned int val; - int ret; - - ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val); - if (ret) - return ret; - - return val & HMC5843_MEAS_CONF_MASK; -} - -static -int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - unsigned int meas_conf) -{ - struct hmc5843_data *data = iio_priv(indio_dev); - - return hmc5843_set_meas_conf(data, meas_conf); -} - -static const struct iio_enum hmc5843_meas_conf_enum = { - .items = hmc5843_meas_conf_modes, - .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), - .get = hmc5843_show_measurement_configuration, - .set = hmc5843_set_measurement_configuration, -}; - -static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { - IIO_ENUM("meas_conf", true, &hmc5843_meas_conf_enum), - IIO_ENUM_AVAILABLE("meas_conf", &hmc5843_meas_conf_enum), - { }, -}; - -static const struct iio_enum hmc5983_meas_conf_enum = { - .items = hmc5983_meas_conf_modes, - .num_items = ARRAY_SIZE(hmc5983_meas_conf_modes), - .get = hmc5843_show_measurement_configuration, - .set = hmc5843_set_measurement_configuration, -}; - -static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { - IIO_ENUM("meas_conf", true, &hmc5983_meas_conf_enum), - IIO_ENUM_AVAILABLE("meas_conf", &hmc5983_meas_conf_enum), - { }, -}; - -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 < data->variant->n_regval_to_samp_freq; 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 < data->variant->n_regval_to_samp_freq; 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 < data->variant->n_regval_to_nanoscale; 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) - return -EINVAL; - - for (i = 0; i < data->variant->n_regval_to_nanoscale; 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); - unsigned 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, \ - }, \ - .ext_info = hmc5843_ext_info, \ - } - -#define HMC5983_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, \ - }, \ - .ext_info = hmc5983_ext_info, \ - } - -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 and 5983 */ -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 const struct iio_chan_spec hmc5983_channels[] = { - HMC5983_CHANNEL(X, 0), - HMC5983_CHANNEL(Z, 1), - HMC5983_CHANNEL(Y, 2), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - -static struct attribute *hmc5843_attributes[] = { - &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, - .n_regval_to_samp_freq = - ARRAY_SIZE(hmc5843_regval_to_samp_freq), - .regval_to_nanoscale = hmc5843_regval_to_nanoscale, - .n_regval_to_nanoscale = - ARRAY_SIZE(hmc5843_regval_to_nanoscale), - }, - [HMC5883_ID] = { - .channels = hmc5883_channels, - .regval_to_samp_freq = hmc5883_regval_to_samp_freq, - .n_regval_to_samp_freq = - ARRAY_SIZE(hmc5883_regval_to_samp_freq), - .regval_to_nanoscale = hmc5883_regval_to_nanoscale, - .n_regval_to_nanoscale = - ARRAY_SIZE(hmc5883_regval_to_nanoscale), - }, - [HMC5883L_ID] = { - .channels = hmc5883_channels, - .regval_to_samp_freq = hmc5883_regval_to_samp_freq, - .n_regval_to_samp_freq = - ARRAY_SIZE(hmc5883_regval_to_samp_freq), - .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, - .n_regval_to_nanoscale = - ARRAY_SIZE(hmc5883l_regval_to_nanoscale), - }, - [HMC5983_ID] = { - .channels = hmc5983_channels, - .regval_to_samp_freq = hmc5983_regval_to_samp_freq, - .n_regval_to_samp_freq = - ARRAY_SIZE(hmc5983_regval_to_samp_freq), - .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, - .n_regval_to_nanoscale = - ARRAY_SIZE(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/5983 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 device *dev) -{ - return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), - HMC5843_MODE_SLEEP); -} -EXPORT_SYMBOL(hmc5843_common_suspend); - -int hmc5843_common_resume(struct device *dev) -{ - return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)), - HMC5843_MODE_CONVERSION_CONTINUOUS); -} -EXPORT_SYMBOL(hmc5843_common_resume); - -int hmc5843_common_probe(struct device *dev, struct regmap *regmap, - enum hmc5843_ids id, const char *name) -{ - struct hmc5843_data *data; - struct iio_dev *indio_dev; - int ret; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - dev_set_drvdata(dev, indio_dev); - - /* default settings at probe */ - data = iio_priv(indio_dev); - data->dev = dev; - data->regmap = regmap; - data->variant = &hmc5843_chip_info_tbl[id]; - mutex_init(&data->lock); - - indio_dev->dev.parent = dev; - indio_dev->name = name; - 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) - goto buffer_setup_err; - - ret = iio_device_register(indio_dev); - if (ret < 0) - goto buffer_cleanup; - - return 0; - -buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -buffer_setup_err: - hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); - return ret; -} -EXPORT_SYMBOL(hmc5843_common_probe); - -int hmc5843_common_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(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 "); -MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c deleted file mode 100644 index 3de7f4426ac4..000000000000 --- a/drivers/staging/iio/magnetometer/hmc5843_i2c.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * i2c driver for hmc5843/5843/5883/5883l/5983 - * - * Split from hmc5843.c - * Copyright (C) Josef Gajdusek - * - * 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 -#include -#include -#include -#include - -#include "hmc5843.h" - -static const struct regmap_range hmc5843_readable_ranges[] = { - regmap_reg_range(0, HMC5843_ID_END), -}; - -static const 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 const 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 const struct regmap_access_table hmc5843_volatile_table = { - .yes_ranges = hmc5843_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), -}; - -static const 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 *cli, - const struct i2c_device_id *id) -{ - return hmc5843_common_probe(&cli->dev, - devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config), - id->driver_data, id->name); -} - -static int hmc5843_i2c_remove(struct i2c_client *client) -{ - return hmc5843_common_remove(&client->dev); -} - -static const struct i2c_device_id hmc5843_id[] = { - { "hmc5843", HMC5843_ID }, - { "hmc5883", HMC5883_ID }, - { "hmc5883l", HMC5883L_ID }, - { "hmc5983", HMC5983_ID }, - { } -}; -MODULE_DEVICE_TABLE(i2c, hmc5843_id); - -static const struct of_device_id hmc5843_of_match[] = { - { .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID }, - { .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID }, - { .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID }, - { .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID }, - {} -}; -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 "); -MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/magnetometer/hmc5843_spi.c b/drivers/staging/iio/magnetometer/hmc5843_spi.c deleted file mode 100644 index 535f03a70d63..000000000000 --- a/drivers/staging/iio/magnetometer/hmc5843_spi.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SPI driver for hmc5983 - * - * Copyright (C) Josef Gajdusek - * - * 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 -#include -#include - -#include "hmc5843.h" - -static const struct regmap_range hmc5843_readable_ranges[] = { - regmap_reg_range(0, HMC5843_ID_END), -}; - -static const 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 const 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 const struct regmap_access_table hmc5843_volatile_table = { - .yes_ranges = hmc5843_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), -}; - -static const struct regmap_config hmc5843_spi_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .rd_table = &hmc5843_readable_table, - .wr_table = &hmc5843_writable_table, - .volatile_table = &hmc5843_volatile_table, - - /* Autoincrement address pointer */ - .read_flag_mask = 0xc0, - - .cache_type = REGCACHE_RBTREE, -}; - -static int hmc5843_spi_probe(struct spi_device *spi) -{ - int ret; - const struct spi_device_id *id = spi_get_device_id(spi); - - spi->mode = SPI_MODE_3; - spi->max_speed_hz = 8000000; - spi->bits_per_word = 8; - ret = spi_setup(spi); - if (ret) - return ret; - - return hmc5843_common_probe(&spi->dev, - devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config), - id->driver_data, id->name); -} - -static int hmc5843_spi_remove(struct spi_device *spi) -{ - return hmc5843_common_remove(&spi->dev); -} - -static const struct spi_device_id hmc5843_id[] = { - { "hmc5983", HMC5983_ID }, - { } -}; -MODULE_DEVICE_TABLE(spi, hmc5843_id); - -static struct spi_driver hmc5843_driver = { - .driver = { - .name = "hmc5843", - .pm = HMC5843_PM_OPS, - }, - .id_table = hmc5843_id, - .probe = hmc5843_spi_probe, - .remove = hmc5843_spi_remove, -}; - -module_spi_driver(hmc5843_driver); - -MODULE_AUTHOR("Josef Gajdusek "); -MODULE_DESCRIPTION("HMC5983 SPI driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 646708693e91e03cdce82266408590a912a52f6d Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Mon, 22 Feb 2016 12:34:32 -0800 Subject: staging: iio: isl29018: use regmap to retrieve struct device Remove struct device from drivers global data and use regmap API to retrieve device info instead. This replacement can be done for drivers that include regmap in their global data. Signed-off-by: Alison Schofield Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/staging/iio') diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 756057cae86a..26a5412b4bef 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -100,7 +100,6 @@ static const struct isl29018_scale { }; struct isl29018_chip { - struct device *dev; struct regmap *regmap; struct mutex lock; int type; @@ -180,30 +179,31 @@ static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) int status; unsigned int lsb; unsigned int msb; + struct device *dev = regmap_get_device(chip->regmap); /* Set mode */ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, mode << COMMMAND1_OPMODE_SHIFT); if (status) { - dev_err(chip->dev, + dev_err(dev, "Error in setting operating mode err %d\n", status); return status; } msleep(CONVERSION_TIME_MS); status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb); if (status < 0) { - dev_err(chip->dev, + dev_err(dev, "Error in reading LSB DATA with err %d\n", status); return status; } status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb); if (status < 0) { - dev_err(chip->dev, + dev_err(dev, "Error in reading MSB DATA with error %d\n", status); return status; } - dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); + dev_vdbg(dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); return (msb << 8) | lsb; } @@ -246,13 +246,14 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, int status; int prox_data = -1; int ir_data = -1; + struct device *dev = regmap_get_device(chip->regmap); /* Do proximity sensing with required scheme */ status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII, COMMANDII_SCHEME_MASK, scheme << COMMANDII_SCHEME_SHIFT); if (status) { - dev_err(chip->dev, "Error in setting operating mode\n"); + dev_err(dev, "Error in setting operating mode\n"); return status; } @@ -518,10 +519,11 @@ static int isl29035_detect(struct isl29018_chip *chip) { int status; unsigned int id; + struct device *dev = regmap_get_device(chip->regmap); status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); if (status < 0) { - dev_err(chip->dev, + dev_err(dev, "Error reading ID register with error %d\n", status); return status; @@ -546,6 +548,7 @@ enum { static int isl29018_chip_init(struct isl29018_chip *chip) { int status; + struct device *dev = regmap_get_device(chip->regmap); if (chip->type == isl29035) { status = isl29035_detect(chip); @@ -575,7 +578,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip) */ status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0); if (status < 0) { - dev_err(chip->dev, "Failed to clear isl29018 TEST reg.(%d)\n", + dev_err(dev, "Failed to clear isl29018 TEST reg.(%d)\n", status); return status; } @@ -586,7 +589,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip) */ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0); if (status < 0) { - dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg.(%d)\n", + dev_err(dev, "Failed to clear isl29018 CMD1 reg.(%d)\n", status); return status; } @@ -597,14 +600,14 @@ static int isl29018_chip_init(struct isl29018_chip *chip) status = isl29018_set_scale(chip, chip->scale.scale, chip->scale.uscale); if (status < 0) { - dev_err(chip->dev, "Init of isl29018 fails\n"); + dev_err(dev, "Init of isl29018 fails\n"); return status; } status = isl29018_set_integration_time(chip, isl29018_int_utimes[chip->type][chip->int_time]); if (status < 0) { - dev_err(chip->dev, "Init of isl29018 fails\n"); + dev_err(dev, "Init of isl29018 fails\n"); return status; } @@ -721,7 +724,6 @@ static int isl29018_probe(struct i2c_client *client, chip = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - chip->dev = &client->dev; if (id) { name = id->name; @@ -744,7 +746,7 @@ static int isl29018_probe(struct i2c_client *client, chip_info_tbl[dev_id].regmap_cfg); if (IS_ERR(chip->regmap)) { err = PTR_ERR(chip->regmap); - dev_err(chip->dev, "regmap initialization failed: %d\n", err); + dev_err(&client->dev, "regmap initialization fails: %d\n", err); return err; } -- cgit v1.2.3 From c720842e363e6549c122ecdcc8dee51f54c45898 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 26 Feb 2016 10:36:36 +0100 Subject: staging:iio: Remove periodic RTC trigger driver With the recently introduced hrtimer based trigger we have a fully functional replacement for the RTC timer trigger that is more flexible and has a better interface to instantiate and manage the trigger instances. The RTC trigger timer could only be instantiated using platform devices which makes it unsuitable for modern devicetree based platforms, while the hrtimer trigger has a configfs based interface that allows creating and deletion of triggers at runtime. In addition since a few years the periodic RTC timer is internally always emulated using a hrtimer using the hrtimer interface directly will yield the same timing precision. So using the RTC timer won't have any advantages on this front either. There is also no evidence that the periodic RTC trigger is currently actually being used on any system. So considering all this remove the driver. Also remove the related item from the TODO list. Signed-off-by: Lars-Peter Clausen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/staging/iio/TODO | 8 - drivers/staging/iio/trigger/Kconfig | 10 - drivers/staging/iio/trigger/Makefile | 1 - .../staging/iio/trigger/iio-trig-periodic-rtc.c | 216 --------------------- 4 files changed, 235 deletions(-) delete mode 100644 drivers/staging/iio/trigger/iio-trig-periodic-rtc.c (limited to 'drivers/staging/iio') diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index c22a0edd1528..93a896883e37 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -58,14 +58,6 @@ different requirements. This one suits mid range frequencies (100Hz - 4kHz). 2) Lots of testing -Periodic Timer trigger -1) Move to a more general hardware periodic timer request -subsystem. Current approach is abusing purpose of RTC. -Initial discussions have taken place, but no actual code -is in place as yet. This topic will be reopened on lkml -shortly. I don't really envision this patch being merged -in anything like its current form. - GPIO trigger 1) Add control over the type of interrupt etc. This will necessitate a header that is also visible from arch board diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index 710a2f3e787e..0b01d24cea51 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig @@ -5,16 +5,6 @@ comment "Triggers - standalone" if IIO_TRIGGER -config IIO_PERIODIC_RTC_TRIGGER - tristate "Periodic RTC triggers" - depends on RTC_CLASS - help - Provides support for using periodic capable real time - clocks as IIO triggers. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-periodic-rtc. - config IIO_BFIN_TMR_TRIGGER tristate "Blackfin TIMER trigger" depends on BLACKFIN diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile index 238481b78e72..1300a21363db 100644 --- a/drivers/staging/iio/trigger/Makefile +++ b/drivers/staging/iio/trigger/Makefile @@ -2,5 +2,4 @@ # Makefile for triggers not associated with iio-devices # -obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c deleted file mode 100644 index 00d139331261..000000000000 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ /dev/null @@ -1,216 +0,0 @@ -/* The industrial I/O periodic RTC trigger driver - * - * Copyright (c) 2008 Jonathan Cameron - * - * 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. - * - * This is a heavily rewritten version of the periodic timer system in - * earlier version of industrialio. It supplies the same functionality - * but via a trigger rather than a specific periodic timer system. - */ - -#include -#include -#include -#include -#include -#include -#include - -static LIST_HEAD(iio_prtc_trigger_list); -static DEFINE_MUTEX(iio_prtc_trigger_list_lock); - -struct iio_prtc_trigger_info { - struct rtc_device *rtc; - unsigned int frequency; - struct rtc_task task; - bool state; -}; - -static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) -{ - struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - int ret; - - if (trig_info->frequency == 0 && state) - return -EINVAL; - dev_dbg(&trig_info->rtc->dev, "trigger frequency is %u\n", - trig_info->frequency); - ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); - if (!ret) - trig_info->state = state; - - return ret; -} - -static ssize_t iio_trig_periodic_read_freq(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_trigger *trig = to_iio_trigger(dev); - struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - - return sprintf(buf, "%u\n", trig_info->frequency); -} - -static ssize_t iio_trig_periodic_write_freq(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_trigger *trig = to_iio_trigger(dev); - struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - unsigned int val; - int ret; - - ret = kstrtouint(buf, 10, &val); - if (ret) - goto error_ret; - - if (val > 0) { - ret = rtc_irq_set_freq(trig_info->rtc, &trig_info->task, val); - if (ret == 0 && trig_info->state && trig_info->frequency == 0) - ret = rtc_irq_set_state(trig_info->rtc, - &trig_info->task, 1); - } else { - ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0); - } - if (ret) - goto error_ret; - - trig_info->frequency = val; - - return len; - -error_ret: - return ret; -} - -static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, - iio_trig_periodic_read_freq, - iio_trig_periodic_write_freq); - -static struct attribute *iio_trig_prtc_attrs[] = { - &dev_attr_frequency.attr, - NULL, -}; - -static const struct attribute_group iio_trig_prtc_attr_group = { - .attrs = iio_trig_prtc_attrs, -}; - -static const struct attribute_group *iio_trig_prtc_attr_groups[] = { - &iio_trig_prtc_attr_group, - NULL -}; - -static void iio_prtc_trigger_poll(void *private_data) -{ - iio_trigger_poll(private_data); -} - -static const struct iio_trigger_ops iio_prtc_trigger_ops = { - .owner = THIS_MODULE, - .set_trigger_state = &iio_trig_periodic_rtc_set_state, -}; - -static int iio_trig_periodic_rtc_probe(struct platform_device *dev) -{ - char **pdata = dev->dev.platform_data; - struct iio_prtc_trigger_info *trig_info; - struct iio_trigger *trig, *trig2; - - int i, ret; - - for (i = 0;; i++) { - if (!pdata[i]) - break; - trig = iio_trigger_alloc("periodic%s", pdata[i]); - if (!trig) { - ret = -ENOMEM; - goto error_free_completed_registrations; - } - list_add(&trig->alloc_list, &iio_prtc_trigger_list); - - trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); - if (!trig_info) { - ret = -ENOMEM; - goto error_put_trigger_and_remove_from_list; - } - iio_trigger_set_drvdata(trig, trig_info); - trig->ops = &iio_prtc_trigger_ops; - /* RTC access */ - trig_info->rtc = rtc_class_open(pdata[i]); - if (!trig_info->rtc) { - ret = -EINVAL; - goto error_free_trig_info; - } - trig_info->task.func = iio_prtc_trigger_poll; - trig_info->task.private_data = trig; - ret = rtc_irq_register(trig_info->rtc, &trig_info->task); - if (ret) - goto error_close_rtc; - trig->dev.groups = iio_trig_prtc_attr_groups; - ret = iio_trigger_register(trig); - if (ret) - goto error_unregister_rtc_irq; - } - return 0; -error_unregister_rtc_irq: - rtc_irq_unregister(trig_info->rtc, &trig_info->task); -error_close_rtc: - rtc_class_close(trig_info->rtc); -error_free_trig_info: - kfree(trig_info); -error_put_trigger_and_remove_from_list: - list_del(&trig->alloc_list); - iio_trigger_put(trig); -error_free_completed_registrations: - list_for_each_entry_safe(trig, - trig2, - &iio_prtc_trigger_list, - alloc_list) { - trig_info = iio_trigger_get_drvdata(trig); - rtc_irq_unregister(trig_info->rtc, &trig_info->task); - rtc_class_close(trig_info->rtc); - kfree(trig_info); - iio_trigger_unregister(trig); - } - return ret; -} - -static int iio_trig_periodic_rtc_remove(struct platform_device *dev) -{ - struct iio_trigger *trig, *trig2; - struct iio_prtc_trigger_info *trig_info; - - mutex_lock(&iio_prtc_trigger_list_lock); - list_for_each_entry_safe(trig, - trig2, - &iio_prtc_trigger_list, - alloc_list) { - trig_info = iio_trigger_get_drvdata(trig); - rtc_irq_unregister(trig_info->rtc, &trig_info->task); - rtc_class_close(trig_info->rtc); - kfree(trig_info); - iio_trigger_unregister(trig); - } - mutex_unlock(&iio_prtc_trigger_list_lock); - return 0; -} - -static struct platform_driver iio_trig_periodic_rtc_driver = { - .probe = iio_trig_periodic_rtc_probe, - .remove = iio_trig_periodic_rtc_remove, - .driver = { - .name = "iio_prtc_trigger", - }, -}; - -module_platform_driver(iio_trig_periodic_rtc_driver); - -MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3