Staging and IIO driver update for 4.7-rc1

Here's the big staging and iio driver update for 4.7-rc1.
 
 I think we almost broke even with this release, only adding a few more
 lines than we removed, which isn't bad overall given that there's a
 bunch of new iio drivers added.  The Lustre developers seem to have
 woken up from their sleep and have been doing a great job in cleaning up
 the code and pruning unused or old cruft, the filesystem is almost
 readable :)
 
 Other than that, just a lot of basic coding style cleanups in the churn.
 All have been in linux-next for a while with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlc/00QACgkQMUfUDdst+ynXYQCdG9oEsw4CCItbjGfQau5YVGbd
 TOcAnA19tZz+Wcg3sLT8Zsm979dgVvDt
 =9UG/
 -----END PGP SIGNATURE-----

Merge tag 'staging-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging and IIO driver updates from Greg KH:
 "Here's the big staging and iio driver update for 4.7-rc1.

  I think we almost broke even with this release, only adding a few more
  lines than we removed, which isn't bad overall given that there's a
  bunch of new iio drivers added.

  The Lustre developers seem to have woken up from their sleep and have
  been doing a great job in cleaning up the code and pruning unused or
  old cruft, the filesystem is almost readable :)

  Other than that, just a lot of basic coding style cleanups in the
  churn.  All have been in linux-next for a while with no reported
  issues"

* tag 'staging-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (938 commits)
  Staging: emxx_udc: emxx_udc: fixed coding style issue
  staging/gdm724x: fix "alignment should match open parenthesis" issues
  staging/gdm724x: Fix avoid CamelCase
  staging: unisys: rename misleading var ii with frag
  staging: unisys: visorhba: switch success handling to error handling
  staging: unisys: visorhba: main path needs to flow down the left margin
  staging: unisys: visorinput: handle_locking_key() simplifications
  staging: unisys: visorhba: fail gracefully for thread creation failures
  staging: unisys: visornic: comment restructuring and removing bad diction
  staging: unisys: fix format string %Lx to %llx for u64
  staging: unisys: remove unused struct members
  staging: unisys: visorchannel: correct variable misspelling
  staging: unisys: visorhba: replace functionlike macro with function
  staging: dgnc: Need to check for NULL of ch
  staging: dgnc: remove redundant condition check
  staging: dgnc: fix 'line over 80 characters'
  staging: dgnc: clean up the dgnc_get_modem_info()
  staging: lustre: lnet: enable configuration per NI interface
  staging: lustre: o2iblnd: properly set ibr_why
  staging: lustre: o2iblnd: remove last of kiblnd_tunables_fini
  ...
This commit is contained in:
Linus Torvalds 2016-05-20 22:20:48 -07:00
commit 2f37dd131c
668 changed files with 25505 additions and 25079 deletions

View File

@ -1233,7 +1233,7 @@ KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
Description:
Proximity measurement indicating that some
object is near the sensor, usually be observing
object is near the sensor, usually by observing
reflectivity of infrared or ultrasound emitted.
Often these sensors are unit less and as such conversion
to SI units is not possible. Higher proximity measurements
@ -1255,12 +1255,23 @@ Description:
What: /sys/.../iio:deviceX/in_intensityY_raw
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
What: /sys/.../iio:deviceX/in_intensityY_both_raw
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
Description:
Unit-less light intensity. Modifiers both and ir indicate
that measurements contains visible and infrared light
components or just infrared light, respectively.
components or just infrared light, respectively. Modifier uv indicates
that measurements contain ultraviolet light components.
What: /sys/.../iio:deviceX/in_uvindex_input
KernelVersion: 4.6
Contact: linux-iio@vger.kernel.org
Description:
UV light intensity index measuring the human skin's response to
different wavelength of sunlight weighted according to the
standardised CIE Erythemal Action Spectrum. UV index values range
from 0 (low) to >=11 (extreme).
What: /sys/.../iio:deviceX/in_intensity_red_integration_time
What: /sys/.../iio:deviceX/in_intensity_green_integration_time
@ -1501,3 +1512,56 @@ Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) pH reading of a substance as a negative
base-10 logarithm of hydrodium ions in a litre of water.
What: /sys/bus/iio/devices/iio:deviceX/mount_matrix
What: /sys/bus/iio/devices/iio:deviceX/in_mount_matrix
What: /sys/bus/iio/devices/iio:deviceX/out_mount_matrix
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_mount_matrix
What: /sys/bus/iio/devices/iio:deviceX/in_accel_mount_matrix
KernelVersion: 4.6
Contact: linux-iio@vger.kernel.org
Description:
Mounting matrix for IIO sensors. This is a rotation matrix which
informs userspace about sensor chip's placement relative to the
main hardware it is mounted on.
Main hardware placement is defined according to the local
reference frame related to the physical quantity the sensor
measures.
Given that the rotation matrix is defined in a board specific
way (platform data and / or device-tree), the main hardware
reference frame definition is left to the implementor's choice
(see below for a magnetometer example).
Applications should apply this rotation matrix to samples so
that when main hardware reference frame is aligned onto local
reference frame, then sensor chip reference frame is also
perfectly aligned with it.
Matrix is a 3x3 unitary matrix and typically looks like
[0, 1, 0; 1, 0, 0; 0, 0, -1]. Identity matrix
[1, 0, 0; 0, 1, 0; 0, 0, 1] means sensor chip and main hardware
are perfectly aligned with each other.
For example, a mounting matrix for a magnetometer sensor informs
userspace about sensor chip's ORIENTATION relative to the main
hardware.
More specifically, main hardware orientation is defined with
respect to the LOCAL EARTH GEOMAGNETIC REFERENCE FRAME where :
* Y is in the ground plane and positive towards magnetic North ;
* X is in the ground plane, perpendicular to the North axis and
positive towards the East ;
* Z is perpendicular to the ground plane and positive upwards.
An implementor might consider that for a hand-held device, a
'natural' orientation would be 'front facing camera at the top'.
The main hardware reference frame could then be described as :
* Y is in the plane of the screen and is positive towards the
top of the screen ;
* X is in the plane of the screen, perpendicular to Y axis, and
positive towards the right hand side of the screen ;
* Z is perpendicular to the screen plane and positive out of the
screen.
Another example for a quadrotor UAV might be :
* Y is in the plane of the propellers and positive towards the
front-view camera;
* X is in the plane of the propellers, perpendicular to Y axis,
and positive towards the starboard side of the UAV ;
* Z is perpendicular to propellers plane and positive upwards.

View File

@ -136,6 +136,8 @@ X!Edrivers/base/interface.c
!Iinclude/linux/seqno-fence.h
!Edrivers/dma-buf/reservation.c
!Iinclude/linux/reservation.h
!Edrivers/dma-buf/sync_file.c
!Iinclude/linux/sync_file.h
!Edrivers/base/dma-coherent.c
!Edrivers/base/dma-mapping.c
</sect1>

View File

@ -1,4 +1,4 @@
Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC
Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC or FXLS8471Q
triaxial accelerometer
Required properties:
@ -9,6 +9,7 @@ Required properties:
* "fsl,mma8453"
* "fsl,mma8652"
* "fsl,mma8653"
* "fsl,fxls8471"
- reg: the I2C address of the chip

View File

@ -0,0 +1,21 @@
NXP LPC1850 ADC bindings
Required properties:
- compatible: Should be "nxp,lpc1850-adc"
- reg: Offset and length of the register set for the ADC device
- interrupts: The interrupt number for the ADC device
- clocks: The root clock of the ADC controller
- vref-supply: The regulator supply ADC reference voltage
- resets: phandle to reset controller and line specifier
Example:
adc0: adc@400e3000 {
compatible = "nxp,lpc1850-adc";
reg = <0x400e3000 0x1000>;
interrupts = <17>;
clocks = <&ccu1 CLK_APB3_ADC0>;
vref-supply = <&reg_vdda>;
resets = <&rgu 40>;
status = "disabled";
};

View File

@ -1,7 +1,11 @@
Rockchip Successive Approximation Register (SAR) A/D Converter bindings
Required properties:
- compatible: Should be "rockchip,saradc" or "rockchip,rk3066-tsadc"
- compatible: should be "rockchip,<name>-saradc" or "rockchip,rk3066-tsadc"
- "rockchip,saradc": for rk3188, rk3288
- "rockchip,rk3066-tsadc": for rk3036
- "rockchip,rk3399-saradc": for rk3399
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu. The interrupt specifier format

View File

@ -0,0 +1,155 @@
Analog Devices AD5592R/AD5593R DAC/ADC device driver
Required properties for the AD5592R:
- compatible: Must be "adi,ad5592r"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use (< 30000000)
- spi-cpol: The AD5592R requires inverse clock polarity (CPOL) mode
Required properties for the AD5593R:
- compatible: Must be "adi,ad5593r"
- reg: I2C address of the device
Required properties for all supported chips:
- #address-cells: Should be 1.
- #size-cells: Should be 0.
- channel nodes:
Each child node represents one channel and has the following
Required properties:
* reg: Pin on which this channel is connected to.
* adi,mode: Mode or function of this channel.
Macros specifying the valid values
can be found in <dt-bindings/iio/adi,ad5592r.h>.
The following values are currently supported:
* CH_MODE_UNUSED (the pin is unused)
* CH_MODE_ADC (the pin is ADC input)
* CH_MODE_DAC (the pin is DAC output)
* CH_MODE_DAC_AND_ADC (the pin is DAC output
but can be monitored by an ADC, since
there is no disadvantage this
this should be considered as the
preferred DAC mode)
* CH_MODE_GPIO (the pin is registered
with GPIOLIB)
Optional properties:
* adi,off-state: State of this channel when unused or the
device gets removed. Macros specifying the
valid values can be found in
<dt-bindings/iio/adi,ad5592r.h>.
* CH_OFFSTATE_PULLDOWN (the pin is pulled down)
* CH_OFFSTATE_OUT_LOW (the pin is output low)
* CH_OFFSTATE_OUT_HIGH (the pin is output high)
* CH_OFFSTATE_OUT_TRISTATE (the pin is
tristated output)
Optional properties:
- vref-supply: Phandle to the external reference voltage supply. This should
only be set if there is an external reference voltage connected to the VREF
pin. If the property is not set the internal 2.5V reference is used.
- reset-gpios : GPIO spec for the RESET pin. If specified, it will be
asserted during driver probe.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>.
AD5592R Example:
#include <dt-bindings/iio/adi,ad5592r.h>
vref: regulator-vref {
compatible = "regulator-fixed";
regulator-name = "vref-ad559x";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
ad5592r@0 {
#size-cells = <0>;
#address-cells = <1>;
#gpio-cells = <2>;
compatible = "adi,ad5592r";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
vref-supply = <&vref>; /* optional */
reset-gpios = <&gpio0 86 0>; /* optional */
gpio-controller;
channel@0 {
reg = <0>;
adi,mode = <CH_MODE_DAC>;
};
channel@1 {
reg = <1>;
adi,mode = <CH_MODE_ADC>;
};
channel@2 {
reg = <2>;
adi,mode = <CH_MODE_DAC_AND_ADC>;
};
channel@3 {
reg = <3>;
adi,mode = <CH_MODE_DAC_AND_ADC>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@4 {
reg = <4>;
adi,mode = <CH_MODE_UNUSED>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@5 {
reg = <5>;
adi,mode = <CH_MODE_GPIO>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@6 {
reg = <6>;
adi,mode = <CH_MODE_GPIO>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@7 {
reg = <7>;
adi,mode = <CH_MODE_GPIO>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
};
AD5593R Example:
#include <dt-bindings/iio/adi,ad5592r.h>
ad5593r@10 {
#size-cells = <0>;
#address-cells = <1>;
#gpio-cells = <2>;
compatible = "adi,ad5593r";
reg = <0x10>;
gpio-controller;
channel@0 {
reg = <0>;
adi,mode = <CH_MODE_DAC>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@1 {
reg = <1>;
adi,mode = <CH_MODE_ADC>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@2 {
reg = <2>;
adi,mode = <CH_MODE_DAC_AND_ADC>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
channel@6 {
reg = <6>;
adi,mode = <CH_MODE_GPIO>;
adi,off-state = <CH_OFFSTATE_PULLDOWN>;
};
};

View File

@ -0,0 +1,20 @@
NXP LPC1850 DAC bindings
Required properties:
- compatible: Should be "nxp,lpc1850-dac"
- reg: Offset and length of the register set for the ADC device
- interrupts: The interrupt number for the ADC device
- clocks: The root clock of the ADC controller
- vref-supply: The regulator supply ADC reference voltage
- resets: phandle to reset controller and line specifier
Example:
dac: dac@400e1000 {
compatible = "nxp,lpc1850-dac";
reg = <0x400e1000 0x1000>;
interrupts = <0>;
clocks = <&ccu1 CLK_APB3_DAC>;
vref-supply = <&reg_vdda>;
resets = <&rgu 42>;
status = "disabled";
};

View File

@ -8,10 +8,23 @@ Required properties:
- interrupt-parent : should be the phandle for the interrupt controller
- interrupts : interrupt mapping for GPIO IRQ
Optional properties:
- mount-matrix: an optional 3x3 mounting rotation matrix
Example:
mpu6050@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
interrupt-parent = <&gpio1>;
interrupts = <18 1>;
mount-matrix = "-0.984807753012208", /* x0 */
"0", /* y0 */
"-0.173648177666930", /* z0 */
"0", /* x1 */
"-1", /* y1 */
"0", /* z1 */
"-0.173648177666930", /* x2 */
"0", /* y2 */
"0.984807753012208"; /* z2 */
};

View File

@ -8,6 +8,8 @@ Required properties:
Optional properties:
- gpios : should be device tree identifier of the magnetometer DRDY pin
- vdd-supply: an optional regulator that needs to be on to provide VDD
- mount-matrix: an optional 3x3 mounting rotation matrix
Example:
@ -15,4 +17,14 @@ ak8975@0c {
compatible = "asahi-kasei,ak8975";
reg = <0x0c>;
gpios = <&gpj0 7 0>;
vdd-supply = <&ldo_3v3_gnss>;
mount-matrix = "-0.984807753012208", /* x0 */
"0", /* y0 */
"-0.173648177666930", /* z0 */
"0", /* x1 */
"-1", /* y1 */
"0", /* z1 */
"-0.173648177666930", /* x2 */
"0", /* y2 */
"0.984807753012208"; /* z2 */
};

View File

@ -0,0 +1,21 @@
* Maxim Integrated DS1803 digital potentiometer driver
The node for this driver must be a child node of a I2C controller, hence
all mandatory properties for your controller must be specified. See directory:
Documentation/devicetree/bindings/i2c
for more details.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"maxim,ds1803-010",
"maxim,ds1803-050",
"maxim,ds1803-100"
Example:
ds1803: ds1803@1 {
reg = <0x28>;
compatible = "maxim,ds1803-010";
};

View File

@ -0,0 +1,84 @@
* Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer
driver
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"microchip,mcp4131-502"
"microchip,mcp4131-103"
"microchip,mcp4131-503"
"microchip,mcp4131-104"
"microchip,mcp4132-502"
"microchip,mcp4132-103"
"microchip,mcp4132-503"
"microchip,mcp4132-104"
"microchip,mcp4141-502"
"microchip,mcp4141-103"
"microchip,mcp4141-503"
"microchip,mcp4141-104"
"microchip,mcp4142-502"
"microchip,mcp4142-103"
"microchip,mcp4142-503"
"microchip,mcp4142-104"
"microchip,mcp4151-502"
"microchip,mcp4151-103"
"microchip,mcp4151-503"
"microchip,mcp4151-104"
"microchip,mcp4152-502"
"microchip,mcp4152-103"
"microchip,mcp4152-503"
"microchip,mcp4152-104"
"microchip,mcp4161-502"
"microchip,mcp4161-103"
"microchip,mcp4161-503"
"microchip,mcp4161-104"
"microchip,mcp4162-502"
"microchip,mcp4162-103"
"microchip,mcp4162-503"
"microchip,mcp4162-104"
"microchip,mcp4231-502"
"microchip,mcp4231-103"
"microchip,mcp4231-503"
"microchip,mcp4231-104"
"microchip,mcp4232-502"
"microchip,mcp4232-103"
"microchip,mcp4232-503"
"microchip,mcp4232-104"
"microchip,mcp4241-502"
"microchip,mcp4241-103"
"microchip,mcp4241-503"
"microchip,mcp4241-104"
"microchip,mcp4242-502"
"microchip,mcp4242-103"
"microchip,mcp4242-503"
"microchip,mcp4242-104"
"microchip,mcp4251-502"
"microchip,mcp4251-103"
"microchip,mcp4251-503"
"microchip,mcp4251-104"
"microchip,mcp4252-502"
"microchip,mcp4252-103"
"microchip,mcp4252-503"
"microchip,mcp4252-104"
"microchip,mcp4261-502"
"microchip,mcp4261-103"
"microchip,mcp4261-503"
"microchip,mcp4261-104"
"microchip,mcp4262-502"
"microchip,mcp4262-103"
"microchip,mcp4262-503"
"microchip,mcp4262-104"
Example:
mcp4131: mcp4131@0 {
compatible = "mcp4131-502";
reg = <0>;
spi-max-frequency = <500000>;
};

View File

@ -0,0 +1,17 @@
HopeRF HP03 digital pressure/temperature sensors
Required properties:
- compatible: must be "hoperf,hp03"
- xclr-gpio: must be device tree identifier of the XCLR pin.
The XCLR pin is a reset of the ADC in the chip,
it must be pulled HI before the conversion and
readout of the value from the ADC registers and
pulled LO afterward.
Example:
hp03@0x77 {
compatible = "hoperf,hp03";
reg = <0x77>;
xclr-gpio = <&portc 0 0x0>;
};

View File

@ -0,0 +1,19 @@
MEAS ms5611 family pressure sensors
Pressure sensors from MEAS Switzerland with SPI and I2C bus interfaces.
Required properties:
- compatible: "meas,ms5611" or "meas,ms5607"
- reg: the I2C address or SPI chip select the device will respond to
Optional properties:
- vdd-supply: an optional regulator that needs to be on to provide VDD
power to the sensor.
Example:
ms5607@77 {
compatible = "meas,ms5607";
reg = <0x77>;
vdd-supply = <&ldo_3v3_gnss>;
};

View File

@ -16,6 +16,10 @@ Optional properties:
- st,drdy-int-pin: the pin on the package that will be used to signal
"data ready" (valid values: 1 or 2). This property is not configurable
on all sensors.
- drive-open-drain: the interrupt/data ready line will be configured
as open drain, which is useful if several sensors share the same
interrupt line. (This binding is taken from pinctrl/pinctrl-bindings.txt)
This is a boolean property.
Sensors may also have applicable pin control settings, those use the
standard bindings from pinctrl/pinctrl-bindings.txt.
@ -37,6 +41,7 @@ Accelerometers:
- st,lsm330-accel
- st,lsm303agr-accel
- st,lis2dh12-accel
- st,h3lis331dl-accel
Gyroscopes:
- st,l3g4200d-gyro
@ -46,6 +51,7 @@ Gyroscopes:
- st,l3gd20-gyro
- st,l3g4is-gyro
- st,lsm330-gyro
- st,lsm9ds0-gyro
Magnetometers:
- st,lsm303agr-magn

View File

@ -151,6 +151,7 @@ lsi LSI Corp. (LSI Logic)
lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
meas Measurement Specialties
mediatek MediaTek Inc.
melexis Melexis N.V.
merrii Merrii Technology Co., Ltd.

View File

@ -268,6 +268,10 @@ IIO
devm_iio_kfifo_free()
devm_iio_trigger_alloc()
devm_iio_trigger_free()
devm_iio_channel_get()
devm_iio_channel_release()
devm_iio_channel_get_all()
devm_iio_channel_release_all()
INPUT
devm_input_allocate_device()

View File

@ -0,0 +1,69 @@
Sync File API Guide
~~~~~~~~~~~~~~~~~~~
Gustavo Padovan
<gustavo at padovan dot org>
This document serves as a guide for device drivers writers on what the
sync_file API is, and how drivers can support it. Sync file is the carrier of
the fences(struct fence) that needs to synchronized between drivers or across
process boundaries.
The sync_file API is meant to be used to send and receive fence information
to/from userspace. It enables userspace to do explicit fencing, where instead
of attaching a fence to the buffer a producer driver (such as a GPU or V4L
driver) sends the fence related to the buffer to userspace via a sync_file.
The sync_file then can be sent to the consumer (DRM driver for example), that
will not use the buffer for anything before the fence(s) signals, i.e., the
driver that issued the fence is not using/processing the buffer anymore, so it
signals that the buffer is ready to use. And vice-versa for the consumer ->
producer part of the cycle.
Sync files allows userspace awareness on buffer sharing synchronization between
drivers.
Sync file was originally added in the Android kernel but current Linux Desktop
can benefit a lot from it.
in-fences and out-fences
------------------------
Sync files can go either to or from userspace. When a sync_file is sent from
the driver to userspace we call the fences it contains 'out-fences'. They are
related to a buffer that the driver is processing or is going to process, so
the driver an create out-fence to be able to notify, through fence_signal(),
when it has finished using (or processing) that buffer. Out-fences are fences
that the driver creates.
On the other hand if the driver receives fence(s) through a sync_file from
userspace we call these fence(s) 'in-fences'. Receiveing in-fences means that
we need to wait for the fence(s) to signal before using any buffer related to
the in-fences.
Creating Sync Files
-------------------
When a driver needs to send an out-fence userspace it creates a sync_file.
Interface:
struct sync_file *sync_file_create(struct fence *fence);
The caller pass the out-fence and gets back the sync_file. That is just the
first step, next it needs to install an fd on sync_file->file. So it gets an
fd:
fd = get_unused_fd_flags(O_CLOEXEC);
and installs it on sync_file->file:
fd_install(fd, sync_file->file);
The sync_file fd now can be sent to userspace.
If the creation process fail, or the sync_file needs to be released by any
other reason fput(sync_file->file) should be used.
References:
[1] struct sync_file in include/linux/sync_file.h
[2] All interfaces mentioned above defined in include/linux/sync_file.h

View File

@ -776,6 +776,15 @@ S: Supported
F: drivers/android/
F: drivers/staging/android/
ANDROID ION DRIVER
M: Laura Abbott <labbott@redhat.com>
M: Sumit Semwal <sumit.semwal@linaro.org>
L: devel@driverdev.osuosl.org
S: Supported
F: drivers/staging/android/ion
F: drivers/staging/android/uapi/ion.h
F: drivers/staging/android/uapi/ion_test.h
AOA (Apple Onboard Audio) ALSA DRIVER
M: Johannes Berg <johannes@sipsolutions.net>
L: linuxppc-dev@lists.ozlabs.org
@ -4746,6 +4755,7 @@ F: sound/soc/fsl/mpc8610_hpcd.c
FREESCALE QORIQ MANAGEMENT COMPLEX DRIVER
M: "J. German Rivera" <German.Rivera@freescale.com>
M: Stuart Yoder <stuart.yoder@nxp.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-mc/
@ -5617,7 +5627,7 @@ IIO SUBSYSTEM AND DRIVERS
M: Jonathan Cameron <jic23@kernel.org>
R: Hartmut Knaack <knaack.h@gmx.de>
R: Lars-Peter Clausen <lars@metafoo.de>
R: Peter Meerwald <pmeerw@pmeerw.net>
R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/

View File

@ -114,6 +114,8 @@ source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
source "drivers/dma-buf/Kconfig"
source "drivers/dca/Kconfig"
source "drivers/auxdisplay/Kconfig"

11
drivers/dma-buf/Kconfig Normal file
View File

@ -0,0 +1,11 @@
menu "DMABUF options"
config SYNC_FILE
bool "sync_file support for fences"
default n
select ANON_INODES
select DMA_SHARED_BUFFER
---help---
This option enables the fence framework synchronization to export
sync_files to userspace that can represent one or more fences.
endmenu

View File

@ -1 +1,2 @@
obj-y := dma-buf.o fence.o reservation.o seqno-fence.o
obj-$(CONFIG_SYNC_FILE) += sync_file.o

395
drivers/dma-buf/sync_file.c Normal file
View File

@ -0,0 +1,395 @@
/*
* drivers/dma-buf/sync_file.c
*
* Copyright (C) 2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/export.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/anon_inodes.h>
#include <linux/sync_file.h>
#include <uapi/linux/sync_file.h>
static const struct file_operations sync_file_fops;
static struct sync_file *sync_file_alloc(int size)
{
struct sync_file *sync_file;
sync_file = kzalloc(size, GFP_KERNEL);
if (!sync_file)
return NULL;
sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops,
sync_file, 0);
if (IS_ERR(sync_file->file))
goto err;
kref_init(&sync_file->kref);
init_waitqueue_head(&sync_file->wq);
return sync_file;
err:
kfree(sync_file);
return NULL;
}
static void fence_check_cb_func(struct fence *f, struct fence_cb *cb)
{
struct sync_file_cb *check;
struct sync_file *sync_file;
check = container_of(cb, struct sync_file_cb, cb);
sync_file = check->sync_file;
if (atomic_dec_and_test(&sync_file->status))
wake_up_all(&sync_file->wq);
}
/**
* sync_file_create() - creates a sync file
* @fence: fence to add to the sync_fence
*
* Creates a sync_file containg @fence. Once this is called, the sync_file
* takes ownership of @fence. The sync_file can be released with
* fput(sync_file->file). Returns the sync_file or NULL in case of error.
*/
struct sync_file *sync_file_create(struct fence *fence)
{
struct sync_file *sync_file;
sync_file = sync_file_alloc(offsetof(struct sync_file, cbs[1]));
if (!sync_file)
return NULL;
sync_file->num_fences = 1;
atomic_set(&sync_file->status, 1);
snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%d-%d",
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence), fence->context,
fence->seqno);
sync_file->cbs[0].fence = fence;
sync_file->cbs[0].sync_file = sync_file;
if (fence_add_callback(fence, &sync_file->cbs[0].cb,
fence_check_cb_func))
atomic_dec(&sync_file->status);
return sync_file;
}
EXPORT_SYMBOL(sync_file_create);
/**
* sync_file_fdget() - get a sync_file from an fd
* @fd: fd referencing a fence
*
* Ensures @fd references a valid sync_file, increments the refcount of the
* backing file. Returns the sync_file or NULL in case of error.
*/
static struct sync_file *sync_file_fdget(int fd)
{
struct file *file = fget(fd);
if (!file)
return NULL;
if (file->f_op != &sync_file_fops)
goto err;
return file->private_data;
err:
fput(file);
return NULL;
}
static void sync_file_add_pt(struct sync_file *sync_file, int *i,
struct fence *fence)
{
sync_file->cbs[*i].fence = fence;
sync_file->cbs[*i].sync_file = sync_file;
if (!fence_add_callback(fence, &sync_file->cbs[*i].cb,
fence_check_cb_func)) {
fence_get(fence);
(*i)++;
}
}
/**
* sync_file_merge() - merge two sync_files
* @name: name of new fence
* @a: sync_file a
* @b: sync_file b
*
* Creates a new sync_file which contains copies of all the fences in both
* @a and @b. @a and @b remain valid, independent sync_file. Returns the
* new merged sync_file or NULL in case of error.
*/
static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
struct sync_file *b)
{
int num_fences = a->num_fences + b->num_fences;
struct sync_file *sync_file;
int i, i_a, i_b;
unsigned long size = offsetof(struct sync_file, cbs[num_fences]);
sync_file = sync_file_alloc(size);
if (!sync_file)
return NULL;
atomic_set(&sync_file->status, num_fences);
/*
* Assume sync_file a and b are both ordered and have no
* duplicates with the same context.
*
* If a sync_file can only be created with sync_file_merge
* and sync_file_create, this is a reasonable assumption.
*/
for (i = i_a = i_b = 0; i_a < a->num_fences && i_b < b->num_fences; ) {
struct fence *pt_a = a->cbs[i_a].fence;
struct fence *pt_b = b->cbs[i_b].fence;
if (pt_a->context < pt_b->context) {
sync_file_add_pt(sync_file, &i, pt_a);
i_a++;
} else if (pt_a->context > pt_b->context) {
sync_file_add_pt(sync_file, &i, pt_b);
i_b++;
} else {
if (pt_a->seqno - pt_b->seqno <= INT_MAX)
sync_file_add_pt(sync_file, &i, pt_a);
else
sync_file_add_pt(sync_file, &i, pt_b);
i_a++;
i_b++;
}
}
for (; i_a < a->num_fences; i_a++)
sync_file_add_pt(sync_file, &i, a->cbs[i_a].fence);
for (; i_b < b->num_fences; i_b++)
sync_file_add_pt(sync_file, &i, b->cbs[i_b].fence);
if (num_fences > i)
atomic_sub(num_fences - i, &sync_file->status);
sync_file->num_fences = i;
strlcpy(sync_file->name, name, sizeof(sync_file->name));
return sync_file;
}
static void sync_file_free(struct kref *kref)
{
struct sync_file *sync_file = container_of(kref, struct sync_file,
kref);
int i;
for (i = 0; i < sync_file->num_fences; ++i) {
fence_remove_callback(sync_file->cbs[i].fence,
&sync_file->cbs[i].cb);
fence_put(sync_file->cbs[i].fence);
}
kfree(sync_file);
}
static int sync_file_release(struct inode *inode, struct file *file)
{
struct sync_file *sync_file = file->private_data;
kref_put(&sync_file->kref, sync_file_free);
return 0;
}
static unsigned int sync_file_poll(struct file *file, poll_table *wait)
{
struct sync_file *sync_file = file->private_data;
int status;
poll_wait(file, &sync_file->wq, wait);
status = atomic_read(&sync_file->status);
if (!status)
return POLLIN;
if (status < 0)
return POLLERR;
return 0;
}
static long sync_file_ioctl_merge(struct sync_file *sync_file,
unsigned long arg)
{
int fd = get_unused_fd_flags(O_CLOEXEC);
int err;
struct sync_file *fence2, *fence3;
struct sync_merge_data data;
if (fd < 0)
return fd;
if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
err = -EFAULT;
goto err_put_fd;
}
if (data.flags || data.pad) {
err = -EINVAL;
goto err_put_fd;
}
fence2 = sync_file_fdget(data.fd2);
if (!fence2) {
err = -ENOENT;
goto err_put_fd;
}
data.name[sizeof(data.name) - 1] = '\0';
fence3 = sync_file_merge(data.name, sync_file, fence2);
if (!fence3) {
err = -ENOMEM;
goto err_put_fence2;
}
data.fence = fd;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
err = -EFAULT;
goto err_put_fence3;
}
fd_install(fd, fence3->file);
fput(fence2->file);
return 0;
err_put_fence3:
fput(fence3->file);
err_put_fence2:
fput(fence2->file);
err_put_fd:
put_unused_fd(fd);
return err;
}
static void sync_fill_fence_info(struct fence *fence,
struct sync_fence_info *info)
{
strlcpy(info->obj_name, fence->ops->get_timeline_name(fence),
sizeof(info->obj_name));
strlcpy(info->driver_name, fence->ops->get_driver_name(fence),
sizeof(info->driver_name));
if (fence_is_signaled(fence))
info->status = fence->status >= 0 ? 1 : fence->status;
else
info->status = 0;
info->timestamp_ns = ktime_to_ns(fence->timestamp);
}
static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
unsigned long arg)
{
struct sync_file_info info;
struct sync_fence_info *fence_info = NULL;
__u32 size;
int ret, i;
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
return -EFAULT;
if (info.flags || info.pad)
return -EINVAL;
/*
* Passing num_fences = 0 means that userspace doesn't want to
* retrieve any sync_fence_info. If num_fences = 0 we skip filling
* sync_fence_info and return the actual number of fences on
* info->num_fences.
*/
if (!info.num_fences)
goto no_fences;
if (info.num_fences < sync_file->num_fences)
return -EINVAL;
size = sync_file->num_fences * sizeof(*fence_info);
fence_info = kzalloc(size, GFP_KERNEL);
if (!fence_info)
return -ENOMEM;
for (i = 0; i < sync_file->num_fences; ++i)
sync_fill_fence_info(sync_file->cbs[i].fence, &fence_info[i]);
if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
size)) {
ret = -EFAULT;
goto out;
}
no_fences:
strlcpy(info.name, sync_file->name, sizeof(info.name));
info.status = atomic_read(&sync_file->status);
if (info.status >= 0)
info.status = !info.status;
info.num_fences = sync_file->num_fences;
if (copy_to_user((void __user *)arg, &info, sizeof(info)))
ret = -EFAULT;
else
ret = 0;
out:
kfree(fence_info);
return ret;
}
static long sync_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct sync_file *sync_file = file->private_data;
switch (cmd) {
case SYNC_IOC_MERGE:
return sync_file_ioctl_merge(sync_file, arg);
case SYNC_IOC_FILE_INFO:
return sync_file_ioctl_fence_info(sync_file, arg);
default:
return -ENOTTY;
}
}
static const struct file_operations sync_file_fops = {
.release = sync_file_release,
.poll = sync_file_poll,
.unlocked_ioctl = sync_file_ioctl,
.compat_ioctl = sync_file_ioctl,
};

