Browse Source

Merge tag 'iio-for-4.4a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

First round of new driver, new functionality and cleanups for IIO in the 4.4 cycle

New device support
* APDS9960 ALS + proximity driver
* bmg160 SPI devices.
* HDC100x humidity sensors
* Holt HI-8435 threshold detector
* mma8453Q accelerometer added to the mma8452 driver
* mma86452FC and mma8653FC accelerometers added to the mma8452 driver
* mxc4005 accelerometer
* PulsedLight LIDAR
* SensorTech VZ89x volatile organic compound sensor
* UPISEMI uS5182d ALS and proximity sensors

New core functionality
* triggered events - use triggers to check for changes in threshold type
  detectors on devices with out interrupt support.  First user is the holt
  comparator.
* chemical concentration and resistance channel types.

New driver functionality
* vf610
  - buffer support.
  - followup coccinelle warning fix.

Core rework
* buffers
  - break out callback buffer to own module.
  - move buffer implementations to a new subdirectory
* percolate the error code form iio_event_getfd out to userspace
  rather than giving a missleading error later on.

Cleanups
* adddac drivers
  - use BIT macro where appropriate.
* meter drivers
  - use BIT macro where appropriate.

* ad7303
 - add an OF match table to line up with the binding docs.
* adc128s052
  - add an OF match table to line up with the binding docs.
* adf4350
  - add an OF match table to line up with the binding docs
* as3935
  - add an OF match table to line up with the binding docs.
* berlin2-adc
  - use GENMASK and BIT for masks
  - prevent attempting to sample multiple channels at once by moving a
    mutex scop
  - coding style cleanups
* bmg150_magn
  - kconfig sort order was wrong - fix it.
* bmg160
  - use i2c regmap and drop all uses of i2c_client
  - separate i2c and core driver
* cc10001_adc
  - kconfig sort order was wrong - fix it.
* evgen (dummy driver helper module)
  - move interrupt generation to irq_work to reduce differences between
    the dummy driver and real hardware drivers.
* hmc5843
  - set the name dynamically rather than to a fixed value for one of the
    suported parts.
  - export module alias information to allow autoprobing of module.
* lpc32xx
  - on failure to get resource or irq return -ENXIO as uppose to -EBUSY
* max1027
  - set .of_match_table to actually allow OF style matching.
* max5821
  - add MODULE_DEVICE_TABLE for OF table.
* mma8452
  - refactor to separate out chip specific data.
  - add freefall / motion interrupt source for devices that do their
    interrupts slightly differently.
  - update copywrite notice.
  - leave naming of events directory in sysfs to the core
* mcp320x
  - set .of_match_table so that it can be use for OF style matching.
* mlx90614
  - Implement filter configuration (note the datasheet changed as a result
    of the driver reviews to include the values we needed ;)
* opt3001
  - drop .owner field as assigned by platform driver core.
* si7020
  - replace a bitmask on the humidity values with a more correct range
    check.
* stk310
  - improved error handling.
  - use BIT macro where appropriate and use the resulting defines
    instead of magic numbers in the code.
  - fix indentation
* st-sensors
  - add debugfs register read hook
* tsl4531
  - fix error handling in check_id
* twl6030
  - fix module autoload for OF
* iio-trig-sysfs
  - document add and remove attribute
* trigger in staging
  - code alignment fixes.
  - braces on both branches of if statement if needed for one.
* xilinx-xadc
  - push interrupts into hardirq context as there isn't much in them
    any more and it avoids breaking PREEMPT_RT builds due to the use
    of a spinlock between the hardirq and the thread.

Tools
* event-monitor
  - report unsupported events.  We keep expanding what can come from drivers
    so give a helpful error if one turns up in an out of date userspace
    program.
* generic-buffer
  - helpful message about needing to enable a channel to start the buffer.
Greg Kroah-Hartman 10 years ago
parent
commit
9f827d8099
88 changed files with 5114 additions and 471 deletions
  1. 20 0
      Documentation/ABI/testing/sysfs-bus-iio
  2. 43 0
      Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435
  3. 7 0
      Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x
  4. 9 0
      Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x
  5. 22 0
      Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs
  6. 1 1
      Documentation/DocBook/iio.tmpl
  7. 2 1
      Documentation/devicetree/bindings/i2c/trivial-devices.txt
  8. 24 0
      Documentation/devicetree/bindings/iio/accel/mma8452.txt
  9. 21 0
      Documentation/devicetree/bindings/iio/adc/hi8435.txt
  10. 22 0
      Documentation/devicetree/bindings/iio/light/apds9960.txt
  11. 34 0
      Documentation/devicetree/bindings/iio/light/us5182d.txt
  12. 4 0
      Documentation/devicetree/bindings/vendor-prefixes.txt
  13. 7 0
      MAINTAINERS
  14. 8 21
      drivers/iio/Kconfig
  15. 3 3
      drivers/iio/Makefile
  16. 16 3
      drivers/iio/accel/Kconfig
  17. 2 0
      drivers/iio/accel/Makefile
  18. 292 64
      drivers/iio/accel/mma8452.c
  19. 567 0
      drivers/iio/accel/mxc4005.c
  20. 1 0
      drivers/iio/accel/st_accel_core.c
  21. 24 11
      drivers/iio/adc/Kconfig
  22. 2 1
      drivers/iio/adc/Makefile
  23. 48 43
      drivers/iio/adc/berlin2-adc.c
  24. 534 0
      drivers/iio/adc/hi8435.c
  25. 1 0
      drivers/iio/adc/max1027.c
  26. 1 0
      drivers/iio/adc/mcp320x.c
  27. 8 0
      drivers/iio/adc/ti-adc128s052.c
  28. 1 0
      drivers/iio/adc/twl6030-gpadc.c
  29. 94 7
      drivers/iio/adc/vf610_adc.c
  30. 10 27
      drivers/iio/adc/xilinx-xadc-core.c
  31. 0 2
      drivers/iio/adc/xilinx-xadc.h
  32. 1 0
      drivers/iio/amplifiers/ad8366.c
  33. 24 0
      drivers/iio/buffer/Kconfig
  34. 8 0
      drivers/iio/buffer/Makefile
  35. 12 0
      drivers/iio/buffer/industrialio-buffer-cb.c
  36. 0 0
      drivers/iio/buffer/industrialio-triggered-buffer.c
  37. 0 0
      drivers/iio/buffer/kfifo_buf.c
  38. 15 0
      drivers/iio/chemical/Kconfig
  39. 6 0
      drivers/iio/chemical/Makefile
  40. 237 0
      drivers/iio/chemical/vz89x.c
  41. 22 0
      drivers/iio/common/st_sensors/st_sensors_core.c
  42. 7 0
      drivers/iio/dac/ad7303.c
  43. 1 0
      drivers/iio/dac/max5821.c
  44. 9 0
      drivers/iio/frequency/adf4350.c
  45. 15 4
      drivers/iio/gyro/Kconfig
  46. 3 1
      drivers/iio/gyro/Makefile
  47. 10 0
      drivers/iio/gyro/bmg160.h
  48. 145 216
      drivers/iio/gyro/bmg160_core.c
  49. 71 0
      drivers/iio/gyro/bmg160_i2c.c
  50. 57 0
      drivers/iio/gyro/bmg160_spi.c
  51. 1 0
      drivers/iio/gyro/st_gyro_core.c
  52. 10 0
      drivers/iio/humidity/Kconfig
  53. 1 0
      drivers/iio/humidity/Makefile
  54. 319 0
      drivers/iio/humidity/hdc100x.c
  55. 5 1
      drivers/iio/humidity/si7020.c
  56. 8 2
      drivers/iio/industrialio-core.c
  57. 10 2
      drivers/iio/industrialio-trigger.c
  58. 68 0
      drivers/iio/industrialio-triggered-event.c
  59. 23 0
      drivers/iio/light/Kconfig
  60. 2 0
      drivers/iio/light/Makefile
  61. 1130 0
      drivers/iio/light/apds9960.c
  62. 0 1
      drivers/iio/light/opt3001.c
  63. 53 22
      drivers/iio/light/stk3310.c
  64. 5 4
      drivers/iio/light/tsl4531.c
  65. 507 0
      drivers/iio/light/us5182d.c
  66. 18 15
      drivers/iio/magnetometer/Kconfig
  67. 1 2
      drivers/iio/magnetometer/Makefile
  68. 1 0
      drivers/iio/magnetometer/st_magn_core.c
  69. 1 0
      drivers/iio/pressure/st_pressure_core.c
  70. 12 0
      drivers/iio/proximity/Kconfig
  71. 1 0
      drivers/iio/proximity/Makefile
  72. 7 0
      drivers/iio/proximity/as3935.c
  73. 288 0
      drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
  74. 87 3
      drivers/iio/temperature/mlx90614.c
  75. 2 2
      drivers/staging/iio/adc/lpc32xx_adc.c
  76. 25 1
      drivers/staging/iio/iio_dummy_evgen.c
  77. 1 0
      drivers/staging/iio/iio_simple_dummy.h
  78. 14 5
      drivers/staging/iio/iio_simple_dummy_events.c
  79. 1 1
      drivers/staging/iio/magnetometer/hmc5843.h
  80. 2 2
      drivers/staging/iio/magnetometer/hmc5843_core.c
  81. 1 1
      drivers/staging/iio/magnetometer/hmc5843_i2c.c
  82. 3 1
      drivers/staging/iio/magnetometer/hmc5843_spi.c
  83. 4 0
      include/linux/iio/common/st_sensors.h
  84. 3 0
      include/linux/iio/iio.h
  85. 11 0
      include/linux/iio/triggered_event.h
  86. 4 0
      include/uapi/linux/iio/types.h
  87. 9 0
      tools/iio/generic_buffer.c
  88. 5 1
      tools/iio/iio_event_monitor.c

+ 20 - 0
Documentation/ABI/testing/sysfs-bus-iio

@@ -581,6 +581,7 @@ What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
+What:		/sys/.../iio:deviceX/events/in_voltageY_thresh_either_en
 What:		/sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
 What:		/sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
 What:		/sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
 KernelVersion:	2.6.37
 KernelVersion:	2.6.37
@@ -1459,3 +1460,22 @@ Description:
 		measurements and return the average value as output data. Each
 		measurements and return the average value as output data. Each
 		value resulted from <type>[_name]_oversampling_ratio measurements
 		value resulted from <type>[_name]_oversampling_ratio measurements
 		is considered as one sample for <type>[_name]_sampling_frequency.
 		is considered as one sample for <type>[_name]_sampling_frequency.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentration_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
+KernelVersion:	4.3
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no offset etc.) percentage reading of a substance.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_resistance_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
+KernelVersion:	4.3
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Raw (unscaled no offset etc.) resistance reading that can be processed
+		into an ohm value.

+ 43 - 0
Documentation/ABI/testing/sysfs-bus-iio-adc-hi8435

@@ -0,0 +1,43 @@
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_sensing_mode
+Date:		August 2015
+KernelVersion:	4.2.0
+Contact:	source@cogentembedded.com
+Description:
+		Program sensor type for threshold detector inputs.
+		Could be either "GND-Open" or "Supply-Open" mode. Y is a
+		threshold detector input channel. Channels 0..7, 8..15, 16..23
+		and 24..31 has common sensor types.
+
+What:		/sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_falling_value
+Date:		August 2015
+KernelVersion:	4.2.0
+Contact:	source@cogentembedded.com
+Description:
+		Channel Y low voltage threshold. If sensor input voltage goes lower then
+		this value then the threshold falling event is pushed.
+		Depending on in_voltageY_sensing_mode the low voltage threshold
+		is separately set for "GND-Open" and "Supply-Open" modes.
+		Channels 0..31 have common low threshold values, but could have different
+		sensing_modes.
+		The low voltage threshold range is between 2..21V.
+		Hysteresis between low and high thresholds can not be lower then 2 and
+		can not be odd.
+		If falling threshold results hysteresis to odd value then rising
+		threshold is automatically subtracted by one.
+
+What:		/sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_rising_value
+Date:		August 2015
+KernelVersion:	4.2.0
+Contact:	source@cogentembedded.com
+Description:
+		Channel Y high voltage threshold. If sensor input voltage goes higher then
+		this value then the threshold rising event is pushed.
+		Depending on in_voltageY_sensing_mode the high voltage threshold
+		is separately set for "GND-Open" and "Supply-Open" modes.
+		Channels 0..31 have common high threshold values, but could have different
+		sensing_modes.
+		The high voltage threshold range is between 3..22V.
+		Hysteresis between low and high thresholds can not be lower then 2 and
+		can not be odd.
+		If rising threshold results hysteresis to odd value then falling
+		threshold is automatically appended by one.

+ 7 - 0
Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x

@@ -0,0 +1,7 @@
+What:		/sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw
+Date:		September 2015
+KernelVersion:	4.3
+Contact:	Matt Ranostay <mranostay@gmail.com>
+Description:
+		Get the raw calibration VOC value from the sensor.
+		This value has little application outside of calibration.

+ 9 - 0
Documentation/ABI/testing/sysfs-bus-iio-humidity-hdc100x

@@ -0,0 +1,9 @@
+What:		/sys/bus/iio/devices/iio:deviceX/out_current_heater_raw
+What:		/sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available
+KernelVersion:	4.3
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Controls the heater device within the humidity sensor to get
+		rid of excess condensation.
+
+		Valid control values are 0 = OFF, and 1 = ON.

+ 22 - 0
Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs

@@ -18,3 +18,25 @@ Description:
 		trigger. In order to associate the trigger with an IIO device
 		trigger. In order to associate the trigger with an IIO device
 		one should write this name string to
 		one should write this name string to
 		/sys/bus/iio/devices/iio:deviceY/trigger/current_trigger.
 		/sys/bus/iio/devices/iio:deviceY/trigger/current_trigger.
+
+What:		/sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
+KernelVersion:	2.6.39
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is provided by the iio-trig-sysfs stand-alone
+		driver and it is used to activate the creation of a new trigger.
+		In order to achieve this, one should write a positive integer
+		into the associated file, which will serve as the id of the
+		trigger. If the trigger with the specified id is already present
+		in the system, an invalid argument message will be returned.
+
+What:		/sys/bus/iio/devices/iio_sysfs_trigger/remove_trigger
+KernelVersion:	2.6.39
+Contact:	linux-iio@vger.kernel.org
+Description:
+		This attribute is used to unregister and delete a previously
+		created trigger from the list of available triggers. In order to
+		achieve this, one should write a positive integer into the
+		associated file, representing the id of the trigger that needs
+		to be removed. If the trigger can't be found, an invalid
+		argument message will be returned to the user.

+ 1 - 1
Documentation/DocBook/iio.tmpl

@@ -578,7 +578,7 @@
     work together.
     work together.
     </para>
     </para>
     <sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
     <sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
-!Edrivers/iio/industrialio-triggered-buffer.c
+!Edrivers/iio/buffer/industrialio-triggered-buffer.c
 !Finclude/linux/iio/iio.h iio_buffer_setup_ops
 !Finclude/linux/iio/iio.h iio_buffer_setup_ops
 
 
 
 

+ 2 - 1
Documentation/devicetree/bindings/i2c/trivial-devices.txt

@@ -54,7 +54,6 @@ epson,rx8581		I2C-BUS INTERFACE REAL TIME CLOCK MODULE
 fsl,mag3110		MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
 fsl,mag3110		MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
 fsl,mc13892		MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
 fsl,mc13892		MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
 fsl,mma8450		MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
 fsl,mma8450		MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
-fsl,mma8452		MMA8452Q: 3-axis 12-bit / 8-bit Digital Accelerometer
 fsl,mpr121		MPR121: Proximity Capacitive Touch Sensor Controller
 fsl,mpr121		MPR121: Proximity Capacitive Touch Sensor Controller
 fsl,sgtl5000		SGTL5000: Ultra Low-Power Audio Codec
 fsl,sgtl5000		SGTL5000: Ultra Low-Power Audio Codec
 gmt,g751		G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
 gmt,g751		G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
@@ -80,6 +79,7 @@ oki,ml86v7667		OKI ML86V7667 video decoder
 ovti,ov5642		OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus
 ovti,ov5642		OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus
 pericom,pt7c4338	Real-time Clock Module
 pericom,pt7c4338	Real-time Clock Module
 plx,pex8648		48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
 plx,pex8648		48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
+pulsedlight,lidar-lite-v2	Pulsedlight LIDAR range-finding sensor
 ramtron,24c64		i2c serial eeprom  (24cxx)
 ramtron,24c64		i2c serial eeprom  (24cxx)
 ricoh,r2025sd		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,r2025sd		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,r2221tl		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,r2221tl		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
@@ -88,6 +88,7 @@ ricoh,rs5c372b		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,rv5c386		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,rv5c386		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,rv5c387a		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 ricoh,rv5c387a		I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
 samsung,24ad0xd1	S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
 samsung,24ad0xd1	S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
+sgx,vz89x		SGX Sensortech VZ89X Sensors
 sii,s35390a		2-wire CMOS real-time clock
 sii,s35390a		2-wire CMOS real-time clock
 skyworks,sky81452	Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
 skyworks,sky81452	Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
 st-micro,24c256		i2c serial eeprom  (24cxx)
 st-micro,24c256		i2c serial eeprom  (24cxx)

+ 24 - 0
Documentation/devicetree/bindings/iio/accel/mma8452.txt

@@ -0,0 +1,24 @@
+Freescale MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC triaxial accelerometer
+
+Required properties:
+
+  - compatible: should contain one of
+    * "fsl,mma8452"
+    * "fsl,mma8453"
+    * "fsl,mma8652"
+    * "fsl,mma8653"
+  - reg: the I2C address of the chip
+
+Optional properties:
+
+  - interrupt-parent: should be the phandle for the interrupt controller
+  - interrupts: interrupt mapping for GPIO IRQ
+
+Example:
+
+	mma8453fc@1d {
+		compatible = "fsl,mma8453";
+		reg = <0x1d>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <5 0>;
+	};

+ 21 - 0
Documentation/devicetree/bindings/iio/adc/hi8435.txt

@@ -0,0 +1,21 @@
+Holt Integrated Circuits HI-8435 threshold detector bindings
+
+Required properties:
+ - compatible: should be "holt,hi8435"
+ - reg: spi chip select number for the device
+
+Recommended properties:
+ - spi-max-frequency: definition as per
+		Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+ - gpios: GPIO used for controlling the reset pin
+
+Example:
+sensor@0 {
+	compatible = "holt,hi8435";
+	reg = <0>;
+	gpios = <&gpio6 1 0>;
+
+	spi-max-frequency = <1000000>;
+};

+ 22 - 0
Documentation/devicetree/bindings/iio/light/apds9960.txt

@@ -0,0 +1,22 @@
+* Avago APDS9960 gesture/RGB/ALS/proximity sensor
+
+http://www.avagotech.com/docs/AV02-4191EN
+
+Required properties:
+
+  - compatible: must be "avago,apds9960"
+  - 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.
+
+Example:
+
+apds9960@39 {
+	compatible = "avago,apds9960";
+	reg = <0x39>;
+	interrupt-parent = <&gpio1>;
+	interrupts = <16 1>;
+};

+ 34 - 0
Documentation/devicetree/bindings/iio/light/us5182d.txt

@@ -0,0 +1,34 @@
+* UPISEMI us5182d I2C ALS and Proximity sensor
+
+Required properties:
+- compatible: must be "upisemi,usd5182"
+- reg: the I2C address of the device
+
+Optional properties:
+- upisemi,glass-coef: glass attenuation factor - compensation factor of
+                      resolution 1000 for material transmittance.
+- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc
+                    counts) corresponding to every scale.
+- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4
+                           fractional bits - Q4.4) applied when light > threshold
+- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4
+                           fractional bits - Q4.4) applied when light < threshold
+
+If the optional properties are not specified these factors will default to the
+values in the below example.
+The glass-coef defaults to no compensation for the covering material.
+The threshold array defaults to experimental values that work with US5182D
+sensor on evaluation board - roughly between 12-32 lux.
+There will be no dark-gain compensation by default when ALS > thresh
+(0 * dark-gain), and a 1.35 compensation factor when ALS < thresh.
+
+Example:
+
+    usd5182@39 {
+                compatible = "upisemi,usd5182";
+                reg = <0x39>;
+                upisemi,glass-coef = < 1000 >;
+                upisemi,dark-ths = /bits/ 16 <170 200 512 512 800 2000 4000 8000>;
+                upisemi,upper-dark-gain = /bits/ 8 <0x00>;
+                upisemi,lower-dark-gain = /bits/ 8 <0x16>;
+    };

+ 4 - 0
Documentation/devicetree/bindings/vendor-prefixes.txt

@@ -101,6 +101,7 @@ himax	Himax Technologies, Inc.
 hisilicon	Hisilicon Limited.
 hisilicon	Hisilicon Limited.
 hit	Hitachi Ltd.
 hit	Hitachi Ltd.
 hitex	Hitex Development Tools
 hitex	Hitex Development Tools
+holt	Holt Integrated Circuits, Inc.
 honeywell	Honeywell
 honeywell	Honeywell
 hp	Hewlett Packard
 hp	Hewlett Packard
 i2se	I2SE GmbH
 i2se	I2SE GmbH
@@ -169,6 +170,7 @@ phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
 picochip	Picochip Ltd
 plathome	Plat'Home Co., Ltd.
 plathome	Plat'Home Co., Ltd.
 pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 pixcir  PIXCIR MICROELECTRONICS Co., Ltd
+pulsedlight	PulsedLight, Inc
 powervr	PowerVR (deprecated, use img)
 powervr	PowerVR (deprecated, use img)
 qca	Qualcomm Atheros, Inc.
 qca	Qualcomm Atheros, Inc.
 qcom	Qualcomm Technologies, Inc
 qcom	Qualcomm Technologies, Inc
@@ -191,6 +193,7 @@ sbs	Smart Battery System
 schindler	Schindler
 schindler	Schindler
 seagate	Seagate Technology PLC
 seagate	Seagate Technology PLC
 semtech	Semtech Corporation
 semtech	Semtech Corporation
+sgx	SGX Sensortech
 sharp	Sharp Corporation
 sharp	Sharp Corporation
 sil	Silicon Image
 sil	Silicon Image
 silabs	Silicon Laboratories
 silabs	Silicon Laboratories
@@ -223,6 +226,7 @@ toshiba	Toshiba Corporation
 toumaz	Toumaz
 toumaz	Toumaz
 tplink	TP-LINK Technologies Co., Ltd.
 tplink	TP-LINK Technologies Co., Ltd.
 truly	Truly Semiconductors Limited
 truly	Truly Semiconductors Limited
+upisemi	uPI Semiconductor Corp.
 usi	Universal Scientific Industrial Co., Ltd.
 usi	Universal Scientific Industrial Co., Ltd.
 v3	V3 Semiconductor
 v3	V3 Semiconductor
 variscite	Variscite Ltd.
 variscite	Variscite Ltd.

+ 7 - 0
MAINTAINERS

@@ -6918,6 +6918,13 @@ S:	Supported
 F:	include/linux/mlx5/
 F:	include/linux/mlx5/
 F:	drivers/infiniband/hw/mlx5/
 F:	drivers/infiniband/hw/mlx5/
 
 
+MELEXIS MLX90614 DRIVER
+M:	Crt Mori <cmo@melexis.com>
+L:	linux-iio@vger.kernel.org
+W:	http://www.melexis.com
+S:	Supported
+F:	drivers/iio/temperature/mlx90614.c
+
 MN88472 MEDIA DRIVER
 MN88472 MEDIA DRIVER
 M:	Antti Palosaari <crope@iki.fi>
 M:	Antti Palosaari <crope@iki.fi>
 L:	linux-media@vger.kernel.org
 L:	linux-media@vger.kernel.org

+ 8 - 21
drivers/iio/Kconfig

@@ -19,27 +19,7 @@ config IIO_BUFFER
 	  acquisition methods.
 	  acquisition methods.
 
 
 if IIO_BUFFER
 if IIO_BUFFER
-
-config IIO_BUFFER_CB
-	bool "IIO callback buffer used for push in-kernel interfaces"
-	help
-	  Should be selected by any drivers that do in-kernel push
-	  usage.  That is, those where the data is pushed to the consumer.
-
-config IIO_KFIFO_BUF
-	tristate "Industrial I/O buffering based on kfifo"
-	help
-	  A simple fifo based on kfifo.  Note that this currently provides
-	  no buffer events so it is up to userspace to work out how
-	  often to read from the buffer.
-
-config IIO_TRIGGERED_BUFFER
-	tristate
-	select IIO_TRIGGER
-	select IIO_KFIFO_BUF
-	help
-	  Provides helper functions for setting up triggered buffers.
-
+	source "drivers/iio/buffer/Kconfig"
 endif # IIO_BUFFER
 endif # IIO_BUFFER
 
 
 config IIO_TRIGGER
 config IIO_TRIGGER
@@ -58,9 +38,16 @@ config IIO_CONSUMERS_PER_TRIGGER
 	This value controls the maximum number of consumers that a
 	This value controls the maximum number of consumers that a
 	given trigger may handle. Default is 2.
 	given trigger may handle. Default is 2.
 
 
+config IIO_TRIGGERED_EVENT
+	tristate
+	select IIO_TRIGGER
+	help
+	  Provides helper functions for setting up triggered events.
+
 source "drivers/iio/accel/Kconfig"
 source "drivers/iio/accel/Kconfig"
 source "drivers/iio/adc/Kconfig"
 source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
+source "drivers/iio/chemical/Kconfig"
 source "drivers/iio/common/Kconfig"
 source "drivers/iio/common/Kconfig"
 source "drivers/iio/dac/Kconfig"
 source "drivers/iio/dac/Kconfig"
 source "drivers/iio/frequency/Kconfig"
 source "drivers/iio/frequency/Kconfig"

+ 3 - 3
drivers/iio/Makefile

@@ -6,14 +6,14 @@ obj-$(CONFIG_IIO) += industrialio.o
 industrialio-y := industrialio-core.o industrialio-event.o inkern.o
 industrialio-y := industrialio-core.o industrialio-event.o inkern.o
 industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
 
 
-obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
 
 
 obj-y += accel/
 obj-y += accel/
 obj-y += adc/
 obj-y += adc/
 obj-y += amplifiers/
 obj-y += amplifiers/
+obj-y += buffer/
+obj-y += chemical/
 obj-y += common/
 obj-y += common/
 obj-y += dac/
 obj-y += dac/
 obj-y += gyro/
 obj-y += gyro/

+ 16 - 3
drivers/iio/accel/Kconfig

@@ -100,13 +100,13 @@ config KXCJK1013
 	  be called kxcjk-1013.
 	  be called kxcjk-1013.
 
 
 config MMA8452
 config MMA8452
-	tristate "Freescale MMA8452Q Accelerometer Driver"
+	tristate "Freescale MMA8452Q and similar Accelerometers Driver"
 	depends on I2C
 	depends on I2C
 	select IIO_BUFFER
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
 	help
-	  Say yes here to build support for the Freescale MMA8452Q 3-axis
-	  accelerometer.
+	  Say yes here to build support for the following Freescale 3-axis
+	  accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
 
 
 	  To compile this driver as a module, choose M here: the module
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma8452.
 	  will be called mma8452.
@@ -137,6 +137,19 @@ config MMA9553
 	  To compile this driver as a module, choose M here: the module
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma9553.
 	  will be called mma9553.
 
 
+config MXC4005
+	tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
+	depends on I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select REGMAP_I2C
+	help
+	  Say yes here to build support for the Memsic MXC4005XC 3-axis
+	  accelerometer.
+
+	  To compile this driver as a module, choose M. The module will be
+	  called mxc4005.
+
 config STK8312
 config STK8312
 	tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
 	tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
 	depends on I2C
 	depends on I2C

+ 2 - 0
drivers/iio/accel/Makefile

@@ -14,6 +14,8 @@ obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
 obj-$(CONFIG_MMA9551)		+= mma9551.o
 obj-$(CONFIG_MMA9551)		+= mma9551.o
 obj-$(CONFIG_MMA9553)		+= mma9553.o
 obj-$(CONFIG_MMA9553)		+= mma9553.o
 
 
+obj-$(CONFIG_MXC4005)		+= mxc4005.o
+
 obj-$(CONFIG_STK8312)		+= stk8312.o
 obj-$(CONFIG_STK8312)		+= stk8312.o
 obj-$(CONFIG_STK8BA50)		+= stk8ba50.o
 obj-$(CONFIG_STK8BA50)		+= stk8ba50.o
 
 

+ 292 - 64
drivers/iio/accel/mma8452.c

@@ -1,6 +1,12 @@
 /*
 /*
- * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer
+ * mma8452.c - Support for following Freescale 3-axis accelerometers:
  *
  *
+ * MMA8452Q (12 bit)
+ * MMA8453Q (10 bit)
+ * MMA8652FC (12 bit)
+ * MMA8653FC (10 bit)
+ *
+ * Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
  * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
  * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
  *
  *
  * This file is subject to the terms and conditions of version 2 of
  * This file is subject to the terms and conditions of version 2 of
@@ -22,10 +28,11 @@
 #include <linux/iio/triggered_buffer.h>
 #include <linux/iio/triggered_buffer.h>
 #include <linux/iio/events.h>
 #include <linux/iio/events.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
+#include <linux/of_device.h>
 
 
 #define MMA8452_STATUS				0x00
 #define MMA8452_STATUS				0x00
 #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
 #define  MMA8452_STATUS_DRDY			(BIT(2) | BIT(1) | BIT(0))
-#define MMA8452_OUT_X				0x01 /* MSB first, 12-bit  */
+#define MMA8452_OUT_X				0x01 /* MSB first */
 #define MMA8452_OUT_Y				0x03
 #define MMA8452_OUT_Y				0x03
 #define MMA8452_OUT_Z				0x05
 #define MMA8452_OUT_Z				0x05
 #define MMA8452_INT_SRC				0x0c
 #define MMA8452_INT_SRC				0x0c
@@ -38,6 +45,16 @@
 #define  MMA8452_DATA_CFG_HPF_MASK		BIT(4)
 #define  MMA8452_DATA_CFG_HPF_MASK		BIT(4)
 #define MMA8452_HP_FILTER_CUTOFF		0x0f
 #define MMA8452_HP_FILTER_CUTOFF		0x0f
 #define  MMA8452_HP_FILTER_CUTOFF_SEL_MASK	GENMASK(1, 0)
 #define  MMA8452_HP_FILTER_CUTOFF_SEL_MASK	GENMASK(1, 0)
+#define MMA8452_FF_MT_CFG			0x15
+#define  MMA8452_FF_MT_CFG_OAE			BIT(6)
+#define  MMA8452_FF_MT_CFG_ELE			BIT(7)
+#define MMA8452_FF_MT_SRC			0x16
+#define  MMA8452_FF_MT_SRC_XHE			BIT(1)
+#define  MMA8452_FF_MT_SRC_YHE			BIT(3)
+#define  MMA8452_FF_MT_SRC_ZHE			BIT(5)
+#define MMA8452_FF_MT_THS			0x17
+#define  MMA8452_FF_MT_THS_MASK			0x7f
+#define MMA8452_FF_MT_COUNT			0x18
 #define MMA8452_TRANSIENT_CFG			0x1d
 #define MMA8452_TRANSIENT_CFG			0x1d
 #define  MMA8452_TRANSIENT_CFG_HPF_BYP		BIT(0)
 #define  MMA8452_TRANSIENT_CFG_HPF_BYP		BIT(0)
 #define  MMA8452_TRANSIENT_CFG_CHAN(chan)	BIT(chan + 1)
 #define  MMA8452_TRANSIENT_CFG_CHAN(chan)	BIT(chan + 1)
@@ -65,15 +82,65 @@
 #define MMA8452_MAX_REG				0x31
 #define MMA8452_MAX_REG				0x31
 
 
 #define  MMA8452_INT_DRDY			BIT(0)
 #define  MMA8452_INT_DRDY			BIT(0)
+#define  MMA8452_INT_FF_MT			BIT(2)
 #define  MMA8452_INT_TRANS			BIT(5)
 #define  MMA8452_INT_TRANS			BIT(5)
 
 
 #define  MMA8452_DEVICE_ID			0x2a
 #define  MMA8452_DEVICE_ID			0x2a
