瀏覽代碼

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

Jonathan writes:

Second set of new driver, functionality and cleanups for IIO in the 4.2 cycle.

Core functionality
* i and q modifiers from quadrature channels.
* IIO_CHAN_INFO_OVERSAMPLING_RATIO added.
* High pass filter attributes added to mirror the existing low pass filter
  ones.

Core cleanups
* Make IIO tools building more cross compiler friendly.
* Substantial rework of the function __iio_update_buffers to greatly simplify
  a hideously evolved function.

New drivers and support
* ACPI0008 ambient light sensor driver. This one has been around a long time to
  will be good to finally get it into mainline.
* Berlin SOC ADC support.
* BMC150 magnetometer.  The accelerometer in the same package has been supported
  for quite some time, so good to have this half as well.
* m62332 DAC driver
* MEMSIC MMC35420 magnetometer.
* ROHM BH1710 and similar ambient light sensors.
* Sensortek STK3310 light sensor.
* Sensortek STK8312 accelerometer.
* Sensortek STK8BA50 accelerometer.
* ti-adc128s052 gains support form the adc122s021 2 channel ADC.

Driver cleanups and functionality.
* Allow various drivers to compile with !GPIOLIB if COMPILE_TEST enabled.
* bmc150 - decouple trigger from buffer to allow other triggers to be used.
* bmg160 - decouple trigger from buffer to allow other triggers to be used.
  Fix a trivial unused field.
* Constify a load of platform_device_id structures.
* inv_mpu6050 - device tree bindings.
* hid-sensors - fix a memory leak during probe if certain errors occur.
* ltr501 - illuminance channel derived (in an non obvious fashion) from the
  intensity channels.
* ltr501 - fix a boundary check on the proximity threshold.
* mlx90614 - drop a pointless return.
* mma8452 - Debugfs register access and fix a bug that had no effect (by
  coincidence)
* ti_am335x_adc - add device tree bindings for sample-delay, open-delay and
  averaging.  The ideal settings for these tend to be board design specific.
Greg Kroah-Hartman 10 年之前
父節點
當前提交
61e331202f
共有 53 個文件被更改,包括 5061 次插入259 次删除
  1. 88 0
      Documentation/ABI/testing/sysfs-bus-iio
  2. 19 0
      Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt
  3. 2 2
      Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
  4. 17 0
      Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
  5. 22 0
      Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt
  6. 24 0
      Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
  7. 21 0
      drivers/iio/accel/Kconfig
  8. 3 0
      drivers/iio/accel/Makefile
  9. 35 20
      drivers/iio/accel/bmc150-accel.c
  10. 7 8
      drivers/iio/accel/hid-sensor-accel-3d.c
  11. 58 4
      drivers/iio/accel/mma8452.c
  12. 390 0
      drivers/iio/accel/stk8312.c
  13. 302 0
      drivers/iio/accel/stk8ba50.c
  14. 9 2
      drivers/iio/adc/Kconfig
  15. 1 0
      drivers/iio/adc/Makefile
  16. 1 1
      drivers/iio/adc/axp288_adc.c
  17. 378 0
      drivers/iio/adc/berlin2-adc.c
  18. 24 6
      drivers/iio/adc/ti-adc128s052.c
  19. 48 6
      drivers/iio/adc/ti_am335x_adc.c
  20. 10 0
      drivers/iio/dac/Kconfig
  21. 1 0
      drivers/iio/dac/Makefile
  22. 269 0
      drivers/iio/dac/m62332.c
  23. 36 31
      drivers/iio/gyro/bmg160.c
  24. 7 8
      drivers/iio/gyro/hid-sensor-gyro-3d.c
  25. 1 1
      drivers/iio/humidity/Kconfig
  26. 205 123
      drivers/iio/industrialio-buffer.c
  27. 5 0
      drivers/iio/industrialio-core.c
  28. 2 0
      drivers/iio/industrialio-event.c
  29. 34 0
      drivers/iio/light/Kconfig
  30. 3 0
      drivers/iio/light/Makefile
  31. 231 0
      drivers/iio/light/acpi-als.c
  32. 334 0
      drivers/iio/light/bh1750.c
  33. 7 7
      drivers/iio/light/hid-sensor-als.c
  34. 1 1
      drivers/iio/light/hid-sensor-prox.c
  35. 52 1
      drivers/iio/light/ltr501.c
  36. 722 0
      drivers/iio/light/stk3310.c
  37. 27 2
      drivers/iio/magnetometer/Kconfig
  38. 3 0
      drivers/iio/magnetometer/Makefile
  39. 1109 0
      drivers/iio/magnetometer/bmc150_magn.c
  40. 1 1
      drivers/iio/magnetometer/hid-sensor-magn-3d.c
  41. 512 0
      drivers/iio/magnetometer/mmc35240.c
  42. 8 8
      drivers/iio/orientation/hid-sensor-incl-3d.c
  43. 9 8
      drivers/iio/orientation/hid-sensor-rotation.c
  44. 7 7
      drivers/iio/pressure/hid-sensor-press.c
  45. 1 3
      drivers/iio/temperature/mlx90614.c
  46. 1 1
      drivers/staging/iio/accel/Kconfig
  47. 3 3
      drivers/staging/iio/adc/Kconfig
  48. 1 1
      drivers/staging/iio/addac/Kconfig
  49. 2 2
      drivers/staging/iio/resolver/Kconfig
  50. 2 0
      include/linux/iio/iio.h
  51. 2 0
      include/linux/iio/types.h
  52. 2 0
      include/uapi/linux/iio/types.h
  53. 2 2
      tools/iio/Makefile

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

@@ -71,6 +71,8 @@ Description:
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -81,6 +83,11 @@ Description:
 		unique to allow association with event codes. Units after
 		application of scale and offset are millivolts.
 
+		Channels with 'i' and 'q' modifiers always exist in pairs and both
+		channels refer to the same signal. The 'i' channel contains the in-phase
+		component of the signal while the 'q' channel contains the quadrature
+		component.
+
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
 KernelVersion:	2.6.35
 Contact:	linux-iio@vger.kernel.org
@@ -246,8 +253,16 @@ What:		/sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_q_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_i_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_current_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_i_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_q_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_q_offset
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_i_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_tempY_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_temp_offset
 What:		/sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@@ -273,14 +288,22 @@ Description:
 		to the _raw output.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_i_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_q_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_i_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_voltage_q_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_current_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_i_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentY_q_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_i_scale
+What:		/sys/bus/iio/devices/iio:deviceX/in_current_q_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
 What:		/sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
@@ -328,6 +351,10 @@ Description:
 
 What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
 What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
+What		/sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
 What		/sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
 What		/sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
 What		/sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
@@ -420,6 +447,16 @@ Description:
 		to the underlying data channel, then this parameter
 		gives the 3dB frequency of the filter in Hz.
 
+What:		/sys/.../in_accel_filter_high_pass_3db_frequency
+What:		/sys/.../in_anglvel_filter_high_pass_3db_frequency
+What:		/sys/.../in_magn_filter_high_pass_3db_frequency
+KernelVersion:	4.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If a known or controllable high pass filter is applied
+		to the underlying data channel, then this parameter
+		gives the 3dB frequency of the filter in Hz.
+
 What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
 What:		/sys/bus/iio/devices/iio:deviceX/out_altvoltageY_raw
 KernelVersion:	2.6.37
@@ -880,6 +917,26 @@ Description:
 		met before an event is generated. If direction is not
 		specified then this period applies to both directions.
 
+What:		/sys/.../events/in_accel_thresh_rising_low_pass_filter_3db
+What:		/sys/.../events/in_anglvel_thresh_rising_low_pass_filter_3db
+What:		/sys/.../events/in_magn_thresh_rising_low_pass_filter_3db
+KernelVersion:	4.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If a low pass filter can be applied to the event generation
+		this property gives its 3db frequency in Hz.
+		A value of zero disables the filter.
+
+What:		/sys/.../events/in_accel_thresh_rising_high_pass_filter_3db
+What:		/sys/.../events/in_anglvel_thresh_rising_high_pass_filter_3db
+What:		/sys/.../events/in_magn_thresh_rising_high_pass_filter_3db
+KernelVersion:	4.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		If a high pass filter can be applied to the event generation
+		this property gives its 3db frequency in Hz.
+		A value of zero disables the filter.
+
 What:		/sys/.../events/in_activity_still_thresh_rising_en
 What:		/sys/.../events/in_activity_still_thresh_falling_en
 What:		/sys/.../events/in_activity_walking_thresh_rising_en
@@ -1016,6 +1073,10 @@ What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_en
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_en
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY-voltageZ_en
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_i_en
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_q_en
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_i_en
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_q_en
 What:		/sys/.../iio:deviceX/scan_elements/in_incli_x_en
 What:		/sys/.../iio:deviceX/scan_elements/in_incli_y_en
 What:		/sys/.../iio:deviceX/scan_elements/in_pressureY_en
@@ -1034,6 +1095,10 @@ What:		/sys/.../iio:deviceX/scan_elements/in_incli_type
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_type
 What:		/sys/.../iio:deviceX/scan_elements/in_voltage_type
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_i_type
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_q_type
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_i_type
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_q_type
 What:		/sys/.../iio:deviceX/scan_elements/in_timestamp_type
 What:		/sys/.../iio:deviceX/scan_elements/in_pressureY_type
 What:		/sys/.../iio:deviceX/scan_elements/in_pressure_type
@@ -1071,6 +1136,10 @@ Description:
 
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_index
 What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_supply_index
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_i_index
+What:		/sys/.../iio:deviceX/scan_elements/in_voltageY_q_index
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_i_index
+What:		/sys/.../iio:deviceX/scan_elements/in_voltage_q_index
 What:		/sys/.../iio:deviceX/scan_elements/in_accel_x_index
 What:		/sys/.../iio:deviceX/scan_elements/in_accel_y_index
 What:		/sys/.../iio:deviceX/scan_elements/in_accel_z_index
@@ -1230,6 +1299,8 @@ Description:
 		or without compensation from tilt sensors.
 
 What:		/sys/bus/iio/devices/iio:deviceX/in_currentX_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw
+What:		/sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw
 KernelVersion:	3.18
 Contact:	linux-iio@vger.kernel.org
 Description:
@@ -1238,6 +1309,11 @@ Description:
 		present, output should be considered as processed with the
 		unit in milliamps.
 
+		Channels with 'i' and 'q' modifiers always exist in pairs and both
+		channels refer to the same signal. The 'i' channel contains the in-phase
+		component of the signal while the 'q' channel contains the quadrature
+		component.
+
 What:		/sys/.../iio:deviceX/in_energy_en
 What:		/sys/.../iio:deviceX/in_distance_en
 What:		/sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en
@@ -1375,3 +1451,15 @@ Description:
 		The emissivity ratio of the surface in the field of view of the
 		contactless temperature sensor.  Emissivity varies from 0 to 1,
 		with 1 being the emissivity of a black body.
+
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_x_oversampling_ratio
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_y_oversampling_ratio
+What:		/sys/bus/iio/devices/iio:deviceX/in_magn_z_oversampling_ratio
+KernelVersion:	4.2
+Contact:	linux-iio@vger.kernel.org
+Description:
+		Hardware applied number of measurements for acquiring one
+		data point. The HW will do <type>[_name]_oversampling_ratio
+		measurements and return the average value as output data. Each
+		value resulted from <type>[_name]_oversampling_ratio measurements
+		is considered as one sample for <type>[_name]_sampling_frequency.

+ 19 - 0
Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt

@@ -0,0 +1,19 @@
+* Berlin Analog to Digital Converter (ADC)
+
+The Berlin ADC has 8 channels, with one connected to a temperature sensor.
+It is part of the system controller register set. The ADC node should be a
+sub-node of the system controller node.
+
+Required properties:
+- compatible: must be "marvell,berlin2-adc"
+- interrupts: the interrupts for the ADC and the temperature sensor
+- interrupt-names: should be "adc" and "tsen"
+
+Example:
+
+adc: adc {
+	compatible = "marvell,berlin2-adc";
+	interrupt-parent = <&sic>;
+	interrupts = <12>, <14>;
+	interrupt-names = "adc", "tsen";
+};

+ 2 - 2
Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt

@@ -1,7 +1,7 @@
-* Texas Instruments' ADC128S052 ADC chip
+* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
 
 Required properties:
- - compatible: Should be "ti,adc128s052"
+ - compatible: Should be "ti,adc128s052" or "ti,adc122s021"
  - reg: spi chip select number for the device
  - vref-supply: The regulator supply for ADC reference voltage
 

+ 17 - 0
Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt

@@ -0,0 +1,17 @@
+InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
+
+http://www.invensense.com/mems/gyro/mpu6050.html
+
+Required properties:
+ - compatible : should be "invensense,mpu6050"
+ - reg : the I2C address of the sensor
+ - interrupt-parent : should be the phandle for the interrupt controller
+ - interrupts : interrupt mapping for GPIO IRQ
+
+Example:
+	mpu6050@68 {
+		compatible = "invensense,mpu6050";
+		reg = <0x68>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <18 1>;
+	};

+ 22 - 0
Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt

@@ -0,0 +1,22 @@
+* Bosch BMC150 magnetometer sensor
+
+http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf
+
+Required properties:
+
+  - compatible : should be "bosch,bmc150_magn"
+  - reg : the I2C address of the magnetometer
+
+Optional properties:
+
+  - interrupt-parent : phandle to the parent interrupt controller
+  - interrupts : interrupt mapping for GPIO IRQ
+
+Example:
+
+bmc150_magn@12 {
+        compatible = "bosch,bmc150_magn";
+        reg = <0x12>;
+        interrupt-parent = <&gpio1>;
+        interrupts = <0 1>;
+};

+ 24 - 0
Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt

@@ -42,6 +42,27 @@ Optional properties:
 			 hardware knob for adjusting the amount of "settling
 			 time".
 
+- child "adc"
+	ti,chan-step-opendelay: List of open delays for each channel of
+				ADC in the order of ti,adc-channels. The
+				value corresponds to the number of ADC
+				clock cycles to wait after applying the
+				step configuration registers and before
+				sending the start of ADC conversion.
+				Maximum value is 0x3FFFF.
+       ti,chan-step-sampledelay: List of sample delays for each channel
+				  of ADC in the order of ti,adc-channels.
+				  The value corresponds to the number of
+				  ADC clock cycles to sample (to hold
+				  start of conversion high).
+				  Maximum value is 0xFF.
+       ti,chan-step-avg: Number of averages to be performed for each
+			  channel of ADC. If average is 16 then input
+			  is sampled 16 times and averaged to get more
+			  accurate value. This increases the time taken
+			  by ADC to generate a sample. Valid range is 0
+			  average to 16 averages. Maximum value is 16.
+
 Example:
 	tscadc: tscadc@44e0d000 {
 		compatible = "ti,am3359-tscadc";
@@ -55,5 +76,8 @@ Example:
 
 		adc {
 			ti,adc-channels = <4 5 6 7>;
+			ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>;
+			ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>;
+			ti,chan-step-avg = <16 2 4 8>;
 		};
 	}

+ 21 - 0
drivers/iio/accel/Kconfig

@@ -136,4 +136,25 @@ config MMA9553
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called mma9553.
+
+config STK8312
+	tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
+	depends on I2C
+	help
+	  Say yes here to get support for the Sensortek STK8312 3-axis
+	  accelerometer.
+
+	  Choosing M will build the driver as a module. If so, the module
+	  will be called stk8312.
+
+config STK8BA50
+	tristate "Sensortek STK8BA50 3-Axis Accelerometer Driver"
+	depends on I2C
+	help
+	  Say yes here to get support for the Sensortek STK8BA50 3-axis
+	  accelerometer.
+
+	  Choosing M will build the driver as a module. If so, the module
+	  will be called stk8ba50.
+
 endmenu

+ 3 - 0
drivers/iio/accel/Makefile

@@ -14,6 +14,9 @@ obj-$(CONFIG_MMA9551_CORE)	+= mma9551_core.o
 obj-$(CONFIG_MMA9551)		+= mma9551.o
 obj-$(CONFIG_MMA9553)		+= mma9553.o
 
+obj-$(CONFIG_STK8312)		+= stk8312.o
+obj-$(CONFIG_STK8BA50)		+= stk8ba50.o
+
 obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
 
 obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o

+ 35 - 20
drivers/iio/accel/bmc150-accel.c

@@ -196,7 +196,7 @@ struct bmc150_accel_data {
 	u32 slope_thres;
 	u32 range;
 	int ev_enable_state;
-	int64_t timestamp, old_timestamp;
+	int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
 	const struct bmc150_accel_chip_info *chip_info;
 };
 
@@ -1183,7 +1183,6 @@ static const struct iio_info bmc150_accel_info = {
 	.write_event_value	= bmc150_accel_write_event,
 	.write_event_config	= bmc150_accel_write_event_config,
 	.read_event_config	= bmc150_accel_read_event_config,
-	.validate_trigger	= bmc150_accel_validate_trigger,
 	.driver_module		= THIS_MODULE,
 };
 
@@ -1222,7 +1221,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
 	mutex_unlock(&data->mutex);
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-					   data->timestamp);
+					   pf->timestamp);
 err_read:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -1535,6 +1534,13 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
 	return ret;
 }
 
+static int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct bmc150_accel_data *data = iio_priv(indio_dev);
+
+	return bmc150_accel_set_power_state(data, true);
+}
+
 static int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev)
 {
 	struct bmc150_accel_data *data = iio_priv(indio_dev);
@@ -1591,9 +1597,18 @@ out:
 	return 0;
 }
 
+static int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct bmc150_accel_data *data = iio_priv(indio_dev);
+
+	return bmc150_accel_set_power_state(data, false);
+}
+
 static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
+	.preenable = bmc150_accel_buffer_preenable,
 	.postenable = bmc150_accel_buffer_postenable,
 	.predisable = bmc150_accel_buffer_predisable,