View File

@ -28,11 +28,6 @@
#define BO_LOCKED 0x4000
#define BO_PINNED 0x2000
static inline void __user *to_user_ptr(u64 address)
{
return (void __user *)(uintptr_t)address;
}
static struct etnaviv_gem_submit *submit_create(struct drm_device *dev,
struct etnaviv_gpu *gpu, size_t nr)
{
@ -347,21 +342,21 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
cmdbuf->exec_state = args->exec_state;
cmdbuf->ctx = file->driver_priv;
ret = copy_from_user(bos, to_user_ptr(args->bos),
ret = copy_from_user(bos, u64_to_user_ptr(args->bos),
args->nr_bos * sizeof(*bos));
if (ret) {
ret = -EFAULT;
goto err_submit_cmds;
}
ret = copy_from_user(relocs, to_user_ptr(args->relocs),
ret = copy_from_user(relocs, u64_to_user_ptr(args->relocs),
args->nr_relocs * sizeof(*relocs));
if (ret) {
ret = -EFAULT;
goto err_submit_cmds;
}
ret = copy_from_user(stream, to_user_ptr(args->stream),
ret = copy_from_user(stream, u64_to_user_ptr(args->stream),
args->stream_size);
if (ret) {
ret = -EFAULT;

View File

@ -3577,11 +3577,6 @@ static inline i915_reg_t i915_vgacntrl_reg(struct drm_device *dev)
return VGACNTRL;
}
static inline void __user *to_user_ptr(u64 address)
{
return (void __user *)(uintptr_t)address;
}
static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m)
{
unsigned long j = msecs_to_jiffies(m);

View File

@ -324,7 +324,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
void *vaddr = obj->phys_handle->vaddr + args->offset;
char __user *user_data = to_user_ptr(args->data_ptr);
char __user *user_data = u64_to_user_ptr(args->data_ptr);
int ret = 0;
/* We manually control the domain here and pretend that it
@ -605,7 +605,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
int needs_clflush = 0;
struct sg_page_iter sg_iter;
user_data = to_user_ptr(args->data_ptr);
user_data = u64_to_user_ptr(args->data_ptr);
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@ -692,7 +692,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
return 0;
if (!access_ok(VERIFY_WRITE,
to_user_ptr(args->data_ptr),
u64_to_user_ptr(args->data_ptr),
args->size))
return -EFAULT;
@ -783,7 +783,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
if (ret)
goto out_unpin;
user_data = to_user_ptr(args->data_ptr);
user_data = u64_to_user_ptr(args->data_ptr);
remain = args->size;
offset = i915_gem_obj_ggtt_offset(obj) + args->offset;
@ -907,7 +907,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
int needs_clflush_before = 0;
struct sg_page_iter sg_iter;
user_data = to_user_ptr(args->data_ptr);
user_data = u64_to_user_ptr(args->data_ptr);
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
@ -1036,12 +1036,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
return 0;
if (!access_ok(VERIFY_READ,
to_user_ptr(args->data_ptr),
u64_to_user_ptr(args->data_ptr),
args->size))
return -EFAULT;
if (likely(!i915.prefault_disable)) {
ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
ret = fault_in_multipages_readable(u64_to_user_ptr(args->data_ptr),
args->size);
if (ret)
return -EFAULT;

View File

@ -514,7 +514,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
int remain, ret;
user_relocs = to_user_ptr(entry->relocs_ptr);
user_relocs = u64_to_user_ptr(entry->relocs_ptr);
remain = entry->relocation_count;
while (remain) {
@ -865,7 +865,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
u64 invalid_offset = (u64)-1;
int j;
user_relocs = to_user_ptr(exec[i].relocs_ptr);
user_relocs = u64_to_user_ptr(exec[i].relocs_ptr);
if (copy_from_user(reloc+total, user_relocs,
exec[i].relocation_count * sizeof(*reloc))) {
@ -1009,7 +1009,7 @@ validate_exec_list(struct drm_device *dev,
invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
for (i = 0; i < count; i++) {
char __user *ptr = to_user_ptr(exec[i].relocs_ptr);
char __user *ptr = u64_to_user_ptr(exec[i].relocs_ptr);
int length; /* limited by fault_in_pages_readable() */
if (exec[i].flags & invalid_flags)
@ -1696,7 +1696,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
return -ENOMEM;
}
ret = copy_from_user(exec_list,
to_user_ptr(args->buffers_ptr),
u64_to_user_ptr(args->buffers_ptr),
sizeof(*exec_list) * args->buffer_count);
if (ret != 0) {
DRM_DEBUG("copy %d exec entries failed %d\n",
@ -1732,7 +1732,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
if (!ret) {
struct drm_i915_gem_exec_object __user *user_exec_list =
to_user_ptr(args->buffers_ptr);
u64_to_user_ptr(args->buffers_ptr);
/* Copy the new buffer offsets back to the user's exec list. */
for (i = 0; i < args->buffer_count; i++) {
@ -1786,7 +1786,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
return -ENOMEM;
}
ret = copy_from_user(exec2_list,
to_user_ptr(args->buffers_ptr),
u64_to_user_ptr(args->buffers_ptr),
sizeof(*exec2_list) * args->buffer_count);
if (ret != 0) {
DRM_DEBUG("copy %d exec entries failed %d\n",
@ -1799,7 +1799,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
if (!ret) {
/* Copy the new buffer offsets back to the user's exec list. */
struct drm_i915_gem_exec_object2 __user *user_exec_list =
to_user_ptr(args->buffers_ptr);
u64_to_user_ptr(args->buffers_ptr);
int i;
for (i = 0; i < args->buffer_count; i++) {

View File

@ -28,11 +28,6 @@
#define BO_LOCKED 0x4000
#define BO_PINNED 0x2000
static inline void __user *to_user_ptr(u64 address)
{
return (void __user *)(uintptr_t)address;
}
static struct msm_gem_submit *submit_create(struct drm_device *dev,
struct msm_gpu *gpu, int nr)
{
@ -68,7 +63,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
struct drm_gem_object *obj;
struct msm_gem_object *msm_obj;
void __user *userptr =
to_user_ptr(args->bos + (i * sizeof(submit_bo)));
u64_to_user_ptr(args->bos + (i * sizeof(submit_bo)));
ret = copy_from_user(&submit_bo, userptr, sizeof(submit_bo));
if (ret) {
@ -257,7 +252,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
for (i = 0; i < nr_relocs; i++) {
struct drm_msm_gem_submit_reloc submit_reloc;
void __user *userptr =
to_user_ptr(relocs + (i * sizeof(submit_reloc)));
u64_to_user_ptr(relocs + (i * sizeof(submit_reloc)));
uint32_t iova, off;
bool valid;
@ -356,7 +351,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
for (i = 0; i < args->nr_cmds; i++) {
struct drm_msm_gem_submit_cmd submit_cmd;
void __user *userptr =
to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
u64_to_user_ptr(args->cmds + (i * sizeof(submit_cmd)));
struct msm_gem_object *msm_obj;
uint32_t iova;

View File

@ -64,7 +64,7 @@ config IIO_ST_ACCEL_3AXIS
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL.
This driver can also be built as a module. If so, these modules
will be created:
@ -143,7 +143,8 @@ config MMA8452
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the following Freescale 3-axis
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC,
FXLS8471Q.
To compile this driver as a module, choose M here: the module
will be called mma8452.

View File

@ -25,7 +25,6 @@
#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>
@ -138,6 +137,7 @@ enum bmc150_accel_axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
AXIS_MAX,
};
enum bmc150_power_modes {
@ -188,7 +188,6 @@ enum bmc150_accel_trigger_id {
struct bmc150_accel_data {
struct regmap *regmap;
struct device *dev;
int irq;
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
atomic_t active_intr;
@ -246,16 +245,18 @@ static const struct {
{500000, BMC150_ACCEL_SLEEP_500_MS},
{1000000, BMC150_ACCEL_SLEEP_1_SEC} };
static const struct regmap_config bmc150_i2c_regmap_conf = {
const struct regmap_config bmc150_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x3f,
};
EXPORT_SYMBOL_GPL(bmc150_regmap_conf);
static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
enum bmc150_power_modes mode,
int dur_us)
{
struct device *dev = regmap_get_device(data->regmap);
int i;
int ret;
u8 lpw_bits;
@ -279,11 +280,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT;
lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT);
dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits);
dev_dbg(dev, "Set Mode bits %x\n", lpw_bits);
ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_pmu_lpw\n");
dev_err(dev, "Error writing reg_pmu_lpw\n");
return ret;
}
@ -316,23 +317,24 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6,
data->slope_thres);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_int_6\n");
dev_err(dev, "Error writing reg_int_6\n");
return ret;
}
ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5,
BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur);
if (ret < 0) {
dev_err(data->dev, "Error updating reg_int_5\n");
dev_err(dev, "Error updating reg_int_5\n");
return ret;
}
dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres,
dev_dbg(dev, "%s: %x %x\n", __func__, data->slope_thres,
data->slope_dur);
return ret;
@ -378,20 +380,21 @@ static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data)
static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
if (on) {
ret = pm_runtime_get_sync(data->dev);
ret = pm_runtime_get_sync(dev);
} else {
pm_runtime_mark_last_busy(data->dev);
ret = pm_runtime_put_autosuspend(data->dev);
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
}
if (ret < 0) {
dev_err(data->dev,
dev_err(dev,
"Failed: bmc150_accel_set_power_state for %d\n", on);
if (on)
pm_runtime_put_noidle(data->dev);
pm_runtime_put_noidle(dev);
return ret;
}
@ -445,6 +448,7 @@ static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
bool state)
{
struct device *dev = regmap_get_device(data->regmap);
struct bmc150_accel_interrupt *intr = &data->interrupts[i];
const struct bmc150_accel_interrupt_info *info = intr->info;
int ret;
@ -474,7 +478,7 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask,
(state ? info->map_bitmask : 0));
if (ret < 0) {
dev_err(data->dev, "Error updating reg_int_map\n");
dev_err(dev, "Error updating reg_int_map\n");
goto out_fix_power_state;
}
@ -482,7 +486,7 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask,
(state ? info->en_bitmask : 0));
if (ret < 0) {
dev_err(data->dev, "Error updating reg_int_en\n");
dev_err(dev, "Error updating reg_int_en\n");
goto out_fix_power_state;
}
@ -500,6 +504,7 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret, i;
for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
@ -508,8 +513,7 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
BMC150_ACCEL_REG_PMU_RANGE,
data->chip_info->scale_table[i].reg_range);
if (ret < 0) {
dev_err(data->dev,
"Error writing pmu_range\n");
dev_err(dev, "Error writing pmu_range\n");
return ret;
}
@ -523,6 +527,7 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
unsigned int value;
@ -530,7 +535,7 @@ static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_temp\n");
dev_err(dev, "Error reading reg_temp\n");
mutex_unlock(&data->mutex);
return ret;
}
@ -545,6 +550,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
struct iio_chan_spec const *chan,
int *val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
int axis = chan->scan_index;
__le16 raw_val;
@ -559,7 +565,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
&raw_val, sizeof(raw_val));
if (ret < 0) {
dev_err(data->dev, "Error reading axis %d\n", axis);
dev_err(dev, "Error reading axis %d\n", axis);
bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
@ -831,6 +837,7 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
char *buffer, int samples)
{
struct device *dev = regmap_get_device(data->regmap);
int sample_length = 3 * 2;
int ret;
int total_length = samples * sample_length;
@ -854,7 +861,8 @@ static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
}
if (ret)
dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n",
dev_err(dev,
"Error transferring data from fifo in single steps of %zu\n",
step);
return ret;
@ -864,6 +872,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
unsigned samples, bool irq)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int ret, i;
u8 count;
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
@ -873,7 +882,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_fifo_status\n");
dev_err(dev, "Error reading reg_fifo_status\n");
return ret;
}
@ -1105,27 +1114,23 @@ static const struct iio_info bmc150_accel_info_fifo = {
.driver_module = THIS_MODULE,
};
static const unsigned long bmc150_accel_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0};
static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmc150_accel_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
unsigned int raw_val;
int ret;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = regmap_bulk_read(data->regmap,
BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val,
2);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err_read;
}
data->buffer[i++] = raw_val;
}
ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_REG_XOUT_L,
data->buffer, AXIS_MAX * 2);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err_read;
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
pf->timestamp);
@ -1139,6 +1144,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
{
struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig);
struct bmc150_accel_data *data = t->data;
struct device *dev = regmap_get_device(data->regmap);
int ret;
/* new data interrupts don't need ack */
@ -1152,8 +1158,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
BMC150_ACCEL_INT_MODE_LATCH_RESET);
mutex_unlock(&data->mutex);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
dev_err(dev, "Error writing reg_int_rst_latch\n");
return ret;
}
@ -1204,13 +1209,14 @@ static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int dir;
int ret;
unsigned int val;
ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_int_status_2\n");
dev_err(dev, "Error reading reg_int_status_2\n");
return ret;
}
@ -1253,6 +1259,7 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct bmc150_accel_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
bool ack = false;
int ret;
@ -1276,7 +1283,7 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret)
dev_err(data->dev, "Error writing reg_int_rst_latch\n");
dev_err(dev, "Error writing reg_int_rst_latch\n");
ret = IRQ_HANDLED;
} else {
@ -1347,13 +1354,14 @@ static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data,
static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
struct bmc150_accel_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int i, ret;
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
struct bmc150_accel_trigger *t = &data->triggers[i];
t->indio_trig = devm_iio_trigger_alloc(data->dev,
bmc150_accel_triggers[i].name,
t->indio_trig = devm_iio_trigger_alloc(dev,
bmc150_accel_triggers[i].name,
indio_dev->name,
indio_dev->id);
if (!t->indio_trig) {
@ -1361,7 +1369,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
break;
}
t->indio_trig->dev.parent = data->dev;
t->indio_trig->dev.parent = dev;
t->indio_trig->ops = &bmc150_accel_trigger_ops;
t->intr = bmc150_accel_triggers[i].intr;
t->data = data;
@ -1385,12 +1393,13 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
int ret;
ret = regmap_write(data->regmap, reg, data->fifo_mode);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_fifo_config1\n");
dev_err(dev, "Error writing reg_fifo_config1\n");
return ret;
}
@ -1400,7 +1409,7 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0,
data->watermark);
if (ret < 0)
dev_err(data->dev, "Error writing reg_fifo_config0\n");
dev_err(dev, "Error writing reg_fifo_config0\n");
return ret;
}
@ -1484,17 +1493,17 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret, i;
unsigned int val;
ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
if (ret < 0) {
dev_err(data->dev,
"Error: Reading chip id\n");
dev_err(dev, "Error: Reading chip id\n");
return ret;
}
dev_dbg(data->dev, "Chip Id %x\n", val);
dev_dbg(dev, "Chip Id %x\n", val);
for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
if (bmc150_accel_chip_info_tbl[i].chip_id == val) {
data->chip_info = &bmc150_accel_chip_info_tbl[i];
@ -1503,7 +1512,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
}
if (!data->chip_info) {
dev_err(data->dev, "Invalid chip %x\n", val);
dev_err(dev, "Invalid chip %x\n", val);
return -ENODEV;
}
@ -1520,8 +1529,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE,
BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_pmu_range\n");
dev_err(dev, "Error writing reg_pmu_range\n");
return ret;
}
@ -1539,8 +1547,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
dev_err(dev, "Error writing reg_int_rst_latch\n");
return ret;
}
@ -1560,7 +1567,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->dev = dev;
data->irq = irq;
data->regmap = regmap;
@ -1575,6 +1581,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name ? name : data->chip_info->name;
indio_dev->available_scan_masks = bmc150_accel_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_accel_info;
@ -1583,13 +1590,13 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
bmc150_accel_trigger_handler,
&bmc150_accel_buffer_ops);
if (ret < 0) {
dev_err(data->dev, "Failed: iio triggered buffer setup\n");
dev_err(dev, "Failed: iio triggered buffer setup\n");
return ret;
}
if (data->irq > 0) {
ret = devm_request_threaded_irq(
data->dev, data->irq,
dev, data->irq,
bmc150_accel_irq_handler,
bmc150_accel_irq_thread_handler,
IRQF_TRIGGER_RISING,
@ -1607,7 +1614,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_int_rst_latch\n");
dev_err(dev, "Error writing reg_int_rst_latch\n");
goto err_buffer_cleanup;
}
@ -1656,9 +1663,9 @@ int bmc150_accel_core_remove(struct device *dev)
iio_device_unregister(indio_dev);
pm_runtime_disable(data->dev);
pm_runtime_set_suspended(data->dev);
pm_runtime_put_noidle(data->dev);
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
@ -1707,7 +1714,7 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
dev_dbg(data->dev, __func__);
dev_dbg(dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
if (ret < 0)
return -EAGAIN;
@ -1722,7 +1729,7 @@ static int bmc150_accel_runtime_resume(struct device *dev)
int ret;
int sleep_val;
dev_dbg(data->dev, __func__);
dev_dbg(dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)

View File

@ -28,11 +28,6 @@
#include "bmc150-accel.h"
static const struct regmap_config bmc150_i2c_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
};
static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -43,7 +38,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to initialize i2c regmap\n");
return PTR_ERR(regmap);

View File

@ -25,18 +25,12 @@
#include "bmc150-accel.h"
static const struct regmap_config bmc150_spi_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x3f,
};
static int bmc150_accel_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to initialize spi regmap\n");
return PTR_ERR(regmap);

View File

@ -16,5 +16,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported);
int bmc150_accel_core_remove(struct device *dev);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
#endif /* _BMC150_ACCEL_H_ */

View File

@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
@ -115,6 +114,7 @@ enum kxcjk1013_axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
AXIS_MAX,
};
enum kxcjk1013_mode {
@ -922,7 +922,7 @@ static const struct iio_event_spec kxcjk1013_event = {
.realbits = 12, \
.storagebits = 16, \
.shift = 4, \
.endianness = IIO_CPU, \
.endianness = IIO_LE, \
}, \
.event_spec = &kxcjk1013_event, \
.num_event_specs = 1 \
@ -953,25 +953,23 @@ static const struct iio_info kxcjk1013_info = {
.driver_module = THIS_MODULE,
};
static const unsigned long kxcjk1013_scan_masks[] = {0x7, 0};
static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct kxcjk1013_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
int ret;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = kxcjk1013_get_acc_reg(data, bit);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err;
}
data->buffer[i++] = ret;
}
ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
KXCJK1013_REG_XOUT_L,
AXIS_MAX * 2,
(u8 *)data->buffer);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
data->timestamp);
@ -1204,6 +1202,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
indio_dev->dev.parent = &client->dev;
indio_dev->channels = kxcjk1013_channels;
indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels);
indio_dev->available_scan_masks = kxcjk1013_scan_masks;
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &kxcjk1013_info;

View File