+#define  MMA8453_DEVICE_ID			0x3a
+#define MMA8652_DEVICE_ID			0x4a
+#define MMA8653_DEVICE_ID			0x5a
 
 
 struct mma8452_data {
 struct mma8452_data {
 	struct i2c_client *client;
 	struct i2c_client *client;
 	struct mutex lock;
 	struct mutex lock;
 	u8 ctrl_reg1;
 	u8 ctrl_reg1;
 	u8 data_cfg;
 	u8 data_cfg;
+	const struct mma_chip_info *chip_info;
+};
+
+/**
+ * struct mma_chip_info - chip specific data for Freescale's accelerometers
+ * @chip_id:			WHO_AM_I register's value
+ * @channels:			struct iio_chan_spec matching the device's
+ *				capabilities
+ * @num_channels:		number of channels
+ * @mma_scales:			scale factors for converting register values
+ *				to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers
+ *				per mode: m/s^2 and micro m/s^2
+ * @ev_cfg:			event config register address
+ * @ev_cfg_ele:			latch bit in event config register
+ * @ev_cfg_chan_shift:		number of the bit to enable events in X
+ *				direction; in event config register
+ * @ev_src:			event source register address
+ * @ev_src_xe:			bit in event source register that indicates
+ *				an event in X direction
+ * @ev_src_ye:			bit in event source register that indicates
+ *				an event in Y direction
+ * @ev_src_ze:			bit in event source register that indicates
+ *				an event in Z direction
+ * @ev_ths:			event threshold register address
+ * @ev_ths_mask:		mask for the threshold value
+ * @ev_count:			event count (period) register address
+ *
+ * Since not all chips supported by the driver support comparing high pass
+ * filtered data for events (interrupts), different interrupt sources are
+ * used for different chips and the relevant registers are included here.
+ */
+struct mma_chip_info {
+	u8 chip_id;
+	const struct iio_chan_spec *channels;
+	int num_channels;
+	const int mma_scales[3][2];
+	u8 ev_cfg;
+	u8 ev_cfg_ele;
+	u8 ev_cfg_chan_shift;
+	u8 ev_src;
+	u8 ev_src_xe;
+	u8 ev_src_ye;
+	u8 ev_src_ze;
+	u8 ev_ths;
+	u8 ev_ths_mask;
+	u8 ev_count;
 };
 };
 
 
 static int mma8452_drdy(struct mma8452_data *data)
 static int mma8452_drdy(struct mma8452_data *data)
@@ -143,16 +210,6 @@ static const int mma8452_samp_freq[8][2] = {
 	{6, 250000}, {1, 560000}
 	{6, 250000}, {1, 560000}
 };
 };
 
 
-/*
- * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
- * The userspace interface uses m/s^2 and we declare micro units
- * So scale factor is given by:
- *	g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665
- */
-static const int mma8452_scales[3][2] = {
-	{0, 9577}, {0, 19154}, {0, 38307}
-};
-
 /* Datasheet table 35  (step time vs sample frequency) */
 /* Datasheet table 35  (step time vs sample frequency) */
 static const int mma8452_transient_time_step_us[8] = {
 static const int mma8452_transient_time_step_us[8] = {
 	1250,
 	1250,
@@ -189,8 +246,11 @@ static ssize_t mma8452_show_scale_avail(struct device *dev,
 					struct device_attribute *attr,
 					struct device_attribute *attr,
 					char *buf)
 					char *buf)
 {
 {
-	return mma8452_show_int_plus_micros(buf, mma8452_scales,
-					    ARRAY_SIZE(mma8452_scales));
+	struct mma8452_data *data = iio_priv(i2c_get_clientdata(
+					     to_i2c_client(dev)));
+
+	return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales,
+		ARRAY_SIZE(data->chip_info->mma_scales));
 }
 }
 
 
 static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
 static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
@@ -221,9 +281,8 @@ static int mma8452_get_samp_freq_index(struct mma8452_data *data,
 
 
 static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
 static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
 {
 {
-	return mma8452_get_int_plus_micros_index(mma8452_scales,
-						 ARRAY_SIZE(mma8452_scales),
-						 val, val2);
+	return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales,
+			ARRAY_SIZE(data->chip_info->mma_scales), val, val2);
 }
 }
 
 
 static int mma8452_get_hp_filter_index(struct mma8452_data *data,
 static int mma8452_get_hp_filter_index(struct mma8452_data *data,
@@ -270,14 +329,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 
 
-		*val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4,
-				     11);
+		*val = sign_extend32(be16_to_cpu(
+			buffer[chan->scan_index]) >> chan->scan_type.shift,
+			chan->scan_type.realbits - 1);
 
 
 		return IIO_VAL_INT;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 	case IIO_CHAN_INFO_SCALE:
 		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
 		i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
-		*val = mma8452_scales[i][0];
-		*val2 = mma8452_scales[i][1];
+		*val = data->chip_info->mma_scales[i][0];
+		*val2 = data->chip_info->mma_scales[i][1];
 
 
 		return IIO_VAL_INT_PLUS_MICRO;
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_SAMP_FREQ:
 	case IIO_CHAN_INFO_SAMP_FREQ:
@@ -439,17 +499,17 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
 	switch (info) {
 	switch (info) {
 	case IIO_EV_INFO_VALUE:
 	case IIO_EV_INFO_VALUE:
 		ret = i2c_smbus_read_byte_data(data->client,
 		ret = i2c_smbus_read_byte_data(data->client,
-					       MMA8452_TRANSIENT_THS);
+					       data->chip_info->ev_ths);
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 
 
-		*val = ret & MMA8452_TRANSIENT_THS_MASK;
+		*val = ret & data->chip_info->ev_ths_mask;
 
 
 		return IIO_VAL_INT;
 		return IIO_VAL_INT;
 
 
 	case IIO_EV_INFO_PERIOD:
 	case IIO_EV_INFO_PERIOD:
 		ret = i2c_smbus_read_byte_data(data->client,
 		ret = i2c_smbus_read_byte_data(data->client,
-					       MMA8452_TRANSIENT_COUNT);
+					       data->chip_info->ev_count);
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 
 
@@ -497,7 +557,8 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
 		if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
 		if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
 			return -EINVAL;
 			return -EINVAL;
 
 
-		return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
+		return mma8452_change_config(data, data->chip_info->ev_ths,
+					     val);
 
 
 	case IIO_EV_INFO_PERIOD:
 	case IIO_EV_INFO_PERIOD:
 		steps = (val * USEC_PER_SEC + val2) /
 		steps = (val * USEC_PER_SEC + val2) /
@@ -507,7 +568,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
 		if (steps < 0 || steps > 0xff)
 		if (steps < 0 || steps > 0xff)
 			return -EINVAL;
 			return -EINVAL;
 
 
-		return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
+		return mma8452_change_config(data, data->chip_info->ev_count,
 					     steps);
 					     steps);
 
 
 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
 	case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
@@ -538,13 +599,15 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
 				     enum iio_event_direction dir)
 				     enum iio_event_direction dir)
 {
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
 	struct mma8452_data *data = iio_priv(indio_dev);
+	const struct mma_chip_info *chip = data->chip_info;
 	int ret;
 	int ret;
 
 
-	ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
+	ret = i2c_smbus_read_byte_data(data->client,
+				       data->chip_info->ev_cfg);
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0;
+	return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
 }
 }
 
 
 static int mma8452_write_event_config(struct iio_dev *indio_dev,
 static int mma8452_write_event_config(struct iio_dev *indio_dev,
@@ -554,20 +617,22 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
 				      int state)
 				      int state)
 {
 {
 	struct mma8452_data *data = iio_priv(indio_dev);
 	struct mma8452_data *data = iio_priv(indio_dev);
+	const struct mma_chip_info *chip = data->chip_info;
 	int val;
 	int val;
 
 
-	val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG);
+	val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
 	if (val < 0)
 	if (val < 0)
 		return val;
 		return val;
 
 
 	if (state)
 	if (state)
-		val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
+		val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
 	else
 	else
-		val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index);
+		val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
 
 
-	val |= MMA8452_TRANSIENT_CFG_ELE;
+	val |= chip->ev_cfg_ele;
+	val |= MMA8452_FF_MT_CFG_OAE;
 
 
-	return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val);
+	return mma8452_change_config(data, chip->ev_cfg, val);
 }
 }
 
 
 static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
 static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
@@ -576,25 +641,25 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
 	s64 ts = iio_get_time_ns();
 	s64 ts = iio_get_time_ns();
 	int src;
 	int src;
 
 
-	src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC);
+	src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src);
 	if (src < 0)
 	if (src < 0)
 		return;
 		return;
 
 
-	if (src & MMA8452_TRANSIENT_SRC_XTRANSE)
+	if (src & data->chip_info->ev_src_xe)
 		iio_push_event(indio_dev,
 		iio_push_event(indio_dev,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
 						  IIO_EV_TYPE_MAG,
 						  IIO_EV_TYPE_MAG,
 						  IIO_EV_DIR_RISING),
 						  IIO_EV_DIR_RISING),
 			       ts);
 			       ts);
 
 
-	if (src & MMA8452_TRANSIENT_SRC_YTRANSE)
+	if (src & data->chip_info->ev_src_ye)
 		iio_push_event(indio_dev,
 		iio_push_event(indio_dev,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y,
 						  IIO_EV_TYPE_MAG,
 						  IIO_EV_TYPE_MAG,
 						  IIO_EV_DIR_RISING),
 						  IIO_EV_DIR_RISING),
 			       ts);
 			       ts);
 
 
-	if (src & MMA8452_TRANSIENT_SRC_ZTRANSE)
+	if (src & data->chip_info->ev_src_ze)
 		iio_push_event(indio_dev,
 		iio_push_event(indio_dev,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
 			       IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z,
 						  IIO_EV_TYPE_MAG,
 						  IIO_EV_TYPE_MAG,
@@ -606,6 +671,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
 {
 {
 	struct iio_dev *indio_dev = p;
 	struct iio_dev *indio_dev = p;
 	struct mma8452_data *data = iio_priv(indio_dev);
 	struct mma8452_data *data = iio_priv(indio_dev);
+	const struct mma_chip_info *chip = data->chip_info;
 	int ret = IRQ_NONE;
 	int ret = IRQ_NONE;
 	int src;
 	int src;
 
 
@@ -618,7 +684,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
 		ret = IRQ_HANDLED;
 		ret = IRQ_HANDLED;
 	}
 	}
 
 
-	if (src & MMA8452_INT_TRANS) {
+	if ((src & MMA8452_INT_TRANS &&
+	     chip->ev_src == MMA8452_TRANSIENT_SRC) ||
+	    (src & MMA8452_INT_FF_MT &&
+	     chip->ev_src == MMA8452_FF_MT_SRC)) {
 		mma8452_transient_interrupt(indio_dev);
 		mma8452_transient_interrupt(indio_dev);
 		ret = IRQ_HANDLED;
 		ret = IRQ_HANDLED;
 	}
 	}
@@ -680,6 +749,16 @@ static const struct iio_event_spec mma8452_transient_event[] = {
 	},
 	},
 };
 };
 
 
+static const struct iio_event_spec mma8452_motion_event[] = {
+	{
+		.type = IIO_EV_TYPE_MAG,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+					BIT(IIO_EV_INFO_PERIOD)
+	},
+};
+
 /*
 /*
  * Threshold is configured in fixed 8G/127 steps regardless of
  * Threshold is configured in fixed 8G/127 steps regardless of
  * currently selected scale for measurement.
  * currently selected scale for measurement.
@@ -693,10 +772,9 @@ static struct attribute *mma8452_event_attributes[] = {
 
 
 static struct attribute_group mma8452_event_attribute_group = {
 static struct attribute_group mma8452_event_attribute_group = {
 	.attrs = mma8452_event_attributes,
 	.attrs = mma8452_event_attributes,
-	.name = "events",
 };
 };
 
 
-#define MMA8452_CHANNEL(axis, idx) { \
+#define MMA8452_CHANNEL(axis, idx, bits) { \
 	.type = IIO_ACCEL, \
 	.type = IIO_ACCEL, \
 	.modified = 1, \
 	.modified = 1, \
 	.channel2 = IIO_MOD_##axis, \
 	.channel2 = IIO_MOD_##axis, \
@@ -708,22 +786,144 @@ static struct attribute_group mma8452_event_attribute_group = {
 	.scan_index = idx, \
 	.scan_index = idx, \
 	.scan_type = { \
 	.scan_type = { \
 		.sign = 's', \
 		.sign = 's', \
-		.realbits = 12, \
+		.realbits = (bits), \
 		.storagebits = 16, \
 		.storagebits = 16, \
-		.shift = 4, \
+		.shift = 16 - (bits), \
 		.endianness = IIO_BE, \
 		.endianness = IIO_BE, \
 	}, \
 	}, \
 	.event_spec = mma8452_transient_event, \
 	.event_spec = mma8452_transient_event, \
 	.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
 	.num_event_specs = ARRAY_SIZE(mma8452_transient_event), \
 }
 }
 
 
+#define MMA8652_CHANNEL(axis, idx, bits) { \
+	.type = IIO_ACCEL, \
+	.modified = 1, \
+	.channel2 = IIO_MOD_##axis, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+		BIT(IIO_CHAN_INFO_CALIBBIAS), \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+		BIT(IIO_CHAN_INFO_SCALE), \
+	.scan_index = idx, \
+	.scan_type = { \
+		.sign = 's', \
+		.realbits = (bits), \
+		.storagebits = 16, \
+		.shift = 16 - (bits), \
+		.endianness = IIO_BE, \
+	}, \
+	.event_spec = mma8452_motion_event, \
+	.num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
+}
+
 static const struct iio_chan_spec mma8452_channels[] = {
 static const struct iio_chan_spec mma8452_channels[] = {
-	MMA8452_CHANNEL(X, 0),
-	MMA8452_CHANNEL(Y, 1),
-	MMA8452_CHANNEL(Z, 2),
+	MMA8452_CHANNEL(X, 0, 12),
+	MMA8452_CHANNEL(Y, 1, 12),
+	MMA8452_CHANNEL(Z, 2, 12),
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 };
 
 
+static const struct iio_chan_spec mma8453_channels[] = {
+	MMA8452_CHANNEL(X, 0, 10),
+	MMA8452_CHANNEL(Y, 1, 10),
+	MMA8452_CHANNEL(Z, 2, 10),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec mma8652_channels[] = {
+	MMA8652_CHANNEL(X, 0, 12),
+	MMA8652_CHANNEL(Y, 1, 12),
+	MMA8652_CHANNEL(Z, 2, 12),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec mma8653_channels[] = {
+	MMA8652_CHANNEL(X, 0, 10),
+	MMA8652_CHANNEL(Y, 1, 10),
+	MMA8652_CHANNEL(Z, 2, 10),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+enum {
+	mma8452,
+	mma8453,
+	mma8652,
+	mma8653,
+};
+
+static const struct mma_chip_info mma_chip_info_table[] = {
+	[mma8452] = {
+		.chip_id = MMA8452_DEVICE_ID,
+		.channels = mma8452_channels,
+		.num_channels = ARRAY_SIZE(mma8452_channels),
+		/*
+		 * Hardware has fullscale of -2G, -4G, -8G corresponding to
+		 * raw value -2048 for 12 bit or -512 for 10 bit.
+		 * The userspace interface uses m/s^2 and we declare micro units
+		 * So scale factor for 12 bit here is given by:
+		 *	g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
+		 */
+		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
+		.ev_cfg = MMA8452_TRANSIENT_CFG,
+		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+		.ev_cfg_chan_shift = 1,
+		.ev_src = MMA8452_TRANSIENT_SRC,
+		.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
+		.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
+		.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
+		.ev_ths = MMA8452_TRANSIENT_THS,
+		.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+		.ev_count = MMA8452_TRANSIENT_COUNT,
+	},
+	[mma8453] = {
+		.chip_id = MMA8453_DEVICE_ID,
+		.channels = mma8453_channels,
+		.num_channels = ARRAY_SIZE(mma8453_channels),
+		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
+		.ev_cfg = MMA8452_TRANSIENT_CFG,
+		.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
+		.ev_cfg_chan_shift = 1,
+		.ev_src = MMA8452_TRANSIENT_SRC,
+		.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
+		.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
+		.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
+		.ev_ths = MMA8452_TRANSIENT_THS,
+		.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
+		.ev_count = MMA8452_TRANSIENT_COUNT,
+	},
+	[mma8652] = {
+		.chip_id = MMA8652_DEVICE_ID,
+		.channels = mma8652_channels,
+		.num_channels = ARRAY_SIZE(mma8652_channels),
+		.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
+		.ev_cfg = MMA8452_FF_MT_CFG,
+		.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
+		.ev_cfg_chan_shift = 3,
+		.ev_src = MMA8452_FF_MT_SRC,
+		.ev_src_xe = MMA8452_FF_MT_SRC_XHE,
+		.ev_src_ye = MMA8452_FF_MT_SRC_YHE,
+		.ev_src_ze = MMA8452_FF_MT_SRC_ZHE,
+		.ev_ths = MMA8452_FF_MT_THS,
+		.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
+		.ev_count = MMA8452_FF_MT_COUNT,
+	},
+	[mma8653] = {
+		.chip_id = MMA8653_DEVICE_ID,
+		.channels = mma8653_channels,
+		.num_channels = ARRAY_SIZE(mma8653_channels),
+		.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} },
+		.ev_cfg = MMA8452_FF_MT_CFG,
+		.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
+		.ev_cfg_chan_shift = 3,
+		.ev_src = MMA8452_FF_MT_SRC,
+		.ev_src_xe = MMA8452_FF_MT_SRC_XHE,
+		.ev_src_ye = MMA8452_FF_MT_SRC_YHE,
+		.ev_src_ze = MMA8452_FF_MT_SRC_ZHE,
+		.ev_ths = MMA8452_FF_MT_THS,
+		.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
+		.ev_count = MMA8452_FF_MT_COUNT,
+	},
+};
+
 static struct attribute *mma8452_attributes[] = {
 static struct attribute *mma8452_attributes[] = {
 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
@@ -841,18 +1041,28 @@ static int mma8452_reset(struct i2c_client *client)
 	return -ETIMEDOUT;
 	return -ETIMEDOUT;
 }
 }
 
 
+static const struct of_device_id mma8452_dt_ids[] = {
+	{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
+	{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
+	{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
+	{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
+
 static int mma8452_probe(struct i2c_client *client,
 static int mma8452_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 			 const struct i2c_device_id *id)
 {
 {
 	struct mma8452_data *data;
 	struct mma8452_data *data;
 	struct iio_dev *indio_dev;
 	struct iio_dev *indio_dev;
 	int ret;
 	int ret;
+	const struct of_device_id *match;
 
 
-	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
-	if (ret < 0)
-		return ret;
-	if (ret != MMA8452_DEVICE_ID)
+	match = of_match_device(mma8452_dt_ids, &client->dev);
+	if (!match) {
+		dev_err(&client->dev, "unknown device model\n");
 		return -ENODEV;
 		return -ENODEV;
+	}
 
 
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
 	if (!indio_dev)
@@ -861,14 +1071,33 @@ static int mma8452_probe(struct i2c_client *client,
 	data = iio_priv(indio_dev);
 	data = iio_priv(indio_dev);
 	data->client = client;
 	data->client = client;
 	mutex_init(&data->lock);
 	mutex_init(&data->lock);
+	data->chip_info = match->data;
+
+	ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
+	if (ret < 0)
+		return ret;
+
+	switch (ret) {
+	case MMA8452_DEVICE_ID:
+	case MMA8453_DEVICE_ID:
+	case MMA8652_DEVICE_ID:
+	case MMA8653_DEVICE_ID:
+		if (ret == data->chip_info->chip_id)
+			break;
+	default:
+		return -ENODEV;
+	}
+
+	dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
+		 match->compatible, data->chip_info->chip_id);
 
 
 	i2c_set_clientdata(client, indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 	indio_dev->info = &mma8452_info;
 	indio_dev->info = &mma8452_info;
 	indio_dev->name = id->name;
 	indio_dev->name = id->name;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->dev.parent = &client->dev;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	indio_dev->channels = mma8452_channels;
-	indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
+	indio_dev->channels = data->chip_info->channels;
+	indio_dev->num_channels = data->chip_info->num_channels;
 	indio_dev->available_scan_masks = mma8452_scan_masks;
 	indio_dev->available_scan_masks = mma8452_scan_masks;
 
 
 	ret = mma8452_reset(client);
 	ret = mma8452_reset(client);
@@ -892,13 +1121,15 @@ static int mma8452_probe(struct i2c_client *client,
 
 
 	if (client->irq) {
 	if (client->irq) {
 		/*
 		/*
-		 * Although we enable the transient interrupt source once and
-		 * for all here the transient event detection itself is not
-		 * enabled until userspace asks for it by
-		 * mma8452_write_event_config()
+		 * Although we enable the interrupt sources once and for
+		 * all here the event detection itself is not enabled until
+		 * userspace asks for it by mma8452_write_event_config()
 		 */
 		 */
-		int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS;
-		int enabled_interrupts = MMA8452_INT_TRANS;
+		int supported_interrupts = MMA8452_INT_DRDY |
+					   MMA8452_INT_TRANS |
+					   MMA8452_INT_FF_MT;
+		int enabled_interrupts = MMA8452_INT_TRANS |
+					 MMA8452_INT_FF_MT;
 
 
 		/* Assume wired to INT1 pin */
 		/* Assume wired to INT1 pin */
 		ret = i2c_smbus_write_byte_data(client,
 		ret = i2c_smbus_write_byte_data(client,
@@ -987,17 +1218,14 @@ static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
 #endif
 #endif
 
 
 static const struct i2c_device_id mma8452_id[] = {
 static const struct i2c_device_id mma8452_id[] = {
-	{ "mma8452", 0 },
+	{ "mma8452", mma8452 },
+	{ "mma8453", mma8453 },
+	{ "mma8652", mma8652 },
+	{ "mma8653", mma8653 },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, mma8452_id);
 MODULE_DEVICE_TABLE(i2c, mma8452_id);
 
 
-static const struct of_device_id mma8452_dt_ids[] = {
-	{ .compatible = "fsl,mma8452" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
-
 static struct i2c_driver mma8452_driver = {
 static struct i2c_driver mma8452_driver = {
 	.driver = {
 	.driver = {
 		.name	= "mma8452",
 		.name	= "mma8452",

+ 567 - 0
drivers/iio/accel/mxc4005.c

@@ -0,0 +1,567 @@
+/*
+ * 3-axis accelerometer driver for MXC4005XC Memsic sensor
+ *
+ * Copyright (c) 2014, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define MXC4005_DRV_NAME		"mxc4005"
+#define MXC4005_IRQ_NAME		"mxc4005_event"
+#define MXC4005_REGMAP_NAME		"mxc4005_regmap"
+
+#define MXC4005_REG_XOUT_UPPER		0x03
+#define MXC4005_REG_XOUT_LOWER		0x04
+#define MXC4005_REG_YOUT_UPPER		0x05
+#define MXC4005_REG_YOUT_LOWER		0x06
+#define MXC4005_REG_ZOUT_UPPER		0x07
+#define MXC4005_REG_ZOUT_LOWER		0x08
+
+#define MXC4005_REG_INT_MASK1		0x0B
+#define MXC4005_REG_INT_MASK1_BIT_DRDYE	0x01
+
+#define MXC4005_REG_INT_CLR1		0x01
+#define MXC4005_REG_INT_CLR1_BIT_DRDYC	0x01
+
+#define MXC4005_REG_CONTROL		0x0D
+#define MXC4005_REG_CONTROL_MASK_FSR	GENMASK(6, 5)
+#define MXC4005_CONTROL_FSR_SHIFT	5
+
+#define MXC4005_REG_DEVICE_ID		0x0E
+
+enum mxc4005_axis {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+};
+
+enum mxc4005_range {
+	MXC4005_RANGE_2G,
+	MXC4005_RANGE_4G,
+	MXC4005_RANGE_8G,
+};
+
+struct mxc4005_data {
+	struct device *dev;
+	struct mutex mutex;
+	struct regmap *regmap;
+	struct iio_trigger *dready_trig;
+	__be16 buffer[8];
+	bool trigger_enabled;
+};
+
+/*
+ * MXC4005 can operate in the following ranges:
+ * +/- 2G, 4G, 8G (the default +/-2G)
+ *
+ * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582
+ * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164
+ * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329
+ */
+static const struct {
+	u8 range;
+	int scale;
+} mxc4005_scale_table[] = {
+	{MXC4005_RANGE_2G, 9582},
+	{MXC4005_RANGE_4G, 19164},
+	{MXC4005_RANGE_8G, 38329},
+};
+
+
+static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329");
+
+static struct attribute *mxc4005_attributes[] = {
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group mxc4005_attrs_group = {
+	.attrs = mxc4005_attributes,
+};
+
+static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MXC4005_REG_XOUT_UPPER:
+	case MXC4005_REG_XOUT_LOWER:
+	case MXC4005_REG_YOUT_UPPER:
+	case MXC4005_REG_YOUT_LOWER:
+	case MXC4005_REG_ZOUT_UPPER:
+	case MXC4005_REG_ZOUT_LOWER:
+	case MXC4005_REG_DEVICE_ID:
+	case MXC4005_REG_CONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MXC4005_REG_INT_CLR1:
+	case MXC4005_REG_INT_MASK1:
+	case MXC4005_REG_CONTROL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config mxc4005_regmap_config = {
+	.name = MXC4005_REGMAP_NAME,
+
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = MXC4005_REG_DEVICE_ID,
+
+	.readable_reg = mxc4005_is_readable_reg,
+	.writeable_reg = mxc4005_is_writeable_reg,
+};
+
+static int mxc4005_read_xyz(struct mxc4005_data *data)
+{
+	int ret;
+
+	ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
+			       (u8 *) data->buffer, sizeof(data->buffer));
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read axes\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mxc4005_read_axis(struct mxc4005_data *data,
+			     unsigned int addr)
+{
+	__be16 reg;
+	int ret;
+
+	ret = regmap_bulk_read(data->regmap, addr, (u8 *) &reg, sizeof(reg));
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read reg %02x\n", addr);
+		return ret;
+	}
+
+	return be16_to_cpu(reg);
+}
+
+static int mxc4005_read_scale(struct mxc4005_data *data)
+{
+	unsigned int reg;
+	int ret;
+	int i;
+
+	ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &reg);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read reg_control\n");
+		return ret;
+	}
+
+	i = reg >> MXC4005_CONTROL_FSR_SHIFT;
+
+	if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table))
+		return -EINVAL;
+
+	return mxc4005_scale_table[i].scale;
+}
+
+static int mxc4005_set_scale(struct mxc4005_data *data, int val)
+{
+	unsigned int reg;
+	int i;
+	int ret;
+
+	for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) {
+		if (mxc4005_scale_table[i].scale == val) {
+			reg = i << MXC4005_CONTROL_FSR_SHIFT;
+			ret = regmap_update_bits(data->regmap,
+						 MXC4005_REG_CONTROL,
+						 MXC4005_REG_CONTROL_MASK_FSR,
+						 reg);
+			if (ret < 0)
+				dev_err(data->dev,
+					"failed to write reg_control\n");
+			return ret;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int mxc4005_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct mxc4005_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_ACCEL:
+			if (iio_buffer_enabled(indio_dev))
+				return -EBUSY;
+
+			ret = mxc4005_read_axis(data, chan->address);
+			if (ret < 0)
+				return ret;
+			*val = sign_extend32(ret >> chan->scan_type.shift,
+					     chan->scan_type.realbits - 1);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		ret = mxc4005_read_scale(data);
+		if (ret < 0)
+			return ret;
+
+		*val = 0;
+		*val2 = ret;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mxc4005_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct mxc4005_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (val != 0)
+			return -EINVAL;
+
+		return mxc4005_set_scale(data, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info mxc4005_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= mxc4005_read_raw,
+	.write_raw	= mxc4005_write_raw,
+	.attrs		= &mxc4005_attrs_group,
+};
+
+static const unsigned long mxc4005_scan_masks[] = {
+	BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+	0
+};
+
+#define MXC4005_CHANNEL(_axis, _addr) {				\
+	.type = IIO_ACCEL,					\
+	.modified = 1,						\
+	.channel2 = IIO_MOD_##_axis,				\
+	.address = _addr,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+	.scan_index = AXIS_##_axis,				\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 12,					\
+		.storagebits = 16,				\
+		.shift = 4,					\
+		.endianness = IIO_BE,				\
+	},							\
+}
+
+static const struct iio_chan_spec mxc4005_channels[] = {
+	MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
+	MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
+	MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct mxc4005_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = mxc4005_read_xyz(data);
+	if (ret < 0)
+		goto err;
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   pf->timestamp);
+
+err:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int mxc4005_clr_intr(struct mxc4005_data *data)
+{
+	int ret;
+
+	/* clear interrupt */
+	ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
+			   MXC4005_REG_INT_CLR1_BIT_DRDYC);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to write to reg_int_clr1\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mxc4005_set_trigger_state(struct iio_trigger *trig,
+				     bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct mxc4005_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	if (state) {
+		ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
+				   MXC4005_REG_INT_MASK1_BIT_DRDYE);
+	} else {
+		ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1,
+				   ~MXC4005_REG_INT_MASK1_BIT_DRDYE);
+	}
+
+	if (ret < 0) {
+		mutex_unlock(&data->mutex);
+		dev_err(data->dev, "failed to update reg_int_mask1");
+		return ret;
+	}
+
+	data->trigger_enabled = state;
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+static int mxc4005_trigger_try_reen(struct iio_trigger *trig)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct mxc4005_data *data = iio_priv(indio_dev);
+
+	if (!data->dready_trig)
+		return 0;
+
+	return mxc4005_clr_intr(data);
+}
+
+static const struct iio_trigger_ops mxc4005_trigger_ops = {
+	.set_trigger_state = mxc4005_set_trigger_state,
+	.try_reenable = mxc4005_trigger_try_reen,
+	.owner = THIS_MODULE,
+};
+
+static int mxc4005_gpio_probe(struct i2c_client *client,
+			      struct mxc4005_data *data)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "failed to get acpi gpio index\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static int mxc4005_chip_init(struct mxc4005_data *data)
+{
+	int ret;
+	unsigned int reg;
+
+	ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, &reg);
+	if (ret < 0) {
+		dev_err(data->dev, "failed to read chip id\n");
+		return ret;
+	}
+
+	dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
+
+	return 0;
+}
+
+static int mxc4005_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct mxc4005_data *data;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "failed to initialize regmap\n");
+		return PTR_ERR(regmap);
+	}
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->dev = &client->dev;
+	data->regmap = regmap;
+
+	ret = mxc4005_chip_init(data);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to initialize chip\n");
+		return ret;
+	}
+
+	mutex_init(&data->mutex);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = mxc4005_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
+	indio_dev->available_scan_masks = mxc4005_scan_masks;
+	indio_dev->name = MXC4005_DRV_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &mxc4005_info;
+
+	ret = iio_triggered_buffer_setup(indio_dev,
+					 iio_pollfunc_store_time,
+					 mxc4005_trigger_handler,
+					 NULL);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"failed to setup iio triggered buffer\n");
+		return ret;
+	}
+
+	if (client->irq < 0)
+		client->irq = mxc4005_gpio_probe(client, data);
+
+	if (client->irq > 0) {
+		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+							   "%s-dev%d",
+							   indio_dev->name,
+							   indio_dev->id);
+		if (!data->dready_trig)
+			return -ENOMEM;
+
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						iio_trigger_generic_data_rdy_poll,
+						NULL,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						MXC4005_IRQ_NAME,
+						data->dready_trig);
+		if (ret) {
+			dev_err(&client->dev,
+				"failed to init threaded irq\n");
+			goto err_buffer_cleanup;
+		}
+
+		data->dready_trig->dev.parent = &client->dev;
+		data->dready_trig->ops = &mxc4005_trigger_ops;
+		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
+		indio_dev->trig = data->dready_trig;
+		iio_trigger_get(indio_dev->trig);
+		ret = iio_trigger_register(data->dready_trig);
+		if (ret) {
+			dev_err(&client->dev,
+				"failed to register trigger\n");
+			goto err_trigger_unregister;
+		}
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"unable to register iio device %d\n", ret);
+		goto err_buffer_cleanup;
+	}
+
+	return 0;
+
+err_trigger_unregister:
+	iio_trigger_unregister(data->dready_trig);
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return ret;
+}
+
+static int mxc4005_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct mxc4005_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	iio_triggered_buffer_cleanup(indio_dev);
+	if (data->dready_trig)
+		iio_trigger_unregister(data->dready_trig);
+
+	return 0;
+}
+
+static const struct acpi_device_id mxc4005_acpi_match[] = {
+	{"MXC4005",	0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match);
+
+static const struct i2c_device_id mxc4005_id[] = {
+	{"mxc4005",	0},
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, mxc4005_id);
+
+static struct i2c_driver mxc4005_driver = {
+	.driver = {
+		.name = MXC4005_DRV_NAME,
+		.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
+	},
+	.probe		= mxc4005_probe,
+	.remove		= mxc4005_remove,
+	.id_table	= mxc4005_id,
+};
+
+module_i2c_driver(mxc4005_driver);
+
+MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver");

+ 1 - 0
drivers/iio/accel/st_accel_core.c

@@ -618,6 +618,7 @@ static const struct iio_info accel_info = {
 	.attrs = &st_accel_attribute_group,
 	.attrs = &st_accel_attribute_group,
 	.read_raw = &st_accel_read_raw,
 	.read_raw = &st_accel_read_raw,
 	.write_raw = &st_accel_write_raw,
 	.write_raw = &st_accel_write_raw,
+	.debugfs_reg_access = &st_sensors_debugfs_reg_access,
 };
 };
 
 
 #ifdef CONFIG_IIO_TRIGGER
 #ifdef CONFIG_IIO_TRIGGER

+ 24 - 11
drivers/iio/adc/Kconfig

@@ -149,6 +149,17 @@ config BERLIN2_ADC
 	  Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
 	  Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
 	  temperature measurement.
 	  temperature measurement.
 
 
+config CC10001_ADC
+	tristate "Cosmic Circuits 10001 ADC driver"
+	depends on HAS_IOMEM && HAVE_CLK && REGULATOR
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Cosmic Circuits 10001 ADC.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called cc10001_adc.
+
 config DA9150_GPADC
 config DA9150_GPADC
 	tristate "Dialog DA9150 GPADC driver support"
 	tristate "Dialog DA9150 GPADC driver support"
 	depends on MFD_DA9150
 	depends on MFD_DA9150
@@ -161,17 +172,6 @@ config DA9150_GPADC
 	  To compile this driver as a module, choose M here: the module will be
 	  To compile this driver as a module, choose M here: the module will be
 	  called berlin2-adc.
 	  called berlin2-adc.
 
 
-config CC10001_ADC
-	tristate "Cosmic Circuits 10001 ADC driver"
-	depends on HAS_IOMEM && HAVE_CLK && REGULATOR
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
-	help
-	  Say yes here to build support for Cosmic Circuits 10001 ADC.
-
-	  This driver can also be built as a module. If so, the module will be
-	  called cc10001_adc.
-
 config EXYNOS_ADC
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
 	depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -183,6 +183,17 @@ config EXYNOS_ADC
 	  To compile this driver as a module, choose M here: the module will be
 	  To compile this driver as a module, choose M here: the module will be
 	  called exynos_adc.
 	  called exynos_adc.
 
 
+config HI8435
+	tristate "Holt Integrated Circuits HI-8435 threshold detector"
+	select IIO_TRIGGERED_EVENT
+	depends on SPI
+	help
+	  If you say yes here you get support for Holt Integrated Circuits
+	  HI-8435 chip.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called hi8435.
+
 config LP8788_ADC
 config LP8788_ADC
 	tristate "LP8788 ADC driver"
 	tristate "LP8788 ADC driver"
 	depends on MFD_LP8788
 	depends on MFD_LP8788
@@ -361,6 +372,8 @@ config TWL6030_GPADC
 config VF610_ADC
 config VF610_ADC
 	tristate "Freescale vf610 ADC driver"
 	tristate "Freescale vf610 ADC driver"
 	depends on OF
 	depends on OF
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	help
 	  Say yes here to support for Vybrid board analog-to-digital converter.
 	  Say yes here to support for Vybrid board analog-to-digital converter.
 	  Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
 	  Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.

+ 2 - 1
drivers/iio/adc/Makefile

@@ -16,9 +16,10 @@ obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
 obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
 obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
 obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
-obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
+obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
+obj-$(CONFIG_HI8435) += hi8435.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX1363) += max1363.o

+ 48 - 43
drivers/iio/adc/berlin2-adc.c

@@ -27,13 +27,13 @@
 #define  BERLIN2_SM_CTRL_SM_SOC_INT		BIT(1)
 #define  BERLIN2_SM_CTRL_SM_SOC_INT		BIT(1)
 #define  BERLIN2_SM_CTRL_SOC_SM_INT		BIT(2)
 #define  BERLIN2_SM_CTRL_SOC_SM_INT		BIT(2)
 #define  BERLIN2_SM_CTRL_ADC_SEL(x)		((x) << 5)	/* 0-15 */
 #define  BERLIN2_SM_CTRL_ADC_SEL(x)		((x) << 5)	/* 0-15 */
-#define  BERLIN2_SM_CTRL_ADC_SEL_MASK		(0xf << 5)
+#define  BERLIN2_SM_CTRL_ADC_SEL_MASK		GENMASK(8, 5)
 #define  BERLIN2_SM_CTRL_ADC_POWER		BIT(9)
 #define  BERLIN2_SM_CTRL_ADC_POWER		BIT(9)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2	(0x0 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2	(0x0 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3	(0x1 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3	(0x1 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4	(0x2 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4	(0x2 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8	(0x3 << 10)
 #define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8	(0x3 << 10)
-#define  BERLIN2_SM_CTRL_ADC_CLKSEL_MASK	(0x3 << 10)
+#define  BERLIN2_SM_CTRL_ADC_CLKSEL_MASK	GENMASK(11, 10)
 #define  BERLIN2_SM_CTRL_ADC_START		BIT(12)
 #define  BERLIN2_SM_CTRL_ADC_START		BIT(12)
 #define  BERLIN2_SM_CTRL_ADC_RESET		BIT(13)
 #define  BERLIN2_SM_CTRL_ADC_RESET		BIT(13)
 #define  BERLIN2_SM_CTRL_ADC_BANDGAP_RDY	BIT(14)
 #define  BERLIN2_SM_CTRL_ADC_BANDGAP_RDY	BIT(14)
@@ -50,7 +50,7 @@
 #define  BERLIN2_SM_CTRL_TSEN_MODE_10_50	(0x1 << 22)	/* 10-50 C */
 #define  BERLIN2_SM_CTRL_TSEN_MODE_10_50	(0x1 << 22)	/* 10-50 C */
 #define  BERLIN2_SM_CTRL_TSEN_RESET		BIT(29)
 #define  BERLIN2_SM_CTRL_TSEN_RESET		BIT(29)
 #define BERLIN2_SM_ADC_DATA			0x20
 #define BERLIN2_SM_ADC_DATA			0x20
-#define  BERLIN2_SM_ADC_MASK			0x3ff
+#define  BERLIN2_SM_ADC_MASK			GENMASK(9, 0)
 #define BERLIN2_SM_ADC_STATUS			0x1c
 #define BERLIN2_SM_ADC_STATUS			0x1c
 #define  BERLIN2_SM_ADC_STATUS_DATA_RDY(x)	BIT(x)		/* 0-15 */
 #define  BERLIN2_SM_ADC_STATUS_DATA_RDY(x)	BIT(x)		/* 0-15 */
 #define  BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK	GENMASK(15, 0)
 #define  BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK	GENMASK(15, 0)
@@ -65,9 +65,9 @@
 #define  BERLIN2_SM_TSEN_CTRL_START		BIT(8)
 #define  BERLIN2_SM_TSEN_CTRL_START		BIT(8)
 #define  BERLIN2_SM_TSEN_CTRL_SETTLING_4	(0x0 << 21)	/* 4 us */
 #define  BERLIN2_SM_TSEN_CTRL_SETTLING_4	(0x0 << 21)	/* 4 us */
 #define  BERLIN2_SM_TSEN_CTRL_SETTLING_12	(0x1 << 21)	/* 12 us */
 #define  BERLIN2_SM_TSEN_CTRL_SETTLING_12	(0x1 << 21)	/* 12 us */
-#define  BERLIN2_SM_TSEN_CTRL_SETTLING_MASK	(0x1 << 21)
+#define  BERLIN2_SM_TSEN_CTRL_SETTLING_MASK	BIT(21)
 #define  BERLIN2_SM_TSEN_CTRL_TRIM(x)		((x) << 22)
 #define  BERLIN2_SM_TSEN_CTRL_TRIM(x)		((x) << 22)
-#define  BERLIN2_SM_TSEN_CTRL_TRIM_MASK		(0xf << 22)
+#define  BERLIN2_SM_TSEN_CTRL_TRIM_MASK		GENMASK(25, 22)
 
 
 struct berlin2_adc_priv {
 struct berlin2_adc_priv {
 	struct regmap		*regmap;
 	struct regmap		*regmap;
@@ -78,13 +78,13 @@ struct berlin2_adc_priv {
 };
 };
 
 
 #define BERLIN2_ADC_CHANNEL(n, t)					\
 #define BERLIN2_ADC_CHANNEL(n, t)					\
-		{							\
-			.channel	= n,				\
-			.datasheet_name	= "channel"#n,			\
-			.type		= t,				\
-			.indexed	= 1,				\
-			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
-		}
+	{								\
+		.channel		= n,				\
+		.datasheet_name		= "channel"#n,			\
+		.type			= t,				\
+		.indexed		= 1,				\
+		.info_mask_separate	= BIT(IIO_CHAN_INFO_RAW),	\
+	}
 
 
 static const struct iio_chan_spec berlin2_adc_channels[] = {
 static const struct iio_chan_spec berlin2_adc_channels[] = {
 	BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE),	/* external input */
 	BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE),	/* external input */
@@ -111,18 +111,24 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
 
 
 	mutex_lock(&priv->lock);
 	mutex_lock(&priv->lock);
 
 
+	/* Enable the interrupts */
+	regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
+		     BERLIN2_SM_ADC_STATUS_INT_EN(channel));
+
 	/* Configure the ADC */
 	/* Configure the ADC */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-			BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK
-			| BERLIN2_SM_CTRL_ADC_START,
-			BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START);
+			   BERLIN2_SM_CTRL_ADC_RESET |
+			   BERLIN2_SM_CTRL_ADC_SEL_MASK |
+			   BERLIN2_SM_CTRL_ADC_START,
+			   BERLIN2_SM_CTRL_ADC_SEL(channel) |
+			   BERLIN2_SM_CTRL_ADC_START);
 
 
 	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
 	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