+	.postdisable = bmc150_accel_buffer_postdisable,
 };
 
 static int bmc150_accel_probe(struct i2c_client *client,
@@ -1636,6 +1651,15 @@ static int bmc150_accel_probe(struct i2c_client *client,
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &bmc150_accel_info;
 
+	ret = iio_triggered_buffer_setup(indio_dev,
+					 &iio_pollfunc_store_time,
+					 bmc150_accel_trigger_handler,
+					 &bmc150_accel_buffer_ops);
+	if (ret < 0) {
+		dev_err(&client->dev, "Failed: iio triggered buffer setup\n");
+		return ret;
+	}
+
 	if (client->irq < 0)
 		client->irq = bmc150_accel_gpio_probe(client, data);
 
@@ -1648,7 +1672,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
 						BMC150_ACCEL_IRQ_NAME,
 						indio_dev);
 		if (ret)
-			return ret;
+			goto err_buffer_cleanup;
 
 		/*
 		 * Set latched mode interrupt. While certain interrupts are
@@ -1661,24 +1685,14 @@ static int bmc150_accel_probe(struct i2c_client *client,
 					     BMC150_ACCEL_INT_MODE_LATCH_RESET);
 		if (ret < 0) {
 			dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
-			return ret;
+			goto err_buffer_cleanup;
 		}
 
 		bmc150_accel_interrupts_setup(indio_dev, data);
 
 		ret = bmc150_accel_triggers_setup(indio_dev, data);
 		if (ret)
-			return ret;
-
-		ret = iio_triggered_buffer_setup(indio_dev,
-						 &iio_pollfunc_store_time,
-						 bmc150_accel_trigger_handler,
-						 &bmc150_accel_buffer_ops);
-		if (ret < 0) {
-			dev_err(&client->dev,
-				"Failed: iio triggered buffer setup\n");
-			goto err_trigger_unregister;
-		}
+			goto err_buffer_cleanup;
 
 		if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
 		    i2c_check_functionality(client->adapter,
@@ -1692,7 +1706,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
 	ret = iio_device_register(indio_dev);
 	if (ret < 0) {
 		dev_err(&client->dev, "Unable to register iio device\n");
-		goto err_buffer_cleanup;
+		goto err_trigger_unregister;
 	}
 
 	ret = pm_runtime_set_active(&client->dev);
@@ -1708,11 +1722,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
 
 err_iio_unregister:
 	iio_device_unregister(indio_dev);
-err_buffer_cleanup:
-	if (indio_dev->pollfunc)
-		iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
 	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
+err_buffer_cleanup:
+	iio_triggered_buffer_cleanup(indio_dev);
 
 	return ret;
 }
@@ -1730,6 +1743,8 @@ static int bmc150_accel_remove(struct i2c_client *client)
 
 	bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 
+	iio_triggered_buffer_cleanup(indio_dev);
+
 	mutex_lock(&data->mutex);
 	bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
 	mutex_unlock(&data->mutex);

+ 7 - 8
drivers/iio/accel/hid-sensor-accel-3d.c

@@ -299,7 +299,6 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct accel_3d_state *accel_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev,
 					  sizeof(struct accel_3d_state));
@@ -320,21 +319,21 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
-			   GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = kmemdup(accel_3d_channels,
+				      sizeof(accel_3d_channels), GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = accel_3d_parse_report(pdev, hsdev, channels,
-					HID_USAGE_SENSOR_ACCEL_3D, accel_state);
+	ret = accel_3d_parse_report(pdev, hsdev,
+				    (struct iio_chan_spec *)indio_dev->channels,
+				    HID_USAGE_SENSOR_ACCEL_3D, accel_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		goto error_free_dev_mem;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &accel_3d_info;
@@ -400,7 +399,7 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_accel_3d_ids[] = {
+static const struct platform_device_id hid_accel_3d_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200073",

+ 58 - 4
drivers/iio/accel/mma8452.c

@@ -32,6 +32,9 @@
 #define MMA8452_OFF_Z 0x31
 #define MMA8452_CTRL_REG1 0x2a
 #define MMA8452_CTRL_REG2 0x2b
+#define MMA8452_CTRL_REG2_RST		BIT(6)
+
+#define MMA8452_MAX_REG 0x31
 
 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
 
@@ -291,6 +294,28 @@ done:
 	return IRQ_HANDLED;
 }
 
+static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
+				  unsigned reg, unsigned writeval,
+				  unsigned *readval)
+{
+	int ret;
+	struct mma8452_data *data = iio_priv(indio_dev);
+
+	if (reg > MMA8452_MAX_REG)
+		return -EINVAL;
+
+	if (!readval)
+		return mma8452_change_config(data, reg, writeval);
+
+	ret = i2c_smbus_read_byte_data(data->client, reg);
+	if (ret < 0)
+		return ret;
+
+	*readval = ret;
+
+	return 0;
+}
+
 #define MMA8452_CHANNEL(axis, idx) { \
 	.type = IIO_ACCEL, \
 	.modified = 1, \
@@ -330,11 +355,36 @@ static const struct iio_info mma8452_info = {
 	.attrs = &mma8452_group,
 	.read_raw = &mma8452_read_raw,
 	.write_raw = &mma8452_write_raw,
+	.debugfs_reg_access = &mma8452_reg_access_dbg,
 	.driver_module = THIS_MODULE,
 };
 
 static const unsigned long mma8452_scan_masks[] = {0x7, 0};
 
+static int mma8452_reset(struct i2c_client *client)
+{
+	int i;
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client,	MMA8452_CTRL_REG2,
+					MMA8452_CTRL_REG2_RST);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < 10; i++) {
+		usleep_range(100, 200);
+		ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
+		if (ret == -EIO)
+			continue; /* I2C comm reset */
+		if (ret < 0)
+			return ret;
+		if (!(ret & MMA8452_CTRL_REG2_RST))
+			return 0;
+	}
+
+	return -ETIMEDOUT;
+}
+
 static int mma8452_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -365,10 +415,7 @@ static int mma8452_probe(struct i2c_client *client,
 	indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
 	indio_dev->available_scan_masks = mma8452_scan_masks;
 
-	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
-		(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
-	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
-		data->ctrl_reg1);
+	ret = mma8452_reset(client);
 	if (ret < 0)
 		return ret;
 
@@ -378,6 +425,13 @@ static int mma8452_probe(struct i2c_client *client,
 	if (ret < 0)
 		return ret;
 
+	data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
+		(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
+	ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
+					data->ctrl_reg1);
+	if (ret < 0)
+		return ret;
+
 	ret = iio_triggered_buffer_setup(indio_dev, NULL,
 		mma8452_trigger_handler, NULL);
 	if (ret < 0)

+ 390 - 0
drivers/iio/accel/stk8312.c

@@ -0,0 +1,390 @@
+/**
+ * Sensortek STK8312 3-Axis Accelerometer
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for STK8312; 7-bit I2C address: 0x3D.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define STK8312_REG_XOUT		0x00
+#define STK8312_REG_YOUT		0x01
+#define STK8312_REG_ZOUT		0x02
+#define STK8312_REG_MODE		0x07
+#define STK8312_REG_STH			0x13
+#define STK8312_REG_RESET		0x20
+#define STK8312_REG_AFECTRL		0x24
+#define STK8312_REG_OTPADDR		0x3D
+#define STK8312_REG_OTPDATA		0x3E
+#define STK8312_REG_OTPCTRL		0x3F
+
+#define STK8312_MODE_ACTIVE		1
+#define STK8312_MODE_STANDBY		0
+#define STK8312_MODE_MASK		0x01
+#define STK8312_RNG_MASK		0xC0
+#define STK8312_RNG_SHIFT		6
+#define STK8312_READ_RETRIES		16
+
+#define STK8312_DRIVER_NAME		"stk8312"
+
+/*
+ * The accelerometer has two measurement ranges:
+ *
+ * -6g - +6g (8-bit, signed)
+ * -16g - +16g (8-bit, signed)
+ *
+ * scale1 = (6 + 6) * 9.81 / (2^8 - 1)     = 0.4616
+ * scale2 = (16 + 16) * 9.81 / (2^8 - 1)   = 1.2311
+ */
+#define STK8312_SCALE_AVAIL		"0.4616 1.2311"
+
+static const int stk8312_scale_table[][2] = {
+	{0, 461600}, {1, 231100}
+};
+
+#define STK8312_ACCEL_CHANNEL(reg, axis) {			\
+	.type = IIO_ACCEL,					\
+	.address = reg,						\
+	.modified = 1,						\
+	.channel2 = IIO_MOD_##axis,				\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec stk8312_channels[] = {
+	STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
+	STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
+	STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
+};
+
+struct stk8312_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	int range;
+	u8 mode;
+};
+
+static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
+
+static struct attribute *stk8312_attributes[] = {
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stk8312_attribute_group = {
+	.attrs = stk8312_attributes
+};
+
+static int stk8312_otp_init(struct stk8312_data *data)
+{
+	int ret;
+	int count = 10;
+	struct i2c_client *client = data->client;
+
+	ret = i2c_smbus_write_byte_data(client, STK8312_REG_OTPADDR, 0x70);
+	if (ret < 0)
+		goto exit_err;
+	ret = i2c_smbus_write_byte_data(client, STK8312_REG_OTPCTRL, 0x02);
+	if (ret < 0)
+		goto exit_err;
+
+	do {
+		usleep_range(1000, 5000);
+		ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPCTRL);
+		if (ret < 0)
+			goto exit_err;
+		count--;
+	} while (!(ret & 0x80) && count > 0);
+
+	if (count == 0)
+		goto exit_err;
+
+	ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA);
+	if (ret < 0)
+		goto exit_err;
+
+	ret = i2c_smbus_write_byte_data(data->client,
+			STK8312_REG_AFECTRL, ret);
+	if (ret < 0)
+		goto exit_err;
+	msleep(150);
+
+	return ret;
+
+exit_err:
+	dev_err(&client->dev, "failed to initialize sensor\n");
+	return ret;
+}
+
+static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
+{
+	int ret;
+	u8 masked_reg;
+	struct i2c_client *client = data->client;
+
+	if (mode > 1)
+		return -EINVAL;
+	else if (mode == data->mode)
+		return 0;
+
+	ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to change sensor mode\n");
+		return ret;
+	}
+	masked_reg = ret & (~STK8312_MODE_MASK);
+	masked_reg |= mode;
+
+	ret = i2c_smbus_write_byte_data(client,
+			STK8312_REG_MODE, masked_reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to change sensor mode\n");
+		return ret;
+	}
+
+	data->mode = mode;
+	if (mode == STK8312_MODE_ACTIVE) {
+		/* Need to run OTP sequence before entering active mode */
+		usleep_range(1000, 5000);
+		ret = stk8312_otp_init(data);
+	}
+
+	return ret;
+}
+
+static int stk8312_set_range(struct stk8312_data *data, u8 range)
+{
+	int ret;
+	u8 masked_reg;
+	u8 mode;
+	struct i2c_client *client = data->client;
+
+	if (range != 1 && range != 2)
+		return -EINVAL;
+	else if (range == data->range)
+		return 0;
+
+	mode = data->mode;
+	/* We need to go in standby mode to modify registers */
+	ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to change sensor range\n");
+		return ret;
+	}
+
+	masked_reg = ret & (~STK8312_RNG_MASK);
+	masked_reg |= range << STK8312_RNG_SHIFT;
+
+	ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg);
+	if (ret < 0)
+		dev_err(&client->dev, "failed to change sensor range\n");
+	else
+		data->range = range;
+
+	return stk8312_set_mode(data, mode);
+}
+
+static int stk8312_read_accel(struct stk8312_data *data, u8 address)
+{
+	int ret;
+	struct i2c_client *client = data->client;
+
+	if (address > 2)
+		return -EINVAL;
+
+	ret = i2c_smbus_read_byte_data(client, address);
+	if (ret < 0) {
+		dev_err(&client->dev, "register read failed\n");
+		return ret;
+	}
+
+	return sign_extend32(ret, 7);
+}
+
+static int stk8312_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	struct stk8312_data *data = iio_priv(indio_dev);
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+		*val = stk8312_read_accel(data, chan->address);
+		mutex_unlock(&data->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = stk8312_scale_table[data->range - 1][0];
+		*val2 = stk8312_scale_table[data->range - 1][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static int stk8312_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	int i;
+	int index = -1;
+	int ret;
+	struct stk8312_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		for (i = 0; i < ARRAY_SIZE(stk8312_scale_table); i++)
+			if (val == stk8312_scale_table[i][0] &&
+			    val2 == stk8312_scale_table[i][1]) {
+				index = i + 1;
+				break;
+			}
+		if (index < 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = stk8312_set_range(data, index);
+		mutex_unlock(&data->lock);
+
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stk8312_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= stk8312_read_raw,
+	.write_raw		= stk8312_write_raw,
+	.attrs			= &stk8312_attribute_group,
+};
+
+static int stk8312_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct stk8312_data *data;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev) {
+		dev_err(&client->dev, "iio allocation failed!\n");
+		return -ENOMEM;
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	i2c_set_clientdata(client, indio_dev);
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &stk8312_info;
+	indio_dev->name = STK8312_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = stk8312_channels;
+	indio_dev->num_channels = ARRAY_SIZE(stk8312_channels);
+
+	/* A software reset is recommended at power-on */
+	ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_RESET, 0x00);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to reset sensor\n");
+		return ret;
+	}
+	ret = stk8312_set_range(data, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "device_register failed\n");
+		stk8312_set_mode(data, STK8312_MODE_STANDBY);
+	}
+
+	return ret;
+}
+
+static int stk8312_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+
+	return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stk8312_suspend(struct device *dev)
+{
+	struct stk8312_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return stk8312_set_mode(data, STK8312_MODE_STANDBY);
+}
+
+static int stk8312_resume(struct device *dev)
+{
+	struct stk8312_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
+}
+
+static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
+
+#define STK8312_PM_OPS (&stk8312_pm_ops)
+#else
+#define STK8312_PM_OPS NULL
+#endif
+
+static const struct i2c_device_id stk8312_i2c_id[] = {
+	{"STK8312", 0},
+	{}
+};
+
+static const struct acpi_device_id stk8312_acpi_id[] = {
+	{"STK8312", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
+
+static struct i2c_driver stk8312_driver = {
+	.driver = {
+		.name = "stk8312",
+		.pm = STK8312_PM_OPS,
+		.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
+	},
+	.probe =            stk8312_probe,
+	.remove =           stk8312_remove,
+	.id_table =         stk8312_i2c_id,
+};
+
+module_i2c_driver(stk8312_driver);
+
+MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
+MODULE_DESCRIPTION("STK8312 3-Axis Accelerometer driver");
+MODULE_LICENSE("GPL v2");

+ 302 - 0
drivers/iio/accel/stk8ba50.c

@@ -0,0 +1,302 @@
+/**
+ * Sensortek STK8BA50 3-Axis Accelerometer
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * STK8BA50 7-bit I2C address: 0x18.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define STK8BA50_REG_XOUT			0x02
+#define STK8BA50_REG_YOUT			0x04
+#define STK8BA50_REG_ZOUT			0x06
+#define STK8BA50_REG_RANGE			0x0F
+#define STK8BA50_REG_POWMODE			0x11
+#define STK8BA50_REG_SWRST			0x14
+
+#define STK8BA50_MODE_NORMAL			0
+#define STK8BA50_MODE_SUSPEND			1
+#define STK8BA50_MODE_POWERBIT			BIT(7)
+#define STK8BA50_DATA_SHIFT			6
+#define STK8BA50_RESET_CMD			0xB6
+
+#define STK8BA50_DRIVER_NAME			"stk8ba50"
+
+#define STK8BA50_SCALE_AVAIL			"0.0384 0.0767 0.1534 0.3069"
+
+/*
+ * The accelerometer has four measurement ranges:
+ * +/-2g; +/-4g; +/-8g; +/-16g
+ *
+ * Acceleration values are 10-bit, 2's complement.
+ * Scales are calculated as following:
+ *
+ * scale1 = (2 + 2) * 9.81 / (2^10 - 1)   = 0.0384
+ * scale2 = (4 + 4) * 9.81 / (2^10 - 1)   = 0.0767
+ * etc.
+ *
+ * Scales are stored in this format:
+ * { <register value>, <scale value> }
+ *
+ * Locally, the range is stored as a table index.
+ */
+static const int stk8ba50_scale_table[][2] = {
+	{3, 38400}, {5, 76700}, {8, 153400}, {12, 306900}
+};
+
+struct stk8ba50_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	int range;
+};
+
+#define STK8BA50_ACCEL_CHANNEL(reg, axis) {			\
+	.type = IIO_ACCEL,					\
+	.address = reg,						\
+	.modified = 1,						\
+	.channel2 = IIO_MOD_##axis,				\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
+}
+
+static const struct iio_chan_spec stk8ba50_channels[] = {
+	STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X),
+	STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y),
+	STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z),
+};
+
+static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL);
+
+static struct attribute *stk8ba50_attributes[] = {
+	&iio_const_attr_in_accel_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stk8ba50_attribute_group = {
+	.attrs = stk8ba50_attributes
+};
+
+static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg)
+{
+	int ret;
+	struct i2c_client *client = data->client;
+
+	ret = i2c_smbus_read_word_data(client, reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "register read failed\n");
+		return ret;
+	}
+
+	return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9);
+}
+
+static int stk8ba50_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct stk8ba50_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&data->lock);
+		*val = stk8ba50_read_accel(data, chan->address);
+		mutex_unlock(&data->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = stk8ba50_scale_table[data->range][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static int stk8ba50_write_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int val, int val2, long mask)
+{
+	int ret;
+	int i;
+	int index = -1;
+	struct stk8ba50_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (val != 0)
+			return -EINVAL;
+
+		for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++)
+			if (val2 == stk8ba50_scale_table[i][1]) {
+				index = i;
+				break;
+			}
+		if (index < 0)
+			return -EINVAL;
+
+		ret = i2c_smbus_write_byte_data(data->client,
+				STK8BA50_REG_RANGE,
+				stk8ba50_scale_table[index][0]);
+		if (ret < 0)
+			dev_err(&data->client->dev,
+					"failed to set measurement range\n");
+		else
+			data->range = index;
+
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stk8ba50_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= stk8ba50_read_raw,
+	.write_raw		= stk8ba50_write_raw,
+	.attrs			= &stk8ba50_attribute_group,
+};
+
+static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode)
+{
+	int ret;
+	u8 masked_reg;
+	struct i2c_client *client = data->client;
+
+	ret = i2c_smbus_read_byte_data(client, STK8BA50_REG_POWMODE);
+	if (ret < 0)
+		goto exit_err;
+
+	if (mode)
+		masked_reg = ret | STK8BA50_MODE_POWERBIT;
+	else
+		masked_reg = ret & (~STK8BA50_MODE_POWERBIT);
+
+	ret = i2c_smbus_write_byte_data(client, STK8BA50_REG_POWMODE,
+					masked_reg);
+	if (ret < 0)
+		goto exit_err;
+
+	return ret;
+
+exit_err:
+	dev_err(&client->dev, "failed to change sensor mode\n");
+	return ret;
+}
+
+static int stk8ba50_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct stk8ba50_data *data;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev) {
+		dev_err(&client->dev, "iio allocation failed!\n");
+		return -ENOMEM;
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	i2c_set_clientdata(client, indio_dev);
+	mutex_init(&data->lock);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &stk8ba50_info;
+	indio_dev->name = STK8BA50_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = stk8ba50_channels;
+	indio_dev->num_channels = ARRAY_SIZE(stk8ba50_channels);
+
+	/* Reset all registers on startup */
+	ret = i2c_smbus_write_byte_data(client,
+			STK8BA50_REG_SWRST, STK8BA50_RESET_CMD);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to reset sensor\n");
+		return ret;
+	}
+
+	/* The default range is +/-2g */
+	data->range = 0;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "device_register failed\n");
+		stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
+	}
+
+	return ret;
+}
+
+static int stk8ba50_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+
+	return stk8ba50_set_power(iio_priv(indio_dev), STK8BA50_MODE_SUSPEND);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stk8ba50_suspend(struct device *dev)
+{
+	struct stk8ba50_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
+}
+
+static int stk8ba50_resume(struct device *dev)
+{
+	struct stk8ba50_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
+}
+
+static SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume);
+
+#define STK8BA50_PM_OPS (&stk8ba50_pm_ops)
+#else
+#define STK8BA50_PM_OPS NULL
+#endif
+
+static const struct i2c_device_id stk8ba50_i2c_id[] = {
+	{"stk8ba50", 0},
+	{}
+};
+
+static const struct acpi_device_id stk8ba50_acpi_id[] = {
+	{"STK8BA50", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id);
+
+static struct i2c_driver stk8ba50_driver = {
+	.driver = {
+		.name = "stk8ba50",
+		.pm = STK8BA50_PM_OPS,
+		.acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
+	},
+	.probe =            stk8ba50_probe,
+	.remove =           stk8ba50_remove,
+	.id_table =         stk8ba50_i2c_id,
+};
+
+module_i2c_driver(stk8ba50_driver);
+
+MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
+MODULE_DESCRIPTION("STK8BA50 3-Axis Accelerometer driver");
+MODULE_LICENSE("GPL v2");

+ 9 - 2
drivers/iio/adc/Kconfig

@@ -135,6 +135,13 @@ config AXP288_ADC
 	  device. Depending on platform configuration, this general purpose ADC can
 	  be used for sampling sensors such as thermal resistors.
 
+config BERLIN2_ADC
+	tristate "Marvell Berlin2 ADC driver"
+	depends on ARCH_BERLIN
+	help
+	  Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
+	  temperature measurement.
+
 config DA9150_GPADC
 	tristate "Dialog DA9150 GPADC driver support"
 	depends on MFD_DA9150
@@ -285,11 +292,11 @@ config TI_ADC081C
 	  called ti-adc081c.
 
 config TI_ADC128S052
-	tristate "Texas Instruments ADC128S052"
+	tristate "Texas Instruments ADC128S052/ADC122S021"
 	depends on SPI
 	help
 	  If you say yes here you get support for Texas Instruments ADC128S052
-	  chip.
+	  and ADC122S021 chips.
 
 	  This driver can also be built as a module. If so, the module will be
 	  called ti-adc128s052.

+ 1 - 0
drivers/iio/adc/Makefile

@@ -15,6 +15,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_AXP288_ADC) += axp288_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_EXYNOS_ADC) += exynos_adc.o

+ 1 - 1
drivers/iio/adc/axp288_adc.c