@ -55,11 +55,11 @@
struct mma7455_data {
struct regmap *regmap;
struct device *dev;
};
static int mma7455_drdy(struct mma7455_data *mma7455)
{
struct device *dev = regmap_get_device(mma7455->regmap);
unsigned int reg;
int tries = 3;
int ret;
@ -75,7 +75,7 @@ static int mma7455_drdy(struct mma7455_data *mma7455)
msleep(20);
}
dev_warn(mma7455->dev, "data not ready\n");
dev_warn(dev, "data not ready\n");
return -EIO;
}
@ -260,7 +260,6 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap,
dev_set_drvdata(dev, indio_dev);
mma7455 = iio_priv(indio_dev);
mma7455->regmap = regmap;
mma7455->dev = dev;
indio_dev->info = &mma7455_info;
indio_dev->name = name;

View File

@ -6,6 +6,7 @@
* MMA8453Q (10 bit)
* MMA8652FC (12 bit)
* MMA8653FC (10 bit)
* FXLS8471Q (14 bit)
*
* Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
@ -16,7 +17,7 @@
*
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
*
* TODO: orientation events, autosleep
* TODO: orientation events
*/
#include <linux/module.h>
@ -31,6 +32,7 @@
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@ -91,6 +93,9 @@
#define MMA8453_DEVICE_ID 0x3a
#define MMA8652_DEVICE_ID 0x4a
#define MMA8653_DEVICE_ID 0x5a
#define FXLS8471_DEVICE_ID 0x6a
#define MMA8452_AUTO_SUSPEND_DELAY_MS 2000
struct mma8452_data {
struct i2c_client *client;
@ -172,6 +177,31 @@ static int mma8452_drdy(struct mma8452_data *data)
return -EIO;
}
static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
{
#ifdef CONFIG_PM
int ret;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
} else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
}
if (ret < 0) {
dev_err(&client->dev,
"failed to change power state to %d\n", on);
if (on)
pm_runtime_put_noidle(&client->dev);
return ret;
}
#endif
return 0;
}
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
{
int ret = mma8452_drdy(data);
@ -179,8 +209,16 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
if (ret < 0)
return ret;
return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
ret = mma8452_set_runtime_pm_state(data->client, true);
if (ret)
return ret;
ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
ret = mma8452_set_runtime_pm_state(data->client, false);
return ret;
}
static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
@ -357,7 +395,8 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = i2c_smbus_read_byte_data(data->client,
MMA8452_OFF_X + chan->scan_index);
MMA8452_OFF_X +
chan->scan_index);
if (ret < 0)
return ret;
@ -392,24 +431,47 @@ static int mma8452_active(struct mma8452_data *data)
data->ctrl_reg1);
}
/* returns >0 if active, 0 if in standby and <0 on error */
static int mma8452_is_active(struct mma8452_data *data)
{
int reg;
reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1);
if (reg < 0)
return reg;
return reg & MMA8452_CTRL_ACTIVE;
}
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
{
int ret;
int is_active;
mutex_lock(&data->lock);
/* config can only be changed when in standby */
ret = mma8452_standby(data);
if (ret < 0)
is_active = mma8452_is_active(data);
if (is_active < 0) {
ret = is_active;
goto fail;
}
/* config can only be changed when in standby */
if (is_active > 0) {
ret = mma8452_standby(data);
if (ret < 0)
goto fail;
}
ret = i2c_smbus_write_byte_data(data->client, reg, val);
if (ret < 0)
goto fail;
ret = mma8452_active(data);
if (ret < 0)
goto fail;
if (is_active > 0) {
ret = mma8452_active(data);
if (ret < 0)
goto fail;
}
ret = 0;
fail:
@ -418,7 +480,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
return ret;
}
/* returns >0 if in freefall mode, 0 if not or <0 if an error occured */
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
{
int val;
@ -668,7 +730,8 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
return !!(ret & BIT(chan->scan_index +
chip->ev_cfg_chan_shift));
default:
return -EINVAL;
}
@ -682,7 +745,11 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
{
struct mma8452_data *data = iio_priv(indio_dev);
const struct mma_chip_info *chip = data->chip_info;
int val;
int val, ret;
ret = mma8452_set_runtime_pm_state(data->client, state);
if (ret)
return ret;
switch (dir) {
case IIO_EV_DIR_FALLING:
@ -990,6 +1057,7 @@ enum {
mma8453,
mma8652,
mma8653,
fxls8471,
};
static const struct mma_chip_info mma_chip_info_table[] = {
@ -1003,7 +1071,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
* bit.
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor for 12 bit here is given by:
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
*/
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
.ev_cfg = MMA8452_TRANSIENT_CFG,
@ -1081,6 +1149,22 @@ static const struct mma_chip_info mma_chip_info_table[] = {
.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
.ev_count = MMA8452_FF_MT_COUNT,
},
[fxls8471] = {
.chip_id = FXLS8471_DEVICE_ID,
.channels = mma8451_channels,
.num_channels = ARRAY_SIZE(mma8451_channels),
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
.ev_cfg = MMA8452_TRANSIENT_CFG,
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
.ev_cfg_chan_shift = 1,
.ev_src = MMA8452_TRANSIENT_SRC,
.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
.ev_ths = MMA8452_TRANSIENT_THS,
.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
.ev_count = MMA8452_TRANSIENT_COUNT,
},
};
static struct attribute *mma8452_attributes[] = {
@ -1114,7 +1198,11 @@ static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct mma8452_data *data = iio_priv(indio_dev);
int reg;
int reg, ret;
ret = mma8452_set_runtime_pm_state(data->client, state);
if (ret)
return ret;
reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
if (reg < 0)
@ -1206,6 +1294,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
{ .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
{ }
};
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
@ -1243,6 +1332,7 @@ static int mma8452_probe(struct i2c_client *client,
case MMA8453_DEVICE_ID:
case MMA8652_DEVICE_ID:
case MMA8653_DEVICE_ID:
case FXLS8471_DEVICE_ID:
if (ret == data->chip_info->chip_id)
break;
default:
@ -1340,6 +1430,15 @@ static int mma8452_probe(struct i2c_client *client,
goto buffer_cleanup;
}
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
goto buffer_cleanup;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
MMA8452_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
ret = iio_device_register(indio_dev);
if (ret < 0)
goto buffer_cleanup;
@ -1364,6 +1463,11 @@ static int mma8452_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
iio_triggered_buffer_cleanup(indio_dev);
mma8452_trigger_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
@ -1371,6 +1475,45 @@ static int mma8452_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int mma8452_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mma8452_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = mma8452_standby(data);
mutex_unlock(&data->lock);
if (ret < 0) {
dev_err(&data->client->dev, "powering off device failed\n");
return -EAGAIN;
}
return 0;
}
static int mma8452_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mma8452_data *data = iio_priv(indio_dev);
int ret, sleep_val;
ret = mma8452_active(data);
if (ret < 0)
return ret;
ret = mma8452_get_odr_index(data);
sleep_val = 1000 / mma8452_samp_freq[ret][0];
if (sleep_val < 20)
usleep_range(sleep_val * 1000, 20000);
else
msleep_interruptible(sleep_val);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int mma8452_suspend(struct device *dev)
{
@ -1383,18 +1526,21 @@ static int mma8452_resume(struct device *dev)
return mma8452_active(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
}
static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
#define MMA8452_PM_OPS (&mma8452_pm_ops)
#else
#define MMA8452_PM_OPS NULL
#endif
static const struct dev_pm_ops mma8452_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
mma8452_runtime_resume, NULL)
};
static const struct i2c_device_id mma8452_id[] = {
{ "mma8451", mma8451 },
{ "mma8452", mma8452 },
{ "mma8453", mma8453 },
{ "mma8652", mma8652 },
{ "mma8653", mma8653 },
{ "fxls8471", fxls8471 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8452_id);
@ -1403,7 +1549,7 @@ static struct i2c_driver mma8452_driver = {
.driver = {
.name = "mma8452",
.of_match_table = of_match_ptr(mma8452_dt_ids),
.pm = MMA8452_PM_OPS,
.pm = &mma8452_pm_ops,
},
.probe = mma8452_probe,
.remove = mma8452_remove,

View File

@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>

View File

@ -17,7 +17,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
@ -380,31 +379,6 @@ static const struct iio_trigger_ops mxc4005_trigger_ops = {
.owner = THIS_MODULE,
};
static int mxc4005_gpio_probe(struct i2c_client *client,
struct mxc4005_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "failed to get acpi gpio index\n");
return PTR_ERR(gpio);
}
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static int mxc4005_chip_init(struct mxc4005_data *data)
{
int ret;
@ -470,9 +444,6 @@ static int mxc4005_probe(struct i2c_client *client,
return ret;
}
if (client->irq < 0)
client->irq = mxc4005_gpio_probe(client, data);
if (client->irq > 0) {
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",

View File

@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/iio/common/st_sensors.h>
#define H3LIS331DL_DRIVER_NAME "h3lis331dl_accel"
#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel"
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
#define LIS3DH_ACCEL_DEV_NAME "lis3dh"

View File

@ -39,6 +39,9 @@
#define ST_ACCEL_FS_AVL_6G 6
#define ST_ACCEL_FS_AVL_8G 8
#define ST_ACCEL_FS_AVL_16G 16
#define ST_ACCEL_FS_AVL_100G 100
#define ST_ACCEL_FS_AVL_200G 200
#define ST_ACCEL_FS_AVL_400G 400
/* CUSTOM VALUES FOR SENSOR 1 */
#define ST_ACCEL_1_WAI_EXP 0x33
@ -96,6 +99,8 @@
#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10
#define ST_ACCEL_2_IHL_IRQ_ADDR 0x22
#define ST_ACCEL_2_IHL_IRQ_MASK 0x80
#define ST_ACCEL_2_OD_IRQ_ADDR 0x22
#define ST_ACCEL_2_OD_IRQ_MASK 0x40
#define ST_ACCEL_2_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 3 */
@ -177,10 +182,39 @@
#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20
#define ST_ACCEL_5_IHL_IRQ_ADDR 0x22
#define ST_ACCEL_5_IHL_IRQ_MASK 0x80
#define ST_ACCEL_5_OD_IRQ_ADDR 0x22
#define ST_ACCEL_5_OD_IRQ_MASK 0x40
#define ST_ACCEL_5_IG1_EN_ADDR 0x21
#define ST_ACCEL_5_IG1_EN_MASK 0x08
#define ST_ACCEL_5_MULTIREAD_BIT false
/* CUSTOM VALUES FOR SENSOR 6 */
#define ST_ACCEL_6_WAI_EXP 0x32
#define ST_ACCEL_6_ODR_ADDR 0x20
#define ST_ACCEL_6_ODR_MASK 0x18
#define ST_ACCEL_6_ODR_AVL_50HZ_VAL 0x00
#define ST_ACCEL_6_ODR_AVL_100HZ_VAL 0x01
#define ST_ACCEL_6_ODR_AVL_400HZ_VAL 0x02
#define ST_ACCEL_6_ODR_AVL_1000HZ_VAL 0x03
#define ST_ACCEL_6_PW_ADDR 0x20
#define ST_ACCEL_6_PW_MASK 0x20
#define ST_ACCEL_6_FS_ADDR 0x23
#define ST_ACCEL_6_FS_MASK 0x30
#define ST_ACCEL_6_FS_AVL_100_VAL 0x00
#define ST_ACCEL_6_FS_AVL_200_VAL 0x01
#define ST_ACCEL_6_FS_AVL_400_VAL 0x03
#define ST_ACCEL_6_FS_AVL_100_GAIN IIO_G_TO_M_S_2(49000)
#define ST_ACCEL_6_FS_AVL_200_GAIN IIO_G_TO_M_S_2(98000)
#define ST_ACCEL_6_FS_AVL_400_GAIN IIO_G_TO_M_S_2(195000)
#define ST_ACCEL_6_BDU_ADDR 0x23
#define ST_ACCEL_6_BDU_MASK 0x80
#define ST_ACCEL_6_DRDY_IRQ_ADDR 0x22
#define ST_ACCEL_6_DRDY_IRQ_INT1_MASK 0x02
#define ST_ACCEL_6_DRDY_IRQ_INT2_MASK 0x10
#define ST_ACCEL_6_IHL_IRQ_ADDR 0x22
#define ST_ACCEL_6_IHL_IRQ_MASK 0x80
#define ST_ACCEL_6_MULTIREAD_BIT true
static const struct iio_chan_spec st_accel_8bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
@ -302,6 +336,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
.addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR,
.mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
.bootime = 2,
@ -367,6 +402,9 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
.addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR,
.mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK,
.addr_od = ST_ACCEL_2_OD_IRQ_ADDR,
.mask_od = ST_ACCEL_2_OD_IRQ_MASK,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
.bootime = 2,
@ -444,6 +482,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
.addr_ihl = ST_ACCEL_3_IHL_IRQ_ADDR,
.mask_ihl = ST_ACCEL_3_IHL_IRQ_MASK,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.ig1 = {
.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
.en_mask = ST_ACCEL_3_IG1_EN_MASK,
@ -502,6 +541,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.drdy_irq = {
.addr = ST_ACCEL_4_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
.bootime = 2, /* guess */
@ -553,10 +593,75 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
.addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR,
.mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK,
.addr_od = ST_ACCEL_5_OD_IRQ_ADDR,
.mask_od = ST_ACCEL_5_OD_IRQ_MASK,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
.bootime = 2, /* guess */
},
{
.wai = ST_ACCEL_6_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = H3LIS331DL_DRIVER_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = ST_ACCEL_6_ODR_ADDR,
.mask = ST_ACCEL_6_ODR_MASK,
.odr_avl = {
{ 50, ST_ACCEL_6_ODR_AVL_50HZ_VAL },
{ 100, ST_ACCEL_6_ODR_AVL_100HZ_VAL, },
{ 400, ST_ACCEL_6_ODR_AVL_400HZ_VAL, },
{ 1000, ST_ACCEL_6_ODR_AVL_1000HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_6_PW_ADDR,
.mask = ST_ACCEL_6_PW_MASK,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_6_FS_ADDR,
.mask = ST_ACCEL_6_FS_MASK,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_100G,
.value = ST_ACCEL_6_FS_AVL_100_VAL,
.gain = ST_ACCEL_6_FS_AVL_100_GAIN,
},
[1] = {
.num = ST_ACCEL_FS_AVL_200G,
.value = ST_ACCEL_6_FS_AVL_200_VAL,
.gain = ST_ACCEL_6_FS_AVL_200_GAIN,
},
[2] = {
.num = ST_ACCEL_FS_AVL_400G,
.value = ST_ACCEL_6_FS_AVL_400_VAL,
.gain = ST_ACCEL_6_FS_AVL_400_GAIN,
},
},
},
.bdu = {
.addr = ST_ACCEL_6_BDU_ADDR,
.mask = ST_ACCEL_6_BDU_MASK,
},
.drdy_irq = {
.addr = ST_ACCEL_6_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_6_DRDY_IRQ_INT1_MASK,
.mask_int2 = ST_ACCEL_6_DRDY_IRQ_INT2_MASK,
.addr_ihl = ST_ACCEL_6_IHL_IRQ_ADDR,
.mask_ihl = ST_ACCEL_6_IHL_IRQ_MASK,
},
.multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT,
.bootime = 2,
},
};
static int st_accel_read_raw(struct iio_dev *indio_dev,

View File

@ -76,6 +76,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis2dh12-accel",
.data = LIS2DH12_ACCEL_DEV_NAME,
},
{
.compatible = "st,h3lis331dl-accel",
.data = H3LIS331DL_DRIVER_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);

View File

@ -11,7 +11,6 @@
*/
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>

View File

@ -11,7 +11,6 @@
*/
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>

View File

@ -242,6 +242,16 @@ config LP8788_ADC
To compile this driver as a module, choose M here: the module will be
called lp8788_adc.
config LPC18XX_ADC
tristate "NXP LPC18xx ADC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
depends on OF && HAS_IOMEM
help
Say yes here to build support for NXP LPC18XX ADC.
To compile this driver as a module, choose M here: the module will be
called lpc18xx_adc.
config MAX1027
tristate "Maxim max1027 ADC driver"
depends on SPI
@ -375,11 +385,11 @@ config ROCKCHIP_SARADC
module will be called rockchip_saradc.
config TI_ADC081C
tristate "Texas Instruments ADC081C021/027"
tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADC081C021
and ADC081C027 ADC chips.
If you say yes here you get support for Texas Instruments ADC081C,
ADC101C and ADC121C ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-adc081c.

View File

@ -25,6 +25,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o

View File

@ -477,7 +477,7 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1 , 0);
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
}

View File

@ -66,8 +66,10 @@
#define AT91_SAMA5D2_MR_PRESCAL(v) ((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
#define AT91_SAMA5D2_MR_PRESCAL_OFFSET 8
#define AT91_SAMA5D2_MR_PRESCAL_MAX 0xff
#define AT91_SAMA5D2_MR_PRESCAL_MASK GENMASK(15, 8)
/* Startup Time */
#define AT91_SAMA5D2_MR_STARTUP(v) ((v) << 16)
#define AT91_SAMA5D2_MR_STARTUP_MASK GENMASK(19, 16)
/* Analog Change */
#define AT91_SAMA5D2_MR_ANACH BIT(23)
/* Tracking Time */
@ -92,13 +94,13 @@
/* Last Converted Data Register */
#define AT91_SAMA5D2_LCDR 0x20
/* Interrupt Enable Register */
#define AT91_SAMA5D2_IER 0x24
#define AT91_SAMA5D2_IER 0x24
/* Interrupt Disable Register */
#define AT91_SAMA5D2_IDR 0x28
#define AT91_SAMA5D2_IDR 0x28
/* Interrupt Mask Register */
#define AT91_SAMA5D2_IMR 0x2c
#define AT91_SAMA5D2_IMR 0x2c
/* Interrupt Status Register */
#define AT91_SAMA5D2_ISR 0x30
#define AT91_SAMA5D2_ISR 0x30
/* Last Channel Trigger Mode Register */
#define AT91_SAMA5D2_LCTMR 0x34
/* Last Channel Compare Window Register */
@ -106,17 +108,20 @@
/* Overrun Status Register */
#define AT91_SAMA5D2_OVER 0x3c
/* Extended Mode Register */
#define AT91_SAMA5D2_EMR 0x40
#define AT91_SAMA5D2_EMR 0x40
/* Compare Window Register */
#define AT91_SAMA5D2_CWR 0x44
#define AT91_SAMA5D2_CWR 0x44
/* Channel Gain Register */
#define AT91_SAMA5D2_CGR 0x48
#define AT91_SAMA5D2_CGR 0x48
/* Channel Offset Register */
#define AT91_SAMA5D2_COR 0x4c
#define AT91_SAMA5D2_COR 0x4c
#define AT91_SAMA5D2_COR_DIFF_OFFSET 16
/* Channel Data Register 0 */
#define AT91_SAMA5D2_CDR0 0x50
/* Analog Control Register */
#define AT91_SAMA5D2_ACR 0x94
#define AT91_SAMA5D2_ACR 0x94
/* Touchscreen Mode Register */
#define AT91_SAMA5D2_TSMR 0xb0
/* Touchscreen X Position Register */
@ -130,7 +135,7 @@
/* Correction Select Register */
#define AT91_SAMA5D2_COSR 0xd0
/* Correction Value Register */
#define AT91_SAMA5D2_CVR 0xd4
#define AT91_SAMA5D2_CVR 0xd4
/* Channel Error Correction Register */
#define AT91_SAMA5D2_CECR 0xd8
/* Write Protection Mode Register */
@ -140,7 +145,7 @@
/* Version Register */
#define AT91_SAMA5D2_VERSION 0xfc
#define AT91_AT91_SAMA5D2_CHAN(num, addr) \
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
{ \
.type = IIO_VOLTAGE, \
.channel = num, \
@ -156,6 +161,24 @@
.indexed = 1, \
}
#define AT91_SAMA5D2_CHAN_DIFF(num, num2, addr) \
{ \
.type = IIO_VOLTAGE, \
.differential = 1, \
.channel = num, \
.channel2 = num2, \
.address = addr, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
}, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
.datasheet_name = "CH"#num"-CH"#num2, \
.indexed = 1, \
}
#define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
#define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
@ -185,18 +208,24 @@ struct at91_adc_state {
};
static const struct iio_chan_spec at91_adc_channels[] = {
AT91_AT91_SAMA5D2_CHAN(0, 0x50),
AT91_AT91_SAMA5D2_CHAN(1, 0x54),
AT91_AT91_SAMA5D2_CHAN(2, 0x58),
AT91_AT91_SAMA5D2_CHAN(3, 0x5c),
AT91_AT91_SAMA5D2_CHAN(4, 0x60),
AT91_AT91_SAMA5D2_CHAN(5, 0x64),
AT91_AT91_SAMA5D2_CHAN(6, 0x68),
AT91_AT91_SAMA5D2_CHAN(7, 0x6c),
AT91_AT91_SAMA5D2_CHAN(8, 0x70),
AT91_AT91_SAMA5D2_CHAN(9, 0x74),
AT91_AT91_SAMA5D2_CHAN(10, 0x78),
AT91_AT91_SAMA5D2_CHAN(11, 0x7c),
AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
AT91_SAMA5D2_CHAN_SINGLE(3, 0x5c),
AT91_SAMA5D2_CHAN_SINGLE(4, 0x60),
AT91_SAMA5D2_CHAN_SINGLE(5, 0x64),
AT91_SAMA5D2_CHAN_SINGLE(6, 0x68),
AT91_SAMA5D2_CHAN_SINGLE(7, 0x6c),
AT91_SAMA5D2_CHAN_SINGLE(8, 0x70),
AT91_SAMA5D2_CHAN_SINGLE(9, 0x74),
AT91_SAMA5D2_CHAN_SINGLE(10, 0x78),
AT91_SAMA5D2_CHAN_SINGLE(11, 0x7c),
AT91_SAMA5D2_CHAN_DIFF(0, 1, 0x50),
AT91_SAMA5D2_CHAN_DIFF(2, 3, 0x58),
AT91_SAMA5D2_CHAN_DIFF(4, 5, 0x60),
AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
};
static unsigned at91_adc_startup_time(unsigned startup_time_min,
@ -226,7 +255,7 @@ static unsigned at91_adc_startup_time(unsigned startup_time_min,
static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
{
struct iio_dev *indio_dev = iio_priv_to_dev(st);
unsigned f_per, prescal, startup;
unsigned f_per, prescal, startup, mr;
f_per = clk_get_rate(st->per_clk);
prescal = (f_per / (2 * freq)) - 1;
@ -234,10 +263,11 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
startup = at91_adc_startup_time(st->soc_info.startup_time,
freq / 1000);
at91_adc_writel(st, AT91_SAMA5D2_MR,
AT91_SAMA5D2_MR_TRANSFER(2)
| AT91_SAMA5D2_MR_STARTUP(startup)
| AT91_SAMA5D2_MR_PRESCAL(prescal));
mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
mr |= AT91_SAMA5D2_MR_STARTUP(startup);
mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
at91_adc_writel(st, AT91_SAMA5D2_MR, mr);
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
freq, startup, prescal);
@ -278,6 +308,7 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct at91_adc_state *st = iio_priv(indio_dev);
u32 cor = 0;
int ret;
switch (mask) {
@ -286,6 +317,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
st->chan = chan;
if (chan->differential)
cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
AT91_SAMA5D2_COR_DIFF_OFFSET;
at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
@ -298,6 +334,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
if (ret > 0) {
*val = st->conversion_value;
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, 11);
ret = IIO_VAL_INT;
st->conversion_done = false;
}
@ -310,6 +348,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
*val = st->vref_uv / 1000;
if (chan->differential)
*val *= 2;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
@ -444,6 +484,12 @@ static int at91_adc_probe(struct platform_device *pdev)
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
/*
* Transfer field must be set to 2 according to the datasheet and
* allows different analog settings for each channel.
*/
at91_adc_writel(st, AT91_SAMA5D2_MR,
AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);

View File

@ -797,8 +797,8 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
* Startup Time = <lookup_table_value> / ADC Clock
*/
const int startup_lookup[] = {
0 , 8 , 16 , 24 ,
64 , 80 , 96 , 112,
0, 8, 16, 24,
64, 80, 96, 112,
512, 576, 640, 704,
768, 832, 896, 960
};
@ -924,14 +924,14 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
ret = -EINVAL;
goto error_ret;
}
trig->name = name;
trig->name = name;
if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
trig->value = prop;
trig->value = prop;
trig->is_external = of_property_read_bool(trig_node, "trigger-external");
i++;
}

View File

@ -185,9 +185,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
/* processed (mV) = raw*1000/shunt_div */
/* processed (mV) = raw/shunt_div */
*val2 = chip->config->shunt_div;
*val = 1000;
*val = 1;
return IIO_VAL_FRACTIONAL;
case INA2XX_BUS_VOLTAGE:
@ -350,6 +350,23 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
return len;
}
/*
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet). We hardcode a Current_LSB
* of 1.0 x10-6. The only remaining parameter is RShunt.
* There is no need to expose the CALIBRATION register
* to the user for now. But we need to reset this register
* if the user updates RShunt after driver init, e.g upon
* reading an EEPROM/Probe-type value.
*/
static int ina2xx_set_calibration(struct ina2xx_chip_info *chip)
{
u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
chip->shunt_resistor);
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
}
static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
{
if (val <= 0 || val > chip->config->calibration_factor)
@ -385,6 +402,11 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
if (ret)
return ret;
/* Update the Calibration register */
ret = ina2xx_set_calibration(chip);
if (ret)
return ret;
return len;
}
@ -602,24 +624,11 @@ static const struct iio_info ina2xx_info = {
/* Initialize the configuration and calibration registers. */
static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
{
u16 regval;
int ret;
ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
int ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
if (ret)
return ret;
/*
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet). We hardcode a Current_LSB
* of 1.0 x10-6. The only remaining parameter is RShunt.
* There is no need to expose the CALIBRATION register
* to the user for now.
*/
regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
chip->shunt_resistor);
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
return ina2xx_set_calibration(chip);
}
static int ina2xx_probe(struct i2c_client *client,

View File

@ -0,0 +1,231 @@
/*
* IIO ADC driver for NXP LPC18xx ADC
*
* Copyright (C) 2016 Joachim Eastwood <manabian@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.
*
* UNSUPPORTED hardware features:
* - Hardware triggers
* - Burst mode
* - Interrupts
* - DMA
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/* LPC18XX ADC registers and bits */
#define LPC18XX_ADC_CR 0x000
#define LPC18XX_ADC_CR_CLKDIV_SHIFT 8
#define LPC18XX_ADC_CR_PDN BIT(21)
#define LPC18XX_ADC_CR_START_NOW (0x1 << 24)
#define LPC18XX_ADC_GDR 0x004
/* Data register bits */
#define LPC18XX_ADC_SAMPLE_SHIFT 6
#define LPC18XX_ADC_SAMPLE_MASK 0x3ff
#define LPC18XX_ADC_CONV_DONE BIT(31)
/* Clock should be 4.5 MHz or less */
#define LPC18XX_ADC_CLK_TARGET 4500000
struct lpc18xx_adc {
struct regulator *vref;
void __iomem *base;
struct device *dev;
struct mutex lock;
struct clk *clk;
u32 cr_reg;
};
#define LPC18XX_ADC_CHAN(_idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _idx, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec lpc18xx_adc_iio_channels[] = {
LPC18XX_ADC_CHAN(0),
LPC18XX_ADC_CHAN(1),
LPC18XX_ADC_CHAN(2),
LPC18XX_ADC_CHAN(3),
LPC18XX_ADC_CHAN(4),
LPC18XX_ADC_CHAN(5),
LPC18XX_ADC_CHAN(6),
LPC18XX_ADC_CHAN(7),
};
static int lpc18xx_adc_read_chan(struct lpc18xx_adc *adc, unsigned int ch)
{
int ret;
u32 reg;
reg = adc->cr_reg | BIT(ch) | LPC18XX_ADC_CR_START_NOW;
writel(reg, adc->base + LPC18XX_ADC_CR);
ret = readl_poll_timeout(adc->base + LPC18XX_ADC_GDR, reg,
reg & LPC18XX_ADC_CONV_DONE, 3, 9);
if (ret) {
dev_warn(adc->dev, "adc read timed out\n");
return ret;
}
return (reg >> LPC18XX_ADC_SAMPLE_SHIFT) & LPC18XX_ADC_SAMPLE_MASK;
}
static int lpc18xx_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct lpc18xx_adc *adc = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
*val = lpc18xx_adc_read_chan(adc, chan->channel);
mutex_unlock(&adc->lock);
if (*val < 0)
return *val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = regulator_get_voltage(adc->vref) / 1000;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info lpc18xx_adc_info = {
.read_raw = lpc18xx_adc_read_raw,
.driver_module = THIS_MODULE,
};
static int lpc18xx_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct lpc18xx_adc *adc;
struct resource *res;
unsigned int clkdiv;
unsigned long rate;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
adc = iio_priv(indio_dev);
adc->dev = &pdev->dev;
mutex_init(&adc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);
adc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(adc->clk)) {
dev_err(&pdev->dev, "error getting clock\n");
return PTR_ERR(adc->clk);
}
rate = clk_get_rate(adc->clk);
clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET);
adc->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(adc->vref)) {
dev_err(&pdev->dev, "error getting regulator\n");
return PTR_ERR(adc->vref);
}
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &lpc18xx_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = lpc18xx_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(lpc18xx_adc_iio_channels);
ret = regulator_enable(adc->vref);
if (ret) {
dev_err(&pdev->dev, "unable to enable regulator\n");
return ret;
}
ret = clk_prepare_enable(adc->clk);
if (ret) {
dev_err(&pdev->dev, "unable to enable clock\n");
goto dis_reg;
}
adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) |
LPC18XX_ADC_CR_PDN;
writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "unable to register device\n");
goto dis_clk;
}
return 0;
dis_clk:
writel(0, adc->base + LPC18XX_ADC_CR);
clk_disable_unprepare(adc->clk);
dis_reg:
regulator_disable(adc->vref);
return ret;
}
static int lpc18xx_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lpc18xx_adc *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
writel(0, adc->base + LPC18XX_ADC_CR);
clk_disable_unprepare(adc->clk);
regulator_disable(adc->vref);
return 0;
}
static const struct of_device_id lpc18xx_adc_match[] = {
{ .compatible = "nxp,lpc1850-adc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpc18xx_adc_match);
static struct platform_driver lpc18xx_adc_driver = {
.probe = lpc18xx_adc_probe,
.remove = lpc18xx_adc_remove,
.driver = {
.name = "lpc18xx-adc",
.of_match_table = lpc18xx_adc_match,
},
};
module_platform_driver(lpc18xx_adc_driver);
MODULE_DESCRIPTION("LPC18xx ADC driver");
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_LICENSE("GPL v2");

View File

@ -61,9 +61,9 @@
static const int mcp3422_scales[4][4] = {
{ 1000000, 500000, 250000, 125000 },
{ 250000 , 125000, 62500 , 31250 },
{ 62500 , 31250 , 15625 , 7812 },
{ 15625 , 7812 , 3906 , 1953 } };
{ 250000, 125000, 62500, 31250 },
{ 62500, 31250, 15625, 7812 },
{ 15625, 7812, 3906, 1953 } };
/* Constant msleep times for data acquisitions */
static const int mcp3422_read_times[4] = {

View File

@ -686,6 +686,17 @@ static void mxs_lradc_prepare_pressure(struct mxs_lradc *lradc)
static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc)
{
/* Configure the touchscreen type */
if (lradc->soc == IMX28_LRADC) {
mxs_lradc_reg_clear(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
LRADC_CTRL0);
if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
mxs_lradc_reg_set(lradc,
LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
LRADC_CTRL0);
}
mxs_lradc_setup_touch_detection(lradc);
lradc->cur_plate = LRADC_TOUCH;
@ -1127,6 +1138,7 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
__set_bit(EV_ABS, input->evbit);
__set_bit(EV_KEY, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(INPUT_PROP_DIRECT, input->propbit);
input_set_abs_params(input, ABS_X, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
input_set_abs_params(input, ABS_Y, 0, LRADC_SINGLE_SAMPLE_MASK, 0, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, LRADC_SINGLE_SAMPLE_MASK,
@ -1475,18 +1487,13 @@ static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
};
static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
{
/* The ADC always uses DELAY CHANNEL 0. */
const u32 adc_cfg =
(1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + 0)) |
(LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
int ret = stmp_reset_block(lradc->base);
if (ret)
return ret;
/* Configure DELAY CHANNEL 0 for generic ADC sampling. */
mxs_lradc_reg_wrt(lradc, adc_cfg, LRADC_DELAY(0));
@ -1495,20 +1502,8 @@ static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2));
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3));
/* Configure the touchscreen type */
if (lradc->soc == IMX28_LRADC) {
mxs_lradc_reg_clear(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
LRADC_CTRL0);
if (lradc->use_touchscreen == MXS_LRADC_TOUCHSCREEN_5WIRE)
mxs_lradc_reg_set(lradc, LRADC_CTRL0_MX28_TOUCH_SCREEN_TYPE,
LRADC_CTRL0);
}
/* Start internal temperature sensing. */
mxs_lradc_reg_wrt(lradc, 0, LRADC_CTRL2);
return 0;
}
static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
@ -1708,11 +1703,13 @@ static int mxs_lradc_probe(struct platform_device *pdev)
}
}
/* Configure the hardware. */
ret = mxs_lradc_hw_init(lradc);
ret = stmp_reset_block(lradc->base);
if (ret)
goto err_dev;
/* Configure the hardware. */
mxs_lradc_hw_init(lradc);
/* Register the touchscreen input device. */
if (touch_ret == 0) {
ret = mxs_lradc_ts_register(lradc);

View File

@ -159,6 +159,22 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = {
.clk_rate = 50000,
};
static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
ADC_CHANNEL(3, "adc3"),
ADC_CHANNEL(4, "adc4"),
ADC_CHANNEL(5, "adc5"),
};
static const struct rockchip_saradc_data rk3399_saradc_data = {
.num_bits = 10,
.channels = rockchip_rk3399_saradc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
.clk_rate = 1000000,
};
static const struct of_device_id rockchip_saradc_match[] = {
{
.compatible = "rockchip,saradc",
@ -166,6 +182,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
}, {
.compatible = "rockchip,rk3066-tsadc",
.data = &rk3066_tsadc_data,
}, {
.compatible = "rockchip,rk3399-saradc",
.data = &rk3399_saradc_data,
},
{},
};