-			msecs_to_jiffies(1000));
+					       msecs_to_jiffies(1000));
 
 
 	/* Disable the interrupts */
 	/* Disable the interrupts */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
-			BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
+			   BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
 
 
 	if (ret == 0)
 	if (ret == 0)
 		ret = -ETIMEDOUT;
 		ret = -ETIMEDOUT;
@@ -132,7 +138,7 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
 	}
 	}
 
 
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-			BERLIN2_SM_CTRL_ADC_START, 0);
+			   BERLIN2_SM_CTRL_ADC_START, 0);
 
 
 	data = priv->data;
 	data = priv->data;
 	priv->data_available = false;
 	priv->data_available = false;
@@ -149,24 +155,31 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
 
 
 	mutex_lock(&priv->lock);
 	mutex_lock(&priv->lock);
 
 
+	/* Enable interrupts */
+	regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
+		     BERLIN2_SM_TSEN_STATUS_INT_EN);
+
 	/* Configure the ADC */
 	/* Configure the ADC */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-			BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
-			BERLIN2_SM_CTRL_ADC_ROTATE);
+			   BERLIN2_SM_CTRL_TSEN_RESET |
+			   BERLIN2_SM_CTRL_ADC_ROTATE,
+			   BERLIN2_SM_CTRL_ADC_ROTATE);
 
 
 	/* Configure the temperature sensor */
 	/* Configure the temperature sensor */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
-			BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK
-			| BERLIN2_SM_TSEN_CTRL_START,
-			BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12
-			| BERLIN2_SM_TSEN_CTRL_START);
+			   BERLIN2_SM_TSEN_CTRL_TRIM_MASK |
+			   BERLIN2_SM_TSEN_CTRL_SETTLING_MASK |
+			   BERLIN2_SM_TSEN_CTRL_START,
+			   BERLIN2_SM_TSEN_CTRL_TRIM(3) |
+			   BERLIN2_SM_TSEN_CTRL_SETTLING_12 |
+			   BERLIN2_SM_TSEN_CTRL_START);
 
 
 	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
 	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
-			msecs_to_jiffies(1000));
+					       msecs_to_jiffies(1000));
 
 
 	/* Disable interrupts */
 	/* Disable interrupts */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
-			BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
+			   BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
 
 
 	if (ret == 0)
 	if (ret == 0)
 		ret = -ETIMEDOUT;
 		ret = -ETIMEDOUT;
@@ -176,7 +189,7 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
 	}
 	}
 
 
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
-			BERLIN2_SM_TSEN_CTRL_START, 0);
+			   BERLIN2_SM_TSEN_CTRL_START, 0);
 
 
 	data = priv->data;
 	data = priv->data;
 	priv->data_available = false;
 	priv->data_available = false;
@@ -187,10 +200,9 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
 }
 }
 
 
 static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
 static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
-		struct iio_chan_spec const *chan, int *val, int *val2,
-		long mask)
+				struct iio_chan_spec const *chan, int *val,
+				int *val2, long mask)
 {
 {
-	struct berlin2_adc_priv *priv = iio_priv(indio_dev);
 	int temp;
 	int temp;
 
 
 	switch (mask) {
 	switch (mask) {
@@ -198,10 +210,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
 		if (chan->type != IIO_VOLTAGE)
 		if (chan->type != IIO_VOLTAGE)
 			return -EINVAL;
 			return -EINVAL;
 
 
-		/* Enable the interrupts */
-		regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
-				BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel));
-
 		*val = berlin2_adc_read(indio_dev, chan->channel);
 		*val = berlin2_adc_read(indio_dev, chan->channel);
 		if (*val < 0)
 		if (*val < 0)
 			return *val;
 			return *val;
@@ -211,10 +219,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
 		if (chan->type != IIO_TEMP)
 		if (chan->type != IIO_TEMP)
 			return -EINVAL;
 			return -EINVAL;
 
 
-		/* Enable interrupts */
-		regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
-				BERLIN2_SM_TSEN_STATUS_INT_EN);
-
 		temp = berlin2_adc_tsen_read(indio_dev);
 		temp = berlin2_adc_tsen_read(indio_dev);
 		if (temp < 0)
 		if (temp < 0)
 			return temp;
 			return temp;
@@ -306,12 +310,12 @@ static int berlin2_adc_probe(struct platform_device *pdev)
 		return tsen_irq;
 		return tsen_irq;
 
 
 	ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
 	ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
-			pdev->dev.driver->name, indio_dev);
+			       pdev->dev.driver->name, indio_dev);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
 	ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
 	ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
-			0, pdev->dev.driver->name, indio_dev);
+			       0, pdev->dev.driver->name, indio_dev);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
@@ -328,13 +332,14 @@ static int berlin2_adc_probe(struct platform_device *pdev)
 
 
 	/* Power up the ADC */
 	/* Power up the ADC */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-			BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
+			   BERLIN2_SM_CTRL_ADC_POWER,
+			   BERLIN2_SM_CTRL_ADC_POWER);
 
 
 	ret = iio_device_register(indio_dev);
 	ret = iio_device_register(indio_dev);
 	if (ret) {
 	if (ret) {
 		/* Power down the ADC */
 		/* Power down the ADC */
 		regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 		regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-				BERLIN2_SM_CTRL_ADC_POWER, 0);
+				   BERLIN2_SM_CTRL_ADC_POWER, 0);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -350,7 +355,7 @@ static int berlin2_adc_remove(struct platform_device *pdev)
 
 
 	/* Power down the ADC */
 	/* Power down the ADC */
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
 	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
-			BERLIN2_SM_CTRL_ADC_POWER, 0);
+			   BERLIN2_SM_CTRL_ADC_POWER, 0);
 
 
 	return 0;
 	return 0;
 }
 }

+ 534 - 0
drivers/iio/adc/hi8435.c

