From 7c8e818f6e264f978f0f0d6c45daf209870e60fc Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 4 Feb 2017 02:33:32 -0800 Subject: mailmap: Change email to new Konsulko email Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 02d261407683..ac4dde1dcbda 100644 --- a/.mailmap +++ b/.mailmap @@ -109,6 +109,7 @@ Mauro Carvalho Chehab Mauro Carvalho Chehab Matt Ranostay Matthew Ranostay Matt Ranostay +Matt Ranostay Mayuresh Janorkar Michael Buesch Michel Dänzer -- cgit v1.2.3 From 6144f61af6e304044918a3d7a9a2ada2a5c874a7 Mon Sep 17 00:00:00 2001 From: Derek Robson Date: Sat, 4 Feb 2017 14:45:41 +1300 Subject: Staging: iio: resolver: ad2s1210.c - style fix Changed symbolic permissions to octal permissions. Found using checkpatch Signed-off-by: Derek Robson Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 6b992634f009..90b57c03609c 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -531,36 +531,36 @@ error_ret: return ret; } -static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(fclkin, 0644, ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0); -static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(fexcit, 0644, ad2s1210_show_fexcit, ad2s1210_store_fexcit, 0); -static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(control, 0644, ad2s1210_show_control, ad2s1210_store_control, 0); -static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(bits, 0644, ad2s1210_show_resolution, ad2s1210_store_resolution, 0); -static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(fault, 0644, ad2s1210_show_fault, ad2s1210_clear_fault, 0); -static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(los_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_LOS_THRD); -static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(dos_ovr_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_OVR_THRD); -static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(dos_mis_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_MIS_THRD); -static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(dos_rst_max_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_RST_MAX_THRD); -static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(dos_rst_min_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_DOS_RST_MIN_THRD); -static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(lot_high_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_LOT_HIGH_THRD); -static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(lot_low_thrd, 0644, ad2s1210_show_reg, ad2s1210_store_reg, AD2S1210_REG_LOT_LOW_THRD); -- cgit v1.2.3 From 2fb5904d92d42c88432cb29f567654d28f9d6411 Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Tue, 31 Jan 2017 19:03:06 +0100 Subject: iio: distance: add dt binding for devantech-srf04 This patch adds dt binding for devantech ultrasonic ranger srf04. The vendor "devantech" was already added to the vendor list with "[PATCH v4 1/3] iio: distance: srf08: add trivial DT binding" Signed-off-by: Andreas Klinger Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../bindings/iio/proximity/devantech-srf04.txt | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt diff --git a/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt new file mode 100644 index 000000000000..d4dc7a227e2e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/devantech-srf04.txt @@ -0,0 +1,28 @@ +* Devantech SRF04 ultrasonic range finder + Bit-banging driver using two GPIOs + +Required properties: + - compatible: Should be "devantech,srf04" + + - trig-gpios: Definition of the GPIO for the triggering (output) + This GPIO is set for about 10 us by the driver to tell the + device it should initiate the measurement cycle. + + - echo-gpios: Definition of the GPIO for the echo (input) + This GPIO is set by the device as soon as an ultrasonic + burst is sent out and reset when the first echo is + received. + Thus this GPIO is set while the ultrasonic waves are doing + one round trip. + It needs to be an GPIO which is able to deliver an + interrupt because the time between two interrupts is + measured in the driver. + See Documentation/devicetree/bindings/gpio/gpio.txt for + information on how to specify a consumer gpio. + +Example: +srf04@0 { + compatible = "devantech,srf04"; + trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; +}; -- cgit v1.2.3 From feda2840040fcf87d826b0aec945a98222e656ba Mon Sep 17 00:00:00 2001 From: Andreas Klinger Date: Tue, 31 Jan 2017 19:03:45 +0100 Subject: iio: distance: add devantech us ranger srf04 This patch adds support for the ultrasonic ranger srf04 of devantech. This device is measuring the distance of objects in a range between 1 cm and 3 meters and a theoretical resolution of 3 mm. There are two GPIOs used: - trigger: set as output to the device when the measurement should start - echo: set by the device when the ultrasonic wave is sent out and reset when the echo is recognized; this needs to be an interrupt input The time between setting and resetting the echo pin is the time the waveform needed for one round trip. This time is recorded in the interrupt handler. The distance is calculated in the read function by using the ultrasonic speed at 20 degrees celsius which is about 343 m/s. Signed-off-by: Andreas Klinger Signed-off-by: Jonathan Cameron --- MAINTAINERS | 6 + drivers/iio/proximity/Kconfig | 11 ++ drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/srf04.c | 304 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 drivers/iio/proximity/srf04.c diff --git a/MAINTAINERS b/MAINTAINERS index 89e0877e1399..adb9cb0d3d40 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3790,6 +3790,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git S: Maintained F: drivers/usb/dwc3/ +DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER +M: Andreas Klinger +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/proximity/srf*.c + DEVICE COREDUMP (DEV_COREDUMP) M: Johannes Berg L: linux-kernel@vger.kernel.org diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index ab96cb7a0054..5b81a8c9d438 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -32,6 +32,17 @@ config LIDAR_LITE_V2 To compile this driver as a module, choose M here: the module will be called pulsedlight-lite-v2 +config SRF04 + tristate "Devantech SRF04 ultrasonic ranger sensor" + depends on GPIOLIB + help + Say Y here to build a driver for Devantech SRF04 ultrasonic + ranger sensor. This driver can be used to measure the distance + of objects. It is using two GPIOs. + + To compile this driver as a module, choose M here: the + module will be called srf04. + config SX9500 tristate "SX9500 Semtech proximity sensor" select IIO_BUFFER diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index e914c2a5dd49..ed1b6f4cc209 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -5,5 +5,6 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o +obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o obj-$(CONFIG_SX9500) += sx9500.o diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c new file mode 100644 index 000000000000..e37667f933b3 --- /dev/null +++ b/drivers/iio/proximity/srf04.c @@ -0,0 +1,304 @@ +/* + * SRF04: ultrasonic sensor for distance measuring by using GPIOs + * + * Copyright (c) 2017 Andreas Klinger + * + * 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. + * + * For details about the device see: + * http://www.robot-electronics.co.uk/htm/srf04tech.htm + * + * the measurement cycle as timing diagram looks like: + * + * +---+ + * GPIO | | + * trig: --+ +------------------------------------------------------ + * ^ ^ + * |<->| + * udelay(10) + * + * ultra +-+ +-+ +-+ + * sonic | | | | | | + * burst: ---------+ +-+ +-+ +----------------------------------------- + * . + * ultra . +-+ +-+ +-+ + * sonic . | | | | | | + * echo: ----------------------------------+ +-+ +-+ +---------------- + * . . + * +------------------------+ + * GPIO | | + * echo: -------------------+ +--------------- + * ^ ^ + * interrupt interrupt + * (ts_rising) (ts_falling) + * |<---------------------->| + * pulse time measured + * --> one round trip of ultra sonic waves + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct srf04_data { + struct device *dev; + struct gpio_desc *gpiod_trig; + struct gpio_desc *gpiod_echo; + struct mutex lock; + int irqnr; + ktime_t ts_rising; + ktime_t ts_falling; + struct completion rising; + struct completion falling; +}; + +static irqreturn_t srf04_handle_irq(int irq, void *dev_id) +{ + struct iio_dev *indio_dev = dev_id; + struct srf04_data *data = iio_priv(indio_dev); + ktime_t now = ktime_get(); + + if (gpiod_get_value(data->gpiod_echo)) { + data->ts_rising = now; + complete(&data->rising); + } else { + data->ts_falling = now; + complete(&data->falling); + } + + return IRQ_HANDLED; +} + +static int srf04_read(struct srf04_data *data) +{ + int ret; + ktime_t ktime_dt; + u64 dt_ns; + u32 time_ns, distance_mm; + + /* + * just one read-echo-cycle can take place at a time + * ==> lock against concurrent reading calls + */ + mutex_lock(&data->lock); + + reinit_completion(&data->rising); + reinit_completion(&data->falling); + + gpiod_set_value(data->gpiod_trig, 1); + udelay(10); + gpiod_set_value(data->gpiod_trig, 0); + + /* it cannot take more than 20 ms */ + ret = wait_for_completion_killable_timeout(&data->rising, HZ/50); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret == 0) { + mutex_unlock(&data->lock); + return -ETIMEDOUT; + } + + ret = wait_for_completion_killable_timeout(&data->falling, HZ/50); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret == 0) { + mutex_unlock(&data->lock); + return -ETIMEDOUT; + } + + ktime_dt = ktime_sub(data->ts_falling, data->ts_rising); + + mutex_unlock(&data->lock); + + dt_ns = ktime_to_ns(ktime_dt); + /* + * measuring more than 3 meters is beyond the capabilities of + * the sensor + * ==> filter out invalid results for not measuring echos of + * another us sensor + * + * formula: + * distance 3 m + * time = ---------- = --------- = 9404389 ns + * speed 319 m/s + * + * using a minimum speed at -20 °C of 319 m/s + */ + if (dt_ns > 9404389) + return -EIO; + + time_ns = dt_ns; + + /* + * the speed as function of the temperature is approximately: + * + * speed = 331,5 + 0,6 * Temp + * with Temp in °C + * and speed in m/s + * + * use 343 m/s as ultrasonic speed at 20 °C here in absence of the + * temperature + * + * therefore: + * time 343 + * distance = ------ * ----- + * 10^6 2 + * with time in ns + * and distance in mm (one way) + * + * because we limit to 3 meters the multiplication with 343 just + * fits into 32 bit + */ + distance_mm = time_ns * 343 / 2000000; + + return distance_mm; +} + +static int srf04_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long info) +{ + struct srf04_data *data = iio_priv(indio_dev); + int ret; + + if (channel->type != IIO_DISTANCE) + return -EINVAL; + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = srf04_read(data); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * theoretical maximum resolution is 3 mm + * 1 LSB is 1 mm + */ + *val = 0; + *val2 = 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static const struct iio_info srf04_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = srf04_read_raw, +}; + +static const struct iio_chan_spec srf04_chan_spec[] = { + { + .type = IIO_DISTANCE, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int srf04_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct srf04_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct srf04_data)); + if (!indio_dev) { + dev_err(dev, "failed to allocate IIO device\n"); + return -ENOMEM; + } + + data = iio_priv(indio_dev); + data->dev = dev; + + mutex_init(&data->lock); + init_completion(&data->rising); + init_completion(&data->falling); + + data->gpiod_trig = devm_gpiod_get(dev, "trig", GPIOD_OUT_LOW); + if (IS_ERR(data->gpiod_trig)) { + dev_err(dev, "failed to get trig-gpios: err=%ld\n", + PTR_ERR(data->gpiod_trig)); + return PTR_ERR(data->gpiod_trig); + } + + data->gpiod_echo = devm_gpiod_get(dev, "echo", GPIOD_IN); + if (IS_ERR(data->gpiod_echo)) { + dev_err(dev, "failed to get echo-gpios: err=%ld\n", + PTR_ERR(data->gpiod_echo)); + return PTR_ERR(data->gpiod_echo); + } + + if (gpiod_cansleep(data->gpiod_echo)) { + dev_err(data->dev, "cansleep-GPIOs not supported\n"); + return -ENODEV; + } + + data->irqnr = gpiod_to_irq(data->gpiod_echo); + if (data->irqnr < 0) { + dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr); + return data->irqnr; + } + + ret = devm_request_irq(dev, data->irqnr, srf04_handle_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + pdev->name, indio_dev); + if (ret < 0) { + dev_err(data->dev, "request_irq: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = "srf04"; + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &srf04_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = srf04_chan_spec; + indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id of_srf04_match[] = { + { .compatible = "devantech,srf04", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_srf04_match); + +static struct platform_driver srf04_driver = { + .probe = srf04_probe, + .driver = { + .name = "srf04-gpio", + .of_match_table = of_srf04_match, + }, +}; + +module_platform_driver(srf04_driver); + +MODULE_AUTHOR("Andreas Klinger "); +MODULE_DESCRIPTION("SRF04 ultrasonic sensor for distance measuring using GPIOs"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:srf04"); -- cgit v1.2.3 From d068e4a0f9213074c5d893b8b80ca7bca444ed1d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 29 Jan 2017 11:49:24 +0100 Subject: iio: imu: st_lsm6dsx: add support to multiple devices with the same settings Add capability to support multiple devices with the same st_lsm6dsx_settings like LSM6DSM/LSM6DSL Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 3 ++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 30 +++++++++++++++------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 69deafe1c10d..2c1bb9e58d01 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -20,6 +20,7 @@ enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, ST_LSM6DSM_ID, + ST_LSM6DSX_MAX_ID, }; #define ST_LSM6DSX_CHAN_SIZE 2 @@ -50,7 +51,7 @@ struct st_lsm6dsx_reg { struct st_lsm6dsx_settings { u8 wai; u16 max_fifo_size; - enum st_lsm6dsx_hw_id id; + enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID]; }; enum st_lsm6dsx_sensor_id { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index c92ddcc190e2..499e60af8fa7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -74,12 +74,6 @@ #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 -#define ST_LSM6DS3_WHOAMI 0x69 -#define ST_LSM6DSM_WHOAMI 0x6a - -#define ST_LSM6DS3_MAX_FIFO_SIZE 8192 -#define ST_LSM6DSM_MAX_FIFO_SIZE 4096 - #define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) #define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) #define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) @@ -164,14 +158,18 @@ static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { - .wai = ST_LSM6DS3_WHOAMI, - .max_fifo_size = ST_LSM6DS3_MAX_FIFO_SIZE, - .id = ST_LSM6DS3_ID, + .wai = 0x69, + .max_fifo_size = 8192, + .id = { + [0] = ST_LSM6DS3_ID, + }, }, { - .wai = ST_LSM6DSM_WHOAMI, - .max_fifo_size = ST_LSM6DSM_MAX_FIFO_SIZE, - .id = ST_LSM6DSM_ID, + .wai = 0x6a, + .max_fifo_size = 4096, + .id = { + [0] = ST_LSM6DSM_ID, + }, }, }; @@ -241,11 +239,15 @@ out: static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) { - int err, i; + int err, i, j; u8 data; for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { - if (id == st_lsm6dsx_sensor_settings[i].id) + for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { + if (id == st_lsm6dsx_sensor_settings[i].id[j]) + break; + } + if (j < ST_LSM6DSX_MAX_ID) break; } -- cgit v1.2.3 From 0b2a3e5f17d6ba3f00aee1000718a84afb3d4d1f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 29 Jan 2017 11:49:25 +0100 Subject: iio: imu: st_lsm6dsx: add support to lsm6dsl Add support to STM LSM6DSL 6-axis (acc + gyro) Mems sensor http://www.st.com/resource/en/datasheet/lsm6dsl.pdf Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/Kconfig | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 4 ++-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 5 +++-- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 5 +++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 5 +++++ 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 935d4cd071a3..d264783bfffd 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -8,7 +8,7 @@ config IIO_ST_LSM6DSX select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) help Say yes here to build support for STMicroelectronics LSM6DSx imu - sensor. Supported devices: lsm6ds3, lsm6dsm + sensor. Supported devices: lsm6ds3, lsm6dsl, lsm6dsm To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 2c1bb9e58d01..e0ece13974e5 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -15,10 +15,12 @@ #include #define ST_LSM6DS3_DEV_NAME "lsm6ds3" +#define ST_LSM6DSL_DEV_NAME "lsm6dsl" #define ST_LSM6DSM_DEV_NAME "lsm6dsm" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, + ST_LSM6DSL_ID, ST_LSM6DSM_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 78532ce07449..73a6492ed763 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -1,7 +1,7 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DSM: The FIFO buffer can be configured to store data + * LSM6DS3/LSM6DSL/LSM6DSM: The FIFO buffer can be configured to store data * from gyroscope and accelerometer. Samples are queued without any tag * according to a specific pattern based on 'FIFO data sets' (6 bytes each): * - 1st data set is reserved for gyroscope data @@ -206,7 +206,7 @@ out: } /** - * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSM read FIFO routine + * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSL-LSM6DSM read FIFO routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. * * Read samples from the hw FIFO and push them to IIO buffers. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 499e60af8fa7..5d8d5cda33c4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -17,7 +17,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DSM: + * - LSM6DSL/LSM6DSM: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 @@ -168,7 +168,8 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .wai = 0x6a, .max_fifo_size = 4096, .id = { - [0] = ST_LSM6DSM_ID, + [0] = ST_LSM6DSL_ID, + [1] = ST_LSM6DSM_ID, }, }, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index ea3041186e1e..60a3de043ae0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -70,6 +70,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6ds3", .data = (void *)ST_LSM6DS3_ID, }, + { + .compatible = "st,lsm6dsl", + .data = (void *)ST_LSM6DSL_ID, + }, { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, @@ -80,6 +84,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, + { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, {}, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index fbe72470ed1e..39edb40cc5cf 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -87,6 +87,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6ds3", .data = (void *)ST_LSM6DS3_ID, }, + { + .compatible = "st,lsm6dsl", + .data = (void *)ST_LSM6DSL_ID, + }, { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, @@ -97,6 +101,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, + { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, {}, }; -- cgit v1.2.3 From 3e9b1222ef06d336d771ae7279a147ee965071bd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 29 Jan 2017 11:49:26 +0100 Subject: Documentation: dt: iio: imu: st_lsm6dsx: add lsm6dsl sensor device binding Signed-off-by: Lorenzo Bianconi Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt index cf81afdf7803..048eca7a5272 100644 --- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt @@ -3,6 +3,7 @@ Required properties: - compatible: must be one of: "st,lsm6ds3" + "st,lsm6dsl" "st,lsm6dsm" - reg: i2c address of the sensor / spi cs line -- cgit v1.2.3 From df47710a6e4a44bbc5f0c40e7d4058147bfc12ed Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 29 Jan 2017 11:49:27 +0100 Subject: iio: imu: st_lsm6dsx: add support to lsm6ds3h Add support to STM LSM6DS3H 6-axis (acc + gyro) Mems sensor http://www.st.com/resource/en/datasheet/lsm6ds3h.pdf Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/Kconfig | 2 +- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 9 +++++---- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 9 ++++++++- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 5 +++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 5 +++++ 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index d264783bfffd..e57337159b57 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -8,7 +8,7 @@ config IIO_ST_LSM6DSX select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) help Say yes here to build support for STMicroelectronics LSM6DSx imu - sensor. Supported devices: lsm6ds3, lsm6dsl, lsm6dsm + sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index e0ece13974e5..6a9849e6b30a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -15,11 +15,13 @@ #include #define ST_LSM6DS3_DEV_NAME "lsm6ds3" +#define ST_LSM6DS3H_DEV_NAME "lsm6ds3h" #define ST_LSM6DSL_DEV_NAME "lsm6dsl" #define ST_LSM6DSM_DEV_NAME "lsm6dsm" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, + ST_LSM6DS3H_ID, ST_LSM6DSL_ID, ST_LSM6DSM_ID, ST_LSM6DSX_MAX_ID, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 73a6492ed763..e71eccedd340 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -1,9 +1,10 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DSL/LSM6DSM: The FIFO buffer can be configured to store data - * from gyroscope and accelerometer. Samples are queued without any tag - * according to a specific pattern based on 'FIFO data sets' (6 bytes each): + * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM: The FIFO buffer can be configured + * to store data from gyroscope and accelerometer. Samples are queued + * without any tag according to a specific pattern based on 'FIFO data sets' + * (6 bytes each): * - 1st data set is reserved for gyroscope data * - 2nd data set is reserved for accelerometer data * The FIFO pattern changes depending on the ODRs and decimation factors @@ -206,7 +207,7 @@ out: } /** - * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSL-LSM6DSM read FIFO routine + * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. * * Read samples from the hw FIFO and push them to IIO buffers. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 5d8d5cda33c4..c4332232ad71 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -17,7 +17,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DSL/LSM6DSM: + * - LSM6DS3H/LSM6DSL/LSM6DSM: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 @@ -164,6 +164,13 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { [0] = ST_LSM6DS3_ID, }, }, + { + .wai = 0x69, + .max_fifo_size = 4096, + .id = { + [0] = ST_LSM6DS3H_ID, + }, + }, { .wai = 0x6a, .max_fifo_size = 4096, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 60a3de043ae0..2e4ed26fcbbd 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -70,6 +70,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6ds3", .data = (void *)ST_LSM6DS3_ID, }, + { + .compatible = "st,lsm6ds3h", + .data = (void *)ST_LSM6DS3H_ID, + }, { .compatible = "st,lsm6dsl", .data = (void *)ST_LSM6DSL_ID, @@ -84,6 +88,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, + { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, {}, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 39edb40cc5cf..1bf4a582e6cf 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -87,6 +87,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6ds3", .data = (void *)ST_LSM6DS3_ID, }, + { + .compatible = "st,lsm6ds3h", + .data = (void *)ST_LSM6DS3H_ID, + }, { .compatible = "st,lsm6dsl", .data = (void *)ST_LSM6DSL_ID, @@ -101,6 +105,7 @@ MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID }, + { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, {}, -- cgit v1.2.3 From 1bf707675fb84ad02dae751a14110c17a2736a81 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 29 Jan 2017 11:49:28 +0100 Subject: Documentation: dt: iio: imu: st_lsm6dsx: add lsm6ds3h sensor device binding Signed-off-by: Lorenzo Bianconi Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt index 048eca7a5272..8305fb05ffda 100644 --- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt @@ -3,6 +3,7 @@ Required properties: - compatible: must be one of: "st,lsm6ds3" + "st,lsm6ds3h" "st,lsm6dsl" "st,lsm6dsm" - reg: i2c address of the sensor / spi cs line -- cgit v1.2.3 From 48458b0c196c6d6224aac5e1178a561e89011724 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Mon, 30 Jan 2017 18:07:53 +0100 Subject: iio: cros_ec_light_prox: add ChromeOS EC Light and Proximity Sensors Handle Light and Proximity sensors presented by the ChromeOS EC Sensor hub. Creates an IIO device for each functions. Signed-off-by: Gwendal Grignou Signed-off-by: Guenter Roeck Signed-off-by: Enric Balletbo i Serra Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 ++ drivers/iio/light/Makefile | 1 + drivers/iio/light/cros_ec_light_prox.c | 289 +++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 drivers/iio/light/cros_ec_light_prox.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 5f731ead9d46..2afcbacc0f7e 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -136,6 +136,16 @@ config CM36651 To compile this driver as a module, choose M here: the module will be called cm36651. +config IIO_CROS_EC_LIGHT_PROX + tristate "ChromeOS EC Light and Proximity Sensors" + depends on IIO_CROS_EC_SENSORS_CORE + help + Say Y here if you use the light and proximity sensors + presented by the ChromeOS EC Sensor hub. + + To compile this driver as a module, choose M here: + the module will be called cros_ec_light_prox. + config GP2AP020A00F tristate "Sharp GP2AP020A00F Proximity/ALS sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c13a2399e6df..edfd69b6dc6d 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CM3232) += cm3232.o obj-$(CONFIG_CM3323) += cm3323.o obj-$(CONFIG_CM3605) += cm3605.o obj-$(CONFIG_CM36651) += cm36651.o +obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += cros_ec_light_prox.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c new file mode 100644 index 000000000000..721722376fd0 --- /dev/null +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -0,0 +1,289 @@ +/* + * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC. + * + * Copyright (C) 2017 Google, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "../common/cros_ec_sensors/cros_ec_sensors_core.h" + +/* + * We only represent one entry for light or proximity. EC is merging different + * light sensors to return the what the eye would see. For proximity, we + * currently support only one light source. + */ +#define CROS_EC_LIGHT_PROX_MAX_CHANNELS (1 + 1) + +/* State data for ec_sensors iio driver. */ +struct cros_ec_light_prox_state { + /* Shared by all sensors */ + struct cros_ec_sensors_core_state core; + + struct iio_chan_spec channels[CROS_EC_LIGHT_PROX_MAX_CHANNELS]; +}; + +static int cros_ec_light_prox_read(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct cros_ec_light_prox_state *st = iio_priv(indio_dev); + u16 data = 0; + s64 val64; + int ret = IIO_VAL_INT; + int idx = chan->scan_index; + + mutex_lock(&st->core.cmd_lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_PROXIMITY) { + if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data) < 0) { + ret = -EIO; + break; + } + *val = data; + } else { + ret = -EINVAL; + } + break; + case IIO_CHAN_INFO_PROCESSED: + if (chan->type == IIO_LIGHT) { + if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx, + (s16 *)&data) < 0) { + ret = -EIO; + break; + } + /* + * The data coming from the light sensor is + * pre-processed and represents the ambient light + * illuminance reading expressed in lux. + */ + *val = data; + ret = IIO_VAL_INT; + } else { + ret = -EINVAL; + } + break; + case IIO_CHAN_INFO_CALIBBIAS: + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; + st->core.param.sensor_offset.flags = 0; + + if (cros_ec_motion_send_host_cmd(&st->core, 0)) { + ret = -EIO; + break; + } + + /* Save values */ + st->core.calib[0] = st->core.resp->sensor_offset.offset[0]; + + *val = st->core.calib[idx]; + break; + case IIO_CHAN_INFO_CALIBSCALE: + /* + * RANGE is used for calibration + * scale is a number x.y, where x is coded on 16 bits, + * y coded on 16 bits, between 0 and 9999. + */ + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; + st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; + + if (cros_ec_motion_send_host_cmd(&st->core, 0)) { + ret = -EIO; + break; + } + + val64 = st->core.resp->sensor_range.ret; + *val = val64 >> 16; + *val2 = (val64 & 0xffff) * 100; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret = cros_ec_sensors_core_read(&st->core, chan, val, val2, + mask); + break; + } + + mutex_unlock(&st->core.cmd_lock); + + return ret; +} + +static int cros_ec_light_prox_write(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct cros_ec_light_prox_state *st = iio_priv(indio_dev); + int ret = 0; + int idx = chan->scan_index; + + mutex_lock(&st->core.cmd_lock); + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + st->core.calib[idx] = val; + /* Send to EC for each axis, even if not complete */ + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET; + st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET; + st->core.param.sensor_offset.offset[0] = st->core.calib[0]; + st->core.param.sensor_offset.temp = + EC_MOTION_SENSE_INVALID_CALIB_TEMP; + if (cros_ec_motion_send_host_cmd(&st->core, 0)) + ret = -EIO; + break; + case IIO_CHAN_INFO_CALIBSCALE: + st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; + st->core.param.sensor_range.data = (val << 16) | (val2 / 100); + if (cros_ec_motion_send_host_cmd(&st->core, 0)) + ret = -EIO; + break; + default: + ret = cros_ec_sensors_core_write(&st->core, chan, val, val2, + mask); + break; + } + + mutex_unlock(&st->core.cmd_lock); + + return ret; +} + +static const struct iio_info cros_ec_light_prox_info = { + .read_raw = &cros_ec_light_prox_read, + .write_raw = &cros_ec_light_prox_write, + .driver_module = THIS_MODULE, +}; + +static int cros_ec_light_prox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent); + struct cros_ec_device *ec_device; + struct iio_dev *indio_dev; + struct cros_ec_light_prox_state *state; + struct iio_chan_spec *channel; + int ret; + + if (!ec_dev || !ec_dev->ec_dev) { + dev_warn(dev, "No CROS EC device found.\n"); + return -EINVAL; + } + ec_device = ec_dev->ec_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + if (ret) + return ret; + + indio_dev->info = &cros_ec_light_prox_info; + state = iio_priv(indio_dev); + state->core.type = state->core.resp->info.type; + state->core.loc = state->core.resp->info.location; + channel = state->channels; + + /* Common part */ + channel->info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_FREQUENCY); + channel->scan_type.realbits = CROS_EC_SENSOR_BITS; + channel->scan_type.storagebits = CROS_EC_SENSOR_BITS; + channel->scan_type.shift = 0; + channel->scan_index = 0; + channel->ext_info = cros_ec_sensors_ext_info; + channel->scan_type.sign = 'u'; + + state->core.calib[0] = 0; + + /* Sensor specific */ + switch (state->core.type) { + case MOTIONSENSE_TYPE_LIGHT: + channel->type = IIO_LIGHT; + channel->info_mask_separate = + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE); + break; + case MOTIONSENSE_TYPE_PROX: + channel->type = IIO_PROXIMITY; + channel->info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE); + break; + default: + dev_warn(dev, "Unknown motion sensor\n"); + return -EINVAL; + } + + /* Timestamp */ + channel++; + channel->type = IIO_TIMESTAMP; + channel->channel = -1; + channel->scan_index = 1; + channel->scan_type.sign = 's'; + channel->scan_type.realbits = 64; + channel->scan_type.storagebits = 64; + + indio_dev->channels = state->channels; + + indio_dev->num_channels = CROS_EC_LIGHT_PROX_MAX_CHANNELS; + + state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + cros_ec_sensors_capture, NULL); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct platform_device_id cros_ec_light_prox_ids[] = { + { + .name = "cros-ec-prox", + }, + { + .name = "cros-ec-light", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids); + +static struct platform_driver cros_ec_light_prox_platform_driver = { + .driver = { + .name = "cros-ec-light-prox", + }, + .probe = cros_ec_light_prox_probe, + .id_table = cros_ec_light_prox_ids, +}; +module_platform_driver(cros_ec_light_prox_platform_driver); + +MODULE_DESCRIPTION("ChromeOS EC light/proximity sensors driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From c62360753e469a4cc5f4629c4ccb090985b33d6e Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Tue, 31 Jan 2017 15:12:56 +0800 Subject: iio: accel: Add driver for the Analog Devices ADXL345 3-axis accelerometer Add basic IIO support for the Analog Devices ADXL345 3-axis accelerometer. The datasheet can be found here: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf Signed-off-by: Eva Rachel Retuya Cc: Michael Hennerich Cc: Daniel Baluta Cc: Alison Schofield Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 11 +++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/adxl345.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 drivers/iio/accel/adxl345.c diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index ef8401ac1141..2308bac21c17 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -5,6 +5,17 @@ menu "Accelerometers" +config ADXL345 + tristate "Analog Devices ADXL345 3-Axis Digital Accelerometer Driver" + depends on !(INPUT_ADXL34X=y || INPUT_ADXL34X=m) + depends on I2C + help + Say Y here if you want to build support for the Analog Devices + ADXL345 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the + module will be called adxl345. + config BMA180 tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 69fe8edc57a2..618488de1161 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_ADXL345) += adxl345.o obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o diff --git a/drivers/iio/accel/adxl345.c b/drivers/iio/accel/adxl345.c new file mode 100644 index 000000000000..c34991fd5c51 --- /dev/null +++ b/drivers/iio/accel/adxl345.c @@ -0,0 +1,194 @@ +/* + * ADXL345 3-Axis Digital Accelerometer + * + * Copyright (c) 2017 Eva Rachel Retuya + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for ADXL345 + * 7-bit I2C slave address: 0x1D (ALT ADDRESS pin tied to VDDIO) or + * 0x53 (ALT ADDRESS pin grounded) + */ + +#include +#include + +#include + +#define ADXL345_REG_DEVID 0x00 +#define ADXL345_REG_POWER_CTL 0x2D +#define ADXL345_REG_DATA_FORMAT 0x31 +#define ADXL345_REG_DATAX0 0x32 +#define ADXL345_REG_DATAY0 0x34 +#define ADXL345_REG_DATAZ0 0x36 + +#define ADXL345_POWER_CTL_MEASURE BIT(3) +#define ADXL345_POWER_CTL_STANDBY 0x00 + +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_2G 0 +#define ADXL345_DATA_FORMAT_4G 1 +#define ADXL345_DATA_FORMAT_8G 2 +#define ADXL345_DATA_FORMAT_16G 3 + +#define ADXL345_DEVID 0xE5 + +/* + * In full-resolution mode, scale factor is maintained at ~4 mg/LSB + * in all g ranges. + * + * At +/- 16g with 13-bit resolution, scale is computed as: + * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 + */ +static const int adxl345_uscale = 38300; + +struct adxl345_data { + struct i2c_client *client; + u8 data_range; +}; + +#define ADXL345_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .address = reg, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec adxl345_channels[] = { + ADXL345_CHANNEL(ADXL345_REG_DATAX0, X), + ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y), + ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z), +}; + +static int adxl345_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adxl345_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * Data is stored in adjacent registers: + * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte + * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte + */ + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + + *val = sign_extend32(ret, 12); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = adxl345_uscale; + + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static const struct iio_info adxl345_info = { + .driver_module = THIS_MODULE, + .read_raw = adxl345_read_raw, +}; + +static int adxl345_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adxl345_data *data; + struct iio_dev *indio_dev; + int ret; + + ret = i2c_smbus_read_byte_data(client, ADXL345_REG_DEVID); + if (ret < 0) { + dev_err(&client->dev, "Error reading device ID: %d\n", ret); + return ret; + } + + if (ret != ADXL345_DEVID) { + dev_err(&client->dev, "Invalid device ID: %d\n", ret); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + /* Enable full-resolution mode */ + data->data_range = ADXL345_DATA_FORMAT_FULL_RES; + + ret = i2c_smbus_write_byte_data(data->client, ADXL345_REG_DATA_FORMAT, + data->data_range); + if (ret < 0) { + dev_err(&client->dev, "Failed to set data range: %d\n", ret); + return ret; + } + + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->info = &adxl345_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adxl345_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); + + /* Enable measurement mode */ + ret = i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_MEASURE); + if (ret < 0) { + dev_err(&client->dev, "Failed to enable measurement mode: %d\n", + ret); + return ret; + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "iio_device_register failed: %d\n", ret); + i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); + } + + return ret; +} + +static int adxl345_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct adxl345_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + return i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); +} + +static const struct i2c_device_id adxl345_i2c_id[] = { + { "adxl345", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); + +static struct i2c_driver adxl345_driver = { + .driver = { + .name = "adxl345", + }, + .probe = adxl345_probe, + .remove = adxl345_remove, + .id_table = adxl345_i2c_id, +}; + +module_i2c_driver(adxl345_driver); + +MODULE_AUTHOR("Eva Rachel Retuya "); +MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 640fa30a70972c057651dc01a9b7f30cc70dcbde Mon Sep 17 00:00:00 2001 From: "Michael S. Hansen" Date: Sat, 4 Feb 2017 18:30:41 -0500 Subject: iio: addac: adt7136: Fix style to use octal file permissions. Signed-off-by: Michael S. Hansen Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316.c | 108 ++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 6054c7298fce..aa251c245981 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -267,7 +267,7 @@ static ssize_t adt7316_store_enabled(struct device *dev, return len; } -static IIO_DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(enabled, 0644, adt7316_show_enabled, adt7316_store_enabled, 0); @@ -311,7 +311,7 @@ static ssize_t adt7316_store_select_ex_temp(struct device *dev, return len; } -static IIO_DEVICE_ATTR(select_ex_temp, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(select_ex_temp, 0644, adt7316_show_select_ex_temp, adt7316_store_select_ex_temp, 0); @@ -352,7 +352,7 @@ static ssize_t adt7316_store_mode(struct device *dev, return len; } -static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(mode, 0644, adt7316_show_mode, adt7316_store_mode, 0); @@ -364,7 +364,7 @@ static ssize_t adt7316_show_all_modes(struct device *dev, return sprintf(buf, "single_channel\nround_robin\n"); } -static IIO_DEVICE_ATTR(all_modes, S_IRUGO, adt7316_show_all_modes, NULL, 0); +static IIO_DEVICE_ATTR(all_modes, 0444, adt7316_show_all_modes, NULL, 0); static ssize_t adt7316_show_ad_channel(struct device *dev, struct device_attribute *attr, @@ -446,7 +446,7 @@ static ssize_t adt7316_store_ad_channel(struct device *dev, return len; } -static IIO_DEVICE_ATTR(ad_channel, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(ad_channel, 0644, adt7316_show_ad_channel, adt7316_store_ad_channel, 0); @@ -469,7 +469,7 @@ static ssize_t adt7316_show_all_ad_channels(struct device *dev, "2 - External Temperature\n"); } -static IIO_DEVICE_ATTR(all_ad_channels, S_IRUGO, +static IIO_DEVICE_ATTR(all_ad_channels, 0444, adt7316_show_all_ad_channels, NULL, 0); static ssize_t adt7316_show_disable_averaging(struct device *dev, @@ -506,7 +506,7 @@ static ssize_t adt7316_store_disable_averaging(struct device *dev, return len; } -static IIO_DEVICE_ATTR(disable_averaging, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(disable_averaging, 0644, adt7316_show_disable_averaging, adt7316_store_disable_averaging, 0); @@ -545,7 +545,7 @@ static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev, return len; } -static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(enable_smbus_timeout, 0644, adt7316_show_enable_smbus_timeout, adt7316_store_enable_smbus_timeout, 0); @@ -583,7 +583,7 @@ static ssize_t adt7316_store_powerdown(struct device *dev, return len; } -static IIO_DEVICE_ATTR(powerdown, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(powerdown, 0644, adt7316_show_powerdown, adt7316_store_powerdown, 0); @@ -621,7 +621,7 @@ static ssize_t adt7316_store_fast_ad_clock(struct device *dev, return len; } -static IIO_DEVICE_ATTR(fast_ad_clock, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(fast_ad_clock, 0644, adt7316_show_fast_ad_clock, adt7316_store_fast_ad_clock, 0); @@ -674,7 +674,7 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev, return len; } -static IIO_DEVICE_ATTR(da_high_resolution, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(da_high_resolution, 0644, adt7316_show_da_high_resolution, adt7316_store_da_high_resolution, 0); @@ -720,7 +720,7 @@ static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev, return len; } -static IIO_DEVICE_ATTR(AIN_internal_Vref, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644, adt7316_show_AIN_internal_Vref, adt7316_store_AIN_internal_Vref, 0); @@ -760,7 +760,7 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev, return len; } -static IIO_DEVICE_ATTR(enable_proportion_DACA, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(enable_proportion_DACA, 0644, adt7316_show_enable_prop_DACA, adt7316_store_enable_prop_DACA, 0); @@ -799,7 +799,7 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev, return len; } -static IIO_DEVICE_ATTR(enable_proportion_DACB, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(enable_proportion_DACB, 0644, adt7316_show_enable_prop_DACB, adt7316_store_enable_prop_DACB, 0); @@ -842,7 +842,7 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev, return len; } -static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, 0644, adt7316_show_DAC_2Vref_ch_mask, adt7316_store_DAC_2Vref_ch_mask, 0); @@ -902,7 +902,7 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev, return len; } -static IIO_DEVICE_ATTR(DAC_update_mode, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(DAC_update_mode, 0644, adt7316_show_DAC_update_mode, adt7316_store_DAC_update_mode, 0); @@ -922,7 +922,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev, return sprintf(buf, "manual\n"); } -static IIO_DEVICE_ATTR(all_DAC_update_modes, S_IRUGO, +static IIO_DEVICE_ATTR(all_DAC_update_modes, 0444, adt7316_show_all_DAC_update_modes, NULL, 0); @@ -961,7 +961,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, return len; } -static IIO_DEVICE_ATTR(update_DAC, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(update_DAC, 0644, NULL, adt7316_store_update_DAC, 0); @@ -1006,7 +1006,7 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev, return len; } -static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, 0644, adt7316_show_DA_AB_Vref_bypass, adt7316_store_DA_AB_Vref_bypass, 0); @@ -1051,7 +1051,7 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev, return len; } -static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, 0644, adt7316_show_DA_CD_Vref_bypass, adt7316_store_DA_CD_Vref_bypass, 0); @@ -1112,7 +1112,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev, return len; } -static IIO_DEVICE_ATTR(DAC_internal_Vref, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(DAC_internal_Vref, 0644, adt7316_show_DAC_internal_Vref, adt7316_store_DAC_internal_Vref, 0); @@ -1201,7 +1201,7 @@ static ssize_t adt7316_show_VDD(struct device *dev, return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf); } -static IIO_DEVICE_ATTR(VDD, S_IRUGO, adt7316_show_VDD, NULL, 0); +static IIO_DEVICE_ATTR(VDD, 0444, adt7316_show_VDD, NULL, 0); static ssize_t adt7316_show_in_temp(struct device *dev, struct device_attribute *attr, @@ -1213,7 +1213,7 @@ static ssize_t adt7316_show_in_temp(struct device *dev, return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf); } -static IIO_DEVICE_ATTR(in_temp, S_IRUGO, adt7316_show_in_temp, NULL, 0); +static IIO_DEVICE_ATTR(in_temp, 0444, adt7316_show_in_temp, NULL, 0); static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev, struct device_attribute *attr, @@ -1225,9 +1225,9 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev, return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf); } -static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, +static IIO_DEVICE_ATTR(ex_temp_AIN1, 0444, adt7316_show_ex_temp_AIN1, NULL, 0); -static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0); +static IIO_DEVICE_ATTR(ex_temp, 0444, adt7316_show_ex_temp_AIN1, NULL, 0); static ssize_t adt7316_show_AIN2(struct device *dev, struct device_attribute *attr, @@ -1238,7 +1238,7 @@ static ssize_t adt7316_show_AIN2(struct device *dev, return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf); } -static IIO_DEVICE_ATTR(AIN2, S_IRUGO, adt7316_show_AIN2, NULL, 0); +static IIO_DEVICE_ATTR(AIN2, 0444, adt7316_show_AIN2, NULL, 0); static ssize_t adt7316_show_AIN3(struct device *dev, struct device_attribute *attr, @@ -1249,7 +1249,7 @@ static ssize_t adt7316_show_AIN3(struct device *dev, return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf); } -static IIO_DEVICE_ATTR(AIN3, S_IRUGO, adt7316_show_AIN3, NULL, 0); +static IIO_DEVICE_ATTR(AIN3, 0444, adt7316_show_AIN3, NULL, 0); static ssize_t adt7316_show_AIN4(struct device *dev, struct device_attribute *attr, @@ -1260,7 +1260,7 @@ static ssize_t adt7316_show_AIN4(struct device *dev, return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf); } -static IIO_DEVICE_ATTR(AIN4, S_IRUGO, adt7316_show_AIN4, NULL, 0); +static IIO_DEVICE_ATTR(AIN4, 0444, adt7316_show_AIN4, NULL, 0); static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip, int offset_addr, char *buf) @@ -1325,7 +1325,7 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev, len); } -static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(in_temp_offset, 0644, adt7316_show_in_temp_offset, adt7316_store_in_temp_offset, 0); @@ -1351,7 +1351,7 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev, len); } -static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(ex_temp_offset, 0644, adt7316_show_ex_temp_offset, adt7316_store_ex_temp_offset, 0); @@ -1378,7 +1378,7 @@ static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev, ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len); } -static IIO_DEVICE_ATTR(in_analog_temp_offset, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(in_analog_temp_offset, 0644, adt7316_show_in_analog_temp_offset, adt7316_store_in_analog_temp_offset, 0); @@ -1405,7 +1405,7 @@ static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev, ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len); } -static IIO_DEVICE_ATTR(ex_analog_temp_offset, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644, adt7316_show_ex_analog_temp_offset, adt7316_store_ex_analog_temp_offset, 0); @@ -1500,7 +1500,7 @@ static ssize_t adt7316_store_DAC_A(struct device *dev, return adt7316_store_DAC(chip, 0, buf, len); } -static IIO_DEVICE_ATTR(DAC_A, S_IRUGO | S_IWUSR, adt7316_show_DAC_A, +static IIO_DEVICE_ATTR(DAC_A, 0644, adt7316_show_DAC_A, adt7316_store_DAC_A, 0); static ssize_t adt7316_show_DAC_B(struct device *dev, @@ -1524,7 +1524,7 @@ static ssize_t adt7316_store_DAC_B(struct device *dev, return adt7316_store_DAC(chip, 1, buf, len); } -static IIO_DEVICE_ATTR(DAC_B, S_IRUGO | S_IWUSR, adt7316_show_DAC_B, +static IIO_DEVICE_ATTR(DAC_B, 0644, adt7316_show_DAC_B, adt7316_store_DAC_B, 0); static ssize_t adt7316_show_DAC_C(struct device *dev, @@ -1548,7 +1548,7 @@ static ssize_t adt7316_store_DAC_C(struct device *dev, return adt7316_store_DAC(chip, 2, buf, len); } -static IIO_DEVICE_ATTR(DAC_C, S_IRUGO | S_IWUSR, adt7316_show_DAC_C, +static IIO_DEVICE_ATTR(DAC_C, 0644, adt7316_show_DAC_C, adt7316_store_DAC_C, 0); static ssize_t adt7316_show_DAC_D(struct device *dev, @@ -1572,7 +1572,7 @@ static ssize_t adt7316_store_DAC_D(struct device *dev, return adt7316_store_DAC(chip, 3, buf, len); } -static IIO_DEVICE_ATTR(DAC_D, S_IRUGO | S_IWUSR, adt7316_show_DAC_D, +static IIO_DEVICE_ATTR(DAC_D, 0644, adt7316_show_DAC_D, adt7316_store_DAC_D, 0); static ssize_t adt7316_show_device_id(struct device *dev, @@ -1591,7 +1591,7 @@ static ssize_t adt7316_show_device_id(struct device *dev, return sprintf(buf, "%d\n", id); } -static IIO_DEVICE_ATTR(device_id, S_IRUGO, adt7316_show_device_id, NULL, 0); +static IIO_DEVICE_ATTR(device_id, 0444, adt7316_show_device_id, NULL, 0); static ssize_t adt7316_show_manufactorer_id(struct device *dev, struct device_attribute *attr, @@ -1609,7 +1609,7 @@ static ssize_t adt7316_show_manufactorer_id(struct device *dev, return sprintf(buf, "%d\n", id); } -static IIO_DEVICE_ATTR(manufactorer_id, S_IRUGO, +static IIO_DEVICE_ATTR(manufactorer_id, 0444, adt7316_show_manufactorer_id, NULL, 0); static ssize_t adt7316_show_device_rev(struct device *dev, @@ -1628,7 +1628,7 @@ static ssize_t adt7316_show_device_rev(struct device *dev, return sprintf(buf, "%d\n", rev); } -static IIO_DEVICE_ATTR(device_rev, S_IRUGO, adt7316_show_device_rev, NULL, 0); +static IIO_DEVICE_ATTR(device_rev, 0444, adt7316_show_device_rev, NULL, 0); static ssize_t adt7316_show_bus_type(struct device *dev, struct device_attribute *attr, @@ -1649,7 +1649,7 @@ static ssize_t adt7316_show_bus_type(struct device *dev, return sprintf(buf, "i2c\n"); } -static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0); +static IIO_DEVICE_ATTR(bus_type, 0444, adt7316_show_bus_type, NULL, 0); static struct attribute *adt7316_attributes[] = { &iio_dev_attr_all_modes.dev_attr.attr, @@ -1972,61 +1972,61 @@ static ssize_t adt7316_set_int_enabled(struct device *dev, } static IIO_DEVICE_ATTR(int_mask, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_int_mask, adt7316_set_int_mask, 0); static IIO_DEVICE_ATTR(in_temp_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_IN_TEMP_HIGH); static IIO_DEVICE_ATTR(in_temp_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_IN_TEMP_LOW); static IIO_DEVICE_ATTR(ex_temp_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_EX_TEMP_HIGH); static IIO_DEVICE_ATTR(ex_temp_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_EX_TEMP_LOW); /* NASTY duplication to be fixed */ static IIO_DEVICE_ATTR(ex_temp_ain1_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_EX_TEMP_HIGH); static IIO_DEVICE_ATTR(ex_temp_ain1_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7316_EX_TEMP_LOW); static IIO_DEVICE_ATTR(ain2_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN2_HIGH); static IIO_DEVICE_ATTR(ain2_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN2_LOW); static IIO_DEVICE_ATTR(ain3_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN3_HIGH); static IIO_DEVICE_ATTR(ain3_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN3_LOW); static IIO_DEVICE_ATTR(ain4_high_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN4_HIGH); static IIO_DEVICE_ATTR(ain4_low_value, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_ad_bound, adt7316_set_ad_bound, ADT7516_AIN4_LOW); static IIO_DEVICE_ATTR(int_enabled, - S_IRUGO | S_IWUSR, + 0644, adt7316_show_int_enabled, adt7316_set_int_enabled, 0); -- cgit v1.2.3 From 2eaf14277b02fb400b9a5baee5a7cb079cb6e63d Mon Sep 17 00:00:00 2001 From: Artur Lorincz Date: Sat, 4 Feb 2017 20:11:34 +0100 Subject: iio: adc: ad7192: fixed symbolic permission references 'S_IRUGO | S_IWUSR' Replaced the symbolic permission references S_IRUGO and S_IWUSR with their octal counterparts. Signed-off-by: Artur Lorincz Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7192.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 1fb68c01abd5..4fc8588f0392 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -342,9 +342,9 @@ ad7192_show_scale_available(struct device *dev, static IIO_DEVICE_ATTR_NAMED(in_v_m_v_scale_available, in_voltage-voltage_scale_available, - S_IRUGO, ad7192_show_scale_available, NULL, 0); + 0444, ad7192_show_scale_available, NULL, 0); -static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, +static IIO_DEVICE_ATTR(in_voltage_scale_available, 0444, ad7192_show_scale_available, NULL, 0); static ssize_t ad7192_show_ac_excitation(struct device *dev, @@ -412,11 +412,11 @@ static ssize_t ad7192_set(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(bridge_switch_en, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(bridge_switch_en, 0644, ad7192_show_bridge_switch, ad7192_set, AD7192_REG_GPOCON); -static IIO_DEVICE_ATTR(ac_excitation_en, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(ac_excitation_en, 0644, ad7192_show_ac_excitation, ad7192_set, AD7192_REG_MODE); -- cgit v1.2.3 From 5247dd46cf1c2e3300545ea102b866a46aaddbc3 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 4 Feb 2017 02:22:50 -0800 Subject: devicetree: add documentation for MAX30102 oximeter Acked-by: Rob Herring Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/health/max30102.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/health/max30102.txt diff --git a/Documentation/devicetree/bindings/iio/health/max30102.txt b/Documentation/devicetree/bindings/iio/health/max30102.txt new file mode 100644 index 000000000000..c695e7cbeefb --- /dev/null +++ b/Documentation/devicetree/bindings/iio/health/max30102.txt @@ -0,0 +1,30 @@ +Maxim MAX30102 heart rate and pulse oximeter sensor + +* https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf + +Required properties: + - compatible: must be "maxim,max30102" + - reg: the I2C address of the sensor + - interrupt-parent: should be the phandle for the interrupt controller + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - maxim,red-led-current-microamp: configuration for RED LED current + - maxim,ir-led-current-microamp: configuration for IR LED current + + Note that each step is approximately 200 microamps, ranging from 0 uA to + 50800 uA. + +Example: + +max30100@57 { + compatible = "maxim,max30102"; + reg = <0x57>; + maxim,red-led-current-microamp = <7000>; + maxim,ir-led-current-microamp = <7000>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; -- cgit v1.2.3 From b3c590ce14b1f30f4535e4f4ab9f3b9a2c968aaf Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Sat, 4 Feb 2017 02:22:51 -0800 Subject: iio: health: add MAX30102 oximeter driver support MAX30102 is an heart rate and pulse oximeter sensor that works using two LEDS of different wavelengths, and detecting the light reflected back. This patchset adds support for both IR and RED LED channels which can be processed in userspace to determine heart rate and blood oxygen levels. The MAX30102 part isn't completely register and functional compatible with the existing MAX30100 driver. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/health/Kconfig | 13 ++ drivers/iio/health/Makefile | 1 + drivers/iio/health/max30102.c | 485 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 499 insertions(+) create mode 100644 drivers/iio/health/max30102.c diff --git a/drivers/iio/health/Kconfig b/drivers/iio/health/Kconfig index c5f004a8e447..a2ecb4c94c2a 100644 --- a/drivers/iio/health/Kconfig +++ b/drivers/iio/health/Kconfig @@ -46,6 +46,19 @@ config MAX30100 To compile this driver as a module, choose M here: the module will be called max30100. +config MAX30102 + tristate "MAX30102 heart rate and pulse oximeter sensor" + depends on I2C + select REGMAP_I2C + select IIO_BUFFER + select IIO_KFIFO_BUF + help + Say Y here to build I2C interface support for the Maxim + MAX30102 heart rate, and pulse oximeter sensor. + + To compile this driver as a module, choose M here: the + module will be called max30102. + endmenu endmenu diff --git a/drivers/iio/health/Makefile b/drivers/iio/health/Makefile index 9955a2ae8df1..3558f9d64954 100644 --- a/drivers/iio/health/Makefile +++ b/drivers/iio/health/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_AFE4403) += afe4403.o obj-$(CONFIG_AFE4404) += afe4404.o obj-$(CONFIG_MAX30100) += max30100.o +obj-$(CONFIG_MAX30102) += max30102.o diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c new file mode 100644 index 000000000000..377518c15552 --- /dev/null +++ b/drivers/iio/health/max30102.c @@ -0,0 +1,485 @@ +/* + * max30102.c - Support for MAX30102 heart rate and pulse oximeter sensor + * + * Copyright (C) 2017 Matt Ranostay + * + * 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. + * + * TODO: proximity power saving feature + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX30102_REGMAP_NAME "max30102_regmap" +#define MAX30102_DRV_NAME "max30102" + +#define MAX30102_REG_INT_STATUS 0x00 +#define MAX30102_REG_INT_STATUS_PWR_RDY BIT(0) +#define MAX30102_REG_INT_STATUS_PROX_INT BIT(4) +#define MAX30102_REG_INT_STATUS_ALC_OVF BIT(5) +#define MAX30102_REG_INT_STATUS_PPG_RDY BIT(6) +#define MAX30102_REG_INT_STATUS_FIFO_RDY BIT(7) + +#define MAX30102_REG_INT_ENABLE 0x02 +#define MAX30102_REG_INT_ENABLE_PROX_INT_EN BIT(4) +#define MAX30102_REG_INT_ENABLE_ALC_OVF_EN BIT(5) +#define MAX30102_REG_INT_ENABLE_PPG_EN BIT(6) +#define MAX30102_REG_INT_ENABLE_FIFO_EN BIT(7) +#define MAX30102_REG_INT_ENABLE_MASK 0xf0 +#define MAX30102_REG_INT_ENABLE_MASK_SHIFT 4 + +#define MAX30102_REG_FIFO_WR_PTR 0x04 +#define MAX30102_REG_FIFO_OVR_CTR 0x05 +#define MAX30102_REG_FIFO_RD_PTR 0x06 +#define MAX30102_REG_FIFO_DATA 0x07 +#define MAX30102_REG_FIFO_DATA_ENTRY_LEN 6 + +#define MAX30102_REG_FIFO_CONFIG 0x08 +#define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES BIT(1) +#define MAX30102_REG_FIFO_CONFIG_AVG_SHIFT 5 +#define MAX30102_REG_FIFO_CONFIG_AFULL BIT(0) + +#define MAX30102_REG_MODE_CONFIG 0x09 +#define MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN BIT(0) +#define MAX30102_REG_MODE_CONFIG_MODE_HR_EN BIT(1) +#define MAX30102_REG_MODE_CONFIG_MODE_MASK 0x03 +#define MAX30102_REG_MODE_CONFIG_PWR BIT(7) + +#define MAX30102_REG_SPO2_CONFIG 0x0a +#define MAX30102_REG_SPO2_CONFIG_PULSE_411_US 0x03 +#define MAX30102_REG_SPO2_CONFIG_SR_400HZ 0x03 +#define MAX30102_REG_SPO2_CONFIG_SR_MASK 0x07 +#define MAX30102_REG_SPO2_CONFIG_SR_MASK_SHIFT 2 +#define MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS BIT(0) +#define MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT 5 + +#define MAX30102_REG_RED_LED_CONFIG 0x0c +#define MAX30102_REG_IR_LED_CONFIG 0x0d + +#define MAX30102_REG_TEMP_CONFIG 0x21 +#define MAX30102_REG_TEMP_CONFIG_TEMP_EN BIT(0) + +#define MAX30102_REG_TEMP_INTEGER 0x1f +#define MAX30102_REG_TEMP_FRACTION 0x20 + +struct max30102_data { + struct i2c_client *client; + struct iio_dev *indio_dev; + struct mutex lock; + struct regmap *regmap; + + u8 buffer[8]; + __be32 processed_buffer[2]; /* 2 x 18-bit (padded to 32-bits) */ +}; + +static const struct regmap_config max30102_regmap_config = { + .name = MAX30102_REGMAP_NAME, + + .reg_bits = 8, + .val_bits = 8, +}; + +static const unsigned long max30102_scan_masks[] = {0x3, 0}; + +static const struct iio_chan_spec max30102_channels[] = { + { + .type = IIO_INTENSITY, + .channel2 = IIO_MOD_LIGHT_RED, + .modified = 1, + + .scan_index = 0, + .scan_type = { + .sign = 'u', + .shift = 8, + .realbits = 18, + .storagebits = 32, + .endianness = IIO_BE, + }, + }, + { + .type = IIO_INTENSITY, + .channel2 = IIO_MOD_LIGHT_IR, + .modified = 1, + + .scan_index = 1, + .scan_type = { + .sign = 'u', + .shift = 8, + .realbits = 18, + .storagebits = 32, + .endianness = IIO_BE, + }, + }, + { + .type = IIO_TEMP, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = -1, + }, +}; + +static int max30102_set_powermode(struct max30102_data *data, bool state) +{ + return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG, + MAX30102_REG_MODE_CONFIG_PWR, + state ? 0 : MAX30102_REG_MODE_CONFIG_PWR); +} + +static int max30102_buffer_postenable(struct iio_dev *indio_dev) +{ + struct max30102_data *data = iio_priv(indio_dev); + + return max30102_set_powermode(data, true); +} + +static int max30102_buffer_predisable(struct iio_dev *indio_dev) +{ + struct max30102_data *data = iio_priv(indio_dev); + + return max30102_set_powermode(data, false); +} + +static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = { + .postenable = max30102_buffer_postenable, + .predisable = max30102_buffer_predisable, +}; + +static inline int max30102_fifo_count(struct max30102_data *data) +{ + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, MAX30102_REG_INT_STATUS, &val); + if (ret) + return ret; + + /* FIFO has one sample slot left */ + if (val & MAX30102_REG_INT_STATUS_FIFO_RDY) + return 1; + + return 0; +} + +static int max30102_read_measurement(struct max30102_data *data) +{ + int ret; + u8 *buffer = (u8 *) &data->buffer; + + ret = i2c_smbus_read_i2c_block_data(data->client, + MAX30102_REG_FIFO_DATA, + MAX30102_REG_FIFO_DATA_ENTRY_LEN, + buffer); + + memcpy(&data->processed_buffer[0], &buffer[0], 3); + memcpy(&data->processed_buffer[1], &buffer[3], 3); + + return (ret == MAX30102_REG_FIFO_DATA_ENTRY_LEN) ? 0 : -EINVAL; +} + +static irqreturn_t max30102_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct max30102_data *data = iio_priv(indio_dev); + int ret, cnt = 0; + + mutex_lock(&data->lock); + + while (cnt || (cnt = max30102_fifo_count(data)) > 0) { + ret = max30102_read_measurement(data); + if (ret) + break; + + iio_push_to_buffers(data->indio_dev, data->processed_buffer); + cnt--; + } + + mutex_unlock(&data->lock); + + return IRQ_HANDLED; +} + +static int max30102_get_current_idx(unsigned int val, int *reg) +{ + /* each step is 0.200 mA */ + *reg = val / 200; + + return *reg > 0xff ? -EINVAL : 0; +} + +static int max30102_led_init(struct max30102_data *data) +{ + struct device *dev = &data->client->dev; + struct device_node *np = dev->of_node; + unsigned int val; + int reg, ret; + + ret = of_property_read_u32(np, "maxim,red-led-current-microamp", &val); + if (ret) { + dev_info(dev, "no red-led-current-microamp set\n"); + + /* Default to 7 mA RED LED */ + val = 7000; + } + + ret = max30102_get_current_idx(val, ®); + if (ret) { + dev_err(dev, "invalid RED LED current setting %d\n", val); + return ret; + } + + ret = regmap_write(data->regmap, MAX30102_REG_RED_LED_CONFIG, reg); + if (ret) + return ret; + + ret = of_property_read_u32(np, "maxim,ir-led-current-microamp", &val); + if (ret) { + dev_info(dev, "no ir-led-current-microamp set\n"); + + /* Default to 7 mA IR LED */ + val = 7000; + } + + ret = max30102_get_current_idx(val, ®); + if (ret) { + dev_err(dev, "invalid IR LED current setting %d", val); + return ret; + } + + return regmap_write(data->regmap, MAX30102_REG_IR_LED_CONFIG, reg); +} + +static int max30102_chip_init(struct max30102_data *data) +{ + int ret; + + /* setup LED current settings */ + ret = max30102_led_init(data); + if (ret) + return ret; + + /* enable 18-bit HR + SPO2 readings at 400Hz */ + ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG, + (MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS + << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) | + (MAX30102_REG_SPO2_CONFIG_SR_400HZ + << MAX30102_REG_SPO2_CONFIG_SR_MASK_SHIFT) | + MAX30102_REG_SPO2_CONFIG_PULSE_411_US); + if (ret) + return ret; + + /* enable SPO2 mode */ + ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG, + MAX30102_REG_MODE_CONFIG_MODE_MASK, + MAX30102_REG_MODE_CONFIG_MODE_HR_EN | + MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN); + if (ret) + return ret; + + /* average 4 samples + generate FIFO interrupt */ + ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG, + (MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES + << MAX30102_REG_FIFO_CONFIG_AVG_SHIFT) | + MAX30102_REG_FIFO_CONFIG_AFULL); + if (ret) + return ret; + + /* enable FIFO interrupt */ + return regmap_update_bits(data->regmap, MAX30102_REG_INT_ENABLE, + MAX30102_REG_INT_ENABLE_MASK, + MAX30102_REG_INT_ENABLE_FIFO_EN); +} + +static int max30102_read_temp(struct max30102_data *data, int *val) +{ + int ret; + unsigned int reg; + + ret = regmap_read(data->regmap, MAX30102_REG_TEMP_INTEGER, ®); + if (ret < 0) + return ret; + *val = reg << 4; + + ret = regmap_read(data->regmap, MAX30102_REG_TEMP_FRACTION, ®); + if (ret < 0) + return ret; + + *val |= reg & 0xf; + *val = sign_extend32(*val, 11); + + return 0; +} + +static int max30102_get_temp(struct max30102_data *data, int *val) +{ + int ret; + + /* start acquisition */ + ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG, + MAX30102_REG_TEMP_CONFIG_TEMP_EN, + MAX30102_REG_TEMP_CONFIG_TEMP_EN); + if (ret) + return ret; + + msleep(35); + + return max30102_read_temp(data, val); +} + +static int max30102_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max30102_data *data = iio_priv(indio_dev); + int ret = -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * Temperature reading can only be acquired while engine + * is running + */ + mutex_lock(&indio_dev->mlock); + + if (!iio_buffer_enabled(indio_dev)) + ret = -EBUSY; + else { + ret = max30102_get_temp(data, val); + if (!ret) + ret = IIO_VAL_INT; + } + + mutex_unlock(&indio_dev->mlock); + break; + case IIO_CHAN_INFO_SCALE: + *val = 1; /* 0.0625 */ + *val2 = 16; + ret = IIO_VAL_FRACTIONAL; + break; + } + + return ret; +} + +static const struct iio_info max30102_info = { + .driver_module = THIS_MODULE, + .read_raw = max30102_read_raw, +}; + +static int max30102_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max30102_data *data; + struct iio_buffer *buffer; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + buffer = devm_iio_kfifo_allocate(&client->dev); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + + indio_dev->name = MAX30102_DRV_NAME; + indio_dev->channels = max30102_channels; + indio_dev->info = &max30102_info; + indio_dev->num_channels = ARRAY_SIZE(max30102_channels); + indio_dev->available_scan_masks = max30102_scan_masks; + indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); + indio_dev->setup_ops = &max30102_buffer_setup_ops; + + data = iio_priv(indio_dev); + data->indio_dev = indio_dev; + data->client = client; + + mutex_init(&data->lock); + i2c_set_clientdata(client, indio_dev); + + data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(&client->dev, "regmap initialization failed.\n"); + return PTR_ERR(data->regmap); + } + max30102_set_powermode(data, false); + + ret = max30102_chip_init(data); + if (ret) + return ret; + + if (client->irq <= 0) { + dev_err(&client->dev, "no valid irq defined\n"); + return -EINVAL; + } + + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, max30102_interrupt_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max30102_irq", indio_dev); + if (ret) { + dev_err(&client->dev, "request irq (%d) failed\n", client->irq); + return ret; + } + + return iio_device_register(indio_dev); +} + +static int max30102_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct max30102_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + max30102_set_powermode(data, false); + + return 0; +} + +static const struct i2c_device_id max30102_id[] = { + { "max30102", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, max30102_id); + +static const struct of_device_id max30102_dt_ids[] = { + { .compatible = "maxim,max30102" }, + { } +}; +MODULE_DEVICE_TABLE(of, max30102_dt_ids); + +static struct i2c_driver max30102_driver = { + .driver = { + .name = MAX30102_DRV_NAME, + .of_match_table = of_match_ptr(max30102_dt_ids), + }, + .probe = max30102_probe, + .remove = max30102_remove, + .id_table = max30102_id, +}; +module_i2c_driver(max30102_driver); + +MODULE_AUTHOR("Matt Ranostay "); +MODULE_DESCRIPTION("MAX30102 heart rate and pulse oximeter sensor"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7c5bc7e87cc43a45fd34987d0f48637ad4881eb0 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Mon, 23 Jan 2017 21:25:16 +0530 Subject: iio:temperature:tmp007: Add irq and threshold events support This patch adds ALERT irq and limit threshold events support for TI TMP007 - 16 bit IR thermopile sensor with integrated math engine. Following threshold events are supported: 1. TObj high limit 2. TObj low limit 3. TDie high limit 4. TDie low limit Signed-off-by: Manivannan Sadhasivam Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/tmp007.c | 277 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 265 insertions(+), 12 deletions(-) diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index f04d0d1f6ac8..0615324d054c 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -11,9 +11,10 @@ * * (7-bit I2C slave address (0x40 - 0x47), changeable via ADR pins) * - * Note: This driver assumes that the sensor has been calibrated beforehand - * - * TODO: ALERT irq, limit threshold events + * Note: + * 1. This driver assumes that the sensor has been calibrated beforehand + * 2. Limit threshold events are enabled at the start + * 3. Operating mode: INT * */ @@ -24,25 +25,38 @@ #include #include #include +#include +#include #include #include +#include #define TMP007_TDIE 0x01 #define TMP007_CONFIG 0x02 #define TMP007_TOBJECT 0x03 #define TMP007_STATUS 0x04 #define TMP007_STATUS_MASK 0x05 +#define TMP007_TOBJ_HIGH_LIMIT 0x06 +#define TMP007_TOBJ_LOW_LIMIT 0x07 +#define TMP007_TDIE_HIGH_LIMIT 0x08 +#define TMP007_TDIE_LOW_LIMIT 0x09 #define TMP007_MANUFACTURER_ID 0x1e #define TMP007_DEVICE_ID 0x1f #define TMP007_CONFIG_CONV_EN BIT(12) -#define TMP007_CONFIG_COMP_EN BIT(5) #define TMP007_CONFIG_TC_EN BIT(6) #define TMP007_CONFIG_CR_MASK GENMASK(11, 9) +#define TMP007_CONFIG_ALERT_EN BIT(8) #define TMP007_CONFIG_CR_SHIFT 9 +/* Status register flags */ +#define TMP007_STATUS_ALERT BIT(15) #define TMP007_STATUS_CONV_READY BIT(14) +#define TMP007_STATUS_OHF BIT(13) +#define TMP007_STATUS_OLF BIT(12) +#define TMP007_STATUS_LHF BIT(11) +#define TMP007_STATUS_LLF BIT(10) #define TMP007_STATUS_DATA_VALID BIT(9) #define TMP007_MANUFACTURER_MAGIC 0x5449 @@ -52,7 +66,9 @@ struct tmp007_data { struct i2c_client *client; + struct mutex lock; u16 config; + u16 status_mask; }; static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0}, @@ -156,6 +172,188 @@ static int tmp007_write_raw(struct iio_dev *indio_dev, return -EINVAL; } +static irqreturn_t tmp007_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tmp007_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS); + if ((ret < 0) || !(ret & (TMP007_STATUS_OHF | TMP007_STATUS_OLF | + TMP007_STATUS_LHF | TMP007_STATUS_LLF))) + return IRQ_NONE; + + if (ret & TMP007_STATUS_OHF) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_MOD_TEMP_OBJECT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + + if (ret & TMP007_STATUS_OLF) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_MOD_TEMP_OBJECT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + + if (ret & TMP007_STATUS_LHF) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_MOD_TEMP_AMBIENT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + + if (ret & TMP007_STATUS_LLF) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_TEMP, 0, + IIO_MOD_TEMP_AMBIENT, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + + return IRQ_HANDLED; +} + +static int tmp007_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct tmp007_data *data = iio_priv(indio_dev); + unsigned int status_mask; + int ret; + + switch (chan->channel2) { + case IIO_MOD_TEMP_AMBIENT: + if (dir == IIO_EV_DIR_RISING) + status_mask = TMP007_STATUS_LHF; + else + status_mask = TMP007_STATUS_LLF; + break; + case IIO_MOD_TEMP_OBJECT: + if (dir == IIO_EV_DIR_RISING) + status_mask = TMP007_STATUS_OHF; + else + status_mask = TMP007_STATUS_OLF; + break; + default: + return -EINVAL; + } + + mutex_lock(&data->lock); + ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + if (state) + ret |= status_mask; + else + ret &= ~status_mask; + + return i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, + data->status_mask = ret); +} + +static int tmp007_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct tmp007_data *data = iio_priv(indio_dev); + unsigned int mask; + + switch (chan->channel2) { + case IIO_MOD_TEMP_AMBIENT: + if (dir == IIO_EV_DIR_RISING) + mask = TMP007_STATUS_LHF; + else + mask = TMP007_STATUS_LLF; + break; + case IIO_MOD_TEMP_OBJECT: + if (dir == IIO_EV_DIR_RISING) + mask = TMP007_STATUS_OHF; + else + mask = TMP007_STATUS_OLF; + break; + default: + return -EINVAL; + } + + return !!(data->status_mask & mask); +} + +static int tmp007_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + struct tmp007_data *data = iio_priv(indio_dev); + int ret; + u8 reg; + + switch (chan->channel2) { + case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.5 degree Celsius */ + if (dir == IIO_EV_DIR_RISING) + reg = TMP007_TDIE_HIGH_LIMIT; + else + reg = TMP007_TDIE_LOW_LIMIT; + break; + case IIO_MOD_TEMP_OBJECT: + if (dir == IIO_EV_DIR_RISING) + reg = TMP007_TOBJ_HIGH_LIMIT; + else + reg = TMP007_TOBJ_LOW_LIMIT; + break; + default: + return -EINVAL; + } + + ret = i2c_smbus_read_word_swapped(data->client, reg); + if (ret < 0) + return ret; + + /* Shift length 7 bits = 6(15:6) + 1(0.5 LSB) */ + *val = sign_extend32(ret, 15) >> 7; + + return IIO_VAL_INT; +} + +static int tmp007_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + struct tmp007_data *data = iio_priv(indio_dev); + u8 reg; + + switch (chan->channel2) { + case IIO_MOD_TEMP_AMBIENT: + if (dir == IIO_EV_DIR_RISING) + reg = TMP007_TDIE_HIGH_LIMIT; + else + reg = TMP007_TDIE_LOW_LIMIT; + break; + case IIO_MOD_TEMP_OBJECT: + if (dir == IIO_EV_DIR_RISING) + reg = TMP007_TOBJ_HIGH_LIMIT; + else + reg = TMP007_TOBJ_LOW_LIMIT; + break; + default: + return -EINVAL; + } + + /* Full scale threshold value is +/- 256 degree Celsius */ + if (val < -256 || val > 255) + return -EINVAL; + + /* Shift length 7 bits = 6(15:6) + 1(0.5 LSB) */ + return i2c_smbus_write_word_swapped(data->client, reg, (val << 7)); +} + static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25"); static struct attribute *tmp007_attributes[] = { @@ -167,6 +365,36 @@ static const struct attribute_group tmp007_attribute_group = { .attrs = tmp007_attributes, }; +static const struct iio_event_spec tmp007_obj_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_event_spec tmp007_die_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + static const struct iio_chan_spec tmp007_channels[] = { { .type = IIO_TEMP, @@ -175,6 +403,8 @@ static const struct iio_chan_spec tmp007_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = tmp007_die_event, + .num_event_specs = ARRAY_SIZE(tmp007_die_event), }, { .type = IIO_TEMP, @@ -183,12 +413,18 @@ static const struct iio_chan_spec tmp007_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = tmp007_obj_event, + .num_event_specs = ARRAY_SIZE(tmp007_obj_event), } }; static const struct iio_info tmp007_info = { .read_raw = tmp007_read_raw, .write_raw = tmp007_write_raw, + .read_event_config = tmp007_read_event_config, + .write_event_config = tmp007_write_event_config, + .read_event_value = tmp007_read_thresh, + .write_event_value = tmp007_write_thresh, .attrs = &tmp007_attribute_group, .driver_module = THIS_MODULE, }; @@ -214,7 +450,6 @@ static int tmp007_probe(struct i2c_client *client, struct tmp007_data *data; struct iio_dev *indio_dev; int ret; - u16 status; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) return -EOPNOTSUPP; @@ -231,6 +466,7 @@ static int tmp007_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; + mutex_init(&data->lock); indio_dev->dev.parent = &client->dev; indio_dev->name = "tmp007"; @@ -243,7 +479,7 @@ static int tmp007_probe(struct i2c_client *client, /* * Set Configuration register: * 1. Conversion ON - * 2. Comparator mode + * 2. ALERT enable * 3. Transient correction enable */ @@ -252,7 +488,7 @@ static int tmp007_probe(struct i2c_client *client, return ret; data->config = ret; - data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_COMP_EN | TMP007_CONFIG_TC_EN); + data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_ALERT_EN | TMP007_CONFIG_TC_EN); ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG, data->config); @@ -260,22 +496,39 @@ static int tmp007_probe(struct i2c_client *client, return ret; /* + * Only the following flags can activate ALERT pin. Data conversion/validity flags + * flags can still be polled for getting temperature data + * * Set Status Mask register: - * 1. Conversion ready enable - * 2. Data valid enable + * 1. Object temperature high limit enable + * 2. Object temperature low limit enable + * 3. TDIE temperature high limit enable + * 4. TDIE temperature low limit enable */ ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK); if (ret < 0) goto error_powerdown; - status = ret; - status |= (TMP007_STATUS_CONV_READY | TMP007_STATUS_DATA_VALID); + data->status_mask = ret; + data->status_mask |= (TMP007_STATUS_OHF | TMP007_STATUS_OLF + | TMP007_STATUS_LHF | TMP007_STATUS_LLF); - ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, status); + ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, data->status_mask); if (ret < 0) goto error_powerdown; + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, tmp007_interrupt_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + tmp007_id->name, indio_dev); + if (ret) { + dev_err(&client->dev, "irq request error %d\n", -ret); + goto error_powerdown; + } + } + return iio_device_register(indio_dev); error_powerdown: -- cgit v1.2.3 From 92196732bebf3f15962e747e09dbac7590403ec2 Mon Sep 17 00:00:00 2001 From: Derek Robson Date: Fri, 10 Feb 2017 20:00:08 +1300 Subject: Staging: iio: meter: meter.h - style fix Changed file permissions to octal. Found with checkpatch. Signed-off-by: Derek Robson Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/meter.h | 60 +++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h index dfba510f29be..0e37f23853f1 100644 --- a/drivers/staging/iio/meter/meter.h +++ b/drivers/staging/iio/meter/meter.h @@ -81,94 +81,94 @@ IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr) #define IIO_DEV_ATTR_CURRENT_A(_show, _addr) \ - IIO_DEVICE_ATTR(current_a, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(current_a, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CURRENT_B(_show, _addr) \ - IIO_DEVICE_ATTR(current_b, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(current_b, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CURRENT_C(_show, _addr) \ - IIO_DEVICE_ATTR(current_c, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(current_c, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_VOLT_A(_show, _addr) \ - IIO_DEVICE_ATTR(volt_a, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(volt_a, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_VOLT_B(_show, _addr) \ - IIO_DEVICE_ATTR(volt_b, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(volt_b, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_VOLT_C(_show, _addr) \ - IIO_DEVICE_ATTR(volt_c, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(volt_c, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_AENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(aenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(aenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_LENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(lenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_RAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(raenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(raenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_LAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(laenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(laenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_VAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(vaenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(vaenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_LVAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lvaenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(lvaenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_RVAENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(rvaenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(rvaenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_LVARENERGY(_show, _addr) \ - IIO_DEVICE_ATTR(lvarenergy, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(lvarenergy, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CHKSUM(_show, _addr) \ - IIO_DEVICE_ATTR(chksum, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(chksum, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_ANGLE0(_show, _addr) \ - IIO_DEVICE_ATTR(angle0, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(angle0, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_ANGLE1(_show, _addr) \ - IIO_DEVICE_ATTR(angle1, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(angle1, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_ANGLE2(_show, _addr) \ - IIO_DEVICE_ATTR(angle2, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(angle2, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_AWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(awatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(awatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_BWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(bwatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(bwatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(cwatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(cwatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_AFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(afwatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(afwatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_BFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(bfwatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(bfwatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CFWATTHR(_show, _addr) \ - IIO_DEVICE_ATTR(cfwatthr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(cfwatthr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_AVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(avarhr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(avarhr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_BVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(bvarhr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(bvarhr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CVARHR(_show, _addr) \ - IIO_DEVICE_ATTR(cvarhr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(cvarhr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_AVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(avahr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(avahr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_BVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(bvahr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(bvahr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_CVAHR(_show, _addr) \ - IIO_DEVICE_ATTR(cvahr, S_IRUGO, _show, NULL, _addr) + IIO_DEVICE_ATTR(cvahr, 0444, _show, NULL, _addr) #define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr) -- cgit v1.2.3 From 55bf851b4ad76778ce4e591dbb79006d7107cf3d Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 8 Feb 2017 20:54:25 -0500 Subject: staging: iio: isl29028: change mdelay() to msleep() This driver in some cases can busy wait for upwards of 100 ms. Since the kernel at this point is not running in atomic context, and is running in process context, we can safely use msleep() instead. This patch changes the two occurrences of mdelay() to msleep(). Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index 6bb6d37cc7d1..8dc24c9478e8 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -121,7 +121,7 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip) return ret; /* Wait for conversion to be complete for first sample */ - mdelay(DIV_ROUND_UP(1000, chip->prox_sampling)); + msleep(DIV_ROUND_UP(1000, chip->prox_sampling)); return 0; } @@ -192,7 +192,7 @@ static int isl29028_set_als_ir_mode(struct isl29028_chip *chip, return ret; /* Need to wait for conversion time if ALS/IR mode enabled */ - mdelay(ISL29028_CONV_TIME_MS); + msleep(ISL29028_CONV_TIME_MS); chip->als_ir_mode = mode; -- cgit v1.2.3 From 45e2852b8b27b92fb0f1ad9c94a8edd65c5a61c8 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 8 Feb 2017 20:54:26 -0500 Subject: staging: iio: isl29028: fix incorrect sleep time when taking initial proximity reading When proximity is enabled in isl29028_enable_proximity(), the function msleep() is called with the sampling frequency, which is not correct. This patch changes the code to sleep the specified amount of time listed in the datasheet instead. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29028.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index 8dc24c9478e8..177dceda0820 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -63,6 +63,9 @@ #define ISL29028_POWER_OFF_DELAY_MS 2000 +static const unsigned int isl29028_prox_sleep_time[] = {800, 400, 200, 100, 75, + 50, 12, 0}; + enum isl29028_als_ir_mode { ISL29028_MODE_NONE = 0, ISL29028_MODE_ALS, @@ -78,22 +81,29 @@ struct isl29028_chip { enum isl29028_als_ir_mode als_ir_mode; }; -static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, - unsigned int sampling) +static int isl29028_find_prox_sleep_time_index(int sampling) { - struct device *dev = regmap_get_device(chip->regmap); - static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0}; unsigned int period = DIV_ROUND_UP(1000, sampling); - int sel, ret; + int i; - for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) { - if (period >= prox_period[sel]) + for (i = 0; i < ARRAY_SIZE(isl29028_prox_sleep_time); ++i) { + if (period >= isl29028_prox_sleep_time[i]) break; } + return i; +} + +static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, + unsigned int sampling) +{ + struct device *dev = regmap_get_device(chip->regmap); + int sleep_index, ret; + + sleep_index = isl29028_find_prox_sleep_time_index(sampling); ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, ISL29028_CONF_PROX_SLP_MASK, - sel << ISL29028_CONF_PROX_SLP_SH); + sleep_index << ISL29028_CONF_PROX_SLP_SH); if (ret < 0) { dev_err(dev, "%s(): Error %d setting the proximity sampling\n", @@ -108,7 +118,7 @@ static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, static int isl29028_enable_proximity(struct isl29028_chip *chip) { - int ret; + int sleep_index, ret; ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling); if (ret < 0) @@ -121,7 +131,8 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip) return ret; /* Wait for conversion to be complete for first sample */ - msleep(DIV_ROUND_UP(1000, chip->prox_sampling)); + sleep_index = isl29028_find_prox_sleep_time_index(chip->prox_sampling); + msleep(isl29028_prox_sleep_time[sleep_index]); return 0; } -- cgit v1.2.3 From 0b59c388f89caeba22e205f7c6c985f4958323e4 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 8 Feb 2017 20:54:28 -0500 Subject: staging: iio: isl29028: use the runtime power management for system sleep With the introduction of runtime power management in commit 2db5054ac28d ("staging: iio: isl29028: add runtime power management support"), the system could go to sleep and turn off the device without notifying the runtime power management code. This patch changes the system suspend and resume to go through the runtime power management. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29028.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index 177dceda0820..a8f0c6c2dd95 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -656,7 +656,8 @@ static int __maybe_unused isl29028_resume(struct device *dev) } static const struct dev_pm_ops isl29028_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(isl29028_suspend, isl29028_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL) }; -- cgit v1.2.3 From bcbbd0fa82de02ea47fbdaac4f1f42c819392884 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 8 Feb 2017 20:54:29 -0500 Subject: staging: iio: isl29028: add copyright Add Brian Masney's copyright to the header for the several rounds of staging cleanups that has been done to this driver. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29028.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index a8f0c6c2dd95..5375e7a81205 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -3,6 +3,7 @@ * ISL29028 is Concurrent Ambient Light and Proximity Sensor * * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2017 Brian Masney * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, -- cgit v1.2.3 From a18ac95442c29caa6e1e6b7e3768de95aa19e79f Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 8 Feb 2017 20:54:30 -0500 Subject: iio: Documentation: add ABI documentation for in_proximity_sampling_frequency_available Add entry for the in_proximity_sampling_frequency_available sysfs entry to the existing sampling_frequency_available ABI documentation. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 530809ccfacf..1ce46035ecab 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -55,6 +55,7 @@ Description: then it is to be found in the base device directory. What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency_available +What: /sys/bus/iio/devices/iio:deviceX/in_proximity_sampling_frequency_available What: /sys/.../iio:deviceX/buffer/sampling_frequency_available What: /sys/bus/iio/devices/triggerX/sampling_frequency_available KernelVersion: 2.6.35 -- cgit v1.2.3 From 7527a6ed033dc23048e21e5e8ddee681d204dd1e Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 8 Feb 2017 09:01:35 -0500 Subject: Documentation: iio: Fix KernelVersion in counter sysfs ABI documentation The IIO counter driver support did not appear in the 4.9 version of the Linux kernel. This patch fixes the KernelVersion lines of the relevant IIO counter sysfs ABI documentation. Fixes: 1a8f324aa1f2 ("iio: Implement counter channel type and info constants") Signed-off-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 1ce46035ecab..7531d383be8c 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1594,7 +1594,7 @@ Description: can be processed to siemens per meter. What: /sys/bus/iio/devices/iio:deviceX/in_countY_raw -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Raw counter device counts from channel Y. For quadrature @@ -1602,7 +1602,7 @@ Description: the counts of a single quadrature signal phase from channel Y. What: /sys/bus/iio/devices/iio:deviceX/in_indexY_raw -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Raw counter device index value from channel Y. This attribute -- cgit v1.2.3 From b061f1a57c3d2e6ab0fc3988619eaab77917592b Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 8 Feb 2017 09:01:45 -0500 Subject: Documentation: iio: 104-quad-8: Fix KernelVersion in sysfs ABI documentation The ACCES 104-QUAD-8 IIO driver did not appear in the 4.9 version of the Linux kernel. This patch fixes the KernelVersion lines of the 104-QUAD-8 sysfs ABI documentation. Fixes: 28e5d3bb0325 ("iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8") Signed-off-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-counter-104-quad-8 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 index ba676520b953..5f4924a94949 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 +++ b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 @@ -4,21 +4,21 @@ What: /sys/bus/iio/devices/iio:deviceX/in_count_noise_error_available What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available What: /sys/bus/iio/devices/iio:deviceX/in_index_index_polarity_available What: /sys/bus/iio/devices/iio:deviceX/in_index_synchronous_mode_available -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Discrete set of available values for the respective counter configuration are listed in this file. What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_direction -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Read-only attribute that indicates whether the counter for channel Y is counting up or down. What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Count mode for channel Y. Four count modes are available: @@ -52,7 +52,7 @@ Description: continuously throughout. What: /sys/bus/iio/devices/iio:deviceX/in_countY_noise_error -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Read-only attribute that indicates whether excessive noise is @@ -60,14 +60,14 @@ Description: irrelevant in non-quadrature clock mode. What: /sys/bus/iio/devices/iio:deviceX/in_countY_preset -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: If the counter device supports preset registers, the preset count for channel Y is provided by this attribute. What: /sys/bus/iio/devices/iio:deviceX/in_countY_quadrature_mode -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Configure channel Y counter for non-quadrature or quadrature @@ -88,7 +88,7 @@ Description: decoded for UP/DN clock. What: /sys/bus/iio/devices/iio:deviceX/in_countY_set_to_preset_on_index -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Whether to set channel Y counter with channel Y preset value @@ -96,14 +96,14 @@ Description: Valid attribute values are boolean. What: /sys/bus/iio/devices/iio:deviceX/in_indexY_index_polarity -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Active level of channel Y index input; irrelevant in non-synchronous load mode. What: /sys/bus/iio/devices/iio:deviceX/in_indexY_synchronous_mode -KernelVersion: 4.9 +KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org Description: Configure channel Y counter for non-synchronous or synchronous -- cgit v1.2.3 From af8f651b399798c4599e4994708afcf1f206120e Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 5 Feb 2017 12:34:00 +0000 Subject: staging:iio:adc:spear Move out of staging. There are some unanswered questions due to disagreements between the code and various datasheets (including between different datasheets for the same part). I don't think that is necessarily a reason to keep it in staging however. I'm partly posting this patch inorder to reignite debate and with a bit of luck find someone who has one of these to test! Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/spear_adc.c | 395 ++++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 10 - drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/spear_adc.c | 395 ------------------------------------ 6 files changed, 407 insertions(+), 406 deletions(-) create mode 100644 drivers/iio/adc/spear_adc.c delete mode 100644 drivers/staging/iio/adc/spear_adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index dedae7adbce9..789a5fb7c0be 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -494,6 +494,17 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config SPEAR_ADC + tristate "ST SPEAr ADC" + depends on PLAT_SPEAR || COMPILE_TEST + depends on HAS_IOMEM + help + Say yes here to build support for the integrated ADC inside the + ST SPEAr SoC. Provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called spear_adc. + config STM32_ADC_CORE tristate "STMicroelectronics STM32 adc core" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index d0012620cd1c..19e48af43b97 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +obj-$(CONFIG_SPEAR_ADC) += spear_adc.o obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c new file mode 100644 index 000000000000..5dd61f6a57b9 --- /dev/null +++ b/drivers/iio/adc/spear_adc.c @@ -0,0 +1,395 @@ +/* + * ST SPEAr ADC driver + * + * Copyright 2012 Stefan Roese + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* SPEAR registers definitions */ +#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) +#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) +#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0) +#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4) + +/* Bit definitions for SPEAR_ADC_STATUS */ +#define SPEAR_ADC_STATUS_START_CONVERSION BIT(0) +#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) +#define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4) +#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) +#define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9) + +#define SPEAR_ADC_DATA_MASK 0x03ff +#define SPEAR_ADC_DATA_BITS 10 + +#define SPEAR_ADC_MOD_NAME "spear-adc" + +#define SPEAR_ADC_CHANNEL_NUM 8 + +#define SPEAR_ADC_CLK_MIN 2500000 +#define SPEAR_ADC_CLK_MAX 20000000 + +struct adc_regs_spear3xx { + u32 status; + u32 average; + u32 scan_rate; + u32 clk; /* Not avail for 1340 & 1310 */ + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + u32 ch_data[SPEAR_ADC_CHANNEL_NUM]; +}; + +struct chan_data { + u32 lsb; + u32 msb; +}; + +struct adc_regs_spear6xx { + u32 status; + u32 pad[2]; + u32 clk; + u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; + struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM]; + u32 scan_rate_lo; + u32 scan_rate_hi; + struct chan_data average; +}; + +struct spear_adc_state { + struct device_node *np; + struct adc_regs_spear3xx __iomem *adc_base_spear3xx; + struct adc_regs_spear6xx __iomem *adc_base_spear6xx; + struct clk *clk; + struct completion completion; + u32 current_clk; + u32 sampling_freq; + u32 avg_samples; + u32 vref_external; + u32 value; +}; + +/* + * Functions to access some SPEAr ADC register. Abstracted into + * static inline functions, because of different register offsets + * on different SoC variants (SPEAr300 vs SPEAr600 etc). + */ +static void spear_adc_set_status(struct spear_adc_state *st, u32 val) +{ + __raw_writel(val, &st->adc_base_spear6xx->status); +} + +static void spear_adc_set_clk(struct spear_adc_state *st, u32 val) +{ + u32 clk_high, clk_low, count; + u32 apb_clk = clk_get_rate(st->clk); + + count = DIV_ROUND_UP(apb_clk, val); + clk_low = count / 2; + clk_high = count - clk_low; + st->current_clk = apb_clk / count; + + __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), + &st->adc_base_spear6xx->clk); +} + +static void spear_adc_set_ctrl(struct spear_adc_state *st, int n, + u32 val) +{ + __raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]); +} + +static u32 spear_adc_get_average(struct spear_adc_state *st) +{ + if (of_device_is_compatible(st->np, "st,spear600-adc")) { + return __raw_readl(&st->adc_base_spear6xx->average.msb) & + SPEAR_ADC_DATA_MASK; + } else { + return __raw_readl(&st->adc_base_spear3xx->average) & + SPEAR_ADC_DATA_MASK; + } +} + +static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) +{ + if (of_device_is_compatible(st->np, "st,spear600-adc")) { + __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), + &st->adc_base_spear6xx->scan_rate_lo); + __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), + &st->adc_base_spear6xx->scan_rate_hi); + } else { + __raw_writel(rate, &st->adc_base_spear3xx->scan_rate); + } +} + +static int spear_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct spear_adc_state *st = iio_priv(indio_dev); + u32 status; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + + status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | + SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | + SPEAR_ADC_STATUS_START_CONVERSION | + SPEAR_ADC_STATUS_ADC_ENABLE; + if (st->vref_external == 0) + status |= SPEAR_ADC_STATUS_VREF_INTERNAL; + + spear_adc_set_status(st, status); + wait_for_completion(&st->completion); /* set by ISR */ + *val = st->value; + + mutex_unlock(&indio_dev->mlock); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = st->vref_external; + *val2 = SPEAR_ADC_DATA_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->current_clk; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int spear_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct spear_adc_state *st = iio_priv(indio_dev); + int ret = 0; + + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + + if ((val < SPEAR_ADC_CLK_MIN) || + (val > SPEAR_ADC_CLK_MAX) || + (val2 != 0)) { + ret = -EINVAL; + goto out; + } + + spear_adc_set_clk(st, val); + +out: + mutex_unlock(&indio_dev->mlock); + return ret; +} + +#define SPEAR_ADC_CHAN(idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .channel = idx, \ +} + +static const struct iio_chan_spec spear_adc_iio_channels[] = { + SPEAR_ADC_CHAN(0), + SPEAR_ADC_CHAN(1), + SPEAR_ADC_CHAN(2), + SPEAR_ADC_CHAN(3), + SPEAR_ADC_CHAN(4), + SPEAR_ADC_CHAN(5), + SPEAR_ADC_CHAN(6), + SPEAR_ADC_CHAN(7), +}; + +static irqreturn_t spear_adc_isr(int irq, void *dev_id) +{ + struct spear_adc_state *st = dev_id; + + /* Read value to clear IRQ */ + st->value = spear_adc_get_average(st); + complete(&st->completion); + + return IRQ_HANDLED; +} + +static int spear_adc_configure(struct spear_adc_state *st) +{ + int i; + + /* Reset ADC core */ + spear_adc_set_status(st, 0); + __raw_writel(0, &st->adc_base_spear6xx->clk); + for (i = 0; i < 8; i++) + spear_adc_set_ctrl(st, i, 0); + spear_adc_set_scanrate(st, 0); + + spear_adc_set_clk(st, st->sampling_freq); + + return 0; +} + +static const struct iio_info spear_adc_info = { + .read_raw = &spear_adc_read_raw, + .write_raw = &spear_adc_write_raw, + .driver_module = THIS_MODULE, +}; + +static int spear_adc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct spear_adc_state *st; + struct resource *res; + struct iio_dev *indio_dev = NULL; + int ret = -ENODEV; + int irq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); + if (!indio_dev) { + dev_err(dev, "failed allocating iio device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + st->np = np; + + /* + * SPEAr600 has a different register layout than other SPEAr SoC's + * (e.g. SPEAr3xx). Let's provide two register base addresses + * to support multi-arch kernels. + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + st->adc_base_spear6xx = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(st->adc_base_spear6xx)) + return PTR_ERR(st->adc_base_spear6xx); + + st->adc_base_spear3xx = + (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; + + st->clk = devm_clk_get(dev, NULL); + if (IS_ERR(st->clk)) { + dev_err(dev, "failed getting clock\n"); + return PTR_ERR(st->clk); + } + + ret = clk_prepare_enable(st->clk); + if (ret) { + dev_err(dev, "failed enabling clock\n"); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "failed getting interrupt resource\n"); + ret = -EINVAL; + goto errout2; + } + + ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, + st); + if (ret < 0) { + dev_err(dev, "failed requesting interrupt\n"); + goto errout2; + } + + if (of_property_read_u32(np, "sampling-frequency", + &st->sampling_freq)) { + dev_err(dev, "sampling-frequency missing in DT\n"); + ret = -EINVAL; + goto errout2; + } + + /* + * Optional avg_samples defaults to 0, resulting in single data + * conversion + */ + of_property_read_u32(np, "average-samples", &st->avg_samples); + + /* + * Optional vref_external defaults to 0, resulting in internal vref + * selection + */ + of_property_read_u32(np, "vref-external", &st->vref_external); + + spear_adc_configure(st); + + platform_set_drvdata(pdev, indio_dev); + + init_completion(&st->completion); + + indio_dev->name = SPEAR_ADC_MOD_NAME; + indio_dev->dev.parent = dev; + indio_dev->info = &spear_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = spear_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); + + ret = iio_device_register(indio_dev); + if (ret) + goto errout2; + + dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); + + return 0; + +errout2: + clk_disable_unprepare(st->clk); + return ret; +} + +static int spear_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct spear_adc_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + clk_disable_unprepare(st->clk); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id spear_adc_dt_ids[] = { + { .compatible = "st,spear600-adc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); +#endif + +static struct platform_driver spear_adc_driver = { + .probe = spear_adc_probe, + .remove = spear_adc_remove, + .driver = { + .name = SPEAR_ADC_MOD_NAME, + .of_match_table = of_match_ptr(spear_adc_dt_ids), + }, +}; + +module_platform_driver(spear_adc_driver); + +MODULE_AUTHOR("Stefan Roese "); +MODULE_DESCRIPTION("SPEAr ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index deff89973d53..0ad5c44042b2 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -92,14 +92,4 @@ config LPC32XX_ADC activate only one via device tree selection. Provides direct access via sysfs. -config SPEAR_ADC - tristate "ST SPEAr ADC" - depends on PLAT_SPEAR || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for the integrated ADC inside the - ST SPEAr SoC. Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called spear_adc. endmenu diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index ac09485923b6..e7098dedeb75 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -11,4 +11,3 @@ obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o -obj-$(CONFIG_SPEAR_ADC) += spear_adc.o diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c deleted file mode 100644 index 5dd61f6a57b9..000000000000 --- a/drivers/staging/iio/adc/spear_adc.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * ST SPEAr ADC driver - * - * Copyright 2012 Stefan Roese - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* SPEAR registers definitions */ -#define SPEAR600_ADC_SCAN_RATE_LO(x) ((x) & 0xFFFF) -#define SPEAR600_ADC_SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF) -#define SPEAR_ADC_CLK_LOW(x) (((x) & 0xf) << 0) -#define SPEAR_ADC_CLK_HIGH(x) (((x) & 0xf) << 4) - -/* Bit definitions for SPEAR_ADC_STATUS */ -#define SPEAR_ADC_STATUS_START_CONVERSION BIT(0) -#define SPEAR_ADC_STATUS_CHANNEL_NUM(x) ((x) << 1) -#define SPEAR_ADC_STATUS_ADC_ENABLE BIT(4) -#define SPEAR_ADC_STATUS_AVG_SAMPLE(x) ((x) << 5) -#define SPEAR_ADC_STATUS_VREF_INTERNAL BIT(9) - -#define SPEAR_ADC_DATA_MASK 0x03ff -#define SPEAR_ADC_DATA_BITS 10 - -#define SPEAR_ADC_MOD_NAME "spear-adc" - -#define SPEAR_ADC_CHANNEL_NUM 8 - -#define SPEAR_ADC_CLK_MIN 2500000 -#define SPEAR_ADC_CLK_MAX 20000000 - -struct adc_regs_spear3xx { - u32 status; - u32 average; - u32 scan_rate; - u32 clk; /* Not avail for 1340 & 1310 */ - u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; - u32 ch_data[SPEAR_ADC_CHANNEL_NUM]; -}; - -struct chan_data { - u32 lsb; - u32 msb; -}; - -struct adc_regs_spear6xx { - u32 status; - u32 pad[2]; - u32 clk; - u32 ch_ctrl[SPEAR_ADC_CHANNEL_NUM]; - struct chan_data ch_data[SPEAR_ADC_CHANNEL_NUM]; - u32 scan_rate_lo; - u32 scan_rate_hi; - struct chan_data average; -}; - -struct spear_adc_state { - struct device_node *np; - struct adc_regs_spear3xx __iomem *adc_base_spear3xx; - struct adc_regs_spear6xx __iomem *adc_base_spear6xx; - struct clk *clk; - struct completion completion; - u32 current_clk; - u32 sampling_freq; - u32 avg_samples; - u32 vref_external; - u32 value; -}; - -/* - * Functions to access some SPEAr ADC register. Abstracted into - * static inline functions, because of different register offsets - * on different SoC variants (SPEAr300 vs SPEAr600 etc). - */ -static void spear_adc_set_status(struct spear_adc_state *st, u32 val) -{ - __raw_writel(val, &st->adc_base_spear6xx->status); -} - -static void spear_adc_set_clk(struct spear_adc_state *st, u32 val) -{ - u32 clk_high, clk_low, count; - u32 apb_clk = clk_get_rate(st->clk); - - count = DIV_ROUND_UP(apb_clk, val); - clk_low = count / 2; - clk_high = count - clk_low; - st->current_clk = apb_clk / count; - - __raw_writel(SPEAR_ADC_CLK_LOW(clk_low) | SPEAR_ADC_CLK_HIGH(clk_high), - &st->adc_base_spear6xx->clk); -} - -static void spear_adc_set_ctrl(struct spear_adc_state *st, int n, - u32 val) -{ - __raw_writel(val, &st->adc_base_spear6xx->ch_ctrl[n]); -} - -static u32 spear_adc_get_average(struct spear_adc_state *st) -{ - if (of_device_is_compatible(st->np, "st,spear600-adc")) { - return __raw_readl(&st->adc_base_spear6xx->average.msb) & - SPEAR_ADC_DATA_MASK; - } else { - return __raw_readl(&st->adc_base_spear3xx->average) & - SPEAR_ADC_DATA_MASK; - } -} - -static void spear_adc_set_scanrate(struct spear_adc_state *st, u32 rate) -{ - if (of_device_is_compatible(st->np, "st,spear600-adc")) { - __raw_writel(SPEAR600_ADC_SCAN_RATE_LO(rate), - &st->adc_base_spear6xx->scan_rate_lo); - __raw_writel(SPEAR600_ADC_SCAN_RATE_HI(rate), - &st->adc_base_spear6xx->scan_rate_hi); - } else { - __raw_writel(rate, &st->adc_base_spear3xx->scan_rate); - } -} - -static int spear_adc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct spear_adc_state *st = iio_priv(indio_dev); - u32 status; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - - status = SPEAR_ADC_STATUS_CHANNEL_NUM(chan->channel) | - SPEAR_ADC_STATUS_AVG_SAMPLE(st->avg_samples) | - SPEAR_ADC_STATUS_START_CONVERSION | - SPEAR_ADC_STATUS_ADC_ENABLE; - if (st->vref_external == 0) - status |= SPEAR_ADC_STATUS_VREF_INTERNAL; - - spear_adc_set_status(st, status); - wait_for_completion(&st->completion); /* set by ISR */ - *val = st->value; - - mutex_unlock(&indio_dev->mlock); - - return IIO_VAL_INT; - - case IIO_CHAN_INFO_SCALE: - *val = st->vref_external; - *val2 = SPEAR_ADC_DATA_BITS; - return IIO_VAL_FRACTIONAL_LOG2; - case IIO_CHAN_INFO_SAMP_FREQ: - *val = st->current_clk; - return IIO_VAL_INT; - } - - return -EINVAL; -} - -static int spear_adc_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct spear_adc_state *st = iio_priv(indio_dev); - int ret = 0; - - if (mask != IIO_CHAN_INFO_SAMP_FREQ) - return -EINVAL; - - mutex_lock(&indio_dev->mlock); - - if ((val < SPEAR_ADC_CLK_MIN) || - (val > SPEAR_ADC_CLK_MAX) || - (val2 != 0)) { - ret = -EINVAL; - goto out; - } - - spear_adc_set_clk(st, val); - -out: - mutex_unlock(&indio_dev->mlock); - return ret; -} - -#define SPEAR_ADC_CHAN(idx) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ - .channel = idx, \ -} - -static const struct iio_chan_spec spear_adc_iio_channels[] = { - SPEAR_ADC_CHAN(0), - SPEAR_ADC_CHAN(1), - SPEAR_ADC_CHAN(2), - SPEAR_ADC_CHAN(3), - SPEAR_ADC_CHAN(4), - SPEAR_ADC_CHAN(5), - SPEAR_ADC_CHAN(6), - SPEAR_ADC_CHAN(7), -}; - -static irqreturn_t spear_adc_isr(int irq, void *dev_id) -{ - struct spear_adc_state *st = dev_id; - - /* Read value to clear IRQ */ - st->value = spear_adc_get_average(st); - complete(&st->completion); - - return IRQ_HANDLED; -} - -static int spear_adc_configure(struct spear_adc_state *st) -{ - int i; - - /* Reset ADC core */ - spear_adc_set_status(st, 0); - __raw_writel(0, &st->adc_base_spear6xx->clk); - for (i = 0; i < 8; i++) - spear_adc_set_ctrl(st, i, 0); - spear_adc_set_scanrate(st, 0); - - spear_adc_set_clk(st, st->sampling_freq); - - return 0; -} - -static const struct iio_info spear_adc_info = { - .read_raw = &spear_adc_read_raw, - .write_raw = &spear_adc_write_raw, - .driver_module = THIS_MODULE, -}; - -static int spear_adc_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct spear_adc_state *st; - struct resource *res; - struct iio_dev *indio_dev = NULL; - int ret = -ENODEV; - int irq; - - indio_dev = devm_iio_device_alloc(dev, sizeof(struct spear_adc_state)); - if (!indio_dev) { - dev_err(dev, "failed allocating iio device\n"); - return -ENOMEM; - } - - st = iio_priv(indio_dev); - st->np = np; - - /* - * SPEAr600 has a different register layout than other SPEAr SoC's - * (e.g. SPEAr3xx). Let's provide two register base addresses - * to support multi-arch kernels. - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - st->adc_base_spear6xx = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(st->adc_base_spear6xx)) - return PTR_ERR(st->adc_base_spear6xx); - - st->adc_base_spear3xx = - (struct adc_regs_spear3xx __iomem *)st->adc_base_spear6xx; - - st->clk = devm_clk_get(dev, NULL); - if (IS_ERR(st->clk)) { - dev_err(dev, "failed getting clock\n"); - return PTR_ERR(st->clk); - } - - ret = clk_prepare_enable(st->clk); - if (ret) { - dev_err(dev, "failed enabling clock\n"); - return ret; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(dev, "failed getting interrupt resource\n"); - ret = -EINVAL; - goto errout2; - } - - ret = devm_request_irq(dev, irq, spear_adc_isr, 0, SPEAR_ADC_MOD_NAME, - st); - if (ret < 0) { - dev_err(dev, "failed requesting interrupt\n"); - goto errout2; - } - - if (of_property_read_u32(np, "sampling-frequency", - &st->sampling_freq)) { - dev_err(dev, "sampling-frequency missing in DT\n"); - ret = -EINVAL; - goto errout2; - } - - /* - * Optional avg_samples defaults to 0, resulting in single data - * conversion - */ - of_property_read_u32(np, "average-samples", &st->avg_samples); - - /* - * Optional vref_external defaults to 0, resulting in internal vref - * selection - */ - of_property_read_u32(np, "vref-external", &st->vref_external); - - spear_adc_configure(st); - - platform_set_drvdata(pdev, indio_dev); - - init_completion(&st->completion); - - indio_dev->name = SPEAR_ADC_MOD_NAME; - indio_dev->dev.parent = dev; - indio_dev->info = &spear_adc_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = spear_adc_iio_channels; - indio_dev->num_channels = ARRAY_SIZE(spear_adc_iio_channels); - - ret = iio_device_register(indio_dev); - if (ret) - goto errout2; - - dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); - - return 0; - -errout2: - clk_disable_unprepare(st->clk); - return ret; -} - -static int spear_adc_remove(struct platform_device *pdev) -{ - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - struct spear_adc_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - clk_disable_unprepare(st->clk); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id spear_adc_dt_ids[] = { - { .compatible = "st,spear600-adc", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, spear_adc_dt_ids); -#endif - -static struct platform_driver spear_adc_driver = { - .probe = spear_adc_probe, - .remove = spear_adc_remove, - .driver = { - .name = SPEAR_ADC_MOD_NAME, - .of_match_table = of_match_ptr(spear_adc_dt_ids), - }, -}; - -module_platform_driver(spear_adc_driver); - -MODULE_AUTHOR("Stefan Roese "); -MODULE_DESCRIPTION("SPEAr ADC driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5023574adc735a7c85fc4b1150fe82f8d3e0e076 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 5 Feb 2017 13:06:58 +0000 Subject: staging:iio:adc:lpc32xx Apply consistent prefix to local defines There was a bit of a random mixture going on here so change all prefixes to LPC32XXAD_ Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/lpc32xx_adc.c | 54 +++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index b51f237cd817..5d13ff008a39 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -38,25 +38,28 @@ /* * LPC32XX registers definitions */ -#define LPC32XX_ADC_SELECT(x) ((x) + 0x04) -#define LPC32XX_ADC_CTRL(x) ((x) + 0x08) -#define LPC32XX_ADC_VALUE(x) ((x) + 0x48) +#define LPC32XXAD_SELECT(x) ((x) + 0x04) +#define LPC32XXAD_CTRL(x) ((x) + 0x08) +#define LPC32XXAD_VALUE(x) ((x) + 0x48) -/* Bit definitions for LPC32XX_ADC_SELECT: */ -#define AD_REFm 0x00000200 /* constant, always write this value! */ -#define AD_REFp 0x00000080 /* constant, always write this value! */ -#define AD_IN 0x00000010 /* multiple of this is the */ - /* channel number: 0, 1, 2 */ -#define AD_INTERNAL 0x00000004 /* constant, always write this value! */ +/* Bit definitions for LPC32XXAD_SELECT: */ +/* constant, always write this value! */ +#define LPC32XXAD_REFm 0x00000200 +/* constant, always write this value! */ +#define LPC32XXAD_REFp 0x00000080 + /* multiple of this is the channel number: 0, 1, 2 */ +#define LPC32XXAD_IN 0x00000010 +/* constant, always write this value! */ +#define LPC32XXAD_INTERNAL 0x00000004 -/* Bit definitions for LPC32XX_ADC_CTRL: */ -#define AD_STROBE 0x00000002 -#define AD_PDN_CTRL 0x00000004 +/* Bit definitions for LPC32XXAD_CTRL: */ +#define LPC32XXAD_STROBE 0x00000002 +#define LPC32XXAD_PDN_CTRL 0x00000004 -/* Bit definitions for LPC32XX_ADC_VALUE: */ -#define ADC_VALUE_MASK 0x000003FF +/* Bit definitions for LPC32XXAD_VALUE: */ +#define LPC32XXAD_VALUE_MASK 0x000003FF -#define MOD_NAME "lpc32xx-adc" +#define LPC32XXAD_NAME "lpc32xx-adc" struct lpc32xx_adc_info { void __iomem *adc_base; @@ -78,11 +81,12 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); clk_prepare_enable(info->clk); /* Measurement setup */ - __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm, - LPC32XX_ADC_SELECT(info->adc_base)); + __raw_writel(LPC32XXAD_INTERNAL | (chan->address) | + LPC32XXAD_REFp | LPC32XXAD_REFm, + LPC32XXAD_SELECT(info->adc_base)); /* Trigger conversion */ - __raw_writel(AD_PDN_CTRL | AD_STROBE, - LPC32XX_ADC_CTRL(info->adc_base)); + __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE, + LPC32XXAD_CTRL(info->adc_base)); wait_for_completion(&info->completion); /* set by ISR */ clk_disable_unprepare(info->clk); *val = info->value; @@ -104,7 +108,7 @@ static const struct iio_info lpc32xx_adc_iio_info = { .indexed = 1, \ .channel = _index, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .address = AD_IN * _index, \ + .address = LPC32XXAD_IN * _index, \ .scan_index = _index, \ } @@ -119,8 +123,8 @@ static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) struct lpc32xx_adc_info *info = dev_id; /* Read value and clear irq */ - info->value = __raw_readl(LPC32XX_ADC_VALUE(info->adc_base)) & - ADC_VALUE_MASK; + info->value = __raw_readl(LPC32XXAD_VALUE(info->adc_base)) & + LPC32XXAD_VALUE_MASK; complete(&info->completion); return IRQ_HANDLED; @@ -166,7 +170,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) } retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, - MOD_NAME, info); + LPC32XXAD_NAME, info); if (retval < 0) { dev_err(&pdev->dev, "failed requesting interrupt\n"); return retval; @@ -176,7 +180,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) init_completion(&info->completion); - iodev->name = MOD_NAME; + iodev->name = LPC32XXAD_NAME; iodev->dev.parent = &pdev->dev; iodev->info = &lpc32xx_adc_iio_info; iodev->modes = INDIO_DIRECT_MODE; @@ -203,7 +207,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); static struct platform_driver lpc32xx_adc_driver = { .probe = lpc32xx_adc_probe, .driver = { - .name = MOD_NAME, + .name = LPC32XXAD_NAME, .of_match_table = of_match_ptr(lpc32xx_adc_match), }, }; -- cgit v1.2.3 From 7901b2a1453e48c9defff2c97c67d3089bf4df7a Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 5 Feb 2017 13:06:59 +0000 Subject: staging:iio:adc:lpc32xx rename local state structure to _state Previously it was called _info with instances as info. This caused some confusion against the info structure that are used in the core of IIO. Since this driver was written it's become a fairly strong convention to use _state and st for instances so change to that. Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/lpc32xx_adc.c | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index 5d13ff008a39..0de709b4288b 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -61,7 +61,7 @@ #define LPC32XXAD_NAME "lpc32xx-adc" -struct lpc32xx_adc_info { +struct lpc32xx_adc_state { void __iomem *adc_base; struct clk *clk; struct completion completion; @@ -75,21 +75,21 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { - struct lpc32xx_adc_info *info = iio_priv(indio_dev); + struct lpc32xx_adc_state *st = iio_priv(indio_dev); if (mask == IIO_CHAN_INFO_RAW) { mutex_lock(&indio_dev->mlock); - clk_prepare_enable(info->clk); + clk_prepare_enable(st->clk); /* Measurement setup */ __raw_writel(LPC32XXAD_INTERNAL | (chan->address) | LPC32XXAD_REFp | LPC32XXAD_REFm, - LPC32XXAD_SELECT(info->adc_base)); + LPC32XXAD_SELECT(st->adc_base)); /* Trigger conversion */ __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE, - LPC32XXAD_CTRL(info->adc_base)); - wait_for_completion(&info->completion); /* set by ISR */ - clk_disable_unprepare(info->clk); - *val = info->value; + LPC32XXAD_CTRL(st->adc_base)); + wait_for_completion(&st->completion); /* set by ISR */ + clk_disable_unprepare(st->clk); + *val = st->value; mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; @@ -120,19 +120,19 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) { - struct lpc32xx_adc_info *info = dev_id; + struct lpc32xx_adc_state *st = dev_id; /* Read value and clear irq */ - info->value = __raw_readl(LPC32XXAD_VALUE(info->adc_base)) & - LPC32XXAD_VALUE_MASK; - complete(&info->completion); + st->value = __raw_readl(LPC32XXAD_VALUE(st->adc_base)) & + LPC32XXAD_VALUE_MASK; + complete(&st->completion); return IRQ_HANDLED; } static int lpc32xx_adc_probe(struct platform_device *pdev) { - struct lpc32xx_adc_info *info = NULL; + struct lpc32xx_adc_state *st = NULL; struct resource *res; int retval = -ENODEV; struct iio_dev *iodev = NULL; @@ -144,23 +144,23 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) return -ENXIO; } - iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); + iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); if (!iodev) return -ENOMEM; - info = iio_priv(iodev); + st = iio_priv(iodev); - info->adc_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!info->adc_base) { + st->adc_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!st->adc_base) { dev_err(&pdev->dev, "failed mapping memory\n"); return -EBUSY; } - info->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(info->clk)) { + st->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(st->clk)) { dev_err(&pdev->dev, "failed getting clock\n"); - return PTR_ERR(info->clk); + return PTR_ERR(st->clk); } irq = platform_get_irq(pdev, 0); @@ -170,7 +170,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) } retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, - LPC32XXAD_NAME, info); + LPC32XXAD_NAME, st); if (retval < 0) { dev_err(&pdev->dev, "failed requesting interrupt\n"); return retval; @@ -178,7 +178,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iodev); - init_completion(&info->completion); + init_completion(&st->completion); iodev->name = LPC32XXAD_NAME; iodev->dev.parent = &pdev->dev; -- cgit v1.2.3 From 0097e20e7771c482c07cdf397e2a6b9e1154fad8 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sun, 5 Feb 2017 13:07:00 +0000 Subject: staging:iio:adc:lpc32xx Move out of staging. There are a few more little cleanups that could be done on this driver, but I don't think any are sufficient to justify not moving it out of staging. It's a very simple driver (presumably for a simple part) so not much that can go wrong. I think it was only ever in staging because that's where IIO was as a whole at the time and then we forgot about it! Signed-off-by: Jonathan Cameron Cc: Roland Stigge Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/lpc32xx_adc.c | 219 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 12 -- drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/lpc32xx_adc.c | 219 ---------------------------------- 6 files changed, 232 insertions(+), 232 deletions(-) create mode 100644 drivers/iio/adc/lpc32xx_adc.c delete mode 100644 drivers/staging/iio/adc/lpc32xx_adc.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 789a5fb7c0be..d777a972586d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -305,6 +305,18 @@ config LPC18XX_ADC To compile this driver as a module, choose M here: the module will be called lpc18xx_adc. +config LPC32XX_ADC + tristate "NXP LPC32XX ADC" + depends on ARCH_LPC32XX || COMPILE_TEST + depends on HAS_IOMEM + help + Say yes here to build support for the integrated ADC inside the + LPC32XX SoC. Note that this feature uses the same hardware as the + touchscreen driver, so you should either select only one of the two + drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case, + activate only one via device tree selection. Provides direct access + via sysfs. + config LTC2485 tristate "Linear Technology LTC2485 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 19e48af43b97..b11bb5767543 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o +obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX11100) += max11100.o diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c new file mode 100644 index 000000000000..0de709b4288b --- /dev/null +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -0,0 +1,219 @@ +/* + * lpc32xx_adc.c - Support for ADC in LPC32XX + * + * 3-channel, 10-bit ADC + * + * Copyright (C) 2011, 2012 Roland Stigge + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * LPC32XX registers definitions + */ +#define LPC32XXAD_SELECT(x) ((x) + 0x04) +#define LPC32XXAD_CTRL(x) ((x) + 0x08) +#define LPC32XXAD_VALUE(x) ((x) + 0x48) + +/* Bit definitions for LPC32XXAD_SELECT: */ +/* constant, always write this value! */ +#define LPC32XXAD_REFm 0x00000200 +/* constant, always write this value! */ +#define LPC32XXAD_REFp 0x00000080 + /* multiple of this is the channel number: 0, 1, 2 */ +#define LPC32XXAD_IN 0x00000010 +/* constant, always write this value! */ +#define LPC32XXAD_INTERNAL 0x00000004 + +/* Bit definitions for LPC32XXAD_CTRL: */ +#define LPC32XXAD_STROBE 0x00000002 +#define LPC32XXAD_PDN_CTRL 0x00000004 + +/* Bit definitions for LPC32XXAD_VALUE: */ +#define LPC32XXAD_VALUE_MASK 0x000003FF + +#define LPC32XXAD_NAME "lpc32xx-adc" + +struct lpc32xx_adc_state { + void __iomem *adc_base; + struct clk *clk; + struct completion completion; + + u32 value; +}; + +static int lpc32xx_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct lpc32xx_adc_state *st = iio_priv(indio_dev); + + if (mask == IIO_CHAN_INFO_RAW) { + mutex_lock(&indio_dev->mlock); + clk_prepare_enable(st->clk); + /* Measurement setup */ + __raw_writel(LPC32XXAD_INTERNAL | (chan->address) | + LPC32XXAD_REFp | LPC32XXAD_REFm, + LPC32XXAD_SELECT(st->adc_base)); + /* Trigger conversion */ + __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE, + LPC32XXAD_CTRL(st->adc_base)); + wait_for_completion(&st->completion); /* set by ISR */ + clk_disable_unprepare(st->clk); + *val = st->value; + mutex_unlock(&indio_dev->mlock); + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static const struct iio_info lpc32xx_adc_iio_info = { + .read_raw = &lpc32xx_read_raw, + .driver_module = THIS_MODULE, +}; + +#define LPC32XX_ADC_CHANNEL(_index) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .address = LPC32XXAD_IN * _index, \ + .scan_index = _index, \ +} + +static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { + LPC32XX_ADC_CHANNEL(0), + LPC32XX_ADC_CHANNEL(1), + LPC32XX_ADC_CHANNEL(2), +}; + +static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) +{ + struct lpc32xx_adc_state *st = dev_id; + + /* Read value and clear irq */ + st->value = __raw_readl(LPC32XXAD_VALUE(st->adc_base)) & + LPC32XXAD_VALUE_MASK; + complete(&st->completion); + + return IRQ_HANDLED; +} + +static int lpc32xx_adc_probe(struct platform_device *pdev) +{ + struct lpc32xx_adc_state *st = NULL; + struct resource *res; + int retval = -ENODEV; + struct iio_dev *iodev = NULL; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get platform I/O memory\n"); + return -ENXIO; + } + + iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (!iodev) + return -ENOMEM; + + st = iio_priv(iodev); + + st->adc_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!st->adc_base) { + dev_err(&pdev->dev, "failed mapping memory\n"); + return -EBUSY; + } + + st->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(st->clk)) { + dev_err(&pdev->dev, "failed getting clock\n"); + return PTR_ERR(st->clk); + } + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(&pdev->dev, "failed getting interrupt resource\n"); + return -ENXIO; + } + + retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, + LPC32XXAD_NAME, st); + if (retval < 0) { + dev_err(&pdev->dev, "failed requesting interrupt\n"); + return retval; + } + + platform_set_drvdata(pdev, iodev); + + init_completion(&st->completion); + + iodev->name = LPC32XXAD_NAME; + iodev->dev.parent = &pdev->dev; + iodev->info = &lpc32xx_adc_iio_info; + iodev->modes = INDIO_DIRECT_MODE; + iodev->channels = lpc32xx_adc_iio_channels; + iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); + + retval = devm_iio_device_register(&pdev->dev, iodev); + if (retval) + return retval; + + dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id lpc32xx_adc_match[] = { + { .compatible = "nxp,lpc3220-adc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); +#endif + +static struct platform_driver lpc32xx_adc_driver = { + .probe = lpc32xx_adc_probe, + .driver = { + .name = LPC32XXAD_NAME, + .of_match_table = of_match_ptr(lpc32xx_adc_match), + }, +}; + +module_platform_driver(lpc32xx_adc_driver); + +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("LPC32XX ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 0ad5c44042b2..e17efb03bac0 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -80,16 +80,4 @@ config AD7280 To compile this driver as a module, choose M here: the module will be called ad7280a -config LPC32XX_ADC - tristate "NXP LPC32XX ADC" - depends on ARCH_LPC32XX || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for the integrated ADC inside the - LPC32XX SoC. Note that this feature uses the same hardware as the - touchscreen driver, so you should either select only one of the two - drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case, - activate only one via device tree selection. Provides direct access - via sysfs. - endmenu diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index e7098dedeb75..bf18bdd7c99d 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -10,4 +10,3 @@ obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_AD7280) += ad7280a.o -obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c deleted file mode 100644 index 0de709b4288b..000000000000 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * lpc32xx_adc.c - Support for ADC in LPC32XX - * - * 3-channel, 10-bit ADC - * - * Copyright (C) 2011, 2012 Roland Stigge - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * LPC32XX registers definitions - */ -#define LPC32XXAD_SELECT(x) ((x) + 0x04) -#define LPC32XXAD_CTRL(x) ((x) + 0x08) -#define LPC32XXAD_VALUE(x) ((x) + 0x48) - -/* Bit definitions for LPC32XXAD_SELECT: */ -/* constant, always write this value! */ -#define LPC32XXAD_REFm 0x00000200 -/* constant, always write this value! */ -#define LPC32XXAD_REFp 0x00000080 - /* multiple of this is the channel number: 0, 1, 2 */ -#define LPC32XXAD_IN 0x00000010 -/* constant, always write this value! */ -#define LPC32XXAD_INTERNAL 0x00000004 - -/* Bit definitions for LPC32XXAD_CTRL: */ -#define LPC32XXAD_STROBE 0x00000002 -#define LPC32XXAD_PDN_CTRL 0x00000004 - -/* Bit definitions for LPC32XXAD_VALUE: */ -#define LPC32XXAD_VALUE_MASK 0x000003FF - -#define LPC32XXAD_NAME "lpc32xx-adc" - -struct lpc32xx_adc_state { - void __iomem *adc_base; - struct clk *clk; - struct completion completion; - - u32 value; -}; - -static int lpc32xx_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct lpc32xx_adc_state *st = iio_priv(indio_dev); - - if (mask == IIO_CHAN_INFO_RAW) { - mutex_lock(&indio_dev->mlock); - clk_prepare_enable(st->clk); - /* Measurement setup */ - __raw_writel(LPC32XXAD_INTERNAL | (chan->address) | - LPC32XXAD_REFp | LPC32XXAD_REFm, - LPC32XXAD_SELECT(st->adc_base)); - /* Trigger conversion */ - __raw_writel(LPC32XXAD_PDN_CTRL | LPC32XXAD_STROBE, - LPC32XXAD_CTRL(st->adc_base)); - wait_for_completion(&st->completion); /* set by ISR */ - clk_disable_unprepare(st->clk); - *val = st->value; - mutex_unlock(&indio_dev->mlock); - - return IIO_VAL_INT; - } - - return -EINVAL; -} - -static const struct iio_info lpc32xx_adc_iio_info = { - .read_raw = &lpc32xx_read_raw, - .driver_module = THIS_MODULE, -}; - -#define LPC32XX_ADC_CHANNEL(_index) { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = _index, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .address = LPC32XXAD_IN * _index, \ - .scan_index = _index, \ -} - -static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { - LPC32XX_ADC_CHANNEL(0), - LPC32XX_ADC_CHANNEL(1), - LPC32XX_ADC_CHANNEL(2), -}; - -static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) -{ - struct lpc32xx_adc_state *st = dev_id; - - /* Read value and clear irq */ - st->value = __raw_readl(LPC32XXAD_VALUE(st->adc_base)) & - LPC32XXAD_VALUE_MASK; - complete(&st->completion); - - return IRQ_HANDLED; -} - -static int lpc32xx_adc_probe(struct platform_device *pdev) -{ - struct lpc32xx_adc_state *st = NULL; - struct resource *res; - int retval = -ENODEV; - struct iio_dev *iodev = NULL; - int irq; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform I/O memory\n"); - return -ENXIO; - } - - iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); - if (!iodev) - return -ENOMEM; - - st = iio_priv(iodev); - - st->adc_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!st->adc_base) { - dev_err(&pdev->dev, "failed mapping memory\n"); - return -EBUSY; - } - - st->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(st->clk)) { - dev_err(&pdev->dev, "failed getting clock\n"); - return PTR_ERR(st->clk); - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, "failed getting interrupt resource\n"); - return -ENXIO; - } - - retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0, - LPC32XXAD_NAME, st); - if (retval < 0) { - dev_err(&pdev->dev, "failed requesting interrupt\n"); - return retval; - } - - platform_set_drvdata(pdev, iodev); - - init_completion(&st->completion); - - iodev->name = LPC32XXAD_NAME; - iodev->dev.parent = &pdev->dev; - iodev->info = &lpc32xx_adc_iio_info; - iodev->modes = INDIO_DIRECT_MODE; - iodev->channels = lpc32xx_adc_iio_channels; - iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); - - retval = devm_iio_device_register(&pdev->dev, iodev); - if (retval) - return retval; - - dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq); - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id lpc32xx_adc_match[] = { - { .compatible = "nxp,lpc3220-adc" }, - {}, -}; -MODULE_DEVICE_TABLE(of, lpc32xx_adc_match); -#endif - -static struct platform_driver lpc32xx_adc_driver = { - .probe = lpc32xx_adc_probe, - .driver = { - .name = LPC32XXAD_NAME, - .of_match_table = of_match_ptr(lpc32xx_adc_match), - }, -}; - -module_platform_driver(lpc32xx_adc_driver); - -MODULE_AUTHOR("Roland Stigge "); -MODULE_DESCRIPTION("LPC32XX ADC driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From bf0adab4cd0d69eb22495f89e53f79941bb62300 Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Fri, 17 Feb 2017 23:38:07 +0530 Subject: staging: iio: adis16240_core: Replace symbolic permission with octal permission The patch resolves following checkpatch issue: WARNING: Symbolic permissions 'S_IRUGO' are not preferred. Consider using octal permissions '0444'. Signed-off-by: sayli karnik Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/adis16240_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index d5b99e610d08..e1bc9fcb7852 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -65,7 +65,7 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev, return ret; } -static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, S_IRUGO, +static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, 0444, adis16240_read_12bit_signed, NULL, ADIS16240_XYZPEAK_OUT); -- cgit v1.2.3 From fb364cea3d245fff5cb4c953c8c9a4b1efcbe4c6 Mon Sep 17 00:00:00 2001 From: Gargi Sharma Date: Fri, 17 Feb 2017 22:47:21 +0530 Subject: staging: iio: compress return logic Simplify function returns by merging assignment and return. Found with Coccinelle. Semantic patch: @@ local idexpression ret; expression e; @@ -ret = +return e; -return ret; Signed-off-by: Gargi Sharma Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7854.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index e8007f0c5186..c6cffc11b0ba 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -426,9 +426,7 @@ static int ade7854_set_irq(struct device *dev, bool enable) else irqen &= ~BIT(17); - ret = st->write_reg_32(dev, ADE7854_MASK0, irqen); - - return ret; + return st->write_reg_32(dev, ADE7854_MASK0, irqen); } static int ade7854_initial_setup(struct iio_dev *indio_dev) -- cgit v1.2.3 From 31b9f91913cb18d7eb2276640bf0a56fb352d7b6 Mon Sep 17 00:00:00 2001 From: Derek Robson Date: Sun, 12 Feb 2017 20:22:40 +1300 Subject: Staging: iio: impedance-analyzer: ad5933.c - style fix Change permissions to octal style. Found using checkpatch Signed-off-by: Derek Robson Signed-off-by: Jonathan Cameron --- drivers/staging/iio/impedance-analyzer/ad5933.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 5e96352fa4ac..297665d3fe11 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -345,12 +345,12 @@ static ssize_t ad5933_store_frequency(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage0_freq_start, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_freq_start, 0644, ad5933_show_frequency, ad5933_store_frequency, AD5933_REG_FREQ_START); -static IIO_DEVICE_ATTR(out_voltage0_freq_increment, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_freq_increment, 0644, ad5933_show_frequency, ad5933_store_frequency, AD5933_REG_FREQ_INC); @@ -469,32 +469,32 @@ static ssize_t ad5933_store(struct device *dev, return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_voltage0_scale, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_scale, 0644, ad5933_show, ad5933_store, AD5933_OUT_RANGE); -static IIO_DEVICE_ATTR(out_voltage0_scale_available, S_IRUGO, +static IIO_DEVICE_ATTR(out_voltage0_scale_available, 0444, ad5933_show, NULL, AD5933_OUT_RANGE_AVAIL); -static IIO_DEVICE_ATTR(in_voltage0_scale, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(in_voltage0_scale, 0644, ad5933_show, ad5933_store, AD5933_IN_PGA_GAIN); -static IIO_DEVICE_ATTR(in_voltage0_scale_available, S_IRUGO, +static IIO_DEVICE_ATTR(in_voltage0_scale_available, 0444, ad5933_show, NULL, AD5933_IN_PGA_GAIN_AVAIL); -static IIO_DEVICE_ATTR(out_voltage0_freq_points, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_freq_points, 0644, ad5933_show, ad5933_store, AD5933_FREQ_POINTS); -static IIO_DEVICE_ATTR(out_voltage0_settling_cycles, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_settling_cycles, 0644, ad5933_show, ad5933_store, AD5933_OUT_SETTLING_CYCLES); -- cgit v1.2.3 From c5c7d1f34c333d0a14f1f80d3d46eed4f338211e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:14 +0100 Subject: iio: stx104: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Acked-by: William Breathitt Gray --- drivers/iio/adc/stx104.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c index be2de48844bc..2df84fa5e3fc 100644 --- a/drivers/iio/adc/stx104.c +++ b/drivers/iio/adc/stx104.c @@ -318,6 +318,7 @@ static int stx104_probe(struct device *dev, unsigned int id) } indio_dev->name = dev_name(dev); + indio_dev->dev.parent = dev; priv = iio_priv(indio_dev); priv->base = base[id]; -- cgit v1.2.3 From ed165e91719b2c99336786d721d8ae30700c62cb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:15 +0100 Subject: iio: quad-8: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Acked-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- drivers/iio/counter/104-quad-8.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index a5913e97945e..e381ca66a92c 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -551,6 +551,7 @@ static int quad8_probe(struct device *dev, unsigned int id) indio_dev->num_channels = ARRAY_SIZE(quad8_channels); indio_dev->channels = quad8_channels; indio_dev->name = dev_name(dev); + indio_dev->dev.parent = dev; priv = iio_priv(indio_dev); priv->base = base[id]; -- cgit v1.2.3 From 83535359c4302cb0f928eb931b7b1bc0a21a66c5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:16 +0100 Subject: iio: cio-dac: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Acked-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- drivers/iio/dac/cio-dac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/dac/cio-dac.c b/drivers/iio/dac/cio-dac.c index 5a743e2a779d..a0464227a3a0 100644 --- a/drivers/iio/dac/cio-dac.c +++ b/drivers/iio/dac/cio-dac.c @@ -119,6 +119,7 @@ static int cio_dac_probe(struct device *dev, unsigned int id) indio_dev->channels = cio_dac_channels; indio_dev->num_channels = CIO_DAC_NUM_CHAN; indio_dev->name = dev_name(dev); + indio_dev->dev.parent = dev; priv = iio_priv(indio_dev); priv->base = base[id]; -- cgit v1.2.3 From 5d548b733eb4b5cfb03e1acbcbfafca97455132c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:17 +0100 Subject: iio: max30100: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/health/max30100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 9648c69ea1a2..10b3e0d57c4a 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -449,6 +449,7 @@ static int max30100_probe(struct i2c_client *client, indio_dev->available_scan_masks = max30100_scan_masks; indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); indio_dev->setup_ops = &max30100_buffer_setup_ops; + indio_dev->dev.parent = &client->dev; data = iio_priv(indio_dev); data->indio_dev = indio_dev; -- cgit v1.2.3 From fa722499bbf89b5976bdfc77139f7d623a69a18a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:18 +0100 Subject: iio: max30102: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/health/max30102.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index 377518c15552..839b875c29b9 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -410,6 +410,7 @@ static int max30102_probe(struct i2c_client *client, indio_dev->available_scan_masks = max30102_scan_masks; indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); indio_dev->setup_ops = &max30102_buffer_setup_ops; + indio_dev->dev.parent = &client->dev; data = iio_priv(indio_dev); data->indio_dev = indio_dev; -- cgit v1.2.3 From e78c1f5710bc1a394d17850a50de0429aa5e2938 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:19 +0100 Subject: iio: lmp91000: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Reviewed-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/potentiostat/lmp91000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index e22714365022..afa8de3418d0 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -325,6 +325,7 @@ static int lmp91000_probe(struct i2c_client *client, indio_dev->channels = lmp91000_channels; indio_dev->num_channels = ARRAY_SIZE(lmp91000_channels); indio_dev->name = LMP91000_DRV_NAME; + indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; i2c_set_clientdata(client, indio_dev); -- cgit v1.2.3 From b2027d16df9194ec22eb5d315776532a7476bdb1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:20 +0100 Subject: iio: pulsedlight-lidar-lite-v2: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Reviewed-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 20c16a08c9d9..36c1ddc251aa 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -278,6 +278,7 @@ static int lidar_probe(struct i2c_client *client, indio_dev->name = LIDAR_DRV_NAME; indio_dev->channels = lidar_channels; indio_dev->num_channels = ARRAY_SIZE(lidar_channels); + indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; i2c_set_clientdata(client, indio_dev); -- cgit v1.2.3 From 74e2419b00d870b373ada4878e3d66d8dc97f4b0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 11 Feb 2017 13:34:21 +0100 Subject: iio: maxim_thermocouple: Set parent device Initialize the parent of the IIO device to the device that registered it. This makes sure that the IIO device appears the right level in the device hierarchy. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index f962f31a5eb2..557214202eff 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -231,6 +231,7 @@ static int maxim_thermocouple_probe(struct spi_device *spi) indio_dev->available_scan_masks = chip->scan_masks; indio_dev->num_channels = chip->num_channels; indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->dev.parent = &spi->dev; data = iio_priv(indio_dev); data->spi = spi; -- cgit v1.2.3 From 3af109131b7eb880ba0711344912d7a523a812b4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 15 Feb 2017 20:31:45 +0100 Subject: iio: adc: meson-saradc: switch from polling to interrupt mode Switch from polling to interrupt mode. Successfully tested on a S905GXBB-based Odroid C2. Signed-off-by: Heiner Kallweit Acked-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/amlogic,meson-saradc.txt | 2 + drivers/iio/adc/meson_saradc.c | 56 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt index f9e3ff2c656e..047189192aec 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -7,6 +7,7 @@ Required properties: - "amlogic,meson-gxm-saradc" for GXM along with the generic "amlogic,meson-saradc" - reg: the physical base address and length of the registers +- interrupts: the interrupt indicating end of sampling - clocks: phandle and clock identifier (see clock-names) - clock-names: mandatory clocks: - "clkin" for the reference clock (typically XTAL) @@ -23,6 +24,7 @@ Example: compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc"; #io-channel-cells = <1>; reg = <0x0 0x8680 0x0 0x34>; + interrupts = ; clocks = <&xtal>, <&clkc CLKID_SAR_ADC>, <&clkc CLKID_SANA>, diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 89def6034f40..9f186de24cd7 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -163,6 +165,7 @@ #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) #define MESON_SAR_ADC_MAX_FIFO_SIZE 32 +#define MESON_SAR_ADC_TIMEOUT 100 /* ms */ #define MESON_SAR_ADC_CHAN(_chan) { \ .type = IIO_VOLTAGE, \ @@ -229,6 +232,7 @@ struct meson_sar_adc_priv { struct clk_gate clk_gate; struct clk *adc_div_clk; struct clk_divider clk_div; + struct completion done; }; static const struct regmap_config meson_sar_adc_regmap_config = { @@ -274,11 +278,11 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, int *val) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0; + int regval, fifo_chan, fifo_val, sum = 0, count = 0; - ret = meson_sar_adc_wait_busy_clear(indio_dev); - if (ret) - return ret; + if(!wait_for_completion_timeout(&priv->done, + msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) + return -ETIMEDOUT; while (meson_sar_adc_get_fifo_count(indio_dev) > 0 && count < MESON_SAR_ADC_MAX_FIFO_SIZE) { @@ -378,6 +382,12 @@ static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + reinit_completion(&priv->done); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); @@ -391,6 +401,9 @@ static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, MESON_SAR_ADC_REG0_SAMPLING_STOP, MESON_SAR_ADC_REG0_SAMPLING_STOP); @@ -643,6 +656,7 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); int ret; + u32 regval; ret = meson_sar_adc_lock(indio_dev); if (ret) @@ -667,6 +681,9 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) goto err_sana_clk; } + regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, MESON_SAR_ADC_REG11_BANDGAP_EN, MESON_SAR_ADC_REG11_BANDGAP_EN); @@ -728,6 +745,25 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) return 0; } +static irqreturn_t meson_sar_adc_irq(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + unsigned int cnt, threshold; + u32 regval; + + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + cnt = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); + threshold = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); + + if (cnt < threshold) + return IRQ_NONE; + + complete(&priv->done); + + return IRQ_HANDLED; +} + static const struct iio_info meson_sar_adc_iio_info = { .read_raw = meson_sar_adc_iio_info_read_raw, .driver_module = THIS_MODULE, @@ -770,7 +806,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) struct resource *res; void __iomem *base; const struct of_device_id *match; - int ret; + int irq, ret; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); if (!indio_dev) { @@ -779,6 +815,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) } priv = iio_priv(indio_dev); + init_completion(&priv->done); match = of_match_device(meson_sar_adc_of_match, &pdev->dev); priv->data = match->data; @@ -797,6 +834,15 @@ static int meson_sar_adc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + return -EINVAL; + + ret = devm_request_irq(&pdev->dev, irq, meson_sar_adc_irq, IRQF_SHARED, + dev_name(&pdev->dev), indio_dev); + if (ret) + return ret; + priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, &meson_sar_adc_regmap_config); if (IS_ERR(priv->regmap)) -- cgit v1.2.3 From 6a882a2cbeb09b7c32610a644d5915d17b80b617 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 15 Feb 2017 20:31:55 +0100 Subject: iio: adc: meson-saradc: improve meson_sar_adc_read_raw_sample After sampling there should always be only one value in the FIFO. This also applies to averaging mode as the averaging is done chip-internally. So we don't have to loop and let the driver complain if there's not exactly one value in the FIFO. If the value belongs to a different channel then don't silently swallow the value but complain. Signed-off-by: Heiner Kallweit Acked-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 9f186de24cd7..cde9ca7a01b8 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -278,33 +278,31 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, int *val) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - int regval, fifo_chan, fifo_val, sum = 0, count = 0; + int regval, fifo_chan, fifo_val, count; if(!wait_for_completion_timeout(&priv->done, msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) return -ETIMEDOUT; - while (meson_sar_adc_get_fifo_count(indio_dev) > 0 && - count < MESON_SAR_ADC_MAX_FIFO_SIZE) { - regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); - - fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, - regval); - if (fifo_chan != chan->channel) - continue; - - fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, - regval); - fifo_val &= (BIT(priv->data->resolution) - 1); - - sum += fifo_val; - count++; + count = meson_sar_adc_get_fifo_count(indio_dev); + if (count != 1) { + dev_err(&indio_dev->dev, + "ADC FIFO has %d element(s) instead of one\n", count); + return -EINVAL; } - if (!count) - return -ENOENT; + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); + fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval); + if (fifo_chan != chan->channel) { + dev_err(&indio_dev->dev, + "ADC FIFO entry belongs to channel %d instead of %d\n", + fifo_chan, chan->channel); + return -EINVAL; + } - *val = sum / count; + fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); + fifo_val &= GENMASK(priv->data->resolution - 1, 0); + *val = fifo_val; return 0; } -- cgit v1.2.3 From b0105002816907daf72e984a72e16e3a5f2471cc Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Wed, 22 Feb 2017 17:23:33 +0800 Subject: hid: hid-sensor-prox: Add more data field for hysteresis parsing Add HID_USAGE_SENSOR_HUMAN_PRESENCE support for Human Presence sensitivity parsing, in case some implementation uses it as sensitivity modifier. Signed-off-by: Song Hongyan Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-prox.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 45ca056f019e..73fced8a63b7 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -240,6 +240,13 @@ static int prox_parse_report(struct platform_device *pdev, st->common_attributes.sensitivity.index, st->common_attributes.sensitivity.report_id); } + if (st->common_attributes.sensitivity.index < 0) + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_HUMAN_PRESENCE, + &st->common_attributes.sensitivity); + return ret; } -- cgit v1.2.3 From 8f867691ebbce7f03b3bcf79fad61b0454e89e91 Mon Sep 17 00:00:00 2001 From: sayli karnik Date: Mon, 20 Feb 2017 01:28:35 +0530 Subject: staging: iio: ad7152: Use BIT() macro for left shifting 1 Replace left shifting on 1 with the BIT(x) macro as suggested by checkpatch.pl. Signed-off-by: sayli karnik Acked-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/staging/iio/cdc/ad7152.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index b91b50f345bd..e8609b866fec 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -41,10 +41,10 @@ #define AD7152_REG_CFG2 26 /* Status Register Bit Designations (AD7152_REG_STATUS) */ -#define AD7152_STATUS_RDY1 (1 << 0) -#define AD7152_STATUS_RDY2 (1 << 1) -#define AD7152_STATUS_C1C2 (1 << 2) -#define AD7152_STATUS_PWDN (1 << 7) +#define AD7152_STATUS_RDY1 BIT(0) +#define AD7152_STATUS_RDY2 BIT(1) +#define AD7152_STATUS_C1C2 BIT(2) +#define AD7152_STATUS_PWDN BIT(7) /* Setup Register Bit Designations (AD7152_REG_CHx_SETUP) */ #define AD7152_SETUP_CAPDIFF (1 << 5) -- cgit v1.2.3 From 346834727af71eecec770906c8f68c881a19bed4 Mon Sep 17 00:00:00 2001 From: simran singhal Date: Wed, 1 Mar 2017 00:21:17 +0530 Subject: staging: iio: accel: adis16201: Move header file content to source file The contents of the header file are used only by this single source file. Move content into .c and remove .h. Signed-off-by: simran singhal Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/adis16201.h | 144 ----------------------------- drivers/staging/iio/accel/adis16201_core.c | 140 +++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 145 deletions(-) delete mode 100644 drivers/staging/iio/accel/adis16201.h diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h deleted file mode 100644 index 64844adcaacd..000000000000 --- a/drivers/staging/iio/accel/adis16201.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef SPI_ADIS16201_H_ -#define SPI_ADIS16201_H_ - -#define ADIS16201_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16201_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16201_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16201_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16201_YACCL_OUT 0x06 - -/* Output, auxiliary ADC input */ -#define ADIS16201_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16201_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16201_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16201_YINCL_OUT 0x0E - -/* Calibration, x-axis acceleration offset */ -#define ADIS16201_XACCL_OFFS 0x10 - -/* Calibration, y-axis acceleration offset */ -#define ADIS16201_YACCL_OFFS 0x12 - -/* x-axis acceleration scale factor */ -#define ADIS16201_XACCL_SCALE 0x14 - -/* y-axis acceleration scale factor */ -#define ADIS16201_YACCL_SCALE 0x16 - -/* Calibration, x-axis inclination offset */ -#define ADIS16201_XINCL_OFFS 0x18 - -/* Calibration, y-axis inclination offset */ -#define ADIS16201_YINCL_OFFS 0x1A - -/* x-axis inclination scale factor */ -#define ADIS16201_XINCL_SCALE 0x1C - -/* y-axis inclination scale factor */ -#define ADIS16201_YINCL_SCALE 0x1E - -/* Alarm 1 amplitude threshold */ -#define ADIS16201_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16201_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16201_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16201_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16201_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16201_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16201_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16201_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16201_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16201_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16201_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16201_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16201_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test enable */ -#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ -#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) - -/* SPI communications failure */ -#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16201_ERROR_ACTIVE BIT(14) - -enum adis16201_scan { - ADIS16201_SCAN_ACC_X, - ADIS16201_SCAN_ACC_Y, - ADIS16201_SCAN_INCLI_X, - ADIS16201_SCAN_INCLI_Y, - ADIS16201_SCAN_SUPPLY, - ADIS16201_SCAN_AUX_ADC, - ADIS16201_SCAN_TEMP, -}; - -#endif /* SPI_ADIS16201_H_ */ diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c index 7963d4a83f84..d6c8658c88b9 100644 --- a/drivers/staging/iio/accel/adis16201_core.c +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -20,7 +20,145 @@ #include #include -#include "adis16201.h" +#define ADIS16201_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16201_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16201_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16201_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16201_YACCL_OUT 0x06 + +/* Output, auxiliary ADC input */ +#define ADIS16201_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16201_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16201_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16201_YINCL_OUT 0x0E + +/* Calibration, x-axis acceleration offset */ +#define ADIS16201_XACCL_OFFS 0x10 + +/* Calibration, y-axis acceleration offset */ +#define ADIS16201_YACCL_OFFS 0x12 + +/* x-axis acceleration scale factor */ +#define ADIS16201_XACCL_SCALE 0x14 + +/* y-axis acceleration scale factor */ +#define ADIS16201_YACCL_SCALE 0x16 + +/* Calibration, x-axis inclination offset */ +#define ADIS16201_XINCL_OFFS 0x18 + +/* Calibration, y-axis inclination offset */ +#define ADIS16201_YINCL_OFFS 0x1A + +/* x-axis inclination scale factor */ +#define ADIS16201_XINCL_SCALE 0x1C + +/* y-axis inclination scale factor */ +#define ADIS16201_YINCL_SCALE 0x1E + +/* Alarm 1 amplitude threshold */ +#define ADIS16201_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16201_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16201_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16201_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16201_ALM_CTRL 0x28 + +/* Auxiliary DAC data */ +#define ADIS16201_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16201_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16201_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16201_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16201_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16201_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16201_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16201_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test enable */ +#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ +#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) + +/* SPI communications failure */ +#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16201_ERROR_ACTIVE BIT(14) + +enum adis16201_scan { + ADIS16201_SCAN_ACC_X, + ADIS16201_SCAN_ACC_Y, + ADIS16201_SCAN_INCLI_X, + ADIS16201_SCAN_INCLI_Y, + ADIS16201_SCAN_SUPPLY, + ADIS16201_SCAN_AUX_ADC, + ADIS16201_SCAN_TEMP, +}; static const u8 adis16201_addresses[] = { [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS, -- cgit v1.2.3 From a8baa3c02a7faa5405adb03eac240e915dca79ea Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Wed, 1 Mar 2017 00:03:42 +0530 Subject: staging: iio: adis16203: Move header file content to source file. The contents of the header file are used only by this single source file. Moved content into adis16203_core.c file and removed adis16203.h file. Arranged #include files in alphabetical order. Signed-off-by: Varsha Rao Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/adis16203.h | 125 -------------------------- drivers/staging/iio/accel/adis16203_core.c | 136 +++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 133 deletions(-) delete mode 100644 drivers/staging/iio/accel/adis16203.h diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h deleted file mode 100644 index b483e4e6475b..000000000000 --- a/drivers/staging/iio/accel/adis16203.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef SPI_ADIS16203_H_ -#define SPI_ADIS16203_H_ - -#define ADIS16203_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16203_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16203_SUPPLY_OUT 0x02 - -/* Output, auxiliary ADC input */ -#define ADIS16203_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16203_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16203_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16203_YINCL_OUT 0x0E - -/* Incline null calibration */ -#define ADIS16203_INCL_NULL 0x18 - -/* Alarm 1 amplitude threshold */ -#define ADIS16203_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16203_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16203_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16203_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16203_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16203_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16203_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16203_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16203_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16203_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16203_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16203_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16203_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test at power-on: 1 = disabled, 0 = enabled */ -#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST BIT(10) - -/* Reverses rotation of both inclination outputs */ -#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN BIT(9) - -/* Self-test enable */ -#define ADIS16203_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16203_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16203_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ -#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16203_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16203_DIAG_STAT_ALARM1 BIT(8) - -/* Self-test diagnostic error flag */ -#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 - -/* SPI communications failure */ -#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16203_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16203_GLOB_CMD_CLEAR_STAT BIT(4) -#define ADIS16203_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16203_ERROR_ACTIVE BIT(14) - -enum adis16203_scan { - ADIS16203_SCAN_INCLI_X, - ADIS16203_SCAN_INCLI_Y, - ADIS16203_SCAN_SUPPLY, - ADIS16203_SCAN_AUX_ADC, - ADIS16203_SCAN_TEMP, -}; - -#endif /* SPI_ADIS16203_H_ */ diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c index bd8119a23339..68189aded729 100644 --- a/drivers/staging/iio/accel/adis16203_core.c +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -7,20 +7,140 @@ */ #include -#include #include + +#include +#include +#include +#include + #include -#include +#include +#include #include +#include #include -#include -#include -#include -#include -#include +#define ADIS16203_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16203_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16203_SUPPLY_OUT 0x02 + +/* Output, auxiliary ADC input */ +#define ADIS16203_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16203_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16203_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16203_YINCL_OUT 0x0E + +/* Incline null calibration */ +#define ADIS16203_INCL_NULL 0x18 + +/* Alarm 1 amplitude threshold */ +#define ADIS16203_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16203_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16203_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16203_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16203_ALM_CTRL 0x28 -#include "adis16203.h" +/* Auxiliary DAC data */ +#define ADIS16203_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16203_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16203_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16203_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16203_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16203_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16203_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16203_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST BIT(10) + +/* Reverses rotation of both inclination outputs */ +#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN BIT(9) + +/* Self-test enable */ +#define ADIS16203_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16203_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16203_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ +#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_ALARM1 BIT(8) + +/* Self-test diagnostic error flag */ +#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 + +/* SPI communications failure */ +#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16203_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16203_GLOB_CMD_CLEAR_STAT BIT(4) +#define ADIS16203_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16203_ERROR_ACTIVE BIT(14) + +enum adis16203_scan { + ADIS16203_SCAN_INCLI_X, + ADIS16203_SCAN_INCLI_Y, + ADIS16203_SCAN_SUPPLY, + ADIS16203_SCAN_AUX_ADC, + ADIS16203_SCAN_TEMP, +}; #define DRIVER_NAME "adis16203" -- cgit v1.2.3 From d89aa24585a5e350ec406fb4d11bf6968bfe0cf0 Mon Sep 17 00:00:00 2001 From: Narcisa Ana Maria Vasile Date: Mon, 27 Feb 2017 19:28:16 +0200 Subject: staging: iio: ad9832: Moved contents of the header to the source file Moved the contents of the header(ad9832.h) into the corresponding source file with the exception of the platform data struct which is supposed to be used from somewhere else other than the driver. Signed-off-by: Narcisa Ana Maria Vasile Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9832.c | 92 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/frequency/ad9832.h | 92 ---------------------------------- 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index a5b2f068168d..8d40c8e37173 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -22,6 +22,98 @@ #include "ad9832.h" +/* Registers */ + +#define AD9832_FREQ0LL 0x0 +#define AD9832_FREQ0HL 0x1 +#define AD9832_FREQ0LM 0x2 +#define AD9832_FREQ0HM 0x3 +#define AD9832_FREQ1LL 0x4 +#define AD9832_FREQ1HL 0x5 +#define AD9832_FREQ1LM 0x6 +#define AD9832_FREQ1HM 0x7 +#define AD9832_PHASE0L 0x8 +#define AD9832_PHASE0H 0x9 +#define AD9832_PHASE1L 0xA +#define AD9832_PHASE1H 0xB +#define AD9832_PHASE2L 0xC +#define AD9832_PHASE2H 0xD +#define AD9832_PHASE3L 0xE +#define AD9832_PHASE3H 0xF + +#define AD9832_PHASE_SYM 0x10 +#define AD9832_FREQ_SYM 0x11 +#define AD9832_PINCTRL_EN 0x12 +#define AD9832_OUTPUT_EN 0x13 + +/* Command Control Bits */ + +#define AD9832_CMD_PHA8BITSW 0x1 +#define AD9832_CMD_PHA16BITSW 0x0 +#define AD9832_CMD_FRE8BITSW 0x3 +#define AD9832_CMD_FRE16BITSW 0x2 +#define AD9832_CMD_FPSELECT 0x6 +#define AD9832_CMD_SYNCSELSRC 0x8 +#define AD9832_CMD_SLEEPRESCLR 0xC + +#define AD9832_FREQ BIT(11) +#define AD9832_PHASE(x) (((x) & 3) << 9) +#define AD9832_SYNC BIT(13) +#define AD9832_SELSRC BIT(12) +#define AD9832_SLEEP BIT(13) +#define AD9832_RESET BIT(12) +#define AD9832_CLR BIT(11) +#define CMD_SHIFT 12 +#define ADD_SHIFT 8 +#define AD9832_FREQ_BITS 32 +#define AD9832_PHASE_BITS 12 +#define RES_MASK(bits) ((1 << (bits)) - 1) + +/** + * struct ad9832_state - driver instance specific data + * @spi: spi_device + * @avdd: supply regulator for the analog section + * @dvdd: supply regulator for the digital section + * @mclk: external master clock + * @ctrl_fp: cached frequency/phase control word + * @ctrl_ss: cached sync/selsrc control word + * @ctrl_src: cached sleep/reset/clr word + * @xfer: default spi transfer + * @msg: default spi message + * @freq_xfer: tuning word spi transfer + * @freq_msg: tuning word spi message + * @phase_xfer: tuning word spi transfer + * @phase_msg: tuning word spi message + * @data: spi transmit buffer + * @phase_data: tuning word spi transmit buffer + * @freq_data: tuning word spi transmit buffer + */ + +struct ad9832_state { + struct spi_device *spi; + struct regulator *avdd; + struct regulator *dvdd; + unsigned long mclk; + unsigned short ctrl_fp; + unsigned short ctrl_ss; + unsigned short ctrl_src; + struct spi_transfer xfer; + struct spi_message msg; + struct spi_transfer freq_xfer[4]; + struct spi_message freq_msg; + struct spi_transfer phase_xfer[2]; + struct spi_message phase_msg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + union { + __be16 freq_data[4]____cacheline_aligned; + __be16 phase_data[2]; + __be16 data; + }; +}; + static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout) { unsigned long long freqreg = (u64)fout * diff --git a/drivers/staging/iio/frequency/ad9832.h b/drivers/staging/iio/frequency/ad9832.h index 1b08b04482a4..39d326cc1af9 100644 --- a/drivers/staging/iio/frequency/ad9832.h +++ b/drivers/staging/iio/frequency/ad9832.h @@ -8,98 +8,6 @@ #ifndef IIO_DDS_AD9832_H_ #define IIO_DDS_AD9832_H_ -/* Registers */ - -#define AD9832_FREQ0LL 0x0 -#define AD9832_FREQ0HL 0x1 -#define AD9832_FREQ0LM 0x2 -#define AD9832_FREQ0HM 0x3 -#define AD9832_FREQ1LL 0x4 -#define AD9832_FREQ1HL 0x5 -#define AD9832_FREQ1LM 0x6 -#define AD9832_FREQ1HM 0x7 -#define AD9832_PHASE0L 0x8 -#define AD9832_PHASE0H 0x9 -#define AD9832_PHASE1L 0xA -#define AD9832_PHASE1H 0xB -#define AD9832_PHASE2L 0xC -#define AD9832_PHASE2H 0xD -#define AD9832_PHASE3L 0xE -#define AD9832_PHASE3H 0xF - -#define AD9832_PHASE_SYM 0x10 -#define AD9832_FREQ_SYM 0x11 -#define AD9832_PINCTRL_EN 0x12 -#define AD9832_OUTPUT_EN 0x13 - -/* Command Control Bits */ - -#define AD9832_CMD_PHA8BITSW 0x1 -#define AD9832_CMD_PHA16BITSW 0x0 -#define AD9832_CMD_FRE8BITSW 0x3 -#define AD9832_CMD_FRE16BITSW 0x2 -#define AD9832_CMD_FPSELECT 0x6 -#define AD9832_CMD_SYNCSELSRC 0x8 -#define AD9832_CMD_SLEEPRESCLR 0xC - -#define AD9832_FREQ BIT(11) -#define AD9832_PHASE(x) (((x) & 3) << 9) -#define AD9832_SYNC BIT(13) -#define AD9832_SELSRC BIT(12) -#define AD9832_SLEEP BIT(13) -#define AD9832_RESET BIT(12) -#define AD9832_CLR BIT(11) -#define CMD_SHIFT 12 -#define ADD_SHIFT 8 -#define AD9832_FREQ_BITS 32 -#define AD9832_PHASE_BITS 12 -#define RES_MASK(bits) ((1 << (bits)) - 1) - -/** - * struct ad9832_state - driver instance specific data - * @spi: spi_device - * @avdd: supply regulator for the analog section - * @dvdd: supply regulator for the digital section - * @mclk: external master clock - * @ctrl_fp: cached frequency/phase control word - * @ctrl_ss: cached sync/selsrc control word - * @ctrl_src: cached sleep/reset/clr word - * @xfer: default spi transfer - * @msg: default spi message - * @freq_xfer: tuning word spi transfer - * @freq_msg: tuning word spi message - * @phase_xfer: tuning word spi transfer - * @phase_msg: tuning word spi message - * @data: spi transmit buffer - * @phase_data: tuning word spi transmit buffer - * @freq_data: tuning word spi transmit buffer - */ - -struct ad9832_state { - struct spi_device *spi; - struct regulator *avdd; - struct regulator *dvdd; - unsigned long mclk; - unsigned short ctrl_fp; - unsigned short ctrl_ss; - unsigned short ctrl_src; - struct spi_transfer xfer; - struct spi_message msg; - struct spi_transfer freq_xfer[4]; - struct spi_message freq_msg; - struct spi_transfer phase_xfer[2]; - struct spi_message phase_msg; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - union { - __be16 freq_data[4]____cacheline_aligned; - __be16 phase_data[2]; - __be16 data; - }; -}; - /* * TODO: struct ad9832_platform_data needs to go into include/linux/iio */ -- cgit v1.2.3 From dc35fa5628ff2ffc1adfb7be4c415216252df0d5 Mon Sep 17 00:00:00 2001 From: Narcisa Ana Maria Vasile Date: Tue, 28 Feb 2017 00:15:11 +0200 Subject: staging: iio: ad9834: Moved contents of the header to the source file Moved the contents of the header(ad9834.h) into the corresponding source file with the exception of the platform data struct which is supposed to be used from somewhere else other than the driver. Signed-off-by: Narcisa Ana Maria Vasile Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 72 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/frequency/ad9834.h | 72 ---------------------------------- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 19216af1dfc9..f92ff7fef6f3 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -25,6 +25,78 @@ #include "ad9834.h" +/* Registers */ + +#define AD9834_REG_CMD 0 +#define AD9834_REG_FREQ0 BIT(14) +#define AD9834_REG_FREQ1 BIT(15) +#define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) +#define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) + +/* Command Control Bits */ + +#define AD9834_B28 BIT(13) +#define AD9834_HLB BIT(12) +#define AD9834_FSEL BIT(11) +#define AD9834_PSEL BIT(10) +#define AD9834_PIN_SW BIT(9) +#define AD9834_RESET BIT(8) +#define AD9834_SLEEP1 BIT(7) +#define AD9834_SLEEP12 BIT(6) +#define AD9834_OPBITEN BIT(5) +#define AD9834_SIGN_PIB BIT(4) +#define AD9834_DIV2 BIT(3) +#define AD9834_MODE BIT(1) + +#define AD9834_FREQ_BITS 28 +#define AD9834_PHASE_BITS 12 + +#define RES_MASK(bits) (BIT(bits) - 1) + +/** + * struct ad9834_state - driver instance specific data + * @spi: spi_device + * @reg: supply regulator + * @mclk: external master clock + * @control: cached control word + * @xfer: default spi transfer + * @msg: default spi message + * @freq_xfer: tuning word spi transfer + * @freq_msg: tuning word spi message + * @data: spi transmit buffer + * @freq_data: tuning word spi transmit buffer + */ + +struct ad9834_state { + struct spi_device *spi; + struct regulator *reg; + unsigned int mclk; + unsigned short control; + unsigned short devid; + struct spi_transfer xfer; + struct spi_message msg; + struct spi_transfer freq_xfer[2]; + struct spi_message freq_msg; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 data ____cacheline_aligned; + __be16 freq_data[2]; +}; + +/** + * ad9834_supported_device_ids: + */ + +enum ad9834_supported_device_ids { + ID_AD9833, + ID_AD9834, + ID_AD9837, + ID_AD9838, +}; + static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) { unsigned long long freqreg = (u64)fout * (u64)BIT(AD9834_FREQ_BITS); diff --git a/drivers/staging/iio/frequency/ad9834.h b/drivers/staging/iio/frequency/ad9834.h index 40fdd5da7bd0..ae620f38eb49 100644 --- a/drivers/staging/iio/frequency/ad9834.h +++ b/drivers/staging/iio/frequency/ad9834.h @@ -8,67 +8,6 @@ #ifndef IIO_DDS_AD9834_H_ #define IIO_DDS_AD9834_H_ -/* Registers */ - -#define AD9834_REG_CMD 0 -#define AD9834_REG_FREQ0 BIT(14) -#define AD9834_REG_FREQ1 BIT(15) -#define AD9834_REG_PHASE0 (BIT(15) | BIT(14)) -#define AD9834_REG_PHASE1 (BIT(15) | BIT(14) | BIT(13)) - -/* Command Control Bits */ - -#define AD9834_B28 BIT(13) -#define AD9834_HLB BIT(12) -#define AD9834_FSEL BIT(11) -#define AD9834_PSEL BIT(10) -#define AD9834_PIN_SW BIT(9) -#define AD9834_RESET BIT(8) -#define AD9834_SLEEP1 BIT(7) -#define AD9834_SLEEP12 BIT(6) -#define AD9834_OPBITEN BIT(5) -#define AD9834_SIGN_PIB BIT(4) -#define AD9834_DIV2 BIT(3) -#define AD9834_MODE BIT(1) - -#define AD9834_FREQ_BITS 28 -#define AD9834_PHASE_BITS 12 - -#define RES_MASK(bits) (BIT(bits) - 1) - -/** - * struct ad9834_state - driver instance specific data - * @spi: spi_device - * @reg: supply regulator - * @mclk: external master clock - * @control: cached control word - * @xfer: default spi transfer - * @msg: default spi message - * @freq_xfer: tuning word spi transfer - * @freq_msg: tuning word spi message - * @data: spi transmit buffer - * @freq_data: tuning word spi transmit buffer - */ - -struct ad9834_state { - struct spi_device *spi; - struct regulator *reg; - unsigned int mclk; - unsigned short control; - unsigned short devid; - struct spi_transfer xfer; - struct spi_message msg; - struct spi_transfer freq_xfer[2]; - struct spi_message freq_msg; - - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - __be16 data ____cacheline_aligned; - __be16 freq_data[2]; -}; - /* * TODO: struct ad7887_platform_data needs to go into include/linux/iio */ @@ -97,15 +36,4 @@ struct ad9834_platform_data { bool en_signbit_msb_out; }; -/** - * ad9834_supported_device_ids: - */ - -enum ad9834_supported_device_ids { - ID_AD9833, - ID_AD9834, - ID_AD9837, - ID_AD9838, -}; - #endif /* IIO_DDS_AD9834_H_ */ -- cgit v1.2.3 From 21a123beaff48df4b2e8fde7819bb1ad0dc268bb Mon Sep 17 00:00:00 2001 From: Narcisa Ana Maria Vasile Date: Sat, 4 Mar 2017 15:47:08 +0200 Subject: staging: iio: adis16209: Move contents of the header to the source file The contents of the header file are used only by this single source file. Move content into .c file and remove header. Signed-off-by: Narcisa Ana Maria Vasile Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/adis16209.h | 144 ----------------------------- drivers/staging/iio/accel/adis16209_core.c | 140 +++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 145 deletions(-) delete mode 100644 drivers/staging/iio/accel/adis16209.h diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h deleted file mode 100644 index 315f1c0c46e8..000000000000 --- a/drivers/staging/iio/accel/adis16209.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef SPI_ADIS16209_H_ -#define SPI_ADIS16209_H_ - -#define ADIS16209_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16209_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16209_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16209_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16209_YACCL_OUT 0x06 - -/* Output, auxiliary ADC input */ -#define ADIS16209_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16209_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16209_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16209_YINCL_OUT 0x0E - -/* Output, +/-180 vertical rotational position */ -#define ADIS16209_ROT_OUT 0x10 - -/* Calibration, x-axis acceleration offset null */ -#define ADIS16209_XACCL_NULL 0x12 - -/* Calibration, y-axis acceleration offset null */ -#define ADIS16209_YACCL_NULL 0x14 - -/* Calibration, x-axis inclination offset null */ -#define ADIS16209_XINCL_NULL 0x16 - -/* Calibration, y-axis inclination offset null */ -#define ADIS16209_YINCL_NULL 0x18 - -/* Calibration, vertical rotation offset null */ -#define ADIS16209_ROT_NULL 0x1A - -/* Alarm 1 amplitude threshold */ -#define ADIS16209_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16209_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16209_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16209_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16209_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16209_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16209_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16209_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16209_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16209_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16209_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16209_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16209_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test at power-on: 1 = disabled, 0 = enabled */ -#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) - -/* Self-test enable */ -#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ -#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM1 BIT(8) - -/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ -#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5 - -/* SPI communications failure */ -#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16209_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4) -#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16209_ERROR_ACTIVE BIT(14) - -#define ADIS16209_SCAN_SUPPLY 0 -#define ADIS16209_SCAN_ACC_X 1 -#define ADIS16209_SCAN_ACC_Y 2 -#define ADIS16209_SCAN_AUX_ADC 3 -#define ADIS16209_SCAN_TEMP 4 -#define ADIS16209_SCAN_INCLI_X 5 -#define ADIS16209_SCAN_INCLI_Y 6 -#define ADIS16209_SCAN_ROT 7 - -#endif /* SPI_ADIS16209_H_ */ diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index a599e19303d3..8ff537f89d45 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -21,7 +21,145 @@ #include #include -#include "adis16209.h" +#define ADIS16209_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16209_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16209_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16209_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16209_YACCL_OUT 0x06 + +/* Output, auxiliary ADC input */ +#define ADIS16209_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16209_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16209_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16209_YINCL_OUT 0x0E + +/* Output, +/-180 vertical rotational position */ +#define ADIS16209_ROT_OUT 0x10 + +/* Calibration, x-axis acceleration offset null */ +#define ADIS16209_XACCL_NULL 0x12 + +/* Calibration, y-axis acceleration offset null */ +#define ADIS16209_YACCL_NULL 0x14 + +/* Calibration, x-axis inclination offset null */ +#define ADIS16209_XINCL_NULL 0x16 + +/* Calibration, y-axis inclination offset null */ +#define ADIS16209_YINCL_NULL 0x18 + +/* Calibration, vertical rotation offset null */ +#define ADIS16209_ROT_NULL 0x1A + +/* Alarm 1 amplitude threshold */ +#define ADIS16209_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16209_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16209_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16209_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16209_ALM_CTRL 0x28 + +/* Auxiliary DAC data */ +#define ADIS16209_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16209_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16209_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16209_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16209_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16209_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16209_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16209_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) + +/* Self-test enable */ +#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ +#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16209_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16209_DIAG_STAT_ALARM1 BIT(8) + +/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ +#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5 + +/* SPI communications failure */ +#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16209_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4) +#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16209_ERROR_ACTIVE BIT(14) + +#define ADIS16209_SCAN_SUPPLY 0 +#define ADIS16209_SCAN_ACC_X 1 +#define ADIS16209_SCAN_ACC_Y 2 +#define ADIS16209_SCAN_AUX_ADC 3 +#define ADIS16209_SCAN_TEMP 4 +#define ADIS16209_SCAN_INCLI_X 5 +#define ADIS16209_SCAN_INCLI_Y 6 +#define ADIS16209_SCAN_ROT 7 static const u8 adis16209_addresses[8][1] = { [ADIS16209_SCAN_SUPPLY] = { }, -- cgit v1.2.3 From aa04a7078b950e4c705ab6cf9080fb8d49c8d87c Mon Sep 17 00:00:00 2001 From: Narcisa Ana Maria Vasile Date: Sat, 4 Mar 2017 15:47:19 +0200 Subject: staging: iio: adis16240: Move contents of the header to the source file The contents of the header file are used only by this single source file. Move content into .c file and remove header. Signed-off-by: Narcisa Ana Maria Vasile Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/adis16240.h | 179 ----------------------------- drivers/staging/iio/accel/adis16240_core.c | 175 +++++++++++++++++++++++++++- 2 files changed, 174 insertions(+), 180 deletions(-) delete mode 100644 drivers/staging/iio/accel/adis16240.h diff --git a/drivers/staging/iio/accel/adis16240.h b/drivers/staging/iio/accel/adis16240.h deleted file mode 100644 index b2cb37b95913..000000000000 --- a/drivers/staging/iio/accel/adis16240.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef SPI_ADIS16240_H_ -#define SPI_ADIS16240_H_ - -#define ADIS16240_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16240_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16240_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16240_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16240_YACCL_OUT 0x06 - -/* Output, z-axis accelerometer */ -#define ADIS16240_ZACCL_OUT 0x08 - -/* Output, auxiliary ADC input */ -#define ADIS16240_AUX_ADC 0x0A - -/* Output, temperature */ -#define ADIS16240_TEMP_OUT 0x0C - -/* Output, x-axis acceleration peak */ -#define ADIS16240_XPEAK_OUT 0x0E - -/* Output, y-axis acceleration peak */ -#define ADIS16240_YPEAK_OUT 0x10 - -/* Output, z-axis acceleration peak */ -#define ADIS16240_ZPEAK_OUT 0x12 - -/* Output, sum-of-squares acceleration peak */ -#define ADIS16240_XYZPEAK_OUT 0x14 - -/* Output, Capture Buffer 1, X and Y acceleration */ -#define ADIS16240_CAPT_BUF1 0x16 - -/* Output, Capture Buffer 2, Z acceleration */ -#define ADIS16240_CAPT_BUF2 0x18 - -/* Diagnostic, error flags */ -#define ADIS16240_DIAG_STAT 0x1A - -/* Diagnostic, event counter */ -#define ADIS16240_EVNT_CNTR 0x1C - -/* Diagnostic, check sum value from firmware test */ -#define ADIS16240_CHK_SUM 0x1E - -/* Calibration, x-axis acceleration offset adjustment */ -#define ADIS16240_XACCL_OFF 0x20 - -/* Calibration, y-axis acceleration offset adjustment */ -#define ADIS16240_YACCL_OFF 0x22 - -/* Calibration, z-axis acceleration offset adjustment */ -#define ADIS16240_ZACCL_OFF 0x24 - -/* Clock, hour and minute */ -#define ADIS16240_CLK_TIME 0x2E - -/* Clock, month and day */ -#define ADIS16240_CLK_DATE 0x30 - -/* Clock, year */ -#define ADIS16240_CLK_YEAR 0x32 - -/* Wake-up setting, hour and minute */ -#define ADIS16240_WAKE_TIME 0x34 - -/* Wake-up setting, month and day */ -#define ADIS16240_WAKE_DATE 0x36 - -/* Alarm 1 amplitude threshold */ -#define ADIS16240_ALM_MAG1 0x38 - -/* Alarm 2 amplitude threshold */ -#define ADIS16240_ALM_MAG2 0x3A - -/* Alarm control */ -#define ADIS16240_ALM_CTRL 0x3C - -/* Capture, external trigger control */ -#define ADIS16240_XTRIG_CTRL 0x3E - -/* Capture, address pointer */ -#define ADIS16240_CAPT_PNTR 0x40 - -/* Capture, configuration and control */ -#define ADIS16240_CAPT_CTRL 0x42 - -/* General-purpose digital input/output control */ -#define ADIS16240_GPIO_CTRL 0x44 - -/* Miscellaneous control */ -#define ADIS16240_MSC_CTRL 0x46 - -/* Internal sample period (rate) control */ -#define ADIS16240_SMPL_PRD 0x48 - -/* System command */ -#define ADIS16240_GLOB_CMD 0x4A - -/* MSC_CTRL */ - -/* Enables sum-of-squares output (XYZPEAK_OUT) */ -#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN BIT(15) - -/* Enables peak tracking output (XPEAK_OUT, YPEAK_OUT, and ZPEAK_OUT) */ -#define ADIS16240_MSC_CTRL_X_Y_ZPEAK_OUT_EN BIT(14) - -/* Self-test enable: 1 = apply electrostatic force, 0 = disabled */ -#define ADIS16240_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16240_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16240_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ -#define ADIS16240_MSC_CTRL_DATA_RDY_DIO2 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16240_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16240_DIAG_STAT_ALARM1 BIT(8) - -/* Capture buffer full: 1 = capture buffer is full */ -#define ADIS16240_DIAG_STAT_CPT_BUF_FUL BIT(7) - -/* Flash test, checksum flag: 1 = mismatch, 0 = match */ -#define ADIS16240_DIAG_STAT_CHKSUM BIT(6) - -/* Power-on, self-test flag: 1 = failure, 0 = pass */ -#define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT 5 - -/* Power-on self-test: 1 = in-progress, 0 = complete */ -#define ADIS16240_DIAG_STAT_PWRON_BUSY BIT(4) - -/* SPI communications failure */ -#define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16240_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1 - - /* Power supply below 3.15 V */ -#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16240_GLOB_CMD_RESUME BIT(8) -#define ADIS16240_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16240_GLOB_CMD_STANDBY BIT(2) - -#define ADIS16240_ERROR_ACTIVE BIT(14) - -/* At the moment triggers are only used for ring buffer - * filling. This may change! - */ - -#define ADIS16240_SCAN_ACC_X 0 -#define ADIS16240_SCAN_ACC_Y 1 -#define ADIS16240_SCAN_ACC_Z 2 -#define ADIS16240_SCAN_SUPPLY 3 -#define ADIS16240_SCAN_AUX_ADC 4 -#define ADIS16240_SCAN_TEMP 5 - -#endif /* SPI_ADIS16240_H_ */ diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index e1bc9fcb7852..27d7f6ad8c4c 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -24,7 +24,180 @@ #include #include -#include "adis16240.h" +#define ADIS16240_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16240_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16240_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16240_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16240_YACCL_OUT 0x06 + +/* Output, z-axis accelerometer */ +#define ADIS16240_ZACCL_OUT 0x08 + +/* Output, auxiliary ADC input */ +#define ADIS16240_AUX_ADC 0x0A + +/* Output, temperature */ +#define ADIS16240_TEMP_OUT 0x0C + +/* Output, x-axis acceleration peak */ +#define ADIS16240_XPEAK_OUT 0x0E + +/* Output, y-axis acceleration peak */ +#define ADIS16240_YPEAK_OUT 0x10 + +/* Output, z-axis acceleration peak */ +#define ADIS16240_ZPEAK_OUT 0x12 + +/* Output, sum-of-squares acceleration peak */ +#define ADIS16240_XYZPEAK_OUT 0x14 + +/* Output, Capture Buffer 1, X and Y acceleration */ +#define ADIS16240_CAPT_BUF1 0x16 + +/* Output, Capture Buffer 2, Z acceleration */ +#define ADIS16240_CAPT_BUF2 0x18 + +/* Diagnostic, error flags */ +#define ADIS16240_DIAG_STAT 0x1A + +/* Diagnostic, event counter */ +#define ADIS16240_EVNT_CNTR 0x1C + +/* Diagnostic, check sum value from firmware test */ +#define ADIS16240_CHK_SUM 0x1E + +/* Calibration, x-axis acceleration offset adjustment */ +#define ADIS16240_XACCL_OFF 0x20 + +/* Calibration, y-axis acceleration offset adjustment */ +#define ADIS16240_YACCL_OFF 0x22 + +/* Calibration, z-axis acceleration offset adjustment */ +#define ADIS16240_ZACCL_OFF 0x24 + +/* Clock, hour and minute */ +#define ADIS16240_CLK_TIME 0x2E + +/* Clock, month and day */ +#define ADIS16240_CLK_DATE 0x30 + +/* Clock, year */ +#define ADIS16240_CLK_YEAR 0x32 + +/* Wake-up setting, hour and minute */ +#define ADIS16240_WAKE_TIME 0x34 + +/* Wake-up setting, month and day */ +#define ADIS16240_WAKE_DATE 0x36 + +/* Alarm 1 amplitude threshold */ +#define ADIS16240_ALM_MAG1 0x38 + +/* Alarm 2 amplitude threshold */ +#define ADIS16240_ALM_MAG2 0x3A + +/* Alarm control */ +#define ADIS16240_ALM_CTRL 0x3C + +/* Capture, external trigger control */ +#define ADIS16240_XTRIG_CTRL 0x3E + +/* Capture, address pointer */ +#define ADIS16240_CAPT_PNTR 0x40 + +/* Capture, configuration and control */ +#define ADIS16240_CAPT_CTRL 0x42 + +/* General-purpose digital input/output control */ +#define ADIS16240_GPIO_CTRL 0x44 + +/* Miscellaneous control */ +#define ADIS16240_MSC_CTRL 0x46 + +/* Internal sample period (rate) control */ +#define ADIS16240_SMPL_PRD 0x48 + +/* System command */ +#define ADIS16240_GLOB_CMD 0x4A + +/* MSC_CTRL */ + +/* Enables sum-of-squares output (XYZPEAK_OUT) */ +#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN BIT(15) + +/* Enables peak tracking output (XPEAK_OUT, YPEAK_OUT, and ZPEAK_OUT) */ +#define ADIS16240_MSC_CTRL_X_Y_ZPEAK_OUT_EN BIT(14) + +/* Self-test enable: 1 = apply electrostatic force, 0 = disabled */ +#define ADIS16240_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16240_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16240_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ +#define ADIS16240_MSC_CTRL_DATA_RDY_DIO2 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16240_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16240_DIAG_STAT_ALARM1 BIT(8) + +/* Capture buffer full: 1 = capture buffer is full */ +#define ADIS16240_DIAG_STAT_CPT_BUF_FUL BIT(7) + +/* Flash test, checksum flag: 1 = mismatch, 0 = match */ +#define ADIS16240_DIAG_STAT_CHKSUM BIT(6) + +/* Power-on, self-test flag: 1 = failure, 0 = pass */ +#define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT 5 + +/* Power-on self-test: 1 = in-progress, 0 = complete */ +#define ADIS16240_DIAG_STAT_PWRON_BUSY BIT(4) + +/* SPI communications failure */ +#define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16240_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1 + + /* Power supply below 3.15 V */ +#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16240_GLOB_CMD_RESUME BIT(8) +#define ADIS16240_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16240_GLOB_CMD_STANDBY BIT(2) + +#define ADIS16240_ERROR_ACTIVE BIT(14) + +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +#define ADIS16240_SCAN_ACC_X 0 +#define ADIS16240_SCAN_ACC_Y 1 +#define ADIS16240_SCAN_ACC_Z 2 +#define ADIS16240_SCAN_SUPPLY 3 +#define ADIS16240_SCAN_AUX_ADC 4 +#define ADIS16240_SCAN_TEMP 5 static ssize_t adis16240_spi_read_signed(struct device *dev, struct device_attribute *attr, -- cgit v1.2.3 From a70b93bcb36ffe0844b7b4ca33e5c5234f629006 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sat, 4 Mar 2017 16:31:23 +0800 Subject: dt-bindings: iio: accel: Document ADXL345 accelerometer binding Add the device tree binding documentation for the ADXL345 3-axis digital accelerometer. Signed-off-by: Eva Rachel Retuya Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/accel/adxl345.txt | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/adxl345.txt diff --git a/Documentation/devicetree/bindings/iio/accel/adxl345.txt b/Documentation/devicetree/bindings/iio/accel/adxl345.txt new file mode 100644 index 000000000000..e7111b02c02c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/accel/adxl345.txt @@ -0,0 +1,38 @@ +Analog Devices ADXL345 3-Axis, +/-(2g/4g/8g/16g) Digital Accelerometer + +http://www.analog.com/en/products/mems/accelerometers/adxl345.html + +Required properties: + - compatible : should be "adi,adxl345" + - reg : the I2C address or SPI chip select number of the sensor + +Required properties for SPI bus usage: + - spi-max-frequency : set maximum clock frequency, must be 5000000 + - spi-cpol and spi-cpha : must be defined for adxl345 to enable SPI mode 3 + +Optional properties: + - interrupt-parent : phandle to the parent interrupt controller as documented + in Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + - interrupts: interrupt mapping for IRQ as documented in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example for a I2C device node: + + accelerometer@2a { + compatible = "adi,adxl345"; + reg = <0x53>; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + +Example for a SPI device node: + + accelerometer@0 { + compatible = "adi,adxl345"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; -- cgit v1.2.3 From 31fd2c70b26d1fb803283c0488e3f84a2de1f329 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sat, 4 Mar 2017 16:31:24 +0800 Subject: iio: accel: adxl345: Use I2C regmap instead of direct I2C access Convert the driver to use regmap instead of I2C-specific functions. This is done in preparation for splitting this driver into core and I2C-specific code as well as introduction of SPI driver. Signed-off-by: Eva Rachel Retuya Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 1 + drivers/iio/accel/adxl345.c | 66 +++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2308bac21c17..26b86149f20b 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -9,6 +9,7 @@ config ADXL345 tristate "Analog Devices ADXL345 3-Axis Digital Accelerometer Driver" depends on !(INPUT_ADXL34X=y || INPUT_ADXL34X=m) depends on I2C + select REGMAP_I2C help Say Y here if you want to build support for the Analog Devices ADXL345 3-axis digital accelerometer. diff --git a/drivers/iio/accel/adxl345.c b/drivers/iio/accel/adxl345.c index c34991fd5c51..87fdd9f45958 100644 --- a/drivers/iio/accel/adxl345.c +++ b/drivers/iio/accel/adxl345.c @@ -14,6 +14,7 @@ #include #include +#include #include @@ -45,10 +46,15 @@ static const int adxl345_uscale = 38300; struct adxl345_data { - struct i2c_client *client; + struct regmap *regmap; u8 data_range; }; +static const struct regmap_config adxl345_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + #define ADXL345_CHANNEL(reg, axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -69,6 +75,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct adxl345_data *data = iio_priv(indio_dev); + __le16 regval; int ret; switch (mask) { @@ -78,11 +85,12 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte */ - ret = i2c_smbus_read_word_data(data->client, chan->address); + ret = regmap_bulk_read(data->regmap, chan->address, ®val, + sizeof(regval)); if (ret < 0) return ret; - *val = sign_extend32(ret, 12); + *val = sign_extend32(le16_to_cpu(regval), 12); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; @@ -104,37 +112,50 @@ static int adxl345_probe(struct i2c_client *client, { struct adxl345_data *data; struct iio_dev *indio_dev; + struct regmap *regmap; + struct device *dev; + u32 regval; int ret; - ret = i2c_smbus_read_byte_data(client, ADXL345_REG_DEVID); + regmap = devm_regmap_init_i2c(client, &adxl345_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Error initializing regmap: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + dev = regmap_get_device(regmap); + + ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); if (ret < 0) { - dev_err(&client->dev, "Error reading device ID: %d\n", ret); + dev_err(dev, "Error reading device ID: %d\n", ret); return ret; } - if (ret != ADXL345_DEVID) { - dev_err(&client->dev, "Invalid device ID: %d\n", ret); + if (regval != ADXL345_DEVID) { + dev_err(dev, "Invalid device ID: %x, expected %x\n", + regval, ADXL345_DEVID); return -ENODEV; } - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - data->client = client; + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; /* Enable full-resolution mode */ data->data_range = ADXL345_DATA_FORMAT_FULL_RES; - ret = i2c_smbus_write_byte_data(data->client, ADXL345_REG_DATA_FORMAT, - data->data_range); + ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, + data->data_range); if (ret < 0) { - dev_err(&client->dev, "Failed to set data range: %d\n", ret); + dev_err(dev, "Failed to set data range: %d\n", ret); return ret; } - indio_dev->dev.parent = &client->dev; + indio_dev->dev.parent = dev; indio_dev->name = id->name; indio_dev->info = &adxl345_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -142,19 +163,18 @@ static int adxl345_probe(struct i2c_client *client, indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); /* Enable measurement mode */ - ret = i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_MEASURE); + ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_MEASURE); if (ret < 0) { - dev_err(&client->dev, "Failed to enable measurement mode: %d\n", - ret); + dev_err(dev, "Failed to enable measurement mode: %d\n", ret); return ret; } ret = iio_device_register(indio_dev); if (ret < 0) { - dev_err(&client->dev, "iio_device_register failed: %d\n", ret); - i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); + dev_err(dev, "iio_device_register failed: %d\n", ret); + regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); } return ret; @@ -167,8 +187,8 @@ static int adxl345_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - return i2c_smbus_write_byte_data(data->client, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); + return regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); } static const struct i2c_device_id adxl345_i2c_id[] = { -- cgit v1.2.3 From 5170512cf6a17373b3a8bb63187a6e90ddf7c1ca Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sat, 4 Mar 2017 16:31:25 +0800 Subject: iio: accel: adxl345: Split driver into core and I2C Move I2C-specific code into its own file and rely on regmap to access registers. The core code provides access to x, y, z and scale readings. Signed-off-by: Eva Rachel Retuya Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 13 ++- drivers/iio/accel/Makefile | 3 +- drivers/iio/accel/adxl345.c | 214 --------------------------------------- drivers/iio/accel/adxl345.h | 18 ++++ drivers/iio/accel/adxl345_core.c | 179 ++++++++++++++++++++++++++++++++ drivers/iio/accel/adxl345_i2c.c | 73 +++++++++++++ 6 files changed, 281 insertions(+), 219 deletions(-) delete mode 100644 drivers/iio/accel/adxl345.c create mode 100644 drivers/iio/accel/adxl345.h create mode 100644 drivers/iio/accel/adxl345_core.c create mode 100644 drivers/iio/accel/adxl345_i2c.c diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 26b86149f20b..a725227aa7ca 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -6,16 +6,21 @@ menu "Accelerometers" config ADXL345 - tristate "Analog Devices ADXL345 3-Axis Digital Accelerometer Driver" - depends on !(INPUT_ADXL34X=y || INPUT_ADXL34X=m) + tristate + +config ADXL345_I2C + tristate "Analog Devices ADXL345 3-Axis Digital Accelerometer I2C Driver" + depends on INPUT_ADXL34X=n depends on I2C + select ADXL345 select REGMAP_I2C help Say Y here if you want to build support for the Analog Devices ADXL345 3-axis digital accelerometer. - To compile this driver as a module, choose M here: the - module will be called adxl345. + To compile this driver as a module, choose M here: the module + will be called adxl345_i2c and you will also get adxl345_core + for the core module. config BMA180 tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 618488de1161..3f4a6d62d84c 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -3,7 +3,8 @@ # # When adding new entries keep the list in alphabetical order -obj-$(CONFIG_ADXL345) += adxl345.o +obj-$(CONFIG_ADXL345) += adxl345_core.o +obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o diff --git a/drivers/iio/accel/adxl345.c b/drivers/iio/accel/adxl345.c deleted file mode 100644 index 87fdd9f45958..000000000000 --- a/drivers/iio/accel/adxl345.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * ADXL345 3-Axis Digital Accelerometer - * - * Copyright (c) 2017 Eva Rachel Retuya - * - * This file is subject to the terms and conditions of version 2 of - * the GNU General Public License. See the file COPYING in the main - * directory of this archive for more details. - * - * IIO driver for ADXL345 - * 7-bit I2C slave address: 0x1D (ALT ADDRESS pin tied to VDDIO) or - * 0x53 (ALT ADDRESS pin grounded) - */ - -#include -#include -#include - -#include - -#define ADXL345_REG_DEVID 0x00 -#define ADXL345_REG_POWER_CTL 0x2D -#define ADXL345_REG_DATA_FORMAT 0x31 -#define ADXL345_REG_DATAX0 0x32 -#define ADXL345_REG_DATAY0 0x34 -#define ADXL345_REG_DATAZ0 0x36 - -#define ADXL345_POWER_CTL_MEASURE BIT(3) -#define ADXL345_POWER_CTL_STANDBY 0x00 - -#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ -#define ADXL345_DATA_FORMAT_2G 0 -#define ADXL345_DATA_FORMAT_4G 1 -#define ADXL345_DATA_FORMAT_8G 2 -#define ADXL345_DATA_FORMAT_16G 3 - -#define ADXL345_DEVID 0xE5 - -/* - * In full-resolution mode, scale factor is maintained at ~4 mg/LSB - * in all g ranges. - * - * At +/- 16g with 13-bit resolution, scale is computed as: - * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 - */ -static const int adxl345_uscale = 38300; - -struct adxl345_data { - struct regmap *regmap; - u8 data_range; -}; - -static const struct regmap_config adxl345_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -#define ADXL345_CHANNEL(reg, axis) { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .address = reg, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ -} - -static const struct iio_chan_spec adxl345_channels[] = { - ADXL345_CHANNEL(ADXL345_REG_DATAX0, X), - ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y), - ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z), -}; - -static int adxl345_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct adxl345_data *data = iio_priv(indio_dev); - __le16 regval; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - /* - * Data is stored in adjacent registers: - * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte - * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte - */ - ret = regmap_bulk_read(data->regmap, chan->address, ®val, - sizeof(regval)); - if (ret < 0) - return ret; - - *val = sign_extend32(le16_to_cpu(regval), 12); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = adxl345_uscale; - - return IIO_VAL_INT_PLUS_MICRO; - } - - return -EINVAL; -} - -static const struct iio_info adxl345_info = { - .driver_module = THIS_MODULE, - .read_raw = adxl345_read_raw, -}; - -static int adxl345_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct adxl345_data *data; - struct iio_dev *indio_dev; - struct regmap *regmap; - struct device *dev; - u32 regval; - int ret; - - regmap = devm_regmap_init_i2c(client, &adxl345_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "Error initializing regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } - - dev = regmap_get_device(regmap); - - ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); - if (ret < 0) { - dev_err(dev, "Error reading device ID: %d\n", ret); - return ret; - } - - if (regval != ADXL345_DEVID) { - dev_err(dev, "Invalid device ID: %x, expected %x\n", - regval, ADXL345_DEVID); - return -ENODEV; - } - - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); - data->regmap = regmap; - /* Enable full-resolution mode */ - data->data_range = ADXL345_DATA_FORMAT_FULL_RES; - - ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, - data->data_range); - if (ret < 0) { - dev_err(dev, "Failed to set data range: %d\n", ret); - return ret; - } - - indio_dev->dev.parent = dev; - indio_dev->name = id->name; - indio_dev->info = &adxl345_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = adxl345_channels; - indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); - - /* Enable measurement mode */ - ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_MEASURE); - if (ret < 0) { - dev_err(dev, "Failed to enable measurement mode: %d\n", ret); - return ret; - } - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(dev, "iio_device_register failed: %d\n", ret); - regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); - } - - return ret; -} - -static int adxl345_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct adxl345_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - return regmap_write(data->regmap, ADXL345_REG_POWER_CTL, - ADXL345_POWER_CTL_STANDBY); -} - -static const struct i2c_device_id adxl345_i2c_id[] = { - { "adxl345", 0 }, - { } -}; - -MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); - -static struct i2c_driver adxl345_driver = { - .driver = { - .name = "adxl345", - }, - .probe = adxl345_probe, - .remove = adxl345_remove, - .id_table = adxl345_i2c_id, -}; - -module_i2c_driver(adxl345_driver); - -MODULE_AUTHOR("Eva Rachel Retuya "); -MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h new file mode 100644 index 000000000000..c1ddf3927c47 --- /dev/null +++ b/drivers/iio/accel/adxl345.h @@ -0,0 +1,18 @@ +/* + * ADXL345 3-Axis Digital Accelerometer + * + * Copyright (c) 2017 Eva Rachel Retuya + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + */ + +#ifndef _ADXL345_H_ +#define _ADXL345_H_ + +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + const char *name); +int adxl345_core_remove(struct device *dev); + +#endif /* _ADXL345_H_ */ diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c new file mode 100644 index 000000000000..9ccb5828db98 --- /dev/null +++ b/drivers/iio/accel/adxl345_core.c @@ -0,0 +1,179 @@ +/* + * ADXL345 3-Axis Digital Accelerometer IIO core driver + * + * Copyright (c) 2017 Eva Rachel Retuya + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + */ + +#include +#include + +#include + +#include "adxl345.h" + +#define ADXL345_REG_DEVID 0x00 +#define ADXL345_REG_POWER_CTL 0x2D +#define ADXL345_REG_DATA_FORMAT 0x31 +#define ADXL345_REG_DATAX0 0x32 +#define ADXL345_REG_DATAY0 0x34 +#define ADXL345_REG_DATAZ0 0x36 + +#define ADXL345_POWER_CTL_MEASURE BIT(3) +#define ADXL345_POWER_CTL_STANDBY 0x00 + +#define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */ +#define ADXL345_DATA_FORMAT_2G 0 +#define ADXL345_DATA_FORMAT_4G 1 +#define ADXL345_DATA_FORMAT_8G 2 +#define ADXL345_DATA_FORMAT_16G 3 + +#define ADXL345_DEVID 0xE5 + +/* + * In full-resolution mode, scale factor is maintained at ~4 mg/LSB + * in all g ranges. + * + * At +/- 16g with 13-bit resolution, scale is computed as: + * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383 + */ +static const int adxl345_uscale = 38300; + +struct adxl345_data { + struct regmap *regmap; + u8 data_range; +}; + +#define ADXL345_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .address = reg, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec adxl345_channels[] = { + ADXL345_CHANNEL(ADXL345_REG_DATAX0, X), + ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y), + ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z), +}; + +static int adxl345_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adxl345_data *data = iio_priv(indio_dev); + __le16 regval; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * Data is stored in adjacent registers: + * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte + * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte + */ + ret = regmap_bulk_read(data->regmap, chan->address, ®val, + sizeof(regval)); + if (ret < 0) + return ret; + + *val = sign_extend32(le16_to_cpu(regval), 12); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = adxl345_uscale; + + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +static const struct iio_info adxl345_info = { + .driver_module = THIS_MODULE, + .read_raw = adxl345_read_raw, +}; + +int adxl345_core_probe(struct device *dev, struct regmap *regmap, + const char *name) +{ + struct adxl345_data *data; + struct iio_dev *indio_dev; + u32 regval; + int ret; + + ret = regmap_read(regmap, ADXL345_REG_DEVID, ®val); + if (ret < 0) { + dev_err(dev, "Error reading device ID: %d\n", ret); + return ret; + } + + if (regval != ADXL345_DEVID) { + dev_err(dev, "Invalid device ID: %x, expected %x\n", + regval, ADXL345_DEVID); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + /* Enable full-resolution mode */ + data->data_range = ADXL345_DATA_FORMAT_FULL_RES; + + ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT, + data->data_range); + if (ret < 0) { + dev_err(dev, "Failed to set data range: %d\n", ret); + return ret; + } + + indio_dev->dev.parent = dev; + indio_dev->name = name; + indio_dev->info = &adxl345_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adxl345_channels; + indio_dev->num_channels = ARRAY_SIZE(adxl345_channels); + + /* Enable measurement mode */ + ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_MEASURE); + if (ret < 0) { + dev_err(dev, "Failed to enable measurement mode: %d\n", ret); + return ret; + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(dev, "iio_device_register failed: %d\n", ret); + regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); + } + + return ret; +} +EXPORT_SYMBOL_GPL(adxl345_core_probe); + +int adxl345_core_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct adxl345_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + return regmap_write(data->regmap, ADXL345_REG_POWER_CTL, + ADXL345_POWER_CTL_STANDBY); +} +EXPORT_SYMBOL_GPL(adxl345_core_remove); + +MODULE_AUTHOR("Eva Rachel Retuya "); +MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c new file mode 100644 index 000000000000..05e1ec49700c --- /dev/null +++ b/drivers/iio/accel/adxl345_i2c.c @@ -0,0 +1,73 @@ +/* + * ADXL345 3-Axis Digital Accelerometer I2C driver + * + * Copyright (c) 2017 Eva Rachel Retuya + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * 7-bit I2C slave address: 0x1D (ALT ADDRESS pin tied to VDDIO) or + * 0x53 (ALT ADDRESS pin grounded) + */ + +#include +#include +#include + +#include "adxl345.h" + +static const struct regmap_config adxl345_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int adxl345_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Error initializing i2c regmap: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return adxl345_core_probe(&client->dev, regmap, id ? id->name : NULL); +} + +static int adxl345_i2c_remove(struct i2c_client *client) +{ + return adxl345_core_remove(&client->dev); +} + +static const struct i2c_device_id adxl345_i2c_id[] = { + { "adxl345", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id); + +static const struct of_device_id adxl345_of_match[] = { + { .compatible = "adi,adxl345" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adxl345_of_match); + +static struct i2c_driver adxl345_i2c_driver = { + .driver = { + .name = "adxl345_i2c", + .of_match_table = adxl345_of_match, + }, + .probe = adxl345_i2c_probe, + .remove = adxl345_i2c_remove, + .id_table = adxl345_i2c_id, +}; + +module_i2c_driver(adxl345_i2c_driver); + +MODULE_AUTHOR("Eva Rachel Retuya "); +MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer I2C driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From fb0e5250a8a11d5a923c396704ae53b4e35a1da3 Mon Sep 17 00:00:00 2001 From: Eva Rachel Retuya Date: Sat, 4 Mar 2017 16:31:26 +0800 Subject: iio: accel: adxl345: Add SPI support Add SPI driver that initializes SPI regmap for the adxl345 core driver. The driver supports the same functionality as I2C namely the x, y, z and scale readings. Signed-off-by: Eva Rachel Retuya Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 14 +++++++ drivers/iio/accel/Makefile | 1 + drivers/iio/accel/adxl345_spi.c | 81 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 drivers/iio/accel/adxl345_spi.c diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index a725227aa7ca..15de262015df 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -22,6 +22,20 @@ config ADXL345_I2C will be called adxl345_i2c and you will also get adxl345_core for the core module. +config ADXL345_SPI + tristate "Analog Devices ADXL345 3-Axis Digital Accelerometer SPI Driver" + depends on INPUT_ADXL34X=n + depends on SPI + select ADXL345 + select REGMAP_SPI + help + Say Y here if you want to build support for the Analog Devices + ADXL345 3-axis digital accelerometer. + + To compile this driver as a module, choose M here: the module + will be called adxl345_spi and you will also get adxl345_core + for the core module. + config BMA180 tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 3f4a6d62d84c..31fba1974e95 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADXL345) += adxl345_core.o obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o +obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c new file mode 100644 index 000000000000..6d658196f81c --- /dev/null +++ b/drivers/iio/accel/adxl345_spi.c @@ -0,0 +1,81 @@ +/* + * ADXL345 3-Axis Digital Accelerometer SPI driver + * + * Copyright (c) 2017 Eva Rachel Retuya + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + */ + +#include +#include +#include + +#include "adxl345.h" + +#define ADXL345_MAX_SPI_FREQ_HZ 5000000 + +static const struct regmap_config adxl345_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + /* Setting bits 7 and 6 enables multiple-byte read */ + .read_flag_mask = BIT(7) | BIT(6), +}; + +static int adxl345_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct regmap *regmap; + + /* Bail out if max_speed_hz exceeds 5 MHz */ + if (spi->max_speed_hz > ADXL345_MAX_SPI_FREQ_HZ) { + dev_err(&spi->dev, "SPI CLK, %d Hz exceeds 5 MHz\n", + spi->max_speed_hz); + return -EINVAL; + } + + regmap = devm_regmap_init_spi(spi, &adxl345_spi_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return adxl345_core_probe(&spi->dev, regmap, id->name); +} + +static int adxl345_spi_remove(struct spi_device *spi) +{ + return adxl345_core_remove(&spi->dev); +} + +static const struct spi_device_id adxl345_spi_id[] = { + { "adxl345", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(spi, adxl345_spi_id); + +static const struct of_device_id adxl345_of_match[] = { + { .compatible = "adi,adxl345" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adxl345_of_match); + +static struct spi_driver adxl345_spi_driver = { + .driver = { + .name = "adxl345_spi", + .of_match_table = adxl345_of_match, + }, + .probe = adxl345_spi_probe, + .remove = adxl345_spi_remove, + .id_table = adxl345_spi_id, +}; + +module_spi_driver(adxl345_spi_driver); + +MODULE_AUTHOR("Eva Rachel Retuya "); +MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer SPI driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 63a98d2511e2d2fb6fb305c0093ad8a066c43d08 Mon Sep 17 00:00:00 2001 From: Katie Dunne Date: Fri, 3 Mar 2017 07:35:52 -0800 Subject: staging: iio: meter: ade7753: Move header content to implementation file The contents of ade7753.h are only used in ade7753.c. Move the header contents to the implementation file and delete the header file. Signed-off-by: Katie Dunne Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7753.c | 69 ++++++++++++++++++++++++++++++++++- drivers/staging/iio/meter/ade7753.h | 72 ------------------------------------- 2 files changed, 68 insertions(+), 73 deletions(-) delete mode 100644 drivers/staging/iio/meter/ade7753.h diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 671dc9971610..063ff2789b71 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -21,7 +21,74 @@ #include #include #include "meter.h" -#include "ade7753.h" + +#define ADE7753_WAVEFORM 0x01 +#define ADE7753_AENERGY 0x02 +#define ADE7753_RAENERGY 0x03 +#define ADE7753_LAENERGY 0x04 +#define ADE7753_VAENERGY 0x05 +#define ADE7753_RVAENERGY 0x06 +#define ADE7753_LVAENERGY 0x07 +#define ADE7753_LVARENERGY 0x08 +#define ADE7753_MODE 0x09 +#define ADE7753_IRQEN 0x0A +#define ADE7753_STATUS 0x0B +#define ADE7753_RSTSTATUS 0x0C +#define ADE7753_CH1OS 0x0D +#define ADE7753_CH2OS 0x0E +#define ADE7753_GAIN 0x0F +#define ADE7753_PHCAL 0x10 +#define ADE7753_APOS 0x11 +#define ADE7753_WGAIN 0x12 +#define ADE7753_WDIV 0x13 +#define ADE7753_CFNUM 0x14 +#define ADE7753_CFDEN 0x15 +#define ADE7753_IRMS 0x16 +#define ADE7753_VRMS 0x17 +#define ADE7753_IRMSOS 0x18 +#define ADE7753_VRMSOS 0x19 +#define ADE7753_VAGAIN 0x1A +#define ADE7753_VADIV 0x1B +#define ADE7753_LINECYC 0x1C +#define ADE7753_ZXTOUT 0x1D +#define ADE7753_SAGCYC 0x1E +#define ADE7753_SAGLVL 0x1F +#define ADE7753_IPKLVL 0x20 +#define ADE7753_VPKLVL 0x21 +#define ADE7753_IPEAK 0x22 +#define ADE7753_RSTIPEAK 0x23 +#define ADE7753_VPEAK 0x24 +#define ADE7753_RSTVPEAK 0x25 +#define ADE7753_TEMP 0x26 +#define ADE7753_PERIOD 0x27 +#define ADE7753_TMODE 0x3D +#define ADE7753_CHKSUM 0x3E +#define ADE7753_DIEREV 0x3F + +#define ADE7753_READ_REG(a) a +#define ADE7753_WRITE_REG(a) ((a) | 0x80) + +#define ADE7753_MAX_TX 4 +#define ADE7753_MAX_RX 4 +#define ADE7753_STARTUP_DELAY 1000 + +#define ADE7753_SPI_SLOW (u32)(300 * 1000) +#define ADE7753_SPI_BURST (u32)(1000 * 1000) +#define ADE7753_SPI_FAST (u32)(2000 * 1000) + +/** + * struct ade7753_state - device instance specific data + * @us: actual spi_device + * @tx: transmit buffer + * @rx: receive buffer + * @buf_lock: mutex to protect tx and rx + **/ +struct ade7753_state { + struct spi_device *us; + struct mutex buf_lock; + u8 tx[ADE7753_MAX_TX] ____cacheline_aligned; + u8 rx[ADE7753_MAX_RX]; +}; static int ade7753_spi_write_reg_8(struct device *dev, u8 reg_address, diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h deleted file mode 100644 index bfe749156bce..000000000000 --- a/drivers/staging/iio/meter/ade7753.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _ADE7753_H -#define _ADE7753_H - -#define ADE7753_WAVEFORM 0x01 -#define ADE7753_AENERGY 0x02 -#define ADE7753_RAENERGY 0x03 -#define ADE7753_LAENERGY 0x04 -#define ADE7753_VAENERGY 0x05 -#define ADE7753_RVAENERGY 0x06 -#define ADE7753_LVAENERGY 0x07 -#define ADE7753_LVARENERGY 0x08 -#define ADE7753_MODE 0x09 -#define ADE7753_IRQEN 0x0A -#define ADE7753_STATUS 0x0B -#define ADE7753_RSTSTATUS 0x0C -#define ADE7753_CH1OS 0x0D -#define ADE7753_CH2OS 0x0E -#define ADE7753_GAIN 0x0F -#define ADE7753_PHCAL 0x10 -#define ADE7753_APOS 0x11 -#define ADE7753_WGAIN 0x12 -#define ADE7753_WDIV 0x13 -#define ADE7753_CFNUM 0x14 -#define ADE7753_CFDEN 0x15 -#define ADE7753_IRMS 0x16 -#define ADE7753_VRMS 0x17 -#define ADE7753_IRMSOS 0x18 -#define ADE7753_VRMSOS 0x19 -#define ADE7753_VAGAIN 0x1A -#define ADE7753_VADIV 0x1B -#define ADE7753_LINECYC 0x1C -#define ADE7753_ZXTOUT 0x1D -#define ADE7753_SAGCYC 0x1E -#define ADE7753_SAGLVL 0x1F -#define ADE7753_IPKLVL 0x20 -#define ADE7753_VPKLVL 0x21 -#define ADE7753_IPEAK 0x22 -#define ADE7753_RSTIPEAK 0x23 -#define ADE7753_VPEAK 0x24 -#define ADE7753_RSTVPEAK 0x25 -#define ADE7753_TEMP 0x26 -#define ADE7753_PERIOD 0x27 -#define ADE7753_TMODE 0x3D -#define ADE7753_CHKSUM 0x3E -#define ADE7753_DIEREV 0x3F - -#define ADE7753_READ_REG(a) a -#define ADE7753_WRITE_REG(a) ((a) | 0x80) - -#define ADE7753_MAX_TX 4 -#define ADE7753_MAX_RX 4 -#define ADE7753_STARTUP_DELAY 1000 - -#define ADE7753_SPI_SLOW (u32)(300 * 1000) -#define ADE7753_SPI_BURST (u32)(1000 * 1000) -#define ADE7753_SPI_FAST (u32)(2000 * 1000) - -/** - * struct ade7753_state - device instance specific data - * @us: actual spi_device - * @tx: transmit buffer - * @rx: receive buffer - * @buf_lock: mutex to protect tx and rx - **/ -struct ade7753_state { - struct spi_device *us; - struct mutex buf_lock; - u8 tx[ADE7753_MAX_TX] ____cacheline_aligned; - u8 rx[ADE7753_MAX_RX]; -}; - -#endif -- cgit v1.2.3 From 0f0c106aa95243c5e59f06fb447ed7ea89818be1 Mon Sep 17 00:00:00 2001 From: Katie Dunne Date: Fri, 3 Mar 2017 07:38:37 -0800 Subject: staging: iio: meter: ade7753: Clean up includes Alphabetize header files. Signed-off-by: Katie Dunne Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7753.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 063ff2789b71..dfd8b71d6a41 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -6,20 +6,19 @@ * Licensed under the GPL-2 or later. */ -#include -#include #include -#include #include +#include +#include #include -#include -#include -#include #include #include - +#include +#include +#include #include #include +#include #include "meter.h" #define ADE7753_WAVEFORM 0x01 -- cgit v1.2.3 From 59d0f2da35693bfbcf6ffb014213cb8e225c8928 Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Fri, 3 Mar 2017 21:44:32 +0800 Subject: iio: hid: Add temperature sensor support Environmental temperature sensor is a hid defined sensor, it measures temperature. More information can be found in: http://www.usb.org/developers/hidpage/HUTRR39b.pdf According to IIO ABI definition, IIO_TEMP data output unit is milli degrees Celsius. Add the unit convert from degree to milli degree. Signed-off-by: Song Hongyan Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- .../iio/common/hid-sensors/hid-sensor-attributes.c | 3 + drivers/iio/temperature/Kconfig | 14 + drivers/iio/temperature/Makefile | 1 + drivers/iio/temperature/hid-sensor-temperature.c | 311 +++++++++++++++++++++ include/linux/hid-sensor-ids.h | 4 + 5 files changed, 333 insertions(+) create mode 100644 drivers/iio/temperature/hid-sensor-temperature.c diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 7afdac42ed42..9338f94ce1dc 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -62,6 +62,9 @@ static struct { {HID_USAGE_SENSOR_TIME_TIMESTAMP, 0, 1000000000, 0}, {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND, 1000000, 0}, + + {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0}, + {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0}, }; static int pow_10(unsigned power) diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 3089e8d0a32d..5378976d6d27 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -19,6 +19,20 @@ config MAXIM_THERMOCOUPLE This driver can also be built as a module. If so, the module will be called maxim_thermocouple. +config HID_SENSOR_TEMP + tristate "HID Environmental temperature sensor" + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + help + Say yes here to build support for the HID SENSOR + temperature driver + + To compile this driver as a module, choose M here: the module + will be called hid-sensor-temperature. + config MLX90614 tristate "MLX90614 contact-less infrared sensor" depends on I2C diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 4c4377480726..ad1d668de546 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -2,6 +2,7 @@ # Makefile for industrial I/O temperature drivers # +obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o obj-$(CONFIG_MLX90614) += mlx90614.o obj-$(CONFIG_TMP006) += tmp006.o diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c new file mode 100644 index 000000000000..c01efeca4002 --- /dev/null +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -0,0 +1,311 @@ +/* + * HID Sensors Driver + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common/hid-sensors/hid-sensor-trigger.h" + +struct temperature_state { + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info temperature_attr; + s32 temperature_data; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; +}; + +/* Channel definitions */ +static const struct iio_chan_spec temperature_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + }, + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +/* Adjust channel real bits based on report descriptor */ +static void temperature_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is s32 */ + channels[channel].scan_type.storagebits = sizeof(s32) * 8; +} + +static int temperature_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct temperature_state *temp_st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_TEMP) + return -EINVAL; + hid_sensor_power_state( + &temp_st->common_attributes, true); + *val = sensor_hub_input_attr_get_raw_value( + temp_st->common_attributes.hsdev, + HID_USAGE_SENSOR_TEMPERATURE, + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, + temp_st->temperature_attr.report_id, + SENSOR_HUB_SYNC); + hid_sensor_power_state( + &temp_st->common_attributes, + false); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = temp_st->scale_pre_decml; + *val2 = temp_st->scale_post_decml; + return temp_st->scale_precision; + + case IIO_CHAN_INFO_OFFSET: + *val = temp_st->value_offset; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SAMP_FREQ: + return hid_sensor_read_samp_freq_value( + &temp_st->common_attributes, val, val2); + + case IIO_CHAN_INFO_HYSTERESIS: + return hid_sensor_read_raw_hyst_value( + &temp_st->common_attributes, val, val2); + default: + return -EINVAL; + } +} + +static int temperature_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct temperature_state *temp_st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return hid_sensor_write_samp_freq_value( + &temp_st->common_attributes, val, val2); + case IIO_CHAN_INFO_HYSTERESIS: + return hid_sensor_write_raw_hyst_value( + &temp_st->common_attributes, val, val2); + default: + return -EINVAL; + } +} + +static const struct iio_info temperature_info = { + .driver_module = THIS_MODULE, + .read_raw = &temperature_read_raw, + .write_raw = &temperature_write_raw, +}; + +/* Callback handler to send event after all samples are received and captured */ +static int temperature_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned int usage_id, void *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct temperature_state *temp_st = iio_priv(indio_dev); + + if (atomic_read(&temp_st->common_attributes.data_ready)) + iio_push_to_buffers_with_timestamp(indio_dev, + &temp_st->temperature_data, + iio_get_time_ns(indio_dev)); + + return 0; +} + +/* Capture samples in local storage */ +static int temperature_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned int usage_id, size_t raw_len, + char *raw_data, void *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct temperature_state *temp_st = iio_priv(indio_dev); + + switch (usage_id) { + case HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE: + temp_st->temperature_data = *(s32 *)raw_data; + return 0; + default: + return -EINVAL; + } +} + +/* Parse report which is specific to an usage id*/ +static int temperature_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned int usage_id, + struct temperature_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, + &st->temperature_attr); + if (ret < 0) + return ret; + + temperature_adjust_channel_bit_mask(channels, 0, + st->temperature_attr.size); + + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_TEMPERATURE, + &st->temperature_attr, + &st->scale_pre_decml, &st->scale_post_decml); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE, + &st->common_attributes.sensitivity); + + return ret; +} + +static struct hid_sensor_hub_callbacks temperature_callbacks = { + .send_event = &temperature_proc_event, + .capture_sample = &temperature_capture_sample, +}; + +/* Function to initialize the processing for usage id */ +static int hid_temperature_probe(struct platform_device *pdev) +{ + static const char *name = "temperature"; + struct iio_dev *indio_dev; + struct temperature_state *temp_st; + struct iio_chan_spec *temp_chans; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*temp_st)); + if (!indio_dev) + return -ENOMEM; + + temp_st = iio_priv(indio_dev); + temp_st->common_attributes.hsdev = hsdev; + temp_st->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_TEMPERATURE, + &temp_st->common_attributes); + if (ret) + return ret; + + temp_chans = devm_kmemdup(&indio_dev->dev, temperature_channels, + sizeof(temperature_channels), GFP_KERNEL); + if (!temp_chans) + return -ENOMEM; + + ret = temperature_parse_report(pdev, hsdev, temp_chans, + HID_USAGE_SENSOR_TEMPERATURE, temp_st); + if (ret) + return ret; + + indio_dev->channels = temp_chans; + indio_dev->num_channels = ARRAY_SIZE(temperature_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &temperature_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, + &iio_pollfunc_store_time, NULL, NULL); + if (ret) + return ret; + + atomic_set(&temp_st->common_attributes.data_ready, 0); + ret = hid_sensor_setup_trigger(indio_dev, name, + &temp_st->common_attributes); + if (ret) + return ret; + + platform_set_drvdata(pdev, indio_dev); + + temperature_callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE, + &temperature_callbacks); + if (ret) + goto error_remove_trigger; + + ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); + if (ret) + goto error_remove_callback; + + return ret; + +error_remove_callback: + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE); +error_remove_trigger: + hid_sensor_remove_trigger(&temp_st->common_attributes); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_temperature_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct temperature_state *temp_st = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TEMPERATURE); + hid_sensor_remove_trigger(&temp_st->common_attributes); + + return 0; +} + +static const struct platform_device_id hid_temperature_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200033", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_temperature_ids); + +static struct platform_driver hid_temperature_platform_driver = { + .id_table = hid_temperature_ids, + .driver = { + .name = "temperature-sensor", + .pm = &hid_sensor_pm_ops, + }, + .probe = hid_temperature_probe, + .remove = hid_temperature_remove, +}; +module_platform_driver(hid_temperature_platform_driver); + +MODULE_DESCRIPTION("HID Environmental temperature sensor"); +MODULE_AUTHOR("Song Hongyan "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 30c7dc45e45f..46dd1f27d2f2 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -45,6 +45,10 @@ #define HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE 0x200430 #define HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE 0x200431 +/* Tempreture (200033) */ +#define HID_USAGE_SENSOR_TEMPERATURE 0x200033 +#define HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE 0x200434 + /* Gyro 3D: (200076) */ #define HID_USAGE_SENSOR_GYRO_3D 0x200076 #define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456 -- cgit v1.2.3 From 521dbebf70189bdc7ee1830ea393c8a74fd24f21 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Wed, 1 Mar 2017 15:45:05 +0100 Subject: iio: Generalize counting direction modes Move counting direction documentation for 104-quad-8 to sysfs-bus-iio to avoid duplicated for other incoming drivers Signed-off-by: Benjamin Gaignard Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 14 ++++++++++++++ Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 | 8 -------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 7531d383be8c..8c24d0892f61 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1609,3 +1609,17 @@ Description: provides an absolute positional reference (e.g. a pulse once per revolution) which may be used to home positional systems as required. + +What: /sys/bus/iio/devices/iio:deviceX/in_count_count_direction_available +KernelVersion: 4.12 +Contact: linux-iio@vger.kernel.org +Description: + A list of possible counting directions which are: + - "up" : counter device is increasing. + - "down": counter device is decreasing. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_direction +KernelVersion: 4.12 +Contact: linux-iio@vger.kernel.org +Description: + Raw counter device counters direction for channel Y. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 index 5f4924a94949..7fac2c268d9a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 +++ b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 @@ -1,4 +1,3 @@ -What: /sys/bus/iio/devices/iio:deviceX/in_count_count_direction_available What: /sys/bus/iio/devices/iio:deviceX/in_count_count_mode_available What: /sys/bus/iio/devices/iio:deviceX/in_count_noise_error_available What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available @@ -10,13 +9,6 @@ Description: Discrete set of available values for the respective counter configuration are listed in this file. -What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_direction -KernelVersion: 4.10 -Contact: linux-iio@vger.kernel.org -Description: - Read-only attribute that indicates whether the counter for - channel Y is counting up or down. - What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode KernelVersion: 4.10 Contact: linux-iio@vger.kernel.org -- cgit v1.2.3 From 2df79e1bddc46ea6ce9746a171220c3f68e378da Mon Sep 17 00:00:00 2001 From: Narcisa Ana Maria Vasile Date: Sat, 4 Mar 2017 21:43:12 +0200 Subject: staging: iio: accel: Rename source files and update Makefile Rename adis162xx_core.c files to adis162xx.c because these are the only source files for these drivers. Update Makefile to correspond to the new file names. Signed-off-by: Narcisa Ana Maria Vasile rename drivers/staging/iio/accel/{adis16201_core.c => adis16201.c} (100%) rename drivers/staging/iio/accel/{adis16203_core.c => adis16203.c} (100%) rename drivers/staging/iio/accel/{adis16209_core.c => adis16209.c} (100%) rename drivers/staging/iio/accel/{adis16240_core.c => adis16240.c} (100%) Signed-off-by: Jonathan Cameron --- drivers/staging/iio/accel/Makefile | 7 - drivers/staging/iio/accel/adis16201.c | 386 +++++++++++++++++++++++ drivers/staging/iio/accel/adis16201_core.c | 386 ----------------------- drivers/staging/iio/accel/adis16203.c | 336 ++++++++++++++++++++ drivers/staging/iio/accel/adis16203_core.c | 336 -------------------- drivers/staging/iio/accel/adis16209.c | 386 +++++++++++++++++++++++ drivers/staging/iio/accel/adis16209_core.c | 386 ----------------------- drivers/staging/iio/accel/adis16240.c | 474 +++++++++++++++++++++++++++++ drivers/staging/iio/accel/adis16240_core.c | 474 ----------------------------- 9 files changed, 1582 insertions(+), 1589 deletions(-) create mode 100644 drivers/staging/iio/accel/adis16201.c delete mode 100644 drivers/staging/iio/accel/adis16201_core.c create mode 100644 drivers/staging/iio/accel/adis16203.c delete mode 100644 drivers/staging/iio/accel/adis16203_core.c create mode 100644 drivers/staging/iio/accel/adis16209.c delete mode 100644 drivers/staging/iio/accel/adis16209_core.c create mode 100644 drivers/staging/iio/accel/adis16240.c delete mode 100644 drivers/staging/iio/accel/adis16240_core.c diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index febb137b60c4..5d8ad21a0dae 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -2,14 +2,7 @@ # Makefile for industrial I/O accelerometer drivers # -adis16201-y := adis16201_core.o obj-$(CONFIG_ADIS16201) += adis16201.o - -adis16203-y := adis16203_core.o obj-$(CONFIG_ADIS16203) += adis16203.o - -adis16209-y := adis16209_core.o obj-$(CONFIG_ADIS16209) += adis16209.o - -adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o diff --git a/drivers/staging/iio/accel/adis16201.c b/drivers/staging/iio/accel/adis16201.c new file mode 100644 index 000000000000..d6c8658c88b9 --- /dev/null +++ b/drivers/staging/iio/accel/adis16201.c @@ -0,0 +1,386 @@ +/* + * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ADIS16201_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16201_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16201_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16201_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16201_YACCL_OUT 0x06 + +/* Output, auxiliary ADC input */ +#define ADIS16201_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16201_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16201_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16201_YINCL_OUT 0x0E + +/* Calibration, x-axis acceleration offset */ +#define ADIS16201_XACCL_OFFS 0x10 + +/* Calibration, y-axis acceleration offset */ +#define ADIS16201_YACCL_OFFS 0x12 + +/* x-axis acceleration scale factor */ +#define ADIS16201_XACCL_SCALE 0x14 + +/* y-axis acceleration scale factor */ +#define ADIS16201_YACCL_SCALE 0x16 + +/* Calibration, x-axis inclination offset */ +#define ADIS16201_XINCL_OFFS 0x18 + +/* Calibration, y-axis inclination offset */ +#define ADIS16201_YINCL_OFFS 0x1A + +/* x-axis inclination scale factor */ +#define ADIS16201_XINCL_SCALE 0x1C + +/* y-axis inclination scale factor */ +#define ADIS16201_YINCL_SCALE 0x1E + +/* Alarm 1 amplitude threshold */ +#define ADIS16201_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16201_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16201_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16201_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16201_ALM_CTRL 0x28 + +/* Auxiliary DAC data */ +#define ADIS16201_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16201_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16201_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16201_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16201_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16201_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16201_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16201_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test enable */ +#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ +#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) + +/* SPI communications failure */ +#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16201_ERROR_ACTIVE BIT(14) + +enum adis16201_scan { + ADIS16201_SCAN_ACC_X, + ADIS16201_SCAN_ACC_Y, + ADIS16201_SCAN_INCLI_X, + ADIS16201_SCAN_INCLI_Y, + ADIS16201_SCAN_SUPPLY, + ADIS16201_SCAN_AUX_ADC, + ADIS16201_SCAN_TEMP, +}; + +static const u8 adis16201_addresses[] = { + [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS, + [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS, + [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS, + [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS, +}; + +static int adis16201_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int ret; + int bits; + u8 addr; + s16 val16; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, + ADIS16201_ERROR_ACTIVE, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->channel == 0) { + *val = 1; + *val2 = 220000; /* 1.22 mV */ + } else { + *val = 0; + *val2 = 610000; /* 0.610 mV */ + } + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = -470; /* 0.47 C */ + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + *val = 0; + *val2 = IIO_G_TO_M_S_2(462400); /* 0.4624 mg */ + return IIO_VAL_INT_PLUS_NANO; + case IIO_INCLI: + *val = 0; + *val2 = 100000; /* 0.1 degree */ + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_OFFSET: + *val = 25000 / -470 - 1278; /* 25 C = 1278 */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + bits = 12; + break; + case IIO_INCLI: + bits = 9; + break; + default: + return -EINVAL; + } + mutex_lock(&indio_dev->mlock); + addr = adis16201_addresses[chan->scan_index]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + val16 &= (1 << bits) - 1; + val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); + *val = val16; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + } + return -EINVAL; +} + +static int adis16201_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int bits; + s16 val16; + u8 addr; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + bits = 12; + break; + case IIO_INCLI: + bits = 9; + break; + default: + return -EINVAL; + } + val16 = val & ((1 << bits) - 1); + addr = adis16201_addresses[chan->scan_index]; + return adis_write_reg_16(st, addr, val16); + } + return -EINVAL; +} + +static const struct iio_chan_spec adis16201_channels[] = { + ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12), + ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12), + ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + IIO_CHAN_SOFT_TIMESTAMP(7) +}; + +static const struct iio_info adis16201_info = { + .read_raw = &adis16201_read_raw, + .write_raw = &adis16201_write_raw, + .update_scan_mode = adis_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static const char * const adis16201_status_error_msgs[] = { + [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16201_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", + [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", +}; + +static const struct adis_data adis16201_data = { + .read_delay = 20, + .msc_ctrl_reg = ADIS16201_MSC_CTRL, + .glob_cmd_reg = ADIS16201_GLOB_CMD, + .diag_stat_reg = ADIS16201_DIAG_STAT, + + .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN, + .self_test_no_autoclear = true, + .startup_delay = ADIS16201_STARTUP_DELAY, + + .status_error_msgs = adis16201_status_error_msgs, + .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) | + BIT(ADIS16201_DIAG_STAT_FLASH_UPT_BIT) | + BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) | + BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT), +}; + +static int adis16201_probe(struct spi_device *spi) +{ + int ret; + struct adis *st; + struct iio_dev *indio_dev; + + /* setup the industrialio driver allocated elements */ + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + /* this is only used for removal purposes */ + spi_set_drvdata(spi, indio_dev); + + indio_dev->name = spi->dev.driver->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &adis16201_info; + + indio_dev->channels = adis16201_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16201_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(st, indio_dev, spi, &adis16201_data); + if (ret) + return ret; + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); + if (ret) + return ret; + + /* Get the device into a sane initial state */ + ret = adis_initial_startup(st); + if (ret) + goto error_cleanup_buffer_trigger; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto error_cleanup_buffer_trigger; + return 0; + +error_cleanup_buffer_trigger: + adis_cleanup_buffer_and_trigger(st, indio_dev); + return ret; +} + +static int adis16201_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis_cleanup_buffer_and_trigger(st, indio_dev); + + return 0; +} + +static struct spi_driver adis16201_driver = { + .driver = { + .name = "adis16201", + }, + .probe = adis16201_probe, + .remove = adis16201_remove, +}; +module_spi_driver(adis16201_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16201"); diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c deleted file mode 100644 index d6c8658c88b9..000000000000 --- a/drivers/staging/iio/accel/adis16201_core.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define ADIS16201_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16201_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16201_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16201_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16201_YACCL_OUT 0x06 - -/* Output, auxiliary ADC input */ -#define ADIS16201_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16201_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16201_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16201_YINCL_OUT 0x0E - -/* Calibration, x-axis acceleration offset */ -#define ADIS16201_XACCL_OFFS 0x10 - -/* Calibration, y-axis acceleration offset */ -#define ADIS16201_YACCL_OFFS 0x12 - -/* x-axis acceleration scale factor */ -#define ADIS16201_XACCL_SCALE 0x14 - -/* y-axis acceleration scale factor */ -#define ADIS16201_YACCL_SCALE 0x16 - -/* Calibration, x-axis inclination offset */ -#define ADIS16201_XINCL_OFFS 0x18 - -/* Calibration, y-axis inclination offset */ -#define ADIS16201_YINCL_OFFS 0x1A - -/* x-axis inclination scale factor */ -#define ADIS16201_XINCL_SCALE 0x1C - -/* y-axis inclination scale factor */ -#define ADIS16201_YINCL_SCALE 0x1E - -/* Alarm 1 amplitude threshold */ -#define ADIS16201_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16201_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16201_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16201_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16201_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16201_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16201_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16201_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16201_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16201_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16201_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16201_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16201_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test enable */ -#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ -#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) - -/* SPI communications failure */ -#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16201_ERROR_ACTIVE BIT(14) - -enum adis16201_scan { - ADIS16201_SCAN_ACC_X, - ADIS16201_SCAN_ACC_Y, - ADIS16201_SCAN_INCLI_X, - ADIS16201_SCAN_INCLI_Y, - ADIS16201_SCAN_SUPPLY, - ADIS16201_SCAN_AUX_ADC, - ADIS16201_SCAN_TEMP, -}; - -static const u8 adis16201_addresses[] = { - [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS, - [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS, - [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS, - [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS, -}; - -static int adis16201_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int ret; - int bits; - u8 addr; - s16 val16; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - return adis_single_conversion(indio_dev, chan, - ADIS16201_ERROR_ACTIVE, val); - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->channel == 0) { - *val = 1; - *val2 = 220000; /* 1.22 mV */ - } else { - *val = 0; - *val2 = 610000; /* 0.610 mV */ - } - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = -470; /* 0.47 C */ - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(462400); /* 0.4624 mg */ - return IIO_VAL_INT_PLUS_NANO; - case IIO_INCLI: - *val = 0; - *val2 = 100000; /* 0.1 degree */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_OFFSET: - *val = 25000 / -470 - 1278; /* 25 C = 1278 */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - bits = 12; - break; - case IIO_INCLI: - bits = 9; - break; - default: - return -EINVAL; - } - mutex_lock(&indio_dev->mlock); - addr = adis16201_addresses[chan->scan_index]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - } - return -EINVAL; -} - -static int adis16201_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int bits; - s16 val16; - u8 addr; - - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - bits = 12; - break; - case IIO_INCLI: - bits = 9; - break; - default: - return -EINVAL; - } - val16 = val & ((1 << bits) - 1); - addr = adis16201_addresses[chan->scan_index]; - return adis_write_reg_16(st, addr, val16); - } - return -EINVAL; -} - -static const struct iio_chan_spec adis16201_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12), - ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12), - ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 0, 12), - ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - IIO_CHAN_SOFT_TIMESTAMP(7) -}; - -static const struct iio_info adis16201_info = { - .read_raw = &adis16201_read_raw, - .write_raw = &adis16201_write_raw, - .update_scan_mode = adis_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static const char * const adis16201_status_error_msgs[] = { - [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16201_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", -}; - -static const struct adis_data adis16201_data = { - .read_delay = 20, - .msc_ctrl_reg = ADIS16201_MSC_CTRL, - .glob_cmd_reg = ADIS16201_GLOB_CMD, - .diag_stat_reg = ADIS16201_DIAG_STAT, - - .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN, - .self_test_no_autoclear = true, - .startup_delay = ADIS16201_STARTUP_DELAY, - - .status_error_msgs = adis16201_status_error_msgs, - .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16201_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT), -}; - -static int adis16201_probe(struct spi_device *spi) -{ - int ret; - struct adis *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16201_info; - - indio_dev->channels = adis16201_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16201_channels); - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(st, indio_dev, spi, &adis16201_data); - if (ret) - return ret; - ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - ret = adis_initial_startup(st); - if (ret) - goto error_cleanup_buffer_trigger; - - ret = iio_device_register(indio_dev); - if (ret < 0) - goto error_cleanup_buffer_trigger; - return 0; - -error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(st, indio_dev); - return ret; -} - -static int adis16201_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis_cleanup_buffer_and_trigger(st, indio_dev); - - return 0; -} - -static struct spi_driver adis16201_driver = { - .driver = { - .name = "adis16201", - }, - .probe = adis16201_probe, - .remove = adis16201_remove, -}; -module_spi_driver(adis16201_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16201"); diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c new file mode 100644 index 000000000000..68189aded729 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203.c @@ -0,0 +1,336 @@ +/* + * ADIS16203 Programmable 360 Degrees Inclinometer + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ADIS16203_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16203_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16203_SUPPLY_OUT 0x02 + +/* Output, auxiliary ADC input */ +#define ADIS16203_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16203_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16203_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16203_YINCL_OUT 0x0E + +/* Incline null calibration */ +#define ADIS16203_INCL_NULL 0x18 + +/* Alarm 1 amplitude threshold */ +#define ADIS16203_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16203_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16203_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16203_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16203_ALM_CTRL 0x28 + +/* Auxiliary DAC data */ +#define ADIS16203_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16203_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16203_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16203_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16203_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16203_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16203_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16203_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST BIT(10) + +/* Reverses rotation of both inclination outputs */ +#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN BIT(9) + +/* Self-test enable */ +#define ADIS16203_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16203_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16203_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ +#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16203_DIAG_STAT_ALARM1 BIT(8) + +/* Self-test diagnostic error flag */ +#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 + +/* SPI communications failure */ +#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16203_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16203_GLOB_CMD_CLEAR_STAT BIT(4) +#define ADIS16203_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16203_ERROR_ACTIVE BIT(14) + +enum adis16203_scan { + ADIS16203_SCAN_INCLI_X, + ADIS16203_SCAN_INCLI_Y, + ADIS16203_SCAN_SUPPLY, + ADIS16203_SCAN_AUX_ADC, + ADIS16203_SCAN_TEMP, +}; + +#define DRIVER_NAME "adis16203" + +static const u8 adis16203_addresses[] = { + [ADIS16203_SCAN_INCLI_X] = ADIS16203_INCL_NULL, +}; + +static int adis16203_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + /* currently only one writable parameter which keeps this simple */ + u8 addr = adis16203_addresses[chan->scan_index]; + + return adis_write_reg_16(st, addr, val & 0x3FFF); +} + +static int adis16203_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int ret; + int bits; + u8 addr; + s16 val16; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, + ADIS16203_ERROR_ACTIVE, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->channel == 0) { + *val = 1; + *val2 = 220000; /* 1.22 mV */ + } else { + *val = 0; + *val2 = 610000; /* 0.61 mV */ + } + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = -470; /* -0.47 C */ + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_INCLI: + *val = 0; + *val2 = 25000; /* 0.025 degree */ + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = 25000 / -470 - 1278; /* 25 C = 1278 */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + bits = 14; + mutex_lock(&indio_dev->mlock); + addr = adis16203_addresses[chan->scan_index]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + val16 &= (1 << bits) - 1; + val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); + *val = val16; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec adis16203_channels[] = { + ADIS_SUPPLY_CHAN(ADIS16203_SUPPLY_OUT, ADIS16203_SCAN_SUPPLY, 0, 12), + ADIS_AUX_ADC_CHAN(ADIS16203_AUX_ADC, ADIS16203_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16203_XINCL_OUT, ADIS16203_SCAN_INCLI_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + /* Fixme: Not what it appears to be - see data sheet */ + ADIS_INCLI_CHAN(Y, ADIS16203_YINCL_OUT, ADIS16203_SCAN_INCLI_Y, + 0, 0, 14), + ADIS_TEMP_CHAN(ADIS16203_TEMP_OUT, ADIS16203_SCAN_TEMP, 0, 12), + IIO_CHAN_SOFT_TIMESTAMP(5), +}; + +static const struct iio_info adis16203_info = { + .read_raw = &adis16203_read_raw, + .write_raw = &adis16203_write_raw, + .update_scan_mode = adis_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static const char * const adis16203_status_error_msgs[] = { + [ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure", + [ADIS16203_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16203_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", + [ADIS16203_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", +}; + +static const struct adis_data adis16203_data = { + .read_delay = 20, + .msc_ctrl_reg = ADIS16203_MSC_CTRL, + .glob_cmd_reg = ADIS16203_GLOB_CMD, + .diag_stat_reg = ADIS16203_DIAG_STAT, + + .self_test_mask = ADIS16203_MSC_CTRL_SELF_TEST_EN, + .self_test_no_autoclear = true, + .startup_delay = ADIS16203_STARTUP_DELAY, + + .status_error_msgs = adis16203_status_error_msgs, + .status_error_mask = BIT(ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT) | + BIT(ADIS16203_DIAG_STAT_SPI_FAIL_BIT) | + BIT(ADIS16203_DIAG_STAT_FLASH_UPT_BIT) | + BIT(ADIS16203_DIAG_STAT_POWER_HIGH_BIT) | + BIT(ADIS16203_DIAG_STAT_POWER_LOW_BIT), +}; + +static int adis16203_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct adis *st; + + /* setup the industrialio driver allocated elements */ + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); + /* this is only used for removal purposes */ + spi_set_drvdata(spi, indio_dev); + + indio_dev->name = spi->dev.driver->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->channels = adis16203_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16203_channels); + indio_dev->info = &adis16203_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(st, indio_dev, spi, &adis16203_data); + if (ret) + return ret; + + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); + if (ret) + return ret; + + /* Get the device into a sane initial state */ + ret = adis_initial_startup(st); + if (ret) + goto error_cleanup_buffer_trigger; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer_trigger; + + return 0; + +error_cleanup_buffer_trigger: + adis_cleanup_buffer_and_trigger(st, indio_dev); + return ret; +} + +static int adis16203_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis_cleanup_buffer_and_trigger(st, indio_dev); + + return 0; +} + +static struct spi_driver adis16203_driver = { + .driver = { + .name = "adis16203", + }, + .probe = adis16203_probe, + .remove = adis16203_remove, +}; +module_spi_driver(adis16203_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16203"); diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c deleted file mode 100644 index 68189aded729..000000000000 --- a/drivers/staging/iio/accel/adis16203_core.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * ADIS16203 Programmable 360 Degrees Inclinometer - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define ADIS16203_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16203_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16203_SUPPLY_OUT 0x02 - -/* Output, auxiliary ADC input */ -#define ADIS16203_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16203_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16203_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16203_YINCL_OUT 0x0E - -/* Incline null calibration */ -#define ADIS16203_INCL_NULL 0x18 - -/* Alarm 1 amplitude threshold */ -#define ADIS16203_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16203_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16203_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16203_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16203_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16203_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16203_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16203_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16203_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16203_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16203_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16203_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16203_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test at power-on: 1 = disabled, 0 = enabled */ -#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST BIT(10) - -/* Reverses rotation of both inclination outputs */ -#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN BIT(9) - -/* Self-test enable */ -#define ADIS16203_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16203_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16203_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ -#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16203_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16203_DIAG_STAT_ALARM1 BIT(8) - -/* Self-test diagnostic error flag */ -#define ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT 5 - -/* SPI communications failure */ -#define ADIS16203_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16203_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16203_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16203_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16203_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16203_GLOB_CMD_CLEAR_STAT BIT(4) -#define ADIS16203_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16203_ERROR_ACTIVE BIT(14) - -enum adis16203_scan { - ADIS16203_SCAN_INCLI_X, - ADIS16203_SCAN_INCLI_Y, - ADIS16203_SCAN_SUPPLY, - ADIS16203_SCAN_AUX_ADC, - ADIS16203_SCAN_TEMP, -}; - -#define DRIVER_NAME "adis16203" - -static const u8 adis16203_addresses[] = { - [ADIS16203_SCAN_INCLI_X] = ADIS16203_INCL_NULL, -}; - -static int adis16203_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - /* currently only one writable parameter which keeps this simple */ - u8 addr = adis16203_addresses[chan->scan_index]; - - return adis_write_reg_16(st, addr, val & 0x3FFF); -} - -static int adis16203_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int ret; - int bits; - u8 addr; - s16 val16; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - return adis_single_conversion(indio_dev, chan, - ADIS16203_ERROR_ACTIVE, val); - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->channel == 0) { - *val = 1; - *val2 = 220000; /* 1.22 mV */ - } else { - *val = 0; - *val2 = 610000; /* 0.61 mV */ - } - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = -470; /* -0.47 C */ - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_INCLI: - *val = 0; - *val2 = 25000; /* 0.025 degree */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_OFFSET: - *val = 25000 / -470 - 1278; /* 25 C = 1278 */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - bits = 14; - mutex_lock(&indio_dev->mlock); - addr = adis16203_addresses[chan->scan_index]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static const struct iio_chan_spec adis16203_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16203_SUPPLY_OUT, ADIS16203_SCAN_SUPPLY, 0, 12), - ADIS_AUX_ADC_CHAN(ADIS16203_AUX_ADC, ADIS16203_SCAN_AUX_ADC, 0, 12), - ADIS_INCLI_CHAN(X, ADIS16203_XINCL_OUT, ADIS16203_SCAN_INCLI_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - /* Fixme: Not what it appears to be - see data sheet */ - ADIS_INCLI_CHAN(Y, ADIS16203_YINCL_OUT, ADIS16203_SCAN_INCLI_Y, - 0, 0, 14), - ADIS_TEMP_CHAN(ADIS16203_TEMP_OUT, ADIS16203_SCAN_TEMP, 0, 12), - IIO_CHAN_SOFT_TIMESTAMP(5), -}; - -static const struct iio_info adis16203_info = { - .read_raw = &adis16203_read_raw, - .write_raw = &adis16203_write_raw, - .update_scan_mode = adis_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static const char * const adis16203_status_error_msgs[] = { - [ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure", - [ADIS16203_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16203_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16203_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16203_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", -}; - -static const struct adis_data adis16203_data = { - .read_delay = 20, - .msc_ctrl_reg = ADIS16203_MSC_CTRL, - .glob_cmd_reg = ADIS16203_GLOB_CMD, - .diag_stat_reg = ADIS16203_DIAG_STAT, - - .self_test_mask = ADIS16203_MSC_CTRL_SELF_TEST_EN, - .self_test_no_autoclear = true, - .startup_delay = ADIS16203_STARTUP_DELAY, - - .status_error_msgs = adis16203_status_error_msgs, - .status_error_mask = BIT(ADIS16203_DIAG_STAT_SELFTEST_FAIL_BIT) | - BIT(ADIS16203_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16203_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16203_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16203_DIAG_STAT_POWER_LOW_BIT), -}; - -static int adis16203_probe(struct spi_device *spi) -{ - int ret; - struct iio_dev *indio_dev; - struct adis *st; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->channels = adis16203_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16203_channels); - indio_dev->info = &adis16203_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(st, indio_dev, spi, &adis16203_data); - if (ret) - return ret; - - ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - ret = adis_initial_startup(st); - if (ret) - goto error_cleanup_buffer_trigger; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_buffer_trigger; - - return 0; - -error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(st, indio_dev); - return ret; -} - -static int adis16203_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis_cleanup_buffer_and_trigger(st, indio_dev); - - return 0; -} - -static struct spi_driver adis16203_driver = { - .driver = { - .name = "adis16203", - }, - .probe = adis16203_probe, - .remove = adis16203_remove, -}; -module_spi_driver(adis16203_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16203"); diff --git a/drivers/staging/iio/accel/adis16209.c b/drivers/staging/iio/accel/adis16209.c new file mode 100644 index 000000000000..8ff537f89d45 --- /dev/null +++ b/drivers/staging/iio/accel/adis16209.c @@ -0,0 +1,386 @@ +/* + * ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ADIS16209_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16209_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16209_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16209_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16209_YACCL_OUT 0x06 + +/* Output, auxiliary ADC input */ +#define ADIS16209_AUX_ADC 0x08 + +/* Output, temperature */ +#define ADIS16209_TEMP_OUT 0x0A + +/* Output, x-axis inclination */ +#define ADIS16209_XINCL_OUT 0x0C + +/* Output, y-axis inclination */ +#define ADIS16209_YINCL_OUT 0x0E + +/* Output, +/-180 vertical rotational position */ +#define ADIS16209_ROT_OUT 0x10 + +/* Calibration, x-axis acceleration offset null */ +#define ADIS16209_XACCL_NULL 0x12 + +/* Calibration, y-axis acceleration offset null */ +#define ADIS16209_YACCL_NULL 0x14 + +/* Calibration, x-axis inclination offset null */ +#define ADIS16209_XINCL_NULL 0x16 + +/* Calibration, y-axis inclination offset null */ +#define ADIS16209_YINCL_NULL 0x18 + +/* Calibration, vertical rotation offset null */ +#define ADIS16209_ROT_NULL 0x1A + +/* Alarm 1 amplitude threshold */ +#define ADIS16209_ALM_MAG1 0x20 + +/* Alarm 2 amplitude threshold */ +#define ADIS16209_ALM_MAG2 0x22 + +/* Alarm 1, sample period */ +#define ADIS16209_ALM_SMPL1 0x24 + +/* Alarm 2, sample period */ +#define ADIS16209_ALM_SMPL2 0x26 + +/* Alarm control */ +#define ADIS16209_ALM_CTRL 0x28 + +/* Auxiliary DAC data */ +#define ADIS16209_AUX_DAC 0x30 + +/* General-purpose digital input/output control */ +#define ADIS16209_GPIO_CTRL 0x32 + +/* Miscellaneous control */ +#define ADIS16209_MSC_CTRL 0x34 + +/* Internal sample period (rate) control */ +#define ADIS16209_SMPL_PRD 0x36 + +/* Operation, filter configuration */ +#define ADIS16209_AVG_CNT 0x38 + +/* Operation, sleep mode control */ +#define ADIS16209_SLP_CNT 0x3A + +/* Diagnostics, system status register */ +#define ADIS16209_DIAG_STAT 0x3C + +/* Operation, system command register */ +#define ADIS16209_GLOB_CMD 0x3E + +/* MSC_CTRL */ + +/* Self-test at power-on: 1 = disabled, 0 = enabled */ +#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) + +/* Self-test enable */ +#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ +#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16209_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16209_DIAG_STAT_ALARM1 BIT(8) + +/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ +#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5 + +/* SPI communications failure */ +#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1 + +/* Power supply below 3.15 V */ +#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16209_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4) +#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1) + +#define ADIS16209_ERROR_ACTIVE BIT(14) + +#define ADIS16209_SCAN_SUPPLY 0 +#define ADIS16209_SCAN_ACC_X 1 +#define ADIS16209_SCAN_ACC_Y 2 +#define ADIS16209_SCAN_AUX_ADC 3 +#define ADIS16209_SCAN_TEMP 4 +#define ADIS16209_SCAN_INCLI_X 5 +#define ADIS16209_SCAN_INCLI_Y 6 +#define ADIS16209_SCAN_ROT 7 + +static const u8 adis16209_addresses[8][1] = { + [ADIS16209_SCAN_SUPPLY] = { }, + [ADIS16209_SCAN_AUX_ADC] = { }, + [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL }, + [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL }, + [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL }, + [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL }, + [ADIS16209_SCAN_ROT] = { }, + [ADIS16209_SCAN_TEMP] = { }, +}; + +static int adis16209_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int bits; + s16 val16; + u8 addr; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + case IIO_INCLI: + bits = 14; + break; + default: + return -EINVAL; + } + val16 = val & ((1 << bits) - 1); + addr = adis16209_addresses[chan->scan_index][0]; + return adis_write_reg_16(st, addr, val16); + } + return -EINVAL; +} + +static int adis16209_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int ret; + int bits; + u8 addr; + s16 val16; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, + ADIS16209_ERROR_ACTIVE, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = 0; + if (chan->channel == 0) + *val2 = 305180; /* 0.30518 mV */ + else + *val2 = 610500; /* 0.6105 mV */ + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = -470; /* -0.47 C */ + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + *val = 0; + *val2 = IIO_G_TO_M_S_2(244140); /* 0.244140 mg */ + return IIO_VAL_INT_PLUS_NANO; + case IIO_INCLI: + case IIO_ROT: + *val = 0; + *val2 = 25000; /* 0.025 degree */ + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_OFFSET: + *val = 25000 / -470 - 0x4FE; /* 25 C = 0x4FE */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + bits = 14; + break; + default: + return -EINVAL; + } + mutex_lock(&indio_dev->mlock); + addr = adis16209_addresses[chan->scan_index][0]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + val16 &= (1 << bits) - 1; + val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); + *val = val16; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + } + return -EINVAL; +} + +static const struct iio_chan_spec adis16209_channels[] = { + ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 0, 14), + ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 0, 12), + ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, + 0, 0, 14), + ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, + 0, 0, 14), + ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 0, 14), + IIO_CHAN_SOFT_TIMESTAMP(8) +}; + +static const struct iio_info adis16209_info = { + .read_raw = &adis16209_read_raw, + .write_raw = &adis16209_write_raw, + .update_scan_mode = adis_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static const char * const adis16209_status_error_msgs[] = { + [ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure", + [ADIS16209_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16209_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", + [ADIS16209_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16209_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", +}; + +static const struct adis_data adis16209_data = { + .read_delay = 30, + .msc_ctrl_reg = ADIS16209_MSC_CTRL, + .glob_cmd_reg = ADIS16209_GLOB_CMD, + .diag_stat_reg = ADIS16209_DIAG_STAT, + + .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN, + .self_test_no_autoclear = true, + .startup_delay = ADIS16209_STARTUP_DELAY, + + .status_error_msgs = adis16209_status_error_msgs, + .status_error_mask = BIT(ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT) | + BIT(ADIS16209_DIAG_STAT_SPI_FAIL_BIT) | + BIT(ADIS16209_DIAG_STAT_FLASH_UPT_BIT) | + BIT(ADIS16209_DIAG_STAT_POWER_HIGH_BIT) | + BIT(ADIS16209_DIAG_STAT_POWER_LOW_BIT), +}; + +static int adis16209_probe(struct spi_device *spi) +{ + int ret; + struct adis *st; + struct iio_dev *indio_dev; + + /* setup the industrialio driver allocated elements */ + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); + /* this is only used for removal purposes */ + spi_set_drvdata(spi, indio_dev); + + indio_dev->name = spi->dev.driver->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &adis16209_info; + indio_dev->channels = adis16209_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16209_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(st, indio_dev, spi, &adis16209_data); + if (ret) + return ret; + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); + if (ret) + return ret; + + /* Get the device into a sane initial state */ + ret = adis_initial_startup(st); + if (ret) + goto error_cleanup_buffer_trigger; + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer_trigger; + + return 0; + +error_cleanup_buffer_trigger: + adis_cleanup_buffer_and_trigger(st, indio_dev); + return ret; +} + +static int adis16209_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis_cleanup_buffer_and_trigger(st, indio_dev); + + return 0; +} + +static struct spi_driver adis16209_driver = { + .driver = { + .name = "adis16209", + }, + .probe = adis16209_probe, + .remove = adis16209_remove, +}; +module_spi_driver(adis16209_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16209"); diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c deleted file mode 100644 index 8ff537f89d45..000000000000 --- a/drivers/staging/iio/accel/adis16209_core.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define ADIS16209_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16209_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16209_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16209_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16209_YACCL_OUT 0x06 - -/* Output, auxiliary ADC input */ -#define ADIS16209_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16209_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16209_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16209_YINCL_OUT 0x0E - -/* Output, +/-180 vertical rotational position */ -#define ADIS16209_ROT_OUT 0x10 - -/* Calibration, x-axis acceleration offset null */ -#define ADIS16209_XACCL_NULL 0x12 - -/* Calibration, y-axis acceleration offset null */ -#define ADIS16209_YACCL_NULL 0x14 - -/* Calibration, x-axis inclination offset null */ -#define ADIS16209_XINCL_NULL 0x16 - -/* Calibration, y-axis inclination offset null */ -#define ADIS16209_YINCL_NULL 0x18 - -/* Calibration, vertical rotation offset null */ -#define ADIS16209_ROT_NULL 0x1A - -/* Alarm 1 amplitude threshold */ -#define ADIS16209_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16209_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16209_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16209_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16209_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16209_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16209_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16209_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16209_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16209_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16209_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16209_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16209_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test at power-on: 1 = disabled, 0 = enabled */ -#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) - -/* Self-test enable */ -#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ -#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM1 BIT(8) - -/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ -#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5 - -/* SPI communications failure */ -#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16209_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4) -#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16209_ERROR_ACTIVE BIT(14) - -#define ADIS16209_SCAN_SUPPLY 0 -#define ADIS16209_SCAN_ACC_X 1 -#define ADIS16209_SCAN_ACC_Y 2 -#define ADIS16209_SCAN_AUX_ADC 3 -#define ADIS16209_SCAN_TEMP 4 -#define ADIS16209_SCAN_INCLI_X 5 -#define ADIS16209_SCAN_INCLI_Y 6 -#define ADIS16209_SCAN_ROT 7 - -static const u8 adis16209_addresses[8][1] = { - [ADIS16209_SCAN_SUPPLY] = { }, - [ADIS16209_SCAN_AUX_ADC] = { }, - [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL }, - [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL }, - [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL }, - [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL }, - [ADIS16209_SCAN_ROT] = { }, - [ADIS16209_SCAN_TEMP] = { }, -}; - -static int adis16209_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int bits; - s16 val16; - u8 addr; - - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - case IIO_INCLI: - bits = 14; - break; - default: - return -EINVAL; - } - val16 = val & ((1 << bits) - 1); - addr = adis16209_addresses[chan->scan_index][0]; - return adis_write_reg_16(st, addr, val16); - } - return -EINVAL; -} - -static int adis16209_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int ret; - int bits; - u8 addr; - s16 val16; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - return adis_single_conversion(indio_dev, chan, - ADIS16209_ERROR_ACTIVE, val); - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - *val = 0; - if (chan->channel == 0) - *val2 = 305180; /* 0.30518 mV */ - else - *val2 = 610500; /* 0.6105 mV */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = -470; /* -0.47 C */ - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(244140); /* 0.244140 mg */ - return IIO_VAL_INT_PLUS_NANO; - case IIO_INCLI: - case IIO_ROT: - *val = 0; - *val2 = 25000; /* 0.025 degree */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_OFFSET: - *val = 25000 / -470 - 0x4FE; /* 25 C = 0x4FE */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - bits = 14; - break; - default: - return -EINVAL; - } - mutex_lock(&indio_dev->mlock); - addr = adis16209_addresses[chan->scan_index][0]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - } - return -EINVAL; -} - -static const struct iio_chan_spec adis16209_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 0, 14), - ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 0, 12), - ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 0, 12), - ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, - 0, 0, 14), - ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, - 0, 0, 14), - ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 0, 14), - IIO_CHAN_SOFT_TIMESTAMP(8) -}; - -static const struct iio_info adis16209_info = { - .read_raw = &adis16209_read_raw, - .write_raw = &adis16209_write_raw, - .update_scan_mode = adis_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static const char * const adis16209_status_error_msgs[] = { - [ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure", - [ADIS16209_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16209_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16209_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16209_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", -}; - -static const struct adis_data adis16209_data = { - .read_delay = 30, - .msc_ctrl_reg = ADIS16209_MSC_CTRL, - .glob_cmd_reg = ADIS16209_GLOB_CMD, - .diag_stat_reg = ADIS16209_DIAG_STAT, - - .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN, - .self_test_no_autoclear = true, - .startup_delay = ADIS16209_STARTUP_DELAY, - - .status_error_msgs = adis16209_status_error_msgs, - .status_error_mask = BIT(ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT) | - BIT(ADIS16209_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16209_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16209_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16209_DIAG_STAT_POWER_LOW_BIT), -}; - -static int adis16209_probe(struct spi_device *spi) -{ - int ret; - struct adis *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16209_info; - indio_dev->channels = adis16209_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16209_channels); - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(st, indio_dev, spi, &adis16209_data); - if (ret) - return ret; - ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - ret = adis_initial_startup(st); - if (ret) - goto error_cleanup_buffer_trigger; - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_buffer_trigger; - - return 0; - -error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(st, indio_dev); - return ret; -} - -static int adis16209_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis_cleanup_buffer_and_trigger(st, indio_dev); - - return 0; -} - -static struct spi_driver adis16209_driver = { - .driver = { - .name = "adis16209", - }, - .probe = adis16209_probe, - .remove = adis16209_remove, -}; -module_spi_driver(adis16209_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16209"); diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c new file mode 100644 index 000000000000..27d7f6ad8c4c --- /dev/null +++ b/drivers/staging/iio/accel/adis16240.c @@ -0,0 +1,474 @@ +/* + * ADIS16240 Programmable Impact Sensor and Recorder driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ADIS16240_STARTUP_DELAY 220 /* ms */ + +/* Flash memory write count */ +#define ADIS16240_FLASH_CNT 0x00 + +/* Output, power supply */ +#define ADIS16240_SUPPLY_OUT 0x02 + +/* Output, x-axis accelerometer */ +#define ADIS16240_XACCL_OUT 0x04 + +/* Output, y-axis accelerometer */ +#define ADIS16240_YACCL_OUT 0x06 + +/* Output, z-axis accelerometer */ +#define ADIS16240_ZACCL_OUT 0x08 + +/* Output, auxiliary ADC input */ +#define ADIS16240_AUX_ADC 0x0A + +/* Output, temperature */ +#define ADIS16240_TEMP_OUT 0x0C + +/* Output, x-axis acceleration peak */ +#define ADIS16240_XPEAK_OUT 0x0E + +/* Output, y-axis acceleration peak */ +#define ADIS16240_YPEAK_OUT 0x10 + +/* Output, z-axis acceleration peak */ +#define ADIS16240_ZPEAK_OUT 0x12 + +/* Output, sum-of-squares acceleration peak */ +#define ADIS16240_XYZPEAK_OUT 0x14 + +/* Output, Capture Buffer 1, X and Y acceleration */ +#define ADIS16240_CAPT_BUF1 0x16 + +/* Output, Capture Buffer 2, Z acceleration */ +#define ADIS16240_CAPT_BUF2 0x18 + +/* Diagnostic, error flags */ +#define ADIS16240_DIAG_STAT 0x1A + +/* Diagnostic, event counter */ +#define ADIS16240_EVNT_CNTR 0x1C + +/* Diagnostic, check sum value from firmware test */ +#define ADIS16240_CHK_SUM 0x1E + +/* Calibration, x-axis acceleration offset adjustment */ +#define ADIS16240_XACCL_OFF 0x20 + +/* Calibration, y-axis acceleration offset adjustment */ +#define ADIS16240_YACCL_OFF 0x22 + +/* Calibration, z-axis acceleration offset adjustment */ +#define ADIS16240_ZACCL_OFF 0x24 + +/* Clock, hour and minute */ +#define ADIS16240_CLK_TIME 0x2E + +/* Clock, month and day */ +#define ADIS16240_CLK_DATE 0x30 + +/* Clock, year */ +#define ADIS16240_CLK_YEAR 0x32 + +/* Wake-up setting, hour and minute */ +#define ADIS16240_WAKE_TIME 0x34 + +/* Wake-up setting, month and day */ +#define ADIS16240_WAKE_DATE 0x36 + +/* Alarm 1 amplitude threshold */ +#define ADIS16240_ALM_MAG1 0x38 + +/* Alarm 2 amplitude threshold */ +#define ADIS16240_ALM_MAG2 0x3A + +/* Alarm control */ +#define ADIS16240_ALM_CTRL 0x3C + +/* Capture, external trigger control */ +#define ADIS16240_XTRIG_CTRL 0x3E + +/* Capture, address pointer */ +#define ADIS16240_CAPT_PNTR 0x40 + +/* Capture, configuration and control */ +#define ADIS16240_CAPT_CTRL 0x42 + +/* General-purpose digital input/output control */ +#define ADIS16240_GPIO_CTRL 0x44 + +/* Miscellaneous control */ +#define ADIS16240_MSC_CTRL 0x46 + +/* Internal sample period (rate) control */ +#define ADIS16240_SMPL_PRD 0x48 + +/* System command */ +#define ADIS16240_GLOB_CMD 0x4A + +/* MSC_CTRL */ + +/* Enables sum-of-squares output (XYZPEAK_OUT) */ +#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN BIT(15) + +/* Enables peak tracking output (XPEAK_OUT, YPEAK_OUT, and ZPEAK_OUT) */ +#define ADIS16240_MSC_CTRL_X_Y_ZPEAK_OUT_EN BIT(14) + +/* Self-test enable: 1 = apply electrostatic force, 0 = disabled */ +#define ADIS16240_MSC_CTRL_SELF_TEST_EN BIT(8) + +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16240_MSC_CTRL_DATA_RDY_EN BIT(2) + +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16240_MSC_CTRL_ACTIVE_HIGH BIT(1) + +/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ +#define ADIS16240_MSC_CTRL_DATA_RDY_DIO2 BIT(0) + +/* DIAG_STAT */ + +/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16240_DIAG_STAT_ALARM2 BIT(9) + +/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ +#define ADIS16240_DIAG_STAT_ALARM1 BIT(8) + +/* Capture buffer full: 1 = capture buffer is full */ +#define ADIS16240_DIAG_STAT_CPT_BUF_FUL BIT(7) + +/* Flash test, checksum flag: 1 = mismatch, 0 = match */ +#define ADIS16240_DIAG_STAT_CHKSUM BIT(6) + +/* Power-on, self-test flag: 1 = failure, 0 = pass */ +#define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT 5 + +/* Power-on self-test: 1 = in-progress, 0 = complete */ +#define ADIS16240_DIAG_STAT_PWRON_BUSY BIT(4) + +/* SPI communications failure */ +#define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3 + +/* Flash update failure */ +#define ADIS16240_DIAG_STAT_FLASH_UPT_BIT 2 + +/* Power supply above 3.625 V */ +#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1 + + /* Power supply below 3.15 V */ +#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0 + +/* GLOB_CMD */ + +#define ADIS16240_GLOB_CMD_RESUME BIT(8) +#define ADIS16240_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16240_GLOB_CMD_STANDBY BIT(2) + +#define ADIS16240_ERROR_ACTIVE BIT(14) + +/* At the moment triggers are only used for ring buffer + * filling. This may change! + */ + +#define ADIS16240_SCAN_ACC_X 0 +#define ADIS16240_SCAN_ACC_Y 1 +#define ADIS16240_SCAN_ACC_Z 2 +#define ADIS16240_SCAN_SUPPLY 3 +#define ADIS16240_SCAN_AUX_ADC 4 +#define ADIS16240_SCAN_TEMP 5 + +static ssize_t adis16240_spi_read_signed(struct device *dev, + struct device_attribute *attr, + char *buf, + unsigned int bits) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adis *st = iio_priv(indio_dev); + int ret; + s16 val = 0; + unsigned int shift = 16 - bits; + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + ret = adis_read_reg_16(st, + this_attr->address, (u16 *)&val); + if (ret) + return ret; + + if (val & ADIS16240_ERROR_ACTIVE) + adis_check_status(st); + + val = (s16)(val << shift) >> shift; + return sprintf(buf, "%d\n", val); +} + +static ssize_t adis16240_read_12bit_signed(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t ret; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + + /* Take the iio_dev status lock */ + mutex_lock(&indio_dev->mlock); + ret = adis16240_spi_read_signed(dev, attr, buf, 12); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, 0444, + adis16240_read_12bit_signed, NULL, + ADIS16240_XYZPEAK_OUT); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096"); + +static const u8 adis16240_addresses[][2] = { + [ADIS16240_SCAN_ACC_X] = { ADIS16240_XACCL_OFF, ADIS16240_XPEAK_OUT }, + [ADIS16240_SCAN_ACC_Y] = { ADIS16240_YACCL_OFF, ADIS16240_YPEAK_OUT }, + [ADIS16240_SCAN_ACC_Z] = { ADIS16240_ZACCL_OFF, ADIS16240_ZPEAK_OUT }, +}; + +static int adis16240_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int ret; + int bits; + u8 addr; + s16 val16; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, + ADIS16240_ERROR_ACTIVE, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->channel == 0) { + *val = 4; + *val2 = 880000; /* 4.88 mV */ + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; + case IIO_TEMP: + *val = 244; /* 0.244 C */ + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + *val = 0; + *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */ + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_PEAK_SCALE: + *val = 0; + *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */ + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = 25000 / 244 - 0x133; /* 25 C = 0x133 */ + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + bits = 10; + mutex_lock(&indio_dev->mlock); + addr = adis16240_addresses[chan->scan_index][0]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + val16 &= (1 << bits) - 1; + val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); + *val = val16; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_PEAK: + bits = 10; + mutex_lock(&indio_dev->mlock); + addr = adis16240_addresses[chan->scan_index][1]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) { + mutex_unlock(&indio_dev->mlock); + return ret; + } + val16 &= (1 << bits) - 1; + val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); + *val = val16; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + } + return -EINVAL; +} + +static int adis16240_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int bits = 10; + s16 val16; + u8 addr; + + switch (mask) { + case IIO_CHAN_INFO_CALIBBIAS: + val16 = val & ((1 << bits) - 1); + addr = adis16240_addresses[chan->scan_index][0]; + return adis_write_reg_16(st, addr, val16); + } + return -EINVAL; +} + +static const struct iio_chan_spec adis16240_channels[] = { + ADIS_SUPPLY_CHAN(ADIS16240_SUPPLY_OUT, ADIS16240_SCAN_SUPPLY, 0, 10), + ADIS_AUX_ADC_CHAN(ADIS16240_AUX_ADC, ADIS16240_SCAN_AUX_ADC, 0, 10), + ADIS_ACCEL_CHAN(X, ADIS16240_XACCL_OUT, ADIS16240_SCAN_ACC_X, + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), + 0, 10), + ADIS_ACCEL_CHAN(Y, ADIS16240_YACCL_OUT, ADIS16240_SCAN_ACC_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), + 0, 10), + ADIS_ACCEL_CHAN(Z, ADIS16240_ZACCL_OUT, ADIS16240_SCAN_ACC_Z, + BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), + 0, 10), + ADIS_TEMP_CHAN(ADIS16240_TEMP_OUT, ADIS16240_SCAN_TEMP, 0, 10), + IIO_CHAN_SOFT_TIMESTAMP(6) +}; + +static struct attribute *adis16240_attributes[] = { + &iio_dev_attr_in_accel_xyz_squared_peak_raw.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group adis16240_attribute_group = { + .attrs = adis16240_attributes, +}; + +static const struct iio_info adis16240_info = { + .attrs = &adis16240_attribute_group, + .read_raw = &adis16240_read_raw, + .write_raw = &adis16240_write_raw, + .update_scan_mode = adis_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static const char * const adis16240_status_error_msgs[] = { + [ADIS16240_DIAG_STAT_PWRON_FAIL_BIT] = "Power on, self-test failed", + [ADIS16240_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16240_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", + [ADIS16240_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16240_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.225V", +}; + +static const struct adis_data adis16240_data = { + .write_delay = 35, + .read_delay = 35, + .msc_ctrl_reg = ADIS16240_MSC_CTRL, + .glob_cmd_reg = ADIS16240_GLOB_CMD, + .diag_stat_reg = ADIS16240_DIAG_STAT, + + .self_test_mask = ADIS16240_MSC_CTRL_SELF_TEST_EN, + .self_test_no_autoclear = true, + .startup_delay = ADIS16240_STARTUP_DELAY, + + .status_error_msgs = adis16240_status_error_msgs, + .status_error_mask = BIT(ADIS16240_DIAG_STAT_PWRON_FAIL_BIT) | + BIT(ADIS16240_DIAG_STAT_SPI_FAIL_BIT) | + BIT(ADIS16240_DIAG_STAT_FLASH_UPT_BIT) | + BIT(ADIS16240_DIAG_STAT_POWER_HIGH_BIT) | + BIT(ADIS16240_DIAG_STAT_POWER_LOW_BIT), +}; + +static int adis16240_probe(struct spi_device *spi) +{ + int ret; + struct adis *st; + struct iio_dev *indio_dev; + + /* setup the industrialio driver allocated elements */ + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); + /* this is only used for removal purposes */ + spi_set_drvdata(spi, indio_dev); + + indio_dev->name = spi->dev.driver->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &adis16240_info; + indio_dev->channels = adis16240_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16240_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(st, indio_dev, spi, &adis16240_data); + if (ret) + return ret; + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); + if (ret) + return ret; + + /* Get the device into a sane initial state */ + ret = adis_initial_startup(st); + if (ret) + goto error_cleanup_buffer_trigger; + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer_trigger; + return 0; + +error_cleanup_buffer_trigger: + adis_cleanup_buffer_and_trigger(st, indio_dev); + return ret; +} + +static int adis16240_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis_cleanup_buffer_and_trigger(st, indio_dev); + + return 0; +} + +static struct spi_driver adis16240_driver = { + .driver = { + .name = "adis16240", + }, + .probe = adis16240_probe, + .remove = adis16240_remove, +}; +module_spi_driver(adis16240_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16240"); diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c deleted file mode 100644 index 27d7f6ad8c4c..000000000000 --- a/drivers/staging/iio/accel/adis16240_core.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * ADIS16240 Programmable Impact Sensor and Recorder driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define ADIS16240_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16240_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16240_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16240_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16240_YACCL_OUT 0x06 - -/* Output, z-axis accelerometer */ -#define ADIS16240_ZACCL_OUT 0x08 - -/* Output, auxiliary ADC input */ -#define ADIS16240_AUX_ADC 0x0A - -/* Output, temperature */ -#define ADIS16240_TEMP_OUT 0x0C - -/* Output, x-axis acceleration peak */ -#define ADIS16240_XPEAK_OUT 0x0E - -/* Output, y-axis acceleration peak */ -#define ADIS16240_YPEAK_OUT 0x10 - -/* Output, z-axis acceleration peak */ -#define ADIS16240_ZPEAK_OUT 0x12 - -/* Output, sum-of-squares acceleration peak */ -#define ADIS16240_XYZPEAK_OUT 0x14 - -/* Output, Capture Buffer 1, X and Y acceleration */ -#define ADIS16240_CAPT_BUF1 0x16 - -/* Output, Capture Buffer 2, Z acceleration */ -#define ADIS16240_CAPT_BUF2 0x18 - -/* Diagnostic, error flags */ -#define ADIS16240_DIAG_STAT 0x1A - -/* Diagnostic, event counter */ -#define ADIS16240_EVNT_CNTR 0x1C - -/* Diagnostic, check sum value from firmware test */ -#define ADIS16240_CHK_SUM 0x1E - -/* Calibration, x-axis acceleration offset adjustment */ -#define ADIS16240_XACCL_OFF 0x20 - -/* Calibration, y-axis acceleration offset adjustment */ -#define ADIS16240_YACCL_OFF 0x22 - -/* Calibration, z-axis acceleration offset adjustment */ -#define ADIS16240_ZACCL_OFF 0x24 - -/* Clock, hour and minute */ -#define ADIS16240_CLK_TIME 0x2E - -/* Clock, month and day */ -#define ADIS16240_CLK_DATE 0x30 - -/* Clock, year */ -#define ADIS16240_CLK_YEAR 0x32 - -/* Wake-up setting, hour and minute */ -#define ADIS16240_WAKE_TIME 0x34 - -/* Wake-up setting, month and day */ -#define ADIS16240_WAKE_DATE 0x36 - -/* Alarm 1 amplitude threshold */ -#define ADIS16240_ALM_MAG1 0x38 - -/* Alarm 2 amplitude threshold */ -#define ADIS16240_ALM_MAG2 0x3A - -/* Alarm control */ -#define ADIS16240_ALM_CTRL 0x3C - -/* Capture, external trigger control */ -#define ADIS16240_XTRIG_CTRL 0x3E - -/* Capture, address pointer */ -#define ADIS16240_CAPT_PNTR 0x40 - -/* Capture, configuration and control */ -#define ADIS16240_CAPT_CTRL 0x42 - -/* General-purpose digital input/output control */ -#define ADIS16240_GPIO_CTRL 0x44 - -/* Miscellaneous control */ -#define ADIS16240_MSC_CTRL 0x46 - -/* Internal sample period (rate) control */ -#define ADIS16240_SMPL_PRD 0x48 - -/* System command */ -#define ADIS16240_GLOB_CMD 0x4A - -/* MSC_CTRL */ - -/* Enables sum-of-squares output (XYZPEAK_OUT) */ -#define ADIS16240_MSC_CTRL_XYZPEAK_OUT_EN BIT(15) - -/* Enables peak tracking output (XPEAK_OUT, YPEAK_OUT, and ZPEAK_OUT) */ -#define ADIS16240_MSC_CTRL_X_Y_ZPEAK_OUT_EN BIT(14) - -/* Self-test enable: 1 = apply electrostatic force, 0 = disabled */ -#define ADIS16240_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16240_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16240_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ -#define ADIS16240_MSC_CTRL_DATA_RDY_DIO2 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16240_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16240_DIAG_STAT_ALARM1 BIT(8) - -/* Capture buffer full: 1 = capture buffer is full */ -#define ADIS16240_DIAG_STAT_CPT_BUF_FUL BIT(7) - -/* Flash test, checksum flag: 1 = mismatch, 0 = match */ -#define ADIS16240_DIAG_STAT_CHKSUM BIT(6) - -/* Power-on, self-test flag: 1 = failure, 0 = pass */ -#define ADIS16240_DIAG_STAT_PWRON_FAIL_BIT 5 - -/* Power-on self-test: 1 = in-progress, 0 = complete */ -#define ADIS16240_DIAG_STAT_PWRON_BUSY BIT(4) - -/* SPI communications failure */ -#define ADIS16240_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16240_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16240_DIAG_STAT_POWER_HIGH_BIT 1 - - /* Power supply below 3.15 V */ -#define ADIS16240_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16240_GLOB_CMD_RESUME BIT(8) -#define ADIS16240_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16240_GLOB_CMD_STANDBY BIT(2) - -#define ADIS16240_ERROR_ACTIVE BIT(14) - -/* At the moment triggers are only used for ring buffer - * filling. This may change! - */ - -#define ADIS16240_SCAN_ACC_X 0 -#define ADIS16240_SCAN_ACC_Y 1 -#define ADIS16240_SCAN_ACC_Z 2 -#define ADIS16240_SCAN_SUPPLY 3 -#define ADIS16240_SCAN_AUX_ADC 4 -#define ADIS16240_SCAN_TEMP 5 - -static ssize_t adis16240_spi_read_signed(struct device *dev, - struct device_attribute *attr, - char *buf, - unsigned int bits) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct adis *st = iio_priv(indio_dev); - int ret; - s16 val = 0; - unsigned int shift = 16 - bits; - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - - ret = adis_read_reg_16(st, - this_attr->address, (u16 *)&val); - if (ret) - return ret; - - if (val & ADIS16240_ERROR_ACTIVE) - adis_check_status(st); - - val = (s16)(val << shift) >> shift; - return sprintf(buf, "%d\n", val); -} - -static ssize_t adis16240_read_12bit_signed(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - - /* Take the iio_dev status lock */ - mutex_lock(&indio_dev->mlock); - ret = adis16240_spi_read_signed(dev, attr, buf, 12); - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, 0444, - adis16240_read_12bit_signed, NULL, - ADIS16240_XYZPEAK_OUT); - -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096"); - -static const u8 adis16240_addresses[][2] = { - [ADIS16240_SCAN_ACC_X] = { ADIS16240_XACCL_OFF, ADIS16240_XPEAK_OUT }, - [ADIS16240_SCAN_ACC_Y] = { ADIS16240_YACCL_OFF, ADIS16240_YPEAK_OUT }, - [ADIS16240_SCAN_ACC_Z] = { ADIS16240_ZACCL_OFF, ADIS16240_ZPEAK_OUT }, -}; - -static int adis16240_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int ret; - int bits; - u8 addr; - s16 val16; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - return adis_single_conversion(indio_dev, chan, - ADIS16240_ERROR_ACTIVE, val); - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->channel == 0) { - *val = 4; - *val2 = 880000; /* 4.88 mV */ - return IIO_VAL_INT_PLUS_MICRO; - } - return -EINVAL; - case IIO_TEMP: - *val = 244; /* 0.244 C */ - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_PEAK_SCALE: - *val = 0; - *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */ - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_OFFSET: - *val = 25000 / 244 - 0x133; /* 25 C = 0x133 */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - bits = 10; - mutex_lock(&indio_dev->mlock); - addr = adis16240_addresses[chan->scan_index][0]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_PEAK: - bits = 10; - mutex_lock(&indio_dev->mlock); - addr = adis16240_addresses[chan->scan_index][1]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - mutex_unlock(&indio_dev->mlock); - return IIO_VAL_INT; - } - return -EINVAL; -} - -static int adis16240_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int bits = 10; - s16 val16; - u8 addr; - - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - val16 = val & ((1 << bits) - 1); - addr = adis16240_addresses[chan->scan_index][0]; - return adis_write_reg_16(st, addr, val16); - } - return -EINVAL; -} - -static const struct iio_chan_spec adis16240_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16240_SUPPLY_OUT, ADIS16240_SCAN_SUPPLY, 0, 10), - ADIS_AUX_ADC_CHAN(ADIS16240_AUX_ADC, ADIS16240_SCAN_AUX_ADC, 0, 10), - ADIS_ACCEL_CHAN(X, ADIS16240_XACCL_OUT, ADIS16240_SCAN_ACC_X, - BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), - 0, 10), - ADIS_ACCEL_CHAN(Y, ADIS16240_YACCL_OUT, ADIS16240_SCAN_ACC_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), - 0, 10), - ADIS_ACCEL_CHAN(Z, ADIS16240_ZACCL_OUT, ADIS16240_SCAN_ACC_Z, - BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), - 0, 10), - ADIS_TEMP_CHAN(ADIS16240_TEMP_OUT, ADIS16240_SCAN_TEMP, 0, 10), - IIO_CHAN_SOFT_TIMESTAMP(6) -}; - -static struct attribute *adis16240_attributes[] = { - &iio_dev_attr_in_accel_xyz_squared_peak_raw.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16240_attribute_group = { - .attrs = adis16240_attributes, -}; - -static const struct iio_info adis16240_info = { - .attrs = &adis16240_attribute_group, - .read_raw = &adis16240_read_raw, - .write_raw = &adis16240_write_raw, - .update_scan_mode = adis_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static const char * const adis16240_status_error_msgs[] = { - [ADIS16240_DIAG_STAT_PWRON_FAIL_BIT] = "Power on, self-test failed", - [ADIS16240_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16240_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16240_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16240_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.225V", -}; - -static const struct adis_data adis16240_data = { - .write_delay = 35, - .read_delay = 35, - .msc_ctrl_reg = ADIS16240_MSC_CTRL, - .glob_cmd_reg = ADIS16240_GLOB_CMD, - .diag_stat_reg = ADIS16240_DIAG_STAT, - - .self_test_mask = ADIS16240_MSC_CTRL_SELF_TEST_EN, - .self_test_no_autoclear = true, - .startup_delay = ADIS16240_STARTUP_DELAY, - - .status_error_msgs = adis16240_status_error_msgs, - .status_error_mask = BIT(ADIS16240_DIAG_STAT_PWRON_FAIL_BIT) | - BIT(ADIS16240_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16240_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16240_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16240_DIAG_STAT_POWER_LOW_BIT), -}; - -static int adis16240_probe(struct spi_device *spi) -{ - int ret; - struct adis *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16240_info; - indio_dev->channels = adis16240_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16240_channels); - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(st, indio_dev, spi, &adis16240_data); - if (ret) - return ret; - ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - ret = adis_initial_startup(st); - if (ret) - goto error_cleanup_buffer_trigger; - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_buffer_trigger; - return 0; - -error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(st, indio_dev); - return ret; -} - -static int adis16240_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis_cleanup_buffer_and_trigger(st, indio_dev); - - return 0; -} - -static struct spi_driver adis16240_driver = { - .driver = { - .name = "adis16240", - }, - .probe = adis16240_probe, - .remove = adis16240_remove, -}; -module_spi_driver(adis16240_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16240"); -- cgit v1.2.3