View File

@ -1,9 +1,21 @@
/*
* TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver
*
* Copyright (C) 2012 Avionic Design GmbH
* Copyright (C) 2016 Intel
*
* 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.
*
* Datasheets:
* http://www.ti.com/lit/ds/symlink/adc081c021.pdf
* http://www.ti.com/lit/ds/symlink/adc101c021.pdf
* http://www.ti.com/lit/ds/symlink/adc121c021.pdf
*
* The devices have a very similar interface and differ mostly in the number of
* bits handled. For the 8-bit and 10-bit models the least-significant 4 or 2
* bits of value registers are reserved.
*/
#include <linux/err.h>
@ -12,11 +24,17 @@
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regulator/consumer.h>
struct adc081c {
struct i2c_client *i2c;
struct regulator *ref;
/* 8, 10 or 12 */
int bits;
};
#define REG_CONV_RES 0x00
@ -34,7 +52,7 @@ static int adc081c_read_raw(struct iio_dev *iio,
if (err < 0)
return err;
*value = (err >> 4) & 0xff;
*value = (err & 0xFFF) >> (12 - adc->bits);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@ -43,7 +61,7 @@ static int adc081c_read_raw(struct iio_dev *iio,
return err;
*value = err / 1000;
*shift = 8;
*shift = adc->bits;
return IIO_VAL_FRACTIONAL_LOG2;
@ -54,10 +72,53 @@ static int adc081c_read_raw(struct iio_dev *iio,
return -EINVAL;
}
static const struct iio_chan_spec adc081c_channel = {
.type = IIO_VOLTAGE,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
#define ADCxx1C_CHAN(_bits) { \
.type = IIO_VOLTAGE, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 12 - (_bits), \
.endianness = IIO_CPU, \
}, \
}
#define DEFINE_ADCxx1C_CHANNELS(_name, _bits) \
static const struct iio_chan_spec _name ## _channels[] = { \
ADCxx1C_CHAN((_bits)), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}; \
#define ADC081C_NUM_CHANNELS 2
struct adcxx1c_model {
const struct iio_chan_spec* channels;
int bits;
};
#define ADCxx1C_MODEL(_name, _bits) \
{ \
.channels = _name ## _channels, \
.bits = (_bits), \
}
DEFINE_ADCxx1C_CHANNELS(adc081c, 8);
DEFINE_ADCxx1C_CHANNELS(adc101c, 10);
DEFINE_ADCxx1C_CHANNELS(adc121c, 12);
/* Model ids are indexes in _models array */
enum adcxx1c_model_id {
ADC081C = 0,
ADC101C = 1,
ADC121C = 2,
};
static struct adcxx1c_model adcxx1c_models[] = {
ADCxx1C_MODEL(adc081c, 8),
ADCxx1C_MODEL(adc101c, 10),
ADCxx1C_MODEL(adc121c, 12),
};
static const struct iio_info adc081c_info = {
@ -65,11 +126,30 @@ static const struct iio_info adc081c_info = {
.driver_module = THIS_MODULE,
};
static irqreturn_t adc081c_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adc081c *data = iio_priv(indio_dev);
u16 buf[8]; /* 2 bytes data + 6 bytes padding + 8 bytes timestamp */
int ret;
ret = i2c_smbus_read_word_swapped(data->i2c, REG_CONV_RES);
if (ret < 0)
goto out;
buf[0] = ret;
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int adc081c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *iio;
struct adc081c *adc;
struct adcxx1c_model *model = &adcxx1c_models[id->driver_data];
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
@ -81,6 +161,7 @@ static int adc081c_probe(struct i2c_client *client,
adc = iio_priv(iio);
adc->i2c = client;
adc->bits = model->bits;
adc->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(adc->ref))
@ -95,18 +176,26 @@ static int adc081c_probe(struct i2c_client *client,
iio->modes = INDIO_DIRECT_MODE;
iio->info = &adc081c_info;
iio->channels = &adc081c_channel;
iio->num_channels = 1;
iio->channels = model->channels;
iio->num_channels = ADC081C_NUM_CHANNELS;
err = iio_triggered_buffer_setup(iio, NULL, adc081c_trigger_handler, NULL);
if (err < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
goto err_regulator_disable;
}
err = iio_device_register(iio);
if (err < 0)
goto regulator_disable;
goto err_buffer_cleanup;
i2c_set_clientdata(client, iio);
return 0;
regulator_disable:
err_buffer_cleanup:
iio_triggered_buffer_cleanup(iio);
err_regulator_disable:
regulator_disable(adc->ref);
return err;
@ -118,13 +207,16 @@ static int adc081c_remove(struct i2c_client *client)
struct adc081c *adc = iio_priv(iio);
iio_device_unregister(iio);
iio_triggered_buffer_cleanup(iio);
regulator_disable(adc->ref);
return 0;
}
static const struct i2c_device_id adc081c_id[] = {
{ "adc081c", 0 },
{ "adc081c", ADC081C },
{ "adc101c", ADC101C },
{ "adc121c", ADC121C },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc081c_id);
@ -132,6 +224,8 @@ MODULE_DEVICE_TABLE(i2c, adc081c_id);
#ifdef CONFIG_OF
static const struct of_device_id adc081c_of_match[] = {
{ .compatible = "ti,adc081c" },
{ .compatible = "ti,adc101c" },
{ .compatible = "ti,adc121c" },
{ }
};
MODULE_DEVICE_TABLE(of, adc081c_of_match);
@ -149,5 +243,5 @@ static struct i2c_driver adc081c_driver = {
module_i2c_driver(adc081c_driver);
MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver");
MODULE_LICENSE("GPL v2");

View File

@ -714,19 +714,19 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
int i;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0;
i < ARRAY_SIZE(info->sample_freq_avail);
i++)
if (val == info->sample_freq_avail[i]) {
info->adc_feature.sample_rate = i;
vf610_adc_sample_set(info);
return 0;
}
break;
case IIO_CHAN_INFO_SAMP_FREQ:
for (i = 0;
i < ARRAY_SIZE(info->sample_freq_avail);
i++)
if (val == info->sample_freq_avail[i]) {
info->adc_feature.sample_rate = i;
vf610_adc_sample_set(info);
return 0;
}
break;
default:
break;
default:
break;
}
return -EINVAL;

View File

@ -115,7 +115,7 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
return ret;
}
return 0;
return 0;
#else
atomic_set(&st->user_requested_state, state);
return _hid_sensor_power_state(st, state);

View File

@ -106,7 +106,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
unsigned int delay, u32 *adc)
{
int ret;
__be32 buf = 0;
__be32 buf = 0;
struct i2c_client *client = (struct i2c_client *)cli;
/* Trigger conversion */

View File

@ -24,81 +24,30 @@
int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
{
u8 *addr;
int i, n = 0, len;
int i, len;
int total = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int num_data_channels = sdata->num_data_channels;
unsigned int byte_for_channel =
indio_dev->channels[0].scan_type.storagebits >> 3;
addr = kmalloc(num_data_channels, GFP_KERNEL);
if (!addr) {
len = -ENOMEM;
goto st_sensors_get_buffer_element_error;
}
for (i = 0; i < num_data_channels; i++) {
unsigned int bytes_to_read;
if (test_bit(i, indio_dev->active_scan_mask)) {
addr[n] = indio_dev->channels[i].address;
n++;
bytes_to_read = indio_dev->channels[i].scan_type.storagebits >> 3;
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, indio_dev->channels[i].address,
bytes_to_read,
buf + total, sdata->multiread_bit);
if (len < bytes_to_read)
return -EIO;
/* Advance the buffer pointer */
total += len;
}
}
switch (n) {
case 1:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], byte_for_channel, buf, sdata->multiread_bit);
break;
case 2:
if ((addr[1] - addr[0]) == byte_for_channel) {
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0], byte_for_channel * n,
buf, sdata->multiread_bit);
} else {
u8 *rx_array;
rx_array = kmalloc(byte_for_channel * num_data_channels,
GFP_KERNEL);
if (!rx_array) {
len = -ENOMEM;
goto st_sensors_free_memory;
}
len = sdata->tf->read_multiple_byte(&sdata->tb,
sdata->dev, addr[0],
byte_for_channel * num_data_channels,
rx_array, sdata->multiread_bit);
if (len < 0) {
kfree(rx_array);
goto st_sensors_free_memory;
}
for (i = 0; i < n * byte_for_channel; i++) {
if (i < n)
buf[i] = rx_array[i];
else
buf[i] = rx_array[n + i];
}
kfree(rx_array);
len = byte_for_channel * n;
}
break;
case 3:
len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
addr[0], byte_for_channel * num_data_channels,
buf, sdata->multiread_bit);
break;
default:
len = -EINVAL;
goto st_sensors_free_memory;
}
if (len != byte_for_channel * n) {
len = -EIO;
goto st_sensors_free_memory;
}
st_sensors_free_memory:
kfree(addr);
st_sensors_get_buffer_element_error:
return len;
return total;
}
EXPORT_SYMBOL(st_sensors_get_buffer_element);
@ -109,6 +58,24 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct st_sensor_data *sdata = iio_priv(indio_dev);
/* If we have a status register, check if this IRQ came from us */
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) {
u8 status;
len = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
&status);
if (len < 0)
dev_err(sdata->dev, "could not read channel status\n");
/*
* If this was not caused by any channels on this sensor,
* return IRQ_NONE
*/
if (!(status & (u8)indio_dev->active_scan_mask[0]))
return IRQ_NONE;
}
len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
if (len < 0)
goto st_sensors_get_buffer_element_error;

View File

@ -301,6 +301,14 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
return -EINVAL;
}
if (pdata->open_drain) {
if (!sdata->sensor_settings->drdy_irq.addr_od)
dev_err(&indio_dev->dev,
"open drain requested but unsupported.\n");
else
sdata->int_pin_open_drain = true;
}
return 0;
}
@ -321,6 +329,8 @@ static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
else
pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
return pdata;
}
#else
@ -374,6 +384,16 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
return err;
}
if (sdata->int_pin_open_drain) {
dev_info(&indio_dev->dev,
"set interrupt line to open drain mode\n");
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr_od,
sdata->sensor_settings->drdy_irq.mask_od, 1);
if (err < 0)
return err;
}
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
return err;

View File

@ -64,6 +64,19 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
"rising edge\n", irq_trig);
irq_trig = IRQF_TRIGGER_RISING;
}
/*
* If the interrupt pin is Open Drain, by definition this
* means that the interrupt line may be shared with other
* peripherals. But to do this we also need to have a status
* register and mask to figure out if this sensor was firing
* the IRQ or not, so we can tell the interrupt handle that
* it was "our" interrupt.
*/
if (sdata->int_pin_open_drain &&
sdata->sensor_settings->drdy_irq.addr_stat_drdy)
irq_trig |= IRQF_SHARED;
err = request_threaded_irq(irq,
iio_trigger_generic_data_rdy_poll,
NULL,

View File

@ -74,6 +74,33 @@ config AD5449
To compile this driver as a module, choose M here: the
module will be called ad5449.
config AD5592R_BASE
tristate
config AD5592R
tristate "Analog Devices AD5592R ADC/DAC driver"
depends on SPI_MASTER
select GPIOLIB
select AD5592R_BASE
help
Say yes here to build support for Analog Devices AD5592R
Digital to Analog / Analog to Digital Converter.
To compile this driver as a module, choose M here: the
module will be called ad5592r.
config AD5593R
tristate "Analog Devices AD5593R ADC/DAC driver"
depends on I2C
select GPIOLIB
select AD5592R_BASE
help
Say yes here to build support for Analog Devices AD5593R
Digital to Analog / Analog to Digital Converter.
To compile this driver as a module, choose M here: the
module will be called ad5593r.
config AD5504
tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
depends on SPI
@ -154,6 +181,16 @@ config AD7303
To compile this driver as module choose M here: the module will be called
ad7303.
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
depends on OF && HAS_IOMEM
help
Say yes here to build support for NXP LPC18XX DAC.
To compile this driver as a module, choose M here: the module will be
called lpc18xx_dac.
config M62332
tristate "Mitsubishi M62332 DAC driver"
depends on I2C

View File

@ -11,12 +11,16 @@ obj-$(CONFIG_AD5064) += ad5064.o
obj-$(CONFIG_AD5504) += ad5504.o
obj-$(CONFIG_AD5446) += ad5446.o
obj-$(CONFIG_AD5449) += ad5449.o
obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
obj-$(CONFIG_AD5592R) += ad5592r.o
obj-$(CONFIG_AD5593R) += ad5593r.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5761) += ad5761.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o

View File