@@ -0,0 +1,534 @@
+/*
+ * Holt Integrated Circuits HI-8435 threshold detector driver
+ *
+ * Copyright (C) 2015 Zodiac Inflight Innovations
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
+
+#define DRV_NAME "hi8435"
+
+/* Register offsets for HI-8435 */
+#define HI8435_CTRL_REG		0x02
+#define HI8435_PSEN_REG		0x04
+#define HI8435_TMDATA_REG	0x1E
+#define HI8435_GOCENHYS_REG	0x3A
+#define HI8435_SOCENHYS_REG	0x3C
+#define HI8435_SO7_0_REG	0x10
+#define HI8435_SO15_8_REG	0x12
+#define HI8435_SO23_16_REG	0x14
+#define HI8435_SO31_24_REG	0x16
+#define HI8435_SO31_0_REG	0x78
+
+#define HI8435_WRITE_OPCODE	0x00
+#define HI8435_READ_OPCODE	0x80
+
+/* CTRL register bits */
+#define HI8435_CTRL_TEST	0x01
+#define HI8435_CTRL_SRST	0x02
+
+struct hi8435_priv {
+	struct spi_device *spi;
+	struct mutex lock;
+
+	unsigned long event_scan_mask; /* soft mask/unmask channels events */
+	unsigned int event_prev_val;
+
+	unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */
+	unsigned threshold_hi[2]; /* GND-Open and Supply-Open thresholds */
+	u8 reg_buffer[3] ____cacheline_aligned;
+};
+
+static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val)
+{
+	reg |= HI8435_READ_OPCODE;
+	return spi_write_then_read(priv->spi, &reg, 1, val, 1);
+}
+
+static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val)
+{
+	int ret;
+	__be16 be_val;
+
+	reg |= HI8435_READ_OPCODE;
+	ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 2);
+	*val = be16_to_cpu(be_val);
+
+	return ret;
+}
+
+static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val)
+{
+	int ret;
+	__be32 be_val;
+
+	reg |= HI8435_READ_OPCODE;
+	ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 4);
+	*val = be32_to_cpu(be_val);
+
+	return ret;
+}
+
+static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val)
+{
+	priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
+	priv->reg_buffer[1] = val;
+
+	return spi_write(priv->spi, priv->reg_buffer, 2);
+}
+
+static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
+{
+	priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
+	priv->reg_buffer[1] = (val >> 8) & 0xff;
+	priv->reg_buffer[2] = val & 0xff;
+
+	return spi_write(priv->spi, priv->reg_buffer, 3);
+}
+
+static int hi8435_read_event_config(struct iio_dev *idev,
+				    const struct iio_chan_spec *chan,
+				    enum iio_event_type type,
+				    enum iio_event_direction dir)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+
+	return !!(priv->event_scan_mask & BIT(chan->channel));
+}
+
+static int hi8435_write_event_config(struct iio_dev *idev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir, int state)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+
+	priv->event_scan_mask &= ~BIT(chan->channel);
+	if (state)
+		priv->event_scan_mask |= BIT(chan->channel);
+
+	return 0;
+}
+
+static int hi8435_read_event_value(struct iio_dev *idev,
+				   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 hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u8 mode, psen;
+	u16 reg;
+
+	ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
+	if (ret < 0)
+		return ret;
+
+	/* Supply-Open or GND-Open sensing mode */
+	mode = !!(psen & BIT(chan->channel / 8));
+
+	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+				 HI8435_GOCENHYS_REG, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (dir == IIO_EV_DIR_FALLING)
+		*val = ((reg & 0xff) - (reg >> 8)) / 2;
+	else if (dir == IIO_EV_DIR_RISING)
+		*val = ((reg & 0xff) + (reg >> 8)) / 2;
+
+	return IIO_VAL_INT;
+}
+
+static int hi8435_write_event_value(struct iio_dev *idev,
+				    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 hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u8 mode, psen;
+	u16 reg;
+
+	ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
+	if (ret < 0)
+		return ret;
+
+	/* Supply-Open or GND-Open sensing mode */
+	mode = !!(psen & BIT(chan->channel / 8));
+
+	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+				 HI8435_GOCENHYS_REG, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (dir == IIO_EV_DIR_FALLING) {
+		/* falling threshold range 2..21V, hysteresis minimum 2V */
+		if (val < 2 || val > 21 || (val + 2) > priv->threshold_hi[mode])
+			return -EINVAL;
+
+		if (val == priv->threshold_lo[mode])
+			return 0;
+
+		priv->threshold_lo[mode] = val;
+
+		/* hysteresis must not be odd */
+		if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
+			priv->threshold_hi[mode]--;
+	} else if (dir == IIO_EV_DIR_RISING) {
+		/* rising threshold range 3..22V, hysteresis minimum 2V */
+		if (val < 3 || val > 22 || val < (priv->threshold_lo[mode] + 2))
+			return -EINVAL;
+
+		if (val == priv->threshold_hi[mode])
+			return 0;
+
+		priv->threshold_hi[mode] = val;
+
+		/* hysteresis must not be odd */
+		if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
+			priv->threshold_lo[mode]++;
+	}
+
+	/* program thresholds */
+	mutex_lock(&priv->lock);
+
+	ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
+				 HI8435_GOCENHYS_REG, &reg);
+	if (ret < 0) {
+		mutex_unlock(&priv->lock);
+		return ret;
+	}
+
+	/* hysteresis */
+	reg = priv->threshold_hi[mode] - priv->threshold_lo[mode];
+	reg <<= 8;
+	/* threshold center */
+	reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]);
+
+	ret = hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG :
+				  HI8435_GOCENHYS_REG, reg);
+
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int hi8435_debugfs_reg_access(struct iio_dev *idev,
+				     unsigned reg, unsigned writeval,
+				     unsigned *readval)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u8 val;
+
+	if (readval != NULL) {
+		ret = hi8435_readb(priv, reg, &val);
+		*readval = val;
+	} else {
+		val = (u8)writeval;
+		ret = hi8435_writeb(priv, reg, val);
+	}
+
+	return ret;
+}
+
+static const struct iio_event_spec hi8435_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+static int hi8435_get_sensing_mode(struct iio_dev *idev,
+				   const struct iio_chan_spec *chan)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u8 reg;
+
+	ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
+	if (ret < 0)
+		return ret;
+
+	return !!(reg & BIT(chan->channel / 8));
+}
+
+static int hi8435_set_sensing_mode(struct iio_dev *idev,
+				   const struct iio_chan_spec *chan,
+				   unsigned int mode)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+	int ret;
+	u8 reg;
+
+	mutex_lock(&priv->lock);
+
+	ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
+	if (ret < 0) {
+		mutex_unlock(&priv->lock);
+		return ret;
+	}
+
+	reg &= ~BIT(chan->channel / 8);
+	if (mode)
+		reg |= BIT(chan->channel / 8);
+
+	ret = hi8435_writeb(priv, HI8435_PSEN_REG, reg);
+
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static const char * const hi8435_sensing_modes[] = { "GND-Open",
+						     "Supply-Open" };
+
+static const struct iio_enum hi8435_sensing_mode = {
+	.items = hi8435_sensing_modes,
+	.num_items = ARRAY_SIZE(hi8435_sensing_modes),
+	.get = hi8435_get_sensing_mode,
+	.set = hi8435_set_sensing_mode,
+};
+
+static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
+	IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
+	{},
+};
+
+#define HI8435_VOLTAGE_CHANNEL(num)			\
+{							\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.channel = num,					\
+	.event_spec = hi8435_events,			\
+	.num_event_specs = ARRAY_SIZE(hi8435_events),	\
+	.ext_info = hi8435_ext_info,			\
+}
+
+static const struct iio_chan_spec hi8435_channels[] = {
+	HI8435_VOLTAGE_CHANNEL(0),
+	HI8435_VOLTAGE_CHANNEL(1),
+	HI8435_VOLTAGE_CHANNEL(2),
+	HI8435_VOLTAGE_CHANNEL(3),
+	HI8435_VOLTAGE_CHANNEL(4),
+	HI8435_VOLTAGE_CHANNEL(5),
+	HI8435_VOLTAGE_CHANNEL(6),
+	HI8435_VOLTAGE_CHANNEL(7),
+	HI8435_VOLTAGE_CHANNEL(8),
+	HI8435_VOLTAGE_CHANNEL(9),
+	HI8435_VOLTAGE_CHANNEL(10),
+	HI8435_VOLTAGE_CHANNEL(11),
+	HI8435_VOLTAGE_CHANNEL(12),
+	HI8435_VOLTAGE_CHANNEL(13),
+	HI8435_VOLTAGE_CHANNEL(14),
+	HI8435_VOLTAGE_CHANNEL(15),
+	HI8435_VOLTAGE_CHANNEL(16),
+	HI8435_VOLTAGE_CHANNEL(17),
+	HI8435_VOLTAGE_CHANNEL(18),
+	HI8435_VOLTAGE_CHANNEL(19),
+	HI8435_VOLTAGE_CHANNEL(20),
+	HI8435_VOLTAGE_CHANNEL(21),
+	HI8435_VOLTAGE_CHANNEL(22),
+	HI8435_VOLTAGE_CHANNEL(23),
+	HI8435_VOLTAGE_CHANNEL(24),
+	HI8435_VOLTAGE_CHANNEL(25),
+	HI8435_VOLTAGE_CHANNEL(26),
+	HI8435_VOLTAGE_CHANNEL(27),
+	HI8435_VOLTAGE_CHANNEL(28),
+	HI8435_VOLTAGE_CHANNEL(29),
+	HI8435_VOLTAGE_CHANNEL(30),
+	HI8435_VOLTAGE_CHANNEL(31),
+	IIO_CHAN_SOFT_TIMESTAMP(32),
+};
+
+static const struct iio_info hi8435_info = {
+	.driver_module = THIS_MODULE,
+	.read_event_config = &hi8435_read_event_config,
+	.write_event_config = hi8435_write_event_config,
+	.read_event_value = &hi8435_read_event_value,
+	.write_event_value = &hi8435_write_event_value,
+	.debugfs_reg_access = &hi8435_debugfs_reg_access,
+};
+
+static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
+{
+	struct hi8435_priv *priv = iio_priv(idev);
+	enum iio_event_direction dir;
+	unsigned int i;
+	unsigned int status = priv->event_prev_val ^ val;
+
+	if (!status)
+		return;
+
+	for_each_set_bit(i, &priv->event_scan_mask, 32) {
+		if (status & BIT(i)) {
+			dir = val & BIT(i) ? IIO_EV_DIR_RISING :
+					     IIO_EV_DIR_FALLING;
+			iio_push_event(idev,
+				       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+						    IIO_EV_TYPE_THRESH, dir),
+				       iio_get_time_ns());
+		}
+	}
+
+	priv->event_prev_val = val;
+}
+
+static irqreturn_t hi8435_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *idev = pf->indio_dev;
+	struct hi8435_priv *priv = iio_priv(idev);
+	u32 val;
+	int ret;
+
+	ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val);
+	if (ret < 0)
+		goto err_read;
+
+	hi8435_iio_push_event(idev, val);
+
+err_read:
+	iio_trigger_notify_done(idev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int hi8435_probe(struct spi_device *spi)
+{
+	struct iio_dev *idev;
+	struct hi8435_priv *priv;
+	struct gpio_desc *reset_gpio;
+	int ret;
+
+	idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
+	if (!idev)
+		return -ENOMEM;
+
+	priv = iio_priv(idev);
+	priv->spi = spi;
+
+	reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
+	if (IS_ERR(reset_gpio)) {
+		/* chip s/w reset if h/w reset failed */
+		hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
+		hi8435_writeb(priv, HI8435_CTRL_REG, 0);
+	} else {
+		udelay(5);
+		gpiod_set_value(reset_gpio, 1);
+	}
+
+	spi_set_drvdata(spi, idev);
+	mutex_init(&priv->lock);
+
+	idev->dev.parent	= &spi->dev;
+	idev->name		= spi_get_device_id(spi)->name;
+	idev->modes		= INDIO_DIRECT_MODE;
+	idev->info		= &hi8435_info;
+	idev->channels		= hi8435_channels;
+	idev->num_channels	= ARRAY_SIZE(hi8435_channels);
+
+	/* unmask all events */
+	priv->event_scan_mask = ~(0);
+	/*
+	 * There is a restriction in the chip - the hysteresis can not be odd.
+	 * If the hysteresis is set to odd value then chip gets into lock state
+	 * and not functional anymore.
+	 * After chip reset the thresholds are in undefined state, so we need to
+	 * initialize thresholds to some initial values and then prevent
+	 * userspace setting odd hysteresis.
+	 *
+	 * Set threshold low voltage to 2V, threshold high voltage to 4V
+	 * for both GND-Open and Supply-Open sensing modes.
+	 */
+	priv->threshold_lo[0] = priv->threshold_lo[1] = 2;
+	priv->threshold_hi[0] = priv->threshold_hi[1] = 4;
+	hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206);
+	hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206);
+
+	ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler);
+	if (ret)
+		return ret;
+
+	ret = iio_device_register(idev);
+	if (ret < 0) {
+		dev_err(&spi->dev, "unable to register device\n");
+		goto unregister_triggered_event;
+	}
+
+	return 0;
+
+unregister_triggered_event:
+	iio_triggered_event_cleanup(idev);
+	return ret;
+}
+
+static int hi8435_remove(struct spi_device *spi)
+{
+	struct iio_dev *idev = spi_get_drvdata(spi);
+
+	iio_device_unregister(idev);
+	iio_triggered_event_cleanup(idev);
+
+	return 0;
+}
+
+static const struct of_device_id hi8435_dt_ids[] = {
+	{ .compatible = "holt,hi8435" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
+
+static const struct spi_device_id hi8435_id[] = {
+	{ "hi8435", 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, hi8435_id);
+
+static struct spi_driver hi8435_driver = {
+	.driver	= {
+		.name		= DRV_NAME,
+		.of_match_table	= of_match_ptr(hi8435_dt_ids),
+	},
+	.probe		= hi8435_probe,
+	.remove		= hi8435_remove,
+	.id_table	= hi8435_id,
+};
+module_spi_driver(hi8435_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("HI-8435 threshold detector");

+ 1 - 0
drivers/iio/adc/max1027.c

@@ -508,6 +508,7 @@ static int max1027_remove(struct spi_device *spi)
 static struct spi_driver max1027_driver = {
 static struct spi_driver max1027_driver = {
 	.driver = {
 	.driver = {
 		.name	= "max1027",
 		.name	= "max1027",
+		.of_match_table = of_match_ptr(max1027_adc_dt_ids),
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= max1027_probe,
 	.probe		= max1027_probe,

+ 1 - 0
drivers/iio/adc/mcp320x.c

@@ -404,6 +404,7 @@ MODULE_DEVICE_TABLE(spi, mcp320x_id);
 static struct spi_driver mcp320x_driver = {
 static struct spi_driver mcp320x_driver = {
 	.driver = {
 	.driver = {
 		.name = "mcp320x",
 		.name = "mcp320x",
+		.of_match_table = of_match_ptr(mcp320x_dt_ids),
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe = mcp320x_probe,
 	.probe = mcp320x_probe,

+ 8 - 0
drivers/iio/adc/ti-adc128s052.c

@@ -174,6 +174,13 @@ static int adc128_remove(struct spi_device *spi)
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct of_device_id adc128_of_match[] = {
+	{ .compatible = "ti,adc128s052", },
+	{ .compatible = "ti,adc122s021", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, adc128_of_match);
+
 static const struct spi_device_id adc128_id[] = {
 static const struct spi_device_id adc128_id[] = {
 	{ "adc128s052", 0},	/* index into adc128_config */
 	{ "adc128s052", 0},	/* index into adc128_config */
 	{ "adc122s021",	1},
 	{ "adc122s021",	1},
@@ -184,6 +191,7 @@ MODULE_DEVICE_TABLE(spi, adc128_id);
 static struct spi_driver adc128_driver = {
 static struct spi_driver adc128_driver = {
 	.driver = {
 	.driver = {
 		.name = "adc128s052",
 		.name = "adc128s052",
+		.of_match_table = of_match_ptr(adc128_of_match),
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe = adc128_probe,
 	.probe = adc128_probe,

+ 1 - 0
drivers/iio/adc/twl6030-gpadc.c

@@ -875,6 +875,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = {
 	},
 	},
 	{ /* end */ }
 	{ /* end */ }
 };
 };
+MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl);
 
 
 static int twl6030_gpadc_probe(struct platform_device *pdev)
 static int twl6030_gpadc_probe(struct platform_device *pdev)
 {
 {

+ 94 - 7
drivers/iio/adc/vf610_adc.c

@@ -34,8 +34,11 @@
 #include <linux/err.h>
 #include <linux/err.h>
 
 
 #include <linux/iio/iio.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/sysfs.h>
-#include <linux/iio/driver.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 
 /* This will be the driver name the kernel reports */
 /* This will be the driver name the kernel reports */
 #define DRIVER_NAME "vf610-adc"
 #define DRIVER_NAME "vf610-adc"
@@ -170,6 +173,7 @@ struct vf610_adc {
 	u32 sample_freq_avail[5];
 	u32 sample_freq_avail[5];
 
 
 	struct completion completion;
 	struct completion completion;
+	u16 buffer[8];
 };
 };
 
 
 static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
 static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
@@ -505,12 +509,24 @@ static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
 				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
 				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
 	.ext_info = vf610_ext_info,				\
 	.ext_info = vf610_ext_info,				\
+	.scan_index = (_idx),			\
+	.scan_type = {					\
+		.sign = 'u',				\
+		.realbits = 12,				\
+		.storagebits = 16,			\
+	},						\
 }
 }
 
 
 #define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) {	\
 #define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) {	\
 	.type = (_chan_type),	\
 	.type = (_chan_type),	\
 	.channel = (_idx),		\
 	.channel = (_idx),		\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),	\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),	\
+	.scan_index = (_idx),					\
+	.scan_type = {						\
+		.sign = 'u',					\
+		.realbits = 12,					\
+		.storagebits = 16,				\
+	},							\
 }
 }
 
 
 static const struct iio_chan_spec vf610_adc_iio_channels[] = {
 static const struct iio_chan_spec vf610_adc_iio_channels[] = {
@@ -531,6 +547,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
 	VF610_ADC_CHAN(14, IIO_VOLTAGE),
 	VF610_ADC_CHAN(14, IIO_VOLTAGE),
 	VF610_ADC_CHAN(15, IIO_VOLTAGE),
 	VF610_ADC_CHAN(15, IIO_VOLTAGE),
 	VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
 	VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
+	IIO_CHAN_SOFT_TIMESTAMP(32),
 	/* sentinel */
 	/* sentinel */
 };
 };
 
 
@@ -559,13 +576,20 @@ static int vf610_adc_read_data(struct vf610_adc *info)
 
 
 static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
 static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
 {
 {
-	struct vf610_adc *info = (struct vf610_adc *)dev_id;
+	struct iio_dev *indio_dev = (struct iio_dev *)dev_id;
+	struct vf610_adc *info = iio_priv(indio_dev);
 	int coco;
 	int coco;
 
 
 	coco = readl(info->regs + VF610_REG_ADC_HS);
 	coco = readl(info->regs + VF610_REG_ADC_HS);
 	if (coco & VF610_ADC_HS_COCO0) {
 	if (coco & VF610_ADC_HS_COCO0) {
 		info->value = vf610_adc_read_data(info);
 		info->value = vf610_adc_read_data(info);
-		complete(&info->completion);
+		if (iio_buffer_enabled(indio_dev)) {
+			info->buffer[0] = info->value;
+			iio_push_to_buffers_with_timestamp(indio_dev,
+					info->buffer, iio_get_time_ns());
+			iio_trigger_notify_done(indio_dev->trig);
+		} else
+			complete(&info->completion);
 	}
 	}
 
 
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
@@ -613,8 +637,12 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_RAW:
 	case IIO_CHAN_INFO_RAW:
 	case IIO_CHAN_INFO_PROCESSED:
 	case IIO_CHAN_INFO_PROCESSED:
 		mutex_lock(&indio_dev->mlock);
 		mutex_lock(&indio_dev->mlock);
-		reinit_completion(&info->completion);
+		if (iio_buffer_enabled(indio_dev)) {
+			mutex_unlock(&indio_dev->mlock);
+			return -EBUSY;
+		}
 
 
+		reinit_completion(&info->completion);
 		hc_cfg = VF610_ADC_ADCHC(chan->channel);
 		hc_cfg = VF610_ADC_ADCHC(chan->channel);
 		hc_cfg |= VF610_ADC_AIEN;
 		hc_cfg |= VF610_ADC_AIEN;
 		writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
 		writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
@@ -694,6 +722,56 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
 	return -EINVAL;
 	return -EINVAL;
 }
 }
 
 
+static int vf610_adc_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct vf610_adc *info = iio_priv(indio_dev);
+	unsigned int channel;
+	int ret;
+	int val;
+
+	ret = iio_triggered_buffer_postenable(indio_dev);
+	if (ret)
+		return ret;
+
+	val = readl(info->regs + VF610_REG_ADC_GC);
+	val |= VF610_ADC_ADCON;
+	writel(val, info->regs + VF610_REG_ADC_GC);
+
+	channel = find_first_bit(indio_dev->active_scan_mask,
+						indio_dev->masklength);
+
+	val = VF610_ADC_ADCHC(channel);
+	val |= VF610_ADC_AIEN;
+
+	writel(val, info->regs + VF610_REG_ADC_HC0);
+
+	return 0;
+}
+
+static int vf610_adc_buffer_predisable(struct iio_dev *indio_dev)
+{
+	struct vf610_adc *info = iio_priv(indio_dev);
+	unsigned int hc_cfg = 0;
+	int val;
+
+	val = readl(info->regs + VF610_REG_ADC_GC);
+	val &= ~VF610_ADC_ADCON;
+	writel(val, info->regs + VF610_REG_ADC_GC);
+
+	hc_cfg |= VF610_ADC_CONV_DISABLE;
+	hc_cfg &= ~VF610_ADC_AIEN;
+
+	writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
+
+	return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+	.postenable = &vf610_adc_buffer_postenable,
+	.predisable = &vf610_adc_buffer_predisable,
+	.validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
 static int vf610_adc_reg_access(struct iio_dev *indio_dev,
 static int vf610_adc_reg_access(struct iio_dev *indio_dev,
 			unsigned reg, unsigned writeval,
 			unsigned reg, unsigned writeval,
 			unsigned *readval)
 			unsigned *readval)
@@ -753,7 +831,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
 
 
 	ret = devm_request_irq(info->dev, irq,
 	ret = devm_request_irq(info->dev, irq,
 				vf610_adc_isr, 0,
 				vf610_adc_isr, 0,
-				dev_name(&pdev->dev), info);
+				dev_name(&pdev->dev), indio_dev);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
 		dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
 		return ret;
 		return ret;
@@ -806,15 +884,23 @@ static int vf610_adc_probe(struct platform_device *pdev)
 	vf610_adc_cfg_init(info);
 	vf610_adc_cfg_init(info);
 	vf610_adc_hw_init(info);
 	vf610_adc_hw_init(info);
 
 
+	ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
+					NULL, &iio_triggered_buffer_setup_ops);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialise the buffer\n");
+		goto error_iio_device_register;
+	}
+
 	ret = iio_device_register(indio_dev);
 	ret = iio_device_register(indio_dev);
 	if (ret) {
 	if (ret) {
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
 		dev_err(&pdev->dev, "Couldn't register the device.\n");
-		goto error_iio_device_register;
+		goto error_adc_buffer_init;
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
-
+error_adc_buffer_init:
+	iio_triggered_buffer_cleanup(indio_dev);
 error_iio_device_register:
 error_iio_device_register:
 	clk_disable_unprepare(info->clk);
 	clk_disable_unprepare(info->clk);
 error_adc_clk_enable:
 error_adc_clk_enable:
@@ -829,6 +915,7 @@ static int vf610_adc_remove(struct platform_device *pdev)
 	struct vf610_adc *info = iio_priv(indio_dev);
 	struct vf610_adc *info = iio_priv(indio_dev);
 
 
 	iio_device_unregister(indio_dev);
 	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
 	regulator_disable(info->vref);
 	regulator_disable(info->vref);
 	clk_disable_unprepare(info->clk);
 	clk_disable_unprepare(info->clk);
 
 

+ 10 - 27
drivers/iio/adc/xilinx-xadc-core.c

@@ -273,33 +273,13 @@ static void xadc_zynq_unmask_worker(struct work_struct *work)
 		schedule_delayed_work(&xadc->zynq_unmask_work,
 		schedule_delayed_work(&xadc->zynq_unmask_work,
 				msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
 				msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
 	}
 	}
-}
-
-static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid)
-{
-	struct iio_dev *indio_dev = devid;
-	struct xadc *xadc = iio_priv(indio_dev);
-	unsigned int alarm;
-
-	spin_lock_irq(&xadc->lock);
-	alarm = xadc->zynq_alarm;
-	xadc->zynq_alarm = 0;
-	spin_unlock_irq(&xadc->lock);
-
-	xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm));
 
 
-	/* unmask the required interrupts in timer. */
-	schedule_delayed_work(&xadc->zynq_unmask_work,
-			msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
-
-	return IRQ_HANDLED;
 }
 }
 
 
 static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
 static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
 {
 {
 	struct iio_dev *indio_dev = devid;
 	struct iio_dev *indio_dev = devid;
 	struct xadc *xadc = iio_priv(indio_dev);
 	struct xadc *xadc = iio_priv(indio_dev);
-	irqreturn_t ret = IRQ_HANDLED;
 	uint32_t status;
 	uint32_t status;
 
 
 	xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
 	xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
@@ -321,18 +301,23 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
 
 
 	status &= XADC_ZYNQ_INT_ALARM_MASK;
 	status &= XADC_ZYNQ_INT_ALARM_MASK;
 	if (status) {
 	if (status) {
-		xadc->zynq_alarm |= status;
 		xadc->zynq_masked_alarm |= status;
 		xadc->zynq_masked_alarm |= status;
 		/*
 		/*
 		 * mask the current event interrupt,
 		 * mask the current event interrupt,
 		 * unmask it when the interrupt is no more active.
 		 * unmask it when the interrupt is no more active.
 		 */
 		 */
 		xadc_zynq_update_intmsk(xadc, 0, 0);
 		xadc_zynq_update_intmsk(xadc, 0, 0);
-		ret = IRQ_WAKE_THREAD;
+
+		xadc_handle_events(indio_dev,
+				xadc_zynq_transform_alarm(status));
+
+		/* unmask the required interrupts in timer. */
+		schedule_delayed_work(&xadc->zynq_unmask_work,
+				msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
 	}
 	}
 	spin_unlock(&xadc->lock);
 	spin_unlock(&xadc->lock);
 
 
-	return ret;
+	return IRQ_HANDLED;
 }
 }
 
 
 #define XADC_ZYNQ_TCK_RATE_MAX 50000000
 #define XADC_ZYNQ_TCK_RATE_MAX 50000000
@@ -437,7 +422,6 @@ static const struct xadc_ops xadc_zynq_ops = {
 	.setup = xadc_zynq_setup,
 	.setup = xadc_zynq_setup,
 	.get_dclk_rate = xadc_zynq_get_dclk_rate,
 	.get_dclk_rate = xadc_zynq_get_dclk_rate,
 	.interrupt_handler = xadc_zynq_interrupt_handler,
 	.interrupt_handler = xadc_zynq_interrupt_handler,
-	.threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
 	.update_alarm = xadc_zynq_update_alarm,
 	.update_alarm = xadc_zynq_update_alarm,
 };
 };
 
 
@@ -1225,9 +1209,8 @@ static int xadc_probe(struct platform_device *pdev)
 	if (ret)
 	if (ret)
 		goto err_free_samplerate_trigger;
 		goto err_free_samplerate_trigger;
 
 
-	ret = request_threaded_irq(irq, xadc->ops->interrupt_handler,
-				xadc->ops->threaded_interrupt_handler,
-				0, dev_name(&pdev->dev), indio_dev);
+	ret = request_irq(irq, xadc->ops->interrupt_handler, 0,
+			dev_name(&pdev->dev), indio_dev);
 	if (ret)
 	if (ret)
 		goto err_clk_disable_unprepare;
 		goto err_clk_disable_unprepare;
 
 

+ 0 - 2
drivers/iio/adc/xilinx-xadc.h

@@ -60,7 +60,6 @@ struct xadc {
 
 
 	enum xadc_external_mux_mode external_mux_mode;
 	enum xadc_external_mux_mode external_mux_mode;
 
 
-	unsigned int zynq_alarm;
 	unsigned int zynq_masked_alarm;
 	unsigned int zynq_masked_alarm;
 	unsigned int zynq_intmask;
 	unsigned int zynq_intmask;
 	struct delayed_work zynq_unmask_work;
 	struct delayed_work zynq_unmask_work;
@@ -79,7 +78,6 @@ struct xadc_ops {
 	void (*update_alarm)(struct xadc *, unsigned int);
 	void (*update_alarm)(struct xadc *, unsigned int);
 	unsigned long (*get_dclk_rate)(struct xadc *);
 	unsigned long (*get_dclk_rate)(struct xadc *);
 	irqreturn_t (*interrupt_handler)(int, void *);
 	irqreturn_t (*interrupt_handler)(int, void *);
-	irqreturn_t (*threaded_interrupt_handler)(int, void *);
 
 
 	unsigned int flags;
 	unsigned int flags;
 };
 };

+ 1 - 0
drivers/iio/amplifiers/ad8366.c

@@ -195,6 +195,7 @@ static const struct spi_device_id ad8366_id[] = {
 	{"ad8366", 0},
 	{"ad8366", 0},
 	{}
 	{}
 };
 };
+MODULE_DEVICE_TABLE(spi, ad8366_id);
 
 
 static struct spi_driver ad8366_driver = {
 static struct spi_driver ad8366_driver = {
 	.driver = {
 	.driver = {

+ 24 - 0
drivers/iio/buffer/Kconfig

@@ -0,0 +1,24 @@
+#
+# Industrial I/O generic buffer implementations
+#
+# When adding new entries keep the list in alphabetical order
+
+config IIO_BUFFER_CB
+	tristate "IIO callback buffer used for push in-kernel interfaces"
+	help
+	  Should be selected by any drivers that do in-kernel push
+	  usage.  That is, those where the data is pushed to the consumer.
+
+config IIO_KFIFO_BUF
+	tristate "Industrial I/O buffering based on kfifo"
+	help
+	  A simple fifo based on kfifo.  Note that this currently provides
+	  no buffer events so it is up to userspace to work out how
+	  often to read from the buffer.
+
+config IIO_TRIGGERED_BUFFER
+	tristate
+	select IIO_TRIGGER
+	select IIO_KFIFO_BUF
+	help
+	  Provides helper functions for setting up triggered buffers.

+ 8 - 0
drivers/iio/buffer/Makefile

@@ -0,0 +1,8 @@
+#
+# Makefile for the industrial I/O buffer implementations
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
+obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o

+ 12 - 0
drivers/iio/buffer_cb.c → drivers/iio/buffer/industrialio-buffer-cb.c

@@ -1,4 +1,12 @@
+/* The industrial I/O callback buffer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/export.h>
@@ -124,3 +132,7 @@ struct iio_channel
 	return cb_buffer->channels;
 	return cb_buffer->channels;
 }
 }
 EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
 EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("Industrial I/O callback buffer");
+MODULE_LICENSE("GPL");

+ 0 - 0
drivers/iio/industrialio-triggered-buffer.c → drivers/iio/buffer/industrialio-triggered-buffer.c


+ 0 - 0
drivers/iio/kfifo_buf.c → drivers/iio/buffer/kfifo_buf.c


+ 15 - 0
drivers/iio/chemical/Kconfig

@@ -0,0 +1,15 @@
+#
+# Chemical sensors
+#
+
+menu "Chemical Sensors"
+
+config VZ89X
+	tristate "SGX Sensortech MiCS VZ89X VOC sensor"
+	depends on I2C
+	help
+	  Say Y here to build I2C interface support for the SGX
+	  Sensortech MiCS VZ89X VOC (Volatile Organic Compounds)
+	  sensors
+
+endmenu

+ 6 - 0
drivers/iio/chemical/Makefile

@@ -0,0 +1,6 @@
+#
+# Makefile for IIO chemical sensors
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_VZ89X)		+= vz89x.o

+ 237 - 0
drivers/iio/chemical/vz89x.c

@@ -0,0 +1,237 @@
+/*
+ * vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define VZ89X_REG_MEASUREMENT		0x09
+#define VZ89X_REG_MEASUREMENT_SIZE	6
+
+#define VZ89X_VOC_CO2_IDX		0
+#define VZ89X_VOC_SHORT_IDX		1
+#define VZ89X_VOC_TVOC_IDX		2
+#define VZ89X_VOC_RESISTANCE_IDX	3
+
+struct vz89x_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	unsigned long last_update;
+
+	u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
+};
+
+static const struct iio_chan_spec vz89x_channels[] = {
+	{
+		.type = IIO_CONCENTRATION,
+		.channel2 = IIO_MOD_CO2,
+		.modified = 1,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+		.address = VZ89X_VOC_CO2_IDX,
+	},
+	{
+		.type = IIO_CONCENTRATION,
+		.channel2 = IIO_MOD_VOC,
+		.modified = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.address = VZ89X_VOC_SHORT_IDX,
+		.extend_name = "short",
+	},
+	{
+		.type = IIO_CONCENTRATION,
+		.channel2 = IIO_MOD_VOC,
+		.modified = 1,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
+		.address = VZ89X_VOC_TVOC_IDX,
+	},
+	{
+		.type = IIO_RESISTANCE,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.address = VZ89X_VOC_RESISTANCE_IDX,
+	},
+};
+
+static IIO_CONST_ATTR(in_concentration_co2_scale, "0.00000698689");
+static IIO_CONST_ATTR(in_concentration_voc_scale, "0.00000000436681223");
+
+static struct attribute *vz89x_attributes[] = {
+	&iio_const_attr_in_concentration_co2_scale.dev_attr.attr,
+	&iio_const_attr_in_concentration_voc_scale.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group vz89x_attrs_group = {
+	.attrs = vz89x_attributes,
+};
+
+static int vz89x_get_measurement(struct vz89x_data *data)
+{
+	int ret;
+	int i;
+
+	/* sensor can only be polled once a second max per datasheet */
+	if (!time_after(jiffies, data->last_update + HZ))
+		return 0;
+
+	ret = i2c_smbus_write_word_data(data->client,
+					VZ89X_REG_MEASUREMENT, 0);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
+		ret = i2c_smbus_read_byte(data->client);
+		if (ret < 0)
+			return ret;
+		data->buffer[i] = ret;
+	}
+
+	data->last_update = jiffies;
+
+	return 0;
+}
+
+static int vz89x_get_resistance_reading(struct vz89x_data *data)
+{
+	u8 *buf = &data->buffer[VZ89X_VOC_TVOC_IDX];
+
+	return buf[0] | (buf[1] << 8) | (buf[2] << 16);
+}
+
+static int vz89x_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan, int *val,
+			  int *val2, long mask)
+{
+	struct vz89x_data *data = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+		ret = vz89x_get_measurement(data);
+		mutex_unlock(&data->lock);
+
+		if (ret)
+			return ret;
+
+		switch (chan->address) {
+		case VZ89X_VOC_CO2_IDX:
+		case VZ89X_VOC_SHORT_IDX:
+		case VZ89X_VOC_TVOC_IDX:
+			*val = data->buffer[chan->address];
+			return IIO_VAL_INT;
+		case VZ89X_VOC_RESISTANCE_IDX:
+			*val = vz89x_get_resistance_reading(data);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		switch (chan->type) {
+		case IIO_RESISTANCE:
+			*val = 10;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		switch (chan->address) {
+		case VZ89X_VOC_CO2_IDX:
+			*val = 44;
+			*val2 = 250000;
+			return IIO_VAL_INT_PLUS_MICRO;
+		case VZ89X_VOC_TVOC_IDX:
+			*val = -13;
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+static const struct iio_info vz89x_info = {
+	.attrs		= &vz89x_attrs_group,
+	.read_raw	= vz89x_read_raw,
+	.driver_module	= THIS_MODULE,
+};
+
+static int vz89x_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct vz89x_data *data;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
+				     I2C_FUNC_SMBUS_BYTE))
+		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;
+	data->last_update = jiffies - HZ;
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &vz89x_info,
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	indio_dev->channels = vz89x_channels;
+	indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id vz89x_id[] = {
+	{ "vz89x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, vz89x_id);
+
+static const struct of_device_id vz89x_dt_ids[] = {
+	{ .compatible = "sgx,vz89x" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
+
+static struct i2c_driver vz89x_driver = {
+	.driver = {
+		.name	= "vz89x",
+		.of_match_table = of_match_ptr(vz89x_dt_ids),
+	},
+	.probe = vz89x_probe,
+	.id_table = vz89x_id,
+};
+module_i2c_driver(vz89x_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors");
+MODULE_LICENSE("GPL v2");

+ 22 - 0
drivers/iio/common/st_sensors/st_sensors_core.c

@@ -44,6 +44,28 @@ st_sensors_write_data_with_mask_error:
 	return err;
 	return err;
 }
 }
 
 
+int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
+				  unsigned reg, unsigned writeval,
+				  unsigned *readval)
+{
+	struct st_sensor_data *sdata = iio_priv(indio_dev);
+	u8 readdata;
+	int err;
+
+	if (!readval)
+		return sdata->tf->write_byte(&sdata->tb, sdata->dev,
+					     (u8)reg, (u8)writeval);
+
+	err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata);
+	if (err < 0)
+		return err;
+
+	*readval = (unsigned)readdata;
+
+	return 0;
+}
+EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
+
 static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
 static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
 			unsigned int odr, struct st_sensor_odr_avl *odr_out)
 			unsigned int odr, struct st_sensor_odr_avl *odr_out)
 {
 {

+ 7 - 0
drivers/iio/dac/ad7303.c

@@ -281,6 +281,12 @@ static int ad7303_remove(struct spi_device *spi)
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct of_device_id ad7303_spi_of_match[] = {
+	{ .compatible = "adi,ad7303", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ad7303_spi_of_match);
+
 static const struct spi_device_id ad7303_spi_ids[] = {
 static const struct spi_device_id ad7303_spi_ids[] = {
 	{ "ad7303", 0 },
 	{ "ad7303", 0 },
 	{}
 	{}
@@ -290,6 +296,7 @@ MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
 static struct spi_driver ad7303_driver = {
 static struct spi_driver ad7303_driver = {
 	.driver = {
 	.driver = {
 		.name = "ad7303",
 		.name = "ad7303",
+		.of_match_table = of_match_ptr(ad7303_spi_of_match),
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe = ad7303_probe,
 	.probe = ad7303_probe,

+ 1 - 0
drivers/iio/dac/max5821.c

@@ -387,6 +387,7 @@ static const struct of_device_id max5821_of_match[] = {
 	{ .compatible = "maxim,max5821" },
 	{ .compatible = "maxim,max5821" },
 	{ }
 	{ }
 };
 };
+MODULE_DEVICE_TABLE(of, max5821_of_match);
 
 
 static struct i2c_driver max5821_driver = {
 static struct i2c_driver max5821_driver = {
 	.driver = {
 	.driver = {

+ 9 - 0
drivers/iio/frequency/adf4350.c

@@ -616,15 +616,24 @@ static int adf4350_remove(struct spi_device *spi)
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct of_device_id adf4350_of_match[] = {
+	{ .compatible = "adi,adf4350", },
+	{ .compatible = "adi,adf4351", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, adf4350_of_match);
+
 static const struct spi_device_id adf4350_id[] = {
 static const struct spi_device_id adf4350_id[] = {
 	{"adf4350", 4350},
 	{"adf4350", 4350},
 	{"adf4351", 4351},
 	{"adf4351", 4351},
 	{}
 	{}
 };
 };
+MODULE_DEVICE_TABLE(spi, adf4350_id);
 
 
 static struct spi_driver adf4350_driver = {
 static struct spi_driver adf4350_driver = {
 	.driver = {
 	.driver = {
 		.name	= "adf4350",
 		.name	= "adf4350",
+		.of_match_table = of_match_ptr(adf4350_of_match),
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= adf4350_probe,
 	.probe		= adf4350_probe,

+ 15 - 4
drivers/iio/gyro/Kconfig

@@ -52,15 +52,26 @@ config ADXRS450
 
 
 config BMG160
 config BMG160
 	tristate "BOSCH BMG160 Gyro Sensor"
 	tristate "BOSCH BMG160 Gyro Sensor"
-	depends on I2C
+	depends on (I2C || SPI_MASTER)
 	select IIO_BUFFER
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	select IIO_TRIGGERED_BUFFER
+	select BMG160_I2C if (I2C)
+	select BMG160_SPI if (SPI)
 	help
 	help
-	  Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
-	  driver. This driver also supports BMI055 gyroscope.
+	  Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor
+	  driver connected via I2C or SPI. This driver also supports BMI055
+	  gyroscope.
 
 
 	  This driver can also be built as a module.  If so, the module
 	  This driver can also be built as a module.  If so, the module
-	  will be called bmg160.
+	  will be called bmg160_i2c or bmg160_spi.
+
+config BMG160_I2C
+	tristate
+	select REGMAP_I2C
+
+config BMG160_SPI
+	tristate
+	select REGMAP_SPI
 
 
 config HID_SENSOR_GYRO_3D
 config HID_SENSOR_GYRO_3D
 	depends on HID_SENSOR_HUB
 	depends on HID_SENSOR_HUB

+ 3 - 1
drivers/iio/gyro/Makefile

@@ -8,7 +8,9 @@ obj-$(CONFIG_ADIS16130) += adis16130.o
 obj-$(CONFIG_ADIS16136) += adis16136.o
 obj-$(CONFIG_ADIS16136) += adis16136.o
 obj-$(CONFIG_ADIS16260) += adis16260.o
 obj-$(CONFIG_ADIS16260) += adis16260.o
 obj-$(CONFIG_ADXRS450) += adxrs450.o
 obj-$(CONFIG_ADXRS450) += adxrs450.o
-obj-$(CONFIG_BMG160) += bmg160.o
+obj-$(CONFIG_BMG160) += bmg160_core.o
+obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
+obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
 
 
 obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
 obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
 
 

+ 10 - 0
drivers/iio/gyro/bmg160.h

@@ -0,0 +1,10 @@
+#ifndef BMG160_H_
+#define BMG160_H_
+
+extern const struct dev_pm_ops bmg160_pm_ops;
+
+int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+		      const char *name);
+void bmg160_core_remove(struct device *dev);
+
+#endif  /* BMG160_H_ */

+ 145 - 216
drivers/iio/gyro/bmg160.c → drivers/iio/gyro/bmg160_core.c

@@ -13,7 +13,6 @@
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -28,8 +27,9 @@
 #include <linux/iio/events.h>
 #include <linux/iio/events.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
 #include <linux/iio/triggered_buffer.h>
+#include <linux/regmap.h>
+#include "bmg160.h"
 
 
-#define BMG160_DRV_NAME		"bmg160"
 #define BMG160_IRQ_NAME		"bmg160_event"
 #define BMG160_IRQ_NAME		"bmg160_event"
 #define BMG160_GPIO_NAME		"gpio_int"
 #define BMG160_GPIO_NAME		"gpio_int"
 
 
@@ -97,7 +97,8 @@
 #define BMG160_AUTO_SUSPEND_DELAY_MS	2000
 #define BMG160_AUTO_SUSPEND_DELAY_MS	2000
 
 
 struct bmg160_data {
 struct bmg160_data {
-	struct i2c_client *client;
+	struct device *dev;
+	struct regmap *regmap;
 	struct iio_trigger *dready_trig;
 	struct iio_trigger *dready_trig;
 	struct iio_trigger *motion_trig;
 	struct iio_trigger *motion_trig;
 	struct mutex mutex;
 	struct mutex mutex;
@@ -108,6 +109,7 @@ struct bmg160_data {
 	int slope_thres;
 	int slope_thres;
 	bool dready_trigger_on;
 	bool dready_trigger_on;
 	bool motion_trigger_on;
 	bool motion_trigger_on;
+	int irq;
 };
 };
 
 
 enum bmg160_axis {
 enum bmg160_axis {
@@ -138,10 +140,9 @@ static int bmg160_set_mode(struct bmg160_data *data, u8 mode)
 {
 {
 	int ret;
 	int ret;
 
 
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_PMU_LPW, mode);
+	ret = regmap_write(data->regmap, BMG160_REG_PMU_LPW, mode);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n");
+		dev_err(data->dev, "Error writing reg_pmu_lpw\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -169,10 +170,9 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
 	if (bw_bits < 0)
 	if (bw_bits < 0)
 		return bw_bits;
 		return bw_bits;
 
 
-	ret = i2c_smbus_write_byte_data(data->client, BMG160_REG_PMU_BW,
-					bw_bits);
+	ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bw_bits);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_pmu_bw\n");
+		dev_err(data->dev, "Error writing reg_pmu_bw\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -184,16 +184,17 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
 static int bmg160_chip_init(struct bmg160_data *data)
 static int bmg160_chip_init(struct bmg160_data *data)
 {
 {
 	int ret;
 	int ret;
+	unsigned int val;
 
 
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_CHIP_ID);
+	ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_chip_id\n");
+		dev_err(data->dev, "Error reading reg_chip_id\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
-	dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
-	if (ret != BMG160_CHIP_ID_VAL) {
-		dev_err(&data->client->dev, "invalid chip %x\n", ret);
+	dev_dbg(data->dev, "Chip Id %x\n", val);
+	if (val != BMG160_CHIP_ID_VAL) {
+		dev_err(data->dev, "invalid chip %x\n", val);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -210,42 +211,33 @@ static int bmg160_chip_init(struct bmg160_data *data)
 		return ret;
 		return ret;
 
 
 	/* Set Default Range */
 	/* Set Default Range */
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_RANGE,
-					BMG160_RANGE_500DPS);
+	ret = regmap_write(data->regmap, BMG160_REG_RANGE, BMG160_RANGE_500DPS);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_range\n");
+		dev_err(data->dev, "Error writing reg_range\n");
 		return ret;
 		return ret;
 	}
 	}
 	data->dps_range = BMG160_RANGE_500DPS;
 	data->dps_range = BMG160_RANGE_500DPS;
 
 
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_SLOPE_THRES);
+	ret = regmap_read(data->regmap, BMG160_REG_SLOPE_THRES, &val);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_slope_thres\n");
+		dev_err(data->dev, "Error reading reg_slope_thres\n");
 		return ret;
 		return ret;
 	}
 	}
-	data->slope_thres = ret;
+	data->slope_thres = val;
 
 
 	/* Set default interrupt mode */
 	/* Set default interrupt mode */
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1);
+	ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
+				 BMG160_INT1_BIT_OD, 0);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_en_1\n");
-		return ret;
-	}
-	ret &= ~BMG160_INT1_BIT_OD;
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_EN_1, ret);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_en_1\n");
+		dev_err(data->dev, "Error updating bits in reg_int_en_1\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_RST_LATCH,
-					BMG160_INT_MODE_LATCH_INT |
-					BMG160_INT_MODE_LATCH_RESET);
+	ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+			   BMG160_INT_MODE_LATCH_INT |
+			   BMG160_INT_MODE_LATCH_RESET);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev,
+		dev_err(data->dev,
 			"Error writing reg_motion_intr\n");
 			"Error writing reg_motion_intr\n");
 		return ret;
 		return ret;
 	}
 	}
@@ -259,17 +251,17 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on)
 	int ret;
 	int ret;
 
 
 	if (on)
 	if (on)
-		ret = pm_runtime_get_sync(&data->client->dev);
+		ret = pm_runtime_get_sync(data->dev);
 	else {
 	else {
-		pm_runtime_mark_last_busy(&data->client->dev);
-		ret = pm_runtime_put_autosuspend(&data->client->dev);
+		pm_runtime_mark_last_busy(data->dev);
+		ret = pm_runtime_put_autosuspend(data->dev);
 	}
 	}
 
 
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev,
+		dev_err(data->dev,
 			"Failed: bmg160_set_power_state for %d\n", on);
 			"Failed: bmg160_set_power_state for %d\n", on);
 		if (on)
 		if (on)
-			pm_runtime_put_noidle(&data->client->dev);
+			pm_runtime_put_noidle(data->dev);
 
 
 		return ret;
 		return ret;
 	}
 	}
@@ -284,43 +276,30 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 	int ret;
 	int ret;
 
 
 	/* Enable/Disable INT_MAP0 mapping */
 	/* Enable/Disable INT_MAP0 mapping */
-	ret = i2c_smbus_read_byte_data(data->client,  BMG160_REG_INT_MAP_0);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_map0\n");
-		return ret;
-	}
-	if (status)
-		ret |= BMG160_INT_MAP_0_BIT_ANY;
-	else
-		ret &= ~BMG160_INT_MAP_0_BIT_ANY;
-
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_MAP_0,
-					ret);
+	ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_0,
+				 BMG160_INT_MAP_0_BIT_ANY,
+				 (status ? BMG160_INT_MAP_0_BIT_ANY : 0));
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_map0\n");
+		dev_err(data->dev, "Error updating bits reg_int_map0\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
 	/* Enable/Disable slope interrupts */
 	/* Enable/Disable slope interrupts */
 	if (status) {
 	if (status) {
 		/* Update slope thres */
 		/* Update slope thres */
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_SLOPE_THRES,
-						data->slope_thres);
+		ret = regmap_write(data->regmap, BMG160_REG_SLOPE_THRES,
+				   data->slope_thres);
 		if (ret < 0) {
 		if (ret < 0) {
-			dev_err(&data->client->dev,
+			dev_err(data->dev,
 				"Error writing reg_slope_thres\n");
 				"Error writing reg_slope_thres\n");
 			return ret;
 			return ret;
 		}
 		}
 
 
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_MOTION_INTR,
-						BMG160_INT_MOTION_X |
-						BMG160_INT_MOTION_Y |
-						BMG160_INT_MOTION_Z);
+		ret = regmap_write(data->regmap, BMG160_REG_MOTION_INTR,
+				   BMG160_INT_MOTION_X | BMG160_INT_MOTION_Y |
+				   BMG160_INT_MOTION_Z);
 		if (ret < 0) {
 		if (ret < 0) {
-			dev_err(&data->client->dev,
+			dev_err(data->dev,
 				"Error writing reg_motion_intr\n");
 				"Error writing reg_motion_intr\n");
 			return ret;
 			return ret;
 		}
 		}
@@ -331,28 +310,26 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
 		 * to set latched mode, we will be flooded anyway with INTR
 		 * to set latched mode, we will be flooded anyway with INTR
 		 */
 		 */
 		if (!data->dready_trigger_on) {
 		if (!data->dready_trigger_on) {
-			ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_RST_LATCH,
-						BMG160_INT_MODE_LATCH_INT |
-						BMG160_INT_MODE_LATCH_RESET);
+			ret = regmap_write(data->regmap,
+					   BMG160_REG_INT_RST_LATCH,
+					   BMG160_INT_MODE_LATCH_INT |
+					   BMG160_INT_MODE_LATCH_RESET);
 			if (ret < 0) {
 			if (ret < 0) {
-				dev_err(&data->client->dev,
+				dev_err(data->dev,
 					"Error writing reg_rst_latch\n");
 					"Error writing reg_rst_latch\n");
 				return ret;
 				return ret;
 			}
 			}
 		}
 		}
 
 
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_EN_0,
-						BMG160_DATA_ENABLE_INT);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
+				   BMG160_DATA_ENABLE_INT);
 
 
-	} else
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_EN_0,
-						0);
+	} else {
+		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
+	}
 
 
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_en0\n");
+		dev_err(data->dev, "Error writing reg_int_en0\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -365,59 +342,43 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
 	int ret;
 	int ret;
 
 
 	/* Enable/Disable INT_MAP1 mapping */
 	/* Enable/Disable INT_MAP1 mapping */
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_1);
-	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_map1\n");
-		return ret;
-	}
-
-	if (status)
-		ret |= BMG160_INT_MAP_1_BIT_NEW_DATA;
-	else
-		ret &= ~BMG160_INT_MAP_1_BIT_NEW_DATA;
-
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_MAP_1,
-					ret);
+	ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_1,
+				 BMG160_INT_MAP_1_BIT_NEW_DATA,
+				 (status ? BMG160_INT_MAP_1_BIT_NEW_DATA : 0));
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_map1\n");
+		dev_err(data->dev, "Error updating bits in reg_int_map1\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
 	if (status) {
 	if (status) {
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_RST_LATCH,
-						BMG160_INT_MODE_NON_LATCH_INT |
-						BMG160_INT_MODE_LATCH_RESET);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+				   BMG160_INT_MODE_NON_LATCH_INT |
+				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
 		if (ret < 0) {
-			dev_err(&data->client->dev,
+			dev_err(data->dev,
 				"Error writing reg_rst_latch\n");
 				"Error writing reg_rst_latch\n");
 				return ret;
 				return ret;
 		}
 		}
 
 
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_EN_0,
-						BMG160_DATA_ENABLE_INT);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
+				   BMG160_DATA_ENABLE_INT);
 
 
 	} else {
 	} else {
 		/* Restore interrupt mode */
 		/* Restore interrupt mode */
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_RST_LATCH,
-						BMG160_INT_MODE_LATCH_INT |
-						BMG160_INT_MODE_LATCH_RESET);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+				   BMG160_INT_MODE_LATCH_INT |
+				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
 		if (ret < 0) {
-			dev_err(&data->client->dev,
+			dev_err(data->dev,
 				"Error writing reg_rst_latch\n");
 				"Error writing reg_rst_latch\n");
 				return ret;
 				return ret;
 		}
 		}
 
 