@@ -238,7 +238,7 @@ static int axp288_adc_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id axp288_adc_id_table[] = {
+static const struct platform_device_id axp288_adc_id_table[] = {
 	{ .name = "axp288_adc" },
 	{},
 };

+ 378 - 0
drivers/iio/adc/berlin2-adc.c

@@ -0,0 +1,378 @@
+/*
+ * Marvell Berlin2 ADC driver
+ *
+ * Copyright (C) 2015 Marvell Technology Group Ltd.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/machine.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+#define BERLIN2_SM_CTRL				0x14
+#define  BERLIN2_SM_CTRL_SM_SOC_INT		BIT(1)
+#define  BERLIN2_SM_CTRL_SOC_SM_INT		BIT(2)
+#define  BERLIN2_SM_CTRL_ADC_SEL(x)		(BIT(x) << 5)	/* 0-15 */
+#define  BERLIN2_SM_CTRL_ADC_SEL_MASK		(0xf << 5)
+#define  BERLIN2_SM_CTRL_ADC_POWER		BIT(9)
+#define  BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2	(0x0 << 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_DIV8	(0x3 << 10)
+#define  BERLIN2_SM_CTRL_ADC_CLKSEL_MASK	(0x3 << 10)
+#define  BERLIN2_SM_CTRL_ADC_START		BIT(12)
+#define  BERLIN2_SM_CTRL_ADC_RESET		BIT(13)
+#define  BERLIN2_SM_CTRL_ADC_BANDGAP_RDY	BIT(14)
+#define  BERLIN2_SM_CTRL_ADC_CONT_SINGLE	(0x0 << 15)
+#define  BERLIN2_SM_CTRL_ADC_CONT_CONTINUOUS	(0x1 << 15)
+#define  BERLIN2_SM_CTRL_ADC_BUFFER_EN		BIT(16)
+#define  BERLIN2_SM_CTRL_ADC_VREF_EXT		(0x0 << 17)
+#define  BERLIN2_SM_CTRL_ADC_VREF_INT		(0x1 << 17)
+#define  BERLIN2_SM_CTRL_ADC_ROTATE		BIT(19)
+#define  BERLIN2_SM_CTRL_TSEN_EN		BIT(20)
+#define  BERLIN2_SM_CTRL_TSEN_CLK_SEL_125	(0x0 << 21)	/* 1.25 MHz */
+#define  BERLIN2_SM_CTRL_TSEN_CLK_SEL_250	(0x1 << 21)	/* 2.5 MHz */
+#define  BERLIN2_SM_CTRL_TSEN_MODE_0_125	(0x0 << 22)	/* 0-125 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_ADC_DATA			0x20
+#define  BERLIN2_SM_ADC_MASK			0x3ff
+#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_MASK	0xf
+#define  BERLIN2_SM_ADC_STATUS_INT_EN(x)	(BIT(x) << 16)	/* 0-15 */
+#define  BERLIN2_SM_ADC_STATUS_INT_EN_MASK	(0xf << 16)
+#define BERLIN2_SM_TSEN_STATUS			0x24
+#define  BERLIN2_SM_TSEN_STATUS_DATA_RDY	BIT(0)
+#define  BERLIN2_SM_TSEN_STATUS_INT_EN		BIT(1)
+#define BERLIN2_SM_TSEN_DATA			0x28
+#define  BERLIN2_SM_TSEN_MASK			0xfff
+#define BERLIN2_SM_TSEN_CTRL			0x74
+#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_12	(0x1 << 21)	/* 12 us */
+#define  BERLIN2_SM_TSEN_CTRL_SETTLING_MASK	(0x1 << 21)
+#define  BERLIN2_SM_TSEN_CTRL_TRIM(x)		((x) << 22)
+#define  BERLIN2_SM_TSEN_CTRL_TRIM_MASK		(0xf << 22)
+
+struct berlin2_adc_priv {
+	struct regmap		*regmap;
+	struct mutex		lock;
+	wait_queue_head_t	wq;
+	bool			data_available;
+	int			data;
+};
+
+#define BERLIN2_ADC_CHANNEL(n, t)					\
+		{							\
+			.channel	= n,				\
+			.datasheet_name	= "channel"#n,			\
+			.type		= t,				\
+			.indexed	= 1,				\
+			.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),	\
+		}
+
+static struct iio_chan_spec berlin2_adc_channels[] = {
+	BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE),	/* external input */
+	BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE),	/* external input */
+	BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE),	/* external input */
+	BERLIN2_ADC_CHANNEL(3, IIO_VOLTAGE),	/* external input */
+	BERLIN2_ADC_CHANNEL(4, IIO_VOLTAGE),	/* reserved */
+	BERLIN2_ADC_CHANNEL(5, IIO_VOLTAGE),	/* reserved */
+	{					/* temperature sensor */
+		.channel		= 6,
+		.datasheet_name		= "channel6",
+		.type			= IIO_TEMP,
+		.indexed		= 0,
+		.info_mask_separate	= BIT(IIO_CHAN_INFO_PROCESSED),
+	},
+	BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE),	/* reserved */
+	IIO_CHAN_SOFT_TIMESTAMP(8),		/* timestamp */
+};
+#define BERLIN2_N_CHANNELS	ARRAY_SIZE(berlin2_adc_channels)
+
+static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
+{
+	struct berlin2_adc_priv *priv = iio_priv(indio_dev);
+	int data, ret;
+
+	mutex_lock(&priv->lock);
+
+	/* Configure the ADC */
+	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);
+
+	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
+			msecs_to_jiffies(1000));
+
+	/* Disable the interrupts */
+	regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
+			BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
+
+	if (ret == 0)
+		ret = -ETIMEDOUT;
+	if (ret < 0) {
+		mutex_unlock(&priv->lock);
+		return ret;
+	}
+
+	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
+			BERLIN2_SM_CTRL_ADC_START, 0);
+
+	data = priv->data;
+	priv->data_available = false;
+
+	mutex_unlock(&priv->lock);
+
+	return data;
+}
+
+static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
+{
+	struct berlin2_adc_priv *priv = iio_priv(indio_dev);
+	int data, ret;
+
+	mutex_lock(&priv->lock);
+
+	/* Configure the ADC */
+	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
+			BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
+			BERLIN2_SM_CTRL_ADC_ROTATE);
+
+	/* Configure the temperature sensor */
+	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);
+
+	ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
+			msecs_to_jiffies(1000));
+
+	/* Disable interrupts */
+	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
+			BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
+
+	if (ret == 0)
+		ret = -ETIMEDOUT;
+	if (ret < 0) {
+		mutex_unlock(&priv->lock);
+		return ret;
+	}
+
+	regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
+			BERLIN2_SM_TSEN_CTRL_START, 0);
+
+	data = priv->data;
+	priv->data_available = false;
+
+	mutex_unlock(&priv->lock);
+
+	return data;
+}
+
+static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan, int *val, int *val2,
+		long mask)
+{
+	struct berlin2_adc_priv *priv = iio_priv(indio_dev);
+	int temp;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type != IIO_VOLTAGE)
+			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);
+		if (*val < 0)
+			return *val;
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_PROCESSED:
+		if (chan->type != IIO_TEMP)
+			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);
+		if (temp < 0)
+			return temp;
+
+		if (temp > 2047)
+			temp = -(4096 - temp);
+
+		/* Convert to milli Celsius */
+		*val = ((temp * 100000) / 264 - 270000);
+		return IIO_VAL_INT;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static irqreturn_t berlin2_adc_irq(int irq, void *private)
+{
+	struct berlin2_adc_priv *priv = iio_priv(private);
+	unsigned val;
+
+	regmap_read(priv->regmap, BERLIN2_SM_ADC_STATUS, &val);
+	if (val & BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK) {
+		regmap_read(priv->regmap, BERLIN2_SM_ADC_DATA, &priv->data);
+		priv->data &= BERLIN2_SM_ADC_MASK;
+
+		val &= ~BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK;
+		regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, val);
+
+		priv->data_available = true;
+		wake_up_interruptible(&priv->wq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t berlin2_adc_tsen_irq(int irq, void *private)
+{
+	struct berlin2_adc_priv *priv = iio_priv(private);
+	unsigned val;
+
+	regmap_read(priv->regmap, BERLIN2_SM_TSEN_STATUS, &val);
+	if (val & BERLIN2_SM_TSEN_STATUS_DATA_RDY) {
+		regmap_read(priv->regmap, BERLIN2_SM_TSEN_DATA, &priv->data);
+		priv->data &= BERLIN2_SM_TSEN_MASK;
+
+		val &= ~BERLIN2_SM_TSEN_STATUS_DATA_RDY;
+		regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, val);
+
+		priv->data_available = true;
+		wake_up_interruptible(&priv->wq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_info berlin2_adc_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= berlin2_adc_read_raw,
+};
+
+static int berlin2_adc_probe(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev;
+	struct berlin2_adc_priv *priv;
+	struct device_node *parent_np = of_get_parent(pdev->dev.of_node);
+	int irq, tsen_irq;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct berlin2_adc_priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	priv = iio_priv(indio_dev);
+	platform_set_drvdata(pdev, indio_dev);
+
+	priv->regmap = syscon_node_to_regmap(parent_np);
+	of_node_put(parent_np);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	irq = platform_get_irq_byname(pdev, "adc");
+	if (irq < 0)
+		return -ENODEV;
+
+	tsen_irq = platform_get_irq_byname(pdev, "tsen");
+	if (tsen_irq < 0)
+		return -ENODEV;
+
+	ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
+			pdev->dev.driver->name, indio_dev);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
+			0, pdev->dev.driver->name, indio_dev);
+	if (ret)
+		return ret;
+
+	init_waitqueue_head(&priv->wq);
+	mutex_init(&priv->lock);
+
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &berlin2_adc_info;
+
+	indio_dev->num_channels = BERLIN2_N_CHANNELS;
+	indio_dev->channels = berlin2_adc_channels;
+
+	/* Power up the ADC */
+	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
+			BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		/* Power down the ADC */
+		regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
+				BERLIN2_SM_CTRL_ADC_POWER, 0);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int berlin2_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+	struct berlin2_adc_priv *priv = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	/* Power down the ADC */
+	regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
+			BERLIN2_SM_CTRL_ADC_POWER, 0);
+
+	return 0;
+}
+
+static const struct of_device_id berlin2_adc_match[] = {
+	{ .compatible = "marvell,berlin2-adc", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, berlin2_adc_match);
+
+static struct platform_driver berlin2_adc_driver = {
+	.driver	= {
+		.name		= "berlin2-adc",
+		.of_match_table	= berlin2_adc_match,
+	},
+	.probe	= berlin2_adc_probe,
+	.remove	= berlin2_adc_remove,
+};
+module_platform_driver(berlin2_adc_driver);
+
+MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Berlin2 ADC driver");
+MODULE_LICENSE("GPL v2");

+ 24 - 6
drivers/iio/adc/ti-adc128s052.c

@@ -1,9 +1,10 @@
 /*
  * Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
  *
- * Driver for Texas Instruments' ADC128S052 ADC chip.
- * Datasheet can be found here:
+ * Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
+ * Datasheets can be found here:
  * http://www.ti.com/lit/ds/symlink/adc128s052.pdf
+ * http://www.ti.com/lit/ds/symlink/adc122s021.pdf
  *
  * 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
@@ -16,6 +17,11 @@
 #include <linux/iio/iio.h>
 #include <linux/regulator/consumer.h>
 
+struct adc128_configuration {
+	const struct iio_chan_spec	*channels;
+	u8				num_channels;
+};
+
 struct adc128 {
 	struct spi_device *spi;
 
@@ -92,7 +98,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev,
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
 	}
 
-static const struct iio_chan_spec adc128_channels[] = {
+static const struct iio_chan_spec adc128s052_channels[] = {
 	ADC128_VOLTAGE_CHANNEL(0),
 	ADC128_VOLTAGE_CHANNEL(1),
 	ADC128_VOLTAGE_CHANNEL(2),
@@ -103,6 +109,16 @@ static const struct iio_chan_spec adc128_channels[] = {
 	ADC128_VOLTAGE_CHANNEL(7),
 };
 
+static const struct iio_chan_spec adc122s021_channels[] = {
+	ADC128_VOLTAGE_CHANNEL(0),
+	ADC128_VOLTAGE_CHANNEL(1),
+};
+
+static const struct adc128_configuration adc128_config[] = {
+	{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
+	{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
+};
+
 static const struct iio_info adc128_info = {
 	.read_raw = adc128_read_raw,
 	.driver_module = THIS_MODULE,
@@ -112,6 +128,7 @@ static int adc128_probe(struct spi_device *spi)
 {
 	struct iio_dev *indio_dev;
 	struct adc128 *adc;
+	int config = spi_get_device_id(spi)->driver_data;
 	int ret;
 
 	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
@@ -128,8 +145,8 @@ static int adc128_probe(struct spi_device *spi)
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->info = &adc128_info;
 
-	indio_dev->channels = adc128_channels;
-	indio_dev->num_channels = ARRAY_SIZE(adc128_channels);
+	indio_dev->channels = adc128_config[config].channels;
+	indio_dev->num_channels = adc128_config[config].num_channels;
 
 	adc->reg = devm_regulator_get(&spi->dev, "vref");
 	if (IS_ERR(adc->reg))
@@ -158,7 +175,8 @@ static int adc128_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id adc128_id[] = {
-	{ "adc128s052", 0},
+	{ "adc128s052", 0},	/* index into adc128_config */
+	{ "adc122s021",	1},
 	{ }
 };
 MODULE_DEVICE_TABLE(spi, adc128_id);

+ 48 - 6
drivers/iio/adc/ti_am335x_adc.c

@@ -37,6 +37,7 @@ struct tiadc_device {
 	u8 channel_step[8];
 	int buffer_en_ch_steps;
 	u16 data[8];
+	u32 open_delay[8], sample_delay[8], step_avg[8];
 };
 
 static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
@@ -85,6 +86,7 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
 static void tiadc_step_config(struct iio_dev *indio_dev)
 {
 	struct tiadc_device *adc_dev = iio_priv(indio_dev);
+	struct device *dev = adc_dev->mfd_tscadc->dev;
 	unsigned int stepconfig;
 	int i, steps = 0;
 
@@ -98,20 +100,47 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
 	 * needs to be given to ADC to digitalize data.
 	 */
 
-	if (iio_buffer_enabled(indio_dev))
-		stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
-					| STEPCONFIG_MODE_SWCNT;
-	else
-		stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
 
 	for (i = 0; i < adc_dev->channels; i++) {
 		int chan;
 
 		chan = adc_dev->channel_line[i];
+
+		if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) {
+			dev_warn(dev, "chan %d step_avg truncating to %d\n",
+				 chan, STEPCONFIG_AVG_16);
+			adc_dev->step_avg[i] = STEPCONFIG_AVG_16;
+		}
+
+		if (adc_dev->step_avg[i])
+			stepconfig =
+			STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) |
+			STEPCONFIG_FIFO1;
+		else
+			stepconfig = STEPCONFIG_FIFO1;
+
+		if (iio_buffer_enabled(indio_dev))
+			stepconfig |= STEPCONFIG_MODE_SWCNT;
+
 		tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
 				stepconfig | STEPCONFIG_INP(chan));
+
+		if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) {
+			dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n",
+				 chan);
+			adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK;
+		}
+
+		if (adc_dev->sample_delay[i] > 0xFF) {
+			dev_warn(dev, "chan %d sample delay truncating to 0xFF\n",
+				 chan);
+			adc_dev->sample_delay[i] = 0xFF;
+		}
+
 		tiadc_writel(adc_dev, REG_STEPDELAY(steps),
-				STEPCONFIG_OPENDLY);
+				STEPDELAY_OPEN(adc_dev->open_delay[i]) |
+				STEPDELAY_SAMPLE(adc_dev->sample_delay[i]));
+
 		adc_dev->channel_step[i] = steps;
 		steps++;
 	}
@@ -406,9 +435,22 @@ static int tiadc_parse_dt(struct platform_device *pdev,
 
 	of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
 		adc_dev->channel_line[channels] = val;
+
+		/* Set Default values for optional DT parameters */
+		adc_dev->open_delay[channels] = STEPCONFIG_OPENDLY;
+		adc_dev->sample_delay[channels] = STEPCONFIG_SAMPLEDLY;
+		adc_dev->step_avg[channels] = 16;
+
 		channels++;
 	}
 
+	of_property_read_u32_array(node, "ti,chan-step-avg",
+				   adc_dev->step_avg, channels);
+	of_property_read_u32_array(node, "ti,chan-step-opendelay",
+				   adc_dev->open_delay, channels);
+	of_property_read_u32_array(node, "ti,chan-step-sampledelay",
+				   adc_dev->sample_delay, channels);
+
 	adc_dev->channels = channels;
 	return 0;
 }

+ 10 - 0
drivers/iio/dac/Kconfig

@@ -142,6 +142,16 @@ config AD7303
 	  To compile this driver as module choose M here: the module will be called
 	  ad7303.
 
+config M62332
+	tristate "Mitsubishi M62332 DAC driver"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Mitsubishi M62332
+	  (I2C 8-Bit DACs with rail-to-rail outputs).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called m62332.
+
 config MAX517
 	tristate "Maxim MAX517/518/519/520/521 DAC driver"
 	depends on I2C

+ 1 - 0
drivers/iio/dac/Makefile

@@ -16,6 +16,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5791) += ad5791.o
 obj-$(CONFIG_AD5686) += ad5686.o
 obj-$(CONFIG_AD7303) += ad7303.o
+obj-$(CONFIG_M62332) += m62332.o
 obj-$(CONFIG_MAX517) += max517.o
 obj-$(CONFIG_MAX5821) += max5821.o
 obj-$(CONFIG_MCP4725) += mcp4725.o

+ 269 - 0
drivers/iio/dac/m62332.c

@@ -0,0 +1,269 @@
+/*
+ *  m62332.c - Support for Mitsubishi m62332 DAC
+ *
+ *  Copyright (c) 2014 Dmitry Eremin-Solenikov
+ *
+ *  Based on max517 driver:
+ *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ *  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/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+
+#include <linux/regulator/consumer.h>
+
+#define M62332_CHANNELS 2
+
+struct m62332_data {
+	struct i2c_client	*client;
+	u16			vref_mv;
+	struct regulator	*vcc;
+	struct mutex		mutex;
+	u8			raw[M62332_CHANNELS];
+#ifdef CONFIG_PM_SLEEP
+	u8			save[M62332_CHANNELS];
+#endif
+};
+
+static int m62332_set_value(struct iio_dev *indio_dev,
+	u8 val, int channel)
+{
+	struct m62332_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+	u8 outbuf[2];
+	int res;
+
+	if (val == data->raw[channel])
+		return 0;
+
+	outbuf[0] = channel;
+	outbuf[1] = val;
+
+	mutex_lock(&data->mutex);
+
+	if (val) {
+		res = regulator_enable(data->vcc);
+		if (res)
+			goto out;
+	}
+
+	res = i2c_master_send(client, outbuf, 2);
+	if (res >= 0 && res != 2)
+		res = -EIO;
+	if (res < 0)
+		goto out;
+
+	data->raw[channel] = val;
+
+	if (!val)
+		regulator_disable(data->vcc);
+
+	mutex_unlock(&data->mutex);
+
+	return 0;
+
+out:
+	mutex_unlock(&data->mutex);
+
+	return res;
+}
+
+static int m62332_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct m62332_data *data = iio_priv(indio_dev);
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		/* Corresponds to Vref / 2^(bits) */
+		*val = data->vref_mv;
+		*val2 = 8;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	case IIO_CHAN_INFO_RAW:
+		*val = data->raw[chan->channel];
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 1;
+		return IIO_VAL_INT;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int m62332_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val < 0 || val > 255)
+			return -EINVAL;
+
+		ret = m62332_set_value(indio_dev, val, chan->channel);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int m62332_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct m62332_data *data = iio_priv(indio_dev);
+	int ret;
+
+	data->save[0] = data->raw[0];
+	data->save[1] = data->raw[1];
+
+	ret = m62332_set_value(indio_dev, 0, 0);
+	if (ret < 0)
+		return ret;
+
+	return m62332_set_value(indio_dev, 0, 1);
+}
+
+static int m62332_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct m62332_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = m62332_set_value(indio_dev, data->save[0], 0);
+	if (ret < 0)
+		return ret;
+
+	return m62332_set_value(indio_dev, data->save[1], 1);
+}
+
+static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
+#define M62332_PM_OPS (&m62332_pm_ops)
+#else
+#define M62332_PM_OPS NULL
+#endif
+
+static const struct iio_info m62332_info = {
+	.read_raw = m62332_read_raw,
+	.write_raw = m62332_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define M62332_CHANNEL(chan) {				\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.output = 1,					\
+	.channel = (chan),				\
+	.datasheet_name = "CH" #chan,			\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
+		BIT(IIO_CHAN_INFO_SCALE) |		\
+		BIT(IIO_CHAN_INFO_OFFSET),		\
+}
+
+static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
+	M62332_CHANNEL(0),
+	M62332_CHANNEL(1)
+};
+
+static int m62332_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct m62332_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->mutex);
+
+	data->vcc = devm_regulator_get(&client->dev, "VCC");
+	if (IS_ERR(data->vcc))
+		return PTR_ERR(data->vcc);
+
+	/* establish that the iio_dev is a child of the i2c device */
+	indio_dev->dev.parent = &client->dev;
+
+	indio_dev->num_channels = M62332_CHANNELS;
+	indio_dev->channels = m62332_channels;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &m62332_info;
+
+	ret = regulator_get_voltage(data->vcc);
+	if (ret < 0)
+		return ret;
+	data->vref_mv = ret / 1000; /* mV */
+
+	ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+
+err:
+	iio_map_array_unregister(indio_dev);
+	return ret;
+}
+
+static int m62332_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	iio_map_array_unregister(indio_dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id m62332_id[] = {
+	{ "m62332", },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, m62332_id);
+
+static struct i2c_driver m62332_driver = {
+	.driver = {
+		.name	= "m62332",
+		.pm	= M62332_PM_OPS,
+	},
+	.probe		= m62332_probe,
+	.remove		= m62332_remove,
+	.id_table	= m62332_id,
+};
+module_i2c_driver(m62332_driver);
+
+MODULE_AUTHOR("Dmitry Eremin-Solenikov");
+MODULE_DESCRIPTION("M62332 8-bit DAC");
+MODULE_LICENSE("GPL v2");

+ 36 - 31
drivers/iio/gyro/bmg160.c

@@ -108,7 +108,6 @@ struct bmg160_data {
 	int slope_thres;
 	bool dready_trigger_on;
 	bool motion_trigger_on;
-	int64_t timestamp;
 };
 
 enum bmg160_axis {
@@ -738,17 +737,6 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
 	return 0;
 }
 
-static int bmg160_validate_trigger(struct iio_dev *indio_dev,
-				   struct iio_trigger *trig)
-{
-	struct bmg160_data *data = iio_priv(indio_dev);
-
-	if (data->dready_trig != trig && data->motion_trig != trig)
-		return -EINVAL;
-
-	return 0;
-}
-
 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000");
 
 static IIO_CONST_ATTR(in_anglvel_scale_available,
@@ -810,7 +798,6 @@ static const struct iio_info bmg160_info = {
 	.write_event_value	= bmg160_write_event,
 	.write_event_config	= bmg160_write_event_config,
 	.read_event_config	= bmg160_read_event_config,
-	.validate_trigger	= bmg160_validate_trigger,
 	.driver_module		= THIS_MODULE,
 };
 
@@ -835,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
 	mutex_unlock(&data->mutex);
 
 	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
-					   data->timestamp);
+					   pf->timestamp);
 err:
 	iio_trigger_notify_done(indio_dev->trig);
 
@@ -938,21 +925,21 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
 							IIO_MOD_X,
 							IIO_EV_TYPE_ROC,
 							dir),
-							data->timestamp);
+							iio_get_time_ns());
 	if (ret & BMG160_ANY_MOTION_BIT_Y)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 							0,
 							IIO_MOD_Y,
 							IIO_EV_TYPE_ROC,
 							dir),
-							data->timestamp);
+							iio_get_time_ns());
 	if (ret & BMG160_ANY_MOTION_BIT_Z)
 		iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
 							0,
 							IIO_MOD_Z,
 							IIO_EV_TYPE_ROC,
 							dir),
-							data->timestamp);
+							iio_get_time_ns());
 
 ack_intr_status:
 	if (!data->dready_trigger_on) {
@@ -973,8 +960,6 @@ static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private)
 	struct iio_dev *indio_dev = private;
 	struct bmg160_data *data = iio_priv(indio_dev);
 
-	data->timestamp = iio_get_time_ns();
-
 	if (data->dready_trigger_on)
 		iio_trigger_poll(data->dready_trig);
 	else if (data->motion_trigger_on)
@@ -987,6 +972,27 @@ static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private)
 
 }
 
+static int bmg160_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct bmg160_data *data = iio_priv(indio_dev);
+
+	return bmg160_set_power_state(data, true);
+}
+
+static int bmg160_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct bmg160_data *data = iio_priv(indio_dev);
+
+	return bmg160_set_power_state(data, false);
+}
+
+static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
+	.preenable = bmg160_buffer_preenable,
+	.postenable = iio_triggered_buffer_postenable,
+	.predisable = iio_triggered_buffer_predisable,
+	.postdisable = bmg160_buffer_postdisable,
+};
+
 static int bmg160_gpio_probe(struct i2c_client *client,
 			     struct bmg160_data *data)
 
@@ -1103,16 +1109,16 @@ static int bmg160_probe(struct i2c_client *client,
 			data->motion_trig = NULL;
 			goto err_trigger_unregister;
 		}
+	}
 
-		ret = iio_triggered_buffer_setup(indio_dev,
-						 NULL,
-						 bmg160_trigger_handler,
-						 NULL);
-		if (ret < 0) {
-			dev_err(&client->dev,
-				"iio triggered buffer setup failed\n");
-			goto err_trigger_unregister;
-		}
+	ret = iio_triggered_buffer_setup(indio_dev,
+					 iio_pollfunc_store_time,
+					 bmg160_trigger_handler,
+					 &bmg160_buffer_setup_ops);
+	if (ret < 0) {
+		dev_err(&client->dev,
+			"iio triggered buffer setup failed\n");
+		goto err_trigger_unregister;
 	}
 
 	ret = iio_device_register(indio_dev);