@ -0,0 +1,691 @@
/*
* AD5592R Digital <-> Analog converters driver
*
* Copyright 2014-2016 Analog Devices Inc.
* Author: Paul Cercueil <paul.cercueil@analog.com>
*
* Licensed under the GPL-2.
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/property.h>
#include <dt-bindings/iio/adi,ad5592r.h>
#include "ad5592r-base.h"
static int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret = 0;
u8 val;
mutex_lock(&st->gpio_lock);
if (st->gpio_out & BIT(offset))
val = st->gpio_val;
else
ret = st->ops->gpio_read(st, &val);
mutex_unlock(&st->gpio_lock);
if (ret < 0)
return ret;
return !!(val & BIT(offset));
}
static void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
mutex_lock(&st->gpio_lock);
if (value)
st->gpio_val |= BIT(offset);
else
st->gpio_val &= ~BIT(offset);
st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
mutex_unlock(&st->gpio_lock);
}
static int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret;
mutex_lock(&st->gpio_lock);
st->gpio_out &= ~BIT(offset);
st->gpio_in |= BIT(offset);
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret < 0)
goto err_unlock;
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
err_unlock:
mutex_unlock(&st->gpio_lock);
return ret;
}
static int ad5592r_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
int ret;
mutex_lock(&st->gpio_lock);
if (value)
st->gpio_val |= BIT(offset);
else
st->gpio_val &= ~BIT(offset);
st->gpio_in &= ~BIT(offset);
st->gpio_out |= BIT(offset);
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
if (ret < 0)
goto err_unlock;
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret < 0)
goto err_unlock;
ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
err_unlock:
mutex_unlock(&st->gpio_lock);
return ret;
}
static int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct ad5592r_state *st = gpiochip_get_data(chip);
if (!(st->gpio_map & BIT(offset))) {
dev_err(st->dev, "GPIO %d is reserved by alternate function\n",
offset);
return -ENODEV;
}
return 0;
}
static int ad5592r_gpio_init(struct ad5592r_state *st)
{
if (!st->gpio_map)
return 0;
st->gpiochip.label = dev_name(st->dev);
st->gpiochip.base = -1;
st->gpiochip.ngpio = 8;
st->gpiochip.parent = st->dev;
st->gpiochip.can_sleep = true;
st->gpiochip.direction_input = ad5592r_gpio_direction_input;
st->gpiochip.direction_output = ad5592r_gpio_direction_output;
st->gpiochip.get = ad5592r_gpio_get;
st->gpiochip.set = ad5592r_gpio_set;
st->gpiochip.request = ad5592r_gpio_request;
st->gpiochip.owner = THIS_MODULE;
mutex_init(&st->gpio_lock);
return gpiochip_add_data(&st->gpiochip, st);
}
static void ad5592r_gpio_cleanup(struct ad5592r_state *st)
{
if (st->gpio_map)
gpiochip_remove(&st->gpiochip);
}
static int ad5592r_reset(struct ad5592r_state *st)
{
struct gpio_desc *gpio;
struct iio_dev *iio_dev = iio_priv_to_dev(st);
gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
udelay(1);
gpiod_set_value(gpio, 1);
} else {
mutex_lock(&iio_dev->mlock);
/* Writing this magic value resets the device */
st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac);
mutex_unlock(&iio_dev->mlock);
}
udelay(250);
return 0;
}
static int ad5592r_get_vref(struct ad5592r_state *st)
{
int ret;
if (st->reg) {
ret = regulator_get_voltage(st->reg);
if (ret < 0)
return ret;
return ret / 1000;
} else {
return 2500;
}
}
static int ad5592r_set_channel_modes(struct ad5592r_state *st)
{
const struct ad5592r_rw_ops *ops = st->ops;
int ret;
unsigned i;
struct iio_dev *iio_dev = iio_priv_to_dev(st);
u8 pulldown = 0, tristate = 0, dac = 0, adc = 0;
u16 read_back;
for (i = 0; i < st->num_channels; i++) {
switch (st->channel_modes[i]) {
case CH_MODE_DAC:
dac |= BIT(i);
break;
case CH_MODE_ADC:
adc |= BIT(i);
break;
case CH_MODE_DAC_AND_ADC:
dac |= BIT(i);
adc |= BIT(i);
break;
case CH_MODE_GPIO:
st->gpio_map |= BIT(i);
st->gpio_in |= BIT(i); /* Default to input */
break;
case CH_MODE_UNUSED:
/* fall-through */
default:
switch (st->channel_offstate[i]) {
case CH_OFFSTATE_OUT_TRISTATE:
tristate |= BIT(i);
break;
case CH_OFFSTATE_OUT_LOW:
st->gpio_out |= BIT(i);
break;
case CH_OFFSTATE_OUT_HIGH:
st->gpio_out |= BIT(i);
st->gpio_val |= BIT(i);
break;
case CH_OFFSTATE_PULLDOWN:
/* fall-through */
default:
pulldown |= BIT(i);
break;
}
}
}
mutex_lock(&iio_dev->mlock);
/* Pull down unused pins to GND */
ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown);
if (ret)
goto err_unlock;
ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate);
if (ret)
goto err_unlock;
/* Configure pins that we use */
ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac);
if (ret)
goto err_unlock;
ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc);
if (ret)
goto err_unlock;
ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val);
if (ret)
goto err_unlock;
ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out);
if (ret)
goto err_unlock;
ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in);
if (ret)
goto err_unlock;
/* Verify that we can read back at least one register */
ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back);
if (!ret && (read_back & 0xff) != adc)
ret = -EIO;
err_unlock:
mutex_unlock(&iio_dev->mlock);
return ret;
}
static int ad5592r_reset_channel_modes(struct ad5592r_state *st)
{
int i;
for (i = 0; i < ARRAY_SIZE(st->channel_modes); i++)
st->channel_modes[i] = CH_MODE_UNUSED;
return ad5592r_set_channel_modes(st);
}
static int ad5592r_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct ad5592r_state *st = iio_priv(iio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
if (!chan->output)
return -EINVAL;
mutex_lock(&iio_dev->mlock);
ret = st->ops->write_dac(st, chan->channel, val);
if (!ret)
st->cached_dac[chan->channel] = val;
mutex_unlock(&iio_dev->mlock);
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_VOLTAGE) {
bool gain;
if (val == st->scale_avail[0][0] &&
val2 == st->scale_avail[0][1])
gain = false;
else if (val == st->scale_avail[1][0] &&
val2 == st->scale_avail[1][1])
gain = true;
else
return -EINVAL;
mutex_lock(&iio_dev->mlock);
ret = st->ops->reg_read(st, AD5592R_REG_CTRL,
&st->cached_gp_ctrl);
if (ret < 0) {
mutex_unlock(&iio_dev->mlock);
return ret;
}
if (chan->output) {
if (gain)
st->cached_gp_ctrl |=
AD5592R_REG_CTRL_DAC_RANGE;
else
st->cached_gp_ctrl &=
~AD5592R_REG_CTRL_DAC_RANGE;
} else {
if (gain)
st->cached_gp_ctrl |=
AD5592R_REG_CTRL_ADC_RANGE;
else
st->cached_gp_ctrl &=
~AD5592R_REG_CTRL_ADC_RANGE;
}
ret = st->ops->reg_write(st, AD5592R_REG_CTRL,
st->cached_gp_ctrl);
mutex_unlock(&iio_dev->mlock);
return ret;
}
break;
default:
return -EINVAL;
}
return 0;
}
static int ad5592r_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
struct ad5592r_state *st = iio_priv(iio_dev);
u16 read_val;
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&iio_dev->mlock);
if (!chan->output) {
ret = st->ops->read_adc(st, chan->channel, &read_val);
if (ret)
goto unlock;
if ((read_val >> 12 & 0x7) != (chan->channel & 0x7)) {
dev_err(st->dev, "Error while reading channel %u\n",
chan->channel);
ret = -EIO;
goto unlock;
}
read_val &= GENMASK(11, 0);
} else {
read_val = st->cached_dac[chan->channel];
}
dev_dbg(st->dev, "Channel %u read: 0x%04hX\n",
chan->channel, read_val);
*val = (int) read_val;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = ad5592r_get_vref(st);
if (chan->type == IIO_TEMP) {
s64 tmp = *val * (3767897513LL / 25LL);
*val = div_s64_rem(tmp, 1000000000LL, val2);
ret = IIO_VAL_INT_PLUS_MICRO;
} else {
int mult;
mutex_lock(&iio_dev->mlock);
if (chan->output)
mult = !!(st->cached_gp_ctrl &
AD5592R_REG_CTRL_DAC_RANGE);
else
mult = !!(st->cached_gp_ctrl &
AD5592R_REG_CTRL_ADC_RANGE);
*val *= ++mult;
*val2 = chan->scan_type.realbits;
ret = IIO_VAL_FRACTIONAL_LOG2;
}
break;
case IIO_CHAN_INFO_OFFSET:
ret = ad5592r_get_vref(st);
mutex_lock(&iio_dev->mlock);
if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE)
*val = (-34365 * 25) / ret;
else
*val = (-75365 * 25) / ret;
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
}
unlock:
mutex_unlock(&iio_dev->mlock);
return ret;
}
static int ad5592r_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_NANO;
default:
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static const struct iio_info ad5592r_info = {
.read_raw = ad5592r_read_raw,
.write_raw = ad5592r_write_raw,
.write_raw_get_fmt = ad5592r_write_raw_get_fmt,
.driver_module = THIS_MODULE,
};
static ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct ad5592r_state *st = iio_priv(iio_dev);
return sprintf(buf, "%d.%09u %d.%09u\n",
st->scale_avail[0][0], st->scale_avail[0][1],
st->scale_avail[1][0], st->scale_avail[1][1]);
}
static struct iio_chan_spec_ext_info ad5592r_ext_info[] = {
{
.name = "scale_available",
.read = ad5592r_show_scale_available,
.shared = true,
},
{},
};
static void ad5592r_setup_channel(struct iio_dev *iio_dev,
struct iio_chan_spec *chan, bool output, unsigned id)
{
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->output = output;
chan->channel = id;
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
chan->scan_type.sign = 'u';
chan->scan_type.realbits = 12;
chan->scan_type.storagebits = 16;
chan->ext_info = ad5592r_ext_info;
}
static int ad5592r_alloc_channels(struct ad5592r_state *st)
{
unsigned i, curr_channel = 0,
num_channels = st->num_channels;
struct iio_dev *iio_dev = iio_priv_to_dev(st);
struct iio_chan_spec *channels;
struct fwnode_handle *child;
u32 reg, tmp;
int ret;
device_for_each_child_node(st->dev, child) {
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg > ARRAY_SIZE(st->channel_modes))
continue;
ret = fwnode_property_read_u32(child, "adi,mode", &tmp);
if (!ret)
st->channel_modes[reg] = tmp;
fwnode_property_read_u32(child, "adi,off-state", &tmp);
if (!ret)
st->channel_offstate[reg] = tmp;
}
channels = devm_kzalloc(st->dev,
(1 + 2 * num_channels) * sizeof(*channels), GFP_KERNEL);
if (!channels)
return -ENOMEM;
for (i = 0; i < num_channels; i++) {
switch (st->channel_modes[i]) {
case CH_MODE_DAC:
ad5592r_setup_channel(iio_dev, &channels[curr_channel],
true, i);
curr_channel++;
break;
case CH_MODE_ADC:
ad5592r_setup_channel(iio_dev, &channels[curr_channel],
false, i);
curr_channel++;
break;
case CH_MODE_DAC_AND_ADC:
ad5592r_setup_channel(iio_dev, &channels[curr_channel],
true, i);
curr_channel++;
ad5592r_setup_channel(iio_dev, &channels[curr_channel],
false, i);
curr_channel++;
break;
default:
continue;
}
}
channels[curr_channel].type = IIO_TEMP;
channels[curr_channel].channel = 8;
channels[curr_channel].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET);
curr_channel++;
iio_dev->num_channels = curr_channel;
iio_dev->channels = channels;
return 0;
}
static void ad5592r_init_scales(struct ad5592r_state *st, int vref_mV)
{
s64 tmp = (s64)vref_mV * 1000000000LL >> 12;
st->scale_avail[0][0] =
div_s64_rem(tmp, 1000000000LL, &st->scale_avail[0][1]);
st->scale_avail[1][0] =
div_s64_rem(tmp * 2, 1000000000LL, &st->scale_avail[1][1]);
}
int ad5592r_probe(struct device *dev, const char *name,
const struct ad5592r_rw_ops *ops)
{
struct iio_dev *iio_dev;
struct ad5592r_state *st;
int ret;
iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!iio_dev)
return -ENOMEM;
st = iio_priv(iio_dev);
st->dev = dev;
st->ops = ops;
st->num_channels = 8;
dev_set_drvdata(dev, iio_dev);
st->reg = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->reg)) {
if ((PTR_ERR(st->reg) != -ENODEV) && dev->of_node)
return PTR_ERR(st->reg);
st->reg = NULL;
} else {
ret = regulator_enable(st->reg);
if (ret)
return ret;
}
iio_dev->dev.parent = dev;
iio_dev->name = name;
iio_dev->info = &ad5592r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
ad5592r_init_scales(st, ad5592r_get_vref(st));
ret = ad5592r_reset(st);
if (ret)
goto error_disable_reg;
ret = ops->reg_write(st, AD5592R_REG_PD,
(st->reg == NULL) ? AD5592R_REG_PD_EN_REF : 0);
if (ret)
goto error_disable_reg;
ret = ad5592r_alloc_channels(st);
if (ret)
goto error_disable_reg;
ret = ad5592r_set_channel_modes(st);
if (ret)
goto error_reset_ch_modes;
ret = iio_device_register(iio_dev);
if (ret)
goto error_reset_ch_modes;
ret = ad5592r_gpio_init(st);
if (ret)
goto error_dev_unregister;
return 0;
error_dev_unregister:
iio_device_unregister(iio_dev);
error_reset_ch_modes:
ad5592r_reset_channel_modes(st);
error_disable_reg:
if (st->reg)
regulator_disable(st->reg);
return ret;
}
EXPORT_SYMBOL_GPL(ad5592r_probe);
int ad5592r_remove(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct ad5592r_state *st = iio_priv(iio_dev);
iio_device_unregister(iio_dev);
ad5592r_reset_channel_modes(st);
ad5592r_gpio_cleanup(st);
if (st->reg)
regulator_disable(st->reg);
return 0;
}
EXPORT_SYMBOL_GPL(ad5592r_remove);
MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,76 @@
/*
* AD5592R / AD5593R Digital <-> Analog converters driver
*
* Copyright 2015-2016 Analog Devices Inc.
* Author: Paul Cercueil <paul.cercueil@analog.com>
*
* Licensed under the GPL-2.
*/
#ifndef __DRIVERS_IIO_DAC_AD5592R_BASE_H__
#define __DRIVERS_IIO_DAC_AD5592R_BASE_H__
#include <linux/types.h>
#include <linux/cache.h>
#include <linux/mutex.h>
#include <linux/gpio/driver.h>
struct device;
struct ad5592r_state;
enum ad5592r_registers {
AD5592R_REG_NOOP = 0x0,
AD5592R_REG_DAC_READBACK = 0x1,
AD5592R_REG_ADC_SEQ = 0x2,
AD5592R_REG_CTRL = 0x3,
AD5592R_REG_ADC_EN = 0x4,
AD5592R_REG_DAC_EN = 0x5,
AD5592R_REG_PULLDOWN = 0x6,
AD5592R_REG_LDAC = 0x7,
AD5592R_REG_GPIO_OUT_EN = 0x8,
AD5592R_REG_GPIO_SET = 0x9,
AD5592R_REG_GPIO_IN_EN = 0xA,
AD5592R_REG_PD = 0xB,
AD5592R_REG_OPEN_DRAIN = 0xC,
AD5592R_REG_TRISTATE = 0xD,
AD5592R_REG_RESET = 0xF,
};
#define AD5592R_REG_PD_EN_REF BIT(9)
#define AD5592R_REG_CTRL_ADC_RANGE BIT(5)
#define AD5592R_REG_CTRL_DAC_RANGE BIT(4)
struct ad5592r_rw_ops {
int (*write_dac)(struct ad5592r_state *st, unsigned chan, u16 value);
int (*read_adc)(struct ad5592r_state *st, unsigned chan, u16 *value);
int (*reg_write)(struct ad5592r_state *st, u8 reg, u16 value);
int (*reg_read)(struct ad5592r_state *st, u8 reg, u16 *value);
int (*gpio_read)(struct ad5592r_state *st, u8 *value);
};
struct ad5592r_state {
struct device *dev;
struct regulator *reg;
struct gpio_chip gpiochip;
struct mutex gpio_lock; /* Protect cached gpio_out, gpio_val, etc. */
unsigned int num_channels;
const struct ad5592r_rw_ops *ops;
int scale_avail[2][2];
u16 cached_dac[8];
u16 cached_gp_ctrl;
u8 channel_modes[8];
u8 channel_offstate[8];
u8 gpio_map;
u8 gpio_out;
u8 gpio_in;
u8 gpio_val;
__be16 spi_msg ____cacheline_aligned;
__be16 spi_msg_nop;
};
int ad5592r_probe(struct device *dev, const char *name,
const struct ad5592r_rw_ops *ops);
int ad5592r_remove(struct device *dev);
#endif /* __DRIVERS_IIO_DAC_AD5592R_BASE_H__ */

164
drivers/iio/dac/ad5592r.c Normal file
View File

@ -0,0 +1,164 @@
/*
* AD5592R Digital <-> Analog converters driver
*
* Copyright 2015-2016 Analog Devices Inc.
* Author: Paul Cercueil <paul.cercueil@analog.com>
*
* Licensed under the GPL-2.
*/
#include "ad5592r-base.h"
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#define AD5592R_GPIO_READBACK_EN BIT(10)
#define AD5592R_LDAC_READBACK_EN BIT(6)
static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf)
{
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
struct spi_transfer t = {
.tx_buf = &st->spi_msg_nop,
.rx_buf = buf,
.len = 2
};
st->spi_msg_nop = 0; /* NOP */
return spi_sync_transfer(spi, &t, 1);
}
static int ad5592r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
{
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
st->spi_msg = cpu_to_be16(BIT(15) | (chan << 12) | value);
return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
}
static int ad5592r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
{
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
int ret;
st->spi_msg = cpu_to_be16((AD5592R_REG_ADC_SEQ << 11) | BIT(chan));
ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
if (ret)
return ret;
/*
* Invalid data:
* See Figure 40. Single-Channel ADC Conversion Sequence
*/
ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
if (ret)
return ret;
ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
if (ret)
return ret;
*value = be16_to_cpu(st->spi_msg);
return 0;
}
static int ad5592r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
{
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
st->spi_msg = cpu_to_be16((reg << 11) | value);
return spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
}
static int ad5592r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
{
struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
int ret;
st->spi_msg = cpu_to_be16((AD5592R_REG_LDAC << 11) |
AD5592R_LDAC_READBACK_EN | (reg << 2));
ret = spi_write(spi, &st->spi_msg, sizeof(st->spi_msg));
if (ret)
return ret;
ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
if (ret)
return ret;
*value = be16_to_cpu(st->spi_msg);
return 0;
}
static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
{
int ret;
ret = ad5592r_reg_write(st, AD5592R_REG_GPIO_IN_EN,
AD5592R_GPIO_READBACK_EN | st->gpio_in);
if (ret)
return ret;
ret = ad5592r_spi_wnop_r16(st, &st->spi_msg);
if (ret)
return ret;
*value = (u8) be16_to_cpu(st->spi_msg);
return 0;
}
static const struct ad5592r_rw_ops ad5592r_rw_ops = {
.write_dac = ad5592r_write_dac,
.read_adc = ad5592r_read_adc,
.reg_write = ad5592r_reg_write,
.reg_read = ad5592r_reg_read,
.gpio_read = ad5593r_gpio_read,
};
static int ad5592r_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
return ad5592r_probe(&spi->dev, id->name, &ad5592r_rw_ops);
}
static int ad5592r_spi_remove(struct spi_device *spi)
{
return ad5592r_remove(&spi->dev);
}
static const struct spi_device_id ad5592r_spi_ids[] = {
{ .name = "ad5592r", },
{}
};
MODULE_DEVICE_TABLE(spi, ad5592r_spi_ids);
static const struct of_device_id ad5592r_of_match[] = {
{ .compatible = "adi,ad5592r", },
{},
};
MODULE_DEVICE_TABLE(of, ad5592r_of_match);
static struct spi_driver ad5592r_spi_driver = {
.driver = {
.name = "ad5592r",
.of_match_table = of_match_ptr(ad5592r_of_match),
},
.probe = ad5592r_spi_probe,
.remove = ad5592r_spi_remove,
.id_table = ad5592r_spi_ids,
};
module_spi_driver(ad5592r_spi_driver);
MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
MODULE_LICENSE("GPL v2");

131
drivers/iio/dac/ad5593r.c Normal file
View File