-		ret = i2c_smbus_write_byte_data(data->client,
-						BMG160_REG_INT_EN_0,
-						0);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
 	}
 	}
 
 
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_int_en0\n");
+		dev_err(data->dev, "Error writing reg_int_en0\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -444,12 +405,10 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
 
 
 	for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
 	for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
 		if (bmg160_scale_table[i].scale == val) {
 		if (bmg160_scale_table[i].scale == val) {
-			ret = i2c_smbus_write_byte_data(
-					data->client,
-					BMG160_REG_RANGE,
-					bmg160_scale_table[i].dps_range);
+			ret = regmap_write(data->regmap, BMG160_REG_RANGE,
+					   bmg160_scale_table[i].dps_range);
 			if (ret < 0) {
 			if (ret < 0) {
-				dev_err(&data->client->dev,
+				dev_err(data->dev,
 					"Error writing reg_range\n");
 					"Error writing reg_range\n");
 				return ret;
 				return ret;
 			}
 			}
@@ -464,6 +423,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
 static int bmg160_get_temp(struct bmg160_data *data, int *val)
 static int bmg160_get_temp(struct bmg160_data *data, int *val)
 {
 {
 	int ret;
 	int ret;
+	unsigned int raw_val;
 
 
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
 	ret = bmg160_set_power_state(data, true);
 	ret = bmg160_set_power_state(data, true);
@@ -472,15 +432,15 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_TEMP);
+	ret = regmap_read(data->regmap, BMG160_REG_TEMP, &raw_val);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_temp\n");
+		dev_err(data->dev, "Error reading reg_temp\n");
 		bmg160_set_power_state(data, false);
 		bmg160_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		mutex_unlock(&data->mutex);
 		return ret;
 		return ret;
 	}
 	}
 
 
-	*val = sign_extend32(ret, 7);
+	*val = sign_extend32(raw_val, 7);
 	ret = bmg160_set_power_state(data, false);
 	ret = bmg160_set_power_state(data, false);
 	mutex_unlock(&data->mutex);
 	mutex_unlock(&data->mutex);
 	if (ret < 0)
 	if (ret < 0)
@@ -492,6 +452,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 {
 {
 	int ret;
 	int ret;
+	unsigned int raw_val;
 
 
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
 	ret = bmg160_set_power_state(data, true);
 	ret = bmg160_set_power_state(data, true);
@@ -500,15 +461,16 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	ret = i2c_smbus_read_word_data(data->client, BMG160_AXIS_TO_REG(axis));
+	ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
+			       2);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading axis %d\n", axis);
+		dev_err(data->dev, "Error reading axis %d\n", axis);
 		bmg160_set_power_state(data, false);
 		bmg160_set_power_state(data, false);
 		mutex_unlock(&data->mutex);
 		mutex_unlock(&data->mutex);
 		return ret;
 		return ret;
 	}
 	}
 
 
-	*val = sign_extend32(ret, 15);
+	*val = sign_extend32(raw_val, 15);
 	ret = bmg160_set_power_state(data, false);
 	ret = bmg160_set_power_state(data, false);
 	mutex_unlock(&data->mutex);
 	mutex_unlock(&data->mutex);
 	if (ret < 0)
 	if (ret < 0)
@@ -807,12 +769,13 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct iio_dev *indio_dev = pf->indio_dev;
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	int bit, ret, i = 0;
 	int bit, ret, i = 0;
+	unsigned int val;
 
 
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
 	for_each_set_bit(bit, indio_dev->active_scan_mask,
 	for_each_set_bit(bit, indio_dev->active_scan_mask,
 			 indio_dev->masklength) {
 			 indio_dev->masklength) {
-		ret = i2c_smbus_read_word_data(data->client,
-					       BMG160_AXIS_TO_REG(bit));
+		ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit),
+				       &val, 2);
 		if (ret < 0) {
 		if (ret < 0) {
 			mutex_unlock(&data->mutex);
 			mutex_unlock(&data->mutex);
 			goto err;
 			goto err;
@@ -840,12 +803,11 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
 		return 0;
 		return 0;
 
 
 	/* Set latched mode interrupt and clear any latched interrupt */
 	/* Set latched mode interrupt and clear any latched interrupt */
-	ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_RST_LATCH,
-					BMG160_INT_MODE_LATCH_INT |
-					BMG160_INT_MODE_LATCH_RESET);
+	ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+			   BMG160_INT_MODE_LATCH_INT |
+			   BMG160_INT_MODE_LATCH_RESET);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error writing reg_rst_latch\n");
+		dev_err(data->dev, "Error writing reg_rst_latch\n");
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -907,33 +869,34 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	int ret;
 	int ret;
 	int dir;
 	int dir;
+	unsigned int val;
 
 
-	ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_STATUS_2);
+	ret = regmap_read(data->regmap, BMG160_REG_INT_STATUS_2, &val);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "Error reading reg_int_status2\n");
+		dev_err(data->dev, "Error reading reg_int_status2\n");
 		goto ack_intr_status;
 		goto ack_intr_status;
 	}
 	}
 
 
-	if (ret & 0x08)
+	if (val & 0x08)
 		dir = IIO_EV_DIR_RISING;
 		dir = IIO_EV_DIR_RISING;
 	else
 	else
 		dir = IIO_EV_DIR_FALLING;
 		dir = IIO_EV_DIR_FALLING;
 
 
-	if (ret & BMG160_ANY_MOTION_BIT_X)
+	if (val & BMG160_ANY_MOTION_BIT_X)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 							0,
 							0,
 							IIO_MOD_X,
 							IIO_MOD_X,
 							IIO_EV_TYPE_ROC,
 							IIO_EV_TYPE_ROC,
 							dir),
 							dir),
 							iio_get_time_ns());
 							iio_get_time_ns());
-	if (ret & BMG160_ANY_MOTION_BIT_Y)
+	if (val & BMG160_ANY_MOTION_BIT_Y)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 							0,
 							0,
 							IIO_MOD_Y,
 							IIO_MOD_Y,
 							IIO_EV_TYPE_ROC,
 							IIO_EV_TYPE_ROC,
 							dir),
 							dir),
 							iio_get_time_ns());
 							iio_get_time_ns());
-	if (ret & BMG160_ANY_MOTION_BIT_Z)
+	if (val & BMG160_ANY_MOTION_BIT_Z)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 							0,
 							0,
 							IIO_MOD_Z,
 							IIO_MOD_Z,
@@ -943,12 +906,11 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
 
 
 ack_intr_status:
 ack_intr_status:
 	if (!data->dready_trigger_on) {
 	if (!data->dready_trigger_on) {
-		ret = i2c_smbus_write_byte_data(data->client,
-					BMG160_REG_INT_RST_LATCH,
-					BMG160_INT_MODE_LATCH_INT |
-					BMG160_INT_MODE_LATCH_RESET);
+		ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH,
+				   BMG160_INT_MODE_LATCH_INT |
+				   BMG160_INT_MODE_LATCH_RESET);
 		if (ret < 0)
 		if (ret < 0)
-			dev_err(&data->client->dev,
+			dev_err(data->dev,
 				"Error writing reg_rst_latch\n");
 				"Error writing reg_rst_latch\n");
 	}
 	}
 
 
@@ -993,18 +955,13 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
 	.postdisable = bmg160_buffer_postdisable,
 	.postdisable = bmg160_buffer_postdisable,
 };
 };
 
 
-static int bmg160_gpio_probe(struct i2c_client *client,
-			     struct bmg160_data *data)
+static int bmg160_gpio_probe(struct bmg160_data *data)
 
 
 {
 {
 	struct device *dev;
 	struct device *dev;
 	struct gpio_desc *gpio;
 	struct gpio_desc *gpio;
-	int ret;
-
-	if (!client)
-		return -EINVAL;
 
 
-	dev = &client->dev;
+	dev = data->dev;
 
 
 	/* data ready gpio interrupt pin */
 	/* data ready gpio interrupt pin */
 	gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
 	gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
@@ -1013,11 +970,12 @@ static int bmg160_gpio_probe(struct i2c_client *client,
 		return PTR_ERR(gpio);
 		return PTR_ERR(gpio);
 	}
 	}
 
 
-	ret = gpiod_to_irq(gpio);
+	data->irq = gpiod_to_irq(gpio);
 
 
-	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
+		data->irq);
 
 
-	return ret;
+	return 0;
 }
 }
 
 
 static const char *bmg160_match_acpi_device(struct device *dev)
 static const char *bmg160_match_acpi_device(struct device *dev)
@@ -1031,21 +989,22 @@ static const char *bmg160_match_acpi_device(struct device *dev)
 	return dev_name(dev);
 	return dev_name(dev);
 }
 }
 
 
-static int bmg160_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
+		      const char *name)
 {
 {
 	struct bmg160_data *data;
 	struct bmg160_data *data;
 	struct iio_dev *indio_dev;
 	struct iio_dev *indio_dev;
 	int ret;
 	int ret;
-	const char *name = NULL;
 
 
-	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
 	if (!indio_dev)
 	if (!indio_dev)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	data = iio_priv(indio_dev);
 	data = iio_priv(indio_dev);
-	i2c_set_clientdata(client, indio_dev);
-	data->client = client;
+	dev_set_drvdata(dev, indio_dev);
+	data->dev = dev;
+	data->irq = irq;
+	data->regmap = regmap;
 
 
 	ret = bmg160_chip_init(data);
 	ret = bmg160_chip_init(data);
 	if (ret < 0)
 	if (ret < 0)
@@ -1053,25 +1012,22 @@ static int bmg160_probe(struct i2c_client *client,
 
 
 	mutex_init(&data->mutex);
 	mutex_init(&data->mutex);
 
 
-	if (id)
-		name = id->name;
+	if (ACPI_HANDLE(dev))
+		name = bmg160_match_acpi_device(dev);
 
 
-	if (ACPI_HANDLE(&client->dev))
-		name = bmg160_match_acpi_device(&client->dev);
-
-	indio_dev->dev.parent = &client->dev;
+	indio_dev->dev.parent = dev;
 	indio_dev->channels = bmg160_channels;
 	indio_dev->channels = bmg160_channels;
 	indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
 	indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
 	indio_dev->name = name;
 	indio_dev->name = name;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &bmg160_info;
 	indio_dev->info = &bmg160_info;
 
 
-	if (client->irq <= 0)
-		client->irq = bmg160_gpio_probe(client, data);
+	if (data->irq <= 0)
+		bmg160_gpio_probe(data);
 
 
-	if (client->irq > 0) {
-		ret = devm_request_threaded_irq(&client->dev,
-						client->irq,
+	if (data->irq > 0) {
+		ret = devm_request_threaded_irq(dev,
+						data->irq,
 						bmg160_data_rdy_trig_poll,
 						bmg160_data_rdy_trig_poll,
 						bmg160_event_handler,
 						bmg160_event_handler,
 						IRQF_TRIGGER_RISING,
 						IRQF_TRIGGER_RISING,
@@ -1080,28 +1036,28 @@ static int bmg160_probe(struct i2c_client *client,
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 
 
-		data->dready_trig = devm_iio_trigger_alloc(&client->dev,
+		data->dready_trig = devm_iio_trigger_alloc(dev,
 							   "%s-dev%d",
 							   "%s-dev%d",
 							   indio_dev->name,
 							   indio_dev->name,
 							   indio_dev->id);
 							   indio_dev->id);
 		if (!data->dready_trig)
 		if (!data->dready_trig)
 			return -ENOMEM;
 			return -ENOMEM;
 
 
-		data->motion_trig = devm_iio_trigger_alloc(&client->dev,
+		data->motion_trig = devm_iio_trigger_alloc(dev,
 							  "%s-any-motion-dev%d",
 							  "%s-any-motion-dev%d",
 							  indio_dev->name,
 							  indio_dev->name,
 							  indio_dev->id);
 							  indio_dev->id);
 		if (!data->motion_trig)
 		if (!data->motion_trig)
 			return -ENOMEM;
 			return -ENOMEM;
 
 
-		data->dready_trig->dev.parent = &client->dev;
+		data->dready_trig->dev.parent = dev;
 		data->dready_trig->ops = &bmg160_trigger_ops;
 		data->dready_trig->ops = &bmg160_trigger_ops;
 		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
 		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
 		ret = iio_trigger_register(data->dready_trig);
 		ret = iio_trigger_register(data->dready_trig);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
 
 
-		data->motion_trig->dev.parent = &client->dev;
+		data->motion_trig->dev.parent = dev;
 		data->motion_trig->ops = &bmg160_trigger_ops;
 		data->motion_trig->ops = &bmg160_trigger_ops;
 		iio_trigger_set_drvdata(data->motion_trig, indio_dev);
 		iio_trigger_set_drvdata(data->motion_trig, indio_dev);
 		ret = iio_trigger_register(data->motion_trig);
 		ret = iio_trigger_register(data->motion_trig);
@@ -1116,25 +1072,25 @@ static int bmg160_probe(struct i2c_client *client,
 					 bmg160_trigger_handler,
 					 bmg160_trigger_handler,
 					 &bmg160_buffer_setup_ops);
 					 &bmg160_buffer_setup_ops);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&client->dev,
+		dev_err(dev,
 			"iio triggered buffer setup failed\n");
 			"iio triggered buffer setup failed\n");
 		goto err_trigger_unregister;
 		goto err_trigger_unregister;
 	}
 	}
 
 
 	ret = iio_device_register(indio_dev);
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&client->dev, "unable to register iio device\n");
+		dev_err(dev, "unable to register iio device\n");
 		goto err_buffer_cleanup;
 		goto err_buffer_cleanup;
 	}
 	}
 
 
-	ret = pm_runtime_set_active(&client->dev);
+	ret = pm_runtime_set_active(dev);
 	if (ret)
 	if (ret)
 		goto err_iio_unregister;
 		goto err_iio_unregister;
 
 
-	pm_runtime_enable(&client->dev);
-	pm_runtime_set_autosuspend_delay(&client->dev,
+	pm_runtime_enable(dev);
+	pm_runtime_set_autosuspend_delay(dev,
 					 BMG160_AUTO_SUSPEND_DELAY_MS);
 					 BMG160_AUTO_SUSPEND_DELAY_MS);
-	pm_runtime_use_autosuspend(&client->dev);
+	pm_runtime_use_autosuspend(dev);
 
 
 	return 0;
 	return 0;
 
 
@@ -1150,15 +1106,16 @@ err_trigger_unregister:
 
 
 	return ret;
 	return ret;
 }
 }