@@ -1135,8 +1141,7 @@ static int bmg160_probe(struct i2c_client *client,
 err_iio_unregister:
 	iio_device_unregister(indio_dev);
 err_buffer_cleanup:
-	if (data->dready_trig)
-		iio_triggered_buffer_cleanup(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
 	if (data->dready_trig)
 		iio_trigger_unregister(data->dready_trig);
@@ -1156,9 +1161,9 @@ static int bmg160_remove(struct i2c_client *client)
 	pm_runtime_put_noidle(&client->dev);
 
 	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
 
 	if (data->dready_trig) {
-		iio_triggered_buffer_cleanup(indio_dev);
 		iio_trigger_unregister(data->dready_trig);
 		iio_trigger_unregister(data->motion_trig);
 	}

+ 7 - 8
drivers/iio/gyro/hid-sensor-gyro-3d.c

@@ -298,7 +298,6 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct gyro_3d_state *gyro_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
 	if (!indio_dev)
@@ -317,21 +316,21 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
-			   GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = kmemdup(gyro_3d_channels,
+				      sizeof(gyro_3d_channels), GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = gyro_3d_parse_report(pdev, hsdev, channels,
-					HID_USAGE_SENSOR_GYRO_3D, gyro_state);
+	ret = gyro_3d_parse_report(pdev, hsdev,
+				   (struct iio_chan_spec *)indio_dev->channels,
+				   HID_USAGE_SENSOR_GYRO_3D, gyro_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		goto error_free_dev_mem;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &gyro_3d_info;
@@ -397,7 +396,7 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_gyro_3d_ids[] = {
+static const struct platform_device_id hid_gyro_3d_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200076",

+ 1 - 1
drivers/iio/humidity/Kconfig

@@ -5,7 +5,7 @@ menu "Humidity sensors"
 
 config DHT11
 	tristate "DHT11 (and compatible sensors) driver"
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  This driver supports reading data via a single interrupt
 	  generating GPIO line. Currently tested are DHT11 and DHT22.

+ 205 - 123
drivers/iio/industrialio-buffer.c

@@ -539,26 +539,13 @@ static void iio_buffer_deactivate(struct iio_buffer *buffer)
 	iio_buffer_put(buffer);
 }
 
-void iio_disable_all_buffers(struct iio_dev *indio_dev)
+static void iio_buffer_deactivate_all(struct iio_dev *indio_dev)
 {
 	struct iio_buffer *buffer, *_buffer;
 
-	if (list_empty(&indio_dev->buffer_list))
-		return;
-
-	if (indio_dev->setup_ops->predisable)
-		indio_dev->setup_ops->predisable(indio_dev);
-
 	list_for_each_entry_safe(buffer, _buffer,
 			&indio_dev->buffer_list, buffer_list)
 		iio_buffer_deactivate(buffer);
-
-	indio_dev->currentmode = INDIO_DIRECT_MODE;
-	if (indio_dev->setup_ops->postdisable)
-		indio_dev->setup_ops->postdisable(indio_dev);
-
-	if (indio_dev->available_scan_masks == NULL)
-		kfree(indio_dev->active_scan_mask);
 }
 
 static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
@@ -575,167 +562,256 @@ static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
 	buffer->access->set_bytes_per_datum(buffer, bytes);
 }
 
-static int __iio_update_buffers(struct iio_dev *indio_dev,
-		       struct iio_buffer *insert_buffer,
-		       struct iio_buffer *remove_buffer)
+static int iio_buffer_request_update(struct iio_dev *indio_dev,
+	struct iio_buffer *buffer)
 {
 	int ret;
-	int success = 0;
-	struct iio_buffer *buffer;
-	unsigned long *compound_mask;
-	const unsigned long *old_mask;
 
-	/* Wind down existing buffers - iff there are any */
-	if (!list_empty(&indio_dev->buffer_list)) {
-		if (indio_dev->setup_ops->predisable) {
-			ret = indio_dev->setup_ops->predisable(indio_dev);
-			if (ret)
-				return ret;
-		}
-		indio_dev->currentmode = INDIO_DIRECT_MODE;
-		if (indio_dev->setup_ops->postdisable) {
-			ret = indio_dev->setup_ops->postdisable(indio_dev);
-			if (ret)
-				return ret;
+	iio_buffer_update_bytes_per_datum(indio_dev, buffer);
+	if (buffer->access->request_update) {
+		ret = buffer->access->request_update(buffer);
+		if (ret) {
+			dev_dbg(&indio_dev->dev,
+			       "Buffer not started: buffer parameter update failed (%d)\n",
+				ret);
+			return ret;
 		}
 	}
-	/* Keep a copy of current setup to allow roll back */
-	old_mask = indio_dev->active_scan_mask;
+
+	return 0;
+}
+
+static void iio_free_scan_mask(struct iio_dev *indio_dev,
+	const unsigned long *mask)
+{
+	/* If the mask is dynamically allocated free it, otherwise do nothing */
 	if (!indio_dev->available_scan_masks)
-		indio_dev->active_scan_mask = NULL;
+		kfree(mask);
+}
 
-	if (remove_buffer)
-		iio_buffer_deactivate(remove_buffer);
-	if (insert_buffer)
-		iio_buffer_activate(indio_dev, insert_buffer);
+struct iio_device_config {
+	unsigned int mode;
+	const unsigned long *scan_mask;
+	unsigned int scan_bytes;
+	bool scan_timestamp;
+};
 
-	/* If no buffers in list, we are done */
-	if (list_empty(&indio_dev->buffer_list)) {
-		indio_dev->currentmode = INDIO_DIRECT_MODE;
-		if (indio_dev->available_scan_masks == NULL)
-			kfree(old_mask);
-		return 0;
+static int iio_verify_update(struct iio_dev *indio_dev,
+	struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer,
+	struct iio_device_config *config)
+{
+	unsigned long *compound_mask;
+	const unsigned long *scan_mask;
+	struct iio_buffer *buffer;
+	bool scan_timestamp;
+
+	memset(config, 0, sizeof(*config));
+
+	/*
+	 * If there is just one buffer and we are removing it there is nothing
+	 * to verify.
+	 */
+	if (remove_buffer && !insert_buffer &&
+		list_is_singular(&indio_dev->buffer_list))
+			return 0;
+
+	/* Definitely possible for devices to support both of these. */
+	if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
+		config->mode = INDIO_BUFFER_TRIGGERED;
+	} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+		config->mode = INDIO_BUFFER_HARDWARE;
+	} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
+		config->mode = INDIO_BUFFER_SOFTWARE;
+	} else {
+		/* Can only occur on first buffer */
+		if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+			dev_dbg(&indio_dev->dev, "Buffer not started: no trigger\n");
+		return -EINVAL;
 	}
 
 	/* What scan mask do we actually have? */
 	compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
 				sizeof(long), GFP_KERNEL);
-	if (compound_mask == NULL) {
-		if (indio_dev->available_scan_masks == NULL)
-			kfree(old_mask);
+	if (compound_mask == NULL)
 		return -ENOMEM;
-	}
-	indio_dev->scan_timestamp = 0;
+
+	scan_timestamp = false;
 
 	list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+		if (buffer == remove_buffer)
+			continue;
 		bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
 			  indio_dev->masklength);
-		indio_dev->scan_timestamp |= buffer->scan_timestamp;
+		scan_timestamp |= buffer->scan_timestamp;
+	}
+
+	if (insert_buffer) {
+		bitmap_or(compound_mask, compound_mask,
+			  insert_buffer->scan_mask, indio_dev->masklength);
+		scan_timestamp |= insert_buffer->scan_timestamp;
 	}
+
 	if (indio_dev->available_scan_masks) {
-		indio_dev->active_scan_mask =
-			iio_scan_mask_match(indio_dev->available_scan_masks,
-					    indio_dev->masklength,
-					    compound_mask);
-		if (indio_dev->active_scan_mask == NULL) {
-			/*
-			 * Roll back.
-			 * Note can only occur when adding a buffer.
-			 */
-			iio_buffer_deactivate(insert_buffer);
-			if (old_mask) {
-				indio_dev->active_scan_mask = old_mask;
-				success = -EINVAL;
-			}
-			else {
-				kfree(compound_mask);
-				ret = -EINVAL;
-				return ret;
-			}
-		}
+		scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks,
+				    indio_dev->masklength,
+				    compound_mask);
+		kfree(compound_mask);
+		if (scan_mask == NULL)
+			return -EINVAL;
 	} else {
-		indio_dev->active_scan_mask = compound_mask;
+	    scan_mask = compound_mask;
 	}
 
+	config->scan_bytes = iio_compute_scan_bytes(indio_dev,
+				    scan_mask, scan_timestamp);
+	config->scan_mask = scan_mask;
+	config->scan_timestamp = scan_timestamp;
+
+	return 0;
+}
+
+static int iio_enable_buffers(struct iio_dev *indio_dev,
+	struct iio_device_config *config)
+{
+	int ret;
+
+	indio_dev->active_scan_mask = config->scan_mask;
+	indio_dev->scan_timestamp = config->scan_timestamp;
+	indio_dev->scan_bytes = config->scan_bytes;
+
 	iio_update_demux(indio_dev);
 
 	/* Wind up again */
 	if (indio_dev->setup_ops->preenable) {
 		ret = indio_dev->setup_ops->preenable(indio_dev);
 		if (ret) {
-			printk(KERN_ERR
+			dev_dbg(&indio_dev->dev,
 			       "Buffer not started: buffer preenable failed (%d)\n", ret);
-			goto error_remove_inserted;
-		}
-	}
-	indio_dev->scan_bytes =
-		iio_compute_scan_bytes(indio_dev,
-				       indio_dev->active_scan_mask,
-				       indio_dev->scan_timestamp);
-	list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
-		iio_buffer_update_bytes_per_datum(indio_dev, buffer);
-		if (buffer->access->request_update) {
-			ret = buffer->access->request_update(buffer);
-			if (ret) {
-				printk(KERN_INFO
-				       "Buffer not started: buffer parameter update failed (%d)\n", ret);
-				goto error_run_postdisable;
-			}
+			goto err_undo_config;
 		}
 	}
+
 	if (indio_dev->info->update_scan_mode) {
 		ret = indio_dev->info
 			->update_scan_mode(indio_dev,
 					   indio_dev->active_scan_mask);
 		if (ret < 0) {
-			printk(KERN_INFO "Buffer not started: update scan mode failed (%d)\n", ret);
-			goto error_run_postdisable;
+			dev_dbg(&indio_dev->dev,
+				"Buffer not started: update scan mode failed (%d)\n",
+				ret);
+			goto err_run_postdisable;
 		}
 	}
-	/* Definitely possible for devices to support both of these. */
-	if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
-		indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
-	} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
-		indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
-	} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
-		indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
-	} else { /* Should never be reached */
-		/* Can only occur on first buffer */
-		if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
-			pr_info("Buffer not started: no trigger\n");
-		ret = -EINVAL;
-		goto error_run_postdisable;
-	}
+
+	indio_dev->currentmode = config->mode;
 
 	if (indio_dev->setup_ops->postenable) {
 		ret = indio_dev->setup_ops->postenable(indio_dev);
 		if (ret) {
-			printk(KERN_INFO
+			dev_dbg(&indio_dev->dev,
 			       "Buffer not started: postenable failed (%d)\n", ret);
-			indio_dev->currentmode = INDIO_DIRECT_MODE;
-			if (indio_dev->setup_ops->postdisable)
-				indio_dev->setup_ops->postdisable(indio_dev);
-			goto error_disable_all_buffers;
+			goto err_run_postdisable;
 		}
 	}
 
-	if (indio_dev->available_scan_masks)
-		kfree(compound_mask);
-	else
-		kfree(old_mask);
-
-	return success;
+	return 0;
 
-error_disable_all_buffers:
+err_run_postdisable:
 	indio_dev->currentmode = INDIO_DIRECT_MODE;
-error_run_postdisable:
 	if (indio_dev->setup_ops->postdisable)
 		indio_dev->setup_ops->postdisable(indio_dev);
-error_remove_inserted:
+err_undo_config:
+	indio_dev->active_scan_mask = NULL;
+
+	return ret;
+}
+
+static int iio_disable_buffers(struct iio_dev *indio_dev)
+{
+	int ret = 0;
+	int ret2;
+
+	/* Wind down existing buffers - iff there are any */
+	if (list_empty(&indio_dev->buffer_list))
+		return 0;
+
+	/*
+	 * If things go wrong at some step in disable we still need to continue
+	 * to perform the other steps, otherwise we leave the device in a
+	 * inconsistent state. We return the error code for the first error we
+	 * encountered.
+	 */
+
+	if (indio_dev->setup_ops->predisable) {
+		ret2 = indio_dev->setup_ops->predisable(indio_dev);
+		if (ret2 && !ret)
+			ret = ret2;
+	}
+
+	indio_dev->currentmode = INDIO_DIRECT_MODE;
+
+	if (indio_dev->setup_ops->postdisable) {
+		ret2 = indio_dev->setup_ops->postdisable(indio_dev);
+		if (ret2 && !ret)
+			ret = ret2;
+	}
+
+	iio_free_scan_mask(indio_dev, indio_dev->active_scan_mask);
+	indio_dev->active_scan_mask = NULL;
+
+	return ret;
+}
+
+static int __iio_update_buffers(struct iio_dev *indio_dev,
+		       struct iio_buffer *insert_buffer,
+		       struct iio_buffer *remove_buffer)
+{
+	struct iio_device_config new_config;
+	int ret;
+
+	ret = iio_verify_update(indio_dev, insert_buffer, remove_buffer,
+		&new_config);
+	if (ret)
+		return ret;
+
+	if (insert_buffer) {
+		ret = iio_buffer_request_update(indio_dev, insert_buffer);
+		if (ret)
+			goto err_free_config;
+	}
+
+	ret = iio_disable_buffers(indio_dev);
+	if (ret)
+		goto err_deactivate_all;
+
+	if (remove_buffer)
+		iio_buffer_deactivate(remove_buffer);
 	if (insert_buffer)
-		iio_buffer_deactivate(insert_buffer);
-	indio_dev->active_scan_mask = old_mask;
-	kfree(compound_mask);
+		iio_buffer_activate(indio_dev, insert_buffer);
+
+	/* If no buffers in list, we are done */
+	if (list_empty(&indio_dev->buffer_list))
+		return 0;
+
+	ret = iio_enable_buffers(indio_dev, &new_config);
+	if (ret)
+		goto err_deactivate_all;
+
+	return 0;
+
+err_deactivate_all:
+	/*
+	 * We've already verified that the config is valid earlier. If things go
+	 * wrong in either enable or disable the most likely reason is an IO
+	 * error from the device. In this case there is no good recovery
+	 * strategy. Just make sure to disable everything and leave the device
+	 * in a sane state.  With a bit of luck the device might come back to
+	 * life again later and userspace can try again.
+	 */
+	iio_buffer_deactivate_all(indio_dev);
+
+err_free_config:
+	iio_free_scan_mask(indio_dev, new_config.scan_mask);
 	return ret;
 }
 
@@ -777,6 +853,12 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(iio_update_buffers);
 