@ -0,0 +1,131 @@
/*
* AD5593R Digital <-> Analog converters driver
*
* Copyright 2015-2016 Analog Devices Inc.
* Author: Paul Cercueil <paul.cercueil@analog.com>
*
* Licensed under the GPL-2.
*/
#include "ad5592r-base.h"
#include <linux/bitops.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#define AD5593R_MODE_CONF (0 << 4)
#define AD5593R_MODE_DAC_WRITE (1 << 4)
#define AD5593R_MODE_ADC_READBACK (4 << 4)
#define AD5593R_MODE_DAC_READBACK (5 << 4)
#define AD5593R_MODE_GPIO_READBACK (6 << 4)
#define AD5593R_MODE_REG_READBACK (7 << 4)
static int ad5593r_write_dac(struct ad5592r_state *st, unsigned chan, u16 value)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
return i2c_smbus_write_word_swapped(i2c,
AD5593R_MODE_DAC_WRITE | chan, value);
}
static int ad5593r_read_adc(struct ad5592r_state *st, unsigned chan, u16 *value)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
s32 val;
val = i2c_smbus_write_word_swapped(i2c,
AD5593R_MODE_CONF | AD5592R_REG_ADC_SEQ, BIT(chan));
if (val < 0)
return (int) val;
val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_ADC_READBACK);
if (val < 0)
return (int) val;
*value = (u16) val;
return 0;
}
static int ad5593r_reg_write(struct ad5592r_state *st, u8 reg, u16 value)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
return i2c_smbus_write_word_swapped(i2c,
AD5593R_MODE_CONF | reg, value);
}
static int ad5593r_reg_read(struct ad5592r_state *st, u8 reg, u16 *value)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
s32 val;
val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_REG_READBACK | reg);
if (val < 0)
return (int) val;
*value = (u16) val;
return 0;
}
static int ad5593r_gpio_read(struct ad5592r_state *st, u8 *value)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
s32 val;
val = i2c_smbus_read_word_swapped(i2c, AD5593R_MODE_GPIO_READBACK);
if (val < 0)
return (int) val;
*value = (u8) val;
return 0;
}
static const struct ad5592r_rw_ops ad5593r_rw_ops = {
.write_dac = ad5593r_write_dac,
.read_adc = ad5593r_read_adc,
.reg_write = ad5593r_reg_write,
.reg_read = ad5593r_reg_read,
.gpio_read = ad5593r_gpio_read,
};
static int ad5593r_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
return ad5592r_probe(&i2c->dev, id->name, &ad5593r_rw_ops);
}
static int ad5593r_i2c_remove(struct i2c_client *i2c)
{
return ad5592r_remove(&i2c->dev);
}
static const struct i2c_device_id ad5593r_i2c_ids[] = {
{ .name = "ad5593r", },
{},
};
MODULE_DEVICE_TABLE(i2c, ad5593r_i2c_ids);
static const struct of_device_id ad5593r_of_match[] = {
{ .compatible = "adi,ad5593r", },
{},
};
MODULE_DEVICE_TABLE(of, ad5593r_of_match);
static struct i2c_driver ad5593r_driver = {
.driver = {
.name = "ad5593r",
.of_match_table = of_match_ptr(ad5593r_of_match),
},
.probe = ad5593r_i2c_probe,
.remove = ad5593r_i2c_remove,
.id_table = ad5593r_i2c_ids,
};
module_i2c_driver(ad5593r_driver);
MODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,210 @@
/*
* IIO DAC driver for NXP LPC18xx DAC
*
* Copyright (C) 2016 Joachim Eastwood <manabian@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.
*
* UNSUPPORTED hardware features:
* - Interrupts
* - DMA
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/* LPC18XX DAC registers and bits */
#define LPC18XX_DAC_CR 0x000
#define LPC18XX_DAC_CR_VALUE_SHIFT 6
#define LPC18XX_DAC_CR_VALUE_MASK 0x3ff
#define LPC18XX_DAC_CR_BIAS BIT(16)
#define LPC18XX_DAC_CTRL 0x004
#define LPC18XX_DAC_CTRL_DMA_ENA BIT(3)
struct lpc18xx_dac {
struct regulator *vref;
void __iomem *base;
struct mutex lock;
struct clk *clk;
};
static const struct iio_chan_spec lpc18xx_dac_iio_channels[] = {
{
.type = IIO_VOLTAGE,
.output = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static int lpc18xx_dac_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct lpc18xx_dac *dac = iio_priv(indio_dev);
u32 reg;
switch (mask) {
case IIO_CHAN_INFO_RAW:
reg = readl(dac->base + LPC18XX_DAC_CR);
*val = reg >> LPC18XX_DAC_CR_VALUE_SHIFT;
*val &= LPC18XX_DAC_CR_VALUE_MASK;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = regulator_get_voltage(dac->vref) / 1000;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct lpc18xx_dac *dac = iio_priv(indio_dev);
u32 reg;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val > LPC18XX_DAC_CR_VALUE_MASK)
return -EINVAL;
reg = LPC18XX_DAC_CR_BIAS;
reg |= val << LPC18XX_DAC_CR_VALUE_SHIFT;
mutex_lock(&dac->lock);
writel(reg, dac->base + LPC18XX_DAC_CR);
writel(LPC18XX_DAC_CTRL_DMA_ENA, dac->base + LPC18XX_DAC_CTRL);
mutex_unlock(&dac->lock);
return 0;
}
return -EINVAL;
}
static const struct iio_info lpc18xx_dac_info = {
.read_raw = lpc18xx_dac_read_raw,
.write_raw = lpc18xx_dac_write_raw,
.driver_module = THIS_MODULE,
};
static int lpc18xx_dac_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct lpc18xx_dac *dac;
struct resource *res;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
dac = iio_priv(indio_dev);
mutex_init(&dac->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dac->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dac->base))
return PTR_ERR(dac->base);
dac->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dac->clk)) {
dev_err(&pdev->dev, "error getting clock\n");
return PTR_ERR(dac->clk);
}
dac->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(dac->vref)) {
dev_err(&pdev->dev, "error getting regulator\n");
return PTR_ERR(dac->vref);
}
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &lpc18xx_dac_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = lpc18xx_dac_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(lpc18xx_dac_iio_channels);
ret = regulator_enable(dac->vref);
if (ret) {
dev_err(&pdev->dev, "unable to enable regulator\n");
return ret;
}
ret = clk_prepare_enable(dac->clk);
if (ret) {
dev_err(&pdev->dev, "unable to enable clock\n");
goto dis_reg;
}
writel(0, dac->base + LPC18XX_DAC_CTRL);
writel(0, dac->base + LPC18XX_DAC_CR);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "unable to register device\n");
goto dis_clk;
}
return 0;
dis_clk:
clk_disable_unprepare(dac->clk);
dis_reg:
regulator_disable(dac->vref);
return ret;
}
static int lpc18xx_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct lpc18xx_dac *dac = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
writel(0, dac->base + LPC18XX_DAC_CTRL);
clk_disable_unprepare(dac->clk);
regulator_disable(dac->vref);
return 0;
}
static const struct of_device_id lpc18xx_dac_match[] = {
{ .compatible = "nxp,lpc1850-dac" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
static struct platform_driver lpc18xx_dac_driver = {
.probe = lpc18xx_dac_probe,
.remove = lpc18xx_dac_remove,
.driver = {
.name = "lpc18xx-dac",
.of_match_table = lpc18xx_dac_match,
},
};
module_platform_driver(lpc18xx_dac_driver);
MODULE_DESCRIPTION("LPC18xx DAC driver");
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_LICENSE("GPL v2");

View File

@ -284,7 +284,7 @@ struct ad9523_state {
} data[2] ____cacheline_aligned;
};
static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
static int ad9523_read(struct iio_dev *indio_dev, unsigned int addr)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
@ -318,7 +318,8 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
return ret;
};
static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
static int ad9523_write(struct iio_dev *indio_dev,
unsigned int addr, unsigned int val)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
@ -351,11 +352,11 @@ static int ad9523_io_update(struct iio_dev *indio_dev)
}
static int ad9523_vco_out_map(struct iio_dev *indio_dev,
unsigned ch, unsigned out)
unsigned int ch, unsigned int out)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
unsigned mask;
unsigned int mask;
switch (ch) {
case 0 ... 3:
@ -405,7 +406,7 @@ static int ad9523_vco_out_map(struct iio_dev *indio_dev,
}
static int ad9523_set_clock_provider(struct iio_dev *indio_dev,
unsigned ch, unsigned long freq)
unsigned int ch, unsigned long freq)
{
struct ad9523_state *st = iio_priv(indio_dev);
long tmp1, tmp2;
@ -619,7 +620,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad9523_state *st = iio_priv(indio_dev);
unsigned code;
unsigned int code;
int ret;
mutex_lock(&indio_dev->mlock);
@ -655,7 +656,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad9523_state *st = iio_priv(indio_dev);
unsigned reg;
unsigned int reg;
int ret, tmp, code;
mutex_lock(&indio_dev->mlock);
@ -709,8 +710,8 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
}
static int ad9523_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
unsigned int reg, unsigned int writeval,
unsigned int *readval)
{
int ret;

View File

@ -93,7 +93,7 @@ config IIO_ST_GYRO_3AXIS
select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
help
Say yes here to build support for STMicroelectronics gyroscopes:
L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330, LSM9DS0.
This driver can also be built as a module. If so, these modules
will be created:

View File

@ -17,7 +17,6 @@
#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>
@ -31,7 +30,6 @@
#include "bmg160.h"
#define BMG160_IRQ_NAME "bmg160_event"
#define BMG160_GPIO_NAME "gpio_int"
#define BMG160_REG_CHIP_ID 0x00
#define BMG160_CHIP_ID_VAL 0x0F
@ -97,7 +95,6 @@
#define BMG160_AUTO_SUSPEND_DELAY_MS 2000
struct bmg160_data {
struct device *dev;
struct regmap *regmap;
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
@ -116,6 +113,7 @@ enum bmg160_axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
AXIS_MAX,
};
static const struct {
@ -138,11 +136,12 @@ static const struct {
static int bmg160_set_mode(struct bmg160_data *data, u8 mode)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
ret = regmap_write(data->regmap, BMG160_REG_PMU_LPW, mode);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_pmu_lpw\n");
dev_err(dev, "Error writing reg_pmu_lpw\n");
return ret;
}
@ -163,6 +162,7 @@ static int bmg160_convert_freq_to_bit(int val)
static int bmg160_set_bw(struct bmg160_data *data, int val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
int bw_bits;
@ -172,7 +172,7 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bw_bits);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_pmu_bw\n");
dev_err(dev, "Error writing reg_pmu_bw\n");
return ret;
}
@ -183,18 +183,19 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
static int bmg160_chip_init(struct bmg160_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
unsigned int val;
ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_chip_id\n");
dev_err(dev, "Error reading reg_chip_id\n");
return ret;
}
dev_dbg(data->dev, "Chip Id %x\n", val);
dev_dbg(dev, "Chip Id %x\n", val);
if (val != BMG160_CHIP_ID_VAL) {
dev_err(data->dev, "invalid chip %x\n", val);
dev_err(dev, "invalid chip %x\n", val);
return -ENODEV;
}
@ -213,14 +214,14 @@ static int bmg160_chip_init(struct bmg160_data *data)
/* Set Default Range */
ret = regmap_write(data->regmap, BMG160_REG_RANGE, BMG160_RANGE_500DPS);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_range\n");
dev_err(dev, "Error writing reg_range\n");
return ret;
}
data->dps_range = BMG160_RANGE_500DPS;
ret = regmap_read(data->regmap, BMG160_REG_SLOPE_THRES, &val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_slope_thres\n");
dev_err(dev, "Error reading reg_slope_thres\n");
return ret;
}
data->slope_thres = val;
@ -229,7 +230,7 @@ static int bmg160_chip_init(struct bmg160_data *data)
ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1,
BMG160_INT1_BIT_OD, 0);
if (ret < 0) {
dev_err(data->dev, "Error updating bits in reg_int_en_1\n");
dev_err(dev, "Error updating bits in reg_int_en_1\n");
return ret;
}
@ -237,7 +238,7 @@ static int bmg160_chip_init(struct bmg160_data *data)
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev,
dev_err(dev,
"Error writing reg_motion_intr\n");
return ret;
}
@ -248,20 +249,21 @@ static int bmg160_chip_init(struct bmg160_data *data)
static int bmg160_set_power_state(struct bmg160_data *data, bool on)
{
#ifdef CONFIG_PM
struct device *dev = regmap_get_device(data->regmap);
int ret;
if (on)
ret = pm_runtime_get_sync(data->dev);
ret = pm_runtime_get_sync(dev);
else {
pm_runtime_mark_last_busy(data->dev);
ret = pm_runtime_put_autosuspend(data->dev);
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
}
if (ret < 0) {
dev_err(data->dev,
"Failed: bmg160_set_power_state for %d\n", on);
dev_err(dev, "Failed: bmg160_set_power_state for %d\n", on);
if (on)
pm_runtime_put_noidle(data->dev);
pm_runtime_put_noidle(dev);
return ret;
}
@ -273,6 +275,7 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on)
static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
bool status)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
/* Enable/Disable INT_MAP0 mapping */
@ -280,7 +283,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
BMG160_INT_MAP_0_BIT_ANY,
(status ? BMG160_INT_MAP_0_BIT_ANY : 0));
if (ret < 0) {
dev_err(data->dev, "Error updating bits reg_int_map0\n");
dev_err(dev, "Error updating bits reg_int_map0\n");
return ret;
}
@ -290,8 +293,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
ret = regmap_write(data->regmap, BMG160_REG_SLOPE_THRES,
data->slope_thres);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_slope_thres\n");
dev_err(dev, "Error writing reg_slope_thres\n");
return ret;
}
@ -299,8 +301,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
BMG160_INT_MOTION_X | BMG160_INT_MOTION_Y |
BMG160_INT_MOTION_Z);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_motion_intr\n");
dev_err(dev, "Error writing reg_motion_intr\n");
return ret;
}
@ -315,8 +316,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_rst_latch\n");
dev_err(dev, "Error writing reg_rst_latch\n");
return ret;
}
}
@ -329,7 +329,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
}
if (ret < 0) {
dev_err(data->dev, "Error writing reg_int_en0\n");
dev_err(dev, "Error writing reg_int_en0\n");
return ret;
}
@ -339,6 +339,7 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data,
static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
bool status)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
/* Enable/Disable INT_MAP1 mapping */
@ -346,7 +347,7 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
BMG160_INT_MAP_1_BIT_NEW_DATA,
(status ? BMG160_INT_MAP_1_BIT_NEW_DATA : 0));
if (ret < 0) {
dev_err(data->dev, "Error updating bits in reg_int_map1\n");
dev_err(dev, "Error updating bits in reg_int_map1\n");
return ret;
}
@ -355,9 +356,8 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
BMG160_INT_MODE_NON_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_rst_latch\n");
return ret;
dev_err(dev, "Error writing reg_rst_latch\n");
return ret;
}
ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0,
@ -369,16 +369,15 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_rst_latch\n");
return ret;
dev_err(dev, "Error writing reg_rst_latch\n");
return ret;
}
ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0);
}
if (ret < 0) {
dev_err(data->dev, "Error writing reg_int_en0\n");
dev_err(dev, "Error writing reg_int_en0\n");
return ret;
}
@ -401,6 +400,7 @@ static int bmg160_get_bw(struct bmg160_data *data, int *val)
static int bmg160_set_scale(struct bmg160_data *data, int val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret, i;
for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) {
@ -408,8 +408,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
ret = regmap_write(data->regmap, BMG160_REG_RANGE,
bmg160_scale_table[i].dps_range);
if (ret < 0) {
dev_err(data->dev,
"Error writing reg_range\n");
dev_err(dev, "Error writing reg_range\n");
return ret;
}
data->dps_range = bmg160_scale_table[i].dps_range;
@ -422,6 +421,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val)
static int bmg160_get_temp(struct bmg160_data *data, int *val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
unsigned int raw_val;
@ -434,7 +434,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
ret = regmap_read(data->regmap, BMG160_REG_TEMP, &raw_val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_temp\n");
dev_err(dev, "Error reading reg_temp\n");
bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
@ -451,6 +451,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val)
static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
__le16 raw_val;
@ -464,7 +465,7 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val)
ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val,
sizeof(raw_val));
if (ret < 0) {
dev_err(data->dev, "Error reading axis %d\n", axis);
dev_err(dev, "Error reading axis %d\n", axis);
bmg160_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
@ -764,26 +765,23 @@ static const struct iio_info bmg160_info = {
.driver_module = THIS_MODULE,
};
static const unsigned long bmg160_accel_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0};
static irqreturn_t bmg160_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmg160_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
unsigned int val;
int ret;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit),
&val, 2);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err;
}
data->buffer[i++] = val;
}
ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L,
data->buffer, AXIS_MAX * 2);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
pf->timestamp);
@ -797,6 +795,7 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bmg160_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int ret;
/* new data interrupts don't need ack */
@ -808,7 +807,7 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig)
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(data->dev, "Error writing reg_rst_latch\n");
dev_err(dev, "Error writing reg_rst_latch\n");
return ret;
}
@ -868,13 +867,14 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct bmg160_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
int ret;
int dir;
unsigned int val;
ret = regmap_read(data->regmap, BMG160_REG_INT_STATUS_2, &val);
if (ret < 0) {
dev_err(data->dev, "Error reading reg_int_status2\n");
dev_err(dev, "Error reading reg_int_status2\n");
goto ack_intr_status;
}
@ -911,8 +911,7 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
BMG160_INT_MODE_LATCH_INT |
BMG160_INT_MODE_LATCH_RESET);
if (ret < 0)
dev_err(data->dev,
"Error writing reg_rst_latch\n");
dev_err(dev, "Error writing reg_rst_latch\n");
}
return IRQ_HANDLED;
@ -956,29 +955,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
.postdisable = bmg160_buffer_postdisable,
};
static int bmg160_gpio_probe(struct bmg160_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
dev = data->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
data->irq = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
data->irq);
return 0;
}
static const char *bmg160_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
@ -1003,7 +979,6 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->dev = dev;
data->irq = irq;
data->regmap = regmap;
@ -1020,12 +995,10 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
indio_dev->channels = bmg160_channels;
indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
indio_dev->name = name;
indio_dev->available_scan_masks = bmg160_accel_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmg160_info;
if (data->irq <= 0)
bmg160_gpio_probe(data);
if (data->irq > 0) {
ret = devm_request_threaded_irq(dev,
data->irq,
@ -1168,7 +1141,7 @@ static int bmg160_runtime_suspend(struct device *dev)
ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND);
if (ret < 0) {
dev_err(data->dev, "set mode failed\n");
dev_err(dev, "set mode failed\n");
return -EAGAIN;
}

View File

@ -21,6 +21,7 @@
#define L3GD20_GYRO_DEV_NAME "l3gd20"
#define L3G4IS_GYRO_DEV_NAME "l3g4is_ui"
#define LSM330_GYRO_DEV_NAME "lsm330_gyro"
#define LSM9DS0_GYRO_DEV_NAME "lsm9ds0_gyro"
/**
* struct st_sensors_platform_data - gyro platform data

View File

@ -190,6 +190,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_GYRO_1_MULTIREAD_BIT,
.bootime = 2,
@ -203,6 +204,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
[2] = LSM330DLC_GYRO_DEV_NAME,
[3] = L3G4IS_GYRO_DEV_NAME,
[4] = LSM330_GYRO_DEV_NAME,
[5] = LSM9DS0_GYRO_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
.odr = {
@ -258,6 +260,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
.bootime = 2,
@ -322,6 +325,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
},
.multi_read_bit = ST_GYRO_3_MULTIREAD_BIT,
.bootime = 2,

View File

@ -48,6 +48,10 @@ static const struct of_device_id st_gyro_of_match[] = {
.compatible = "st,lsm330-gyro",
.data = LSM330_GYRO_DEV_NAME,
},
{
.compatible = "st,lsm9ds0-gyro",
.data = LSM9DS0_GYRO_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
@ -93,6 +97,7 @@ static const struct i2c_device_id st_gyro_id_table[] = {
{ L3GD20_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{ LSM9DS0_GYRO_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);

View File

@ -54,6 +54,7 @@ static const struct spi_device_id st_gyro_id_table[] = {
{ L3GD20_GYRO_DEV_NAME },
{ L3G4IS_GYRO_DEV_NAME },
{ LSM330_GYRO_DEV_NAME },
{ LSM9DS0_GYRO_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_gyro_id_table);

View File

@ -3,6 +3,16 @@
#
menu "Humidity sensors"
config AM2315
tristate "Aosong AM2315 relative humidity and temperature sensor"
depends on I2C
help
If you say yes here you get support for the Aosong AM2315
relative humidity and ambient temperature sensor.
This driver can also be built as a module. If so, the module will
be called am2315.
config DHT11
tristate "DHT11 (and compatible sensors) driver"
depends on GPIOLIB || COMPILE_TEST

View File

@ -2,6 +2,7 @@
# Makefile for IIO humidity sensor drivers
#
obj-$(CONFIG_AM2315) += am2315.o
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o
obj-$(CONFIG_HTU21) += htu21.o

View File

@ -0,0 +1,303 @@
/**
* Aosong AM2315 relative humidity and temperature
*
* Copyright (c) 2016, 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.
*
* 7-bit I2C address: 0x5C.
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define AM2315_REG_HUM_MSB 0x00
#define AM2315_REG_HUM_LSB 0x01
#define AM2315_REG_TEMP_MSB 0x02
#define AM2315_REG_TEMP_LSB 0x03
#define AM2315_FUNCTION_READ 0x03
#define AM2315_HUM_OFFSET 2
#define AM2315_TEMP_OFFSET 4
#define AM2315_ALL_CHANNEL_MASK GENMASK(1, 0)
#define AM2315_DRIVER_NAME "am2315"
struct am2315_data {
struct i2c_client *client;
struct mutex lock;
s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */
};
struct am2315_sensor_data {
s16 hum_data;
s16 temp_data;
};
static const struct iio_chan_spec am2315_channels[] = {
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_CPU,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
/* CRC calculation algorithm, as specified in the datasheet (page 13). */
static u16 am2315_crc(u8 *data, u8 nr_bytes)
{
int i;
u16 crc = 0xffff;
while (nr_bytes--) {
crc ^= *data++;
for (i = 0; i < 8; i++) {
if (crc & 0x01) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
/* Simple function that sends a few bytes to the device to wake it up. */
static void am2315_ping(struct i2c_client *client)
{
i2c_smbus_read_byte_data(client, AM2315_REG_HUM_MSB);
}
static int am2315_read_data(struct am2315_data *data,
struct am2315_sensor_data *sensor_data)
{
int ret;
/* tx_buf format: <function code> <start addr> <nr of regs to read> */
u8 tx_buf[3] = { AM2315_FUNCTION_READ, AM2315_REG_HUM_MSB, 4 };
/*
* rx_buf format:
* <function code> <number of registers read>
* <humidity MSB> <humidity LSB> <temp MSB> <temp LSB>
* <CRC LSB> <CRC MSB>
*/
u8 rx_buf[8];
u16 crc;
/* First wake up the device. */
am2315_ping(data->client);
mutex_lock(&data->lock);
ret = i2c_master_send(data->client, tx_buf, sizeof(tx_buf));
if (ret < 0) {
dev_err(&data->client->dev, "failed to send read request\n");
goto exit_unlock;
}
/* Wait 2-3 ms, then read back the data sent by the device. */
usleep_range(2000, 3000);
/* Do a bulk data read, then pick out what we need. */
ret = i2c_master_recv(data->client, rx_buf, sizeof(rx_buf));
if (ret < 0) {
dev_err(&data->client->dev, "failed to read sensor data\n");
goto exit_unlock;
}
mutex_unlock(&data->lock);
/*
* Do a CRC check on the data and compare it to the value
* calculated by the device.
*/
crc = am2315_crc(rx_buf, sizeof(rx_buf) - 2);
if ((crc & 0xff) != rx_buf[6] || (crc >> 8) != rx_buf[7]) {
dev_err(&data->client->dev, "failed to verify sensor data\n");
return -EIO;
}
sensor_data->hum_data = (rx_buf[AM2315_HUM_OFFSET] << 8) |
rx_buf[AM2315_HUM_OFFSET + 1];
sensor_data->temp_data = (rx_buf[AM2315_TEMP_OFFSET] << 8) |
rx_buf[AM2315_TEMP_OFFSET + 1];
return ret;
exit_unlock:
mutex_unlock(&data->lock);
return ret;
}
static irqreturn_t am2315_trigger_handler(int irq, void *p)
{
int i;
int ret;
int bit;
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct am2315_data *data = iio_priv(indio_dev);
struct am2315_sensor_data sensor_data;
ret = am2315_read_data(data, &sensor_data);
if (ret < 0) {
mutex_unlock(&data->lock);
goto err;
}
mutex_lock(&data->lock);
if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
data->buffer[0] = sensor_data.hum_data;
data->buffer[1] = sensor_data.temp_data;
} else {
i = 0;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
data->buffer[i] = (bit ? sensor_data.temp_data :
sensor_data.hum_data);
i++;
}
}
mutex_unlock(&data->lock);
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int am2315_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct am2315_sensor_data sensor_data;
struct am2315_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = am2315_read_data(data, &sensor_data);
if (ret < 0)
return ret;
*val = (chan->type == IIO_HUMIDITYRELATIVE) ?
sensor_data.hum_data : sensor_data.temp_data;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 100;
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info am2315_info = {
.driver_module = THIS_MODULE,
.read_raw = am2315_read_raw,
};
static int am2315_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct am2315_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 = &am2315_info;
indio_dev->name = AM2315_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = am2315_channels;
indio_dev->num_channels = ARRAY_SIZE(am2315_channels);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
am2315_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_buffer_cleanup;
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int am2315_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static const struct i2c_device_id am2315_i2c_id[] = {
{"am2315", 0},
{}
};
static const struct acpi_device_id am2315_acpi_id[] = {
{"AOS2315", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, am2315_acpi_id);
static struct i2c_driver am2315_driver = {
.driver = {
.name = "am2315",
.acpi_match_table = ACPI_PTR(am2315_acpi_id),
},
.probe = am2315_probe,
.remove = am2315_remove,
.id_table = am2315_i2c_id,
};
module_i2c_driver(am2315_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
MODULE_DESCRIPTION("Aosong AM2315 relative humidity and temperature");
MODULE_LICENSE("GPL v2");

View File

@ -96,6 +96,24 @@ struct dht11 {
struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ];
};
#ifdef CONFIG_DYNAMIC_DEBUG
/*
* dht11_edges_print: show the data as actually received by the
* driver.
*/
static void dht11_edges_print(struct dht11 *dht11)
{
int i;
dev_dbg(dht11->dev, "%d edges detected:\n", dht11->num_edges);
for (i = 1; i < dht11->num_edges; ++i) {
dev_dbg(dht11->dev, "%d: %lld ns %s\n", i,
dht11->edges[i].ts - dht11->edges[i - 1].ts,
dht11->edges[i - 1].value ? "high" : "low");
}
}
#endif /* CONFIG_DYNAMIC_DEBUG */
static unsigned char dht11_decode_byte(char *bits)
{
unsigned char ret = 0;
@ -119,8 +137,12 @@ static int dht11_decode(struct dht11 *dht11, int offset)
for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
t = dht11->edges[offset + 2 * i + 2].ts -
dht11->edges[offset + 2 * i + 1].ts;
if (!dht11->edges[offset + 2 * i + 1].value)
return -EIO; /* lost synchronisation */
if (!dht11->edges[offset + 2 * i + 1].value) {
dev_dbg(dht11->dev,
"lost synchronisation at edge %d\n",
offset + 2 * i + 1);
return -EIO;
}
bits[i] = t > DHT11_THRESHOLD;
}
@ -130,8 +152,10 @@ static int dht11_decode(struct dht11 *dht11, int offset)
temp_dec = dht11_decode_byte(&bits[24]);
checksum = dht11_decode_byte(&bits[32]);
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) {
dev_dbg(dht11->dev, "invalid checksum\n");
return -EIO;
}
dht11->timestamp = ktime_get_boot_ns();
if (hum_int < 20) { /* DHT22 */
@ -182,6 +206,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
mutex_lock(&dht11->lock);
if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) {
timeres = ktime_get_resolution_ns();
dev_dbg(dht11->dev, "current timeresolution: %dns\n", timeres);
if (timeres > DHT11_MIN_TIMERES) {
dev_err(dht11->dev, "timeresolution %dns too low\n",
timeres);
@ -219,10 +244,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
free_irq(dht11->irq, iio_dev);
#ifdef CONFIG_DYNAMIC_DEBUG
dht11_edges_print(dht11);
#endif
if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
dev_err(&iio_dev->dev,
"Only %d signal edges detected\n",
dht11->num_edges);
dev_err(dht11->dev, "Only %d signal edges detected\n",
dht11->num_edges);
ret = -ETIMEDOUT;
}
if (ret < 0)

View File

@ -25,6 +25,8 @@ config ADIS16480
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
source "drivers/iio/imu/bmi160/Kconfig"
config KMX61
tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
depends on I2C

View File

@ -13,6 +13,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += bmi160/
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o

View File

@ -324,7 +324,12 @@ static int adis_self_test(struct adis *adis)
msleep(adis->data->startup_delay);
return adis_check_status(adis);
ret = adis_check_status(adis);
if (adis->data->self_test_no_autoclear)
adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
return ret;
}
/**

View File

@ -0,0 +1,32 @@
#
# BMI160 IMU driver
#
config BMI160
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config BMI160_I2C
tristate "Bosch BMI160 I2C driver"
depends on I2C
select BMI160
select REGMAP_I2C
help
If you say yes here you get support for BMI160 IMU on I2C with
accelerometer, gyroscope and external BMG160 magnetometer.
This driver can also be built as a module. If so, the module will be
called bmi160_i2c.
config BMI160_SPI
tristate "Bosch BMI160 SPI driver"
depends on SPI
select BMI160
select REGMAP_SPI
help
If you say yes here you get support for BMI160 IMU on SPI with
accelerometer, gyroscope and external BMG160 magnetometer.
This driver can also be built as a module. If so, the module will be
called bmi160_spi.

View File

@ -0,0 +1,6 @@
#
# Makefile for Bosch BMI160 IMU
#
obj-$(CONFIG_BMI160) += bmi160_core.o
obj-$(CONFIG_BMI160_I2C) += bmi160_i2c.o
obj-$(CONFIG_BMI160_SPI) += bmi160_spi.o

View File

@ -0,0 +1,10 @@
#ifndef BMI160_H_
#define BMI160_H_
extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
void bmi160_core_remove(struct device *dev);
#endif /* BMI160_H_ */

View File

@ -0,0 +1,596 @@
/*
* BMI160 - Bosch IMU (accel, gyro plus external magnetometer)
*
* Copyright (c) 2016, 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 core driver for BMI160, with support for I2C/SPI busses
*
* TODO: magnetometer, interrupts, hardware FIFO
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include "bmi160.h"
#define BMI160_REG_CHIP_ID 0x00
#define BMI160_CHIP_ID_VAL 0xD1
#define BMI160_REG_PMU_STATUS 0x03
/* X axis data low byte address, the rest can be obtained using axis offset */
#define BMI160_REG_DATA_MAGN_XOUT_L 0x04
#define BMI160_REG_DATA_GYRO_XOUT_L 0x0C
#define BMI160_REG_DATA_ACCEL_XOUT_L 0x12
#define BMI160_REG_ACCEL_CONFIG 0x40
#define BMI160_ACCEL_CONFIG_ODR_MASK GENMASK(3, 0)
#define BMI160_ACCEL_CONFIG_BWP_MASK GENMASK(6, 4)
#define BMI160_REG_ACCEL_RANGE 0x41
#define BMI160_ACCEL_RANGE_2G 0x03
#define BMI160_ACCEL_RANGE_4G 0x05
#define BMI160_ACCEL_RANGE_8G 0x08
#define BMI160_ACCEL_RANGE_16G 0x0C
#define BMI160_REG_GYRO_CONFIG 0x42
#define BMI160_GYRO_CONFIG_ODR_MASK GENMASK(3, 0)
#define BMI160_GYRO_CONFIG_BWP_MASK GENMASK(5, 4)
#define BMI160_REG_GYRO_RANGE 0x43
#define BMI160_GYRO_RANGE_2000DPS 0x00
#define BMI160_GYRO_RANGE_1000DPS 0x01
#define BMI160_GYRO_RANGE_500DPS 0x02
#define BMI160_GYRO_RANGE_250DPS 0x03
#define BMI160_GYRO_RANGE_125DPS 0x04
#define BMI160_REG_CMD 0x7E
#define BMI160_CMD_ACCEL_PM_SUSPEND 0x10
#define BMI160_CMD_ACCEL_PM_NORMAL 0x11
#define BMI160_CMD_ACCEL_PM_LOW_POWER 0x12
#define BMI160_CMD_GYRO_PM_SUSPEND 0x14
#define BMI160_CMD_GYRO_PM_NORMAL 0x15
#define BMI160_CMD_GYRO_PM_FAST_STARTUP 0x17
#define BMI160_CMD_SOFTRESET 0xB6
#define BMI160_REG_DUMMY 0x7F
#define BMI160_ACCEL_PMU_MIN_USLEEP 3200
#define BMI160_ACCEL_PMU_MAX_USLEEP 3800
#define BMI160_GYRO_PMU_MIN_USLEEP 55000
#define BMI160_GYRO_PMU_MAX_USLEEP 80000
#define BMI160_SOFTRESET_USLEEP 1000
#define BMI160_CHANNEL(_type, _axis, _index) { \
.type = _type, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
/* scan indexes follow DATA register order */
enum bmi160_scan_axis {
BMI160_SCAN_EXT_MAGN_X = 0,
BMI160_SCAN_EXT_MAGN_Y,
BMI160_SCAN_EXT_MAGN_Z,
BMI160_SCAN_RHALL,
BMI160_SCAN_GYRO_X,
BMI160_SCAN_GYRO_Y,
BMI160_SCAN_GYRO_Z,
BMI160_SCAN_ACCEL_X,
BMI160_SCAN_ACCEL_Y,
BMI160_SCAN_ACCEL_Z,
BMI160_SCAN_TIMESTAMP,
};
enum bmi160_sensor_type {
BMI160_ACCEL = 0,
BMI160_GYRO,
BMI160_EXT_MAGN,
BMI160_NUM_SENSORS /* must be last */
};
struct bmi160_data {
struct regmap *regmap;
};
const struct regmap_config bmi160_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
EXPORT_SYMBOL(bmi160_regmap_config);
struct bmi160_regs {
u8 data; /* LSB byte register for X-axis */
u8 config;
u8 config_odr_mask;
u8 config_bwp_mask;
u8 range;
u8 pmu_cmd_normal;
u8 pmu_cmd_suspend;
};
static struct bmi160_regs bmi160_regs[] = {
[BMI160_ACCEL] = {
.data = BMI160_REG_DATA_ACCEL_XOUT_L,
.config = BMI160_REG_ACCEL_CONFIG,
.config_odr_mask = BMI160_ACCEL_CONFIG_ODR_MASK,
.config_bwp_mask = BMI160_ACCEL_CONFIG_BWP_MASK,
.range = BMI160_REG_ACCEL_RANGE,
.pmu_cmd_normal = BMI160_CMD_ACCEL_PM_NORMAL,
.pmu_cmd_suspend = BMI160_CMD_ACCEL_PM_SUSPEND,
},
[BMI160_GYRO] = {
.data = BMI160_REG_DATA_GYRO_XOUT_L,
.config = BMI160_REG_GYRO_CONFIG,
.config_odr_mask = BMI160_GYRO_CONFIG_ODR_MASK,
.config_bwp_mask = BMI160_GYRO_CONFIG_BWP_MASK,
.range = BMI160_REG_GYRO_RANGE,
.pmu_cmd_normal = BMI160_CMD_GYRO_PM_NORMAL,
.pmu_cmd_suspend = BMI160_CMD_GYRO_PM_SUSPEND,
},
};
struct bmi160_pmu_time {
unsigned long min;
unsigned long max;
};
static struct bmi160_pmu_time bmi160_pmu_time[] = {
[BMI160_ACCEL] = {
.min = BMI160_ACCEL_PMU_MIN_USLEEP,
.max = BMI160_ACCEL_PMU_MAX_USLEEP
},
[BMI160_GYRO] = {
.min = BMI160_GYRO_PMU_MIN_USLEEP,
.max = BMI160_GYRO_PMU_MIN_USLEEP,
},
};
struct bmi160_scale {
u8 bits;
int uscale;
};
struct bmi160_odr {
u8 bits;
int odr;
int uodr;
};
static const struct bmi160_scale bmi160_accel_scale[] = {
{ BMI160_ACCEL_RANGE_2G, 598},
{ BMI160_ACCEL_RANGE_4G, 1197},
{ BMI160_ACCEL_RANGE_8G, 2394},
{ BMI160_ACCEL_RANGE_16G, 4788},
};
static const struct bmi160_scale bmi160_gyro_scale[] = {
{ BMI160_GYRO_RANGE_2000DPS, 1065},
{ BMI160_GYRO_RANGE_1000DPS, 532},
{ BMI160_GYRO_RANGE_500DPS, 266},
{ BMI160_GYRO_RANGE_250DPS, 133},
{ BMI160_GYRO_RANGE_125DPS, 66},
};
struct bmi160_scale_item {
const struct bmi160_scale *tbl;
int num;
};
static const struct bmi160_scale_item bmi160_scale_table[] = {
[BMI160_ACCEL] = {
.tbl = bmi160_accel_scale,
.num = ARRAY_SIZE(bmi160_accel_scale),
},
[BMI160_GYRO] = {
.tbl = bmi160_gyro_scale,
.num = ARRAY_SIZE(bmi160_gyro_scale),
},
};
static const struct bmi160_odr bmi160_accel_odr[] = {
{0x01, 0, 78125},
{0x02, 1, 5625},
{0x03, 3, 125},
{0x04, 6, 25},
{0x05, 12, 5},
{0x06, 25, 0},
{0x07, 50, 0},
{0x08, 100, 0},
{0x09, 200, 0},
{0x0A, 400, 0},
{0x0B, 800, 0},
{0x0C, 1600, 0},
};
static const struct bmi160_odr bmi160_gyro_odr[] = {
{0x06, 25, 0},
{0x07, 50, 0},
{0x08, 100, 0},
{0x09, 200, 0},
{0x0A, 400, 0},
{0x0B, 8000, 0},
{0x0C, 1600, 0},
{0x0D, 3200, 0},
};
struct bmi160_odr_item {
const struct bmi160_odr *tbl;
int num;
};
static const struct bmi160_odr_item bmi160_odr_table[] = {
[BMI160_ACCEL] = {
.tbl = bmi160_accel_odr,
.num = ARRAY_SIZE(bmi160_accel_odr),
},
[BMI160_GYRO] = {
.tbl = bmi160_gyro_odr,
.num = ARRAY_SIZE(bmi160_gyro_odr),
},
};
static const struct iio_chan_spec bmi160_channels[] = {
BMI160_CHANNEL(IIO_ACCEL, X, BMI160_SCAN_ACCEL_X),
BMI160_CHANNEL(IIO_ACCEL, Y, BMI160_SCAN_ACCEL_Y),
BMI160_CHANNEL(IIO_ACCEL, Z, BMI160_SCAN_ACCEL_Z),
BMI160_CHANNEL(IIO_ANGL_VEL, X, BMI160_SCAN_GYRO_X),
BMI160_CHANNEL(IIO_ANGL_VEL, Y, BMI160_SCAN_GYRO_Y),
BMI160_CHANNEL(IIO_ANGL_VEL, Z, BMI160_SCAN_GYRO_Z),
IIO_CHAN_SOFT_TIMESTAMP(BMI160_SCAN_TIMESTAMP),
};
static enum bmi160_sensor_type bmi160_to_sensor(enum iio_chan_type iio_type)
{
switch (iio_type) {
case IIO_ACCEL:
return BMI160_ACCEL;
case IIO_ANGL_VEL:
return BMI160_GYRO;
default:
return -EINVAL;
}
}
static
int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t,
bool mode)
{
int ret;
u8 cmd;
if (mode)
cmd = bmi160_regs[t].pmu_cmd_normal;
else
cmd = bmi160_regs[t].pmu_cmd_suspend;
ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd);
if (ret < 0)
return ret;
usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max);
return 0;
}
static
int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
int uscale)
{
int i;
for (i = 0; i < bmi160_scale_table[t].num; i++)
if (bmi160_scale_table[t].tbl[i].uscale == uscale)
break;
if (i == bmi160_scale_table[t].num)
return -EINVAL;
return regmap_write(data->regmap, bmi160_regs[t].range,
bmi160_scale_table[t].tbl[i].bits);
}
static
int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t,
int *uscale)
{
int i, ret, val;
ret = regmap_read(data->regmap, bmi160_regs[t].range, &val);
if (ret < 0)
return ret;
for (i = 0; i < bmi160_scale_table[t].num; i++)
if (bmi160_scale_table[t].tbl[i].bits == val) {
*uscale = bmi160_scale_table[t].tbl[i].uscale;
return 0;
}
return -EINVAL;
}
static int bmi160_get_data(struct bmi160_data *data, int chan_type,
int axis, int *val)
{
u8 reg;
int ret;
__le16 sample;
enum bmi160_sensor_type t = bmi160_to_sensor(chan_type);
reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16);
ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16));
if (ret < 0)
return ret;
*val = sign_extend32(le16_to_cpu(sample), 15);
return 0;
}
static
int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
int odr, int uodr)
{
int i;
for (i = 0; i < bmi160_odr_table[t].num; i++)
if (bmi160_odr_table[t].tbl[i].odr == odr &&
bmi160_odr_table[t].tbl[i].uodr == uodr)
break;
if (i >= bmi160_odr_table[t].num)
return -EINVAL;
return regmap_update_bits(data->regmap,
bmi160_regs[t].config,
bmi160_odr_table[t].tbl[i].bits,
bmi160_regs[t].config_odr_mask);
}
static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
int *odr, int *uodr)
{
int i, val, ret;
ret = regmap_read(data->regmap, bmi160_regs[t].config, &val);
if (ret < 0)
return ret;
val &= bmi160_regs[t].config_odr_mask;
for (i = 0; i < bmi160_odr_table[t].num; i++)
if (val == bmi160_odr_table[t].tbl[i].bits)
break;
if (i >= bmi160_odr_table[t].num)
return -EINVAL;
*odr = bmi160_odr_table[t].tbl[i].odr;
*uodr = bmi160_odr_table[t].tbl[i].uodr;
return 0;
}
static irqreturn_t bmi160_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmi160_data *data = iio_priv(indio_dev);
s16 buf[16]; /* 3 sens x 3 axis x s16 + 3 x s16 pad + 4 x s16 tstamp */
int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
__le16 sample;
for_each_set_bit(i, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16),
&sample, sizeof(__le16));
if (ret < 0)
goto done;
buf[j++] = sample;
}
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int bmi160_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct bmi160_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = bmi160_get_data(data, chan->type, chan->channel2, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
ret = bmi160_get_scale(data,
bmi160_to_sensor(chan->type), val2);
return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = bmi160_get_odr(data, bmi160_to_sensor(chan->type),
val, val2);
return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
return 0;
}
static int bmi160_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct bmi160_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return bmi160_set_scale(data,
bmi160_to_sensor(chan->type), val2);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
return bmi160_set_odr(data, bmi160_to_sensor(chan->type),
val, val2);
default:
return -EINVAL;
}
return 0;
}
static const struct iio_info bmi160_info = {
.driver_module = THIS_MODULE,
.read_raw = bmi160_read_raw,
.write_raw = bmi160_write_raw,
};
static const char *bmi160_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 bmi160_chip_init(struct bmi160_data *data, bool use_spi)
{
int ret;
unsigned int val;
struct device *dev = regmap_get_device(data->regmap);
ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET);
if (ret < 0)
return ret;
usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1);
/*
* CS rising edge is needed before starting SPI, so do a dummy read
* See Section 3.2.1, page 86 of the datasheet
*/
if (use_spi) {
ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val);
if (ret < 0)
return ret;
}
ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val);
if (ret < 0) {
dev_err(dev, "Error reading chip id\n");
return ret;
}
if (val != BMI160_CHIP_ID_VAL) {
dev_err(dev, "Wrong chip id, got %x expected %x\n",
val, BMI160_CHIP_ID_VAL);
return -ENODEV;
}
ret = bmi160_set_mode(data, BMI160_ACCEL, true);
if (ret < 0)
return ret;
ret = bmi160_set_mode(data, BMI160_GYRO, true);
if (ret < 0)
return ret;
return 0;
}
static void bmi160_chip_uninit(struct bmi160_data *data)
{
bmi160_set_mode(data, BMI160_GYRO, false);
bmi160_set_mode(data, BMI160_ACCEL, false);
}
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi)
{
struct iio_dev *indio_dev;
struct bmi160_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
ret = bmi160_chip_init(data, use_spi);
if (ret < 0)
return ret;
if (!name && ACPI_HANDLE(dev))
name = bmi160_match_acpi_device(dev);
indio_dev->dev.parent = dev;
indio_dev->channels = bmi160_channels;
indio_dev->num_channels = ARRAY_SIZE(bmi160_channels);
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmi160_info;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bmi160_trigger_handler, NULL);
if (ret < 0)
goto uninit;
ret = iio_device_register(indio_dev);
if (ret < 0)
goto buffer_cleanup;
return 0;
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
uninit:
bmi160_chip_uninit(data);
return ret;
}
EXPORT_SYMBOL_GPL(bmi160_core_probe);
void bmi160_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmi160_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
bmi160_chip_uninit(data);
}
EXPORT_SYMBOL_GPL(bmi160_core_remove);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
MODULE_DESCRIPTION("Bosch BMI160 driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,72 @@
/*
* BMI160 - Bosch IMU, I2C bits
*
* Copyright (c) 2016, 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.
*
* 7-bit I2C slave address is:
* - 0x68 if SDO is pulled to GND
* - 0x69 if SDO is pulled to VDDIO
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include "bmi160.h"
static int bmi160_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
regmap = devm_regmap_init_i2c(client, &bmi160_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
if (id)
name = id->name;
return bmi160_core_probe(&client->dev, regmap, name, false);
}
static int bmi160_i2c_remove(struct i2c_client *client)
{
bmi160_core_remove(&client->dev);
return 0;
}
static const struct i2c_device_id bmi160_i2c_id[] = {
{"bmi160", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, bmi160_i2c_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static struct i2c_driver bmi160_i2c_driver = {
.driver = {
.name = "bmi160_i2c",
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
},
.probe = bmi160_i2c_probe,
.remove = bmi160_i2c_remove,
.id_table = bmi160_i2c_id,
};
module_i2c_driver(bmi160_i2c_driver);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("BMI160 I2C driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,63 @@
/*
* BMI160 - Bosch IMU, SPI bits
*
* Copyright (c) 2016, 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.
*/
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include "bmi160.h"
static int bmi160_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &bmi160_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return bmi160_core_probe(&spi->dev, regmap, id->name, true);
}
static int bmi160_spi_remove(struct spi_device *spi)
{
bmi160_core_remove(&spi->dev);
return 0;
}
static const struct spi_device_id bmi160_spi_id[] = {
{"bmi160", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bmi160_spi_id);
static const struct acpi_device_id bmi160_acpi_match[] = {
{"BMI0160", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
static struct spi_driver bmi160_spi_driver = {
.probe = bmi160_spi_probe,
.remove = bmi160_spi_remove,
.id_table = bmi160_spi_id,
.driver = {
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
.name = "bmi160_spi",
},
};
module_spi_driver(bmi160_spi_driver);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
MODULE_DESCRIPTION("Bosch BMI160 SPI driver");
MODULE_LICENSE("GPL v2");

View File

@ -13,10 +13,8 @@ config INV_MPU6050_I2C
select INV_MPU6050_IIO
select REGMAP_I2C
help
This driver supports the Invensense MPU6050 devices.
This driver can also support MPU6500 in MPU6050 compatibility mode
and also in MPU6500 mode with some limitations.
It is a gyroscope/accelerometer combo device.
This driver supports the Invensense MPU6050/6500/9150 motion tracking
devices over I2C.
This driver can be built as a module. The module will be called
inv-mpu6050-i2c.
@ -26,7 +24,7 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6050 devices.
It is a gyroscope/accelerometer combo device.
This driver supports the Invensense MPU6000/6500/9150 motion tracking
devices over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.

View File

@ -87,16 +87,29 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
.accl_fs = INV_MPU6050_FS_02G,
};
/* Indexed by enum inv_devices */
static const struct inv_mpu6050_hw hw_info[] = {
{
.num_reg = 117,
.whoami = INV_MPU6050_WHOAMI_VALUE,
.name = "MPU6050",
.reg = &reg_set_6050,
.config = &chip_config_6050,
},
{
.whoami = INV_MPU6500_WHOAMI_VALUE,
.name = "MPU6500",
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
{
.num_reg = 117,
.name = "MPU6050",
.whoami = INV_MPU6000_WHOAMI_VALUE,
.name = "MPU6000",
.reg = &reg_set_6050,
.config = &chip_config_6050,
},
{
.whoami = INV_MPU9150_WHOAMI_VALUE,
.name = "MPU9150",
.reg = &reg_set_6050,
.config = &chip_config_6050,
},
@ -599,6 +612,10 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
/**
* inv_attr_show() - calling this function will show current
* parameters.
*
* Deprecated in favor of IIO mounting matrix API.
*
* See inv_get_mount_matrix()
*/
static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
char *buf)
@ -643,6 +660,18 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
return 0;
}
static const struct iio_mount_matrix *
inv_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation;
}
static const struct iio_chan_spec_ext_info inv_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix),
{ },
};
#define INV_MPU6050_CHAN(_type, _channel2, _index) \
{ \
.type = _type, \
@ -659,6 +688,7 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
.shift = 0, \
.endianness = IIO_BE, \
}, \
.ext_info = inv_ext_info, \
}
static const struct iio_chan_spec inv_mpu_channels[] = {
@ -691,14 +721,16 @@ static IIO_CONST_ATTR(in_accel_scale_available,
"0.000598 0.001196 0.002392 0.004785");
static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
inv_mpu6050_fifo_rate_store);
/* Deprecated: kept for userspace backward compatibility. */
static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
ATTR_GYRO_MATRIX);
static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL,
ATTR_ACCL_MATRIX);
static struct attribute *inv_attributes[] = {
&iio_dev_attr_in_gyro_matrix.dev_attr.attr,
&iio_dev_attr_in_accel_matrix.dev_attr.attr,
&iio_dev_attr_in_gyro_matrix.dev_attr.attr, /* deprecated */
&iio_dev_attr_in_accel_matrix.dev_attr.attr, /* deprecated */
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
@ -725,6 +757,7 @@ static const struct iio_info mpu_info = {
static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
{
int result;
unsigned int regval;
st->hw = &hw_info[st->chip_type];
st->reg = hw_info[st->chip_type].reg;
@ -735,6 +768,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
if (result)
return result;
msleep(INV_MPU6050_POWER_UP_TIME);
/* check chip self-identification */
result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
if (result)
return result;
if (regval != st->hw->whoami) {
dev_warn(regmap_get_device(st->map),
"whoami mismatch got %#02x expected %#02hhx for %s\n",
regval, st->hw->whoami, st->hw->name);
}
/*
* toggle power state. After reset, the sleep bit could be on
* or off depending on the OTP settings. Toggling power would
@ -773,14 +817,31 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
if (!indio_dev)
return -ENOMEM;
BUILD_BUG_ON(ARRAY_SIZE(hw_info) != INV_NUM_PARTS);
if (chip_type < 0 || chip_type >= INV_NUM_PARTS) {
dev_err(dev, "Bad invensense chip_type=%d name=%s\n",
chip_type, name);
return -ENODEV;
}
st = iio_priv(indio_dev);
st->chip_type = chip_type;
st->powerup_count = 0;
st->irq = irq;
st->map = regmap;
pdata = dev_get_platdata(dev);
if (pdata)
if (!pdata) {
result = of_iio_read_mount_matrix(dev, "mount-matrix",
&st->orientation);
if (result) {
dev_err(dev, "Failed to retrieve mounting matrix %d\n",
result);
return result;
}
} else {
st->plat_data = *pdata;
}
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)

View File

@ -169,13 +169,14 @@ static int inv_mpu_remove(struct i2c_client *client)
static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{}
};
MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6500", 0},
{"INVN6500", INV_MPU6500},
{ },
};

View File

@ -69,6 +69,7 @@ enum inv_devices {
INV_MPU6050,
INV_MPU6500,
INV_MPU6000,
INV_MPU9150,
INV_NUM_PARTS
};
@ -94,13 +95,13 @@ struct inv_mpu6050_chip_config {
/**
* struct inv_mpu6050_hw - Other important hardware information.
* @num_reg: Number of registers on device.
* @whoami: Self identification byte from WHO_AM_I register
* @name: name of the chip.
* @reg: register map of the chip.
* @config: configuration of the chip.
*/
struct inv_mpu6050_hw {
u8 num_reg;
u8 whoami;
u8 *name;
const struct inv_mpu6050_reg_map *reg;
const struct inv_mpu6050_chip_config *config;
@ -115,7 +116,8 @@ struct inv_mpu6050_hw {
* @hw: Other hardware-specific information.
* @chip_type: chip type.
* @time_stamp_lock: spin lock to time stamp.
* @plat_data: platform data.
* @plat_data: platform data (deprecated in favor of @orientation).
* @orientation: sensor chip orientation relative to main hardware.
* @timestamps: kfifo queue to store time stamp.
* @map regmap pointer.
* @irq interrupt number.
@ -132,6 +134,7 @@ struct inv_mpu6050_state {
struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
struct iio_mount_matrix orientation;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
struct regmap *map;
int irq;
@ -216,6 +219,13 @@ struct inv_mpu6050_state {
#define INV_MPU6050_MIN_FIFO_RATE 4
#define INV_MPU6050_ONE_K_HZ 1000
#define INV_MPU6050_REG_WHOAMI 117
#define INV_MPU6000_WHOAMI_VALUE 0x68
#define INV_MPU6050_WHOAMI_VALUE 0x68
#define INV_MPU6500_WHOAMI_VALUE 0x70
#define INV_MPU9150_WHOAMI_VALUE 0x68
/* scan element definition */
enum inv_mpu6050_scan {
INV_MPU6050_SCAN_ACCL_X,

View File

@ -44,9 +44,19 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
static int inv_mpu_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
const char *name = id ? id->name : NULL;
const int chip_type = id ? id->driver_data : 0;
const struct spi_device_id *spi_id;
const struct acpi_device_id *acpi_id;
const char *name = NULL;
enum inv_devices chip_type;
if ((spi_id = spi_get_device_id(spi))) {
chip_type = (enum inv_devices)spi_id->driver_data;
name = spi_id->name;
} else if ((acpi_id = acpi_match_device(spi->dev.driver->acpi_match_table, &spi->dev))) {
chip_type = (enum inv_devices)acpi_id->driver_data;
} else {
return -ENODEV;
}
regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config);
if (IS_ERR(regmap)) {
@ -70,13 +80,15 @@ static int inv_mpu_remove(struct spi_device *spi)
*/
static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{}
};
MODULE_DEVICE_TABLE(spi, inv_mpu_id);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6000", 0},
{"INVN6000", INV_MPU6000},
{ },
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);

View File

@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>

View File

@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
@ -78,6 +79,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CONCENTRATION] = "concentration",
[IIO_RESISTANCE] = "resistance",
[IIO_PH] = "ph",
[IIO_UVINDEX] = "uvindex",
};
static const char * const iio_modifier_names[] = {
@ -100,6 +102,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_LIGHT_RED] = "red",
[IIO_MOD_LIGHT_GREEN] = "green",
[IIO_MOD_LIGHT_BLUE] = "blue",
[IIO_MOD_LIGHT_UV] = "uv",
[IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient",
[IIO_MOD_TEMP_OBJECT] = "object",
@ -409,6 +412,88 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL_GPL(iio_enum_write);
static const struct iio_mount_matrix iio_mount_idmatrix = {
.rotation = {
"1", "0", "0",
"0", "1", "0",
"0", "0", "1"
}
};
static int iio_setup_mount_idmatrix(const struct device *dev,
struct iio_mount_matrix *matrix)
{
*matrix = iio_mount_idmatrix;
dev_info(dev, "mounting matrix not found: using identity...\n");
return 0;
}
ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
const struct iio_chan_spec *chan, char *buf)
{
const struct iio_mount_matrix *mtx = ((iio_get_mount_matrix_t *)
priv)(indio_dev, chan);
if (IS_ERR(mtx))
return PTR_ERR(mtx);
if (!mtx)
mtx = &iio_mount_idmatrix;
return snprintf(buf, PAGE_SIZE, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n",
mtx->rotation[0], mtx->rotation[1], mtx->rotation[2],
mtx->rotation[3], mtx->rotation[4], mtx->rotation[5],
mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]);
}
EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
/**
* of_iio_read_mount_matrix() - retrieve iio device mounting matrix from
* device-tree "mount-matrix" property
* @dev: device the mounting matrix property is assigned to
* @propname: device specific mounting matrix property name
* @matrix: where to store retrieved matrix
*
* If device is assigned no mounting matrix property, a default 3x3 identity
* matrix will be filled in.
*
* Return: 0 if success, or a negative error code on failure.
*/
#ifdef CONFIG_OF
int of_iio_read_mount_matrix(const struct device *dev,
const char *propname,
struct iio_mount_matrix *matrix)
{
if (dev->of_node) {
int err = of_property_read_string_array(dev->of_node,
propname, matrix->rotation,
ARRAY_SIZE(iio_mount_idmatrix.rotation));
if (err == ARRAY_SIZE(iio_mount_idmatrix.rotation))
return 0;
if (err >= 0)
/* Invalid number of matrix entries. */
return -EINVAL;
if (err != -EINVAL)
/* Invalid matrix declaration format. */
return err;
}
/* Matrix was not declared at all: fallback to identity. */
return iio_setup_mount_idmatrix(dev, matrix);
}
#else
int of_iio_read_mount_matrix(const struct device *dev,
const char *propname,
struct iio_mount_matrix *matrix)
{
return iio_setup_mount_idmatrix(dev, matrix);
}
#endif
EXPORT_SYMBOL(of_iio_read_mount_matrix);
/**
* iio_format_value() - Formats a IIO value into its string representation
* @buf: The buffer to which the formatted value gets written
@ -1375,6 +1460,44 @@ void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev)
}
EXPORT_SYMBOL_GPL(devm_iio_device_unregister);
/**
* iio_device_claim_direct_mode - Keep device in direct mode
* @indio_dev: the iio_dev associated with the device
*
* If the device is in direct mode it is guaranteed to stay
* that way until iio_device_release_direct_mode() is called.
*
* Use with iio_device_release_direct_mode()
*
* Returns: 0 on success, -EBUSY on failure
*/
int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
{
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
return 0;
}
EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
/**
* iio_device_release_direct_mode - releases claim on direct mode
* @indio_dev: the iio_dev associated with the device
*
* Release the claim. Device is no longer guaranteed to stay
* in direct mode.
*
* Use with iio_device_claim_direct_mode()
*/
void iio_device_release_direct_mode(struct iio_dev *indio_dev)
{
mutex_unlock(&indio_dev->mlock);
}
EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
subsys_initcall(iio_init);
module_exit(iio_exit);

View File

@ -356,6 +356,54 @@ void iio_channel_release(struct iio_channel *channel)
}
EXPORT_SYMBOL_GPL(iio_channel_release);
static void devm_iio_channel_free(struct device *dev, void *res)
{
struct iio_channel *channel = *(struct iio_channel **)res;
iio_channel_release(channel);
}
static int devm_iio_channel_match(struct device *dev, void *res, void *data)
{
struct iio_channel **r = res;
if (!r || !*r) {
WARN_ON(!r || !*r);
return 0;
}
return *r == data;
}
struct iio_channel *devm_iio_channel_get(struct device *dev,
const char *channel_name)
{
struct iio_channel **ptr, *channel;
ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
channel = iio_channel_get(dev, channel_name);
if (IS_ERR(channel)) {
devres_free(ptr);
return channel;
}
*ptr = channel;
devres_add(dev, ptr);
return channel;
}
EXPORT_SYMBOL_GPL(devm_iio_channel_get);
void devm_iio_channel_release(struct device *dev, struct iio_channel *channel)
{
WARN_ON(devres_release(dev, devm_iio_channel_free,
devm_iio_channel_match, channel));
}
EXPORT_SYMBOL_GPL(devm_iio_channel_release);
struct iio_channel *iio_channel_get_all(struct device *dev)
{
const char *name;
@ -441,6 +489,42 @@ void iio_channel_release_all(struct iio_channel *channels)
}
EXPORT_SYMBOL_GPL(iio_channel_release_all);
static void devm_iio_channel_free_all(struct device *dev, void *res)
{
struct iio_channel *channels = *(struct iio_channel **)res;
iio_channel_release_all(channels);
}
struct iio_channel *devm_iio_channel_get_all(struct device *dev)
{
struct iio_channel **ptr, *channels;
ptr = devres_alloc(devm_iio_channel_free_all, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
channels = iio_channel_get_all(dev);
if (IS_ERR(channels)) {
devres_free(ptr);
return channels;
}
*ptr = channels;
devres_add(dev, ptr);
return channels;
}
EXPORT_SYMBOL_GPL(devm_iio_channel_get_all);
void devm_iio_channel_release_all(struct device *dev,
struct iio_channel *channels)
{
WARN_ON(devres_release(dev, devm_iio_channel_free_all,
devm_iio_channel_match, channels));
}
EXPORT_SYMBOL_GPL(devm_iio_channel_release_all);
static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
enum iio_chan_info_enum info)
{
@ -452,7 +536,7 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
if (val2 == NULL)
val2 = &unused;
if(!iio_channel_has_info(chan->channel, info))
if (!iio_channel_has_info(chan->channel, info))
return -EINVAL;
if (chan->indio_dev->info->read_raw_multi) {

View File

@ -73,6 +73,17 @@ config BH1750
To compile this driver as a module, choose M here: the module will
be called bh1750.
config BH1780
tristate "ROHM BH1780 ambient light sensor"
depends on I2C
depends on !SENSORS_BH1780
help
Say Y here to build support for the ROHM BH1780GLI ambient
light sensor.
To compile this driver as a module, choose M here: the module will
be called bh1780.
config CM32181
depends on I2C
tristate "CM32181 driver"
@ -223,6 +234,17 @@ config LTR501
This driver can also be built as a module. If so, the module
will be called ltr501.
config MAX44000
tristate "MAX44000 Ambient and Infrared Proximity Sensor"
depends on I2C
select REGMAP_I2C
help
Say Y here if you want to build support for Maxim Integrated's
MAX44000 ambient and infrared proximity sensor device.
To compile this driver as a module, choose M here:
the module will be called max44000.
config OPT3001
tristate "Texas Instruments OPT3001 Light Sensor"
depends on I2C
@ -320,4 +342,14 @@ config VCNL4000
To compile this driver as a module, choose M here: the
module will be called vcnl4000.
config VEML6070
tristate "VEML6070 UV A light sensor"
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VEML6070 UV A
light sensor.
To compile this driver as a module, choose M here: the
module will be called veml6070.
endmenu

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_BH1780) += bh1780.o
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
obj-$(CONFIG_CM3323) += cm3323.o
@ -20,6 +21,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_MAX44000) += max44000.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
@ -30,3 +32,4 @@ obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VEML6070) += veml6070.o

View File

@ -321,8 +321,12 @@ static const struct iio_chan_spec apds9960_channels[] = {
};
/* integration time in us */
static const int apds9960_int_time[][2] =
{ {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} };
static const int apds9960_int_time[][2] = {
{ 28000, 246},
{100000, 219},
{200000, 182},
{700000, 0}
};
/* gain mapping */
static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};
@ -491,9 +495,10 @@ static int apds9960_read_raw(struct iio_dev *indio_dev,
case IIO_INTENSITY:
ret = regmap_bulk_read(data->regmap, chan->address,
&buf, 2);
if (!ret)
if (!ret) {
ret = IIO_VAL_INT;
*val = le16_to_cpu(buf);
*val = le16_to_cpu(buf);
}
break;
default:
ret = -EINVAL;

297
drivers/iio/light/bh1780.c Normal file
View File

@ -0,0 +1,297 @@
/*
* ROHM 1780GLI Ambient Light Sensor Driver
*
* Copyright (C) 2016 Linaro Ltd.
* Author: Linus Walleij <linus.walleij@linaro.org>
* Loosely based on the previous BH1780 ALS misc driver
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*/
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/bitops.h>
#define BH1780_CMD_BIT BIT(7)
#define BH1780_REG_CONTROL 0x00
#define BH1780_REG_PARTID 0x0A
#define BH1780_REG_MANFID 0x0B
#define BH1780_REG_DLOW 0x0C
#define BH1780_REG_DHIGH 0x0D
#define BH1780_REVMASK GENMASK(3,0)
#define BH1780_POWMASK GENMASK(1,0)
#define BH1780_POFF (0x0)
#define BH1780_PON (0x3)
/* power on settling time in ms */
#define BH1780_PON_DELAY 2
/* max time before value available in ms */
#define BH1780_INTERVAL 250
struct bh1780_data {
struct i2c_client *client;
};
static int bh1780_write(struct bh1780_data *bh1780, u8 reg, u8 val)
{
int ret = i2c_smbus_write_byte_data(bh1780->client,
BH1780_CMD_BIT | reg,
val);
if (ret < 0)
dev_err(&bh1780->client->dev,
"i2c_smbus_write_byte_data failed error "
"%d, register %01x\n",
ret, reg);
return ret;
}
static int bh1780_read(struct bh1780_data *bh1780, u8 reg)
{
int ret = i2c_smbus_read_byte_data(bh1780->client,
BH1780_CMD_BIT | reg);
if (ret < 0)
dev_err(&bh1780->client->dev,
"i2c_smbus_read_byte_data failed error "
"%d, register %01x\n",
ret, reg);
return ret;
}
static int bh1780_read_word(struct bh1780_data *bh1780, u8 reg)
{
int ret = i2c_smbus_read_word_data(bh1780->client,
BH1780_CMD_BIT | reg);
if (ret < 0)
dev_err(&bh1780->client->dev,
"i2c_smbus_read_word_data failed error "
"%d, register %01x\n",
ret, reg);
return ret;
}
static int bh1780_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval,
unsigned int *readval)
{
struct bh1780_data *bh1780 = iio_priv(indio_dev);
int ret;
if (!readval)
bh1780_write(bh1780, (u8)reg, (u8)writeval);
ret = bh1780_read(bh1780, (u8)reg);
if (ret < 0)
return ret;
*readval = ret;
return 0;
}
static int bh1780_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct bh1780_data *bh1780 = iio_priv(indio_dev);
int value;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
pm_runtime_get_sync(&bh1780->client->dev);
value = bh1780_read_word(bh1780, BH1780_REG_DLOW);
if (value < 0)
return value;
pm_runtime_mark_last_busy(&bh1780->client->dev);
pm_runtime_put_autosuspend(&bh1780->client->dev);
*val = value;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
*val2 = BH1780_INTERVAL * 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static const struct iio_info bh1780_info = {
.driver_module = THIS_MODULE,
.read_raw = bh1780_read_raw,
.debugfs_reg_access = bh1780_debugfs_reg_access,
};
static const struct iio_chan_spec bh1780_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_INT_TIME)
}
};
static int bh1780_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct bh1780_data *bh1780;
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct iio_dev *indio_dev;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
return -EIO;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*bh1780));
if (!indio_dev)
return -ENOMEM;
bh1780 = iio_priv(indio_dev);
bh1780->client = client;
i2c_set_clientdata(client, indio_dev);
/* Power up the device */
ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
if (ret < 0)
return ret;
msleep(BH1780_PON_DELAY);
pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
ret = bh1780_read(bh1780, BH1780_REG_PARTID);
if (ret < 0)
goto out_disable_pm;
dev_info(&client->dev,
"Ambient Light Sensor, Rev : %lu\n",
(ret & BH1780_REVMASK));
/*
* As the device takes 250 ms to even come up with a fresh
* measurement after power-on, do not shut it down unnecessarily.
* Set autosuspend to a five seconds.
*/
pm_runtime_set_autosuspend_delay(&client->dev, 5000);
pm_runtime_use_autosuspend(&client->dev);
pm_runtime_put(&client->dev);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &bh1780_info;
indio_dev->name = id->name;
indio_dev->channels = bh1780_channels;
indio_dev->num_channels = ARRAY_SIZE(bh1780_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_device_register(indio_dev);
if (ret)
goto out_disable_pm;
return 0;
out_disable_pm:
pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev);
return ret;
}
static int bh1780_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct bh1780_data *bh1780 = iio_priv(indio_dev);
int ret;
iio_device_unregister(indio_dev);
pm_runtime_get_sync(&client->dev);
pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev);
ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
if (ret < 0) {
dev_err(&client->dev, "failed to power off\n");
return ret;
}
return 0;
}
#ifdef CONFIG_PM
static int bh1780_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bh1780_data *bh1780 = i2c_get_clientdata(client);
int ret;
ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_POFF);
if (ret < 0) {
dev_err(dev, "failed to runtime suspend\n");
return ret;
}
return 0;
}
static int bh1780_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bh1780_data *bh1780 = i2c_get_clientdata(client);
int ret;
ret = bh1780_write(bh1780, BH1780_REG_CONTROL, BH1780_PON);
if (ret < 0) {
dev_err(dev, "failed to runtime resume\n");
return ret;
}
/* Wait for power on, then for a value to be available */
msleep(BH1780_PON_DELAY + BH1780_INTERVAL);
return 0;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops bh1780_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(bh1780_runtime_suspend,
bh1780_runtime_resume, NULL)
};
static const struct i2c_device_id bh1780_id[] = {
{ "bh1780", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, bh1780_id);
#ifdef CONFIG_OF
static const struct of_device_id of_bh1780_match[] = {
{ .compatible = "rohm,bh1780gli", },
{},
};
MODULE_DEVICE_TABLE(of, of_bh1780_match);
#endif
static struct i2c_driver bh1780_driver = {
.probe = bh1780_probe,
.remove = bh1780_remove,
.id_table = bh1780_id,
.driver = {
.name = "bh1780",
.pm = &bh1780_dev_pm_ops,
.of_match_table = of_match_ptr(of_bh1780_match),
},
};
module_i2c_driver(bh1780_driver);
MODULE_DESCRIPTION("ROHM BH1780GLI Ambient Light Sensor Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");

View File

@ -0,0 +1,639 @@
/*
* MAX44000 Ambient and Infrared Proximity Sensor
*
* Copyright (c) 2016, 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.
*
* Data sheet: https://datasheets.maximintegrated.com/en/ds/MAX44000.pdf
*
* 7-bit I2C slave address 0x4a
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/util_macros.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/acpi.h>
#define MAX44000_DRV_NAME "max44000"
/* Registers in datasheet order */
#define MAX44000_REG_STATUS 0x00
#define MAX44000_REG_CFG_MAIN 0x01
#define MAX44000_REG_CFG_RX 0x02
#define MAX44000_REG_CFG_TX 0x03
#define MAX44000_REG_ALS_DATA_HI 0x04
#define MAX44000_REG_ALS_DATA_LO 0x05
#define MAX44000_REG_PRX_DATA 0x16
#define MAX44000_REG_ALS_UPTHR_HI 0x06
#define MAX44000_REG_ALS_UPTHR_LO 0x07
#define MAX44000_REG_ALS_LOTHR_HI 0x08
#define MAX44000_REG_ALS_LOTHR_LO 0x09
#define MAX44000_REG_PST 0x0a
#define MAX44000_REG_PRX_IND 0x0b
#define MAX44000_REG_PRX_THR 0x0c
#define MAX44000_REG_TRIM_GAIN_GREEN 0x0f
#define MAX44000_REG_TRIM_GAIN_IR 0x10
/* REG_CFG bits */
#define MAX44000_CFG_ALSINTE 0x01
#define MAX44000_CFG_PRXINTE 0x02
#define MAX44000_CFG_MASK 0x1c
#define MAX44000_CFG_MODE_SHUTDOWN 0x00
#define MAX44000_CFG_MODE_ALS_GIR 0x04
#define MAX44000_CFG_MODE_ALS_G 0x08
#define MAX44000_CFG_MODE_ALS_IR 0x0c
#define MAX44000_CFG_MODE_ALS_PRX 0x10
#define MAX44000_CFG_MODE_PRX 0x14
#define MAX44000_CFG_TRIM 0x20
/*
* Upper 4 bits are not documented but start as 1 on powerup
* Setting them to 0 causes proximity to misbehave so set them to 1
*/
#define MAX44000_REG_CFG_RX_DEFAULT 0xf0
/* REG_RX bits */
#define MAX44000_CFG_RX_ALSTIM_MASK 0x0c
#define MAX44000_CFG_RX_ALSTIM_SHIFT 2
#define MAX44000_CFG_RX_ALSPGA_MASK 0x03
#define MAX44000_CFG_RX_ALSPGA_SHIFT 0
/* REG_TX bits */
#define MAX44000_LED_CURRENT_MASK 0xf
#define MAX44000_LED_CURRENT_MAX 11
#define MAX44000_LED_CURRENT_DEFAULT 6
#define MAX44000_ALSDATA_OVERFLOW 0x4000
struct max44000_data {
struct mutex lock;
struct regmap *regmap;
};
/* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */
#define MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2 5
/* Scale can be multiplied by up to 128x via ALSPGA for measurement gain */
static const int max44000_alspga_shift[] = {0, 2, 4, 7};
#define MAX44000_ALSPGA_MAX_SHIFT 7
/*
* Scale can be multiplied by up to 64x via ALSTIM because of lost resolution
*
* This scaling factor is hidden from userspace and instead accounted for when
* reading raw values from the device.
*
* This makes it possible to cleanly expose ALSPGA as IIO_CHAN_INFO_SCALE and
* ALSTIM as IIO_CHAN_INFO_INT_TIME without the values affecting each other.
*
* Handling this internally is also required for buffer support because the
* channel's scan_type can't be modified dynamically.
*/
static const int max44000_alstim_shift[] = {0, 2, 4, 6};
#define MAX44000_ALSTIM_SHIFT(alstim) (2 * (alstim))
/* Available integration times with pretty manual alignment: */
static const int max44000_int_time_avail_ns_array[] = {
100000000,
25000000,
6250000,
1562500,
};
static const char max44000_int_time_avail_str[] =
"0.100 "
"0.025 "
"0.00625 "
"0.001625";
/* Available scales (internal to ulux) with pretty manual alignment: */
static const int max44000_scale_avail_ulux_array[] = {
31250,
125000,
500000,
4000000,
};
static const char max44000_scale_avail_str[] =
"0.03125 "
"0.125 "
"0.5 "
"4";
#define MAX44000_SCAN_INDEX_ALS 0
#define MAX44000_SCAN_INDEX_PRX 1
static const struct iio_chan_spec max44000_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME),
.scan_index = MAX44000_SCAN_INDEX_ALS,
.scan_type = {
.sign = 'u',
.realbits = 14,
.storagebits = 16,
}
},
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_index = MAX44000_SCAN_INDEX_PRX,
.scan_type = {
.sign = 'u',
.realbits = 8,
.storagebits = 16,
}
},
IIO_CHAN_SOFT_TIMESTAMP(2),
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.extend_name = "led",
.output = 1,
.scan_index = -1,
},
};
static int max44000_read_alstim(struct max44000_data *data)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, MAX44000_REG_CFG_RX, &val);
if (ret < 0)
return ret;
return (val & MAX44000_CFG_RX_ALSTIM_MASK) >> MAX44000_CFG_RX_ALSTIM_SHIFT;
}
static int max44000_write_alstim(struct max44000_data *data, int val)
{
return regmap_write_bits(data->regmap, MAX44000_REG_CFG_RX,
MAX44000_CFG_RX_ALSTIM_MASK,
val << MAX44000_CFG_RX_ALSTIM_SHIFT);
}
static int max44000_read_alspga(struct max44000_data *data)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, MAX44000_REG_CFG_RX, &val);
if (ret < 0)
return ret;
return (val & MAX44000_CFG_RX_ALSPGA_MASK) >> MAX44000_CFG_RX_ALSPGA_SHIFT;
}
static int max44000_write_alspga(struct max44000_data *data, int val)
{
return regmap_write_bits(data->regmap, MAX44000_REG_CFG_RX,
MAX44000_CFG_RX_ALSPGA_MASK,
val << MAX44000_CFG_RX_ALSPGA_SHIFT);
}
static int max44000_read_alsval(struct max44000_data *data)
{
u16 regval;
int alstim, ret;
ret = regmap_bulk_read(data->regmap, MAX44000_REG_ALS_DATA_HI,
&regval, sizeof(regval));
if (ret < 0)
return ret;
alstim = ret = max44000_read_alstim(data);
if (ret < 0)
return ret;
regval = be16_to_cpu(regval);
/*
* Overflow is explained on datasheet page 17.
*
* It's a warning that either the G or IR channel has become saturated
* and that the value in the register is likely incorrect.
*
* The recommendation is to change the scale (ALSPGA).
* The driver just returns the max representable value.
*/
if (regval & MAX44000_ALSDATA_OVERFLOW)
return 0x3FFF;
return regval << MAX44000_ALSTIM_SHIFT(alstim);
}
static int max44000_write_led_current_raw(struct max44000_data *data, int val)
{
/* Maybe we should clamp the value instead? */
if (val < 0 || val > MAX44000_LED_CURRENT_MAX)
return -ERANGE;
if (val >= 8)
val += 4;
return regmap_write_bits(data->regmap, MAX44000_REG_CFG_TX,
MAX44000_LED_CURRENT_MASK, val);
}
static int max44000_read_led_current_raw(struct max44000_data *data)
{
unsigned int regval;
int ret;
ret = regmap_read(data->regmap, MAX44000_REG_CFG_TX, &regval);
if (ret < 0)
return ret;
regval &= MAX44000_LED_CURRENT_MASK;
if (regval >= 8)
regval -= 4;
return regval;
}
static int max44000_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct max44000_data *data = iio_priv(indio_dev);
int alstim, alspga;
unsigned int regval;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
mutex_lock(&data->lock);
ret = max44000_read_alsval(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_PROXIMITY:
mutex_lock(&data->lock);
ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = regval;
return IIO_VAL_INT;
case IIO_CURRENT:
mutex_lock(&data->lock);
ret = max44000_read_led_current_raw(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_CURRENT:
/* Output register is in 10s of miliamps */
*val = 10;
return IIO_VAL_INT;
case IIO_LIGHT:
mutex_lock(&data->lock);
alspga = ret = max44000_read_alspga(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
/* Avoid negative shifts */
*val = (1 << MAX44000_ALSPGA_MAX_SHIFT);
*val2 = MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2
+ MAX44000_ALSPGA_MAX_SHIFT
- max44000_alspga_shift[alspga];
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_INT_TIME:
mutex_lock(&data->lock);
alstim = ret = max44000_read_alstim(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = 0;
*val2 = max44000_int_time_avail_ns_array[alstim];
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
}
static int max44000_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct max44000_data *data = iio_priv(indio_dev);
int ret;
if (mask == IIO_CHAN_INFO_RAW && chan->type == IIO_CURRENT) {
mutex_lock(&data->lock);
ret = max44000_write_led_current_raw(data, val);
mutex_unlock(&data->lock);
return ret;
} else if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT) {
s64 valns = val * NSEC_PER_SEC + val2;
int alstim = find_closest_descending(valns,
max44000_int_time_avail_ns_array,
ARRAY_SIZE(max44000_int_time_avail_ns_array));
mutex_lock(&data->lock);
ret = max44000_write_alstim(data, alstim);
mutex_unlock(&data->lock);
return ret;
} else if (mask == IIO_CHAN_INFO_SCALE && chan->type == IIO_LIGHT) {
s64 valus = val * USEC_PER_SEC + val2;
int alspga = find_closest(valus,
max44000_scale_avail_ulux_array,
ARRAY_SIZE(max44000_scale_avail_ulux_array));
mutex_lock(&data->lock);
ret = max44000_write_alspga(data, alspga);
mutex_unlock(&data->lock);
return ret;
}
return -EINVAL;
}
static int max44000_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT)
return IIO_VAL_INT_PLUS_NANO;
else if (mask == IIO_CHAN_INFO_SCALE && chan->type == IIO_LIGHT)
return IIO_VAL_INT_PLUS_MICRO;
else
return IIO_VAL_INT;
}
static IIO_CONST_ATTR(illuminance_integration_time_available, max44000_int_time_avail_str);
static IIO_CONST_ATTR(illuminance_scale_available, max44000_scale_avail_str);
static struct attribute *max44000_attributes[] = {
&iio_const_attr_illuminance_integration_time_available.dev_attr.attr,
&iio_const_attr_illuminance_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group max44000_attribute_group = {
.attrs = max44000_attributes,
};
static const struct iio_info max44000_info = {
.driver_module = THIS_MODULE,
.read_raw = max44000_read_raw,
.write_raw = max44000_write_raw,
.write_raw_get_fmt = max44000_write_raw_get_fmt,
.attrs = &max44000_attribute_group,
};
static bool max44000_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX44000_REG_STATUS:
case MAX44000_REG_CFG_MAIN:
case MAX44000_REG_CFG_RX:
case MAX44000_REG_CFG_TX:
case MAX44000_REG_ALS_DATA_HI:
case MAX44000_REG_ALS_DATA_LO:
case MAX44000_REG_PRX_DATA:
case MAX44000_REG_ALS_UPTHR_HI:
case MAX44000_REG_ALS_UPTHR_LO:
case MAX44000_REG_ALS_LOTHR_HI:
case MAX44000_REG_ALS_LOTHR_LO:
case MAX44000_REG_PST:
case MAX44000_REG_PRX_IND:
case MAX44000_REG_PRX_THR:
case MAX44000_REG_TRIM_GAIN_GREEN:
case MAX44000_REG_TRIM_GAIN_IR:
return true;
default:
return false;
}
}
static bool max44000_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX44000_REG_CFG_MAIN:
case MAX44000_REG_CFG_RX:
case MAX44000_REG_CFG_TX:
case MAX44000_REG_ALS_UPTHR_HI:
case MAX44000_REG_ALS_UPTHR_LO:
case MAX44000_REG_ALS_LOTHR_HI:
case MAX44000_REG_ALS_LOTHR_LO:
case MAX44000_REG_PST:
case MAX44000_REG_PRX_IND:
case MAX44000_REG_PRX_THR:
case MAX44000_REG_TRIM_GAIN_GREEN:
case MAX44000_REG_TRIM_GAIN_IR:
return true;
default:
return false;
}
}
static bool max44000_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX44000_REG_STATUS:
case MAX44000_REG_ALS_DATA_HI:
case MAX44000_REG_ALS_DATA_LO:
case MAX44000_REG_PRX_DATA:
return true;
default:
return false;
}
}
static bool max44000_precious_reg(struct device *dev, unsigned int reg)
{
return reg == MAX44000_REG_STATUS;
}
static const struct regmap_config max44000_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX44000_REG_PRX_DATA,
.readable_reg = max44000_readable_reg,
.writeable_reg = max44000_writeable_reg,
.volatile_reg = max44000_volatile_reg,
.precious_reg = max44000_precious_reg,
.use_single_rw = 1,
.cache_type = REGCACHE_RBTREE,
};
static irqreturn_t max44000_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct max44000_data *data = iio_priv(indio_dev);
u16 buf[8]; /* 2x u16 + padding + 8 bytes timestamp */
int index = 0;
unsigned int regval;
int ret;
mutex_lock(&data->lock);
if (test_bit(MAX44000_SCAN_INDEX_ALS, indio_dev->active_scan_mask)) {
ret = max44000_read_alsval(data);
if (ret < 0)
goto out_unlock;
buf[index++] = ret;
}
if (test_bit(MAX44000_SCAN_INDEX_PRX, indio_dev->active_scan_mask)) {
ret = regmap_read(data->regmap, MAX44000_REG_PRX_DATA, &regval);
if (ret < 0)
goto out_unlock;
buf[index] = regval;
}
mutex_unlock(&data->lock);
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
out_unlock:
mutex_unlock(&data->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int max44000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max44000_data *data;
struct iio_dev *indio_dev;
int ret, reg;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = devm_regmap_init_i2c(client, &max44000_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(&client->dev, "regmap_init failed!\n");
return PTR_ERR(data->regmap);
}
i2c_set_clientdata(client, indio_dev);
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &max44000_info;
indio_dev->name = MAX44000_DRV_NAME;
indio_dev->channels = max44000_channels;
indio_dev->num_channels = ARRAY_SIZE(max44000_channels);
/*
* The device doesn't have a reset function so we just clear some
* important bits at probe time to ensure sane operation.
*
* Since we don't support interrupts/events the threshold values are
* not important. We also don't touch trim values.
*/
/* Reset ALS scaling bits */
ret = regmap_write(data->regmap, MAX44000_REG_CFG_RX,
MAX44000_REG_CFG_RX_DEFAULT);
if (ret < 0) {
dev_err(&client->dev, "failed to write default CFG_RX: %d\n",
ret);
return ret;
}
/*
* By default the LED pulse used for the proximity sensor is disabled.
* Set a middle value so that we get some sort of valid data by default.
*/
ret = max44000_write_led_current_raw(data, MAX44000_LED_CURRENT_DEFAULT);
if (ret < 0) {
dev_err(&client->dev, "failed to write init config: %d\n", ret);
return ret;
}
/* Reset CFG bits to ALS_PRX mode which allows easy reading of both values. */
reg = MAX44000_CFG_TRIM | MAX44000_CFG_MODE_ALS_PRX;
ret = regmap_write(data->regmap, MAX44000_REG_CFG_MAIN, reg);
if (ret < 0) {
dev_err(&client->dev, "failed to write init config: %d\n", ret);
return ret;
}
/* Read status at least once to clear any stale interrupt bits. */
ret = regmap_read(data->regmap, MAX44000_REG_STATUS, &reg);
if (ret < 0) {
dev_err(&client->dev, "failed to read init status: %d\n", ret);
return ret;
}
ret = iio_triggered_buffer_setup(indio_dev, NULL, max44000_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
return ret;
}
return iio_device_register(indio_dev);
}
static int max44000_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static const struct i2c_device_id max44000_id[] = {
{"max44000", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, max44000_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id max44000_acpi_match[] = {
{"MAX44000", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, max44000_acpi_match);
#endif
static struct i2c_driver max44000_driver = {
.driver = {
.name = MAX44000_DRV_NAME,
.acpi_match_table = ACPI_PTR(max44000_acpi_match),
},
.probe = max44000_probe,
.remove = max44000_remove,
.id_table = max44000_id,
};
module_i2c_driver(max44000_driver);
MODULE_AUTHOR("Crestez Dan Leonard <leonard.crestez@intel.com>");
MODULE_DESCRIPTION("MAX44000 Ambient and Infrared Proximity Sensor");
MODULE_LICENSE("GPL v2");

Some files were not shown because too many files have changed in this diff Show More