+EXPORT_SYMBOL_GPL(bmg160_core_probe);
 
 
-static int bmg160_remove(struct i2c_client *client)
+void bmg160_core_remove(struct device *dev)
 {
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 
 
-	pm_runtime_disable(&client->dev);
-	pm_runtime_set_suspended(&client->dev);
-	pm_runtime_put_noidle(&client->dev);
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_put_noidle(dev);
 
 
 	iio_device_unregister(indio_dev);
 	iio_device_unregister(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
 	iio_triggered_buffer_cleanup(indio_dev);
@@ -1171,14 +1128,13 @@ static int bmg160_remove(struct i2c_client *client)
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
 	bmg160_set_mode(data, BMG160_MODE_DEEP_SUSPEND);
 	bmg160_set_mode(data, BMG160_MODE_DEEP_SUSPEND);
 	mutex_unlock(&data->mutex);
 	mutex_unlock(&data->mutex);
-
-	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(bmg160_core_remove);
 
 
 #ifdef CONFIG_PM_SLEEP
 #ifdef CONFIG_PM_SLEEP
 static int bmg160_suspend(struct device *dev)
 static int bmg160_suspend(struct device *dev)
 {
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 
 
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
@@ -1190,7 +1146,7 @@ static int bmg160_suspend(struct device *dev)
 
 
 static int bmg160_resume(struct device *dev)
 static int bmg160_resume(struct device *dev)
 {
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 
 
 	mutex_lock(&data->mutex);
 	mutex_lock(&data->mutex);
@@ -1206,13 +1162,13 @@ static int bmg160_resume(struct device *dev)
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int bmg160_runtime_suspend(struct device *dev)
 static int bmg160_runtime_suspend(struct device *dev)
 {
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	int ret;
 	int ret;
 
 
 	ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
 	ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(&data->client->dev, "set mode failed\n");
+		dev_err(data->dev, "set mode failed\n");
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
@@ -1221,7 +1177,7 @@ static int bmg160_runtime_suspend(struct device *dev)
 
 
 static int bmg160_runtime_resume(struct device *dev)
 static int bmg160_runtime_resume(struct device *dev)
 {
 {
-	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	struct bmg160_data *data = iio_priv(indio_dev);
 	int ret;
 	int ret;
 
 
@@ -1235,39 +1191,12 @@ static int bmg160_runtime_resume(struct device *dev)
 }
 }
 #endif
 #endif
 
 
-static const struct dev_pm_ops bmg160_pm_ops = {
+const struct dev_pm_ops bmg160_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(bmg160_suspend, bmg160_resume)
 	SET_SYSTEM_SLEEP_PM_OPS(bmg160_suspend, bmg160_resume)
 	SET_RUNTIME_PM_OPS(bmg160_runtime_suspend,
 	SET_RUNTIME_PM_OPS(bmg160_runtime_suspend,
 			   bmg160_runtime_resume, NULL)
 			   bmg160_runtime_resume, NULL)
 };
 };
-
-static const struct acpi_device_id bmg160_acpi_match[] = {
-	{"BMG0160", 0},
-	{"BMI055B", 0},
-	{},
-};
-
-MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
-
-static const struct i2c_device_id bmg160_id[] = {
-	{"bmg160", 0},
-	{"bmi055_gyro", 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, bmg160_id);
-
-static struct i2c_driver bmg160_driver = {
-	.driver = {
-		.name	= BMG160_DRV_NAME,
-		.acpi_match_table = ACPI_PTR(bmg160_acpi_match),
-		.pm	= &bmg160_pm_ops,
-	},
-	.probe		= bmg160_probe,
-	.remove		= bmg160_remove,
-	.id_table	= bmg160_id,
-};
-module_i2c_driver(bmg160_driver);
+EXPORT_SYMBOL_GPL(bmg160_pm_ops);
 
 
 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");

+ 71 - 0
drivers/iio/gyro/bmg160_i2c.c

@@ -0,0 +1,71 @@
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+
+#include "bmg160.h"
+
+static const struct regmap_config bmg160_regmap_i2c_conf = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x3f
+};
+
+static int bmg160_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+	const char *name = NULL;
+
+	regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "Failed to register i2c regmap %d\n",
+			(int)PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	if (id)
+		name = id->name;
+
+	return bmg160_core_probe(&client->dev, regmap, client->irq, name);
+}
+
+static int bmg160_i2c_remove(struct i2c_client *client)
+{
+	bmg160_core_remove(&client->dev);
+
+	return 0;
+}
+
+static const struct acpi_device_id bmg160_acpi_match[] = {
+	{"BMG0160", 0},
+	{"BMI055B", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
+
+static const struct i2c_device_id bmg160_i2c_id[] = {
+	{"bmg160", 0},
+	{"bmi055_gyro", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
+
+static struct i2c_driver bmg160_i2c_driver = {
+	.driver = {
+		.name	= "bmg160_i2c",
+		.acpi_match_table = ACPI_PTR(bmg160_acpi_match),
+		.pm	= &bmg160_pm_ops,
+	},
+	.probe		= bmg160_i2c_probe,
+	.remove		= bmg160_i2c_remove,
+	.id_table	= bmg160_i2c_id,
+};
+module_i2c_driver(bmg160_i2c_driver);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMG160 I2C Gyro driver");

+ 57 - 0
drivers/iio/gyro/bmg160_spi.c

@@ -0,0 +1,57 @@
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+
+#include "bmg160.h"
+
+static const struct regmap_config bmg160_regmap_spi_conf = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0x3f,
+};
+
+static int bmg160_spi_probe(struct spi_device *spi)
+{
+	struct regmap *regmap;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+
+	regmap = devm_regmap_init_spi(spi, &bmg160_regmap_spi_conf);
+	if (IS_ERR(regmap)) {
+		dev_err(&spi->dev, "Failed to register spi regmap %d\n",
+			(int)PTR_ERR(regmap));
+		return PTR_ERR(regmap);
+	}
+
+	return bmg160_core_probe(&spi->dev, regmap, spi->irq, id->name);
+}
+
+static int bmg160_spi_remove(struct spi_device *spi)
+{
+	bmg160_core_remove(&spi->dev);
+
+	return 0;
+}
+
+static const struct spi_device_id bmg160_spi_id[] = {
+	{"bmg160", 0},
+	{"bmi055_gyro", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(spi, bmg160_spi_id);
+
+static struct spi_driver bmg160_spi_driver = {
+	.driver = {
+		.name	= "bmg160_spi",
+		.pm	= &bmg160_pm_ops,
+	},
+	.probe		= bmg160_spi_probe,
+	.remove		= bmg160_spi_remove,
+	.id_table	= bmg160_spi_id,
+};
+module_spi_driver(bmg160_spi_driver);
+
+MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMG160 SPI Gyro driver");

+ 1 - 0
drivers/iio/gyro/st_gyro_core.c

@@ -383,6 +383,7 @@ static const struct iio_info gyro_info = {
 	.attrs = &st_gyro_attribute_group,
 	.attrs = &st_gyro_attribute_group,
 	.read_raw = &st_gyro_read_raw,
 	.read_raw = &st_gyro_read_raw,
 	.write_raw = &st_gyro_write_raw,
 	.write_raw = &st_gyro_write_raw,
+	.debugfs_reg_access = &st_sensors_debugfs_reg_access,
 };
 };
 
 
 #ifdef CONFIG_IIO_TRIGGER
 #ifdef CONFIG_IIO_TRIGGER

+ 10 - 0
drivers/iio/humidity/Kconfig

@@ -12,6 +12,16 @@ config DHT11
 	  Other sensors should work as well as long as they speak the
 	  Other sensors should work as well as long as they speak the
 	  same protocol.
 	  same protocol.
 
 
+config HDC100X
+	tristate "TI HDC100x relative humidity and temperature sensor"
+	depends on I2C
+	help
+	 Say yes here to build support for the TI HDC100x series of
+	 relative humidity and temperature sensors.
+
+	 To compile this driver as a module, choose M here: the module
+	 will be called hdc100x.
+
 config SI7005
 config SI7005
 	tristate "SI7005 relative humidity and temperature sensor"
 	tristate "SI7005 relative humidity and temperature sensor"
 	depends on I2C
 	depends on I2C

+ 1 - 0
drivers/iio/humidity/Makefile

@@ -3,5 +3,6 @@
 #
 #
 
 
 obj-$(CONFIG_DHT11) += dht11.o
 obj-$(CONFIG_DHT11) += dht11.o
+obj-$(CONFIG_HDC100X) += hdc100x.o
 obj-$(CONFIG_SI7005) += si7005.o
 obj-$(CONFIG_SI7005) += si7005.o
 obj-$(CONFIG_SI7020) += si7020.o
 obj-$(CONFIG_SI7020) += si7020.o

+ 319 - 0
drivers/iio/humidity/hdc100x.c

@@ -0,0 +1,319 @@
+/*
+ * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define HDC100X_REG_TEMP			0x00
+#define HDC100X_REG_HUMIDITY			0x01
+
+#define HDC100X_REG_CONFIG			0x02
+#define HDC100X_REG_CONFIG_HEATER_EN		BIT(13)
+
+struct hdc100x_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	u16 config;
+
+	/* integration time of the sensor */
+	int adc_int_us[2];
+};
+
+/* integration time in us */
+static const int hdc100x_int_time[][3] = {
+	{ 6350, 3650, 0 },	/* IIO_TEMP channel*/
+	{ 6500, 3850, 2500 },	/* IIO_HUMIDITYRELATIVE channel */
+};
+
+/* HDC100X_REG_CONFIG shift and mask values */
+static const struct {
+	int shift;
+	int mask;
+} hdc100x_resolution_shift[2] = {
+	{ /* IIO_TEMP channel */
+		.shift = 10,
+		.mask = 1
+	},
+	{ /* IIO_HUMIDITYRELATIVE channel */
+		.shift = 8,
+		.mask = 2,
+	},
+};
+
+static IIO_CONST_ATTR(temp_integration_time_available,
+		"0.00365 0.00635");
+
+static IIO_CONST_ATTR(humidityrelative_integration_time_available,
+		"0.0025 0.00385 0.0065");
+
+static IIO_CONST_ATTR(out_current_heater_raw_available,
+		"0 1");
+
+static struct attribute *hdc100x_attributes[] = {
+	&iio_const_attr_temp_integration_time_available.dev_attr.attr,
+	&iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr,
+	&iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group hdc100x_attribute_group = {
+	.attrs = hdc100x_attributes,
+};
+
+static const struct iio_chan_spec hdc100x_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.address = HDC100X_REG_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME) |
+			BIT(IIO_CHAN_INFO_OFFSET),
+	},
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.address = HDC100X_REG_HUMIDITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME)
+	},
+	{
+		.type = IIO_CURRENT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.extend_name = "heater",
+		.output = 1,
+	},
+};
+
+static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val)
+{
+	int tmp = (~mask & data->config) | val;
+	int ret;
+
+	ret = i2c_smbus_write_word_swapped(data->client,
+						HDC100X_REG_CONFIG, tmp);
+	if (!ret)
+		data->config = tmp;
+
+	return ret;
+}
+
+static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2)
+{
+	int shift = hdc100x_resolution_shift[chan].shift;
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) {
+		if (val2 && val2 == hdc100x_int_time[chan][i]) {
+			ret = hdc100x_update_config(data,
+				hdc100x_resolution_shift[chan].mask << shift,
+				i << shift);
+			if (!ret)
+				data->adc_int_us[chan] = val2;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int hdc100x_get_measurement(struct hdc100x_data *data,
+				   struct iio_chan_spec const *chan)
+{
+	struct i2c_client *client = data->client;
+	int delay = data->adc_int_us[chan->address];
+	int ret;
+	int val;
+
+	/* start measurement */
+	ret = i2c_smbus_write_byte(client, chan->address);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot start measurement");
+		return ret;
+	}
+
+	/* wait for integration time to pass */
+	usleep_range(delay, delay + 1000);
+
+	/*
+	 * i2c_smbus_read_word_data cannot() be used here due to the command
+	 * value not being understood and causes NAKs preventing any reading
+	 * from being accessed.
+	 */
+	ret = i2c_smbus_read_byte(client);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot read high byte measurement");
+		return ret;
+	}
+	val = ret << 6;
+
+	ret = i2c_smbus_read_byte(client);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot read low byte measurement");
+		return ret;
+	}
+	val |= ret >> 2;
+
+	return val;
+}
+
+static int hdc100x_get_heater_status(struct hdc100x_data *data)
+{
+	return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN);
+}
+
+static int hdc100x_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW: {
+		int ret;
+
+		mutex_lock(&data->lock);
+		if (chan->type == IIO_CURRENT) {
+			*val = hdc100x_get_heater_status(data);
+			ret = IIO_VAL_INT;
+		} else {
+			ret = hdc100x_get_measurement(data, chan);
+			if (ret >= 0) {
+				*val = ret;
+				ret = IIO_VAL_INT;
+			}
+		}
+		mutex_unlock(&data->lock);
+		return ret;
+	}
+	case IIO_CHAN_INFO_INT_TIME:
+		*val = 0;
+		*val2 = data->adc_int_us[chan->address];
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_TEMP) {
+			*val = 165;
+			*val2 = 65536 >> 2;
+			return IIO_VAL_FRACTIONAL;
+		} else {
+			*val = 0;
+			*val2 = 10000;
+			return IIO_VAL_INT_PLUS_MICRO;
+		}
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = -40;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hdc100x_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct hdc100x_data *data = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		if (val != 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = hdc100x_set_it_time(data, chan->address, val2);
+		mutex_unlock(&data->lock);
+		return ret;
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type != IIO_CURRENT || val2 != 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
+					val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
+		mutex_unlock(&data->lock);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info hdc100x_info = {
+	.read_raw = hdc100x_read_raw,
+	.write_raw = hdc100x_write_raw,
+	.attrs = &hdc100x_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static int hdc100x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct iio_dev *indio_dev;
+	struct hdc100x_data *data;
+
+	if (!i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
+		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;
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &hdc100x_info;
+
+	indio_dev->channels = hdc100x_channels;
+	indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels);
+
+	/* be sure we are in a known state */
+	hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]);
+	hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
+
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id hdc100x_id[] = {
+	{ "hdc100x", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, hdc100x_id);
+
+static struct i2c_driver hdc100x_driver = {
+	.driver = {
+		.name	= "hdc100x",
+	},
+	.probe = hdc100x_probe,
+	.id_table = hdc100x_id,
+};
+module_i2c_driver(hdc100x_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");

+ 5 - 1
drivers/iio/humidity/si7020.c

@@ -57,8 +57,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
 		*val = ret >> 2;
 		*val = ret >> 2;
+		/*
+		 * Humidity values can slightly exceed the 0-100%RH
+		 * range and should be corrected by software
+		 */
 		if (chan->type == IIO_HUMIDITYRELATIVE)
 		if (chan->type == IIO_HUMIDITYRELATIVE)
-			*val &= GENMASK(11, 0);
+			*val = clamp_val(*val, 786, 13893);
 		return IIO_VAL_INT;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_SCALE:
 	case IIO_CHAN_INFO_SCALE:
 		if (chan->type == IIO_TEMP)
 		if (chan->type == IIO_TEMP)

+ 8 - 2
drivers/iio/industrialio-core.c

@@ -75,6 +75,8 @@ static const char * const iio_chan_type_name_spec[] = {
 	[IIO_ENERGY] = "energy",
 	[IIO_ENERGY] = "energy",
 	[IIO_DISTANCE] = "distance",
 	[IIO_DISTANCE] = "distance",
 	[IIO_VELOCITY] = "velocity",
 	[IIO_VELOCITY] = "velocity",
+	[IIO_CONCENTRATION] = "concentration",
+	[IIO_RESISTANCE] = "resistance",
 };
 };
 
 
 static const char * const iio_modifier_names[] = {
 static const char * const iio_modifier_names[] = {
@@ -111,6 +113,8 @@ static const char * const iio_modifier_names[] = {
 	[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
 	[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
 	[IIO_MOD_I] = "i",
 	[IIO_MOD_I] = "i",
 	[IIO_MOD_Q] = "q",
 	[IIO_MOD_Q] = "q",
+	[IIO_MOD_CO2] = "co2",
+	[IIO_MOD_VOC] = "voc",
 };
 };
 
 
 /* relies on pairs of these shared then separate */
 /* relies on pairs of these shared then separate */
@@ -962,7 +966,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
 static void iio_dev_release(struct device *device)
 static void iio_dev_release(struct device *device)
 {
 {
 	struct iio_dev *indio_dev = dev_to_iio_dev(device);
 	struct iio_dev *indio_dev = dev_to_iio_dev(device);
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+	if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
 		iio_device_unregister_trigger_consumer(indio_dev);
 		iio_device_unregister_trigger_consumer(indio_dev);
 	iio_device_unregister_eventset(indio_dev);
 	iio_device_unregister_eventset(indio_dev);
 	iio_device_unregister_sysfs(indio_dev);
 	iio_device_unregister_sysfs(indio_dev);
@@ -1153,6 +1157,8 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
 
 	if (cmd == IIO_GET_EVENT_FD_IOCTL) {
 	if (cmd == IIO_GET_EVENT_FD_IOCTL) {
 		fd = iio_event_getfd(indio_dev);
 		fd = iio_event_getfd(indio_dev);
+		if (fd < 0)
+			return fd;
 		if (copy_to_user(ip, &fd, sizeof(fd)))
 		if (copy_to_user(ip, &fd, sizeof(fd)))
 			return -EFAULT;
 			return -EFAULT;
 		return 0;
 		return 0;
@@ -1241,7 +1247,7 @@ int iio_device_register(struct iio_dev *indio_dev)
 			"Failed to register event set\n");
 			"Failed to register event set\n");
 		goto error_free_sysfs;
 		goto error_free_sysfs;
 	}
 	}
-	if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+	if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
 		iio_device_register_trigger_consumer(indio_dev);
 		iio_device_register_trigger_consumer(indio_dev);
 
 
 	if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
 	if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&

+ 10 - 2
drivers/iio/industrialio-trigger.c

@@ -366,10 +366,18 @@ static ssize_t iio_trigger_write_current(struct device *dev,
 
 
 	indio_dev->trig = trig;
 	indio_dev->trig = trig;
 
 
-	if (oldtrig)
+	if (oldtrig) {
+		if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
+			iio_trigger_detach_poll_func(oldtrig,
+						     indio_dev->pollfunc_event);
 		iio_trigger_put(oldtrig);
 		iio_trigger_put(oldtrig);
-	if (indio_dev->trig)
+	}
+	if (indio_dev->trig) {
 		iio_trigger_get(indio_dev->trig);
 		iio_trigger_get(indio_dev->trig);
+		if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
+			iio_trigger_attach_poll_func(indio_dev->trig,
+						     indio_dev->pollfunc_event);
+	}
 
 
 	return len;
 	return len;
 }
 }

+ 68 - 0
drivers/iio/industrialio-triggered-event.c

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_event.h>
+#include <linux/iio/trigger_consumer.h>
+
+/**
+ * iio_triggered_event_setup() - Setup pollfunc_event for triggered event
+ * @indio_dev:	IIO device structure
+ * @h:		Function which will be used as pollfunc_event top half
+ * @thread:	Function which will be used as pollfunc_event bottom half
+ *
+ * This function combines some common tasks which will normally be performed
+ * when setting up a triggered event. It will allocate the pollfunc_event and
+ * set mode to use it for triggered event.
+ *
+ * Before calling this function the indio_dev structure should already be
+ * completely initialized, but not yet registered. In practice this means that
+ * this function should be called right before iio_device_register().
+ *
+ * To free the resources allocated by this function call
+ * iio_triggered_event_cleanup().
+ */
+int iio_triggered_event_setup(struct iio_dev *indio_dev,
+			      irqreturn_t (*h)(int irq, void *p),
+			      irqreturn_t (*thread)(int irq, void *p))
+{
+	indio_dev->pollfunc_event = iio_alloc_pollfunc(h,
+						       thread,
+						       IRQF_ONESHOT,
+						       indio_dev,
+						       "%s_consumer%d",
+						       indio_dev->name,
+						       indio_dev->id);
+	if (indio_dev->pollfunc_event == NULL)
+		return -ENOMEM;
+
+	/* Flag that events polling is possible */
+	indio_dev->modes |= INDIO_EVENT_TRIGGERED;
+
+	return 0;
+}
+EXPORT_SYMBOL(iio_triggered_event_setup);
+
+/**
+ * iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup()
+ * @indio_dev: IIO device structure
+ */
+void iio_triggered_event_cleanup(struct iio_dev *indio_dev)
+{
+	indio_dev->modes &= ~INDIO_EVENT_TRIGGERED;
+	iio_dealloc_pollfunc(indio_dev->pollfunc_event);
+}
+EXPORT_SYMBOL(iio_triggered_event_cleanup);
+
+MODULE_AUTHOR("Vladimir Barinov");
+MODULE_DESCRIPTION("IIO helper functions for setting up triggered events");
+MODULE_LICENSE("GPL");

+ 23 - 0
drivers/iio/light/Kconfig

@@ -50,6 +50,19 @@ config APDS9300
 	 To compile this driver as a module, choose M here: the
 	 To compile this driver as a module, choose M here: the
 	 module will be called apds9300.
 	 module will be called apds9300.
 
 
+config APDS9960
+	tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor"
+	select REGMAP_I2C
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	depends on I2C
+	help
+	  Say Y here to build I2C interface support for the Avago
+	  APDS9960 gesture/RGB/ALS/proximity sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called apds9960
+
 config BH1750
 config BH1750
 	tristate "ROHM BH1750 ambient light sensor"
 	tristate "ROHM BH1750 ambient light sensor"
 	depends on I2C
 	depends on I2C
@@ -287,6 +300,16 @@ config TSL4531
 	 To compile this driver as a module, choose M here: the
 	 To compile this driver as a module, choose M here: the
 	 module will be called tsl4531.
 	 module will be called tsl4531.
 
 
+config US5182D
+	tristate "UPISEMI light and proximity sensor"
+	depends on I2C
+	help
+	 If you say yes here you get support for the UPISEMI US5182D
+	 ambient light and proximity sensor.
+
+	 This driver can also be built as a module.  If so, the module
+	 will be called us5182d.
+
 config VCNL4000
 config VCNL4000
 	tristate "VCNL4000 combined ALS and proximity sensor"
 	tristate "VCNL4000 combined ALS and proximity sensor"
 	depends on I2C
 	depends on I2C

+ 2 - 0
drivers/iio/light/Makefile

@@ -7,6 +7,7 @@ obj-$(CONFIG_ACPI_ALS)		+= acpi-als.o
 obj-$(CONFIG_ADJD_S311)		+= adjd_s311.o
 obj-$(CONFIG_ADJD_S311)		+= adjd_s311.o
 obj-$(CONFIG_AL3320A)		+= al3320a.o
 obj-$(CONFIG_AL3320A)		+= al3320a.o
 obj-$(CONFIG_APDS9300)		+= apds9300.o
 obj-$(CONFIG_APDS9300)		+= apds9300.o
+obj-$(CONFIG_APDS9960)		+= apds9960.o
 obj-$(CONFIG_BH1750)		+= bh1750.o
 obj-$(CONFIG_BH1750)		+= bh1750.o
 obj-$(CONFIG_CM32181)		+= cm32181.o
 obj-$(CONFIG_CM32181)		+= cm32181.o
 obj-$(CONFIG_CM3232)		+= cm3232.o
 obj-$(CONFIG_CM3232)		+= cm3232.o
@@ -27,4 +28,5 @@ obj-$(CONFIG_STK3310)          += stk3310.o
 obj-$(CONFIG_TCS3414)		+= tcs3414.o
 obj-$(CONFIG_TCS3414)		+= tcs3414.o
 obj-$(CONFIG_TCS3472)		+= tcs3472.o
 obj-$(CONFIG_TCS3472)		+= tcs3472.o
 obj-$(CONFIG_TSL4531)		+= tsl4531.o
 obj-$(CONFIG_TSL4531)		+= tsl4531.o
+obj-$(CONFIG_US5182D)		+= us5182d.o
 obj-$(CONFIG_VCNL4000)		+= vcnl4000.o
 obj-$(CONFIG_VCNL4000)		+= vcnl4000.o

+ 1130 - 0
drivers/iio/light/apds9960.c

@@ -0,0 +1,1130 @@
+/*
+ * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * 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: gesture + proximity calib offsets
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/sysfs.h>
+#include <linux/of_gpio.h>
+
+#define APDS9960_REGMAP_NAME	"apds9960_regmap"
+#define APDS9960_DRV_NAME	"apds9960"
+
+#define APDS9960_REG_RAM_START	0x00
+#define APDS9960_REG_RAM_END	0x7f
+
+#define APDS9960_REG_ENABLE	0x80
+#define APDS9960_REG_ATIME	0x81
+#define APDS9960_REG_WTIME	0x83
+
+#define APDS9960_REG_AILTL	0x84
+#define APDS9960_REG_AILTH	0x85
+#define APDS9960_REG_AIHTL	0x86
+#define APDS9960_REG_AIHTH	0x87
+
+#define APDS9960_REG_PILT	0x89
+#define APDS9960_REG_PIHT	0x8b
+#define APDS9960_REG_PERS	0x8c
+
+#define APDS9960_REG_CONFIG_1	0x8d
+#define APDS9960_REG_PPULSE	0x8e
+
+#define APDS9960_REG_CONTROL	0x8f
+#define APDS9960_REG_CONTROL_AGAIN_MASK		0x03
+#define APDS9960_REG_CONTROL_PGAIN_MASK		0x0c
+#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT	0
+#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT	2
+
+#define APDS9960_REG_CONFIG_2	0x90
+#define APDS9960_REG_CONFIG_2_GGAIN_MASK	0x60
+#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT	5
+
+#define APDS9960_REG_ID		0x92
+
+#define APDS9960_REG_STATUS	0x93
+#define APDS9960_REG_STATUS_PS_INT	BIT(5)
+#define APDS9960_REG_STATUS_ALS_INT	BIT(4)
+#define APDS9960_REG_STATUS_GINT	BIT(2)
+
+#define APDS9960_REG_PDATA	0x9c
+#define APDS9960_REG_POFFSET_UR	0x9d
+#define APDS9960_REG_POFFSET_DL 0x9e
+#define APDS9960_REG_CONFIG_3	0x9f
+
+#define APDS9960_REG_GPENTH	0xa0
+#define APDS9960_REG_GEXTH	0xa1
+
+#define APDS9960_REG_GCONF_1	0xa2
+#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK		0xc0
+#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT	6
+
+#define APDS9960_REG_GCONF_2	0xa3
+#define APDS9960_REG_GOFFSET_U	0xa4
+#define APDS9960_REG_GOFFSET_D	0xa5
+#define APDS9960_REG_GPULSE	0xa6
+#define APDS9960_REG_GOFFSET_L	0xa7
+#define APDS9960_REG_GOFFSET_R	0xa9
+#define APDS9960_REG_GCONF_3	0xaa
+
+#define APDS9960_REG_GCONF_4	0xab
+#define APDS9960_REG_GFLVL	0xae
+#define APDS9960_REG_GSTATUS	0xaf
+
+#define APDS9960_REG_IFORCE	0xe4
+#define APDS9960_REG_PICLEAR	0xe5
+#define APDS9960_REG_CICLEAR	0xe6
+#define APDS9960_REG_AICLEAR	0xe7
+
+#define APDS9960_DEFAULT_PERS	0x33
+#define APDS9960_DEFAULT_GPENTH	0x50
+#define APDS9960_DEFAULT_GEXTH	0x40
+
+#define APDS9960_MAX_PXS_THRES_VAL	255
+#define APDS9960_MAX_ALS_THRES_VAL	0xffff
+#define APDS9960_MAX_INT_TIME_IN_US	1000000
+
+enum apds9960_als_channel_idx {
+	IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE,
+};
+
+#define APDS9960_REG_ALS_BASE	0x94
+#define APDS9960_REG_ALS_CHANNEL(_colour) \
+	(APDS9960_REG_ALS_BASE + (IDX_ALS_##_colour * 2))
+
+enum apds9960_gesture_channel_idx {
+	IDX_DIR_UP, IDX_DIR_DOWN, IDX_DIR_LEFT, IDX_DIR_RIGHT,
+};
+
+#define APDS9960_REG_GFIFO_BASE	0xfc
+#define APDS9960_REG_GFIFO_DIR(_dir) \
+	(APDS9960_REG_GFIFO_BASE + IDX_DIR_##_dir)
+
+struct apds9960_data {
+	struct i2c_client *client;
+	struct iio_dev *indio_dev;
+	struct mutex lock;
+
+	/* regmap fields */
+	struct regmap *regmap;
+	struct regmap_field *reg_int_als;
+	struct regmap_field *reg_int_ges;
+	struct regmap_field *reg_int_pxs;
+
+	struct regmap_field *reg_enable_als;
+	struct regmap_field *reg_enable_ges;
+	struct regmap_field *reg_enable_pxs;
+
+	/* state */
+	int als_int;
+	int pxs_int;
+	int gesture_mode_running;
+
+	/* gain values */
+	int als_gain;
+	int pxs_gain;
+
+	/* integration time value in us */
+	int als_adc_int_us;
+
+	/* gesture buffer */
+	u8 buffer[4]; /* 4 8-bit channels */
+};
+
+static const struct reg_default apds9960_reg_defaults[] = {
+	/* Default ALS integration time = 2.48ms */
+	{ APDS9960_REG_ATIME, 0xff },
+};
+
+static const struct regmap_range apds9960_volatile_ranges[] = {
+	regmap_reg_range(APDS9960_REG_STATUS,
+				APDS9960_REG_PDATA),
+	regmap_reg_range(APDS9960_REG_GFLVL,
+				APDS9960_REG_GSTATUS),
+	regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
+				APDS9960_REG_GFIFO_DIR(RIGHT)),
+	regmap_reg_range(APDS9960_REG_IFORCE,
+				APDS9960_REG_AICLEAR),
+};
+
+static const struct regmap_access_table apds9960_volatile_table = {
+	.yes_ranges	= apds9960_volatile_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(apds9960_volatile_ranges),
+};
+
+static const struct regmap_range apds9960_precious_ranges[] = {
+	regmap_reg_range(APDS9960_REG_RAM_START, APDS9960_REG_RAM_END),
+};
+
+static const struct regmap_access_table apds9960_precious_table = {
+	.yes_ranges	= apds9960_precious_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(apds9960_precious_ranges),
+};
+
+static const struct regmap_range apds9960_readable_ranges[] = {
+	regmap_reg_range(APDS9960_REG_ENABLE,
+				APDS9960_REG_GSTATUS),
+	regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),
+				APDS9960_REG_GFIFO_DIR(RIGHT)),
+};
+
+static const struct regmap_access_table apds9960_readable_table = {
+	.yes_ranges	= apds9960_readable_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(apds9960_readable_ranges),
+};
+
+static const struct regmap_range apds9960_writeable_ranges[] = {
+	regmap_reg_range(APDS9960_REG_ENABLE, APDS9960_REG_CONFIG_2),
+	regmap_reg_range(APDS9960_REG_POFFSET_UR, APDS9960_REG_GCONF_4),
+	regmap_reg_range(APDS9960_REG_IFORCE, APDS9960_REG_AICLEAR),
+};
+
+static const struct regmap_access_table apds9960_writeable_table = {
+	.yes_ranges	= apds9960_writeable_ranges,
+	.n_yes_ranges	= ARRAY_SIZE(apds9960_writeable_ranges),
+};
+
+static const struct regmap_config apds9960_regmap_config = {
+	.name = APDS9960_REGMAP_NAME,
+	.reg_bits = 8,
+	.val_bits = 8,
+	.use_single_rw = 1,
+
+	.volatile_table = &apds9960_volatile_table,
+	.precious_table = &apds9960_precious_table,
+	.rd_table = &apds9960_readable_table,
+	.wr_table = &apds9960_writeable_table,
+
+	.reg_defaults = apds9960_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(apds9960_reg_defaults),
+	.max_register = APDS9960_REG_GFIFO_DIR(RIGHT),
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static const struct iio_event_spec apds9960_pxs_event_spec[] = {
+	{
+		.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 apds9960_als_event_spec[] = {
+	{
+		.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),
+	},
+};
+
+#define APDS9960_GESTURE_CHANNEL(_dir, _si) { \
+	.type = IIO_PROXIMITY, \
+	.channel = _si + 1, \
+	.scan_index = _si, \
+	.indexed = 1, \
+	.scan_type = { \
+		.sign = 'u', \
+		.realbits = 8, \
+		.storagebits = 8, \
+	}, \
+}
+
+#define APDS9960_INTENSITY_CHANNEL(_colour) { \
+	.type = IIO_INTENSITY, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+			BIT(IIO_CHAN_INFO_INT_TIME), \
+	.channel2 = IIO_MOD_LIGHT_##_colour, \
+	.address = APDS9960_REG_ALS_CHANNEL(_colour), \
+	.modified = 1, \
+	.scan_index = -1, \
+}
+
+static const unsigned long apds9960_scan_masks[] = {0xf, 0};
+
+static const struct iio_chan_spec apds9960_channels[] = {
+	{
+		.type = IIO_PROXIMITY,
+		.address = APDS9960_REG_PDATA,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+		.channel = 0,
+		.indexed = 0,
+		.scan_index = -1,
+
+		.event_spec = apds9960_pxs_event_spec,
+		.num_event_specs = ARRAY_SIZE(apds9960_pxs_event_spec),
+	},
+	/* Gesture Sensor */
+	APDS9960_GESTURE_CHANNEL(UP, 0),
+	APDS9960_GESTURE_CHANNEL(DOWN, 1),
+	APDS9960_GESTURE_CHANNEL(LEFT, 2),
+	APDS9960_GESTURE_CHANNEL(RIGHT, 3),
+	/* ALS */
+	{
+		.type = IIO_INTENSITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME),
+		.channel2 = IIO_MOD_LIGHT_CLEAR,
+		.address = APDS9960_REG_ALS_CHANNEL(CLEAR),
+		.modified = 1,
+		.scan_index = -1,
+
+		.event_spec = apds9960_als_event_spec,
+		.num_event_specs = ARRAY_SIZE(apds9960_als_event_spec),
+	},
+	/* RGB Sensor */
+	APDS9960_INTENSITY_CHANNEL(RED),
+	APDS9960_INTENSITY_CHANNEL(GREEN),
+	APDS9960_INTENSITY_CHANNEL(BLUE),
+};
+
+/* integration time in us */
+static const int apds9960_int_time[][2] =
+	{ {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} };
+
+/* gain mapping */
+static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};
+static const int apds9960_als_gain_map[] = {1, 4, 16, 64};
+
+static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8");
+static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64");
+static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7");
+
+static struct attribute *apds9960_attributes[] = {
+	&iio_const_attr_proximity_scale_available.dev_attr.attr,
+	&iio_const_attr_intensity_scale_available.dev_attr.attr,
+	&iio_const_attr_integration_time_available.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group apds9960_attribute_group = {
+	.attrs = apds9960_attributes,
+};
+
+static const struct reg_field apds9960_reg_field_int_als =
+				REG_FIELD(APDS9960_REG_ENABLE, 4, 4);
+
+static const struct reg_field apds9960_reg_field_int_ges =
+				REG_FIELD(APDS9960_REG_GCONF_4, 1, 1);
+
+static const struct reg_field apds9960_reg_field_int_pxs =
+				REG_FIELD(APDS9960_REG_ENABLE, 5, 5);
+
+static const struct reg_field apds9960_reg_field_enable_als =
+				REG_FIELD(APDS9960_REG_ENABLE, 1, 1);
+
+static const struct reg_field apds9960_reg_field_enable_ges =
+				REG_FIELD(APDS9960_REG_ENABLE, 6, 6);
+
+static const struct reg_field apds9960_reg_field_enable_pxs =
+				REG_FIELD(APDS9960_REG_ENABLE, 2, 2);
+
+static int apds9960_set_it_time(struct apds9960_data *data, int val2)
+{
+	int ret = -EINVAL;
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) {
+		if (apds9960_int_time[idx][0] == val2) {
+			mutex_lock(&data->lock);
+			ret = regmap_write(data->regmap, APDS9960_REG_ATIME,
+						 apds9960_int_time[idx][1]);
+			if (!ret)
+				data->als_adc_int_us = val2;
+			mutex_unlock(&data->lock);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)
+{
+	int ret = -EINVAL;
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) {
+		if (apds9960_pxs_gain_map[idx] == val) {
+			/* pxs + gesture gains are mirrored */
+			mutex_lock(&data->lock);
+			ret = regmap_update_bits(data->regmap,
+				APDS9960_REG_CONTROL,
+				APDS9960_REG_CONTROL_PGAIN_MASK,
+				idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT);
+			if (ret) {
+				mutex_unlock(&data->lock);
+				break;
+			}
+
+			ret = regmap_update_bits(data->regmap,
+				APDS9960_REG_CONFIG_2,
+				APDS9960_REG_CONFIG_2_GGAIN_MASK,
+				idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT);
+			if (!ret)
+				data->pxs_gain = idx;
+			mutex_unlock(&data->lock);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int apds9960_set_als_gain(struct apds9960_data *data, int val)
+{
+	int ret = -EINVAL;
+	int idx;
+
+	for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) {
+		if (apds9960_als_gain_map[idx] == val) {
+			mutex_lock(&data->lock);
+			ret = regmap_update_bits(data->regmap,
+					APDS9960_REG_CONTROL,
+					APDS9960_REG_CONTROL_AGAIN_MASK, idx);
+			if (!ret)
+				data->als_gain = idx;
+			mutex_unlock(&data->lock);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int apds9960_set_power_state(struct apds9960_data *data, bool on)
+{
+	struct device *dev = &data->client->dev;
+	int ret = 0;
+
+	mutex_lock(&data->lock);
+
+	if (on) {
+		int suspended;
+
+		suspended = pm_runtime_suspended(dev);
+		ret = pm_runtime_get_sync(dev);
+
+		/* Allow one integration cycle before allowing a reading */
+		if (suspended)
+			usleep_range(data->als_adc_int_us,
+				     APDS9960_MAX_INT_TIME_IN_US);
+	} else {
+		ret = pm_runtime_put_autosuspend(dev);
+	}
+
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+#else
+static int apds9960_set_power_state(struct apds9960_data *data, bool on)
+{
+	return 0;
+}
+#endif
+
+static int apds9960_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct apds9960_data *data = iio_priv(indio_dev);
+	u16 buf;
+	int ret = -EINVAL;
+
+	if (data->gesture_mode_running)
+		return -EBUSY;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		apds9960_set_power_state(data, true);
+		switch (chan->type) {
+		case IIO_PROXIMITY:
+			ret = regmap_read(data->regmap, chan->address, val);
+			if (!ret)
+				ret = IIO_VAL_INT;
+			break;
+		case IIO_INTENSITY:
+			ret = regmap_bulk_read(data->regmap, chan->address,
+					       &buf, 2);
+			if (!ret)
+				ret = IIO_VAL_INT;
+			*val = le16_to_cpu(buf);
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		apds9960_set_power_state(data, false);
+		break;
+	case IIO_CHAN_INFO_INT_TIME:
+		/* RGB + ALS sensors only have integration time */
+		mutex_lock(&data->lock);
+		switch (chan->type) {
+		case IIO_INTENSITY:
+			*val = 0;
+			*val2 = data->als_adc_int_us;
+			ret = IIO_VAL_INT_PLUS_MICRO;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		mutex_unlock(&data->lock);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		mutex_lock(&data->lock);
+		switch (chan->type) {
+		case IIO_PROXIMITY:
+			*val = apds9960_pxs_gain_map[data->pxs_gain];
+			ret = IIO_VAL_INT;
+			break;
+		case IIO_INTENSITY:
+			*val = apds9960_als_gain_map[data->als_gain];
+			ret = IIO_VAL_INT;
+			break;
+		default:
+			ret = -EINVAL;
+		}
+		mutex_unlock(&data->lock);
+		break;
+	}
+
+	return ret;
+};
+
+static int apds9960_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	struct apds9960_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		/* RGB + ALS sensors only have int time */
+		switch (chan->type) {
+		case IIO_INTENSITY:
+			if (val != 0)
+				return -EINVAL;
+			return apds9960_set_it_time(data, val2);
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		if (val2 != 0)
+			return -EINVAL;
+		switch (chan->type) {
+		case IIO_PROXIMITY:
+			return apds9960_set_pxs_gain(data, val);
+		case IIO_INTENSITY:
+			return apds9960_set_als_gain(data, val);
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan,
+					 enum iio_event_direction dir,
+					 u8 *reg)
+{
+	switch (dir) {
+	case IIO_EV_DIR_RISING:
+		switch (chan->type) {
+		case IIO_PROXIMITY:
+			*reg = APDS9960_REG_PIHT;
+			break;
+		case IIO_INTENSITY:
+			*reg = APDS9960_REG_AIHTL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	case IIO_EV_DIR_FALLING:
+		switch (chan->type) {
+		case IIO_PROXIMITY:
+			*reg = APDS9960_REG_PILT;
+			break;
+		case IIO_INTENSITY:
+			*reg = APDS9960_REG_AILTL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int apds9960_read_event(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)
+{
+	u8 reg;
+	u16 buf;
+	int ret = 0;
+	struct apds9960_data *data = iio_priv(indio_dev);
+
+	if (info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	ret = apds9960_get_thres_reg(chan, dir, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (chan->type == IIO_PROXIMITY) {
+		ret = regmap_read(data->regmap, reg, val);
+		if (ret < 0)
+			return ret;
+	} else if (chan->type == IIO_INTENSITY) {
+		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+		if (ret < 0)
+			return ret;
+		*val = le16_to_cpu(buf);
+	} else
+		return -EINVAL;
+
+	*val2 = 0;
+
+	return IIO_VAL_INT;
+}
+
+static int apds9960_write_event(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)
+{
+	u8 reg;
+	u16 buf;
+	int ret = 0;
+	struct apds9960_data *data = iio_priv(indio_dev);
+
+	if (info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	ret = apds9960_get_thres_reg(chan, dir, &reg);
+	if (ret < 0)
+		return ret;
+
+	if (chan->type == IIO_PROXIMITY) {
+		if (val < 0 || val > APDS9960_MAX_PXS_THRES_VAL)
+			return -EINVAL;
+		ret = regmap_write(data->regmap, reg, val);
+		if (ret < 0)
+			return ret;
+	} else if (chan->type == IIO_INTENSITY) {
+		if (val < 0 || val > APDS9960_MAX_ALS_THRES_VAL)
+			return -EINVAL;
+		buf = cpu_to_le16(val);
+		ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
+		if (ret < 0)
+			return ret;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int apds9960_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 apds9960_data *data = iio_priv(indio_dev);
+
+	switch (chan->type) {
+	case IIO_PROXIMITY:
+		return data->pxs_int;
+	case IIO_INTENSITY:
+		return data->als_int;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int apds9960_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 apds9960_data *data = iio_priv(indio_dev);
+	int ret;
+
+	state = !!state;
+
+	switch (chan->type) {
+	case IIO_PROXIMITY:
+		if (data->pxs_int == state)
+			return -EINVAL;
+
+		ret = regmap_field_write(data->reg_int_pxs, state);
+		if (ret)
+			return ret;
+		data->pxs_int = state;
+		apds9960_set_power_state(data, state);
+		break;
+	case IIO_INTENSITY:
+		if (data->als_int == state)
+			return -EINVAL;
+
+		ret = regmap_field_write(data->reg_int_als, state);
+		if (ret)
+			return ret;
+		data->als_int = state;
+		apds9960_set_power_state(data, state);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct iio_info apds9960_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &apds9960_attribute_group,
+	.read_raw = apds9960_read_raw,
+	.write_raw = apds9960_write_raw,
+	.read_event_value = apds9960_read_event,
+	.write_event_value = apds9960_write_event,
+	.read_event_config = apds9960_read_event_config,
+	.write_event_config = apds9960_write_event_config,
+
+};
+
+static inline int apds9660_fifo_is_empty(struct apds9960_data *data)
+{
+	int cnt;
+	int ret;
+
+	ret = regmap_read(data->regmap, APDS9960_REG_GFLVL, &cnt);
+	if (ret)
+		return ret;
+
+	return cnt;
+}
+
+static void apds9960_read_gesture_fifo(struct apds9960_data *data)
+{
+	int ret, cnt = 0;
+
+	mutex_lock(&data->lock);
+	data->gesture_mode_running = 1;
+
+	while (cnt-- || (cnt = apds9660_fifo_is_empty(data) > 0)) {
+		ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE,
+				      &data->buffer, 4);
+
+		if (ret)
+			goto err_read;
+
+		iio_push_to_buffers(data->indio_dev, data->buffer);
+	}
+
+err_read:
+	data->gesture_mode_running = 0;
+	mutex_unlock(&data->lock);
+}
+
+static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct apds9960_data *data = iio_priv(indio_dev);
+	int ret, status;
+
+	ret = regmap_read(data->regmap, APDS9960_REG_STATUS, &status);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "irq status reg read failed\n");
+		return IRQ_HANDLED;
+	}
+
+	if ((status & APDS9960_REG_STATUS_ALS_INT) && data->als_int) {
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_EITHER),
+			       iio_get_time_ns());
+		regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);
+	}
+
+	if ((status & APDS9960_REG_STATUS_PS_INT) && data->pxs_int) {
+		iio_push_event(indio_dev,
+			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_EITHER),
+			       iio_get_time_ns());
+		regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);
+	}
+
+	if (status & APDS9960_REG_STATUS_GINT)
+		apds9960_read_gesture_fifo(data);
+
+	return IRQ_HANDLED;
+}
+
+static int apds9960_set_powermode(struct apds9960_data *data, bool state)
+{
+	return regmap_update_bits(data->regmap, APDS9960_REG_ENABLE, 1, state);
+}
+
+static int apds9960_buffer_postenable(struct iio_dev *indio_dev)
+{
+	struct apds9960_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_field_write(data->reg_int_ges, 1);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(data->reg_enable_ges, 1);
+	if (ret)
+		return ret;
+
+	pm_runtime_get_sync(&data->client->dev);
+
+	return 0;
+}
+
+static int apds9960_buffer_predisable(struct iio_dev *indio_dev)
+{
+	struct apds9960_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_field_write(data->reg_enable_ges, 0);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(data->reg_int_ges, 0);
+	if (ret)
+		return ret;
+
+	pm_runtime_put_autosuspend(&data->client->dev);
+
+	return 0;
+}
+
+static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops = {
+	.postenable = apds9960_buffer_postenable,
+	.predisable = apds9960_buffer_predisable,
+};
+
+static int apds9960_regfield_init(struct apds9960_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct regmap *regmap = data->regmap;
+
+	data->reg_int_als = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_int_als);
+	if (IS_ERR(data->reg_int_als)) {
+		dev_err(dev, "INT ALS reg field init failed\n");
+		return PTR_ERR(data->reg_int_als);
+	}
+
+	data->reg_int_ges = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_int_ges);
+	if (IS_ERR(data->reg_int_ges)) {
+		dev_err(dev, "INT gesture reg field init failed\n");
+		return PTR_ERR(data->reg_int_ges);
+	}
+
+	data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_int_pxs);
+	if (IS_ERR(data->reg_int_pxs)) {
+		dev_err(dev, "INT pxs reg field init failed\n");
+		return PTR_ERR(data->reg_int_pxs);
+	}
+
+	data->reg_enable_als = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_enable_als);
+	if (IS_ERR(data->reg_enable_als)) {
+		dev_err(dev, "Enable ALS reg field init failed\n");
+		return PTR_ERR(data->reg_enable_als);
+	}
+
+	data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_enable_ges);
+	if (IS_ERR(data->reg_enable_ges)) {
+		dev_err(dev, "Enable gesture reg field init failed\n");
+		return PTR_ERR(data->reg_enable_ges);
+	}
+
+	data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap,
+						apds9960_reg_field_enable_pxs);
+	if (IS_ERR(data->reg_enable_pxs)) {
+		dev_err(dev, "Enable PXS reg field init failed\n");
+		return PTR_ERR(data->reg_enable_pxs);
+	}
+
+	return 0;
+}
+
+static int apds9960_chip_init(struct apds9960_data *data)
+{
+	int ret;
+
+	/* Default IT for ALS of 28 ms */
+	ret = apds9960_set_it_time(data, 28000);
+	if (ret)
+		return ret;
+
+	/* Ensure gesture interrupt is OFF */
+	ret = regmap_field_write(data->reg_int_ges, 0);
+	if (ret)
+		return ret;
+
+	/* Disable gesture sensor, since polling is useless from user-space */
+	ret = regmap_field_write(data->reg_enable_ges, 0);
+	if (ret)
+		return ret;
+
+	/* Ensure proximity interrupt is OFF */
+	ret = regmap_field_write(data->reg_int_pxs, 0);
+	if (ret)
+		return ret;
+
+	/* Enable proximity sensor for polling */
+	ret = regmap_field_write(data->reg_enable_pxs, 1);
+	if (ret)
+		return ret;
+
+	/* Ensure ALS interrupt is OFF */
+	ret = regmap_field_write(data->reg_int_als, 0);
+	if (ret)
+		return ret;
+
+	/* Enable ALS sensor for polling */
+	ret = regmap_field_write(data->reg_enable_als, 1);
+	if (ret)
+		return ret;
+	/*
+	 * When enabled trigger an interrupt after 3 readings
+	 * outside threshold for ALS + PXS
+	 */
+	ret = regmap_write(data->regmap, APDS9960_REG_PERS,
+			   APDS9960_DEFAULT_PERS);
+	if (ret)
+		return ret;
+
+	/*
+	 * Wait for 4 event outside gesture threshold to prevent interrupt
+	 * flooding.
+	 */
+	ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1,
+			APDS9960_REG_GCONF_1_GFIFO_THRES_MASK,
+			BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT);
+	if (ret)
+		return ret;
+
+	/* Default ENTER and EXIT thresholds for the GESTURE engine. */
+	ret = regmap_write(data->regmap, APDS9960_REG_GPENTH,
+			   APDS9960_DEFAULT_GPENTH);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(data->regmap, APDS9960_REG_GEXTH,
+			   APDS9960_DEFAULT_GEXTH);
+	if (ret)
+		return ret;
+
+	return apds9960_set_powermode(data, 1);
+}
+
+static int apds9960_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct apds9960_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->info = &apds9960_info;
+	indio_dev->name = APDS9960_DRV_NAME;
+	indio_dev->channels = apds9960_channels;
+	indio_dev->num_channels = ARRAY_SIZE(apds9960_channels);
+	indio_dev->available_scan_masks = apds9960_scan_masks;
+	indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
+	indio_dev->setup_ops = &apds9960_buffer_setup_ops;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+
+	data->regmap = devm_regmap_init_i2c(client, &apds9960_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		dev_err(&client->dev, "regmap initialization failed.\n");
+		return PTR_ERR(data->regmap);
+	}
+
+	data->client = client;
+	data->indio_dev = indio_dev;
+	mutex_init(&data->lock);
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret)
+		goto error_power_down;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev, 5000);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	apds9960_set_power_state(data, true);
+
+	ret = apds9960_regfield_init(data);
+	if (ret)
+		goto error_power_down;
+
+	ret = apds9960_chip_init(data);
+	if (ret)
+		goto error_power_down;
+
+	if (client->irq <= 0) {
+		dev_err(&client->dev, "no valid irq defined\n");
+		ret = -EINVAL;
+		goto error_power_down;
+	}
+	ret = devm_request_threaded_irq(&client->dev, client->irq,
+					NULL, apds9960_interrupt_handler,
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					"apds9960_event",
+					indio_dev);
+	if (ret) {
+		dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
+		goto error_power_down;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_power_down;
+
+	apds9960_set_power_state(data, false);
+
+	return 0;
+
+error_power_down:
+	apds9960_set_power_state(data, false);
+
+	return ret;
+}
+
+static int apds9960_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct apds9960_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	apds9960_set_powermode(data, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int apds9960_runtime_suspend(struct device *dev)
+{
+	struct apds9960_data *data =
+			iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return apds9960_set_powermode(data, 0);
+}
+
+static int apds9960_runtime_resume(struct device *dev)
+{
+	struct apds9960_data *data =
+			iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return apds9960_set_powermode(data, 1);
+}
+#endif
+
+static const struct dev_pm_ops apds9960_pm_ops = {
+	SET_RUNTIME_PM_OPS(apds9960_runtime_suspend,
+			   apds9960_runtime_resume, NULL)
+};
+
+static const struct i2c_device_id apds9960_id[] = {
+	{ "apds9960", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, apds9960_id);
+
+static struct i2c_driver apds9960_driver = {
+	.driver = {
+		.name	= APDS9960_DRV_NAME,
+		.pm	= &apds9960_pm_ops,
+	},
+	.probe		= apds9960_probe,
+	.remove		= apds9960_remove,
+	.id_table	= apds9960_id,
+};
+module_i2c_driver(apds9960_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
+MODULE_LICENSE("GPL");

+ 0 - 1
drivers/iio/light/opt3001.c

@@ -793,7 +793,6 @@ static struct i2c_driver opt3001_driver = {
 	.driver = {
 	.driver = {
 		.name = "opt3001",
 		.name = "opt3001",
 		.of_match_table = of_match_ptr(opt3001_of_match),
 		.of_match_table = of_match_ptr(opt3001_of_match),
-		.owner = THIS_MODULE,
 	},
 	},
 };
 };
 
 

+ 53 - 22
drivers/iio/light/stk3310.c

@@ -35,8 +35,8 @@
 #define STK3310_REG_ID				0x3E
 #define STK3310_REG_ID				0x3E
 #define STK3310_MAX_REG				0x80
 #define STK3310_MAX_REG				0x80
 
 
-#define STK3310_STATE_EN_PS			0x01
-#define STK3310_STATE_EN_ALS			0x02
+#define STK3310_STATE_EN_PS			BIT(0)
+#define STK3310_STATE_EN_ALS			BIT(1)
 #define STK3310_STATE_STANDBY			0x00
 #define STK3310_STATE_STANDBY			0x00
 
 
 #define STK3310_CHIP_ID_VAL			0x13
 #define STK3310_CHIP_ID_VAL			0x13
@@ -241,8 +241,11 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	struct i2c_client *client = data->client;
 
 
-	regmap_field_read(data->reg_ps_gain, &index);
-	if (val > stk3310_ps_max[index])
+	ret = regmap_field_read(data->reg_ps_gain, &index);
+	if (ret < 0)
+		return ret;
+
+	if (val < 0 || val > stk3310_ps_max[index])
 		return -EINVAL;
 		return -EINVAL;
 
 
 	if (dir == IIO_EV_DIR_RISING)
 	if (dir == IIO_EV_DIR_RISING)
@@ -266,9 +269,12 @@ static int stk3310_read_event_config(struct iio_dev *indio_dev,
 				     enum iio_event_direction dir)
 				     enum iio_event_direction dir)
 {
 {
 	unsigned int event_val;
 	unsigned int event_val;
+	int ret;
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct stk3310_data *data = iio_priv(indio_dev);
 
 
-	regmap_field_read(data->reg_int_ps, &event_val);
+	ret = regmap_field_read(data->reg_int_ps, &event_val);
+	if (ret < 0)
+		return ret;
 
 
 	return event_val;
 	return event_val;
 }
 }
@@ -307,14 +313,16 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	struct i2c_client *client = data->client;
 
 
+	if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
 	switch (mask) {
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
 	case IIO_CHAN_INFO_RAW:
 		if (chan->type == IIO_LIGHT)
 		if (chan->type == IIO_LIGHT)
 			reg = STK3310_REG_ALS_DATA_MSB;
 			reg = STK3310_REG_ALS_DATA_MSB;
-		else if (chan->type == IIO_PROXIMITY)
-			reg = STK3310_REG_PS_DATA_MSB;
 		else
 		else
-			return -EINVAL;
+			reg = STK3310_REG_PS_DATA_MSB;
+
 		mutex_lock(&data->lock);
 		mutex_lock(&data->lock);
 		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
 		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
 		if (ret < 0) {
 		if (ret < 0) {
@@ -327,17 +335,23 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT;
 		return IIO_VAL_INT;
 	case IIO_CHAN_INFO_INT_TIME:
 	case IIO_CHAN_INFO_INT_TIME:
 		if (chan->type == IIO_LIGHT)
 		if (chan->type == IIO_LIGHT)
-			regmap_field_read(data->reg_als_it, &index);
+			ret = regmap_field_read(data->reg_als_it, &index);
 		else
 		else
-			regmap_field_read(data->reg_ps_it, &index);
+			ret = regmap_field_read(data->reg_ps_it, &index);
+		if (ret < 0)
+			return ret;
+
 		*val = stk3310_it_table[index][0];
 		*val = stk3310_it_table[index][0];
 		*val2 = stk3310_it_table[index][1];
 		*val2 = stk3310_it_table[index][1];
 		return IIO_VAL_INT_PLUS_MICRO;
 		return IIO_VAL_INT_PLUS_MICRO;
 	case IIO_CHAN_INFO_SCALE:
 	case IIO_CHAN_INFO_SCALE:
 		if (chan->type == IIO_LIGHT)
 		if (chan->type == IIO_LIGHT)
-			regmap_field_read(data->reg_als_gain, &index);
+			ret = regmap_field_read(data->reg_als_gain, &index);
 		else
 		else
-			regmap_field_read(data->reg_ps_gain, &index);
+			ret = regmap_field_read(data->reg_ps_gain, &index);
+		if (ret < 0)
+			return ret;
+
 		*val = stk3310_scale_table[index][0];
 		*val = stk3310_scale_table[index][0];
 		*val2 = stk3310_scale_table[index][1];
 		*val2 = stk3310_scale_table[index][1];
 		return IIO_VAL_INT_PLUS_MICRO;
 		return IIO_VAL_INT_PLUS_MICRO;
@@ -354,6 +368,9 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
 	int index;
 	int index;
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct stk3310_data *data = iio_priv(indio_dev);
 
 
+	if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
+		return -EINVAL;
+
 	switch (mask) {
 	switch (mask) {
 	case IIO_CHAN_INFO_INT_TIME:
 	case IIO_CHAN_INFO_INT_TIME:
 		index = stk3310_get_index(stk3310_it_table,
 		index = stk3310_get_index(stk3310_it_table,
@@ -368,7 +385,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
 			ret = regmap_field_write(data->reg_ps_it, index);
 			ret = regmap_field_write(data->reg_ps_it, index);
 		if (ret < 0)
 		if (ret < 0)
 			dev_err(&data->client->dev,
 			dev_err(&data->client->dev,
-					"sensor configuration failed\n");
+				"sensor configuration failed\n");
 		mutex_unlock(&data->lock);
 		mutex_unlock(&data->lock);
 		return ret;
 		return ret;
 
 
@@ -385,7 +402,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
 			ret = regmap_field_write(data->reg_ps_gain, index);
 			ret = regmap_field_write(data->reg_ps_gain, index);
 		if (ret < 0)
 		if (ret < 0)
 			dev_err(&data->client->dev,
 			dev_err(&data->client->dev,
-					"sensor configuration failed\n");
+				"sensor configuration failed\n");
 		mutex_unlock(&data->lock);
 		mutex_unlock(&data->lock);
 		return ret;
 		return ret;
 	}
 	}
@@ -419,8 +436,8 @@ static int stk3310_set_state(struct stk3310_data *data, u8 state)
 		dev_err(&client->dev, "failed to change sensor state\n");
 		dev_err(&client->dev, "failed to change sensor state\n");
 	} else if (state != STK3310_STATE_STANDBY) {
 	} else if (state != STK3310_STATE_STANDBY) {
 		/* Don't reset the 'enabled' flags if we're going in standby */
 		/* Don't reset the 'enabled' flags if we're going in standby */
-		data->ps_enabled  = !!(state & 0x01);
-		data->als_enabled = !!(state & 0x02);
+		data->ps_enabled  = !!(state & STK3310_STATE_EN_PS);
+		data->als_enabled = !!(state & STK3310_STATE_EN_ALS);
 	}
 	}
 	mutex_unlock(&data->lock);
 	mutex_unlock(&data->lock);
 
 
@@ -435,7 +452,10 @@ static int stk3310_init(struct iio_dev *indio_dev)
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct stk3310_data *data = iio_priv(indio_dev);
 	struct i2c_client *client = data->client;
 	struct i2c_client *client = data->client;
 
 
-	regmap_read(data->regmap, STK3310_REG_ID, &chipid);
+	ret = regmap_read(data->regmap, STK3310_REG_ID, &chipid);
+	if (ret < 0)
+		return ret;
+
 	if (chipid != STK3310_CHIP_ID_VAL &&
 	if (chipid != STK3310_CHIP_ID_VAL &&
 	    chipid != STK3311_CHIP_ID_VAL) {
 	    chipid != STK3311_CHIP_ID_VAL) {
 		dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
 		dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
@@ -604,8 +624,13 @@ static int stk3310_probe(struct i2c_client *client,
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	if (client->irq < 0)
+	if (client->irq < 0) {
 		client->irq = stk3310_gpio_probe(client);
 		client->irq = stk3310_gpio_probe(client);
+		if (client->irq < 0) {
+			ret = client->irq;
+			goto err_standby;
+		}
+	}
 
 
 	if (client->irq >= 0) {
 	if (client->irq >= 0) {
 		ret = devm_request_threaded_irq(&client->dev, client->irq,
 		ret = devm_request_threaded_irq(&client->dev, client->irq,
@@ -614,17 +639,23 @@ static int stk3310_probe(struct i2c_client *client,
 						IRQF_TRIGGER_FALLING |
 						IRQF_TRIGGER_FALLING |
 						IRQF_ONESHOT,
 						IRQF_ONESHOT,
 						STK3310_EVENT, indio_dev);
 						STK3310_EVENT, indio_dev);
-		if (ret < 0)
+		if (ret < 0) {
 			dev_err(&client->dev, "request irq %d failed\n",
 			dev_err(&client->dev, "request irq %d failed\n",
-					client->irq);
+				client->irq);
+			goto err_standby;
+		}
 	}
 	}
 
 
 	ret = iio_device_register(indio_dev);
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&client->dev, "device_register failed\n");
 		dev_err(&client->dev, "device_register failed\n");
-		stk3310_set_state(data, STK3310_STATE_STANDBY);
+		goto err_standby;
 	}
 	}
 
 
+	return 0;
+
+err_standby:
+	stk3310_set_state(data, STK3310_STATE_STANDBY);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -648,7 +679,7 @@ static int stk3310_suspend(struct device *dev)
 
 
 static int stk3310_resume(struct device *dev)
 static int stk3310_resume(struct device *dev)
 {
 {
-	int state = 0;
+	u8 state = 0;
 	struct stk3310_data *data;
 	struct stk3310_data *data;
 
 
 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));

+ 5 - 4
drivers/iio/light/tsl4531.c

@@ -158,9 +158,9 @@ static int tsl4531_check_id(struct i2c_client *client)
 	case TSL45313_ID:
 	case TSL45313_ID:
 	case TSL45315_ID:
 	case TSL45315_ID:
 	case TSL45317_ID:
 	case TSL45317_ID:
-		return 1;
-	default:
 		return 0;
 		return 0;
+	default:
+		return -ENODEV;
 	}
 	}
 }
 }
 
 
@@ -180,9 +180,10 @@ static int tsl4531_probe(struct i2c_client *client,
 	data->client = client;
 	data->client = client;
 	mutex_init(&data->lock);
 	mutex_init(&data->lock);
 
 
-	if (!tsl4531_check_id(client)) {
+	ret = tsl4531_check_id(client);
+	if (ret) {
 		dev_err(&client->dev, "no TSL4531 sensor\n");
 		dev_err(&client->dev, "no TSL4531 sensor\n");
-		return -ENODEV;
+		return ret;
 	}
 	}
 
 
 	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
 	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,

+ 507 - 0
drivers/iio/light/us5182d.c

@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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.
+ *
+ * To do: Interrupt support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+
+#define US5182D_REG_CFG0				0x00
+#define US5182D_CFG0_ONESHOT_EN				BIT(6)
+#define US5182D_CFG0_SHUTDOWN_EN			BIT(7)
+#define US5182D_CFG0_WORD_ENABLE			BIT(0)
+
+#define US5182D_REG_CFG1				0x01
+#define US5182D_CFG1_ALS_RES16				BIT(4)
+#define US5182D_CFG1_AGAIN_DEFAULT			0x00
+
+#define US5182D_REG_CFG2				0x02
+#define US5182D_CFG2_PX_RES16				BIT(4)
+#define US5182D_CFG2_PXGAIN_DEFAULT			BIT(2)
+
+#define US5182D_REG_CFG3				0x03
+#define US5182D_CFG3_LED_CURRENT100			(BIT(4) | BIT(5))
+
+#define US5182D_REG_CFG4				0x10
+
+/*
+ * Registers for tuning the auto dark current cancelling feature.
+ * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling.
+ * when ALS  > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark
+ * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark
+ */
+#define US5182D_REG_UDARK_TH			0x27
+#define US5182D_REG_DARK_AUTO_EN		0x2b
+#define US5182D_REG_AUTO_LDARK_GAIN		0x29
+#define US5182D_REG_AUTO_HDARK_GAIN		0x2a
+
+#define US5182D_OPMODE_ALS			0x01
+#define US5182D_OPMODE_PX			0x02
+#define US5182D_OPMODE_SHIFT			4
+
+#define US5182D_REG_DARK_AUTO_EN_DEFAULT	0x80
+#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT	0x16
+#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT	0x00
+
+#define US5182D_REG_ADL				0x0c
+#define US5182D_REG_PDL				0x0e
+
+#define US5182D_REG_MODE_STORE			0x21
+#define US5182D_STORE_MODE			0x01
+
+#define US5182D_REG_CHIPID			0xb2
+
+#define US5182D_OPMODE_MASK			GENMASK(5, 4)
+#define US5182D_AGAIN_MASK			0x07
+#define US5182D_RESET_CHIP			0x01
+
+#define US5182D_CHIPID				0x26
+#define US5182D_DRV_NAME			"us5182d"
+
+#define US5182D_GA_RESOLUTION			1000
+
+#define US5182D_READ_BYTE			1
+#define US5182D_READ_WORD			2
+#define US5182D_OPSTORE_SLEEP_TIME		20 /* ms */
+
+/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
+static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
+				     3900, 2100};
+
+/*
+ * Experimental thresholds that work with US5182D sensor on evaluation board
+ * roughly between 12-32 lux
+ */
+static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000,
+				      8000};
+
+enum mode {
+	US5182D_ALS_PX,
+	US5182D_ALS_ONLY,
+	US5182D_PX_ONLY
+};
+
+struct us5182d_data {
+	struct i2c_client *client;
+	struct mutex lock;
+
+	/* Glass attenuation factor */
+	u32 ga;
+
+	/* Dark gain tuning */
+	u8 lower_dark_gain;
+	u8 upper_dark_gain;
+	u16 *us5182d_dark_ths;
+
+	u8 opmode;
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available,
+		      "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");
+
+static struct attribute *us5182d_attrs[] = {
+	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group us5182d_attr_group = {
+	.attrs = us5182d_attrs,
+};
+
+static const struct {
+	u8 reg;
+	u8 val;
+} us5182d_regvals[] = {
+	{US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN |
+			    US5182D_CFG0_WORD_ENABLE)},
+	{US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
+	{US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
+			    US5182D_CFG2_PXGAIN_DEFAULT)},
+	{US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
+	{US5182D_REG_MODE_STORE, US5182D_STORE_MODE},
+	{US5182D_REG_CFG4, 0x00},
+};
+
+static const struct iio_chan_spec us5182d_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+	},
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+	}
+};
+
+static int us5182d_get_als(struct us5182d_data *data)
+{
+	int ret;
+	unsigned long result;
+
+	ret = i2c_smbus_read_word_data(data->client,
+				       US5182D_REG_ADL);
+	if (ret < 0)
+		return ret;
+
+	result = ret * data->ga / US5182D_GA_RESOLUTION;
+	if (result > 0xffff)
+		result = 0xffff;
+
+	return result;
+}
+
+static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * In oneshot mode the chip will power itself down after taking the
+	 * required measurement.
+	 */
+	ret = ret | US5182D_CFG0_ONESHOT_EN;
+
+	/* update mode */
+	ret = ret & ~US5182D_OPMODE_MASK;
+	ret = ret | (mode << US5182D_OPMODE_SHIFT);
+
+	/*
+	 * After updating the operating mode, the chip requires that
+	 * the operation is stored, by writing 1 in the STORE_MODE
+	 * register (auto-clearing).
+	 */
+	ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
+	if (ret < 0)
+		return ret;
+
+	if (mode == data->opmode)
+		return 0;
+
+	ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
+					US5182D_STORE_MODE);
+	if (ret < 0)
+		return ret;
+
+	data->opmode = mode;
+	msleep(US5182D_OPSTORE_SLEEP_TIME);
+
+	return 0;
+}
+
+static int us5182d_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			mutex_lock(&data->lock);
+			ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
+			if (ret < 0)
+				goto out_err;
+
+			ret = us5182d_get_als(data);
+			if (ret < 0)
+				goto out_err;
+			mutex_unlock(&data->lock);
+			*val = ret;
+			return IIO_VAL_INT;
+		case IIO_PROXIMITY:
+			mutex_lock(&data->lock);
+			ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
+			if (ret < 0)
+				goto out_err;
+
+			ret = i2c_smbus_read_word_data(data->client,
+						       US5182D_REG_PDL);
+			if (ret < 0)
+				goto out_err;
+			mutex_unlock(&data->lock);
+			*val = ret;
+			return  IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
+		if (ret < 0)
+			return ret;
+
+		*val = 0;
+		*val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];
+
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+out_err:
+	mutex_unlock(&data->lock);
+	return ret;
+}
+
+/**
+ * us5182d_update_dark_th - update Darh_Th registers
+ * @data	us5182d_data structure
+ * @index	index in us5182d_dark_ths array to use for the updated value
+ *
+ * Function needs to be called with a lock held because it needs two i2c write
+ * byte operations as these registers (0x27 0x28) don't work in word mode
+ * accessing.
+ */
+static int us5182d_update_dark_th(struct us5182d_data *data, int index)
+{
+	__be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]);
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH,
+					((u8 *)&dark_th)[0]);
+	if (ret < 0)
+		return ret;
+
+	return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1,
+					((u8 *)&dark_th)[1]);
+}
+
+/**
+ * us5182d_apply_scale - update the ALS scale
+ * @data	us5182d_data structure
+ * @index	index in us5182d_scales array to use for the updated value
+ *
+ * Function needs to be called with a lock held as we're having more than one
+ * i2c operation.
+ */
+static int us5182d_apply_scale(struct us5182d_data *data, int index)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);
+	if (ret < 0)
+		return ret;
+
+	ret = ret & (~US5182D_AGAIN_MASK);
+	ret |= index;
+
+	ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret);
+	if (ret < 0)
+		return ret;
+
+	return us5182d_update_dark_th(data, index);
+}
+
+static int us5182d_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int val,
+			     int val2, long mask)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+	int ret, i;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (val != 0)
+			return -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++)
+			if (val2 == us5182d_scales[i]) {
+				mutex_lock(&data->lock);
+				ret = us5182d_apply_scale(data, i);
+				mutex_unlock(&data->lock);
+				return ret;
+			}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info us5182d_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw = us5182d_read_raw,
+	.write_raw = us5182d_write_raw,
+	.attrs = &us5182d_attr_group,
+};
+
+static int us5182d_reset(struct iio_dev *indio_dev)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+
+	return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3,
+					 US5182D_RESET_CHIP);
+}
+
+static int us5182d_init(struct iio_dev *indio_dev)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+	int i, ret;
+
+	ret = us5182d_reset(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	data->opmode = 0;
+	for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
+		ret = i2c_smbus_write_byte_data(data->client,
+						us5182d_regvals[i].reg,
+						us5182d_regvals[i].val);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void us5182d_get_platform_data(struct iio_dev *indio_dev)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+
+	if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef",
+				     &data->ga))
+		data->ga = US5182D_GA_RESOLUTION;
+	if (device_property_read_u16_array(&data->client->dev,
+					   "upisemi,dark-ths",
+					   data->us5182d_dark_ths,
+					   ARRAY_SIZE(us5182d_dark_ths_vals)))
+		data->us5182d_dark_ths = us5182d_dark_ths_vals;
+	if (device_property_read_u8(&data->client->dev,
+				    "upisemi,upper-dark-gain",
+				    &data->upper_dark_gain))
+		data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT;
+	if (device_property_read_u8(&data->client->dev,
+				    "upisemi,lower-dark-gain",
+				    &data->lower_dark_gain))
+		data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
+}
+
+static int  us5182d_dark_gain_config(struct iio_dev *indio_dev)
+{
+	struct us5182d_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(data->client,
+					US5182D_REG_AUTO_LDARK_GAIN,
+					data->lower_dark_gain);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_write_byte_data(data->client,
+					US5182D_REG_AUTO_HDARK_GAIN,
+					data->upper_dark_gain);
+	if (ret < 0)
+		return ret;
+
+	return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN,
+					 US5182D_REG_DARK_AUTO_EN_DEFAULT);
+}
+
+static int us5182d_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct us5182d_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	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;
+
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &us5182d_info;
+	indio_dev->name = US5182D_DRV_NAME;
+	indio_dev->channels = us5182d_channels;
+	indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);
+	if (ret != US5182D_CHIPID) {
+		dev_err(&data->client->dev,
+			"Failed to detect US5182 light chip\n");
+		return (ret < 0) ? ret : -ENODEV;
+	}
+
+	us5182d_get_platform_data(indio_dev);
+	ret = us5182d_init(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	ret = us5182d_dark_gain_config(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	return iio_device_register(indio_dev);
+}
+
+static int us5182d_remove(struct i2c_client *client)
+{
+	iio_device_unregister(i2c_get_clientdata(client));
+	return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0,
+					 US5182D_CFG0_SHUTDOWN_EN);
+}
+
+static const struct acpi_device_id us5182d_acpi_match[] = {
+	{ "USD5182", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
+
+static const struct i2c_device_id us5182d_id[] = {
+		{"usd5182", 0},
+		{}
+};
+
+MODULE_DEVICE_TABLE(i2c, us5182d_id);
+
+static struct i2c_driver us5182d_driver = {
+	.driver = {
+		.name = US5182D_DRV_NAME,
+		.acpi_match_table = ACPI_PTR(us5182d_acpi_match),
+	},
+	.probe = us5182d_probe,
+	.remove = us5182d_remove,
+	.id_table = us5182d_id,
+
+};
+module_i2c_driver(us5182d_driver);
+
+MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
+MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
+MODULE_LICENSE("GPL v2");

+ 18 - 15
drivers/iio/magnetometer/Kconfig

@@ -24,6 +24,24 @@ config AK09911
 	help
 	help
 	  Deprecated: AK09911 is now supported by AK8975 driver.
 	  Deprecated: AK09911 is now supported by AK8975 driver.
 
 
+config BMC150_MAGN
+	tristate "Bosch BMC150 Magnetometer Driver"
+	depends on I2C
+	select REGMAP_I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for the BMC150 magnetometer.
+
+	  Currently this only supports the device via an i2c interface.
+
+	  This is a combo module with both accelerometer and magnetometer.
+	  This driver is only implementing magnetometer part, which has
+	  its own address and register map.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called bmc150_magn.
+
 config MAG3110
 config MAG3110
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
 	tristate "Freescale MAG3110 3-Axis Magnetometer"
 	depends on I2C
 	depends on I2C
@@ -87,19 +105,4 @@ config IIO_ST_MAGN_SPI_3AXIS
 	depends on IIO_ST_MAGN_3AXIS
 	depends on IIO_ST_MAGN_3AXIS
 	depends on IIO_ST_SENSORS_SPI
 	depends on IIO_ST_SENSORS_SPI
 
 
-config BMC150_MAGN
-	tristate "Bosch BMC150 Magnetometer Driver"
-	depends on I2C
-	select REGMAP_I2C
-	select IIO_BUFFER
-	select IIO_TRIGGERED_BUFFER
-	help
-	  Say yes here to build support for the BMC150 magnetometer.
-
-	  Currently this only supports the device via an i2c interface.
-
-	  This is a combo module with both accelerometer and magnetometer.
-	  This driver is only implementing magnetometer part, which has
-	  its own address and register map.
-
 endmenu
 endmenu

+ 1 - 2
drivers/iio/magnetometer/Makefile

@@ -4,6 +4,7 @@
 
 
 # When adding new entries keep the list in alphabetical order
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_AK8975)	+= ak8975.o
+obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
 obj-$(CONFIG_MMC35240)	+= mmc35240.o
 obj-$(CONFIG_MMC35240)	+= mmc35240.o
@@ -14,5 +15,3 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
 
 
 obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
 obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
 obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
 obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
-
-obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o

+ 1 - 0
drivers/iio/magnetometer/st_magn_core.c

@@ -560,6 +560,7 @@ static const struct iio_info magn_info = {
 	.attrs = &st_magn_attribute_group,
 	.attrs = &st_magn_attribute_group,
 	.read_raw = &st_magn_read_raw,
 	.read_raw = &st_magn_read_raw,
 	.write_raw = &st_magn_write_raw,
 	.write_raw = &st_magn_write_raw,
+	.debugfs_reg_access = &st_sensors_debugfs_reg_access,
 };
 };
 
 
 #ifdef CONFIG_IIO_TRIGGER
 #ifdef CONFIG_IIO_TRIGGER