+void iio_disable_all_buffers(struct iio_dev *indio_dev)
+{
+	iio_disable_buffers(indio_dev);
+	iio_buffer_deactivate_all(indio_dev);
+}
+
 static ssize_t iio_buffer_store_enable(struct device *dev,
 				       struct device_attribute *attr,
 				       const char *buf,

+ 5 - 0
drivers/iio/industrialio-core.c

@@ -101,6 +101,8 @@ static const char * const iio_modifier_names[] = {
 	[IIO_MOD_WALKING] = "walking",
 	[IIO_MOD_STILL] = "still",
 	[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
+	[IIO_MOD_I] = "i",
+	[IIO_MOD_Q] = "q",
 };
 
 /* relies on pairs of these shared then separate */
@@ -117,6 +119,8 @@ static const char * const iio_chan_info_postfix[] = {
 	[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
 	[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
 	= "filter_low_pass_3db_frequency",
+	[IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY]
+	= "filter_high_pass_3db_frequency",
 	[IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
 	[IIO_CHAN_INFO_FREQUENCY] = "frequency",
 	[IIO_CHAN_INFO_PHASE] = "phase",
@@ -129,6 +133,7 @@ static const char * const iio_chan_info_postfix[] = {
 	[IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count",
 	[IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
 	[IIO_CHAN_INFO_CALIBEMISSIVITY] = "calibemissivity",
+	[IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio",
 };
 
 /**

+ 2 - 0
drivers/iio/industrialio-event.c

@@ -211,6 +211,8 @@ static const char * const iio_ev_info_text[] = {
 	[IIO_EV_INFO_VALUE] = "value",
 	[IIO_EV_INFO_HYSTERESIS] = "hysteresis",
 	[IIO_EV_INFO_PERIOD] = "period",
+	[IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db",
+	[IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db",
 };
 
 static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)

+ 34 - 0
drivers/iio/light/Kconfig

@@ -5,6 +5,19 @@
 
 menu "Light sensors"
 
+config ACPI_ALS
+	tristate "ACPI Ambient Light Sensor"
+	depends on ACPI
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	select IIO_KFIFO_BUF
+	help
+	 Say Y here if you want to build a driver for the ACPI0008
+	 Ambient Light Sensor.
+
+	 To compile this driver as a module, choose M here: the module will
+	 be called acpi-als.
+
 config ADJD_S311
 	tristate "ADJD-S311-CR999 digital color sensor"
 	select IIO_BUFFER
@@ -37,6 +50,16 @@ config APDS9300
 	 To compile this driver as a module, choose M here: the
 	 module will be called apds9300.
 
+config BH1750
+	tristate "ROHM BH1750 ambient light sensor"
+	depends on I2C
+	help
+	 Say Y here to build support for the ROHM BH1710, BH1715, BH1721,
+	 BH1750, BH1751 ambient light sensors.
+
+	 To compile this driver as a module, choose M here: the module will
+	 be called bh1750.
+
 config CM32181
 	depends on I2C
 	tristate "CM32181 driver"
@@ -175,6 +198,17 @@ config LTR501
 	 This driver can also be built as a module.  If so, the module
          will be called ltr501.
 
+config STK3310
+	tristate "STK3310 ALS and proximity sensor"
+	depends on I2C
+	help
+	 Say yes here to get support for the Sensortek STK3310 ambient light
+	 and proximity sensor. The STK3311 model is also supported by this
+	 driver.
+
+	 Choosing M will build the driver as a module. If so, the module
+	 will be called stk3310.
+
 config TCS3414
 	tristate "TAOS TCS3414 digital color sensor"
 	depends on I2C

+ 3 - 0
drivers/iio/light/Makefile

@@ -3,9 +3,11 @@
 #
 
 # When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_ACPI_ALS)		+= acpi-als.o
 obj-$(CONFIG_ADJD_S311)		+= adjd_s311.o
 obj-$(CONFIG_AL3320A)		+= al3320a.o
 obj-$(CONFIG_APDS9300)		+= apds9300.o
+obj-$(CONFIG_BH1750)		+= bh1750.o
 obj-$(CONFIG_CM32181)		+= cm32181.o
 obj-$(CONFIG_CM3232)		+= cm3232.o
 obj-$(CONFIG_CM3323)		+= cm3323.o
@@ -18,6 +20,7 @@ obj-$(CONFIG_JSA1212)		+= jsa1212.o
 obj-$(CONFIG_SENSORS_LM3533)	+= lm3533-als.o
 obj-$(CONFIG_LTR501)		+= ltr501.o
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
+obj-$(CONFIG_STK3310)          += stk3310.o
 obj-$(CONFIG_TCS3414)		+= tcs3414.o
 obj-$(CONFIG_TCS3472)		+= tcs3472.o
 obj-$(CONFIG_TSL4531)		+= tsl4531.o

+ 231 - 0
drivers/iio/light/acpi-als.c

@@ -0,0 +1,231 @@
+/*
+ * ACPI Ambient Light Sensor Driver
+ *
+ * Based on ALS driver:
+ * Copyright (C) 2009 Zhang Rui <rui.zhang@intel.com>
+ *
+ * Rework for IIO subsystem:
+ * Copyright (C) 2012-2013 Martin Liska <marxin.liska@gmail.com>
+ *
+ * Final cleanup and debugging:
+ * Copyright (C) 2013-2014 Marek Vasut <marex@denx.de>
+ * Copyright (C) 2015 Gabriele Mazzotta <gabriele.mzt@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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#define ACPI_ALS_CLASS			"als"
+#define ACPI_ALS_DEVICE_NAME		"acpi-als"
+#define ACPI_ALS_NOTIFY_ILLUMINANCE	0x80
+
+ACPI_MODULE_NAME("acpi-als");
+
+/*
+ * So far, there's only one channel in here, but the specification for
+ * ACPI0008 says there can be more to what the block can report. Like
+ * chromaticity and such. We are ready for incoming additions!
+ */
+static const struct iio_chan_spec acpi_als_channels[] = {
+	{
+		.type		= IIO_LIGHT,
+		.scan_type	= {
+			.sign		= 's',
+			.realbits	= 32,
+			.storagebits	= 32,
+		},
+		.info_mask_separate	= BIT(IIO_CHAN_INFO_RAW),
+	},
+};
+
+/*
+ * The event buffer contains timestamp and all the data from
+ * the ACPI0008 block. There are multiple, but so far we only
+ * support _ALI (illuminance). Once someone adds new channels
+ * to acpi_als_channels[], the evt_buffer below will grow
+ * automatically.
+ */
+#define EVT_NR_SOURCES		ARRAY_SIZE(acpi_als_channels)
+#define EVT_BUFFER_SIZE		\
+	(sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32)))
+
+struct acpi_als {
+	struct acpi_device	*device;
+	struct mutex		lock;
+
+	s32			evt_buffer[EVT_BUFFER_SIZE];
+};
+
+/*
+ * All types of properties the ACPI0008 block can report. The ALI, ALC, ALT
+ * and ALP can all be handled by als_read_value() below, while the ALR is
+ * special.
+ *
+ * The _ALR property returns tables that can be used to fine-tune the values
+ * reported by the other props based on the particular hardware type and it's
+ * location (it contains tables for "rainy", "bright inhouse lighting" etc.).
+ *
+ * So far, we support only ALI (illuminance).
+ */
+#define ACPI_ALS_ILLUMINANCE	"_ALI"
+#define ACPI_ALS_CHROMATICITY	"_ALC"
+#define ACPI_ALS_COLOR_TEMP	"_ALT"
+#define ACPI_ALS_POLLING	"_ALP"
+#define ACPI_ALS_TABLES		"_ALR"
+
+static int als_read_value(struct acpi_als *als, char *prop, s32 *val)
+{
+	unsigned long long temp_val;
+	acpi_status status;
+
+	status = acpi_evaluate_integer(als->device->handle, prop, NULL,
+				       &temp_val);
+
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Error reading ALS %s", prop));
+		return -EIO;
+	}
+
+	*val = temp_val;
+
+	return 0;
+}
+
+static void acpi_als_notify(struct acpi_device *device, u32 event)
+{
+	struct iio_dev *indio_dev = acpi_driver_data(device);
+	struct acpi_als *als = iio_priv(indio_dev);
+	s32 *buffer = als->evt_buffer;
+	s64 time_ns = iio_get_time_ns();
+	s32 val;
+	int ret;
+
+	mutex_lock(&als->lock);
+
+	memset(buffer, 0, EVT_BUFFER_SIZE);
+
+	switch (event) {
+	case ACPI_ALS_NOTIFY_ILLUMINANCE:
+		ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
+		if (ret < 0)
+			goto out;
+		*buffer++ = val;
+		break;
+	default:
+		/* Unhandled event */
+		dev_dbg(&device->dev, "Unhandled ACPI ALS event (%08x)!\n",
+			event);
+		goto out;
+	}
+
+	iio_push_to_buffers_with_timestamp(indio_dev, als->evt_buffer, time_ns);
+
+out:
+	mutex_unlock(&als->lock);
+}
+
+static int acpi_als_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int *val,
+			     int *val2, long mask)
+{
+	struct acpi_als *als = iio_priv(indio_dev);
+	s32 temp_val;
+	int ret;
+
+	if (mask != IIO_CHAN_INFO_RAW)
+		return -EINVAL;
+
+	/* we support only illumination (_ALI) so far. */
+	if (chan->type != IIO_LIGHT)
+		return -EINVAL;
+
+	ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
+	if (ret < 0)
+		return ret;
+
+	*val = temp_val;
+
+	return IIO_VAL_INT;
+}
+
+static const struct iio_info acpi_als_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= acpi_als_read_raw,
+};
+
+static int acpi_als_add(struct acpi_device *device)
+{
+	struct acpi_als *als;
+	struct iio_dev *indio_dev;
+	struct iio_buffer *buffer;
+
+	indio_dev = devm_iio_device_alloc(&device->dev, sizeof(*als));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	als = iio_priv(indio_dev);
+
+	device->driver_data = indio_dev;
+	als->device = device;
+	mutex_init(&als->lock);
+
+	indio_dev->name = ACPI_ALS_DEVICE_NAME;
+	indio_dev->dev.parent = &device->dev;
+	indio_dev->info = &acpi_als_info;
+	indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+	indio_dev->channels = acpi_als_channels;
+	indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels);
+
+	buffer = devm_iio_kfifo_allocate(&device->dev);
+	if (!buffer)
+		return -ENOMEM;
+
+	iio_device_attach_buffer(indio_dev, buffer);
+
+	return devm_iio_device_register(&device->dev, indio_dev);
+}
+
+static const struct acpi_device_id acpi_als_device_ids[] = {
+	{"ACPI0008", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids);
+
+static struct acpi_driver acpi_als_driver = {
+	.name	= "acpi_als",
+	.class	= ACPI_ALS_CLASS,
+	.ids	= acpi_als_device_ids,
+	.ops = {
+		.add	= acpi_als_add,
+		.notify	= acpi_als_notify,
+	},
+};
+
+module_acpi_driver(acpi_als_driver);
+
+MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
+MODULE_AUTHOR("Martin Liska <marxin.liska@gmail.com>");
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("ACPI Ambient Light Sensor Driver");
+MODULE_LICENSE("GPL");

+ 334 - 0
drivers/iio/light/bh1750.c

@@ -0,0 +1,334 @@
+/*
+ * ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
+ *
+ * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
+ *
+ * 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.
+ *
+ * Data sheets:
+ *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
+ *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
+ *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1721fvc-e.pdf
+ *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
+ *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1751fvi-e.pdf
+ *
+ * 7-bit I2C slave addresses:
+ *  0x23 (ADDR pin low)
+ *  0x5C (ADDR pin high)
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+
+#define BH1750_POWER_DOWN		0x00
+#define BH1750_ONE_TIME_H_RES_MODE	0x20 /* auto-mode for BH1721 */
+#define BH1750_CHANGE_INT_TIME_H_BIT	0x40
+#define BH1750_CHANGE_INT_TIME_L_BIT	0x60
+
+enum {
+	BH1710,
+	BH1721,
+	BH1750,
+};
+
+struct bh1750_chip_info;
+struct bh1750_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	const struct bh1750_chip_info *chip_info;
+	u16 mtreg;
+};
+
+struct bh1750_chip_info {
+	u16 mtreg_min;
+	u16 mtreg_max;
+	u16 mtreg_default;
+	int mtreg_to_usec;
+	int mtreg_to_scale;
+
+	/*
+	 * For BH1710/BH1721 all possible integration time values won't fit
+	 * into one page so displaying is limited to every second one.
+	 * Note, that user can still write proper values which were not
+	 * listed.
+	 */
+	int inc;
+
+	u16 int_time_low_mask;
+	u16 int_time_high_mask;
+}
+
+static const bh1750_chip_info_tbl[] = {
+	[BH1710] = { 140, 1022, 300, 400,  250000000, 2, 0x001F, 0x03E0 },
+	[BH1721] = { 140, 1020, 300, 400,  250000000, 2, 0x0010, 0x03E0 },
+	[BH1750] = { 31,  254,  69,  1740, 57500000,  1, 0x001F, 0x00E0 },
+};
+
+static int bh1750_change_int_time(struct bh1750_data *data, int usec)
+{
+	int ret;
+	u16 val;
+	u8 regval;
+	const struct bh1750_chip_info *chip_info = data->chip_info;
+
+	if ((usec % chip_info->mtreg_to_usec) != 0)
+		return -EINVAL;
+
+	val = usec / chip_info->mtreg_to_usec;
+	if (val < chip_info->mtreg_min || val > chip_info->mtreg_max)
+		return -EINVAL;
+
+	ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
+	if (ret < 0)
+		return ret;
+
+	regval = (val & chip_info->int_time_high_mask) >> 5;
+	ret = i2c_smbus_write_byte(data->client,
+				   BH1750_CHANGE_INT_TIME_H_BIT | regval);
+	if (ret < 0)
+		return ret;
+
+	regval = val & chip_info->int_time_low_mask;
+	ret = i2c_smbus_write_byte(data->client,
+				   BH1750_CHANGE_INT_TIME_L_BIT | regval);
+	if (ret < 0)
+		return ret;
+
+	data->mtreg = val;
+
+	return 0;
+}
+
+static int bh1750_read(struct bh1750_data *data, int *val)
+{
+	int ret;
+	__be16 result;
+	const struct bh1750_chip_info *chip_info = data->chip_info;
+	unsigned long delay = chip_info->mtreg_to_usec * data->mtreg;
+
+	/*
+	 * BH1721 will enter continuous mode on receiving this command.
+	 * Note, that this eliminates need for bh1750_resume().
+	 */
+	ret = i2c_smbus_write_byte(data->client, BH1750_ONE_TIME_H_RES_MODE);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(delay + 15000, delay + 40000);
+
+	ret = i2c_master_recv(data->client, (char *)&result, 2);
+	if (ret < 0)
+		return ret;
+
+	*val = be16_to_cpu(result);
+
+	return 0;
+}
+
+static int bh1750_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	int ret, tmp;
+	struct bh1750_data *data = iio_priv(indio_dev);
+	const struct bh1750_chip_info *chip_info = data->chip_info;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (chan->type) {
+		case IIO_LIGHT:
+			mutex_lock(&data->lock);
+			ret = bh1750_read(data, val);
+			mutex_unlock(&data->lock);
+			if (ret < 0)
+				return ret;
+
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	case IIO_CHAN_INFO_SCALE:
+		tmp = chip_info->mtreg_to_scale / data->mtreg;
+		*val = tmp / 1000000;
+		*val2 = tmp % 1000000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_INT_TIME:
+		*val = 0;
+		*val2 = chip_info->mtreg_to_usec * data->mtreg;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bh1750_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val, int val2, long mask)
+{
+	int ret;
+	struct bh1750_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		if (val != 0)
+			return -EINVAL;
+
+		mutex_lock(&data->lock);
+		ret = bh1750_change_int_time(data, val2);
+		mutex_unlock(&data->lock);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t bh1750_show_int_time_available(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int i;
+	size_t len = 0;
+	struct bh1750_data *data = iio_priv(dev_to_iio_dev(dev));
+	const struct bh1750_chip_info *chip_info = data->chip_info;
+
+	for (i = chip_info->mtreg_min; i <= chip_info->mtreg_max; i += chip_info->inc)
+		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06d ",
+				 chip_info->mtreg_to_usec * i);
+
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static IIO_DEV_ATTR_INT_TIME_AVAIL(bh1750_show_int_time_available);
+
+static struct attribute *bh1750_attributes[] = {
+	&iio_dev_attr_integration_time_available.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group bh1750_attribute_group = {
+	.attrs = bh1750_attributes,
+};
+
+static const struct iio_info bh1750_info = {
+	.driver_module = THIS_MODULE,
+	.attrs = &bh1750_attribute_group,
+	.read_raw = bh1750_read_raw,
+	.write_raw = bh1750_write_raw,
+};
+
+static const struct iio_chan_spec bh1750_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE) |
+				      BIT(IIO_CHAN_INFO_INT_TIME)
+	}
+};
+
+static int bh1750_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int ret, usec;
+	struct bh1750_data *data;
+	struct iio_dev *indio_dev;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+				I2C_FUNC_SMBUS_WRITE_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->chip_info = &bh1750_chip_info_tbl[id->driver_data];
+
+	usec = data->chip_info->mtreg_to_usec * data->chip_info->mtreg_default;
+	ret = bh1750_change_int_time(data, usec);
+	if (ret < 0)
+		return ret;
+
+	mutex_init(&data->lock);
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &bh1750_info;
+	indio_dev->name = id->name;
+	indio_dev->channels = bh1750_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bh1750_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	return iio_device_register(indio_dev);
+}
+
+static int bh1750_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bh1750_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	mutex_lock(&data->lock);
+	i2c_smbus_write_byte(client, BH1750_POWER_DOWN);
+	mutex_unlock(&data->lock);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bh1750_suspend(struct device *dev)
+{
+	int ret;
+	struct bh1750_data *data =
+		iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	/*
+	 * This is mainly for BH1721 which doesn't enter power down
+	 * mode automatically.
+	 */
+	mutex_lock(&data->lock);
+	ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
+#define BH1750_PM_OPS (&bh1750_pm_ops)
+#else
+#define BH1750_PM_OPS NULL
+#endif
+
+static const struct i2c_device_id bh1750_id[] = {
+	{ "bh1710", BH1710 },
+	{ "bh1715", BH1750 },
+	{ "bh1721", BH1721 },
+	{ "bh1750", BH1750 },
+	{ "bh1751", BH1750 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, bh1750_id);
+
+static struct i2c_driver bh1750_driver = {
+	.driver = {
+		.name = "bh1750",
+		.owner = THIS_MODULE,
+		.pm = BH1750_PM_OPS,
+	},
+	.probe = bh1750_probe,
+	.remove = bh1750_remove,
+	.id_table = bh1750_id,
+
+};
+module_i2c_driver(bh1750_driver);
+
+MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
+MODULE_DESCRIPTION("ROHM BH1710/BH1715/BH1721/BH1750/BH1751 als driver");
+MODULE_LICENSE("GPL v2");

+ 7 - 7
drivers/iio/light/hid-sensor-als.c

@@ -263,7 +263,6 @@ static int hid_als_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct als_state *als_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
 	if (!indio_dev)
@@ -281,20 +280,21 @@ static int hid_als_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = kmemdup(als_channels,
+				      sizeof(als_channels), GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = als_parse_report(pdev, hsdev, channels,
-				HID_USAGE_SENSOR_ALS, als_state);
+	ret = als_parse_report(pdev, hsdev,
+			       (struct iio_chan_spec *)indio_dev->channels,
+			       HID_USAGE_SENSOR_ALS, als_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		goto error_free_dev_mem;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels =
 				ARRAY_SIZE(als_channels);
 	indio_dev->dev.parent = &pdev->dev;
@@ -361,7 +361,7 @@ static int hid_als_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_als_ids[] = {
+static const struct platform_device_id hid_als_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200041",

+ 1 - 1
drivers/iio/light/hid-sensor-prox.c

@@ -350,7 +350,7 @@ static int hid_prox_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_prox_ids[] = {
+static const struct platform_device_id hid_prox_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200011",

+ 52 - 1
drivers/iio/light/ltr501.c

@@ -66,6 +66,9 @@
 
 #define LTR501_REGMAP_NAME "ltr501_regmap"
 
+#define LTR501_LUX_CONV(vis_coeff, vis_data, ir_coeff, ir_data) \
+			((vis_coeff * vis_data) - (ir_coeff * ir_data))
+
 static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
 
 static const struct reg_field reg_field_it =
@@ -298,6 +301,29 @@ static int ltr501_ps_read_samp_period(struct ltr501_data *data, int *val)
 	return IIO_VAL_INT;
 }
 
+/* IR and visible spectrum coeff's are given in data sheet */
+static unsigned long ltr501_calculate_lux(u16 vis_data, u16 ir_data)
+{
+	unsigned long ratio, lux;
+
+	if (vis_data == 0)
+		return 0;
+
+	/* multiply numerator by 100 to avoid handling ratio < 1 */
+	ratio = DIV_ROUND_UP(ir_data * 100, ir_data + vis_data);
+
+	if (ratio < 45)
+		lux = LTR501_LUX_CONV(1774, vis_data, -1105, ir_data);
+	else if (ratio >= 45 && ratio < 64)
+		lux = LTR501_LUX_CONV(3772, vis_data, 1336, ir_data);
+	else if (ratio >= 64 && ratio < 85)
+		lux = LTR501_LUX_CONV(1690, vis_data, 169, ir_data);
+	else
+		lux = 0;
+
+	return lux / 1000;
+}
+
 static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
 {
 	int tries = 100;
@@ -548,7 +574,14 @@ static const struct iio_event_spec ltr501_pxs_event_spec[] = {
 	.num_event_specs = _evsize,\
 }
 
+#define LTR501_LIGHT_CHANNEL() { \
+	.type = IIO_LIGHT, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+	.scan_index = -1, \
+}
+
 static const struct iio_chan_spec ltr501_channels[] = {
+	LTR501_LIGHT_CHANNEL(),
 	LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0,
 				 ltr501_als_event_spec,
 				 ARRAY_SIZE(ltr501_als_event_spec)),
@@ -576,6 +609,7 @@ static const struct iio_chan_spec ltr501_channels[] = {
 };
 
 static const struct iio_chan_spec ltr301_channels[] = {
+	LTR501_LIGHT_CHANNEL(),
 	LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0,
 				 ltr501_als_event_spec,
 				 ARRAY_SIZE(ltr501_als_event_spec)),
@@ -596,6 +630,23 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
 	int ret, i;
 
 	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		if (iio_buffer_enabled(indio_dev))
+			return -EBUSY;
+
+		switch (chan->type) {
+		case IIO_LIGHT:
+			mutex_lock(&data->lock_als);
+			ret = ltr501_read_als(data, buf);
+			mutex_unlock(&data->lock_als);
+			if (ret < 0)
+				return ret;
+			*val = ltr501_calculate_lux(le16_to_cpu(buf[1]),
+						    le16_to_cpu(buf[0]));
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
 	case IIO_CHAN_INFO_RAW:
 		if (iio_buffer_enabled(indio_dev))
 			return -EBUSY;
@@ -865,9 +916,9 @@ static int ltr501_write_thresh(struct iio_dev *indio_dev,
 			return -EINVAL;
 		}
 	case IIO_PROXIMITY:
-		switch (dir) {
 		if (val > LTR501_PS_THRESH_MASK)
 			return -EINVAL;
+		switch (dir) {
 		case IIO_EV_DIR_RISING:
 			mutex_lock(&data->lock_ps);
 			ret = regmap_bulk_write(data->regmap,

+ 722 - 0
drivers/iio/light/stk3310.c

@@ -0,0 +1,722 @@
+/**
+ * Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define STK3310_REG_STATE			0x00
+#define STK3310_REG_PSCTRL			0x01
+#define STK3310_REG_ALSCTRL			0x02
+#define STK3310_REG_INT				0x04
+#define STK3310_REG_THDH_PS			0x06
+#define STK3310_REG_THDL_PS			0x08
+#define STK3310_REG_FLAG			0x10
+#define STK3310_REG_PS_DATA_MSB			0x11
+#define STK3310_REG_PS_DATA_LSB			0x12
+#define STK3310_REG_ALS_DATA_MSB		0x13
+#define STK3310_REG_ALS_DATA_LSB		0x14
+#define STK3310_REG_ID				0x3E
+#define STK3310_MAX_REG				0x80
+
+#define STK3310_STATE_EN_PS			0x01
+#define STK3310_STATE_EN_ALS			0x02
+#define STK3310_STATE_STANDBY			0x00
+
+#define STK3310_CHIP_ID_VAL			0x13
+#define STK3311_CHIP_ID_VAL			0x1D
+#define STK3310_PSINT_EN			0x01
+#define STK3310_PS_MAX_VAL			0xFFFF
+#define STK3310_THRESH_MAX			0xFFFF
+
+#define STK3310_DRIVER_NAME			"stk3310"
+#define STK3310_REGMAP_NAME			"stk3310_regmap"
+#define STK3310_EVENT				"stk3310_event"
+#define STK3310_GPIO				"stk3310_gpio"
+
+#define STK3310_SCALE_AVAILABLE			"6.4 1.6 0.4 0.1"
+
+#define STK3310_IT_AVAILABLE \
+	"0.000185 0.000370 0.000741 0.001480 0.002960 0.005920 0.011840 " \
+	"0.023680 0.047360 0.094720 0.189440 0.378880 0.757760 1.515520 " \
+	"3.031040 6.062080"
+
+#define STK3310_REGFIELD(name)						    \
+	do {								    \
+		data->reg_##name =					    \
+			devm_regmap_field_alloc(&client->dev, regmap,	    \
+				stk3310_reg_field_##name);		    \
+		if (IS_ERR(data->reg_##name)) {				    \
+			dev_err(&client->dev, "reg field alloc failed.\n"); \
+			return PTR_ERR(data->reg_##name);		    \
+		}							    \
+	} while (0)
+
+static const struct reg_field stk3310_reg_field_state =
+				REG_FIELD(STK3310_REG_STATE, 0, 2);
+static const struct reg_field stk3310_reg_field_als_gain =
+				REG_FIELD(STK3310_REG_ALSCTRL, 4, 5);
+static const struct reg_field stk3310_reg_field_ps_gain =
+				REG_FIELD(STK3310_REG_PSCTRL, 4, 5);
+static const struct reg_field stk3310_reg_field_als_it =
+				REG_FIELD(STK3310_REG_ALSCTRL, 0, 3);
+static const struct reg_field stk3310_reg_field_ps_it =
+				REG_FIELD(STK3310_REG_PSCTRL, 0, 3);
+static const struct reg_field stk3310_reg_field_int_ps =
+				REG_FIELD(STK3310_REG_INT, 0, 2);
+static const struct reg_field stk3310_reg_field_flag_psint =
+				REG_FIELD(STK3310_REG_FLAG, 4, 4);
+static const struct reg_field stk3310_reg_field_flag_nf =
+				REG_FIELD(STK3310_REG_FLAG, 0, 0);
+/*
+ * Maximum PS values with regard to scale. Used to export the 'inverse'
+ * PS value (high values for far objects, low values for near objects).
+ */
+static const int stk3310_ps_max[4] = {
+	STK3310_PS_MAX_VAL / 64,
+	STK3310_PS_MAX_VAL / 16,
+	STK3310_PS_MAX_VAL /  4,
+	STK3310_PS_MAX_VAL,
+};
+
+static const int stk3310_scale_table[][2] = {
+	{6, 400000}, {1, 600000}, {0, 400000}, {0, 100000}
+};
+
+/* Integration time in seconds, microseconds */
+static const int stk3310_it_table[][2] = {
+	{0, 185},	{0, 370},	{0, 741},	{0, 1480},
+	{0, 2960},	{0, 5920},	{0, 11840},	{0, 23680},
+	{0, 47360},	{0, 94720},	{0, 189440},	{0, 378880},
+	{0, 757760},	{1, 515520},	{3, 31040},	{6, 62080},
+};
+
+struct stk3310_data {
+	struct i2c_client *client;
+	struct mutex lock;
+	bool als_enabled;
+	bool ps_enabled;
+	u64 timestamp;
+	struct regmap *regmap;
+	struct regmap_field *reg_state;
+	struct regmap_field *reg_als_gain;
+	struct regmap_field *reg_ps_gain;
+	struct regmap_field *reg_als_it;
+	struct regmap_field *reg_ps_it;
+	struct regmap_field *reg_int_ps;
+	struct regmap_field *reg_flag_psint;
+	struct regmap_field *reg_flag_nf;
+};
+
+static const struct iio_event_spec stk3310_events[] = {
+	/* Proximity event */
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
+				 BIT(IIO_EV_INFO_ENABLE),
+	},
+	/* Out-of-proximity event */
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
+				 BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+static const struct iio_chan_spec stk3310_channels[] = {
+	{
+		.type = IIO_LIGHT,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME),
+	},
+	{
+		.type = IIO_PROXIMITY,
+		.info_mask_separate =
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE) |
+			BIT(IIO_CHAN_INFO_INT_TIME),
+		.event_spec = stk3310_events,
+		.num_event_specs = ARRAY_SIZE(stk3310_events),
+	}
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE);
+
+static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE);
+
+static IIO_CONST_ATTR(in_illuminance_integration_time_available,
+		      STK3310_IT_AVAILABLE);
+
+static IIO_CONST_ATTR(in_proximity_integration_time_available,
+		      STK3310_IT_AVAILABLE);
+
+static struct attribute *stk3310_attributes[] = {
+	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+	&iio_const_attr_in_proximity_scale_available.dev_attr.attr,
+	&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
+	&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group stk3310_attribute_group = {
+	.attrs = stk3310_attributes
+};
+
+static int stk3310_get_index(const int table[][2], int table_size,
+			     int val, int val2)
+{
+	int i;
+
+	for (i = 0; i < table_size; i++) {
+		if (val == table[i][0] && val2 == table[i][1])
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int stk3310_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;
+	unsigned int index;
+	struct stk3310_data *data = iio_priv(indio_dev);
+
+	if (info != IIO_EV_INFO_VALUE)
+		return -EINVAL;
+
+	/*
+	 * Only proximity interrupts are implemented at the moment.
+	 * Since we're inverting proximity values, the sensor's 'high'
+	 * threshold will become our 'low' threshold, associated with
+	 * 'near' events. Similarly, the sensor's 'low' threshold will
+	 * be our 'high' threshold, associated with 'far' events.
+	 */
+	if (dir == IIO_EV_DIR_RISING)
+		reg = STK3310_REG_THDL_PS;
+	else if (dir == IIO_EV_DIR_FALLING)
+		reg = STK3310_REG_THDH_PS;
+	else
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+	mutex_unlock(&data->lock);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "register read failed\n");
+		return ret;
+	}
+	regmap_field_read(data->reg_ps_gain, &index);
+	*val = swab16(stk3310_ps_max[index] - buf);
+
+	return IIO_VAL_INT;
+}
+
+static int stk3310_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;
+	unsigned int index;
+	struct stk3310_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	regmap_field_read(data->reg_ps_gain, &index);
+	if (val > stk3310_ps_max[index])
+		return -EINVAL;
+
+	if (dir == IIO_EV_DIR_RISING)
+		reg = STK3310_REG_THDL_PS;
+	else if (dir == IIO_EV_DIR_FALLING)
+		reg = STK3310_REG_THDH_PS;
+	else
+		return -EINVAL;
+
+	buf = swab16(stk3310_ps_max[index] - val);
+	ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
+	if (ret < 0)
+		dev_err(&client->dev, "failed to set PS threshold!\n");
+
+	return ret;
+}
+
+static int stk3310_read_event_config(struct iio_dev *indio_dev,
+				     const struct iio_chan_spec *chan,
+				     enum iio_event_type type,
+				     enum iio_event_direction dir)
+{
+	unsigned int event_val;
+	struct stk3310_data *data = iio_priv(indio_dev);
+
+	regmap_field_read(data->reg_int_ps, &event_val);
+
+	return event_val;
+}
+
+static int stk3310_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)
+{
+	int ret;
+	struct stk3310_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	if (state < 0 || state > 7)
+		return -EINVAL;
+
+	/* Set INT_PS value */
+	mutex_lock(&data->lock);
+	ret = regmap_field_write(data->reg_int_ps, state);
+	if (ret < 0)
+		dev_err(&client->dev, "failed to set interrupt mode\n");
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int stk3310_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int *val, int *val2, long mask)
+{
+	u8 reg;
+	u16 buf;
+	int ret;
+	unsigned int index;
+	struct stk3310_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (chan->type == IIO_LIGHT)
+			reg = STK3310_REG_ALS_DATA_MSB;
+		else if (chan->type == IIO_PROXIMITY)
+			reg = STK3310_REG_PS_DATA_MSB;
+		else
+			return -EINVAL;
+		mutex_lock(&data->lock);
+		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
+		if (ret < 0) {
+			dev_err(&client->dev, "register read failed\n");
+			mutex_unlock(&data->lock);
+			return ret;
+		}
+		*val = swab16(buf);
+		if (chan->type == IIO_PROXIMITY) {
+			/*
+			 * Invert the proximity data so we return low values
+			 * for close objects and high values for far ones.
+			 */
+			regmap_field_read(data->reg_ps_gain, &index);
+			*val = stk3310_ps_max[index] - *val;
+		}
+		mutex_unlock(&data->lock);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_INT_TIME:
+		if (chan->type == IIO_LIGHT)
+			regmap_field_read(data->reg_als_it, &index);
+		else
+			regmap_field_read(data->reg_ps_it, &index);
+		*val = stk3310_it_table[index][0];
+		*val2 = stk3310_it_table[index][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type == IIO_LIGHT)
+			regmap_field_read(data->reg_als_gain, &index);
+		else
+			regmap_field_read(data->reg_ps_gain, &index);
+		*val = stk3310_scale_table[index][0];
+		*val2 = stk3310_scale_table[index][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+
+	return -EINVAL;
+}
+
+static int stk3310_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan,
+			     int val, int val2, long mask)
+{
+	int ret;
+	unsigned int index;
+	struct stk3310_data *data = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_INT_TIME:
+		index = stk3310_get_index(stk3310_it_table,
+					  ARRAY_SIZE(stk3310_it_table),
+					  val, val2);
+		if (index < 0)
+			return -EINVAL;
+		mutex_lock(&data->lock);
+		if (chan->type == IIO_LIGHT)
+			ret = regmap_field_write(data->reg_als_it, index);
+		else
+			ret = regmap_field_write(data->reg_ps_it, index);
+		if (ret < 0)
+			dev_err(&data->client->dev,
+					"sensor configuration failed\n");
+		mutex_unlock(&data->lock);
+		return ret;
+
+	case IIO_CHAN_INFO_SCALE:
+		index = stk3310_get_index(stk3310_scale_table,
+					  ARRAY_SIZE(stk3310_scale_table),
+					  val, val2);
+		if (index < 0)
+			return -EINVAL;
+		mutex_lock(&data->lock);
+		if (chan->type == IIO_LIGHT)
+			ret = regmap_field_write(data->reg_als_gain, index);
+		else
+			ret = regmap_field_write(data->reg_ps_gain, index);
+		if (ret < 0)
+			dev_err(&data->client->dev,
+					"sensor configuration failed\n");
+		mutex_unlock(&data->lock);
+		return ret;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info stk3310_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= stk3310_read_raw,
+	.write_raw		= stk3310_write_raw,
+	.attrs			= &stk3310_attribute_group,
+	.read_event_value	= stk3310_read_event,
+	.write_event_value	= stk3310_write_event,
+	.read_event_config	= stk3310_read_event_config,
+	.write_event_config	= stk3310_write_event_config,
+};
+
+static int stk3310_set_state(struct stk3310_data *data, u8 state)
+{
+	int ret;
+	struct i2c_client *client = data->client;
+
+	/* 3-bit state; 0b100 is not supported. */
+	if (state > 7 || state == 4)
+		return -EINVAL;
+
+	mutex_lock(&data->lock);
+	ret = regmap_field_write(data->reg_state, state);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to change sensor state\n");
+	} else if (state != STK3310_STATE_STANDBY) {
+		/* Don't reset the 'enabled' flags if we're going in standby */
+		data->ps_enabled  = !!(state & 0x01);
+		data->als_enabled = !!(state & 0x02);
+	}
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
+static int stk3310_init(struct iio_dev *indio_dev)
+{
+	int ret;
+	int chipid;
+	u8 state;
+	struct stk3310_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+
+	regmap_read(data->regmap, STK3310_REG_ID, &chipid);
+	if (chipid != STK3310_CHIP_ID_VAL &&
+	    chipid != STK3311_CHIP_ID_VAL) {
+		dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
+		return -ENODEV;
+	}
+
+	state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS;
+	ret = stk3310_set_state(data, state);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed to enable sensor");
+		return ret;
+	}
+
+	/* Enable PS interrupts */
+	ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN);
+	if (ret < 0)
+		dev_err(&client->dev, "failed to enable interrupts!\n");
+
+	return ret;
+}
+
+static int stk3310_gpio_probe(struct i2c_client *client)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* gpio interrupt pin */
+	gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "acpi gpio get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case STK3310_REG_ALS_DATA_MSB:
+	case STK3310_REG_ALS_DATA_LSB:
+	case STK3310_REG_PS_DATA_LSB:
+	case STK3310_REG_PS_DATA_MSB:
+	case STK3310_REG_FLAG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static struct regmap_config stk3310_regmap_config = {
+	.name = STK3310_REGMAP_NAME,
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = STK3310_MAX_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = stk3310_is_volatile_reg,
+};
+
+static int stk3310_regmap_init(struct stk3310_data *data)
+{
+	struct regmap *regmap;
+	struct i2c_client *client;
+
+	client = data->client;
+	regmap = devm_regmap_init_i2c(client, &stk3310_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "regmap initialization failed.\n");
+		return PTR_ERR(regmap);
+	}
+	data->regmap = regmap;
+
+	STK3310_REGFIELD(state);
+	STK3310_REGFIELD(als_gain);
+	STK3310_REGFIELD(ps_gain);
+	STK3310_REGFIELD(als_it);
+	STK3310_REGFIELD(ps_it);
+	STK3310_REGFIELD(int_ps);
+	STK3310_REGFIELD(flag_psint);
+	STK3310_REGFIELD(flag_nf);
+
+	return 0;
+}
+
+static irqreturn_t stk3310_irq_handler(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct stk3310_data *data = iio_priv(indio_dev);
+
+	data->timestamp = iio_get_time_ns();
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
+{
+	int ret;
+	unsigned int dir;
+	u64 event;
+
+	struct iio_dev *indio_dev = private;
+	struct stk3310_data *data = iio_priv(indio_dev);
+
+	/* Read FLAG_NF to figure out what threshold has been met. */
+	mutex_lock(&data->lock);
+	ret = regmap_field_read(data->reg_flag_nf, &dir);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "register read failed\n");
+		mutex_unlock(&data->lock);
+		return ret;
+	}
+	event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
+				     IIO_EV_TYPE_THRESH,
+				     (dir ? IIO_EV_DIR_RISING :
+					    IIO_EV_DIR_FALLING));
+	iio_push_event(indio_dev, event, data->timestamp);
+
+	/* Reset the interrupt flag */
+	ret = regmap_field_write(data->reg_flag_psint, 0);
+	if (ret < 0)
+		dev_err(&data->client->dev, "failed to reset interrupts\n");
+	mutex_unlock(&data->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int stk3310_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	int ret;
+	struct iio_dev *indio_dev;
+	struct stk3310_data *data;
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev) {
+		dev_err(&client->dev, "iio allocation failed!\n");
+		return -ENOMEM;
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	i2c_set_clientdata(client, indio_dev);
+	mutex_init(&data->lock);
+
+	ret = stk3310_regmap_init(data);
+	if (ret < 0)
+		return ret;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &stk3310_info;
+	indio_dev->name = STK3310_DRIVER_NAME;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = stk3310_channels;
+	indio_dev->num_channels = ARRAY_SIZE(stk3310_channels);
+
+	ret = stk3310_init(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "device_register failed\n");
+		stk3310_set_state(data, STK3310_STATE_STANDBY);
+	}
+
+	if (client->irq <= 0)
+		client->irq = stk3310_gpio_probe(client);
+
+	if (client->irq >= 0) {
+		ret = devm_request_threaded_irq(&client->dev, client->irq,
+						stk3310_irq_handler,
+						stk3310_irq_event_handler,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						STK3310_EVENT, indio_dev);
+		if (ret < 0)
+			dev_err(&client->dev, "request irq %d failed\n",
+					client->irq);
+	}
+
+	return ret;
+}
+
+static int stk3310_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+	iio_device_unregister(indio_dev);
+	return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stk3310_suspend(struct device *dev)
+{
+	struct stk3310_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+	return stk3310_set_state(data, STK3310_STATE_STANDBY);
+}
+
+static int stk3310_resume(struct device *dev)
+{
+	int state = 0;
+	struct stk3310_data *data;
+
+	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+	if (data->ps_enabled)
+		state |= STK3310_STATE_EN_PS;
+	if (data->als_enabled)
+		state |= STK3310_STATE_EN_ALS;
+
+	return stk3310_set_state(data, state);
+}
+
+static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume);
+
+#define STK3310_PM_OPS (&stk3310_pm_ops)
+#else
+#define STK3310_PM_OPS NULL
+#endif
+
+static const struct i2c_device_id stk3310_i2c_id[] = {
+	{"STK3310", 0},
+	{"STK3311", 0},
+	{}
+};
+
+static const struct acpi_device_id stk3310_acpi_id[] = {
+	{"STK3310", 0},
+	{"STK3311", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
+
+static struct i2c_driver stk3310_driver = {
+	.driver = {
+		.name = "stk3310",
+		.pm = STK3310_PM_OPS,
+		.acpi_match_table = ACPI_PTR(stk3310_acpi_id),
+	},
+	.probe =            stk3310_probe,
+	.remove =           stk3310_remove,
+	.id_table =         stk3310_i2c_id,
+};
+
+module_i2c_driver(stk3310_driver);
+
+MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
+MODULE_DESCRIPTION("STK3310 Ambient Light and Proximity Sensor driver");
+MODULE_LICENSE("GPL v2");

+ 27 - 2
drivers/iio/magnetometer/Kconfig

@@ -8,7 +8,7 @@ menu "Magnetometer sensors"
 config AK8975
 	tristate "Asahi Kasei AK 3-Axis Magnetometer"
 	depends on I2C
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say yes here to build support for Asahi Kasei AK8975, AK8963,
 	  AK09911 or AK09912 3-Axis Magnetometer.
@@ -19,7 +19,7 @@ config AK8975
 config AK09911
 	tristate "Asahi Kasei AK09911 3-axis Compass"
 	depends on I2C
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	select AK8975
 	help
 	  Deprecated: AK09911 is now supported by AK8975 driver.
@@ -47,6 +47,17 @@ config HID_SENSOR_MAGNETOMETER_3D
 	  Say yes here to build support for the HID SENSOR
 	  Magnetometer 3D.
 
+config MMC35240
+	tristate "MEMSIC MMC35240 3-axis magnetic sensor"
+	select REGMAP_I2C
+	depends on I2C
+	help
+	  Say yes here to build support for the MEMSIC MMC35240 3-axis
+	  magnetic sensor.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mmc35240.
+
 config IIO_ST_MAGN_3AXIS
 	tristate "STMicroelectronics magnetometers 3-Axis Driver"
 	depends on (I2C || SPI_MASTER) && SYSFS
@@ -76,4 +87,18 @@ config IIO_ST_MAGN_SPI_3AXIS
 	depends on IIO_ST_MAGN_3AXIS
 	depends on IIO_ST_SENSORS_SPI
 
+config BMC150_MAGN
+	tristate "Bosch BMC150 Magnetometer Driver"
+	depends on 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

+ 3 - 0
drivers/iio/magnetometer/Makefile

@@ -6,6 +6,7 @@
 obj-$(CONFIG_AK8975)	+= ak8975.o
 obj-$(CONFIG_MAG3110)	+= mag3110.o
 obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
+obj-$(CONFIG_MMC35240)	+= mmc35240.o
 
 obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
 st_magn-y := st_magn_core.o
@@ -13,3 +14,5 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
 
 obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
 obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
+
+obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o

+ 1109 - 0
drivers/iio/magnetometer/bmc150_magn.c

@@ -0,0 +1,1109 @@
+/*
+ * Bosch BMC150 three-axis magnetic field sensor driver
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This code is based on bmm050_api.c authored by contact@bosch.sensortec.com:
+ *
+ * (C) Copyright 2011~2014 Bosch Sensortec GmbH All Rights Reserved
+ *
+ * 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/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/regmap.h>
+
+#define BMC150_MAGN_DRV_NAME			"bmc150_magn"
+#define BMC150_MAGN_IRQ_NAME			"bmc150_magn_event"
+#define BMC150_MAGN_GPIO_INT			"interrupt"
+
+#define BMC150_MAGN_REG_CHIP_ID			0x40
+#define BMC150_MAGN_CHIP_ID_VAL			0x32
+
+#define BMC150_MAGN_REG_X_L			0x42
+#define BMC150_MAGN_REG_X_M			0x43
+#define BMC150_MAGN_REG_Y_L			0x44
+#define BMC150_MAGN_REG_Y_M			0x45
+#define BMC150_MAGN_SHIFT_XY_L			3
+#define BMC150_MAGN_REG_Z_L			0x46
+#define BMC150_MAGN_REG_Z_M			0x47
+#define BMC150_MAGN_SHIFT_Z_L			1
+#define BMC150_MAGN_REG_RHALL_L			0x48
+#define BMC150_MAGN_REG_RHALL_M			0x49
+#define BMC150_MAGN_SHIFT_RHALL_L		2
+
+#define BMC150_MAGN_REG_INT_STATUS		0x4A
+
+#define BMC150_MAGN_REG_POWER			0x4B
+#define BMC150_MAGN_MASK_POWER_CTL		BIT(0)
+
+#define BMC150_MAGN_REG_OPMODE_ODR		0x4C
+#define BMC150_MAGN_MASK_OPMODE			GENMASK(2, 1)
+#define BMC150_MAGN_SHIFT_OPMODE		1
+#define BMC150_MAGN_MODE_NORMAL			0x00
+#define BMC150_MAGN_MODE_FORCED			0x01
+#define BMC150_MAGN_MODE_SLEEP			0x03
+#define BMC150_MAGN_MASK_ODR			GENMASK(5, 3)
+#define BMC150_MAGN_SHIFT_ODR			3
+
+#define BMC150_MAGN_REG_INT			0x4D
+
+#define BMC150_MAGN_REG_INT_DRDY		0x4E
+#define BMC150_MAGN_MASK_DRDY_EN		BIT(7)
+#define BMC150_MAGN_SHIFT_DRDY_EN		7
+#define BMC150_MAGN_MASK_DRDY_INT3		BIT(6)
+#define BMC150_MAGN_MASK_DRDY_Z_EN		BIT(5)
+#define BMC150_MAGN_MASK_DRDY_Y_EN		BIT(4)
+#define BMC150_MAGN_MASK_DRDY_X_EN		BIT(3)
+#define BMC150_MAGN_MASK_DRDY_DR_POLARITY	BIT(2)
+#define BMC150_MAGN_MASK_DRDY_LATCHING		BIT(1)
+#define BMC150_MAGN_MASK_DRDY_INT3_POLARITY	BIT(0)
+
+#define BMC150_MAGN_REG_LOW_THRESH		0x4F
+#define BMC150_MAGN_REG_HIGH_THRESH		0x50
+#define BMC150_MAGN_REG_REP_XY			0x51
+#define BMC150_MAGN_REG_REP_Z			0x52
+
+#define BMC150_MAGN_REG_TRIM_START		0x5D
+#define BMC150_MAGN_REG_TRIM_END		0x71
+
+#define BMC150_MAGN_XY_OVERFLOW_VAL		-4096
+#define BMC150_MAGN_Z_OVERFLOW_VAL		-16384
+
+/* Time from SUSPEND to SLEEP */
+#define BMC150_MAGN_START_UP_TIME_MS		3
+
+#define BMC150_MAGN_AUTO_SUSPEND_DELAY_MS	2000
+
+#define BMC150_MAGN_REGVAL_TO_REPXY(regval) (((regval) * 2) + 1)
+#define BMC150_MAGN_REGVAL_TO_REPZ(regval) ((regval) + 1)
+#define BMC150_MAGN_REPXY_TO_REGVAL(rep) (((rep) - 1) / 2)
+#define BMC150_MAGN_REPZ_TO_REGVAL(rep) ((rep) - 1)
+
+enum bmc150_magn_axis {
+	AXIS_X,
+	AXIS_Y,
+	AXIS_Z,
+	RHALL,
+	AXIS_XYZ_MAX = RHALL,
+	AXIS_XYZR_MAX,
+};
+
+enum bmc150_magn_power_modes {
+	BMC150_MAGN_POWER_MODE_SUSPEND,
+	BMC150_MAGN_POWER_MODE_SLEEP,
+	BMC150_MAGN_POWER_MODE_NORMAL,
+};
+
+struct bmc150_magn_trim_regs {
+	s8 x1;
+	s8 y1;
+	__le16 reserved1;
+	u8 reserved2;
+	__le16 z4;
+	s8 x2;
+	s8 y2;
+	__le16 reserved3;
+	__le16 z2;
+	__le16 z1;
+	__le16 xyz1;
+	__le16 z3;
+	s8 xy2;
+	u8 xy1;
+} __packed;
+
+struct bmc150_magn_data {
+	struct i2c_client *client;
+	/*
+	 * 1. Protect this structure.
+	 * 2. Serialize sequences that power on/off the device and access HW.
+	 */
+	struct mutex mutex;
+	struct regmap *regmap;
+	/* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
+	s32 buffer[6];
+	struct iio_trigger *dready_trig;
+	bool dready_trigger_on;
+	int max_odr;
+};
+
+static const struct {
+	int freq;
+	u8 reg_val;
+} bmc150_magn_samp_freq_table[] = { {2, 0x01},
+				    {6, 0x02},
+				    {8, 0x03},
+				    {10, 0x00},
+				    {15, 0x04},
+				    {20, 0x05},
+				    {25, 0x06},
+				    {30, 0x07} };
+
+enum bmc150_magn_presets {
+	LOW_POWER_PRESET,
+	REGULAR_PRESET,
+	ENHANCED_REGULAR_PRESET,
+	HIGH_ACCURACY_PRESET
+};
+
+static const struct bmc150_magn_preset {
+	u8 rep_xy;
+	u8 rep_z;
+	u8 odr;
+} bmc150_magn_presets_table[] = {
+	[LOW_POWER_PRESET] = {3, 3, 10},
+	[REGULAR_PRESET] =  {9, 15, 10},
+	[ENHANCED_REGULAR_PRESET] =  {15, 27, 10},
+	[HIGH_ACCURACY_PRESET] =  {47, 83, 20},
+};
+
+#define BMC150_MAGN_DEFAULT_PRESET REGULAR_PRESET
+
+static bool bmc150_magn_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMC150_MAGN_REG_POWER:
+	case BMC150_MAGN_REG_OPMODE_ODR:
+	case BMC150_MAGN_REG_INT:
+	case BMC150_MAGN_REG_INT_DRDY:
+	case BMC150_MAGN_REG_LOW_THRESH:
+	case BMC150_MAGN_REG_HIGH_THRESH:
+	case BMC150_MAGN_REG_REP_XY:
+	case BMC150_MAGN_REG_REP_Z:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool bmc150_magn_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case BMC150_MAGN_REG_X_L:
+	case BMC150_MAGN_REG_X_M:
+	case BMC150_MAGN_REG_Y_L:
+	case BMC150_MAGN_REG_Y_M:
+	case BMC150_MAGN_REG_Z_L:
+	case BMC150_MAGN_REG_Z_M:
+	case BMC150_MAGN_REG_RHALL_L:
+	case BMC150_MAGN_REG_RHALL_M:
+	case BMC150_MAGN_REG_INT_STATUS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config bmc150_magn_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = BMC150_MAGN_REG_TRIM_END,
+	.cache_type = REGCACHE_RBTREE,
+
+	.writeable_reg = bmc150_magn_is_writeable_reg,
+	.volatile_reg = bmc150_magn_is_volatile_reg,
+};
+
+static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data,
+				      enum bmc150_magn_power_modes mode,
+				      bool state)
+{
+	int ret;
+
+	switch (mode) {
+	case BMC150_MAGN_POWER_MODE_SUSPEND:
+		ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_POWER,
+					 BMC150_MAGN_MASK_POWER_CTL, !state);
+		if (ret < 0)
+			return ret;
+		usleep_range(BMC150_MAGN_START_UP_TIME_MS * 1000, 20000);
+		return 0;
+	case BMC150_MAGN_POWER_MODE_SLEEP:
+		return regmap_update_bits(data->regmap,
+					  BMC150_MAGN_REG_OPMODE_ODR,
+					  BMC150_MAGN_MASK_OPMODE,
+					  BMC150_MAGN_MODE_SLEEP <<
+					  BMC150_MAGN_SHIFT_OPMODE);
+	case BMC150_MAGN_POWER_MODE_NORMAL:
+		return regmap_update_bits(data->regmap,
+					  BMC150_MAGN_REG_OPMODE_ODR,
+					  BMC150_MAGN_MASK_OPMODE,
+					  BMC150_MAGN_MODE_NORMAL <<
+					  BMC150_MAGN_SHIFT_OPMODE);
+	}
+
+	return -EINVAL;
+}
+
+static int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on)
+{
+#ifdef CONFIG_PM
+	int ret;
+
+	if (on) {
+		ret = pm_runtime_get_sync(&data->client->dev);
+	} else {
+		pm_runtime_mark_last_busy(&data->client->dev);
+		ret = pm_runtime_put_autosuspend(&data->client->dev);
+	}
+
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"failed to change power state to %d\n", on);
+		if (on)
+			pm_runtime_put_noidle(&data->client->dev);
+
+		return ret;
+	}
+#endif
+
+	return 0;
+}
+
+static int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val)
+{
+	int ret, reg_val;
+	u8 i, odr_val;
+
+	ret = regmap_read(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, &reg_val);
+	if (ret < 0)
+		return ret;
+	odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR;
+
+	for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++)
+		if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) {
+			*val = bmc150_magn_samp_freq_table[i].freq;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+static int bmc150_magn_set_odr(struct bmc150_magn_data *data, int val)
+{
+	int ret;
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) {
+		if (bmc150_magn_samp_freq_table[i].freq == val) {
+			ret = regmap_update_bits(data->regmap,
+						 BMC150_MAGN_REG_OPMODE_ODR,
+						 BMC150_MAGN_MASK_ODR,
+						 bmc150_magn_samp_freq_table[i].
+						 reg_val <<
+						 BMC150_MAGN_SHIFT_ODR);
+			if (ret < 0)
+				return ret;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int bmc150_magn_set_max_odr(struct bmc150_magn_data *data, int rep_xy,
+				   int rep_z, int odr)
+{
+	int ret, reg_val, max_odr;
+
+	if (rep_xy <= 0) {
+		ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_XY,
+				  &reg_val);
+		if (ret < 0)
+			return ret;
+		rep_xy = BMC150_MAGN_REGVAL_TO_REPXY(reg_val);
+	}
+	if (rep_z <= 0) {
+		ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_Z,
+				  &reg_val);
+		if (ret < 0)
+			return ret;
+		rep_z = BMC150_MAGN_REGVAL_TO_REPZ(reg_val);
+	}
+	if (odr <= 0) {
+		ret = bmc150_magn_get_odr(data, &odr);
+		if (ret < 0)
+			return ret;
+	}
+	/* the maximum selectable read-out frequency from datasheet */
+	max_odr = 1000000 / (145 * rep_xy + 500 * rep_z + 980);
+	if (odr > max_odr) {
+		dev_err(&data->client->dev,
+			"Can't set oversampling with sampling freq %d\n",
+			odr);
+		return -EINVAL;
+	}
+	data->max_odr = max_odr;
+
+	return 0;
+}
+
+static s32 bmc150_magn_compensate_x(struct bmc150_magn_trim_regs *tregs, s16 x,
+				    u16 rhall)
+{
+	s16 val;
+	u16 xyz1 = le16_to_cpu(tregs->xyz1);
+
+	if (x == BMC150_MAGN_XY_OVERFLOW_VAL)
+		return S32_MIN;
+
+	if (!rhall)
+		rhall = xyz1;
+
+	val = ((s16)(((u16)((((s32)xyz1) << 14) / rhall)) - ((u16)0x4000)));
+	val = ((s16)((((s32)x) * ((((((((s32)tregs->xy2) * ((((s32)val) *
+	      ((s32)val)) >> 7)) + (((s32)val) *
+	      ((s32)(((s16)tregs->xy1) << 7)))) >> 9) + ((s32)0x100000)) *
+	      ((s32)(((s16)tregs->x2) + ((s16)0xA0)))) >> 12)) >> 13)) +
+	      (((s16)tregs->x1) << 3);
+
+	return (s32)val;
+}
+
+static s32 bmc150_magn_compensate_y(struct bmc150_magn_trim_regs *tregs, s16 y,
+				    u16 rhall)
+{
+	s16 val;
+	u16 xyz1 = le16_to_cpu(tregs->xyz1);
+
+	if (y == BMC150_MAGN_XY_OVERFLOW_VAL)
+		return S32_MIN;
+
+	if (!rhall)
+		rhall = xyz1;
+
+	val = ((s16)(((u16)((((s32)xyz1) << 14) / rhall)) - ((u16)0x4000)));
+	val = ((s16)((((s32)y) * ((((((((s32)tregs->xy2) * ((((s32)val) *
+	      ((s32)val)) >> 7)) + (((s32)val) *
+	      ((s32)(((s16)tregs->xy1) << 7)))) >> 9) + ((s32)0x100000)) *
+	      ((s32)(((s16)tregs->y2) + ((s16)0xA0)))) >> 12)) >> 13)) +
+	      (((s16)tregs->y1) << 3);
+
+	return (s32)val;
+}
+
+static s32 bmc150_magn_compensate_z(struct bmc150_magn_trim_regs *tregs, s16 z,
+				    u16 rhall)
+{
+	s32 val;
+	u16 xyz1 = le16_to_cpu(tregs->xyz1);
+	u16 z1 = le16_to_cpu(tregs->z1);
+	s16 z2 = le16_to_cpu(tregs->z2);
+	s16 z3 = le16_to_cpu(tregs->z3);
+	s16 z4 = le16_to_cpu(tregs->z4);
+
+	if (z == BMC150_MAGN_Z_OVERFLOW_VAL)
+		return S32_MIN;
+
+	val = (((((s32)(z - z4)) << 15) - ((((s32)z3) * ((s32)(((s16)rhall) -
+	      ((s16)xyz1)))) >> 2)) / (z2 + ((s16)(((((s32)z1) *
+	      ((((s16)rhall) << 1))) + (1 << 15)) >> 16))));
+
+	return val;
+}
+
+static int bmc150_magn_read_xyz(struct bmc150_magn_data *data, s32 *buffer)
+{
+	int ret;
+	__le16 values[AXIS_XYZR_MAX];
+	s16 raw_x, raw_y, raw_z;
+	u16 rhall;
+	struct bmc150_magn_trim_regs tregs;
+
+	ret = regmap_bulk_read(data->regmap, BMC150_MAGN_REG_X_L,
+			       values, sizeof(values));
+	if (ret < 0)
+		return ret;
+
+	raw_x = (s16)le16_to_cpu(values[AXIS_X]) >> BMC150_MAGN_SHIFT_XY_L;
+	raw_y = (s16)le16_to_cpu(values[AXIS_Y]) >> BMC150_MAGN_SHIFT_XY_L;
+	raw_z = (s16)le16_to_cpu(values[AXIS_Z]) >> BMC150_MAGN_SHIFT_Z_L;
+	rhall = le16_to_cpu(values[RHALL]) >> BMC150_MAGN_SHIFT_RHALL_L;
+
+	ret = regmap_bulk_read(data->regmap, BMC150_MAGN_REG_TRIM_START,
+			       &tregs, sizeof(tregs));
+	if (ret < 0)
+		return ret;
+
+	buffer[AXIS_X] = bmc150_magn_compensate_x(&tregs, raw_x, rhall);
+	buffer[AXIS_Y] = bmc150_magn_compensate_y(&tregs, raw_y, rhall);
+	buffer[AXIS_Z] = bmc150_magn_compensate_z(&tregs, raw_z, rhall);
+
+	return 0;
+}
+
+static int bmc150_magn_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret, tmp;
+	s32 values[AXIS_XYZ_MAX];
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (iio_buffer_enabled(indio_dev))
+			return -EBUSY;
+		mutex_lock(&data->mutex);
+
+		ret = bmc150_magn_set_power_state(data, true);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+
+		ret = bmc150_magn_read_xyz(data, values);
+		if (ret < 0) {
+			bmc150_magn_set_power_state(data, false);
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+		*val = values[chan->scan_index];
+
+		ret = bmc150_magn_set_power_state(data, false);
+		if (ret < 0) {
+			mutex_unlock(&data->mutex);
+			return ret;
+		}
+
+		mutex_unlock(&data->mutex);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/*
+		 * The API/driver performs an off-chip temperature
+		 * compensation and outputs x/y/z magnetic field data in
+		 * 16 LSB/uT to the upper application layer.
+		 */
+		*val = 0;
+		*val2 = 625;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = bmc150_magn_get_odr(data, val);
+		if (ret < 0)
+			return ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->channel2) {
+		case IIO_MOD_X:
+		case IIO_MOD_Y:
+			ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_XY,
+					  &tmp);
+			if (ret < 0)
+				return ret;
+			*val = BMC150_MAGN_REGVAL_TO_REPXY(tmp);
+			return IIO_VAL_INT;
+		case IIO_MOD_Z:
+			ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_Z,
+					  &tmp);
+			if (ret < 0)
+				return ret;
+			*val = BMC150_MAGN_REGVAL_TO_REPZ(tmp);
+			return IIO_VAL_INT;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
+				 struct iio_chan_spec const *chan,
+				 int val, int val2, long mask)
+{
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		if (val > data->max_odr)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = bmc150_magn_set_odr(data, val);
+		mutex_unlock(&data->mutex);
+		return ret;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		switch (chan->channel2) {
+		case IIO_MOD_X:
+		case IIO_MOD_Y:
+			if (val < 1 || val > 511)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = bmc150_magn_set_max_odr(data, val, 0, 0);
+			if (ret < 0) {
+				mutex_unlock(&data->mutex);
+				return ret;
+			}
+			ret = regmap_update_bits(data->regmap,
+						 BMC150_MAGN_REG_REP_XY,
+						 0xFF,
+						 BMC150_MAGN_REPXY_TO_REGVAL
+						 (val));
+			mutex_unlock(&data->mutex);
+			return ret;
+		case IIO_MOD_Z:
+			if (val < 1 || val > 256)
+				return -EINVAL;
+			mutex_lock(&data->mutex);
+			ret = bmc150_magn_set_max_odr(data, 0, val, 0);
+			if (ret < 0) {
+				mutex_unlock(&data->mutex);
+				return ret;
+			}
+			ret = regmap_update_bits(data->regmap,
+						 BMC150_MAGN_REG_REP_Z,
+						 0xFF,
+						 BMC150_MAGN_REPZ_TO_REGVAL
+						 (val));
+			mutex_unlock(&data->mutex);
+			return ret;
+		default:
+			return -EINVAL;
+		}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int bmc150_magn_validate_trigger(struct iio_dev *indio_dev,
+					struct iio_trigger *trig)
+{
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+
+	if (data->dready_trig != trig)
+		return -EINVAL;
+
+	return 0;
+}
+
+static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	size_t len = 0;
+	u8 i;
+
+	for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) {
+		if (bmc150_magn_samp_freq_table[i].freq > data->max_odr)
+			break;
+		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+				 bmc150_magn_samp_freq_table[i].freq);
+	}
+	/* replace last space with a newline */
+	buf[len - 1] = '\n';
+
+	return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail);
+
+static struct attribute *bmc150_magn_attributes[] = {
+	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group bmc150_magn_attrs_group = {
+	.attrs = bmc150_magn_attributes,
+};
+
+#define BMC150_MAGN_CHANNEL(_axis) {					\
+	.type = IIO_MAGN,						\
+	.modified = 1,							\
+	.channel2 = IIO_MOD_##_axis,					\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
+			      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
+				    BIT(IIO_CHAN_INFO_SCALE),		\
+	.scan_index = AXIS_##_axis,					\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 32,						\
+		.storagebits = 32,					\
+		.endianness = IIO_LE					\
+	},								\
+}
+
+static const struct iio_chan_spec bmc150_magn_channels[] = {
+	BMC150_MAGN_CHANNEL(X),
+	BMC150_MAGN_CHANNEL(Y),
+	BMC150_MAGN_CHANNEL(Z),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_info bmc150_magn_info = {
+	.attrs = &bmc150_magn_attrs_group,
+	.read_raw = bmc150_magn_read_raw,
+	.write_raw = bmc150_magn_write_raw,
+	.validate_trigger = bmc150_magn_validate_trigger,
+	.driver_module = THIS_MODULE,
+};
+
+static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0};
+
+static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bmc150_magn_read_xyz(data, data->buffer);
+	mutex_unlock(&data->mutex);
+	if (ret < 0)
+		goto err;
+
+	iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+					   pf->timestamp);
+
+err:
+	iio_trigger_notify_done(data->dready_trig);
+
+	return IRQ_HANDLED;
+}
+
+static int bmc150_magn_init(struct bmc150_magn_data *data)
+{
+	int ret, chip_id;
+	struct bmc150_magn_preset preset;
+
+	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND,
+					 false);
+	if (ret < 0) {
+		dev_err(&data->client->dev,
+			"Failed to bring up device from suspend mode\n");
+		return ret;
+	}
+
+	ret = regmap_read(data->regmap, BMC150_MAGN_REG_CHIP_ID, &chip_id);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed reading chip id\n");
+		goto err_poweroff;
+	}
+	if (chip_id != BMC150_MAGN_CHIP_ID_VAL) {
+		dev_err(&data->client->dev, "Invalid chip id 0x%x\n", ret);
+		ret = -ENODEV;
+		goto err_poweroff;
+	}
+	dev_dbg(&data->client->dev, "Chip id %x\n", ret);
+
+	preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET];
+	ret = bmc150_magn_set_odr(data, preset.odr);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed to set ODR to %d\n",
+			preset.odr);
+		goto err_poweroff;
+	}
+
+	ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_XY,
+			   BMC150_MAGN_REPXY_TO_REGVAL(preset.rep_xy));
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed to set REP XY to %d\n",
+			preset.rep_xy);
+		goto err_poweroff;
+	}
+
+	ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_Z,
+			   BMC150_MAGN_REPZ_TO_REGVAL(preset.rep_z));
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed to set REP Z to %d\n",
+			preset.rep_z);
+		goto err_poweroff;
+	}
+
+	ret = bmc150_magn_set_max_odr(data, preset.rep_xy, preset.rep_z,
+				      preset.odr);
+	if (ret < 0)
+		goto err_poweroff;
+
+	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
+					 true);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Failed to power on device\n");
+		goto err_poweroff;
+	}
+
+	return 0;
+
+err_poweroff:
+	bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
+	return ret;
+}
+
+static int bmc150_magn_reset_intr(struct bmc150_magn_data *data)
+{
+	int tmp;
+
+	/*
+	 * Data Ready (DRDY) is always cleared after
+	 * readout of data registers ends.
+	 */
+	return regmap_read(data->regmap, BMC150_MAGN_REG_X_L, &tmp);
+}
+
+static int bmc150_magn_trig_try_reen(struct iio_trigger *trig)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	if (!data->dready_trigger_on)
+		return 0;
+
+	mutex_lock(&data->mutex);
+	ret = bmc150_magn_reset_intr(data);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
+						  bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret = 0;
+
+	mutex_lock(&data->mutex);
+	if (state == data->dready_trigger_on)
+		goto err_unlock;
+
+	ret = bmc150_magn_set_power_state(data, state);
+	if (ret < 0)
+		goto err_unlock;
+
+	ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY,
+				 BMC150_MAGN_MASK_DRDY_EN,
+				 state << BMC150_MAGN_SHIFT_DRDY_EN);
+	if (ret < 0)
+		goto err_poweroff;
+
+	data->dready_trigger_on = state;
+
+	if (state) {
+		ret = bmc150_magn_reset_intr(data);
+		if (ret < 0)
+			goto err_poweroff;
+	}
+	mutex_unlock(&data->mutex);
+
+	return 0;
+
+err_poweroff:
+	bmc150_magn_set_power_state(data, false);
+err_unlock:
+	mutex_unlock(&data->mutex);
+	return ret;
+}
+
+static const struct iio_trigger_ops bmc150_magn_trigger_ops = {
+	.set_trigger_state = bmc150_magn_data_rdy_trigger_set_state,
+	.try_reenable = bmc150_magn_trig_try_reen,
+	.owner = THIS_MODULE,
+};
+
+static int bmc150_magn_gpio_probe(struct i2c_client *client)
+{
+	struct device *dev;
+	struct gpio_desc *gpio;
+	int ret;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* data ready GPIO interrupt pin */
+	gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0);
+	if (IS_ERR(gpio)) {
+		dev_err(dev, "ACPI GPIO get index failed\n");
+		return PTR_ERR(gpio);
+	}
+
+	ret = gpiod_direction_input(gpio);
+	if (ret)
+		return ret;
+
+	ret = gpiod_to_irq(gpio);
+
+	dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+	return ret;
+}
+
+static const char *bmc150_magn_match_acpi_device(struct device *dev)
+{
+	const struct acpi_device_id *id;
+
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return NULL;
+
+	return dev_name(dev);
+}
+
+static int bmc150_magn_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id)
+{
+	struct bmc150_magn_data *data;
+	struct iio_dev *indio_dev;
+	const char *name = NULL;
+	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;
+
+	if (id)
+		name = id->name;
+	else if (ACPI_HANDLE(&client->dev))
+		name = bmc150_magn_match_acpi_device(&client->dev);
+	else
+		return -ENOSYS;
+
+	mutex_init(&data->mutex);
+	data->regmap = devm_regmap_init_i2c(client, &bmc150_magn_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		dev_err(&client->dev, "Failed to allocate register map\n");
+		return PTR_ERR(data->regmap);
+	}
+
+	ret = bmc150_magn_init(data);
+	if (ret < 0)
+		return ret;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->channels = bmc150_magn_channels;
+	indio_dev->num_channels = ARRAY_SIZE(bmc150_magn_channels);
+	indio_dev->available_scan_masks = bmc150_magn_scan_masks;
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &bmc150_magn_info;
+
+	if (client->irq <= 0)
+		client->irq = bmc150_magn_gpio_probe(client);
+
+	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) {
+			ret = -ENOMEM;
+			dev_err(&client->dev, "iio trigger alloc failed\n");
+			goto err_poweroff;
+		}
+
+		data->dready_trig->dev.parent = &client->dev;
+		data->dready_trig->ops = &bmc150_magn_trigger_ops;
+		iio_trigger_set_drvdata(data->dready_trig, indio_dev);
+		ret = iio_trigger_register(data->dready_trig);
+		if (ret) {
+			dev_err(&client->dev, "iio trigger register failed\n");
+			goto err_poweroff;
+		}
+
+		ret = iio_triggered_buffer_setup(indio_dev,
+						 &iio_pollfunc_store_time,
+						 bmc150_magn_trigger_handler,
+						 NULL);
+		if (ret < 0) {
+			dev_err(&client->dev,
+				"iio triggered buffer setup failed\n");
+			goto err_trigger_unregister;
+		}
+
+		ret = request_threaded_irq(client->irq,
+					   iio_trigger_generic_data_rdy_poll,
+					   NULL,
+					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					   BMC150_MAGN_IRQ_NAME,
+					   data->dready_trig);
+		if (ret < 0) {
+			dev_err(&client->dev, "request irq %d failed\n",
+				client->irq);
+			goto err_buffer_cleanup;
+		}
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(&client->dev, "unable to register iio device\n");
+		goto err_free_irq;
+	}
+
+	ret = pm_runtime_set_active(&client->dev);
+	if (ret)
+		goto err_iio_unregister;
+
+	pm_runtime_enable(&client->dev);
+	pm_runtime_set_autosuspend_delay(&client->dev,
+					 BMC150_MAGN_AUTO_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(&client->dev);
+
+	dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+
+	return 0;
+
+err_iio_unregister:
+	iio_device_unregister(indio_dev);
+err_free_irq:
+	if (client->irq > 0)
+		free_irq(client->irq, data->dready_trig);
+err_buffer_cleanup:
+	if (data->dready_trig)
+		iio_triggered_buffer_cleanup(indio_dev);
+err_trigger_unregister:
+	if (data->dready_trig)
+		iio_trigger_unregister(data->dready_trig);
+err_poweroff:
+	bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
+	return ret;
+}
+
+static int bmc150_magn_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (client->irq > 0)
+		free_irq(data->client->irq, data->dready_trig);
+
+	if (data->dready_trig) {
+		iio_triggered_buffer_cleanup(indio_dev);
+		iio_trigger_unregister(data->dready_trig);
+	}
+
+	mutex_lock(&data->mutex);
+	bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
+	mutex_unlock(&data->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bmc150_magn_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP,
+					 true);
+	mutex_unlock(&data->mutex);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "powering off device failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int bmc150_magn_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+
+	return bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
+					  true);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int bmc150_magn_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP,
+					 true);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+
+static int bmc150_magn_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct bmc150_magn_data *data = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&data->mutex);
+	ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL,
+					 true);
+	mutex_unlock(&data->mutex);
+
+	return ret;
+}
+#endif
+
+static const struct dev_pm_ops bmc150_magn_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(bmc150_magn_suspend, bmc150_magn_resume)
+	SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend,
+			   bmc150_magn_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id bmc150_magn_acpi_match[] = {
+	{"BMC150B", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match);
+
+static const struct i2c_device_id bmc150_magn_id[] = {
+	{"bmc150_magn", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, bmc150_magn_id);
+
+static struct i2c_driver bmc150_magn_driver = {
+	.driver = {
+		   .name = BMC150_MAGN_DRV_NAME,
+		   .acpi_match_table = ACPI_PTR(bmc150_magn_acpi_match),
+		   .pm = &bmc150_magn_pm_ops,
+		   },
+	.probe = bmc150_magn_probe,
+	.remove = bmc150_magn_remove,
+	.id_table = bmc150_magn_id,
+};
+module_i2c_driver(bmc150_magn_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 magnetometer driver");

+ 1 - 1
drivers/iio/magnetometer/hid-sensor-magn-3d.c

@@ -510,7 +510,7 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_magn_3d_ids[] = {
+static const struct platform_device_id hid_magn_3d_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200083",

+ 512 - 0
drivers/iio/magnetometer/mmc35240.c

@@ -0,0 +1,512 @@
+/*
+ * MMC35240 - MEMSIC 3-axis Magnetic Sensor
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for MMC35240 (7-bit I2C slave address 0x30).
+ *
+ * TODO: offset, ACPI, continuous measurement mode, PM
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/acpi.h>
+#include <linux/pm.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define MMC35240_DRV_NAME "mmc35240"
+#define MMC35240_REGMAP_NAME "mmc35240_regmap"
+
+#define MMC35240_REG_XOUT_L	0x00
+#define MMC35240_REG_XOUT_H	0x01
+#define MMC35240_REG_YOUT_L	0x02
+#define MMC35240_REG_YOUT_H	0x03
+#define MMC35240_REG_ZOUT_L	0x04
+#define MMC35240_REG_ZOUT_H	0x05
+
+#define MMC35240_REG_STATUS	0x06
+#define MMC35240_REG_CTRL0	0x07
+#define MMC35240_REG_CTRL1	0x08
+
+#define MMC35240_REG_ID		0x20
+
+#define MMC35240_STATUS_MEAS_DONE_BIT	BIT(0)
+
+#define MMC35240_CTRL0_REFILL_BIT	BIT(7)
+#define MMC35240_CTRL0_RESET_BIT	BIT(6)
+#define MMC35240_CTRL0_SET_BIT		BIT(5)
+#define MMC35240_CTRL0_CMM_BIT		BIT(1)
+#define MMC35240_CTRL0_TM_BIT		BIT(0)
+
+/* output resolution bits */
+#define MMC35240_CTRL1_BW0_BIT		BIT(0)
+#define MMC35240_CTRL1_BW1_BIT		BIT(1)
+
+#define MMC35240_CTRL1_BW_MASK	 (MMC35240_CTRL1_BW0_BIT | \
+		 MMC35240_CTRL1_BW1_BIT)
+#define MMC35240_CTRL1_BW_SHIFT		0
+
+#define MMC35240_WAIT_CHARGE_PUMP	50000	/* us */
+#define MMC53240_WAIT_SET_RESET		1000	/* us */
+
+enum mmc35240_resolution {
+	MMC35240_16_BITS_SLOW = 0, /* 100 Hz */
+	MMC35240_16_BITS_FAST,     /* 200 Hz */
+	MMC35240_14_BITS,          /* 333 Hz */
+	MMC35240_12_BITS,          /* 666 Hz */
+};
+
+enum mmc35240_axis {
+	AXIS_X = 0,
+	AXIS_Y,
+	AXIS_Z,
+};
+
+static const struct {
+	int sens[3]; /* sensitivity per X, Y, Z axis */
+	int nfo; /* null field output */
+} mmc35240_props_table[] = {
+	/* 16 bits, 100Hz ODR */
+	{
+		{1024, 1024, 770},
+		32768,
+	},
+	/* 16 bits, 200Hz ODR */
+	{
+		{1024, 1024, 770},
+		32768,
+	},
+	/* 14 bits, 333Hz ODR */
+	{
+		{256, 256, 193},
+		8192,
+	},
+	/* 12 bits, 666Hz ODR */
+	{
+		{64, 64, 48},
+		2048,
+	},
+};
+
+struct mmc35240_data {
+	struct i2c_client *client;
+	struct mutex mutex;
+	struct regmap *regmap;
+	enum mmc35240_resolution res;
+};
+
+static const int mmc35240_samp_freq[] = {100, 200, 333, 666};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 333 666");
+
+#define MMC35240_CHANNEL(_axis) { \
+	.type = IIO_MAGN, \
+	.modified = 1, \
+	.channel2 = IIO_MOD_ ## _axis, \
+	.address = AXIS_ ## _axis, \
+	.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec mmc35240_channels[] = {
+	MMC35240_CHANNEL(X),
+	MMC35240_CHANNEL(Y),
+	MMC35240_CHANNEL(Z),
+};
+
+static struct attribute *mmc35240_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+};
+
+static const struct attribute_group mmc35240_attribute_group = {
+	.attrs = mmc35240_attributes,
+};
+
+static int mmc35240_get_samp_freq_index(struct mmc35240_data *data,
+					int val, int val2)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mmc35240_samp_freq); i++)
+		if (mmc35240_samp_freq[i] == val)
+			return i;
+	return -EINVAL;
+}
+
+static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
+{
+	int ret;
+	u8 coil_bit;
+
+	/*
+	 * Recharge the capacitor at VCAP pin, requested to be issued
+	 * before a SET/RESET command.
+	 */
+	ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
+				 MMC35240_CTRL0_REFILL_BIT,
+				 MMC35240_CTRL0_REFILL_BIT);
+	if (ret < 0)
+		return ret;
+	usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1);
+
+	if (set)
+		coil_bit = MMC35240_CTRL0_SET_BIT;
+	else
+		coil_bit = MMC35240_CTRL0_RESET_BIT;
+
+	return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
+				  MMC35240_CTRL0_REFILL_BIT,
+				  coil_bit);
+}
+
+static int mmc35240_init(struct mmc35240_data *data)
+{
+	int ret;
+	unsigned int reg_id;
+
+	ret = regmap_read(data->regmap, MMC35240_REG_ID, &reg_id);
+	if (ret < 0) {
+		dev_err(&data->client->dev, "Error reading product id\n");
+		return ret;
+	}
+
+	dev_dbg(&data->client->dev, "MMC35240 chip id %x\n", reg_id);
+
+	/*
+	 * make sure we restore sensor characteristics, by doing
+	 * a RESET/SET sequence
+	 */
+	ret = mmc35240_hw_set(data, false);
+	if (ret < 0)
+		return ret;
+	usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1);
+
+	ret = mmc35240_hw_set(data, true);
+	if (ret < 0)
+		return ret;
+
+	/* set default sampling frequency */
+	return regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,
+				  MMC35240_CTRL1_BW_MASK,
+				  data->res << MMC35240_CTRL1_BW_SHIFT);
+}
+
+static int mmc35240_take_measurement(struct mmc35240_data *data)
+{
+	int ret, tries = 100;
+	unsigned int reg_status;
+
+	ret = regmap_write(data->regmap, MMC35240_REG_CTRL0,
+			   MMC35240_CTRL0_TM_BIT);
+	if (ret < 0)
+		return ret;
+
+	while (tries-- > 0) {
+		ret = regmap_read(data->regmap, MMC35240_REG_STATUS,
+				  &reg_status);
+		if (ret < 0)
+			return ret;
+		if (reg_status & MMC35240_STATUS_MEAS_DONE_BIT)
+			break;
+		msleep(20);
+	}
+
+	if (tries < 0) {
+		dev_err(&data->client->dev, "data not ready\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
+{
+	int ret;
+
+	ret = mmc35240_take_measurement(data);
+	if (ret < 0)
+		return ret;
+
+	return regmap_bulk_read(data->regmap, MMC35240_REG_XOUT_L, (u8 *)buf,
+				3 * sizeof(__le16));
+}
+
+static int mmc35240_raw_to_gauss(struct mmc35240_data *data, int index,
+				 __le16 buf[],
+				 int *val, int *val2)
+{
+	int raw_x, raw_y, raw_z;
+	int sens_x, sens_y, sens_z;
+	int nfo;
+
+	raw_x = le16_to_cpu(buf[AXIS_X]);
+	raw_y = le16_to_cpu(buf[AXIS_Y]);
+	raw_z = le16_to_cpu(buf[AXIS_Z]);
+
+	sens_x = mmc35240_props_table[data->res].sens[AXIS_X];
+	sens_y = mmc35240_props_table[data->res].sens[AXIS_Y];
+	sens_z = mmc35240_props_table[data->res].sens[AXIS_Z];
+
+	nfo = mmc35240_props_table[data->res].nfo;
+
+	switch (index) {
+	case AXIS_X:
+		*val = (raw_x - nfo) / sens_x;
+		*val2 = ((raw_x - nfo) % sens_x) * 1000000;
+		break;
+	case AXIS_Y:
+		*val = (raw_y - nfo) / sens_y - (raw_z - nfo) / sens_z;
+		*val2 = (((raw_y - nfo) % sens_y - (raw_z - nfo) % sens_z))
+			* 1000000;
+		break;
+	case AXIS_Z:
+		*val = (raw_y - nfo) / sens_y + (raw_z - nfo) / sens_z;
+		*val2 = (((raw_y - nfo) % sens_y + (raw_z - nfo) % sens_z))
+			* 1000000;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int mmc35240_read_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int *val,
+			     int *val2, long mask)
+{
+	struct mmc35240_data *data = iio_priv(indio_dev);
+	int ret, i;
+	unsigned int reg;
+	__le16 buf[3];
+
+	switch (mask) {
+	case IIO_CHAN_INFO_PROCESSED:
+		mutex_lock(&data->mutex);
+		ret = mmc35240_read_measurement(data, buf);
+		mutex_unlock(&data->mutex);
+		if (ret < 0)
+			return ret;
+		ret = mmc35240_raw_to_gauss(data, chan->address,
+					    buf, val, val2);
+		if (ret < 0)
+			return ret;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		mutex_lock(&data->mutex);
+		ret = regmap_read(data->regmap, MMC35240_REG_CTRL1, &reg);
+		mutex_unlock(&data->mutex);
+		if (ret < 0)
+			return ret;
+
+		i = (reg & MMC35240_CTRL1_BW_MASK) >> MMC35240_CTRL1_BW_SHIFT;
+		if (i < 0 || i > ARRAY_SIZE(mmc35240_samp_freq))
+			return -EINVAL;
+
+		*val = mmc35240_samp_freq[i];
+		*val2 = 0;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mmc35240_write_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan, int val,
+			      int val2, long mask)
+{
+	struct mmc35240_data *data = iio_priv(indio_dev);
+	int i, ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		i = mmc35240_get_samp_freq_index(data, val, val2);
+		if (i < 0)
+			return -EINVAL;
+		mutex_lock(&data->mutex);
+		ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,
+					 MMC35240_CTRL1_BW_MASK,
+					 i << MMC35240_CTRL1_BW_SHIFT);
+		mutex_unlock(&data->mutex);
+		return ret;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info mmc35240_info = {
+	.driver_module	= THIS_MODULE,
+	.read_raw	= mmc35240_read_raw,
+	.write_raw	= mmc35240_write_raw,
+	.attrs		= &mmc35240_attribute_group,
+};
+
+static bool mmc35240_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MMC35240_REG_CTRL0:
+	case MMC35240_REG_CTRL1:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool mmc35240_is_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MMC35240_REG_XOUT_L:
+	case MMC35240_REG_XOUT_H:
+	case MMC35240_REG_YOUT_L:
+	case MMC35240_REG_YOUT_H:
+	case MMC35240_REG_ZOUT_L:
+	case MMC35240_REG_ZOUT_H:
+	case MMC35240_REG_STATUS:
+	case MMC35240_REG_ID:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool mmc35240_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case MMC35240_REG_CTRL0:
+	case MMC35240_REG_CTRL1:
+		return false;
+	default:
+		return true;
+	}
+}
+
+static struct reg_default mmc35240_reg_defaults[] = {
+	{ MMC35240_REG_CTRL0,  0x00 },
+	{ MMC35240_REG_CTRL1,  0x00 },
+};
+
+static const struct regmap_config mmc35240_regmap_config = {
+	.name = MMC35240_REGMAP_NAME,
+
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.max_register = MMC35240_REG_ID,
+	.cache_type = REGCACHE_FLAT,
+
+	.writeable_reg = mmc35240_is_writeable_reg,
+	.readable_reg = mmc35240_is_readable_reg,
+	.volatile_reg = mmc35240_is_volatile_reg,
+
+	.reg_defaults = mmc35240_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(mmc35240_reg_defaults),
+};
+
+static int mmc35240_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
+{
+	struct mmc35240_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, &mmc35240_regmap_config);
+	if (IS_ERR(regmap)) {
+		dev_err(&client->dev, "regmap initialization failed\n");
+		return PTR_ERR(regmap);
+	}
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	data->regmap = regmap;
+	data->res = MMC35240_16_BITS_SLOW;
+
+	mutex_init(&data->mutex);
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->info = &mmc35240_info;
+	indio_dev->name = MMC35240_DRV_NAME;
+	indio_dev->channels = mmc35240_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mmc35240_channels);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = mmc35240_init(data);
+	if (ret < 0) {
+		dev_err(&client->dev, "mmc35240 chip init failed\n");
+		return ret;
+	}
+	return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mmc35240_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mmc35240_data *data = iio_priv(indio_dev);
+
+	regcache_cache_only(data->regmap, true);
+
+	return 0;
+}
+
+static int mmc35240_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct mmc35240_data *data = iio_priv(indio_dev);
+	int ret;
+
+	regcache_mark_dirty(data->regmap);
+	ret = regcache_sync_region(data->regmap, MMC35240_REG_CTRL0,
+				   MMC35240_REG_CTRL1);
+	if (ret < 0)
+		dev_err(dev, "Failed to restore control registers\n");
+
+	regcache_cache_only(data->regmap, false);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops mmc35240_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
+};
+
+static const struct acpi_device_id mmc35240_acpi_match[] = {
+	{"MMC35240", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
+
+static const struct i2c_device_id mmc35240_id[] = {
+	{"MMC35240", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, mmc35240_id);
+
+static struct i2c_driver mmc35240_driver = {
+	.driver = {
+		.name = MMC35240_DRV_NAME,
+		.pm = &mmc35240_pm_ops,
+		.acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
+	},
+	.probe		= mmc35240_probe,
+	.id_table	= mmc35240_id,
+};
+
+module_i2c_driver(mmc35240_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("MEMSIC MMC35240 magnetic sensor driver");
+MODULE_LICENSE("GPL v2");

+ 8 - 8
drivers/iio/orientation/hid-sensor-incl-3d.c

@@ -315,7 +315,6 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct incl_3d_state *incl_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev,
 					  sizeof(struct incl_3d_state));
@@ -336,21 +335,22 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(incl_3d_channels, sizeof(incl_3d_channels),
-			   GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = kmemdup(incl_3d_channels,
+				      sizeof(incl_3d_channels), GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = incl_3d_parse_report(pdev, hsdev, channels,
-				HID_USAGE_SENSOR_INCLINOMETER_3D, incl_state);
+	ret = incl_3d_parse_report(pdev, hsdev,
+				   (struct iio_chan_spec *)indio_dev->channels,
+				   HID_USAGE_SENSOR_INCLINOMETER_3D,
+				   incl_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		goto error_free_dev_mem;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels);
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &incl_3d_info;
@@ -417,7 +417,7 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_incl_3d_ids[] = {
+static const struct platform_device_id hid_incl_3d_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200086",

+ 9 - 8
drivers/iio/orientation/hid-sensor-rotation.c

@@ -222,7 +222,6 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct dev_rot_state *rot_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev,
 					  sizeof(struct dev_rot_state));
@@ -243,21 +242,23 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
-					sizeof(dev_rot_channels), GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
+					   sizeof(dev_rot_channels),
+					   GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = dev_rot_parse_report(pdev, hsdev, channels,
-			HID_USAGE_SENSOR_DEVICE_ORIENTATION, rot_state);
+	ret = dev_rot_parse_report(pdev, hsdev,
+				   (struct iio_chan_spec *)indio_dev->channels,
+				   HID_USAGE_SENSOR_DEVICE_ORIENTATION,
+				   rot_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		return ret;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels);
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &dev_rot_info;
@@ -321,7 +322,7 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_dev_rot_ids[] = {
+static const struct platform_device_id hid_dev_rot_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-20008a",

+ 7 - 7
drivers/iio/pressure/hid-sensor-press.c

@@ -260,7 +260,6 @@ static int hid_press_probe(struct platform_device *pdev)
 	struct iio_dev *indio_dev;
 	struct press_state *press_state;
 	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
-	struct iio_chan_spec *channels;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev,
 				sizeof(struct press_state));
@@ -280,20 +279,21 @@ static int hid_press_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL);
-	if (!channels) {
+	indio_dev->channels = kmemdup(press_channels, sizeof(press_channels),
+				      GFP_KERNEL);
+	if (!indio_dev->channels) {
 		dev_err(&pdev->dev, "failed to duplicate channels\n");
 		return -ENOMEM;
 	}
 
-	ret = press_parse_report(pdev, hsdev, channels,
-				HID_USAGE_SENSOR_PRESSURE, press_state);
+	ret = press_parse_report(pdev, hsdev,
+				 (struct iio_chan_spec *)indio_dev->channels,
+				 HID_USAGE_SENSOR_PRESSURE, press_state);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to setup attributes\n");
 		goto error_free_dev_mem;
 	}
 
-	indio_dev->channels = channels;
 	indio_dev->num_channels =
 				ARRAY_SIZE(press_channels);
 	indio_dev->dev.parent = &pdev->dev;
@@ -360,7 +360,7 @@ static int hid_press_remove(struct platform_device *pdev)
 	return 0;
 }
 
-static struct platform_device_id hid_press_ids[] = {
+static const struct platform_device_id hid_press_ids[] = {
 	{
 		/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 		.name = "HID-SENSOR-200031",

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

@@ -254,9 +254,7 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
 		mutex_unlock(&data->lock);
 		mlx90614_power_put(data);
 
-		if (ret < 0)
-			return ret;
-		return 0;
+		return ret;
 	default:
 		return -EINVAL;
 	}

+ 1 - 1
drivers/staging/iio/accel/Kconfig

@@ -79,7 +79,7 @@ config LIS3L02DQ
 	depends on SPI
 	select IIO_TRIGGER if IIO_BUFFER
 	depends on !IIO_BUFFER || IIO_KFIFO_BUF
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say Y here to build SPI support for the ST microelectronics
 	  accelerometer. The driver supplies direct access via sysfs files

+ 3 - 3
drivers/staging/iio/adc/Kconfig

@@ -5,7 +5,7 @@ menu "Analog to digital converters"
 
 config AD7606
 	tristate "Analog Devices AD7606 ADC driver"
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	select IIO_BUFFER
 	select IIO_TRIGGERED_BUFFER
 	help
@@ -39,7 +39,7 @@ config AD7606_IFACE_SPI
 config AD7780
 	tristate "Analog Devices AD7780 and similar ADCs driver"
 	depends on SPI
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	select AD_SIGMA_DELTA
 	help
 	  Say yes here to build support for Analog Devices AD7170, AD7171,
@@ -52,7 +52,7 @@ config AD7780
 config AD7816
 	tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver"
 	depends on SPI
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say yes here to build support for Analog Devices AD7816/7/8
 	  temperature sensors and ADC.

+ 1 - 1
drivers/staging/iio/addac/Kconfig

@@ -5,7 +5,7 @@ menu "Analog digital bi-direction converters"
 
 config ADT7316
 	tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver"
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318
 	  and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC.

+ 2 - 2
drivers/staging/iio/resolver/Kconfig

@@ -16,7 +16,7 @@ config AD2S90
 config AD2S1200
 	tristate "Analog Devices ad2s1200/ad2s1205 driver"
 	depends on SPI
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say yes here to build support for Analog Devices spi resolver
 	  to digital converters, ad2s1200 and ad2s1205, provides direct access
@@ -28,7 +28,7 @@ config AD2S1200
 config AD2S1210
 	tristate "Analog Devices ad2s1210 driver"
 	depends on SPI
-	depends on GPIOLIB
+	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say yes here to build support for Analog Devices spi resolver
 	  to digital converters, ad2s1210, provides direct access via sysfs.

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

@@ -32,6 +32,7 @@ enum iio_chan_info_enum {
 	IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
 	IIO_CHAN_INFO_AVERAGE_RAW,
 	IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
+	IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY,
 	IIO_CHAN_INFO_SAMP_FREQ,
 	IIO_CHAN_INFO_FREQUENCY,
 	IIO_CHAN_INFO_PHASE,
@@ -44,6 +45,7 @@ enum iio_chan_info_enum {
 	IIO_CHAN_INFO_DEBOUNCE_COUNT,
 	IIO_CHAN_INFO_DEBOUNCE_TIME,
 	IIO_CHAN_INFO_CALIBEMISSIVITY,
+	IIO_CHAN_INFO_OVERSAMPLING_RATIO,
 };
 
 enum iio_shared_by {

+ 2 - 0
include/linux/iio/types.h

@@ -17,6 +17,8 @@ enum iio_event_info {
 	IIO_EV_INFO_VALUE,
 	IIO_EV_INFO_HYSTERESIS,
 	IIO_EV_INFO_PERIOD,
+	IIO_EV_INFO_HIGH_PASS_FILTER_3DB,
+	IIO_EV_INFO_LOW_PASS_FILTER_3DB,
 };
 
 #define IIO_VAL_INT 1

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

@@ -70,6 +70,8 @@ enum iio_modifier {
 	IIO_MOD_WALKING,
 	IIO_MOD_STILL,
 	IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
+	IIO_MOD_I,
+	IIO_MOD_Q,
 };
 
 enum iio_event_type {

+ 2 - 2
tools/iio/Makefile

@@ -1,5 +1,5 @@
-CC = gcc
-CFLAGS = -Wall -g -D_GNU_SOURCE
+CC = $(CROSS_COMPILE)gcc
+CFLAGS += -Wall -g -D_GNU_SOURCE
 
 all: iio_event_monitor lsiio generic_buffer