+ 1 - 0
drivers/iio/pressure/st_pressure_core.c

@@ -400,6 +400,7 @@ static const struct iio_info press_info = {
 	.attrs = &st_press_attribute_group,
 	.attrs = &st_press_attribute_group,
 	.read_raw = &st_press_read_raw,
 	.read_raw = &st_press_read_raw,
 	.write_raw = &st_press_write_raw,
 	.write_raw = &st_press_write_raw,
+	.debugfs_reg_access = &st_sensors_debugfs_reg_access,
 };
 };
 
 
 #ifdef CONFIG_IIO_TRIGGER
 #ifdef CONFIG_IIO_TRIGGER

+ 12 - 0
drivers/iio/proximity/Kconfig

@@ -20,6 +20,18 @@ endmenu
 
 
 menu "Proximity sensors"
 menu "Proximity sensors"
 
 
+config LIDAR_LITE_V2
+	tristate "PulsedLight LIDAR sensor"
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	depends on I2C
+	help
+	  Say Y to build a driver for PulsedLight LIDAR range finding
+	  sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pulsedlight-lite-v2
+
 config SX9500
 config SX9500
 	tristate "SX9500 Semtech proximity sensor"
 	tristate "SX9500 Semtech proximity sensor"
 	select IIO_BUFFER
 	select IIO_BUFFER

+ 1 - 0
drivers/iio/proximity/Makefile

@@ -4,4 +4,5 @@
 
 
 # When adding new entries keep the list in alphabetical order
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AS3935)		+= as3935.o
 obj-$(CONFIG_AS3935)		+= as3935.o
+obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
 obj-$(CONFIG_SX9500)		+= sx9500.o
 obj-$(CONFIG_SX9500)		+= sx9500.o

+ 7 - 0
drivers/iio/proximity/as3935.c

@@ -434,6 +434,12 @@ static int as3935_remove(struct spi_device *spi)
 	return 0;
 	return 0;
 }
 }
 
 
+static const struct of_device_id as3935_of_match[] = {
+	{ .compatible = "ams,as3935", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, as3935_of_match);
+
 static const struct spi_device_id as3935_id[] = {
 static const struct spi_device_id as3935_id[] = {
 	{"as3935", 0},
 	{"as3935", 0},
 	{},
 	{},
@@ -443,6 +449,7 @@ MODULE_DEVICE_TABLE(spi, as3935_id);
 static struct spi_driver as3935_driver = {
 static struct spi_driver as3935_driver = {
 	.driver = {
 	.driver = {
 		.name	= "as3935",
 		.name	= "as3935",
+		.of_match_table = of_match_ptr(as3935_of_match),
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.pm	= AS3935_PM_OPS,
 		.pm	= AS3935_PM_OPS,
 	},
 	},

+ 288 - 0
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c

@@ -0,0 +1,288 @@
+/*
+ * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor
+ *
+ * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
+ *
+ * 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: runtime pm, interrupt mode, and signal strength reporting
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define LIDAR_REG_CONTROL		0x00
+#define LIDAR_REG_CONTROL_ACQUIRE	BIT(2)
+
+#define LIDAR_REG_STATUS		0x01
+#define LIDAR_REG_STATUS_INVALID	BIT(3)
+#define LIDAR_REG_STATUS_READY		BIT(0)
+
+#define LIDAR_REG_DATA_HBYTE	0x0f
+#define LIDAR_REG_DATA_LBYTE	0x10
+
+#define LIDAR_DRV_NAME "lidar"
+
+struct lidar_data {
+	struct iio_dev *indio_dev;
+	struct i2c_client *client;
+
+	u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
+};
+
+static const struct iio_chan_spec lidar_channels[] = {
+	{
+		.type = IIO_DISTANCE,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 'u',
+			.realbits = 16,
+			.storagebits = 16,
+		},
+	},
+	IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static int lidar_read_byte(struct lidar_data *data, int reg)
+{
+	struct i2c_client *client = data->client;
+	int ret;
+
+	/*
+	 * Device needs a STOP condition between address write, and data read
+	 * so in turn i2c_smbus_read_byte_data cannot be used
+	 */
+
+	ret = i2c_smbus_write_byte(client, reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot write addr value");
+		return ret;
+	}
+
+	ret = i2c_smbus_read_byte(client);
+	if (ret < 0)
+		dev_err(&client->dev, "cannot read data value");
+
+	return ret;
+}
+
+static inline int lidar_write_control(struct lidar_data *data, int val)
+{
+	return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
+}
+
+static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
+{
+	int ret;
+	int val;
+
+	ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
+	if (ret < 0)
+		return ret;
+	val = ret << 8;
+
+	ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
+	if (ret < 0)
+		return ret;
+
+	val |= ret;
+	*reg = val;
+
+	return 0;
+}
+
+static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
+{
+	struct i2c_client *client = data->client;
+	int tries = 10;
+	int ret;
+
+	/* start sample */
+	ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot send start measurement command");
+		return ret;
+	}
+
+	while (tries--) {
+		usleep_range(1000, 2000);
+
+		ret = lidar_read_byte(data, LIDAR_REG_STATUS);
+		if (ret < 0)
+			break;
+
+		/* return 0 since laser is likely pointed out of range */
+		if (ret & LIDAR_REG_STATUS_INVALID) {
+			*reg = 0;
+			ret = 0;
+			break;
+		}
+
+		/* sample ready to read */
+		if (!(ret & LIDAR_REG_STATUS_READY)) {
+			ret = lidar_read_measurement(data, reg);
+			break;
+		}
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int lidar_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  int *val, int *val2, long mask)
+{
+	struct lidar_data *data = iio_priv(indio_dev);
+	int ret = -EINVAL;
+
+	mutex_lock(&indio_dev->mlock);
+
+	if (iio_buffer_enabled(indio_dev) && mask == IIO_CHAN_INFO_RAW) {
+		ret = -EBUSY;
+		goto error_busy;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW: {
+		u16 reg;
+
+		ret = lidar_get_measurement(data, &reg);
+		if (!ret) {
+			*val = reg;
+			ret = IIO_VAL_INT;
+		}
+		break;
+	}
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = 10000;
+		ret = IIO_VAL_INT_PLUS_MICRO;
+		break;
+	}
+
+error_busy:
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static irqreturn_t lidar_trigger_handler(int irq, void *private)
+{
+	struct iio_poll_func *pf = private;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct lidar_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = lidar_get_measurement(data, data->buffer);
+	if (!ret) {
+		iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+						   iio_get_time_ns());
+	} else {
+		dev_err(&data->client->dev, "cannot read LIDAR measurement");
+	}
+
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_info lidar_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = lidar_read_raw,
+};
+
+static int lidar_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	struct lidar_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	indio_dev->info = &lidar_info;
+	indio_dev->name = LIDAR_DRV_NAME;
+	indio_dev->channels = lidar_channels;
+	indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+
+	data->client = client;
+	data->indio_dev = indio_dev;
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 lidar_trigger_handler, NULL);
+	if (ret)
+		return ret;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_unreg_buffer;
+
+	return 0;
+
+error_unreg_buffer:
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return ret;
+}
+
+static int lidar_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id lidar_id[] = {
+	{"lidar-lite-v2", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, lidar_id);
+
+static const struct of_device_id lidar_dt_ids[] = {
+	{ .compatible = "pulsedlight,lidar-lite-v2" },
+	{ }
+};
+
+static struct i2c_driver lidar_driver = {
+	.driver = {
+		.name	= LIDAR_DRV_NAME,
+		.of_match_table	= of_match_ptr(lidar_dt_ids),
+	},
+	.probe		= lidar_probe,
+	.remove		= lidar_remove,
+	.id_table	= lidar_id,
+};
+module_i2c_driver(lidar_driver);
+
+MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
+MODULE_DESCRIPTION("PulsedLight LIDAR sensor");
+MODULE_LICENSE("GPL");

+ 87 - 3
drivers/iio/temperature/mlx90614.c

@@ -3,6 +3,7 @@
  *
  *
  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
  * Copyright (c) 2015 Essensium NV
  * Copyright (c) 2015 Essensium NV
+ * Copyright (c) 2015 Melexis
  *
  *
  * This file is subject to the terms and conditions of version 2 of
  * 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
  * the GNU General Public License.  See the file COPYING in the main
@@ -20,7 +21,6 @@
  * always has a pull-up so we do not need an extra GPIO to drive it high.  If
  * always has a pull-up so we do not need an extra GPIO to drive it high.  If
  * the "wakeup" GPIO is not given, power management will be disabled.
  * the "wakeup" GPIO is not given, power management will be disabled.
  *
  *
- * TODO: filter configuration
  */
  */
 
 
 #include <linux/err.h>
 #include <linux/err.h>
@@ -32,6 +32,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/pm_runtime.h>
 
 
 #include <linux/iio/iio.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
 
 
 #define MLX90614_OP_RAM		0x00
 #define MLX90614_OP_RAM		0x00
 #define MLX90614_OP_EEPROM	0x20
 #define MLX90614_OP_EEPROM	0x20
@@ -79,6 +80,20 @@ struct mlx90614_data {
 	unsigned long ready_timestamp; /* in jiffies */
 	unsigned long ready_timestamp; /* in jiffies */
 };
 };
 
 
+/* Bandwidth values for IIR filtering */
+static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
+static IIO_CONST_ATTR(in_temp_object_filter_low_pass_3db_frequency_available,
+		      "0.15 0.20 0.31 0.77 0.86 1.10 1.53 7.23");
+
+static struct attribute *mlx90614_attributes[] = {
+	&iio_const_attr_in_temp_object_filter_low_pass_3db_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group mlx90614_attr_group = {
+	.attrs = mlx90614_attributes,
+};
+
 /*
 /*
  * Erase an address and write word.
  * Erase an address and write word.
  * The mutex must be locked before calling.
  * The mutex must be locked before calling.
@@ -117,6 +132,42 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command,
 	return ret;
 	return ret;
 }
 }
 
 
+/*
+ * Find the IIR value inside mlx90614_iir_values array and return its position
+ * which is equivalent to the bit value in sensor register
+ */
+static inline s32 mlx90614_iir_search(const struct i2c_client *client,
+				      int value)
+{
+	int i;
+	s32 ret;
+
+	for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) {
+		if (value == mlx90614_iir_values[i])
+			break;
+	}
+
+	if (i == ARRAY_SIZE(mlx90614_iir_values))
+		return -EINVAL;
+
+	/*
+	 * CONFIG register values must not be changed so
+	 * we must read them before we actually write
+	 * changes
+	 */
+	ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
+	if (ret > 0)
+		return ret;
+
+	/* Write changed values */
+	ret = mlx90614_write_word(client, MLX90614_CONFIG,
+			(i << MLX90614_CONFIG_IIR_SHIFT) |
+			(((u16) ((0x7 << MLX90614_CONFIG_FIR_SHIFT) |
+			((u16) ret & (~((u16) MLX90614_CONFIG_FIR_MASK))))) &
+			(~(u16) MLX90614_CONFIG_IIR_MASK)));
+	return ret;
+}
+
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 /*
 /*
  * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since
  * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since
@@ -236,6 +287,21 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
 			*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
 			*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
 		}
 		}
 		return IIO_VAL_INT_PLUS_NANO;
 		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
+							     FIR = 1024 */
+		mlx90614_power_get(data, false);
+		mutex_lock(&data->lock);
+		ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
+		mutex_unlock(&data->lock);
+		mlx90614_power_put(data);
+
+		if (ret < 0)
+			return ret;
+
+		*val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100;
+		*val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) *
+			10000;
+		return IIO_VAL_INT_PLUS_MICRO;
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -262,6 +328,18 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
 		mutex_unlock(&data->lock);
 		mutex_unlock(&data->lock);
 		mlx90614_power_put(data);
 		mlx90614_power_put(data);
 
 
+		return ret;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR Filter setting */
+		if (val < 0 || val2 < 0)
+			return -EINVAL;
+
+		mlx90614_power_get(data, false);
+		mutex_lock(&data->lock);
+		ret = mlx90614_iir_search(data->client,
+					  val * 100 + val2 / 10000);
+		mutex_unlock(&data->lock);
+		mlx90614_power_put(data);
+
 		return ret;
 		return ret;
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
@@ -275,6 +353,8 @@ static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev,
 	switch (mask) {
 	switch (mask) {
 	case IIO_CHAN_INFO_CALIBEMISSIVITY:
 	case IIO_CHAN_INFO_CALIBEMISSIVITY:
 		return IIO_VAL_INT_PLUS_NANO;
 		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+		return IIO_VAL_INT_PLUS_MICRO;
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -294,7 +374,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
 		.modified = 1,
 		.modified = 1,
 		.channel2 = IIO_MOD_TEMP_OBJECT,
 		.channel2 = IIO_MOD_TEMP_OBJECT,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-		    BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+		    BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 		    BIT(IIO_CHAN_INFO_SCALE),
 		    BIT(IIO_CHAN_INFO_SCALE),
 	},
 	},
@@ -305,7 +386,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
 		.channel = 1,
 		.channel = 1,
 		.channel2 = IIO_MOD_TEMP_OBJECT,
 		.channel2 = IIO_MOD_TEMP_OBJECT,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-		    BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+		    BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
+			BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
 		    BIT(IIO_CHAN_INFO_SCALE),
 		    BIT(IIO_CHAN_INFO_SCALE),
 	},
 	},
@@ -315,6 +397,7 @@ static const struct iio_info mlx90614_info = {
 	.read_raw = mlx90614_read_raw,
 	.read_raw = mlx90614_read_raw,
 	.write_raw = mlx90614_write_raw,
 	.write_raw = mlx90614_write_raw,
 	.write_raw_get_fmt = mlx90614_write_raw_get_fmt,
 	.write_raw_get_fmt = mlx90614_write_raw_get_fmt,
+	.attrs = &mlx90614_attr_group,
 	.driver_module = THIS_MODULE,
 	.driver_module = THIS_MODULE,
 };
 };
 
 
@@ -569,5 +652,6 @@ module_i2c_driver(mlx90614_driver);
 
 
 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
 MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
+MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
 MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
 MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 2 - 2
drivers/staging/iio/adc/lpc32xx_adc.c

@@ -137,7 +137,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 	if (!res) {
 		dev_err(&pdev->dev, "failed to get platform I/O memory\n");
 		dev_err(&pdev->dev, "failed to get platform I/O memory\n");
-		return -EBUSY;
+		return -ENXIO;
 	}
 	}
 
 
 	iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
 	iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
@@ -162,7 +162,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
 	irq = platform_get_irq(pdev, 0);
 	irq = platform_get_irq(pdev, 0);
 	if (irq <= 0) {
 	if (irq <= 0) {
 		dev_err(&pdev->dev, "failed getting interrupt resource\n");
 		dev_err(&pdev->dev, "failed getting interrupt resource\n");
-		return -EINVAL;
+		return -ENXIO;
 	}
 	}
 
 
 	retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
 	retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,

+ 25 - 1
drivers/staging/iio/iio_dummy_evgen.c

@@ -24,9 +24,21 @@
 #include "iio_dummy_evgen.h"
 #include "iio_dummy_evgen.h"
 #include <linux/iio/iio.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/sysfs.h>
+#include <linux/irq_work.h>
 
 
 /* Fiddly bit of faking and irq without hardware */
 /* Fiddly bit of faking and irq without hardware */
 #define IIO_EVENTGEN_NO 10
 #define IIO_EVENTGEN_NO 10
+
+/**
+ * struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
+ * @work: irq_work used to run handlers from hardirq context
+ * @irq: fake irq line number to trigger an interrupt
+ */
+struct iio_dummy_handle_irq {
+	struct irq_work work;
+	int irq;
+};
+
 /**
 /**
  * struct iio_dummy_evgen - evgen state
  * struct iio_dummy_evgen - evgen state
  * @chip: irq chip we are faking
  * @chip: irq chip we are faking
@@ -35,6 +47,7 @@
  * @inuse: mask of which irqs are connected
  * @inuse: mask of which irqs are connected
  * @regs: irq regs we are faking
  * @regs: irq regs we are faking
  * @lock: protect the evgen state
  * @lock: protect the evgen state
+ * @handler: helper for a 'hardware-like' interrupt simulation
  */
  */
 struct iio_dummy_eventgen {
 struct iio_dummy_eventgen {
 	struct irq_chip chip;
 	struct irq_chip chip;
@@ -43,6 +56,7 @@ struct iio_dummy_eventgen {
 	bool inuse[IIO_EVENTGEN_NO];
 	bool inuse[IIO_EVENTGEN_NO];
 	struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
 	struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
 	struct mutex lock;
 	struct mutex lock;
+	struct iio_dummy_handle_irq handler;
 };
 };
 
 
 /* We can only ever have one instance of this 'device' */
 /* We can only ever have one instance of this 'device' */
@@ -67,6 +81,14 @@ static void iio_dummy_event_irqunmask(struct irq_data *d)
 	evgen->enabled[d->irq - evgen->base] = true;
 	evgen->enabled[d->irq - evgen->base] = true;
 }
 }
 
 
+static void iio_dummy_work_handler(struct irq_work *work)
+{
+	struct iio_dummy_handle_irq *irq_handler;
+
+	irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
+	handle_simple_irq(irq_handler->irq, irq_to_desc(irq_handler->irq));
+}
+
 static int iio_dummy_evgen_create(void)
 static int iio_dummy_evgen_create(void)
 {
 {
 	int ret, i;
 	int ret, i;
@@ -91,6 +113,7 @@ static int iio_dummy_evgen_create(void)
 				  IRQ_NOREQUEST | IRQ_NOAUTOEN,
 				  IRQ_NOREQUEST | IRQ_NOAUTOEN,
 				  IRQ_NOPROBE);
 				  IRQ_NOPROBE);
 	}
 	}
+	init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
 	mutex_init(&iio_evgen->lock);
 	mutex_init(&iio_evgen->lock);
 	return 0;
 	return 0;
 }
 }
@@ -169,8 +192,9 @@ static ssize_t iio_evgen_poke(struct device *dev,
 	iio_evgen->regs[this_attr->address].reg_id   = this_attr->address;
 	iio_evgen->regs[this_attr->address].reg_id   = this_attr->address;
 	iio_evgen->regs[this_attr->address].reg_data = event;
 	iio_evgen->regs[this_attr->address].reg_data = event;
 
 
+	iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
 	if (iio_evgen->enabled[this_attr->address])
 	if (iio_evgen->enabled[this_attr->address])
-		handle_nested_irq(iio_evgen->base + this_attr->address);
+		irq_work_queue(&iio_evgen->handler.work);
 
 
 	return len;
 	return len;
 }
 }

+ 1 - 0
drivers/staging/iio/iio_simple_dummy.h

@@ -46,6 +46,7 @@ struct iio_dummy_state {
 	int event_irq;
 	int event_irq;
 	int event_val;
 	int event_val;
 	bool event_en;
 	bool event_en;
+	s64 event_timestamp;
 #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
 #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
 };
 };
 
 

+ 14 - 5
drivers/staging/iio/iio_simple_dummy_events.c

@@ -153,6 +153,15 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
 	return 0;
 	return 0;
 }
 }
 
 
+static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct iio_dummy_state *st = iio_priv(indio_dev);
+
+	st->event_timestamp = iio_get_time_ns();
+	return IRQ_HANDLED;
+}
+
 /**
 /**
  * iio_simple_dummy_event_handler() - identify and pass on event
  * iio_simple_dummy_event_handler() - identify and pass on event
  * @irq: irq of event line
  * @irq: irq of event line
@@ -177,7 +186,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
 			       IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
 			       IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
 					      IIO_EV_DIR_RISING,
 					      IIO_EV_DIR_RISING,
 					      IIO_EV_TYPE_THRESH, 0, 0, 0),
 					      IIO_EV_TYPE_THRESH, 0, 0, 0),
-			       iio_get_time_ns());
+			       st->event_timestamp);
 		break;
 		break;
 	case 1:
 	case 1:
 		if (st->activity_running > st->event_val)
 		if (st->activity_running > st->event_val)
@@ -187,7 +196,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
 						      IIO_EV_DIR_RISING,
 						      IIO_EV_DIR_RISING,
 						      IIO_EV_TYPE_THRESH,
 						      IIO_EV_TYPE_THRESH,
 						      0, 0, 0),
 						      0, 0, 0),
-				       iio_get_time_ns());
+				       st->event_timestamp);
 		break;
 		break;
 	case 2:
 	case 2:
 		if (st->activity_walking < st->event_val)
 		if (st->activity_walking < st->event_val)
@@ -197,14 +206,14 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
 						      IIO_EV_DIR_FALLING,
 						      IIO_EV_DIR_FALLING,
 						      IIO_EV_TYPE_THRESH,
 						      IIO_EV_TYPE_THRESH,
 						      0, 0, 0),
 						      0, 0, 0),
-				       iio_get_time_ns());
+				       st->event_timestamp);
 		break;
 		break;
 	case 3:
 	case 3:
 		iio_push_event(indio_dev,
 		iio_push_event(indio_dev,
 			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
 			       IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
 					      IIO_EV_DIR_NONE,
 					      IIO_EV_DIR_NONE,
 					      IIO_EV_TYPE_CHANGE, 0, 0, 0),
 					      IIO_EV_TYPE_CHANGE, 0, 0, 0),
-			       iio_get_time_ns());
+			       st->event_timestamp);
 		break;
 		break;
 	default:
 	default:
 		break;
 		break;
@@ -238,7 +247,7 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
 	st->regs = iio_dummy_evgen_get_regs(st->event_irq);
 	st->regs = iio_dummy_evgen_get_regs(st->event_irq);
 
 
 	ret = request_threaded_irq(st->event_irq,
 	ret = request_threaded_irq(st->event_irq,
-				   NULL,
+				   &iio_simple_dummy_get_timestamp,
 				   &iio_simple_dummy_event_handler,
 				   &iio_simple_dummy_event_handler,
 				   IRQF_ONESHOT,
 				   IRQF_ONESHOT,
 				   "iio_simple_event",
 				   "iio_simple_event",

+ 1 - 1
drivers/staging/iio/magnetometer/hmc5843.h

@@ -48,7 +48,7 @@ struct hmc5843_data {
 };
 };
 
 
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
-			 enum hmc5843_ids id);
+			 enum hmc5843_ids id, const char *name);
 int hmc5843_common_remove(struct device *dev);
 int hmc5843_common_remove(struct device *dev);
 
 
 int hmc5843_common_suspend(struct device *dev);
 int hmc5843_common_suspend(struct device *dev);

+ 2 - 2
drivers/staging/iio/magnetometer/hmc5843_core.c

@@ -577,7 +577,7 @@ int hmc5843_common_resume(struct device *dev)
 EXPORT_SYMBOL(hmc5843_common_resume);
 EXPORT_SYMBOL(hmc5843_common_resume);
 
 
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
 int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
-			 enum hmc5843_ids id)
+			 enum hmc5843_ids id, const char *name)
 {
 {
 	struct hmc5843_data *data;
 	struct hmc5843_data *data;
 	struct iio_dev *indio_dev;
 	struct iio_dev *indio_dev;
@@ -597,7 +597,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
 	mutex_init(&data->lock);
 	mutex_init(&data->lock);
 
 
 	indio_dev->dev.parent = dev;
 	indio_dev->dev.parent = dev;
-	indio_dev->name = dev->driver->name;
+	indio_dev->name = name;
 	indio_dev->info = &hmc5843_info;
 	indio_dev->info = &hmc5843_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = data->variant->channels;
 	indio_dev->channels = data->variant->channels;

+ 1 - 1
drivers/staging/iio/magnetometer/hmc5843_i2c.c

@@ -61,7 +61,7 @@ static int hmc5843_i2c_probe(struct i2c_client *cli,
 {
 {
 	return hmc5843_common_probe(&cli->dev,
 	return hmc5843_common_probe(&cli->dev,
 			devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config),
 			devm_regmap_init_i2c(cli, &hmc5843_i2c_regmap_config),
-			id->driver_data);
+			id->driver_data, id->name);
 }
 }
 
 
 static int hmc5843_i2c_remove(struct i2c_client *client)
 static int hmc5843_i2c_remove(struct i2c_client *client)

+ 3 - 1
drivers/staging/iio/magnetometer/hmc5843_spi.c

@@ -59,6 +59,7 @@ static const struct regmap_config hmc5843_spi_regmap_config = {
 static int hmc5843_spi_probe(struct spi_device *spi)
 static int hmc5843_spi_probe(struct spi_device *spi)
 {
 {
 	int ret;
 	int ret;
+	const struct spi_device_id *id = spi_get_device_id(spi);
 
 
 	spi->mode = SPI_MODE_3;
 	spi->mode = SPI_MODE_3;
 	spi->max_speed_hz = 8000000;
 	spi->max_speed_hz = 8000000;
@@ -69,7 +70,7 @@ static int hmc5843_spi_probe(struct spi_device *spi)
 
 
 	return hmc5843_common_probe(&spi->dev,
 	return hmc5843_common_probe(&spi->dev,
 			devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
 			devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
-			HMC5983_ID);
+			id->driver_data, id->name);
 }
 }
 
 
 static int hmc5843_spi_remove(struct spi_device *spi)
 static int hmc5843_spi_remove(struct spi_device *spi)
@@ -81,6 +82,7 @@ static const struct spi_device_id hmc5843_id[] = {
 	{ "hmc5983", HMC5983_ID },
 	{ "hmc5983", HMC5983_ID },
 	{ }
 	{ }
 };
 };
+MODULE_DEVICE_TABLE(spi, hmc5843_id);
 
 
 static struct spi_driver hmc5843_driver = {
 static struct spi_driver hmc5843_driver = {
 		.driver = {
 		.driver = {

+ 4 - 0
include/linux/iio/common/st_sensors.h

@@ -271,6 +271,10 @@ void st_sensors_power_enable(struct iio_dev *indio_dev);
 
 
 void st_sensors_power_disable(struct iio_dev *indio_dev);
 void st_sensors_power_disable(struct iio_dev *indio_dev);
 
 
+int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
+				  unsigned reg, unsigned writeval,
+				  unsigned *readval);
+
 int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr);
 int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr);
 
 
 int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);
 int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);

+ 3 - 0
include/linux/iio/iio.h

@@ -294,6 +294,7 @@ static inline s64 iio_get_time_ns(void)
 #define INDIO_BUFFER_TRIGGERED		0x02
 #define INDIO_BUFFER_TRIGGERED		0x02
 #define INDIO_BUFFER_SOFTWARE		0x04
 #define INDIO_BUFFER_SOFTWARE		0x04
 #define INDIO_BUFFER_HARDWARE		0x08
 #define INDIO_BUFFER_HARDWARE		0x08
+#define INDIO_EVENT_TRIGGERED		0x10
 
 
 #define INDIO_ALL_BUFFER_MODES					\
 #define INDIO_ALL_BUFFER_MODES					\
 	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE)
 	(INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE)
@@ -457,6 +458,7 @@ struct iio_buffer_setup_ops {
  * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
  * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
  * @trig:		[INTERN] current device trigger (buffer modes)
  * @trig:		[INTERN] current device trigger (buffer modes)
  * @pollfunc:		[DRIVER] function run on trigger being received
  * @pollfunc:		[DRIVER] function run on trigger being received
+ * @pollfunc_event:	[DRIVER] function run on events trigger being received
  * @channels:		[DRIVER] channel specification structure table
  * @channels:		[DRIVER] channel specification structure table
  * @num_channels:	[DRIVER] number of channels specified in @channels.
  * @num_channels:	[DRIVER] number of channels specified in @channels.
  * @channel_attr_list:	[INTERN] keep track of automatically created channel
  * @channel_attr_list:	[INTERN] keep track of automatically created channel
@@ -495,6 +497,7 @@ struct iio_dev {
 	unsigned			scan_index_timestamp;
 	unsigned			scan_index_timestamp;
 	struct iio_trigger		*trig;
 	struct iio_trigger		*trig;
 	struct iio_poll_func		*pollfunc;
 	struct iio_poll_func		*pollfunc;
+	struct iio_poll_func		*pollfunc_event;
 
 
 	struct iio_chan_spec const	*channels;
 	struct iio_chan_spec const	*channels;
 	int				num_channels;
 	int				num_channels;

+ 11 - 0
include/linux/iio/triggered_event.h

@@ -0,0 +1,11 @@
+#ifndef _LINUX_IIO_TRIGGERED_EVENT_H_
+#define _LINUX_IIO_TRIGGERED_EVENT_H_
+
+#include <linux/interrupt.h>
+
+int iio_triggered_event_setup(struct iio_dev *indio_dev,
+	irqreturn_t (*h)(int irq, void *p),
+	irqreturn_t (*thread)(int irq, void *p));
+void iio_triggered_event_cleanup(struct iio_dev *indio_dev);
+
+#endif

+ 4 - 0
include/uapi/linux/iio/types.h

@@ -35,6 +35,8 @@ enum iio_chan_type {
 	IIO_ENERGY,
 	IIO_ENERGY,
 	IIO_DISTANCE,
 	IIO_DISTANCE,
 	IIO_VELOCITY,
 	IIO_VELOCITY,
+	IIO_CONCENTRATION,
+	IIO_RESISTANCE,
 };
 };
 
 
 enum iio_modifier {
 enum iio_modifier {
@@ -72,6 +74,8 @@ enum iio_modifier {
 	IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
 	IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
 	IIO_MOD_I,
 	IIO_MOD_I,
 	IIO_MOD_Q,
 	IIO_MOD_Q,
+	IIO_MOD_CO2,
+	IIO_MOD_VOC,
 };
 };
 
 
 enum iio_event_type {
 enum iio_event_type {

+ 9 - 0
tools/iio/generic_buffer.c

@@ -328,6 +328,15 @@ int main(int argc, char **argv)
 			"diag %s\n", dev_dir_name);
 			"diag %s\n", dev_dir_name);
 		goto error_free_triggername;
 		goto error_free_triggername;
 	}
 	}
+	if (!num_channels) {
+		fprintf(stderr,
+			"No channels are enabled, we have nothing to scan.\n");
+		fprintf(stderr, "Enable channels manually in "
+			FORMAT_SCAN_ELEMENTS_DIR
+			"/*_en and try again.\n", dev_dir_name);
+		ret = -ENOENT;
+		goto error_free_triggername;
+	}
 
 
 	/*
 	/*
 	 * Construct the directory name for the associated buffer.
 	 * Construct the directory name for the associated buffer.

+ 5 - 1
tools/iio/iio_event_monitor.c

@@ -284,7 +284,11 @@ int main(int argc, char **argv)
 	ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
 	ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
 	if (ret == -1 || event_fd == -1) {
 	if (ret == -1 || event_fd == -1) {
 		ret = -errno;
 		ret = -errno;
-		fprintf(stderr, "Failed to retrieve event fd\n");
+		if (ret == -ENODEV)
+			fprintf(stderr,
+				"This device does not support events\n");
+		else
+			fprintf(stderr, "Failed to retrieve event fd\n");
 		if (close(fd) == -1)
 		if (close(fd) == -1)
 			perror("Failed to close character device file");
 			perror("Failed to close character device file");