1
0
Fork 0

Second set of new device support, features and cleanup for the 4.3 cycle.

Take 2 also includes a fix set that was too late for the 4.2 cycle.
 
 As we had a lot of tools and docs work in this set, I have broken those
 out into their own categories in this description.
 
 Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'.
 * Poll functions for both event chardev and the buffer one were returning
   negative error codes (via a positive value).
 * A recent change to lsiio adding some error handling that was wrong and
   stopped the tool working.
 * bmg160 was missing some dependencies in Kconfig
 * berlin2-adc had a misshandled register (wrote a value rather than a bitmap)
 
 New device support
 * TI opt3001 light sensor
 * TXC PA12 ALS and proximity sensor.
 * mcp3301 ADC support (in mcp320x driver)
 * ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors
   common support to allow different WHOAMI register addresses, devices with
   fixed scale and allow interrupt equiped magnetometers).
 * ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver)
 * ADIS16266 gyro (in the adis16260 driver)
 * ADIS16137 gyro (in the adis16136 driver)
 
 New functionality
 * mmc35240 DT bindings.
 * Inverse unit conversion macros to aid handing of values written to sysfs
   attributes.
 
 Core cleanup
 * Forward declaration of struct iio_trigger to avoid a compile warning.
 
 Driver cleanup / fixes
 * mxs-lradc
   - Clarify which parts are supported.
   - Fix spelling erorrs.
   - Missing/extra includes
   - reorder includes
   - add datasheet name listings for all usable channels (to allow them
     to be bound by name from consumer drivers)
 * acpi-als - add some function prefixes as per general iio style.
 * bmc150_magn - replace a magic value with the existing define.
 * vf610 - determine possible sample frequencies taking into account the
   electrical characteristics (defining a minimum sample time)
 * dht11
   - whitespace
   - additional docs
   - avoid mulitple assignments in one line
   - Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick
     previously used for timing.
 * Fix all drivers that consider 0 a valid IRQ for historical reasons.
 * Export I2C module alias info where previously missing (to allow autoprobing)
 * Export OF module alias info where previously missing.
 * mmc35240 - switch some variables into arrays to improve readability.
 * mlx90614 - define some magic numbers for readability.
 * bmc150_magn
   - expand area locked by a mutex to cover all the use of the
     data->buffer.
   - use descriptive naming for a mask instead of a magic value.
 * berin2-adc
   - pass up an error code rather that a generic error
   - constify the iio_chan_spec
   - some other little tidy ups.
 * stk8312
   - fix a dependency on triggered buffers in kconfig
   - add a check for invalid attribute values
   - improve error handling by returning error codes where possible and
     return immediately where relevant
   - rework macro defs to use GENMASK etc
   - change some variable types to reduce unnecessary casting
   - clean up code style
   - drop a local buffer copy for bulk reads and use the one in data->buffer
      instead.
 * adis16400 - the adis16448 gyroscope scale was wrong.
 * adis16480 - some more wrong scales for various parts.
 * adis16300 - has an undocumented product id and serial number registers so
   use them.
 * iio_simple_dummy - fix some wrong code indentation.
 * bmc150-accel - use the chip ID to detect the chip present rather than
   verifying the expected part was there.  This was in response to a wrong
   ACPI entry on the WinBook TW100.
 * mma8452
   - fix _get_hp_filter_index
   - drop a double include
   - pass up an error code rather than rewriting it
   - range check input values to attribute writes
   - register defs tidy up using GENMASK and reordering them to be easier to
     follow.
   - various coding style cleanups
   - put the Kconfig entry in the write place (alphabetically).
 
 Tools related
 * Tools cleanup - drop an explicity NULL comparison, some unnecessary braces,
   use the ARRAY_SIZE macro, send error messages to stderr instead of dropping
   them in the middle of normal output.
 * Fix tools to allow that scale and offset attributes are optional.
 * More tools fixes including allowing true 32bit data (previously an overflow
   prevented more than 31bits)
 * Drop a stray header guard that ended up in a c file.
 * Make calc_digits static as it isn't exported or in the header.
 * Set ci_array pointer to NULL after free as a protection against non safe
   usage of the tools core code.  Also convert a double pointer to a single
   one as the extra level of indirection was unnecessary.
 
 Docs
 * DocBook introduction by Daniel Baluta.  Glad we are beginning to
   draw together some more introductory docs to suplement the various
   tools / examples.
 * Drop bytes_per_datum sysfs attribute docs as it no longer exists.
 * A whole load of missing / fixing of kernel-doc for the core of IIO.
 * Document the trigger name sysfs attribute in the ABI docs.
 * Minor typos in the ABI docs related to power down modes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJVy5EbAAoJEFSFNJnE9BaIyjEQAIXc+mjgdyMJEXLKlKKGCSY5
 EX7saX91IeSK5y0CWX0hd0VPewaj4ExG7PWo3gqUSm1L9zmusLcyJm8W2pev3CGE
 m7s40efxZJw0Jmmu18a3LCfcHUu/LWl4mHQtZy/AFGgWhZzWIyKA2XLqgc+Wu9qb
 sjzleSJ05etDksyA7JWFCrrwBnJlW4lD25o0nD0kt3Wry2wlbN2JvZ9QLmmoc0ex
 shvtI556Ew0FRywT9ir555EoJNAQQMW85Ft0dWFBnLwgc67nFTa4YNRXgoRlzhh/
 sRnGKzrs5SVc1c9sxiVS4utiazxy/irHgZ5FkvTTq7F+GXeIwPK9Xv/SXZTmvs5w
 lrSazRIjiLqWgpv/5oaOOGlikbpctI2kSXO0GbCW8th+l3KnKcKfComa3fnU7dca
 /lofp/JzpIfwM+Bnjl1nlNuEbT0mlfJySfhUSSu/kHJxOcvDfkK4vv3oSfFp5nbF
 rhA9vbVEfopXTGIOwWDjV4j0HtMCEHgOPN3T0kuyiYiWZUIjfJXchXG8e5h9/ncd
 ACjH3fg6FQtHzTtzqLQky/NVAKcnFrgJSokN25GXF7R95TxufYJ6RIfnenJiCd2n
 QCIdPam4bZh3/C2QYtiqWKY5e+zfkqs88/Er/HGgvxRUhKCbTvCcey1RY7FEDFHY
 +9nMx/Yts8L1ulUEMjsm
 =/b3G
 -----END PGP SIGNATURE-----

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

Jonathan writes:

Second set of new device support, features and cleanup for the 4.3 cycle.
Take 2 also includes a fix set that was too late for the 4.2 cycle.

As we had a lot of tools and docs work in this set, I have broken those
out into their own categories in this description.

Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'.
* Poll functions for both event chardev and the buffer one were returning
  negative error codes (via a positive value).
* A recent change to lsiio adding some error handling that was wrong and
  stopped the tool working.
* bmg160 was missing some dependencies in Kconfig
* berlin2-adc had a misshandled register (wrote a value rather than a bitmap)

New device support
* TI opt3001 light sensor
* TXC PA12 ALS and proximity sensor.
* mcp3301 ADC support (in mcp320x driver)
* ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors
  common support to allow different WHOAMI register addresses, devices with
  fixed scale and allow interrupt equiped magnetometers).
* ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver)
* ADIS16266 gyro (in the adis16260 driver)
* ADIS16137 gyro (in the adis16136 driver)

New functionality
* mmc35240 DT bindings.
* Inverse unit conversion macros to aid handing of values written to sysfs
  attributes.

Core cleanup
* Forward declaration of struct iio_trigger to avoid a compile warning.

Driver cleanup / fixes
* mxs-lradc
  - Clarify which parts are supported.
  - Fix spelling erorrs.
  - Missing/extra includes
  - reorder includes
  - add datasheet name listings for all usable channels (to allow them
    to be bound by name from consumer drivers)
* acpi-als - add some function prefixes as per general iio style.
* bmc150_magn - replace a magic value with the existing define.
* vf610 - determine possible sample frequencies taking into account the
  electrical characteristics (defining a minimum sample time)
* dht11
  - whitespace
  - additional docs
  - avoid mulitple assignments in one line
  - Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick
    previously used for timing.
* Fix all drivers that consider 0 a valid IRQ for historical reasons.
* Export I2C module alias info where previously missing (to allow autoprobing)
* Export OF module alias info where previously missing.
* mmc35240 - switch some variables into arrays to improve readability.
* mlx90614 - define some magic numbers for readability.
* bmc150_magn
  - expand area locked by a mutex to cover all the use of the
    data->buffer.
  - use descriptive naming for a mask instead of a magic value.
* berin2-adc
  - pass up an error code rather that a generic error
  - constify the iio_chan_spec
  - some other little tidy ups.
* stk8312
  - fix a dependency on triggered buffers in kconfig
  - add a check for invalid attribute values
  - improve error handling by returning error codes where possible and
    return immediately where relevant
  - rework macro defs to use GENMASK etc
  - change some variable types to reduce unnecessary casting
  - clean up code style
  - drop a local buffer copy for bulk reads and use the one in data->buffer
     instead.
* adis16400 - the adis16448 gyroscope scale was wrong.
* adis16480 - some more wrong scales for various parts.
* adis16300 - has an undocumented product id and serial number registers so
  use them.
* iio_simple_dummy - fix some wrong code indentation.
* bmc150-accel - use the chip ID to detect the chip present rather than
  verifying the expected part was there.  This was in response to a wrong
  ACPI entry on the WinBook TW100.
* mma8452
  - fix _get_hp_filter_index
  - drop a double include
  - pass up an error code rather than rewriting it
  - range check input values to attribute writes
  - register defs tidy up using GENMASK and reordering them to be easier to
    follow.
  - various coding style cleanups
  - put the Kconfig entry in the write place (alphabetically).

Tools related
* Tools cleanup - drop an explicity NULL comparison, some unnecessary braces,
  use the ARRAY_SIZE macro, send error messages to stderr instead of dropping
  them in the middle of normal output.
* Fix tools to allow that scale and offset attributes are optional.
* More tools fixes including allowing true 32bit data (previously an overflow
  prevented more than 31bits)
* Drop a stray header guard that ended up in a c file.
* Make calc_digits static as it isn't exported or in the header.
* Set ci_array pointer to NULL after free as a protection against non safe
  usage of the tools core code.  Also convert a double pointer to a single
  one as the extra level of indirection was unnecessary.

Docs
* DocBook introduction by Daniel Baluta.  Glad we are beginning to
  draw together some more introductory docs to suplement the various
  tools / examples.
* Drop bytes_per_datum sysfs attribute docs as it no longer exists.
* A whole load of missing / fixing of kernel-doc for the core of IIO.
* Document the trigger name sysfs attribute in the ABI docs.
* Minor typos in the ABI docs related to power down modes.
steinar/wifi_calib_4_9_kernel
Greg Kroah-Hartman 2015-08-12 12:43:41 -07:00
commit 1c46ae0af6
67 changed files with 3146 additions and 572 deletions

View File

@ -493,7 +493,7 @@ Contact: linux-iio@vger.kernel.org
Description:
Specifies the output powerdown mode.
DAC output stage is disconnected from the amplifier and
1kohm_to_gnd: connected to ground via an 1kOhm resistor,
1kohm_to_gnd: connected to ground via an 1kOhm resistor,
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
100kohm_to_gnd: connected to ground via an 100kOhm resistor,
@ -503,9 +503,9 @@ Description:
outX_powerdown_mode_available. If Y is not present the
mode is shared across all outputs.
What: /sys/.../iio:deviceX/out_votlageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_voltageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_voltage_powerdown_mode_available
What: /sys/.../iio:deviceX/out_altvotlageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_altvoltageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_altvoltage_powerdown_mode_available
KernelVersion: 2.6.38
Contact: linux-iio@vger.kernel.org
@ -1040,13 +1040,6 @@ Contact: linux-iio@vger.kernel.org
Description:
Number of scans contained by the buffer.
What: /sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Bytes per scan. Due to alignment fun, the scan may be larger
than implied directly by the scan_element parameters.
What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org

View File

@ -9,3 +9,12 @@ Description:
automated testing or in situations, where other trigger methods
are not applicable. For example no RTC or spare GPIOs.
X is the IIO index of the trigger.
What: /sys/bus/iio/devices/triggerX/name
KernelVersion: 2.6.39
Contact: linux-iio@vger.kernel.org
Description:
The name attribute holds a description string for the current
trigger. In order to associate the trigger with an IIO device
one should write this name string to
/sys/bus/iio/devices/iio:deviceY/trigger/current_trigger.

View File

@ -15,7 +15,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
tracepoint.xml drm.xml media_api.xml w1.xml \
writing_musb_glue_layer.xml crypto-API.xml
writing_musb_glue_layer.xml crypto-API.xml iio.xml
include Documentation/DocBook/media/Makefile

View File

@ -0,0 +1,697 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<book id="iioid">
<bookinfo>
<title>Industrial I/O driver developer's guide </title>
<authorgroup>
<author>
<firstname>Daniel</firstname>
<surname>Baluta</surname>
<affiliation>
<address>
<email>daniel.baluta@intel.com</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2015</year>
<holder>Intel Corporation</holder>
</copyright>
<legalnotice>
<para>
This documentation is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public
License version 2.
</para>
</legalnotice>
</bookinfo>
<toc></toc>
<chapter id="intro">
<title>Introduction</title>
<para>
The main purpose of the Industrial I/O subsystem (IIO) is to provide
support for devices that in some sense perform either analog-to-digital
conversion (ADC) or digital-to-analog conversion (DAC) or both. The aim
is to fill the gap between the somewhat similar hwmon and input
subsystems.
Hwmon is directed at low sample rate sensors used to monitor and
control the system itself, like fan speed control or temperature
measurement. Input is, as its name suggests, focused on human interaction
input devices (keyboard, mouse, touchscreen). In some cases there is
considerable overlap between these and IIO.
</para>
<para>
Devices that fall into this category include:
<itemizedlist>
<listitem>
analog to digital converters (ADCs)
</listitem>
<listitem>
accelerometers
</listitem>
<listitem>
capacitance to digital converters (CDCs)
</listitem>
<listitem>
digital to analog converters (DACs)
</listitem>
<listitem>
gyroscopes
</listitem>
<listitem>
inertial measurement units (IMUs)
</listitem>
<listitem>
color and light sensors
</listitem>
<listitem>
magnetometers
</listitem>
<listitem>
pressure sensors
</listitem>
<listitem>
proximity sensors
</listitem>
<listitem>
temperature sensors
</listitem>
</itemizedlist>
Usually these sensors are connected via SPI or I2C. A common use case of the
sensors devices is to have combined functionality (e.g. light plus proximity
sensor).
</para>
</chapter>
<chapter id='iiosubsys'>
<title>Industrial I/O core</title>
<para>
The Industrial I/O core offers:
<itemizedlist>
<listitem>
a unified framework for writing drivers for many different types of
embedded sensors.
</listitem>
<listitem>
a standard interface to user space applications manipulating sensors.
</listitem>
</itemizedlist>
The implementation can be found under <filename>
drivers/iio/industrialio-*</filename>
</para>
<sect1 id="iiodevice">
<title> Industrial I/O devices </title>
!Finclude/linux/iio/iio.h iio_dev
!Fdrivers/iio/industrialio-core.c iio_device_alloc
!Fdrivers/iio/industrialio-core.c iio_device_free
!Fdrivers/iio/industrialio-core.c iio_device_register
!Fdrivers/iio/industrialio-core.c iio_device_unregister
<para>
An IIO device usually corresponds to a single hardware sensor and it
provides all the information needed by a driver handling a device.
Let's first have a look at the functionality embedded in an IIO
device then we will show how a device driver makes use of an IIO
device.
</para>
<para>
There are two ways for a user space application to interact
with an IIO driver.
<itemizedlist>
<listitem>
<filename>/sys/bus/iio/iio:deviceX/</filename>, this
represents a hardware sensor and groups together the data
channels of the same chip.
</listitem>
<listitem>
<filename>/dev/iio:deviceX</filename>, character device node
interface used for buffered data transfer and for events information
retrieval.
</listitem>
</itemizedlist>
</para>
A typical IIO driver will register itself as an I2C or SPI driver and will
create two routines, <function> probe </function> and <function> remove
</function>. At <function>probe</function>:
<itemizedlist>
<listitem>call <function>iio_device_alloc</function>, which allocates memory
for an IIO device.
</listitem>
<listitem> initialize IIO device fields with driver specific information
(e.g. device name, device channels).
</listitem>
<listitem>call <function> iio_device_register</function>, this registers the
device with the IIO core. After this call the device is ready to accept
requests from user space applications.
</listitem>
</itemizedlist>
At <function>remove</function>, we free the resources allocated in
<function>probe</function> in reverse order:
<itemizedlist>
<listitem><function>iio_device_unregister</function>, unregister the device
from the IIO core.
</listitem>
<listitem><function>iio_device_free</function>, free the memory allocated
for the IIO device.
</listitem>
</itemizedlist>
<sect2 id="iioattr"> <title> IIO device sysfs interface </title>
<para>
Attributes are sysfs files used to expose chip info and also allowing
applications to set various configuration parameters. For device
with index X, attributes can be found under
<filename>/sys/bus/iio/iio:deviceX/ </filename> directory.
Common attributes are:
<itemizedlist>
<listitem><filename>name</filename>, description of the physical
chip.
</listitem>
<listitem><filename>dev</filename>, shows the major:minor pair
associated with <filename>/dev/iio:deviceX</filename> node.
</listitem>
<listitem><filename>sampling_frequency_available</filename>,
available discrete set of sampling frequency values for
device.
</listitem>
</itemizedlist>
Available standard attributes for IIO devices are described in the
<filename>Documentation/ABI/testing/sysfs-bus-iio </filename> file
in the Linux kernel sources.
</para>
</sect2>
<sect2 id="iiochannel"> <title> IIO device channels </title>
!Finclude/linux/iio/iio.h iio_chan_spec structure.
<para>
An IIO device channel is a representation of a data channel. An
IIO device can have one or multiple channels. For example:
<itemizedlist>
<listitem>
a thermometer sensor has one channel representing the
temperature measurement.
</listitem>
<listitem>
a light sensor with two channels indicating the measurements in
the visible and infrared spectrum.
</listitem>
<listitem>
an accelerometer can have up to 3 channels representing
acceleration on X, Y and Z axes.
</listitem>
</itemizedlist>
An IIO channel is described by the <type> struct iio_chan_spec
</type>. A thermometer driver for the temperature sensor in the
example above would have to describe its channel as follows:
<programlisting>
static const struct iio_chan_spec temp_channel[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
</programlisting>
Channel sysfs attributes exposed to userspace are specified in
the form of <emphasis>bitmasks</emphasis>. Depending on their
shared info, attributes can be set in one of the following masks:
<itemizedlist>
<listitem><emphasis>info_mask_separate</emphasis>, attributes will
be specific to this channel</listitem>
<listitem><emphasis>info_mask_shared_by_type</emphasis>,
attributes are shared by all channels of the same type</listitem>
<listitem><emphasis>info_mask_shared_by_dir</emphasis>, attributes
are shared by all channels of the same direction </listitem>
<listitem><emphasis>info_mask_shared_by_all</emphasis>,
attributes are shared by all channels</listitem>
</itemizedlist>
When there are multiple data channels per channel type we have two
ways to distinguish between them:
<itemizedlist>
<listitem> set <emphasis> .modified</emphasis> field of <type>
iio_chan_spec</type> to 1. Modifiers are specified using
<emphasis>.channel2</emphasis> field of the same
<type>iio_chan_spec</type> structure and are used to indicate a
physically unique characteristic of the channel such as its direction
or spectral response. For example, a light sensor can have two channels,
one for infrared light and one for both infrared and visible light.
</listitem>
<listitem> set <emphasis>.indexed </emphasis> field of
<type>iio_chan_spec</type> to 1. In this case the channel is
simply another instance with an index specified by the
<emphasis>.channel</emphasis> field.
</listitem>
</itemizedlist>
Here is how we can make use of the channel's modifiers:
<programlisting>
static const struct iio_chan_spec light_channels[] = {
{
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_IR,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
}
</programlisting>
This channel's definition will generate two separate sysfs files
for raw data retrieval:
<itemizedlist>
<listitem>
<filename>/sys/bus/iio/iio:deviceX/in_intensity_ir_raw</filename>
</listitem>
<listitem>
<filename>/sys/bus/iio/iio:deviceX/in_intensity_both_raw</filename>
</listitem>
</itemizedlist>
one file for processed data:
<itemizedlist>
<listitem>
<filename>/sys/bus/iio/iio:deviceX/in_illuminance_input
</filename>
</listitem>
</itemizedlist>
and one shared sysfs file for sampling frequency:
<itemizedlist>
<listitem>
<filename>/sys/bus/iio/iio:deviceX/sampling_frequency.
</filename>
</listitem>
</itemizedlist>
</para>
<para>
Here is how we can make use of the channel's indexing:
<programlisting>
static const struct iio_chan_spec light_channels[] = {
{
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
{
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
}
</programlisting>
This will generate two separate attributes files for raw data
retrieval:
<itemizedlist>
<listitem>
<filename>/sys/bus/iio/devices/iio:deviceX/in_voltage0_raw</filename>,
representing voltage measurement for channel 0.
</listitem>
<listitem>
<filename>/sys/bus/iio/devices/iio:deviceX/in_voltage1_raw</filename>,
representing voltage measurement for channel 1.
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="iiobuffer"> <title> Industrial I/O buffers </title>
!Finclude/linux/iio/buffer.h iio_buffer
!Edrivers/iio/industrialio-buffer.c
<para>
The Industrial I/O core offers a way for continuous data capture
based on a trigger source. Multiple data channels can be read at once
from <filename>/dev/iio:deviceX</filename> character device node,
thus reducing the CPU load.
</para>
<sect2 id="iiobuffersysfs">
<title>IIO buffer sysfs interface </title>
<para>
An IIO buffer has an associated attributes directory under <filename>
/sys/bus/iio/iio:deviceX/buffer/</filename>. Here are the existing
attributes:
<itemizedlist>
<listitem>
<emphasis>length</emphasis>, the total number of data samples
(capacity) that can be stored by the buffer.
</listitem>
<listitem>
<emphasis>enable</emphasis>, activate buffer capture.
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2 id="iiobuffersetup"> <title> IIO buffer setup </title>
<para>The meta information associated with a channel reading
placed in a buffer is called a <emphasis> scan element </emphasis>.
The important bits configuring scan elements are exposed to
userspace applications via the <filename>
/sys/bus/iio/iio:deviceX/scan_elements/</filename> directory. This
file contains attributes of the following form:
<itemizedlist>
<listitem><emphasis>enable</emphasis>, used for enabling a channel.
If and only if its attribute is non zero, then a triggered capture
will contain data samples for this channel.
</listitem>
<listitem><emphasis>type</emphasis>, description of the scan element
data storage within the buffer and hence the form in which it is
read from user space. Format is <emphasis>
[be|le]:[s|u]bits/storagebitsXrepeat[>>shift] </emphasis>.
<itemizedlist>
<listitem> <emphasis>be</emphasis> or <emphasis>le</emphasis>, specifies
big or little endian.
</listitem>
<listitem>
<emphasis>s </emphasis>or <emphasis>u</emphasis>, specifies if
signed (2's complement) or unsigned.
</listitem>
<listitem><emphasis>bits</emphasis>, is the number of valid data
bits.
</listitem>
<listitem><emphasis>storagebits</emphasis>, is the number of bits
(after padding) that it occupies in the buffer.
</listitem>
<listitem>
<emphasis>shift</emphasis>, if specified, is the shift that needs
to be applied prior to masking out unused bits.
</listitem>
<listitem>
<emphasis>repeat</emphasis>, specifies the number of bits/storagebits
repetitions. When the repeat element is 0 or 1, then the repeat
value is omitted.
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
For example, a driver for a 3-axis accelerometer with 12 bit
resolution where data is stored in two 8-bits registers as
follows:
<programlisting>
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
|D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06)
+---+---+---+---+---+---+---+---+
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
|D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07)
+---+---+---+---+---+---+---+---+
</programlisting>
will have the following scan element type for each axis:
<programlisting>
$ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type
le:s12/16>>4
</programlisting>
A user space application will interpret data samples read from the
buffer as two byte little endian signed data, that needs a 4 bits
right shift before masking out the 12 valid bits of data.
</para>
<para>
For implementing buffer support a driver should initialize the following
fields in <type>iio_chan_spec</type> definition:
<programlisting>
struct iio_chan_spec {
/* other members */
int scan_index
struct {
char sign;
u8 realbits;
u8 storagebits;
u8 shift;
u8 repeat;
enum iio_endian endianness;
} scan_type;
};
</programlisting>
The driver implementing the accelerometer described above will
have the following channel definition:
<programlisting>
struct struct iio_chan_spec accel_channels[] = {
{
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
/* other stuff here */
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 12,
.storgebits = 16,
.shift = 4,
.endianness = IIO_LE,
},
}
/* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1)
* and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis
*/
}
</programlisting>
</para>
<para>
Here <emphasis> scan_index </emphasis> defines the order in which
the enabled channels are placed inside the buffer. Channels with a lower
scan_index will be placed before channels with a higher index. Each
channel needs to have a unique scan_index.
</para>
<para>
Setting scan_index to -1 can be used to indicate that the specific
channel does not support buffered capture. In this case no entries will
be created for the channel in the scan_elements directory.
</para>
</sect2>
</sect1>
<sect1 id="iiotrigger"> <title> Industrial I/O triggers </title>
!Finclude/linux/iio/trigger.h iio_trigger
!Edrivers/iio/industrialio-trigger.c
<para>
In many situations it is useful for a driver to be able to
capture data based on some external event (trigger) as opposed
to periodically polling for data. An IIO trigger can be provided
by a device driver that also has an IIO device based on hardware
generated events (e.g. data ready or threshold exceeded) or
provided by a separate driver from an independent interrupt
source (e.g. GPIO line connected to some external system, timer
interrupt or user space writing a specific file in sysfs). A
trigger may initiate data capture for a number of sensors and
also it may be completely unrelated to the sensor itself.
</para>
<sect2 id="iiotrigsysfs"> <title> IIO trigger sysfs interface </title>
There are two locations in sysfs related to triggers:
<itemizedlist>
<listitem><filename>/sys/bus/iio/devices/triggerY</filename>,
this file is created once an IIO trigger is registered with
the IIO core and corresponds to trigger with index Y. Because
triggers can be very different depending on type there are few
standard attributes that we can describe here:
<itemizedlist>
<listitem>
<emphasis>name</emphasis>, trigger name that can be later
used for association with a device.
</listitem>
<listitem>
<emphasis>sampling_frequency</emphasis>, some timer based
triggers use this attribute to specify the frequency for
trigger calls.
</listitem>
</itemizedlist>
</listitem>
<listitem>
<filename>/sys/bus/iio/devices/iio:deviceX/trigger/</filename>, this
directory is created once the device supports a triggered
buffer. We can associate a trigger with our device by writing
the trigger's name in the <filename>current_trigger</filename> file.
</listitem>
</itemizedlist>
</sect2>
<sect2 id="iiotrigattr"> <title> IIO trigger setup</title>
<para>
Let's see a simple example of how to setup a trigger to be used
by a driver.
<programlisting>
struct iio_trigger_ops trigger_ops = {
.set_trigger_state = sample_trigger_state,
.validate_device = sample_validate_device,
}
struct iio_trigger *trig;
/* first, allocate memory for our trigger */
trig = iio_trigger_alloc(dev, "trig-%s-%d", name, idx);
/* setup trigger operations field */
trig->ops = &amp;trigger_ops;
/* now register the trigger with the IIO core */
iio_trigger_register(trig);
</programlisting>
</para>
</sect2>
<sect2 id="iiotrigsetup"> <title> IIO trigger ops</title>
!Finclude/linux/iio/trigger.h iio_trigger_ops
<para>
Notice that a trigger has a set of operations attached:
<itemizedlist>
<listitem>
<function>set_trigger_state</function>, switch the trigger on/off
on demand.
</listitem>
<listitem>
<function>validate_device</function>, function to validate the
device when the current trigger gets changed.
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>
<sect1 id="iiotriggered_buffer">
<title> Industrial I/O triggered buffers </title>
<para>
Now that we know what buffers and triggers are let's see how they
work together.
</para>
<sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
!Edrivers/iio/industrialio-triggered-buffer.c
!Finclude/linux/iio/iio.h iio_buffer_setup_ops
<para>
A typical triggered buffer setup looks like this:
<programlisting>
const struct iio_buffer_setup_ops sensor_buffer_setup_ops = {
.preenable = sensor_buffer_preenable,
.postenable = sensor_buffer_postenable,
.postdisable = sensor_buffer_postdisable,
.predisable = sensor_buffer_predisable,
};
irqreturn_t sensor_iio_pollfunc(int irq, void *p)
{
pf->timestamp = iio_get_time_ns();
return IRQ_WAKE_THREAD;
}
irqreturn_t sensor_trigger_handler(int irq, void *p)
{
u16 buf[8];
int i = 0;
/* read data for each active channel */
for_each_set_bit(bit, active_scan_mask, masklength)
buf[i++] = sensor_get_data(bit)
iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp);
iio_trigger_notify_done(trigger);
return IRQ_HANDLED;
}
/* setup triggered buffer, usually in probe function */
iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc,
sensor_trigger_handler,
sensor_buffer_setup_ops);
</programlisting>
</para>
The important things to notice here are:
<itemizedlist>
<listitem><function> iio_buffer_setup_ops</function>, the buffer setup
functions to be called at predefined points in the buffer configuration
sequence (e.g. before enable, after disable). If not specified, the
IIO core uses the default <type>iio_triggered_buffer_setup_ops</type>.
</listitem>
<listitem><function>sensor_iio_pollfunc</function>, the function that
will be used as top half of poll function. It should do as little
processing as possible, because it runs in interrupt context. The most
common operation is recording of the current timestamp and for this reason
one can use the IIO core defined <function>iio_pollfunc_store_time
</function> function.
</listitem>
<listitem><function>sensor_trigger_handler</function>, the function that
will be used as bottom half of the poll function. This runs in the
context of a kernel thread and all the processing takes place here.
It usually reads data from the device and stores it in the internal
buffer together with the timestamp recorded in the top half.
</listitem>
</itemizedlist>
</sect2>
</sect1>
</chapter>
<chapter id='iioresources'>
<title> Resources </title>
IIO core may change during time so the best documentation to read is the
source code. There are several locations where you should look:
<itemizedlist>
<listitem>
<filename>drivers/iio/</filename>, contains the IIO core plus
and directories for each sensor type (e.g. accel, magnetometer,
etc.)
</listitem>
<listitem>
<filename>include/linux/iio/</filename>, contains the header
files, nice to read for the internal kernel interfaces.
</listitem>
<listitem>
<filename>include/uapi/linux/iio/</filename>, contains files to be
used by user space applications.
</listitem>
<listitem>
<filename>tools/iio/</filename>, contains tools for rapidly
testing buffers, events and device creation.
</listitem>
<listitem>
<filename>drivers/staging/iio/</filename>, contains code for some
drivers or experimental features that are not yet mature enough
to be moved out.
</listitem>
</itemizedlist>
<para>
Besides the code, there are some good online documentation sources:
<itemizedlist>
<listitem>
<ulink url="http://marc.info/?l=linux-iio"> Industrial I/O mailing
list </ulink>
</listitem>
<listitem>
<ulink url="http://wiki.analog.com/software/linux/docs/iio/iio">
Analog Device IIO wiki page </ulink>
</listitem>
<listitem>
<ulink url="https://fosdem.org/2015/schedule/event/iiosdr/">
Using the Linux IIO framework for SDR, Lars-Peter Clausen's
presentation at FOSDEM </ulink>
</listitem>
</itemizedlist>
</para>
</chapter>
</book>
<!--
vim: softtabstop=2:shiftwidth=2:expandtab:textwidth=72
-->

View File

@ -18,6 +18,7 @@ Required properties:
"mcp3202"
"mcp3204"
"mcp3208"
"mcp3301"
Examples:

View File

@ -17,6 +17,11 @@ Recommended properties:
- Frequency in normal mode (ADLPC=0, ADHSC=0)
- Frequency in high-speed mode (ADLPC=0, ADHSC=1)
- Frequency in low-power mode (ADLPC=1, ADHSC=0)
- min-sample-time: Minimum sampling time in nanoseconds. This value has
to be chosen according to the conversion mode and the connected analog
source resistance (R_as) and capacitance (C_as). Refer the datasheet's
operating requirements. A safe default across a wide range of R_as and
C_as as well as conversion modes is 1000ns.
Example:
adc0: adc@4003b000 {

View File

@ -0,0 +1,13 @@
* MEMSIC MMC35240 magnetometer sensor
Required properties:
- compatible : should be "memsic,mmc35240"
- reg : the I2C address of the magnetometer
Example:
mmc35240@30 {
compatible = "memsic,mmc35240";
reg = <0x30>;
};

View File

@ -35,6 +35,7 @@ Accelerometers:
- st,lsm303dl-accel
- st,lsm303dlm-accel
- st,lsm330-accel
- st,lsm303agr-accel
Gyroscopes:
- st,l3g4200d-gyro
@ -46,6 +47,7 @@ Gyroscopes:
- st,lsm330-gyro
Magnetometers:
- st,lsm303agr-magn
- st,lsm303dlh-magn
- st,lsm303dlhc-magn
- st,lsm303dlm-magn

View File

@ -1,4 +1,4 @@
* Freescale i.MX28 LRADC device driver
* Freescale MXS LRADC device driver
Required properties:
- compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc"

View File

@ -86,18 +86,6 @@ config KXSD9
To compile this driver as a module, choose M here: the module
will be called kxsd9.
config MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the Freescale MMA8452Q 3-axis
accelerometer.
To compile this driver as a module, choose M here: the module
will be called mma8452.
config KXCJK1013
tristate "Kionix 3-Axis Accelerometer Driver"
depends on I2C
@ -111,6 +99,18 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
config MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the Freescale MMA8452Q 3-axis
accelerometer.
To compile this driver as a module, choose M here: the module
will be called mma8452.
config MMA9551_CORE
tristate
@ -140,6 +140,8 @@ config MMA9553
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to get support for the Sensortek STK8312 3-axis
accelerometer.

View File

@ -151,6 +151,7 @@ struct bmc150_scale_info {
};
struct bmc150_accel_chip_info {
const char *name;
u8 chip_id;
const struct iio_chan_spec *channels;
int num_channels;
@ -345,63 +346,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t,
return 0;
}
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
int ret;
ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
if (ret < 0) {
dev_err(&data->client->dev, "Error: Reading chip id\n");
return ret;
}
dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
if (ret != data->chip_info->chip_id) {
dev_err(&data->client->dev, "Invalid chip %x\n", ret);
return -ENODEV;
}
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)
return ret;
/* Set Bandwidth */
ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
if (ret < 0)
return ret;
/* Set Default Range */
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_PMU_RANGE,
BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
return ret;
}
data->range = BMC150_ACCEL_DEF_RANGE_4G;
/* Set default slope duration and thresholds */
data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
ret = bmc150_accel_update_slope(data);
if (ret < 0)
return ret;
/* Set default as latched interrupts */
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
return 0;
}
static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
int *val2)
{
@ -1119,6 +1063,7 @@ enum {
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
[bmc150] = {
.name = "BMC150A",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@ -1128,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bmi055] = {
.name = "BMI055A",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@ -1137,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma255] = {
.name = "BMA0255",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@ -1146,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma250e] = {
.name = "BMA250E",
.chip_id = 0xF9,
.channels = bma250e_accel_channels,
.num_channels = ARRAY_SIZE(bma250e_accel_channels),
@ -1155,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{306457, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma222e] = {
.name = "BMA222E",
.chip_id = 0xF8,
.channels = bma222e_accel_channels,
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
@ -1164,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma280] = {
.name = "BMA0280",
.chip_id = 0xFB,
.channels = bma280_accel_channels,
.num_channels = ARRAY_SIZE(bma280_accel_channels),
@ -1410,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
return IRQ_NONE;
}
static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
*data = (int)id->driver_data;
return dev_name(dev);
}
static int bmc150_accel_gpio_probe(struct i2c_client *client,
struct bmc150_accel_data *data)
{
@ -1618,6 +1554,70 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
.postdisable = bmc150_accel_buffer_postdisable,
};
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
int ret, i;
ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
if (ret < 0) {
dev_err(&data->client->dev, "Error: Reading chip id\n");
return ret;
}
dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
if (bmc150_accel_chip_info_tbl[i].chip_id == ret) {
data->chip_info = &bmc150_accel_chip_info_tbl[i];
break;
}
}
if (!data->chip_info) {
dev_err(&data->client->dev, "Unsupported chip %x\n", ret);
return -ENODEV;
}
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)
return ret;
/* Set Bandwidth */
ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
if (ret < 0)
return ret;
/* Set Default Range */
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_PMU_RANGE,
BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
return ret;
}
data->range = BMC150_ACCEL_DEF_RANGE_4G;
/* Set default slope duration and thresholds */
data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
ret = bmc150_accel_update_slope(data);
if (ret < 0)
return ret;
/* Set default as latched interrupts */
ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
return 0;
}
static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret;
const char *name = NULL;
int chip_id = 0;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
if (id) {
if (id)
name = id->name;
chip_id = id->driver_data;
}
if (ACPI_HANDLE(&client->dev))
name = bmc150_accel_match_acpi_device(&client->dev, &chip_id);
data->chip_info = &bmc150_accel_chip_info_tbl[chip_id];
ret = bmc150_accel_chip_init(data);
if (ret < 0)
@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
indio_dev->dev.parent = &client->dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name;
indio_dev->name = name ? name : data->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_accel_info;
@ -1670,7 +1662,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = bmc150_accel_gpio_probe(client, data);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(
&client->dev, client->irq,
bmc150_accel_irq_handler,

View File

@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = kxcjk1013_gpio_probe(client, data);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,

View File

@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
@ -24,54 +23,51 @@
#include <linux/iio/events.h>
#include <linux/delay.h>
#define MMA8452_STATUS 0x00
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
#define MMA8452_OUT_Y 0x03
#define MMA8452_OUT_Z 0x05
#define MMA8452_INT_SRC 0x0c
#define MMA8452_WHO_AM_I 0x0d
#define MMA8452_DATA_CFG 0x0e
#define MMA8452_HP_FILTER_CUTOFF 0x0f
#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1))
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
#define MMA8452_TRANSIENT_SRC 0x1e
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
#define MMA8452_TRANSIENT_THS 0x1f
#define MMA8452_TRANSIENT_THS_MASK 0x7f
#define MMA8452_TRANSIENT_COUNT 0x20
#define MMA8452_OFF_X 0x2f
#define MMA8452_OFF_Y 0x30
#define MMA8452_OFF_Z 0x31
#define MMA8452_CTRL_REG1 0x2a
#define MMA8452_CTRL_REG2 0x2b
#define MMA8452_CTRL_REG2_RST BIT(6)
#define MMA8452_CTRL_REG4 0x2d
#define MMA8452_CTRL_REG5 0x2e
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
#define MMA8452_OUT_Y 0x03
#define MMA8452_OUT_Z 0x05
#define MMA8452_INT_SRC 0x0c
#define MMA8452_WHO_AM_I 0x0d
#define MMA8452_DATA_CFG 0x0e
#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0)
#define MMA8452_DATA_CFG_FS_2G 0
#define MMA8452_DATA_CFG_FS_4G 1
#define MMA8452_DATA_CFG_FS_8G 2
#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
#define MMA8452_HP_FILTER_CUTOFF 0x0f
#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0)
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
#define MMA8452_TRANSIENT_SRC 0x1e
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
#define MMA8452_TRANSIENT_THS 0x1f
#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0)
#define MMA8452_TRANSIENT_COUNT 0x20
#define MMA8452_CTRL_REG1 0x2a
#define MMA8452_CTRL_ACTIVE BIT(0)
#define MMA8452_CTRL_DR_MASK GENMASK(5, 3)
#define MMA8452_CTRL_DR_SHIFT 3
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
#define MMA8452_CTRL_REG2 0x2b
#define MMA8452_CTRL_REG2_RST BIT(6)
#define MMA8452_CTRL_REG4 0x2d
#define MMA8452_CTRL_REG5 0x2e
#define MMA8452_OFF_X 0x2f
#define MMA8452_OFF_Y 0x30
#define MMA8452_OFF_Z 0x31
#define MMA8452_MAX_REG 0x31
#define MMA8452_MAX_REG 0x31
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
#define MMA8452_INT_DRDY BIT(0)
#define MMA8452_INT_TRANS BIT(5)
#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
#define MMA8452_CTRL_DR_SHIFT 3
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
#define MMA8452_CTRL_ACTIVE BIT(0)
#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
#define MMA8452_DATA_CFG_FS_2G 0
#define MMA8452_DATA_CFG_FS_4G 1
#define MMA8452_DATA_CFG_FS_8G 2
#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
#define MMA8452_INT_DRDY BIT(0)
#define MMA8452_INT_TRANS BIT(5)
#define MMA8452_DEVICE_ID 0x2a
#define MMA8452_DEVICE_ID 0x2a
struct mma8452_data {
struct i2c_client *client;
@ -91,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data)
return ret;
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
return 0;
msleep(20);
}
dev_err(&data->client->dev, "data not ready\n");
return -EIO;
}
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
{
int ret = mma8452_drdy(data);
if (ret < 0)
return ret;
return i2c_smbus_read_i2c_block_data(data->client,
MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
}
static ssize_t mma8452_show_int_plus_micros(char *buf,
const int (*vals)[2], int n)
static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
int n)
{
size_t len = 0;
while (n-- > 0)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%d.%06d ", vals[n][0], vals[n][1]);
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
@ -123,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf,
}
static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
int val, int val2)
int val, int val2)
{
while (n-- > 0)
if (val == vals[n][0] && val2 == vals[n][1])
@ -147,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = {
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor is given by:
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665
*/
static const int mma8452_scales[3][2] = {
{0, 9577}, {0, 19154}, {0, 38307}
@ -178,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
};
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr, char *buf)
struct device_attribute *attr,
char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
ARRAY_SIZE(mma8452_samp_freq));
ARRAY_SIZE(mma8452_samp_freq));
}
static ssize_t mma8452_show_scale_avail(struct device *dev,
struct device_attribute *attr, char *buf)
struct device_attribute *attr,
char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_scales,
ARRAY_SIZE(mma8452_scales));
ARRAY_SIZE(mma8452_scales));
}
static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
@ -205,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
mma8452_show_scale_avail, NULL, 0);
mma8452_show_scale_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
int val, int val2)
int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
ARRAY_SIZE(mma8452_samp_freq), val, val2);
ARRAY_SIZE(mma8452_samp_freq),
val, val2);
}
static int mma8452_get_scale_index(struct mma8452_data *data,
int val, int val2)
static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_scales,
ARRAY_SIZE(mma8452_scales), val, val2);
ARRAY_SIZE(mma8452_scales),
val, val2);
}
static int mma8452_get_hp_filter_index(struct mma8452_data *data,
@ -229,7 +232,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data,
int i = mma8452_get_odr_index(data);
return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
ARRAY_SIZE(mma8452_scales[0]), val, val2);
ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
}
static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
@ -266,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = sign_extend32(
be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
*val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4,
11);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
*val = mma8452_scales[i][0];
*val2 = mma8452_scales[i][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_odr_index(data);
*val = mma8452_samp_freq[i][0];
*val2 = mma8452_samp_freq[i][1];
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);
ret = i2c_smbus_read_byte_data(data->client,
MMA8452_OFF_X + chan->scan_index);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 7);
return IIO_VAL_INT;
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
@ -295,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
}
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static int mma8452_standby(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
}
static int mma8452_active(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
data->ctrl_reg1);
}
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
@ -334,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
ret = 0;
fail:
mutex_unlock(&data->lock);
return ret;
}
@ -344,12 +356,13 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
i = mma8452_get_hp_filter_index(data, val, val2);
if (i < 0)
return -EINVAL;
return i;
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_HP_FILTER_CUTOFF);
if (reg < 0)
return reg;
reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
reg |= i;
@ -370,25 +383,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_samp_freq_index(data, val, val2);
if (i < 0)
return -EINVAL;
return i;
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
return mma8452_change_config(data, MMA8452_CTRL_REG1,
data->ctrl_reg1);
data->ctrl_reg1);
case IIO_CHAN_INFO_SCALE:
i = mma8452_get_scale_index(data, val, val2);
if (i < 0)
return -EINVAL;
return i;
data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
data->data_cfg |= i;
return mma8452_change_config(data, MMA8452_DATA_CFG,
data->data_cfg);
data->data_cfg);
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -128 || val > 127)
return -EINVAL;
return mma8452_change_config(data, MMA8452_OFF_X +
chan->scan_index, val);
return mma8452_change_config(data,
MMA8452_OFF_X + chan->scan_index,
val);
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
if (val == 0 && val2 == 0) {
@ -399,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
return mma8452_change_config(data, MMA8452_DATA_CFG,
data->data_cfg);
data->data_cfg);
default:
return -EINVAL;
@ -425,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
return ret;
*val = ret & MMA8452_TRANSIENT_THS_MASK;
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
@ -437,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
mma8452_get_odr_index(data)];
*val = us / USEC_PER_SEC;
*val2 = us % USEC_PER_SEC;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
@ -453,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
return IIO_VAL_INT_PLUS_MICRO;
default:
@ -472,19 +494,22 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
switch (info) {
case IIO_EV_INFO_VALUE:
return mma8452_change_config(data, MMA8452_TRANSIENT_THS,
val & MMA8452_TRANSIENT_THS_MASK);
if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
return -EINVAL;
return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
case IIO_EV_INFO_PERIOD:
steps = (val * USEC_PER_SEC + val2) /
mma8452_transient_time_step_us[
mma8452_get_odr_index(data)];
if (steps > 0xff)
if (steps < 0 || steps > 0xff)
return -EINVAL;
return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
steps);
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_TRANSIENT_CFG);
@ -499,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
default:
@ -608,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
u8 buffer[16]; /* 3 16-bit channels + padding + ts */
int ret;
ret = mma8452_read(data, (__be16 *) buffer);
ret = mma8452_read(data, (__be16 *)buffer);
if (ret < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
iio_get_time_ns());
iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
@ -674,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = {
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
@ -780,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
return ret;
indio_dev->trig = trig;
return 0;
}
@ -849,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client,
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
data->data_cfg);
data->data_cfg);
if (ret < 0)
return ret;
@ -891,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client,
}
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
if (ret < 0)
goto trigger_cleanup;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mma8452_trigger_handler, NULL);
mma8452_trigger_handler, NULL);
if (ret < 0)
goto trigger_cleanup;
@ -968,6 +996,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
{ .compatible = "fsl,mma8452" },
{ }
};
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
static struct i2c_driver mma8452_driver = {
.driver = {

View File

@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = mma9553_gpio_probe(client);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
mma9553_irq_handler,
mma9553_event_handler,

View File

@ -26,6 +26,7 @@
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
/**
* struct st_sensors_platform_data - default accel platform data

View File

@ -226,12 +226,14 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = {
static const struct st_sensor_settings st_accel_sensors_settings[] = {
{
.wai = ST_ACCEL_1_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3DH_ACCEL_DEV_NAME,
[1] = LSM303DLHC_ACCEL_DEV_NAME,
[2] = LSM330D_ACCEL_DEV_NAME,
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
[5] = LSM303AGR_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
@ -297,6 +299,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_2_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS331DLH_ACCEL_DEV_NAME,
[1] = LSM303DL_ACCEL_DEV_NAME,
@ -359,6 +362,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_3_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM330_ACCEL_DEV_NAME,
},
@ -437,6 +441,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_4_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3LV02DL_ACCEL_DEV_NAME,
},
@ -494,6 +499,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_5_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS331DL_ACCEL_DEV_NAME,
},

View File

@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm330-accel",
.data = LSM330_ACCEL_DEV_NAME,
},
{
.compatible = "st,lsm303agr-accel",
.data = LSM303AGR_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);

View File

@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);

View File

@ -37,16 +37,16 @@
#define STK8312_REG_OTPDATA 0x3E
#define STK8312_REG_OTPCTRL 0x3F
#define STK8312_MODE_ACTIVE 0x01
#define STK8312_MODE_ACTIVE BIT(0)
#define STK8312_MODE_STANDBY 0x00
#define STK8312_DREADY_BIT 0x10
#define STK8312_INT_MODE 0xC0
#define STK8312_RNG_MASK 0xC0
#define STK8312_SR_MASK 0x07
#define STK8312_SR_400HZ_IDX 0
#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */
#define STK8312_DREADY_BIT BIT(4)
#define STK8312_RNG_6G 1
#define STK8312_RNG_SHIFT 6
#define STK8312_READ_RETRIES 16
#define STK8312_ALL_CHANNEL_MASK 7
#define STK8312_RNG_MASK GENMASK(7, 6)
#define STK8312_SR_MASK GENMASK(2, 0)
#define STK8312_SR_400HZ_IDX 0
#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0)
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312"
@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = {
};
static const struct {
u16 val;
u32 val2;
int val;
int val2;
} stk8312_samp_freq_table[] = {
{400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0},
{12, 500000}, {6, 250000}, {3, 125000}
@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = {
struct stk8312_data {
struct i2c_client *client;
struct mutex lock;
int range;
u8 range;
u8 sample_rate_idx;
u8 mode;
struct iio_trigger *dready_trig;
@ -144,22 +144,25 @@ static int stk8312_otp_init(struct stk8312_data *data)
if (ret < 0)
goto exit_err;
count--;
} while (!(ret & 0x80) && count > 0);
} while (!(ret & BIT(7)) && count > 0);
if (count == 0)
if (count == 0) {
ret = -ETIMEDOUT;
goto exit_err;
}
ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA);
if (ret == 0)
ret = -EINVAL;
if (ret < 0)
goto exit_err;
ret = i2c_smbus_write_byte_data(data->client,
STK8312_REG_AFECTRL, ret);
ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret);
if (ret < 0)
goto exit_err;
msleep(150);
return ret;
return 0;
exit_err:
dev_err(&client->dev, "failed to initialize sensor\n");
@ -203,8 +206,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
return ret;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
if (ret < 0)
if (ret < 0) {
dev_err(&client->dev, "failed to set interrupts\n");
stk8312_set_mode(data, mode);
return ret;
}
return stk8312_set_mode(data, mode);
}
@ -228,7 +234,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
data->dready_trigger_on = state;
return ret;
return 0;
}
static const struct iio_trigger_ops stk8312_trigger_ops = {
@ -236,7 +242,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = {
.owner = THIS_MODULE,
};
static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate)
{
int ret;
u8 masked_reg;
@ -253,20 +259,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
return ret;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR);
if (ret < 0) {
dev_err(&client->dev, "failed to set sampling rate\n");
return ret;
}
if (ret < 0)
goto err_activate;
masked_reg = (ret & (~STK8312_SR_MASK)) | rate;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg);
if (ret < 0)
dev_err(&client->dev, "failed to set sampling rate\n");
else
data->sample_rate_idx = rate;
goto err_activate;
data->sample_rate_idx = rate;
return stk8312_set_mode(data, mode);
err_activate:
dev_err(&client->dev, "failed to set sampling rate\n");
stk8312_set_mode(data, mode);
return ret;
}
static int stk8312_set_range(struct stk8312_data *data, u8 range)
@ -288,21 +298,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range)
return ret;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor range\n");
return ret;
}
if (ret < 0)
goto err_activate;
masked_reg = ret & (~STK8312_RNG_MASK);
masked_reg |= range << STK8312_RNG_SHIFT;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg);
if (ret < 0)
dev_err(&client->dev, "failed to change sensor range\n");
else
data->range = range;
goto err_activate;
data->range = range;
return stk8312_set_mode(data, mode);
err_activate:
dev_err(&client->dev, "failed to change sensor range\n");
stk8312_set_mode(data, mode);
return ret;
}
static int stk8312_read_accel(struct stk8312_data *data, u8 address)
@ -335,18 +349,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
if (ret < 0) {
mutex_unlock(&data->lock);
return -EINVAL;
return ret;
}
ret = stk8312_read_accel(data, chan->address);
if (ret < 0) {
stk8312_set_mode(data,
data->mode & (~STK8312_MODE_ACTIVE));
mutex_unlock(&data->lock);
return -EINVAL;
return ret;
}
*val = sign_extend32(ret, 7);
stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
ret = stk8312_set_mode(data,
data->mode & (~STK8312_MODE_ACTIVE));
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = stk8312_scale_table[data->range - 1][0];
@ -418,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct stk8312_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
u8 buffer[STK8312_ALL_CHANNEL_SIZE];
mutex_lock(&data->lock);
/*
@ -429,18 +445,15 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8312_REG_XOUT,
STK8312_ALL_CHANNEL_SIZE,
buffer);
data->buffer);
if (ret < STK8312_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
mutex_unlock(&data->lock);
goto err;
}
data->buffer[0] = buffer[0];
data->buffer[1] = buffer[1];
data->buffer[2] = buffer[2];
} else {
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
indio_dev->masklength) {
ret = stk8312_read_accel(data, bit);
if (ret < 0) {
mutex_unlock(&data->lock);
@ -547,11 +560,12 @@ static int stk8312_probe(struct i2c_client *client,
return ret;
}
data->sample_rate_idx = STK8312_SR_400HZ_IDX;
ret = stk8312_set_range(data, 1);
ret = stk8312_set_range(data, STK8312_RNG_6G);
if (ret < 0)
return ret;
ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE);
ret = stk8312_set_mode(data,
STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE);
if (ret < 0)
return ret;
@ -606,7 +620,7 @@ static int stk8312_probe(struct i2c_client *client,
goto err_buffer_cleanup;
}
return ret;
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
@ -662,6 +676,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = {
{"STK8312", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
static const struct acpi_device_id stk8312_acpi_id[] = {
{"STK8312", 0},
@ -672,7 +687,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
static struct i2c_driver stk8312_driver = {
.driver = {
.name = "stk8312",
.name = STK8312_DRIVER_NAME,
.pm = STK8312_PM_OPS,
.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
},

View File

@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = {
{"stk8ba50", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
static const struct acpi_device_id stk8ba50_acpi_id[] = {
{"STK8BA50", 0},

View File

@ -228,8 +228,8 @@ config MCP320X
depends on SPI
help
Say yes here to build support for Microchip Technology's
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or
MCP3208 analog to digital converter.
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204,
MCP3208 or MCP3301 analog to digital converter.
This driver can also be built as a module. If so, the module will be
called mcp320x.

View File

@ -26,7 +26,7 @@
#define BERLIN2_SM_CTRL 0x14
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */
#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
@ -53,14 +53,14 @@
#define BERLIN2_SM_ADC_MASK 0x3ff
#define BERLIN2_SM_ADC_STATUS 0x1c
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
#define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16)
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16)
#define BERLIN2_SM_TSEN_STATUS 0x24
#define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
#define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
#define BERLIN2_SM_TSEN_DATA 0x28
#define BERLIN2_SM_TSEN_MASK 0xfff
#define BERLIN2_SM_TSEN_MASK GENMASK(9, 0)
#define BERLIN2_SM_TSEN_CTRL 0x74
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
@ -86,7 +86,7 @@ struct berlin2_adc_priv {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static struct iio_chan_spec berlin2_adc_channels[] = {
static const struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */
@ -103,7 +103,6 @@ static struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */
IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */
};
#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels)
static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
{
@ -221,7 +220,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
return temp;
if (temp > 2047)
temp = -(4096 - temp);
temp -= 4096;
/* Convert to milli Celsius */
*val = ((temp * 100000) / 264 - 270000);
@ -286,8 +285,7 @@ static int berlin2_adc_probe(struct platform_device *pdev)
int irq, tsen_irq;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct berlin2_adc_priv));
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
@ -301,11 +299,11 @@ static int berlin2_adc_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "adc");
if (irq < 0)
return -ENODEV;
return irq;
tsen_irq = platform_get_irq_byname(pdev, "tsen");
if (tsen_irq < 0)
return -ENODEV;
return tsen_irq;
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
pdev->dev.driver->name, indio_dev);
@ -325,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &berlin2_adc_info;
indio_dev->num_channels = BERLIN2_N_CHANNELS;
indio_dev->channels = berlin2_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels);
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,

View File

@ -25,6 +25,7 @@
* http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201
* http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
* http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301
*
* 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
@ -47,6 +48,7 @@ enum {
mcp3202,
mcp3204,
mcp3208,
mcp3301,
};
struct mcp320x_chip_info {
@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index,
switch (device_index) {
case mcp3001:
case mcp3201:
case mcp3301:
return 0;
case mcp3002:
case mcp3202:
@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
adc->tx_buf = mcp320x_channel_to_tx_data(device_index,
channel, differential);
if (device_index != mcp3001 && device_index != mcp3201) {
if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) {
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
case mcp3204:
case mcp3208:
return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
case mcp3301:
return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12);
default:
return -EINVAL;
}
@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
.num_channels = ARRAY_SIZE(mcp3208_channels),
.resolution = 12
},
[mcp3301] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 13
},
};
static int mcp320x_probe(struct spi_device *spi)
@ -368,6 +378,9 @@ static const struct of_device_id mcp320x_dt_ids[] = {
}, {
.compatible = "mcp3208",
.data = &mcp320x_chip_infos[mcp3208],
}, {
.compatible = "mcp3301",
.data = &mcp320x_chip_infos[mcp3301],
}, {
}
};
@ -383,6 +396,7 @@ static const struct spi_device_id mcp320x_id[] = {
{ "mcp3202", mcp3202 },
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ "mcp3301", mcp3301 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);

View File

@ -68,6 +68,9 @@
#define VF610_ADC_CLK_DIV8 0x60
#define VF610_ADC_CLK_MASK 0x60
#define VF610_ADC_ADLSMP_LONG 0x10
#define VF610_ADC_ADSTS_SHORT 0x100
#define VF610_ADC_ADSTS_NORMAL 0x200
#define VF610_ADC_ADSTS_LONG 0x300
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
@ -98,6 +101,8 @@
#define VF610_ADC_CALF 0x2
#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
#define DEFAULT_SAMPLE_TIME 1000
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET,
VF610_ADCIOC_ALTCLK_SET,
@ -124,6 +129,17 @@ enum conversion_mode_sel {
VF610_ADC_CONV_LOW_POWER,
};
enum lst_adder_sel {
VF610_ADCK_CYCLES_3,
VF610_ADCK_CYCLES_5,
VF610_ADCK_CYCLES_7,
VF610_ADCK_CYCLES_9,
VF610_ADCK_CYCLES_13,
VF610_ADCK_CYCLES_17,
VF610_ADCK_CYCLES_21,
VF610_ADCK_CYCLES_25,
};
struct vf610_adc_feature {
enum clk_sel clk_sel;
enum vol_ref vol_ref;
@ -132,6 +148,8 @@ struct vf610_adc_feature {
int clk_div;
int sample_rate;
int res_mode;
u32 lst_adder_index;
u32 default_sample_time;
bool calibration;
bool ovwren;
@ -155,11 +173,13 @@ struct vf610_adc {
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
u32 adck_period, lst_addr_min;
int divisor, i;
adck_rate = info->max_adck_rate[adc_feature->conv_mode];
@ -173,6 +193,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
adc_feature->clk_div = 8;
}
/*
* Determine the long sample time adder value to be used based
* on the default minimum sample time provided.
*/
adck_period = NSEC_PER_SEC / adck_rate;
lst_addr_min = adc_feature->default_sample_time / adck_period;
for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
if (vf610_lst_adder[i] > lst_addr_min) {
adc_feature->lst_adder_index = i;
break;
}
}
/*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
* SFCAdder: fixed to 6 ADCK cycles
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
* LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
* LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
*/
adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
adck_rate / (6 + vf610_hw_avgs[i] *
(25 + vf610_lst_adder[adc_feature->lst_adder_index]));
}
static inline void vf610_adc_cfg_init(struct vf610_adc *info)
@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
break;
}
/* Use the short sample mode */
cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
/*
* Set ADLSMP and ADSTS based on the Long Sample Time Adder value
* determined.
*/
switch (adc_feature->lst_adder_index) {
case VF610_ADCK_CYCLES_3:
break;
case VF610_ADCK_CYCLES_5:
cfg_data |= VF610_ADC_ADSTS_SHORT;
break;
case VF610_ADCK_CYCLES_7:
cfg_data |= VF610_ADC_ADSTS_NORMAL;
break;
case VF610_ADCK_CYCLES_9:
cfg_data |= VF610_ADC_ADSTS_LONG;
break;
case VF610_ADCK_CYCLES_13:
cfg_data |= VF610_ADC_ADLSMP_LONG;
break;
case VF610_ADCK_CYCLES_17:
cfg_data |= VF610_ADC_ADLSMP_LONG;
cfg_data |= VF610_ADC_ADSTS_SHORT;
break;
case VF610_ADCK_CYCLES_21:
cfg_data |= VF610_ADC_ADLSMP_LONG;
cfg_data |= VF610_ADC_ADSTS_NORMAL;
break;
case VF610_ADCK_CYCLES_25:
cfg_data |= VF610_ADC_ADLSMP_LONG;
cfg_data |= VF610_ADC_ADSTS_NORMAL;
break;
default:
dev_err(info->dev, "error in sample time select\n");
}
/* update hardware average selection */
cfg_data &= ~VF610_ADC_AVGS_MASK;
@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev)
of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
info->max_adck_rate, 3);
ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time",
&info->adc_feature.default_sample_time);
if (ret)
info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME;
platform_set_drvdata(pdev, indio_dev);
init_completion(&info->completion);

View File

@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
int err, i = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (sdata->sensor_settings->fs.addr == 0)
return 0;
err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
if (err < 0)
goto st_accel_set_fullscale_error;
@ -479,46 +482,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list,
const struct st_sensor_settings *sensor_settings)
{
u8 wai;
int i, n, err;
u8 wai;
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < num_sensors_list; i++) {
for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
if (strcmp(indio_dev->name,
sensor_settings[i].sensors_supported[n]) == 0) {
break;
}
}
if (n < ST_SENSORS_MAX_4WAI)
break;
}
if (i == num_sensors_list) {
dev_err(&indio_dev->dev, "device name %s not recognized.\n",
indio_dev->name);
return -ENODEV;
}
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
sensor_settings[i].wai_addr, &wai);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
goto read_wai_error;
return err;
}
for (i = 0; i < num_sensors_list; i++) {
if (sensor_settings[i].wai == wai)
break;
}
if (i == num_sensors_list)
goto device_not_supported;
for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) {
if (strcmp(indio_dev->name,
&sensor_settings[i].sensors_supported[n][0]) == 0)
break;
}
if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) {
dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch",
indio_dev->name, wai);
goto sensor_name_mismatch;
if (sensor_settings[i].wai != wai) {
dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
indio_dev->name, wai);
return -EINVAL;
}
sdata->sensor_settings =
(struct st_sensor_settings *)&sensor_settings[i];
return i;
device_not_supported:
dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
sensor_name_mismatch:
err = -ENODEV;
read_wai_error:
return err;
}
EXPORT_SYMBOL(st_sensors_check_device_support);

View File

@ -53,7 +53,8 @@ config ADXRS450
config BMG160
tristate "BOSCH BMG160 Gyro Sensor"
depends on I2C
select IIO_TRIGGERED_BUFFER if IIO_BUFFER
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
driver. This driver also supports BMI055 gyroscope.

View File

@ -473,6 +473,7 @@ enum adis16136_id {
ID_ADIS16133,
ID_ADIS16135,
ID_ADIS16136,
ID_ADIS16137,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
},
[ID_ADIS16137] = {
.precision = IIO_DEGREE_TO_RAD(1000),
.fullscale = 24609,
},
};
static int adis16136_probe(struct spi_device *spi)
@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = {
{ "adis16133", ID_ADIS16133 },
{ "adis16135", ID_ADIS16135 },
{ "adis16136", ID_ADIS16136 },
{ "adis16137", ID_ADIS16137 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);

View File

@ -101,19 +101,24 @@
#define ADIS16260_SCAN_TEMP 3
#define ADIS16260_SCAN_ANGL 4
/* Power down the device */
static int adis16260_stop_device(struct iio_dev *indio_dev)
{
struct adis *adis = iio_priv(indio_dev);
int ret;
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
struct adis16260_chip_info {
unsigned int gyro_max_val;
unsigned int gyro_max_scale;
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
if (ret)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
struct adis16260 {
const struct adis16260_chip_info *info;
return ret;
}
struct adis adis;
};
enum adis16260_type {
ADIS16251,
ADIS16260,
ADIS16266,
};
static const struct iio_chan_spec adis16260_channels[] = {
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(5),
};
static const struct iio_chan_spec adis16266_channels[] = {
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_CALIBSCALE),
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct adis16260_chip_info adis16260_chip_info_table[] = {
[ADIS16251] = {
.gyro_max_scale = 80,
.gyro_max_val = IIO_RAD_TO_DEGREE(4368),
.channels = adis16260_channels,
.num_channels = ARRAY_SIZE(adis16260_channels),
},
[ADIS16260] = {
.gyro_max_scale = 320,
.gyro_max_val = IIO_RAD_TO_DEGREE(4368),
.channels = adis16260_channels,
.num_channels = ARRAY_SIZE(adis16260_channels),
},
[ADIS16266] = {
.gyro_max_scale = 14000,
.gyro_max_val = IIO_RAD_TO_DEGREE(3357),
.channels = adis16266_channels,
.num_channels = ARRAY_SIZE(adis16266_channels),
},
};
/* Power down the device */
static int adis16260_stop_device(struct iio_dev *indio_dev)
{
struct adis16260 *adis16260 = iio_priv(indio_dev);
int ret;
u16 val = ADIS16260_SLP_CNT_POWER_OFF;
ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val);
if (ret)
dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
return ret;
}
static const u8 adis16260_addresses[][2] = {
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
};
@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
struct adis *adis = iio_priv(indio_dev);
struct adis16260 *adis16260 = iio_priv(indio_dev);
const struct adis16260_chip_info *info = adis16260->info;
struct adis *adis = &adis16260->adis;
int ret;
u8 addr;
s16 val16;
@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
if (spi_get_device_id(adis->spi)->driver_data) {
/* 0.01832 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(18320);
} else {
/* 0.07326 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(73260);
}
return IIO_VAL_INT_PLUS_MICRO;
*val = info->gyro_max_scale;
*val2 = info->gyro_max_val;
return IIO_VAL_FRACTIONAL;
case IIO_INCLI:
*val = 0;
*val2 = IIO_DEGREE_TO_RAD(36630);
@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
struct adis *adis = iio_priv(indio_dev);
struct adis16260 *adis16260 = iio_priv(indio_dev);
struct adis *adis = &adis16260->adis;
int ret;
u8 addr;
u8 t;
@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = {
static int adis16260_probe(struct spi_device *spi)
{
const struct spi_device_id *id;
struct adis16260 *adis16260;
struct iio_dev *indio_dev;
struct adis *adis;
int ret;
id = spi_get_device_id(spi);
if (!id)
return -ENODEV;
/* setup the industrialio driver allocated elements */
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260));
if (!indio_dev)
return -ENOMEM;
adis = iio_priv(indio_dev);
adis16260 = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
indio_dev->name = spi_get_device_id(spi)->name;
adis16260->info = &adis16260_chip_info_table[id->driver_data];
indio_dev->name = id->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info;
indio_dev->channels = adis16260_channels;
indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
indio_dev->channels = adis16260->info->channels;
indio_dev->num_channels = adis16260->info->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(adis, indio_dev, spi, &adis16260_data);
ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data);
if (ret)
return ret;
ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL);
if (ret)
return ret;
/* Get the device into a sane initial state */
ret = adis_initial_startup(adis);
ret = adis_initial_startup(&adis16260->adis);
if (ret)
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi)
return 0;
error_cleanup_buffer_trigger:
adis_cleanup_buffer_and_trigger(adis, indio_dev);
adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
return ret;
}
static int adis16260_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis *adis = iio_priv(indio_dev);
struct adis16260 *adis16260 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev);
adis_cleanup_buffer_and_trigger(adis, indio_dev);
adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
return 0;
}
@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi)
* support for the on chip filtering.
*/
static const struct spi_device_id adis16260_id[] = {
{"adis16260", 0},
{"adis16265", 0},
{"adis16250", 0},
{"adis16255", 0},
{"adis16251", 1},
{"adis16260", ADIS16260},
{"adis16265", ADIS16260},
{"adis16266", ADIS16266},
{"adis16250", ADIS16260},
{"adis16255", ADIS16260},
{"adis16251", ADIS16251},
{}
};
MODULE_DEVICE_TABLE(spi, adis16260_id);

View File

@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = {
static const struct st_sensor_settings st_gyro_sensors_settings[] = {
{
.wai = ST_GYRO_1_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3G4200D_GYRO_DEV_NAME,
[1] = LSM330DL_GYRO_DEV_NAME,
@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
},
{
.wai = ST_GYRO_2_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
[1] = LSM330D_GYRO_DEV_NAME,
@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
},
{
.wai = ST_GYRO_3_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
},

View File

@ -33,6 +33,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/timekeeping.h>
#include <linux/iio/iio.h>
@ -46,7 +47,8 @@
* Note that when reading the sensor actually 84 edges are detected, but
* since the last edge is not significant, we only store 83:
*/
#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
DHT11_EDGES_PREAMBLE + 1)
/* Data transmission timing (nano seconds) */
#define DHT11_START_TRANSMISSION 18 /* ms */
@ -62,6 +64,7 @@ struct dht11 {
int irq;
struct completion completion;
/* The iio sysfs interface doesn't prevent concurrent reads: */
struct mutex lock;
s64 timestamp;
@ -87,32 +90,20 @@ static unsigned char dht11_decode_byte(int *timing, int threshold)
return ret;
}
static int dht11_decode(struct dht11 *dht11, int offset)
static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
{
int i, t, timing[DHT11_BITS_PER_READ], threshold,
timeres = DHT11_SENSOR_RESPONSE;
int i, t, timing[DHT11_BITS_PER_READ], threshold;
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
/* Calculate timestamp resolution */
for (i = 1; i < dht11->num_edges; ++i) {
t = dht11->edges[i].ts - dht11->edges[i-1].ts;
if (t > 0 && t < timeres)
timeres = t;
}
if (2*timeres > DHT11_DATA_BIT_HIGH) {
pr_err("dht11: timeresolution %d too bad for decoding\n",
timeres);
return -EIO;
}
threshold = DHT11_DATA_BIT_HIGH / timeres;
if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold)
if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)
pr_err("dht11: WARNING: decoding ambiguous\n");
/* scale down with timeres and check validity */
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)
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 */
timing[i] = t / timeres;
}
@ -126,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
return -EIO;
dht11->timestamp = iio_get_time_ns();
dht11->timestamp = ktime_get_real_ns();
if (hum_int < 20) { /* DHT22 */
dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
((temp_int & 0x80) ? -100 : 100);
@ -154,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
/* TODO: Consider making the handler safe for IRQ sharing */
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
dht11->edges[dht11->num_edges].ts = ktime_get_real_ns();
dht11->edges[dht11->num_edges++].value =
gpio_get_value(dht11->gpio);
@ -166,14 +157,26 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
}
static int dht11_read_raw(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
const struct iio_chan_spec *chan,
int *val, int *val2, long m)
{
struct dht11 *dht11 = iio_priv(iio_dev);
int ret;
int ret, timeres;
mutex_lock(&dht11->lock);
if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {
timeres = ktime_get_resolution_ns();
if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
dev_err(dht11->dev, "timeresolution %dns too low\n",
timeres);
/* In theory a better clock could become available
* at some point ... and there is no error code
* that really fits better.
*/
ret = -EAGAIN;
goto err;
}
reinit_completion(&dht11->completion);
dht11->num_edges = 0;
@ -192,13 +195,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
goto err;
ret = wait_for_completion_killable_timeout(&dht11->completion,
HZ);
HZ);
free_irq(dht11->irq, iio_dev);
if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
dev_err(&iio_dev->dev,
"Only %d signal edges detected\n",
"Only %d signal edges detected\n",
dht11->num_edges);
ret = -ETIMEDOUT;
}
@ -206,9 +209,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
goto err;
ret = dht11_decode(dht11,
dht11->num_edges == DHT11_EDGES_PER_READ ?
dht11->num_edges == DHT11_EDGES_PER_READ ?
DHT11_EDGES_PREAMBLE :
DHT11_EDGES_PREAMBLE - 2);
DHT11_EDGES_PREAMBLE - 2,
timeres);
if (ret)
goto err;
}
@ -261,9 +265,10 @@ static int dht11_probe(struct platform_device *pdev)
dht11 = iio_priv(iio);
dht11->dev = dev;
dht11->gpio = ret = of_get_gpio(node, 0);
ret = of_get_gpio(node, 0);
if (ret < 0)
return ret;
dht11->gpio = ret;
ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
if (ret)
return ret;
@ -274,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev)
return -EINVAL;
}
dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1;
dht11->num_edges = -1;
platform_set_drvdata(pdev, iio);

View File

@ -139,7 +139,9 @@ enum adis16400_chip_variant {
ADIS16360,
ADIS16362,
ADIS16364,
ADIS16367,
ADIS16400,
ADIS16445,
ADIS16448,
};
@ -622,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16445_channels[] = {
ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16),
ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16),
ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16),
ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16),
ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct iio_chan_spec adis16448_channels[] = {
ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
@ -696,7 +709,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16300] = {
.channels = adis16300_channels,
.num_channels = ARRAY_SIZE(adis16300_channels),
.flags = ADIS16400_HAS_SLOW_MODE,
.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
ADIS16400_HAS_SERIAL_NUMBER,
.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 5884,
.temp_scale_nano = 140000000, /* 0.14 C */
@ -763,6 +777,18 @@ static struct adis16400_chip_info adis16400_chips[] = {
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
},
[ADIS16367] = {
.channels = adis16350_channels,
.num_channels = ARRAY_SIZE(adis16350_channels),
.flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
ADIS16400_HAS_SERIAL_NUMBER,
.gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */
.accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
.temp_scale_nano = 136000000, /* 0.136 C */
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
},
[ADIS16400] = {
.channels = adis16400_channels,
.num_channels = ARRAY_SIZE(adis16400_channels),
@ -774,13 +800,26 @@ static struct adis16400_chip_info adis16400_chips[] = {
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
},
[ADIS16445] = {
.channels = adis16445_channels,
.num_channels = ARRAY_SIZE(adis16445_channels),
.flags = ADIS16400_HAS_PROD_ID |
ADIS16400_HAS_SERIAL_NUMBER |
ADIS16400_BURST_DIAG_STAT,
.gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
.accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */
.temp_scale_nano = 73860000, /* 0.07386 C */
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
.set_freq = adis16334_set_freq,
.get_freq = adis16334_get_freq,
},
[ADIS16448] = {
.channels = adis16448_channels,
.num_channels = ARRAY_SIZE(adis16448_channels),
.flags = ADIS16400_HAS_PROD_ID |
ADIS16400_HAS_SERIAL_NUMBER |
ADIS16400_BURST_DIAG_STAT,
.gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
.gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */
.accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
.temp_scale_nano = 73860000, /* 0.07386 C */
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
@ -926,6 +965,7 @@ static int adis16400_remove(struct spi_device *spi)
static const struct spi_device_id adis16400_id[] = {
{"adis16300", ADIS16300},
{"adis16305", ADIS16300},
{"adis16334", ADIS16334},
{"adis16350", ADIS16350},
{"adis16354", ADIS16350},
@ -934,8 +974,10 @@ static const struct spi_device_id adis16400_id[] = {
{"adis16362", ADIS16362},
{"adis16364", ADIS16364},
{"adis16365", ADIS16360},
{"adis16367", ADIS16367},
{"adis16400", ADIS16400},
{"adis16405", ADIS16400},
{"adis16445", ADIS16445},
{"adis16448", ADIS16448},
{}
};

View File

@ -110,6 +110,10 @@
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int gyro_max_val;
unsigned int gyro_max_scale;
unsigned int accel_max_val;
unsigned int accel_max_scale;
};
struct adis16480 {
@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
static int adis16480_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct adis16480 *st = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = 0;
*val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
return IIO_VAL_INT_PLUS_MICRO;
*val = st->chip_info->gyro_max_scale;
*val2 = st->chip_info->gyro_max_val;
return IIO_VAL_FRACTIONAL;
case IIO_ACCEL:
*val = 0;
*val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
return IIO_VAL_INT_PLUS_MICRO;
*val = st->chip_info->accel_max_scale;
*val2 = st->chip_info->accel_max_val;
return IIO_VAL_FRACTIONAL;
case IIO_MAGN:
*val = 0;
*val2 = 100; /* 0.0001 gauss */
@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
/*
* storing the value in rad/degree and the scale in degree
* gives us the result in rad and better precession than
* storing the scale directly in rad.
*/
.gyro_max_val = IIO_RAD_TO_DEGREE(22887),
.gyro_max_scale = 300,
.accel_max_val = IIO_M_S_2_TO_G(21973),
.accel_max_scale = 18,
},
[ADIS16480] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(12500),
.accel_max_scale = 5,
},
[ADIS16485] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(20000),
.accel_max_scale = 5,
},
[ADIS16488] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(22500),
.accel_max_scale = 18,
},
};

View File

@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = kmx61_gpio_probe(client, data);
if (client->irq >= 0) {
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kmx61_data_rdy_trig_poll,
kmx61_event_handler,
@ -1445,10 +1445,10 @@ err_iio_unregister_mag:
err_iio_unregister_acc:
iio_device_unregister(data->acc_indio_dev);
err_buffer_cleanup_mag:
if (client->irq >= 0)
if (client->irq > 0)
iio_triggered_buffer_cleanup(data->mag_indio_dev);
err_buffer_cleanup_acc:
if (client->irq >= 0)
if (client->irq > 0)
iio_triggered_buffer_cleanup(data->acc_indio_dev);
err_trigger_unregister_motion:
iio_trigger_unregister(data->motion_trig);
@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client)
iio_device_unregister(data->acc_indio_dev);
iio_device_unregister(data->mag_indio_dev);
if (client->irq >= 0) {
if (client->irq > 0) {
iio_triggered_buffer_cleanup(data->acc_indio_dev);
iio_triggered_buffer_cleanup(data->mag_indio_dev);
iio_trigger_unregister(data->acc_dready_trig);

View File

@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
* @filp: File structure pointer for the char device
* @buf: Destination buffer for iio buffer read
* @n: First n bytes to read
* @f_ps: Long offset provided by the user as a seek position
*
* This function relies on all buffer implementations having an
* iio_buffer as their first element.
*
* Return: negative values corresponding to error codes or ret != 0
* for ending the reading activity
**/
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps)
@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
/**
* iio_buffer_poll() - poll the buffer to find out if it has data
* @filp: File structure pointer for device access
* @wait: Poll table structure pointer for which the driver adds
* a wait queue
*
* Return: (POLLIN | POLLRDNORM) if data is available for reading
* or 0 for other cases
*/
unsigned int iio_buffer_poll(struct file *filp,
struct poll_table_struct *wait)
@ -151,7 +164,7 @@ unsigned int iio_buffer_poll(struct file *filp,
struct iio_buffer *rb = indio_dev->buffer;
if (!indio_dev->info)
return -ENODEV;
return 0;
poll_wait(filp, &rb->pollq, wait);
if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0))
@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
EXPORT_SYMBOL_GPL(iio_scan_mask_query);
/**
* struct iio_demux_table() - table describing demux memcpy ops
* struct iio_demux_table - table describing demux memcpy ops
* @from: index to copy from
* @to: index to copy to
* @length: how many bytes to copy

View File

@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write);
/**
* iio_format_value() - Formats a IIO value into its string representation
* @buf: The buffer to which the formated value gets written
* @type: One of the IIO_VAL_... constants. This decides how the val and val2
* parameters are formatted.
* @vals: pointer to the values, exact meaning depends on the type parameter.
* @buf: The buffer to which the formatted value gets written
* @type: One of the IIO_VAL_... constants. This decides how the val
* and val2 parameters are formatted.
* @size: Number of IIO value entries contained in vals
* @vals: Pointer to the values, exact meaning depends on the
* type parameter.
*
* Return: 0 by default, a negative number on failure or the
* total number of characters written for a type that belongs
* to the IIO_VAL_... constant.
*/
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
{
@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free);
/**
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
* @inode: Inode structure for identifying the device in the file system
* @filp: File structure for iio device used to keep and later access
* private data
*
* Return: 0 on success or -EBUSY if the device is already opened
**/
static int iio_chrdev_open(struct inode *inode, struct file *filp)
{
@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
/**
* iio_chrdev_release() - chrdev file close buffer access and ioctls
**/
* @inode: Inode structure pointer for the char device
* @filp: File structure pointer for the char device
*
* Return: 0 for successful release
*/
static int iio_chrdev_release(struct inode *inode, struct file *filp)
{
struct iio_dev *indio_dev = container_of(inode->i_cdev,

View File

@ -32,6 +32,7 @@
* @dev_attr_list: list of event interface sysfs attribute
* @flags: file operations related flags including busy flag.
* @group: event interface sysfs attribute group
* @read_lock: lock to protect kfifo read operations
*/
struct iio_event_interface {
wait_queue_head_t wait;
@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event);
/**
* iio_event_poll() - poll the event queue to find out if it has data
* @filep: File structure pointer to identify the device
* @wait: Poll table pointer to add the wait queue on
*
* Return: (POLLIN | POLLRDNORM) if data is available for reading
* or a negative error code on failure
*/
static unsigned int iio_event_poll(struct file *filep,
struct poll_table_struct *wait)
@ -84,7 +90,7 @@ static unsigned int iio_event_poll(struct file *filep,
unsigned int events = 0;
if (!indio_dev->info)
return -ENODEV;
return events;
poll_wait(filep, &ev_int->wait, wait);

View File

@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock);
/**
* iio_trigger_read_name() - retrieve useful identifying name
**/
* @dev: device associated with the iio_trigger
* @attr: pointer to the device_attribute structure that is
* being processed
* @buf: buffer to print the name into
*
* Return: a negative number on failure or the number of written
* characters on success.
*/
static ssize_t iio_trigger_read_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
/**
* iio_trigger_read_current() - trigger consumer sysfs query current trigger
* @dev: device associated with an industrial I/O device
* @attr: pointer to the device_attribute structure that
* is being processed
* @buf: buffer where the current trigger name will be printed into
*
* For trigger consumers the current_trigger interface allows the trigger
* used by the device to be queried.
**/
*
* Return: a negative number on failure, the number of characters written
* on success or 0 if no trigger is available
*/
static ssize_t iio_trigger_read_current(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev,
/**
* iio_trigger_write_current() - trigger consumer sysfs set current trigger
* @dev: device associated with an industrial I/O device
* @attr: device attribute that is being processed
* @buf: string buffer that holds the name of the trigger
* @len: length of the trigger name held by buf
*
* For trigger consumers the current_trigger interface allows the trigger
* used for this device to be specified at run time based on the trigger's
* name.
**/
*
* Return: negative error code on failure or length of the buffer
* on success
*/
static ssize_t iio_trigger_write_current(struct device *dev,
struct device_attribute *attr,
const char *buf,

View File

@ -210,6 +210,27 @@ config LTR501
This driver can also be built as a module. If so, the module
will be called ltr501.
config OPT3001
tristate "Texas Instruments OPT3001 Light Sensor"
depends on I2C
help
If you say Y or M here, you get support for Texas Instruments
OPT3001 Ambient Light Sensor.
If built as a dynamically linked module, it will be called
opt3001.
config PA12203001
tristate "TXC PA12203001 light and proximity sensor"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for the TXC PA12203001
ambient light and proximity sensor.
This driver can also be built as a module. If so, the module
will be called pa12203001.
config STK3310
tristate "STK3310 ALS and proximity sensor"
depends on I2C

View File

@ -19,6 +19,8 @@ obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_STK3310) += stk3310.o

View File

@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = {
* to acpi_als_channels[], the evt_buffer below will grow
* automatically.
*/
#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
#define EVT_BUFFER_SIZE \
(sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32)))
#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
#define ACPI_ALS_EVT_BUFFER_SIZE \
(sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32)))
struct acpi_als {
struct acpi_device *device;
struct mutex lock;
s32 evt_buffer[EVT_BUFFER_SIZE];
s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE];
};
/*
* All types of properties the ACPI0008 block can report. The ALI, ALC, ALT
* and ALP can all be handled by als_read_value() below, while the ALR is
* and ALP can all be handled by acpi_als_read_value() below, while the ALR is
* special.
*
* The _ALR property returns tables that can be used to fine-tune the values
@ -93,7 +93,7 @@ struct acpi_als {
#define ACPI_ALS_POLLING "_ALP"
#define ACPI_ALS_TABLES "_ALR"
static int als_read_value(struct acpi_als *als, char *prop, s32 *val)
static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val)
{
unsigned long long temp_val;
acpi_status status;
@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
mutex_lock(&als->lock);
memset(buffer, 0, EVT_BUFFER_SIZE);
memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE);
switch (event) {
case ACPI_ALS_NOTIFY_ILLUMINANCE:
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
if (ret < 0)
goto out;
*buffer++ = val;
@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_LIGHT)
return -EINVAL;
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
if (ret < 0)
return ret;

View File

@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = {
{ .compatible = "capella,cm32181" },
{ }
};
MODULE_DEVICE_TABLE(of, cm32181_of_match);
static struct i2c_driver cm32181_driver = {
.driver = {

View File

@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = {
{.compatible = "capella,cm3232"},
{}
};
MODULE_DEVICE_TABLE(of, cm3232_of_match);
static struct i2c_driver cm3232_driver = {
.driver = {

View File

@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = {
{ .compatible = "capella,cm36651" },
{ }
};
MODULE_DEVICE_TABLE(of, cm36651_of_match);
static struct i2c_driver cm36651_driver = {
.driver = {

View File

@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = {
{ .compatible = "sharp,gp2ap020a00f" },
{ }
};
MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
#endif
static struct i2c_driver gp2ap020a00f_driver = {

View File

@ -0,0 +1,804 @@
/**
* opt3001.c - Texas Instruments OPT3001 Light Sensor
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Andreas Dannenberg <dannenberg@ti.com>
* Based on previous work from: Felipe Balbi <balbi@ti.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 of the License
* as published by the Free Software Foundation.
*
* 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/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define OPT3001_RESULT 0x00
#define OPT3001_CONFIGURATION 0x01
#define OPT3001_LOW_LIMIT 0x02
#define OPT3001_HIGH_LIMIT 0x03
#define OPT3001_MANUFACTURER_ID 0x7e
#define OPT3001_DEVICE_ID 0x7f
#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12)
#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12)
#define OPT3001_CONFIGURATION_CT BIT(11)
#define OPT3001_CONFIGURATION_M_MASK (3 << 9)
#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9)
#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9)
#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */
#define OPT3001_CONFIGURATION_OVF BIT(8)
#define OPT3001_CONFIGURATION_CRF BIT(7)
#define OPT3001_CONFIGURATION_FH BIT(6)
#define OPT3001_CONFIGURATION_FL BIT(5)
#define OPT3001_CONFIGURATION_L BIT(4)
#define OPT3001_CONFIGURATION_POL BIT(3)
#define OPT3001_CONFIGURATION_ME BIT(2)
#define OPT3001_CONFIGURATION_FC_MASK (3 << 0)
/* The end-of-conversion enable is located in the low-limit register */
#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000
#define OPT3001_REG_EXPONENT(n) ((n) >> 12)
#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff)
/*
* Time to wait for conversion result to be ready. The device datasheet
* worst-case max value is 880ms. Add some slack to be on the safe side.
*/
#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000)
struct opt3001 {
struct i2c_client *client;
struct device *dev;
struct mutex lock;
u16 ok_to_ignore_lock:1;
u16 result_ready:1;
wait_queue_head_t result_ready_queue;
u16 result;
u32 int_time;
u32 mode;
u16 high_thresh_mantissa;
u16 low_thresh_mantissa;
u8 high_thresh_exp;
u8 low_thresh_exp;
};
struct opt3001_scale {
int val;
int val2;
};
static const struct opt3001_scale opt3001_scales[] = {
{
.val = 40,
.val2 = 950000,
},
{
.val = 81,
.val2 = 900000,
},
{
.val = 163,
.val2 = 800000,
},
{
.val = 327,
.val2 = 600000,
},
{
.val = 655,
.val2 = 200000,
},
{
.val = 1310,
.val2 = 400000,
},
{
.val = 2620,
.val2 = 800000,
},
{
.val = 5241,
.val2 = 600000,
},
{
.val = 10483,
.val2 = 200000,
},
{
.val = 20966,
.val2 = 400000,
},
{
.val = 83865,
.val2 = 600000,
},
};
static int opt3001_find_scale(const struct opt3001 *opt, int val,
int val2, u8 *exponent)
{
int i;
for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) {
const struct opt3001_scale *scale = &opt3001_scales[i];
/*
* Combine the integer and micro parts for comparison
* purposes. Use milli lux precision to avoid 32-bit integer
* overflows.
*/
if ((val * 1000 + val2 / 1000) <=
(scale->val * 1000 + scale->val2 / 1000)) {
*exponent = i;
return 0;
}
}
return -EINVAL;
}
static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
u16 mantissa, int *val, int *val2)
{
int lux;
lux = 10 * (mantissa << exponent);
*val = lux / 1000;
*val2 = (lux - (*val * 1000)) * 1000;
}
static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode)
{
*reg &= ~OPT3001_CONFIGURATION_M_MASK;
*reg |= mode;
opt->mode = mode;
}
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8");
static struct attribute *opt3001_attributes[] = {
&iio_const_attr_integration_time_available.dev_attr.attr,
NULL
};
static const struct attribute_group opt3001_attribute_group = {
.attrs = opt3001_attributes,
};
static const struct iio_event_spec opt3001_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_chan_spec opt3001_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME),
.event_spec = opt3001_event_spec,
.num_event_specs = ARRAY_SIZE(opt3001_event_spec),
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2)
{
int ret;
u16 mantissa;
u16 reg;
u8 exponent;
u16 value;
/*
* Enable the end-of-conversion interrupt mechanism. Note that doing
* so will overwrite the low-level limit value however we will restore
* this value later on.
*/
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
OPT3001_LOW_LIMIT_EOC_ENABLE);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_LOW_LIMIT);
return ret;
}
/* Reset data-ready indicator flag (will be set in the IRQ routine) */
opt->result_ready = false;
/* Allow IRQ to access the device despite lock being set */
opt->ok_to_ignore_lock = true;
/* Configure for single-conversion mode and start a new conversion */
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
goto err;
}
reg = ret;
opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SINGLE);
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_CONFIGURATION);
goto err;
}
/* Wait for the IRQ to indicate the conversion is complete */
ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready,
OPT3001_RESULT_READY_TIMEOUT);
err:
/* Disallow IRQ to access the device while lock is active */
opt->ok_to_ignore_lock = false;
if (ret == 0)
return -ETIMEDOUT;
else if (ret < 0)
return ret;
/*
* Disable the end-of-conversion interrupt mechanism by restoring the
* low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note
* that selectively clearing those enable bits would affect the actual
* limit value due to bit-overlap and therefore can't be done.
*/
value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
value);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_LOW_LIMIT);
return ret;
}
exponent = OPT3001_REG_EXPONENT(opt->result);
mantissa = OPT3001_REG_MANTISSA(opt->result);
opt3001_to_iio_ret(opt, exponent, mantissa, val, val2);
return IIO_VAL_INT_PLUS_MICRO;
}
static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2)
{
*val = 0;
*val2 = opt->int_time;
return IIO_VAL_INT_PLUS_MICRO;
}
static int opt3001_set_int_time(struct opt3001 *opt, int time)
{
int ret;
u16 reg;
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
return ret;
}
reg = ret;
switch (time) {
case 100000:
reg &= ~OPT3001_CONFIGURATION_CT;
opt->int_time = 100000;
break;
case 800000:
reg |= OPT3001_CONFIGURATION_CT;
opt->int_time = 800000;
break;
default:
return -EINVAL;
}
return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg);
}
static int opt3001_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
{
struct opt3001 *opt = iio_priv(iio);
int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
if (chan->type != IIO_LIGHT)
return -EINVAL;
mutex_lock(&opt->lock);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
ret = opt3001_get_lux(opt, val, val2);
break;
case IIO_CHAN_INFO_INT_TIME:
ret = opt3001_get_int_time(opt, val, val2);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&opt->lock);
return ret;
}
static int opt3001_write_raw(struct iio_dev *iio,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct opt3001 *opt = iio_priv(iio);
int ret;
if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return -EBUSY;
if (chan->type != IIO_LIGHT)
return -EINVAL;
if (mask != IIO_CHAN_INFO_INT_TIME)
return -EINVAL;
if (val != 0)
return -EINVAL;
mutex_lock(&opt->lock);
ret = opt3001_set_int_time(opt, val2);
mutex_unlock(&opt->lock);
return ret;
}
static int opt3001_read_event_value(struct iio_dev *iio,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2)
{
struct opt3001 *opt = iio_priv(iio);
int ret = IIO_VAL_INT_PLUS_MICRO;
mutex_lock(&opt->lock);
switch (dir) {
case IIO_EV_DIR_RISING:
opt3001_to_iio_ret(opt, opt->high_thresh_exp,
opt->high_thresh_mantissa, val, val2);
break;
case IIO_EV_DIR_FALLING:
opt3001_to_iio_ret(opt, opt->low_thresh_exp,
opt->low_thresh_mantissa, val, val2);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&opt->lock);
return ret;
}
static int opt3001_write_event_value(struct iio_dev *iio,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2)
{
struct opt3001 *opt = iio_priv(iio);
int ret;
u16 mantissa;
u16 value;
u16 reg;
u8 exponent;
if (val < 0)
return -EINVAL;
mutex_lock(&opt->lock);
ret = opt3001_find_scale(opt, val, val2, &exponent);
if (ret < 0) {
dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2);
goto err;
}
mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent;
value = (exponent << 12) | mantissa;
switch (dir) {
case IIO_EV_DIR_RISING:
reg = OPT3001_HIGH_LIMIT;
opt->high_thresh_mantissa = mantissa;
opt->high_thresh_exp = exponent;
break;
case IIO_EV_DIR_FALLING:
reg = OPT3001_LOW_LIMIT;
opt->low_thresh_mantissa = mantissa;
opt->low_thresh_exp = exponent;
break;
default:
ret = -EINVAL;
goto err;
}
ret = i2c_smbus_write_word_swapped(opt->client, reg, value);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n", reg);
goto err;
}
err:
mutex_unlock(&opt->lock);
return ret;
}
static int opt3001_read_event_config(struct iio_dev *iio,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir)
{
struct opt3001 *opt = iio_priv(iio);
return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS;
}
static int opt3001_write_event_config(struct iio_dev *iio,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
struct opt3001 *opt = iio_priv(iio);
int ret;
u16 mode;
u16 reg;
if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
return 0;
if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN)
return 0;
mutex_lock(&opt->lock);
mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS
: OPT3001_CONFIGURATION_M_SHUTDOWN;
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
goto err;
}
reg = ret;
opt3001_set_mode(opt, &reg, mode);
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_CONFIGURATION);
goto err;
}
err:
mutex_unlock(&opt->lock);
return ret;
}
static const struct iio_info opt3001_info = {
.driver_module = THIS_MODULE,
.attrs = &opt3001_attribute_group,
.read_raw = opt3001_read_raw,
.write_raw = opt3001_write_raw,
.read_event_value = opt3001_read_event_value,
.write_event_value = opt3001_write_event_value,
.read_event_config = opt3001_read_event_config,
.write_event_config = opt3001_write_event_config,
};
static int opt3001_read_id(struct opt3001 *opt)
{
char manufacturer[2];
u16 device_id;
int ret;
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_MANUFACTURER_ID);
return ret;
}
manufacturer[0] = ret >> 8;
manufacturer[1] = ret & 0xff;
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_DEVICE_ID);
return ret;
}
device_id = ret;
dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0],
manufacturer[1], device_id);
return 0;
}
static int opt3001_configure(struct opt3001 *opt)
{
int ret;
u16 reg;
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
return ret;
}
reg = ret;
/* Enable automatic full-scale setting mode */
reg &= ~OPT3001_CONFIGURATION_RN_MASK;
reg |= OPT3001_CONFIGURATION_RN_AUTO;
/* Reflect status of the device's integration time setting */
if (reg & OPT3001_CONFIGURATION_CT)
opt->int_time = 800000;
else
opt->int_time = 100000;
/* Ensure device is in shutdown initially */
opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
/* Configure for latched window-style comparison operation */
reg |= OPT3001_CONFIGURATION_L;
reg &= ~OPT3001_CONFIGURATION_POL;
reg &= ~OPT3001_CONFIGURATION_ME;
reg &= ~OPT3001_CONFIGURATION_FC_MASK;
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_CONFIGURATION);
return ret;
}
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_LOW_LIMIT);
return ret;
}
opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret);
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_HIGH_LIMIT);
return ret;
}
opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret);
return 0;
}
static irqreturn_t opt3001_irq(int irq, void *_iio)
{
struct iio_dev *iio = _iio;
struct opt3001 *opt = iio_priv(iio);
int ret;
if (!opt->ok_to_ignore_lock)
mutex_lock(&opt->lock);
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
goto out;
}
if ((ret & OPT3001_CONFIGURATION_M_MASK) ==
OPT3001_CONFIGURATION_M_CONTINUOUS) {
if (ret & OPT3001_CONFIGURATION_FH)
iio_push_event(iio,
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
iio_get_time_ns());
if (ret & OPT3001_CONFIGURATION_FL)
iio_push_event(iio,
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
iio_get_time_ns());
} else if (ret & OPT3001_CONFIGURATION_CRF) {
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_RESULT);
goto out;
}
opt->result = ret;
opt->result_ready = true;
wake_up(&opt->result_ready_queue);
}
out:
if (!opt->ok_to_ignore_lock)
mutex_unlock(&opt->lock);
return IRQ_HANDLED;
}
static int opt3001_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct iio_dev *iio;
struct opt3001 *opt;
int irq = client->irq;
int ret;
iio = devm_iio_device_alloc(dev, sizeof(*opt));
if (!iio)
return -ENOMEM;
opt = iio_priv(iio);
opt->client = client;
opt->dev = dev;
mutex_init(&opt->lock);
init_waitqueue_head(&opt->result_ready_queue);
i2c_set_clientdata(client, iio);
ret = opt3001_read_id(opt);
if (ret)
return ret;
ret = opt3001_configure(opt);
if (ret)
return ret;
iio->name = client->name;
iio->channels = opt3001_channels;
iio->num_channels = ARRAY_SIZE(opt3001_channels);
iio->dev.parent = dev;
iio->modes = INDIO_DIRECT_MODE;
iio->info = &opt3001_info;
ret = devm_iio_device_register(dev, iio);
if (ret) {
dev_err(dev, "failed to register IIO device\n");
return ret;
}
ret = request_threaded_irq(irq, NULL, opt3001_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"opt3001", iio);
if (ret) {
dev_err(dev, "failed to request IRQ #%d\n", irq);
return ret;
}
return 0;
}
static int opt3001_remove(struct i2c_client *client)
{
struct iio_dev *iio = i2c_get_clientdata(client);
struct opt3001 *opt = iio_priv(iio);
int ret;
u16 reg;
free_irq(client->irq, iio);
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
if (ret < 0) {
dev_err(opt->dev, "failed to read register %02x\n",
OPT3001_CONFIGURATION);
return ret;
}
reg = ret;
opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
reg);
if (ret < 0) {
dev_err(opt->dev, "failed to write register %02x\n",
OPT3001_CONFIGURATION);
return ret;
}
return 0;
}
static const struct i2c_device_id opt3001_id[] = {
{ "opt3001", 0 },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(i2c, opt3001_id);
static const struct of_device_id opt3001_of_match[] = {
{ .compatible = "ti,opt3001" },
{ }
};
static struct i2c_driver opt3001_driver = {
.probe = opt3001_probe,
.remove = opt3001_remove,
.id_table = opt3001_id,
.driver = {
.name = "opt3001",
.of_match_table = of_match_ptr(opt3001_of_match),
.owner = THIS_MODULE,
},
};
module_i2c_driver(opt3001_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver");

View File

@ -0,0 +1,483 @@
/*
* Copyright (c) 2015 Intel Corporation
*
* Driver for TXC PA12203001 Proximity and Ambient Light Sensor.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
* To do: Interrupt support.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#define PA12203001_DRIVER_NAME "pa12203001"
#define PA12203001_REG_CFG0 0x00
#define PA12203001_REG_CFG1 0x01
#define PA12203001_REG_CFG2 0x02
#define PA12203001_REG_CFG3 0x03
#define PA12203001_REG_ADL 0x0b
#define PA12203001_REG_PDH 0x0e
#define PA12203001_REG_POFS 0x10
#define PA12203001_REG_PSET 0x11
#define PA12203001_ALS_EN_MASK BIT(0)
#define PA12203001_PX_EN_MASK BIT(1)
#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6)
#define PA12203001_AFSR_MASK GENMASK(5, 4)
#define PA12203001_AFSR_SHIFT 4
#define PA12203001_PSCAN 0x03
/* als range 31000, ps, als disabled */
#define PA12203001_REG_CFG0_DEFAULT 0x30
/* led current: 100 mA */
#define PA12203001_REG_CFG1_DEFAULT 0x20
/* ps mode: normal, interrupts not active */
#define PA12203001_REG_CFG2_DEFAULT 0xcc
#define PA12203001_REG_CFG3_DEFAULT 0x00
#define PA12203001_SLEEP_DELAY_MS 3000
#define PA12203001_CHIP_ENABLE 0xff
#define PA12203001_CHIP_DISABLE 0x00
/* available scales: corresponding to [500, 4000, 7000, 31000] lux */
static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029};
struct pa12203001_data {
struct i2c_client *client;
/* protect device states */
struct mutex lock;
bool als_enabled;
bool px_enabled;
bool als_needs_enable;
bool px_needs_enable;
struct regmap *map;
};
static const struct {
u8 reg;
u8 val;
} regvals[] = {
{PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT},
{PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT},
{PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT},
{PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT},
{PA12203001_REG_PSET, PA12203001_PSCAN},
};
static IIO_CONST_ATTR(in_illuminance_scale_available,
"0.007629 0.061036 0.106813 0.473029");
static struct attribute *pa12203001_attrs[] = {
&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group pa12203001_attr_group = {
.attrs = pa12203001_attrs,
};
static const struct iio_chan_spec pa12203001_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
static const struct regmap_range pa12203001_volatile_regs_ranges[] = {
regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1),
regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH),
};
static const struct regmap_access_table pa12203001_volatile_regs = {
.yes_ranges = pa12203001_volatile_regs_ranges,
.n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges),
};
static const struct regmap_config pa12203001_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = PA12203001_REG_PSET,
.cache_type = REGCACHE_RBTREE,
.volatile_table = &pa12203001_volatile_regs,
};
static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable)
{
int ret;
ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
PA12203001_ALS_EN_MASK, enable);
if (ret < 0)
return ret;
data->als_enabled = !!enable;
return 0;
}
static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable)
{
int ret;
ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
PA12203001_PX_EN_MASK, enable);
if (ret < 0)
return ret;
data->px_enabled = !!enable;
return 0;
}
static int pa12203001_set_power_state(struct pa12203001_data *data, bool on,
u8 mask)
{
#ifdef CONFIG_PM
int ret;
if (on && (mask & PA12203001_ALS_EN_MASK)) {
mutex_lock(&data->lock);
if (data->px_enabled) {
ret = pa12203001_als_enable(data,
PA12203001_ALS_EN_MASK);
if (ret < 0)
goto err;
} else {
data->als_needs_enable = true;
}
mutex_unlock(&data->lock);
}
if (on && (mask & PA12203001_PX_EN_MASK)) {
mutex_lock(&data->lock);
if (data->als_enabled) {
ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
if (ret < 0)
goto err;
} else {
data->px_needs_enable = true;
}
mutex_unlock(&data->lock);
}
if (on) {
ret = pm_runtime_get_sync(&data->client->dev);
if (ret < 0)
pm_runtime_put_noidle(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
}
return ret;
err:
mutex_unlock(&data->lock);
return ret;
#endif
return 0;
}
static int pa12203001_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct pa12203001_data *data = iio_priv(indio_dev);
int ret;
u8 dev_mask;
unsigned int reg_byte;
__le16 reg_word;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
dev_mask = PA12203001_ALS_EN_MASK;
ret = pa12203001_set_power_state(data, true, dev_mask);
if (ret < 0)
return ret;
/*
* ALS ADC value is stored in registers
* PA12203001_REG_ADL and in PA12203001_REG_ADL + 1.
*/
ret = regmap_bulk_read(data->map, PA12203001_REG_ADL,
&reg_word, 2);
if (ret < 0)
goto reg_err;
*val = le16_to_cpu(reg_word);
ret = pa12203001_set_power_state(data, false, dev_mask);
if (ret < 0)
return ret;
break;
case IIO_PROXIMITY:
dev_mask = PA12203001_PX_EN_MASK;
ret = pa12203001_set_power_state(data, true, dev_mask);
if (ret < 0)
return ret;
ret = regmap_read(data->map, PA12203001_REG_PDH,
&reg_byte);
if (ret < 0)
goto reg_err;
*val = reg_byte;
ret = pa12203001_set_power_state(data, false, dev_mask);
if (ret < 0)
return ret;
break;
default:
return -EINVAL;
}
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
if (ret < 0)
return ret;
*val = 0;
reg_byte = (reg_byte & PA12203001_AFSR_MASK);
*val2 = pa12203001_scales[reg_byte >> 4];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
reg_err:
pa12203001_set_power_state(data, false, dev_mask);
return ret;
}
static int pa12203001_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct pa12203001_data *data = iio_priv(indio_dev);
int i, ret, new_val;
unsigned int reg_byte;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
if (val != 0 || ret < 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) {
if (val2 == pa12203001_scales[i]) {
new_val = i << PA12203001_AFSR_SHIFT;
return regmap_update_bits(data->map,
PA12203001_REG_CFG0,
PA12203001_AFSR_MASK,
new_val);
}
}
break;
default:
break;
}
return -EINVAL;
}
static const struct iio_info pa12203001_info = {
.driver_module = THIS_MODULE,
.read_raw = pa12203001_read_raw,
.write_raw = pa12203001_write_raw,
.attrs = &pa12203001_attr_group,
};
static int pa12203001_init(struct iio_dev *indio_dev)
{
struct pa12203001_data *data = iio_priv(indio_dev);
int i, ret;
for (i = 0; i < ARRAY_SIZE(regvals); i++) {
ret = regmap_write(data->map, regvals[i].reg, regvals[i].val);
if (ret < 0)
return ret;
}
return 0;
}
static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state)
{
struct pa12203001_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = pa12203001_als_enable(data, state);
if (ret < 0)
goto out;
ret = pa12203001_px_enable(data, state);
out:
mutex_unlock(&data->lock);
return ret;
}
static int pa12203001_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pa12203001_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev,
sizeof(struct pa12203001_data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config);
if (IS_ERR(data->map))
return PTR_ERR(data->map);
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &pa12203001_info;
indio_dev->name = PA12203001_DRIVER_NAME;
indio_dev->channels = pa12203001_channels;
indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = pa12203001_init(indio_dev);
if (ret < 0)
return ret;
ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
if (ret < 0)
return ret;
ret = pm_runtime_set_active(&client->dev);
if (ret < 0) {
pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
return ret;
}
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
PA12203001_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
return iio_device_register(indio_dev);
}
static int pa12203001_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);
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
}
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
static int pa12203001_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
}
#endif
#ifdef CONFIG_PM_SLEEP
static int pa12203001_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
}
#endif
#ifdef CONFIG_PM
static int pa12203001_runtime_resume(struct device *dev)
{
struct pa12203001_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
mutex_lock(&data->lock);
if (data->als_needs_enable) {
pa12203001_als_enable(data, PA12203001_ALS_EN_MASK);
data->als_needs_enable = false;
}
if (data->px_needs_enable) {
pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
data->px_needs_enable = false;
}
mutex_unlock(&data->lock);
return 0;
}
#endif
static const struct dev_pm_ops pa12203001_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume)
SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL)
};
static const struct acpi_device_id pa12203001_acpi_match[] = {
{ "TXCPA122", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
static const struct i2c_device_id pa12203001_id[] = {
{"txcpa122", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pa12203001_id);
static struct i2c_driver pa12203001_driver = {
.driver = {
.name = PA12203001_DRIVER_NAME,
.pm = &pa12203001_pm_ops,
.acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
},
.probe = pa12203001_probe,
.remove = pa12203001_remove,
.id_table = pa12203001_id,
};
module_i2c_driver(pa12203001_driver);
MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor");
MODULE_LICENSE("GPL v2");

View File

@ -676,6 +676,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
{"STK3311", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3310", 0},

View File

@ -85,6 +85,7 @@
#define BMC150_MAGN_REG_HIGH_THRESH 0x50
#define BMC150_MAGN_REG_REP_XY 0x51
#define BMC150_MAGN_REG_REP_Z 0x52
#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0)
#define BMC150_MAGN_REG_TRIM_START 0x5D
#define BMC150_MAGN_REG_TRIM_END 0x71
@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
}
ret = regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_XY,
0xFF,
BMC150_MAGN_REG_REP_DATAMASK,
BMC150_MAGN_REPXY_TO_REGVAL
(val));
mutex_unlock(&data->mutex);
@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
}
ret = regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_Z,
0xFF,
BMC150_MAGN_REG_REP_DATAMASK,
BMC150_MAGN_REPZ_TO_REGVAL
(val));
mutex_unlock(&data->mutex);
@ -651,7 +652,9 @@ static const struct iio_info bmc150_magn_info = {
.driver_module = THIS_MODULE,
};
static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0};
static const unsigned long bmc150_magn_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0};
static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
{
@ -662,7 +665,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
mutex_lock(&data->mutex);
ret = bmc150_magn_read_xyz(data, data->buffer);
mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
@ -670,6 +672,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
pf->timestamp);
err:
mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@ -781,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
if (state == data->dready_trigger_on)
goto err_unlock;
ret = bmc150_magn_set_power_state(data, state);
if (ret < 0)
goto err_unlock;
ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY,
BMC150_MAGN_MASK_DRDY_EN,
state << BMC150_MAGN_SHIFT_DRDY_EN);
if (ret < 0)
goto err_poweroff;
goto err_unlock;
data->dready_trigger_on = state;
if (state) {
ret = bmc150_magn_reset_intr(data);
if (ret < 0)
goto err_poweroff;
goto err_unlock;
}
mutex_unlock(&data->mutex);
return 0;
err_poweroff:
bmc150_magn_set_power_state(data, false);
err_unlock:
mutex_unlock(&data->mutex);
return ret;
@ -1041,6 +1038,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
return 0;
}
/*
* Should be called with data->mutex held.
*/
static int bmc150_magn_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));

View File

@ -316,31 +316,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index,
__le16 buf[], int *val)
{
int raw_x, raw_y, raw_z;
int sens_x, sens_y, sens_z;
int raw[3];
int sens[3];
int nfo;
raw_x = le16_to_cpu(buf[AXIS_X]);
raw_y = le16_to_cpu(buf[AXIS_Y]);
raw_z = le16_to_cpu(buf[AXIS_Z]);
raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]);
raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]);
raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]);
sens_x = mmc35240_props_table[data->res].sens[AXIS_X];
sens_y = mmc35240_props_table[data->res].sens[AXIS_Y];
sens_z = mmc35240_props_table[data->res].sens[AXIS_Z];
sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X];
sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y];
sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z];
nfo = mmc35240_props_table[data->res].nfo;
switch (index) {
case AXIS_X:
*val = (raw_x - nfo) * 1000 / sens_x;
*val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X];
break;
case AXIS_Y:
*val = (raw_y - nfo) * 1000 / sens_y -
(raw_z - nfo) * 1000 / sens_z;
*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] -
(raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
break;
case AXIS_Z:
*val = (raw_y - nfo) * 1000 / sens_y +
(raw_z - nfo) * 1000 / sens_z;
*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] +
(raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
break;
default:
return -EINVAL;
@ -559,6 +559,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
};
static const struct of_device_id mmc35240_of_match[] = {
{ .compatible = "memsic,mmc35240", },
{ }
};
MODULE_DEVICE_TABLE(of, mmc35240_of_match);
static const struct acpi_device_id mmc35240_acpi_match[] = {
{"MMC35240", 0},
{ },
@ -574,6 +580,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id);
static struct i2c_driver mmc35240_driver = {
.driver = {
.name = MMC35240_DRV_NAME,
.of_match_table = mmc35240_of_match,
.pm = &mmc35240_pm_ops,
.acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
},

View File

@ -18,6 +18,7 @@
#define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn"
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
int st_magn_common_probe(struct iio_dev *indio_dev);
void st_magn_common_remove(struct iio_dev *indio_dev);
@ -25,6 +26,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
void st_magn_deallocate_ring(struct iio_dev *indio_dev);
int st_magn_trig_set_state(struct iio_trigger *trig, bool state);
#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
{

View File

@ -23,6 +23,13 @@
#include <linux/iio/common/st_sensors.h>
#include "st_magn.h"
int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state);
}
static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
{
return st_sensors_set_enable(indio_dev, true);

View File

@ -43,6 +43,7 @@
#define ST_MAGN_FS_AVL_8000MG 8000
#define ST_MAGN_FS_AVL_8100MG 8100
#define ST_MAGN_FS_AVL_12000MG 12000
#define ST_MAGN_FS_AVL_15000MG 15000
#define ST_MAGN_FS_AVL_16000MG 16000
/* CUSTOM VALUES FOR SENSOR 0 */
@ -157,6 +158,29 @@
#define ST_MAGN_2_OUT_Y_L_ADDR 0x2a
#define ST_MAGN_2_OUT_Z_L_ADDR 0x2c
/* CUSTOM VALUES FOR SENSOR 3 */
#define ST_MAGN_3_WAI_ADDR 0x4f
#define ST_MAGN_3_WAI_EXP 0x40
#define ST_MAGN_3_ODR_ADDR 0x60
#define ST_MAGN_3_ODR_MASK 0x0c
#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00
#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01
#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02
#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03
#define ST_MAGN_3_PW_ADDR 0x60
#define ST_MAGN_3_PW_MASK 0x03
#define ST_MAGN_3_PW_ON 0x00
#define ST_MAGN_3_PW_OFF 0x03
#define ST_MAGN_3_BDU_ADDR 0x62
#define ST_MAGN_3_BDU_MASK 0x10
#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62
#define ST_MAGN_3_DRDY_INT_MASK 0x01
#define ST_MAGN_3_FS_AVL_15000_GAIN 1500
#define ST_MAGN_3_MULTIREAD_BIT false
#define ST_MAGN_3_OUT_X_L_ADDR 0x68
#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a
#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c
static const struct iio_chan_spec st_magn_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
@ -189,9 +213,26 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_magn_3_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
ST_MAGN_3_OUT_X_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
ST_MAGN_3_OUT_Y_L_ADDR),
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
ST_MAGN_3_OUT_Z_L_ADDR),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct st_sensor_settings st_magn_sensors_settings[] = {
{
.wai = 0, /* This sensor has no valid WhoAmI report 0 */
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM303DLH_MAGN_DEV_NAME,
},
@ -268,6 +309,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
{
.wai = ST_MAGN_1_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM303DLHC_MAGN_DEV_NAME,
[1] = LSM303DLM_MAGN_DEV_NAME,
@ -346,6 +388,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
{
.wai = ST_MAGN_2_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3MDL_MAGN_DEV_NAME,
},
@ -399,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.multi_read_bit = ST_MAGN_2_MULTIREAD_BIT,
.bootime = 2,
},
{
.wai = ST_MAGN_3_WAI_EXP,
.wai_addr = ST_MAGN_3_WAI_ADDR,
.sensors_supported = {
[0] = LSM303AGR_MAGN_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_magn_3_16bit_channels,
.odr = {
.addr = ST_MAGN_3_ODR_ADDR,
.mask = ST_MAGN_3_ODR_MASK,
.odr_avl = {
{ 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, },
{ 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, },
{ 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, },
{ 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, },
},
},
.pw = {
.addr = ST_MAGN_3_PW_ADDR,
.mask = ST_MAGN_3_PW_MASK,
.value_on = ST_MAGN_3_PW_ON,
.value_off = ST_MAGN_3_PW_OFF,
},
.fs = {
.fs_avl = {
[0] = {
.num = ST_MAGN_FS_AVL_15000MG,
.gain = ST_MAGN_3_FS_AVL_15000_GAIN,
},
},
},
.bdu = {
.addr = ST_MAGN_3_BDU_ADDR,
.mask = ST_MAGN_3_BDU_MASK,
},
.drdy_irq = {
.addr = ST_MAGN_3_DRDY_IRQ_ADDR,
.mask_int1 = ST_MAGN_3_DRDY_INT_MASK,
},
.multi_read_bit = ST_MAGN_3_MULTIREAD_BIT,
.bootime = 2,
},
};
static int st_magn_read_raw(struct iio_dev *indio_dev,
@ -477,6 +562,16 @@ static const struct iio_info magn_info = {
.write_raw = &st_magn_write_raw,
};
#ifdef CONFIG_IIO_TRIGGER
static const struct iio_trigger_ops st_magn_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = ST_MAGN_TRIGGER_SET_STATE,
};
#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops)
#else
#define ST_MAGN_TRIGGER_OPS NULL
#endif
int st_magn_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
@ -513,7 +608,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
return err;
if (irq > 0) {
err = st_sensors_allocate_trigger(indio_dev, NULL);
err = st_sensors_allocate_trigger(indio_dev,
ST_MAGN_TRIGGER_OPS);
if (err < 0)
goto st_magn_probe_trigger_error;
}

View File

@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lis3mdl-magn",
.data = LIS3MDL_MAGN_DEV_NAME,
},
{
.compatible = "st,lsm303agr-magn",
.data = LSM303AGR_MAGN_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LSM303DLHC_MAGN_DEV_NAME },
{ LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME },
{ LSM303AGR_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);

View File

@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LSM303DLHC_MAGN_DEV_NAME },
{ LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME },
{ LSM303AGR_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);

View File

@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
static const struct st_sensor_settings st_press_sensors_settings[] = {
{
.wai = ST_PRESS_LPS331AP_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS331AP_PRESS_DEV_NAME,
},
@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
},
{
.wai = ST_PRESS_LPS001WP_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS001WP_PRESS_DEV_NAME,
},
@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
},
{
.wai = ST_PRESS_LPS25H_WAI_EXP,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS25H_PRESS_DEV_NAME,
},

View File

@ -65,6 +65,13 @@
#define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */
/* Magic constants */
#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */
#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
struct mlx90614_data {
struct i2c_client *client;
struct mutex lock; /* for EEPROM access only */
@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = -13657;
*val2 = 500000;
*val = MLX90614_CONST_OFFSET_DEC;
*val2 = MLX90614_CONST_OFFSET_REM;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
*val = 20;
*val = MLX90614_CONST_SCALE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
mlx90614_power_get(data, false);
@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
if (ret == 65535) {
if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) {
*val = 1;
*val2 = 0;
} else {
*val = 0;
*val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */
*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
}
return IIO_VAL_INT_PLUS_NANO;
default:
@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0))
return -EINVAL;
val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */
val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
mlx90614_power_get(data, false);
mutex_lock(&data->lock);

View File

@ -1,5 +1,5 @@
/*
* Freescale i.MX28 LRADC driver
* Freescale MXS LRADC driver
*
* Copyright (c) 2012 DENX Software Engineering, GmbH.
* Marek Vasut <marex@denx.de>
@ -15,34 +15,30 @@
* GNU General Public License for more details.
*/
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/stmp_device.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/clk.h>
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
#define DRIVER_NAME "mxs-lradc"
@ -65,14 +61,14 @@
* Once the pen touches the touchscreen, the touchscreen switches from
* IRQ-driven mode to polling mode to prevent interrupt storm. The polling
* is realized by worker thread, which is called every 20 or so milliseconds.
* This gives the touchscreen enough fluence and does not strain the system
* This gives the touchscreen enough fluency and does not strain the system
* too much.
*/
#define LRADC_TS_SAMPLE_DELAY_MS 5
/*
* The LRADC reads the following amount of samples from each touchscreen
* channel and the driver then computes avarage of these.
* channel and the driver then computes average of these.
*/
#define LRADC_TS_SAMPLE_AMOUNT 4
@ -238,7 +234,7 @@ struct mxs_lradc {
* CH5 -- Touch screen YNLR
* CH6 -- Touch screen WIPER (5-wire only)
*
* The bitfields below represents which parts of the LRADC block are
* The bit fields below represents which parts of the LRADC block are
* switched into special mode of operation. These channels can not
* be sampled as regular LRADC channels. The driver will refuse any
* attempt to sample these channels.
@ -252,7 +248,7 @@ struct mxs_lradc {
struct input_dev *ts_input;
enum mxs_lradc_id soc;
enum lradc_ts_plate cur_plate; /* statemachine */
enum lradc_ts_plate cur_plate; /* state machine */
bool ts_valid;
unsigned ts_x_pos;
unsigned ts_y_pos;
@ -812,7 +808,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
int ret;
/*
* See if there is no buffered operation in progess. If there is, simply
* See if there is no buffered operation in progress. If there is, simply
* bail out. This can be improved to support both buffered and raw IO at
* the same time, yet the code becomes horribly complicated. Therefore I
* applied KISS principle here.
@ -1369,7 +1365,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
* Driver initialization
*/
#define MXS_ADC_CHAN(idx, chan_type) { \
#define MXS_ADC_CHAN(idx, chan_type, name) { \
.type = (chan_type), \
.indexed = 1, \
.scan_index = (idx), \
@ -1382,17 +1378,18 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.realbits = LRADC_RESOLUTION, \
.storagebits = 32, \
}, \
.datasheet_name = (name), \
}
static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
MXS_ADC_CHAN(0, IIO_VOLTAGE),
MXS_ADC_CHAN(1, IIO_VOLTAGE),
MXS_ADC_CHAN(2, IIO_VOLTAGE),
MXS_ADC_CHAN(3, IIO_VOLTAGE),
MXS_ADC_CHAN(4, IIO_VOLTAGE),
MXS_ADC_CHAN(5, IIO_VOLTAGE),
MXS_ADC_CHAN(6, IIO_VOLTAGE),
MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */
static const struct iio_chan_spec mx23_lradc_chan_spec[] = {
MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"),
MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
/* Combined Temperature sensors */
{
.type = IIO_TEMP,
@ -1403,6 +1400,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
BIT(IIO_CHAN_INFO_SCALE),
.channel = 8,
.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
.datasheet_name = "TEMP_DIE",
},
/* Hidden channel to keep indexes */
{
@ -1411,12 +1409,48 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
.scan_index = -1,
.channel = 9,
},
MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */
MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */
MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */
MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */
MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */
MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */
MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL),
MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL),
MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"),
MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"),
MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
};
static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"),
MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
/* Combined Temperature sensors */
{
.type = IIO_TEMP,
.indexed = 1,
.scan_index = 8,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
.channel = 8,
.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
.datasheet_name = "TEMP_DIE",
},
/* Hidden channel to keep indexes */
{
.type = IIO_TEMP,
.indexed = 1,
.scan_index = -1,
.channel = 9,
},
MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"),
MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"),
MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"),
MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"),
MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
};
static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
@ -1612,10 +1646,16 @@ static int mxs_lradc_probe(struct platform_device *pdev)
iio->dev.parent = &pdev->dev;
iio->info = &mxs_lradc_iio_info;
iio->modes = INDIO_DIRECT_MODE;
iio->channels = mxs_lradc_chan_spec;
iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec);
iio->masklength = LRADC_MAX_TOTAL_CHANS;
if (lradc->soc == IMX23_LRADC) {
iio->channels = mx23_lradc_chan_spec;
iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
} else {
iio->channels = mx28_lradc_chan_spec;
iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
}
ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
&mxs_lradc_trigger_handler,
&mxs_lradc_buffer_ops);
@ -1707,6 +1747,6 @@ static struct platform_driver mxs_lradc_driver = {
module_platform_driver(mxs_lradc_driver);
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver");
MODULE_DESCRIPTION("Freescale MXS LRADC driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View File

@ -166,6 +166,7 @@ struct st_sensor_transfer_function {
/**
* struct st_sensor_settings - ST specific sensor settings
* @wai: Contents of WhoAmI register.
* @wai_addr: The address of WhoAmI register.
* @sensors_supported: List of supported sensors by struct itself.
* @ch: IIO channels for the sensor.
* @odr: Output data rate register and ODR list available.
@ -179,6 +180,7 @@ struct st_sensor_transfer_function {
*/
struct st_sensor_settings {
u8 wai;
u8 wai_addr;
char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME];
struct iio_chan_spec *ch;
int num_ch;

View File

@ -100,7 +100,7 @@ void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff);
/**
* iio_channel_cb_get_channels() - get access to the underlying channels.
* @cb_buff: The callback buffer from whom we want the channel
* @cb_buffer: The callback buffer from whom we want the channel
* information.
*
* This function allows one to obtain information about the channels.

View File

@ -644,6 +644,15 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
*/
#define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL)
/**
* IIO_RAD_TO_DEGREE() - Convert rad to degree
* @rad: A value in rad
*
* Returns the given value converted from rad to degree
*/
#define IIO_RAD_TO_DEGREE(rad) \
(((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL)
/**
* IIO_G_TO_M_S_2() - Convert g to meter / second**2
* @g: A value in g
@ -652,4 +661,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
*/
#define IIO_G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL)
/**
* IIO_M_S_2_TO_G() - Convert meter / second**2 to g
* @ms2: A value in meter / second**2
*
* Returns the given value converted from meter / second**2 to g
*/
#define IIO_M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL)
#endif /* _INDUSTRIAL_IO_H_ */

View File

@ -18,7 +18,8 @@ struct iio_chan_spec;
* struct iio_dev_attr - iio specific device attribute
* @dev_attr: underlying device attribute
* @address: associated register address
* @l: list head for maintaining list of dynamically created attrs.
* @l: list head for maintaining list of dynamically created attrs
* @c: specification for the underlying channel
*/
struct iio_dev_attr {
struct device_attribute dev_attr;

View File

@ -18,6 +18,9 @@ struct iio_subirq {
bool enabled;
};
struct iio_dev;
struct iio_trigger;
/**
* struct iio_trigger_ops - operations structure for an iio_trigger.
* @owner: used to monitor usage count of the trigger.

View File

@ -193,15 +193,15 @@ void process_scan(char *data,
void print_usage(void)
{
printf("Usage: generic_buffer [options]...\n"
"Capture, convert and output data from IIO device buffer\n"
" -c <n> Do n conversions\n"
" -e Disable wait for event (new data)\n"
" -g Use trigger-less mode\n"
" -l <n> Set buffer length to n samples\n"
" -n <name> Set device name (mandatory)\n"
" -t <name> Set trigger name\n"
" -w <n> Set delay between reads in us (event-less mode)\n");
fprintf(stderr, "Usage: generic_buffer [options]...\n"
"Capture, convert and output data from IIO device buffer\n"
" -c <n> Do n conversions\n"
" -e Disable wait for event (new data)\n"
" -g Use trigger-less mode\n"
" -l <n> Set buffer length to n samples\n"
" -n <name> Set device name (mandatory)\n"
" -t <name> Set trigger name\n"
" -w <n> Set delay between reads in us (event-less mode)\n");
}
int main(int argc, char **argv)
@ -270,8 +270,8 @@ int main(int argc, char **argv)
}
}
if (device_name == NULL) {
printf("Device name not set\n");
if (!device_name) {
fprintf(stderr, "Device name not set\n");
print_usage();
return -1;
}
@ -279,7 +279,7 @@ int main(int argc, char **argv)
/* Find the device requested */
dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num < 0) {
printf("Failed to find the %s\n", device_name);
fprintf(stderr, "Failed to find the %s\n", device_name);
return dev_num;
}
@ -290,7 +290,7 @@ int main(int argc, char **argv)
return -ENOMEM;
if (!notrigger) {
if (trigger_name == NULL) {
if (!trigger_name) {
/*
* Build the trigger name. If it is device associated
* its name is <device_name>_dev[n] where n matches
@ -307,7 +307,8 @@ int main(int argc, char **argv)
/* Verify the trigger exists */
trig_num = find_type_by_name(trigger_name, "trigger");
if (trig_num < 0) {
printf("Failed to find the trigger %s\n", trigger_name);
fprintf(stderr, "Failed to find the trigger %s\n",
trigger_name);
ret = trig_num;
goto error_free_triggername;
}
@ -323,8 +324,8 @@ int main(int argc, char **argv)
*/
ret = build_channel_array(dev_dir_name, &channels, &num_channels);
if (ret) {
printf("Problem reading scan element information\n");
printf("diag %s\n", dev_dir_name);
fprintf(stderr, "Problem reading scan element information\n"
"diag %s\n", dev_dir_name);
goto error_free_triggername;
}
@ -350,7 +351,8 @@ int main(int argc, char **argv)
dev_dir_name,
trigger_name);
if (ret < 0) {
printf("Failed to write current_trigger file\n");
fprintf(stderr,
"Failed to write current_trigger file\n");
goto error_free_buf_dir_name;
}
}
@ -362,8 +364,11 @@ int main(int argc, char **argv)
/* Enable the buffer */
ret = write_sysfs_int("enable", buf_dir_name, 1);
if (ret < 0)
if (ret < 0) {
fprintf(stderr,
"Failed to enable buffer: %s\n", strerror(-ret));
goto error_free_buf_dir_name;
}
scan_size = size_from_channelarray(channels, num_channels);
data = malloc(scan_size * buf_len);
@ -382,7 +387,7 @@ int main(int argc, char **argv)
fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* TODO: If it isn't there make the node */
ret = -errno;
printf("Failed to open %s\n", buffer_access);
fprintf(stderr, "Failed to open %s\n", buffer_access);
goto error_free_buffer_access;
}
@ -410,7 +415,7 @@ int main(int argc, char **argv)
read_size = read(fp, data, toread * scan_size);
if (read_size < 0) {
if (errno == EAGAIN) {
printf("nothing available\n");
fprintf(stderr, "nothing available\n");
continue;
} else {
break;
@ -431,7 +436,8 @@ int main(int argc, char **argv)
ret = write_sysfs_string("trigger/current_trigger",
dev_dir_name, "NULL");
if (ret < 0)
printf("Failed to write to %s\n", dev_dir_name);
fprintf(stderr, "Failed to write to %s\n",
dev_dir_name);
error_close_buffer_access:
if (close(fp) == -1)

View File

@ -215,8 +215,8 @@ static void print_event(struct iio_event_data *event)
bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
if (!event_is_known(event)) {
printf("Unknown event: time: %lld, id: %llx\n",
event->timestamp, event->id);
fprintf(stderr, "Unknown event: time: %lld, id: %llx\n",
event->timestamp, event->id);
return;
}
@ -251,7 +251,7 @@ int main(int argc, char **argv)
int fd, event_fd;
if (argc <= 1) {
printf("Usage: %s <device_name>\n", argv[0]);
fprintf(stderr, "Usage: %s <device_name>\n", argv[0]);
return -1;
}
@ -262,9 +262,8 @@ int main(int argc, char **argv)
printf("Found IIO device with name %s with device number %d\n",
device_name, dev_num);
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
if (ret < 0) {
if (ret < 0)
return -ENOMEM;
}
} else {
/*
* If we can't find an IIO device by name assume device_name is
@ -278,14 +277,14 @@ int main(int argc, char **argv)
fd = open(chrdev_name, 0);
if (fd == -1) {
ret = -errno;
fprintf(stdout, "Failed to open %s\n", chrdev_name);
fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto error_free_chrdev_name;
}
ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
if (ret == -1 || event_fd == -1) {
ret = -errno;
fprintf(stdout, "Failed to retrieve event fd\n");
fprintf(stderr, "Failed to retrieve event fd\n");
if (close(fd) == -1)
perror("Failed to close character device file");
@ -301,7 +300,7 @@ int main(int argc, char **argv)
ret = read(event_fd, &event, sizeof(event));
if (ret == -1) {
if (errno == EAGAIN) {
printf("nothing available\n");
fprintf(stderr, "nothing available\n");
continue;
} else {
ret = -errno;
@ -311,7 +310,7 @@ int main(int argc, char **argv)
}
if (ret != sizeof(event)) {
printf("Reading event failed!\n");
fprintf(stderr, "Reading event failed!\n");
ret = -EIO;
break;
}

View File

@ -6,9 +6,6 @@
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _IIO_UTILS_H
#define _IIO_UTILS_H
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@ -39,7 +36,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name)
char *working, *prefix = "";
int i, ret;
for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
for (i = 0; i < ARRAY_SIZE(iio_direction); i++)
if (!strncmp(full_name, iio_direction[i],
strlen(iio_direction[i]))) {
prefix = iio_direction[i];
@ -117,13 +114,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
}
dp = opendir(scan_el_dir);
if (dp == NULL) {
if (!dp) {
ret = -errno;
goto error_free_builtname_generic;
}
ret = -ENOENT;
while (ent = readdir(dp), ent != NULL)
while (ent = readdir(dp), ent)
/*
* Do we allow devices to override a generic name with
* a specific one?
@ -138,9 +135,10 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
}
sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("failed to open %s\n", filename);
fprintf(stderr, "failed to open %s\n",
filename);
goto error_free_filename;
}
@ -152,11 +150,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
&padint, shift);
if (ret < 0) {
ret = -errno;
printf("failed to pass scan type description\n");
fprintf(stderr,
"failed to pass scan type description\n");
goto error_close_sysfsfp;
} else if (ret != 5) {
ret = -EIO;
printf("scan type description didn't match\n");
fprintf(stderr,
"scan type description didn't match\n");
goto error_close_sysfsfp;
}
@ -165,12 +165,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
if (*bits_used == 64)
*mask = ~0;
else
*mask = (1 << *bits_used) - 1;
*mask = (1ULL << *bits_used) - 1;
*is_signed = (signchar == 's');
if (fclose(sysfsfp)) {
ret = -errno;
printf("Failed to close %s\n", filename);
fprintf(stderr, "Failed to close %s\n",
filename);
goto error_free_filename;
}
@ -235,13 +236,13 @@ int iioutils_get_param_float(float *output, const char *param_name,
}
dp = opendir(device_dir);
if (dp == NULL) {
if (!dp) {
ret = -errno;
goto error_free_builtname_generic;
}
ret = -ENOENT;
while (ent = readdir(dp), ent != NULL)
while (ent = readdir(dp), ent)
if ((strcmp(builtname, ent->d_name) == 0) ||
(strcmp(builtname_generic, ent->d_name) == 0)) {
ret = asprintf(&filename,
@ -285,17 +286,17 @@ error_free_builtname:
* @cnt: the amount of array elements
**/
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt)
void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
{
struct iio_channel_info temp;
int x, y;
for (x = 0; x < cnt; x++)
for (y = 0; y < (cnt - 1); y++)
if ((*ci_array)[y].index > (*ci_array)[y + 1].index) {
temp = (*ci_array)[y + 1];
(*ci_array)[y + 1] = (*ci_array)[y];
(*ci_array)[y] = temp;
if (ci_array[y].index > ci_array[y + 1].index) {
temp = ci_array[y + 1];
ci_array[y + 1] = ci_array[y];
ci_array[y] = temp;
}
}
@ -325,12 +326,12 @@ int build_channel_array(const char *device_dir,
return -ENOMEM;
dp = opendir(scan_el_dir);
if (dp == NULL) {
if (!dp) {
ret = -errno;
goto error_free_name;
}
while (ent = readdir(dp), ent != NULL)
while (ent = readdir(dp), ent)
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) {
ret = asprintf(&filename,
@ -341,7 +342,7 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
free(filename);
goto error_close_dir;
@ -369,13 +370,13 @@ int build_channel_array(const char *device_dir,
}
*ci_array = malloc(sizeof(**ci_array) * (*counter));
if (*ci_array == NULL) {
if (!*ci_array) {
ret = -ENOMEM;
goto error_close_dir;
}
seekdir(dp, 0);
while (ent = readdir(dp), ent != NULL) {
while (ent = readdir(dp), ent) {
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) {
int current_enabled = 0;
@ -391,7 +392,7 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
free(filename);
count--;
@ -424,7 +425,7 @@ int build_channel_array(const char *device_dir,
current->name = strndup(ent->d_name,
strlen(ent->d_name) -
strlen("_en"));
if (current->name == NULL) {
if (!current->name) {
free(filename);
ret = -ENOMEM;
count--;
@ -452,9 +453,10 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("failed to open %s\n", filename);
fprintf(stderr, "failed to open %s\n",
filename);
free(filename);
goto error_cleanup_array;
}
@ -482,7 +484,7 @@ int build_channel_array(const char *device_dir,
device_dir,
current->name,
current->generic_name);
if (ret < 0)
if ((ret < 0) && (ret != -ENOENT))
goto error_cleanup_array;
ret = iioutils_get_param_float(&current->offset,
@ -490,7 +492,7 @@ int build_channel_array(const char *device_dir,
device_dir,
current->name,
current->generic_name);
if (ret < 0)
if ((ret < 0) && (ret != -ENOENT))
goto error_cleanup_array;
ret = iioutils_get_type(&current->is_signed,
@ -514,7 +516,7 @@ int build_channel_array(const char *device_dir,
free(scan_el_dir);
/* reorder so that the array is in index order */
bsort_channel_array_by_index(ci_array, *counter);
bsort_channel_array_by_index(*ci_array, *counter);
return 0;
@ -524,6 +526,8 @@ error_cleanup_array:
free((*ci_array)[i].generic_name);
}
free(*ci_array);
*ci_array = NULL;
*counter = 0;
error_close_dir:
if (dp)
if (closedir(dp) == -1)
@ -535,7 +539,7 @@ error_free_name:
return ret;
}
int calc_digits(int num)
static int calc_digits(int num)
{
int count = 0;
@ -567,12 +571,12 @@ int find_type_by_name(const char *name, const char *type)
char *filename;
dp = opendir(iio_dir);
if (dp == NULL) {
printf("No industrialio devices available\n");
if (!dp) {
fprintf(stderr, "No industrialio devices available\n");
return -ENODEV;
}
while (ent = readdir(dp), ent != NULL) {
while (ent = readdir(dp), ent) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0 &&
strlen(ent->d_name) > strlen(type) &&
@ -581,11 +585,13 @@ int find_type_by_name(const char *name, const char *type)
ret = sscanf(ent->d_name + strlen(type), "%d", &number);
if (ret < 0) {
ret = -errno;
printf("failed to read element number\n");
fprintf(stderr,
"failed to read element number\n");
goto error_close_dir;
} else if (ret != 1) {
ret = -EIO;
printf("failed to match element number\n");
fprintf(stderr,
"failed to match element number\n");
goto error_close_dir;
}
@ -595,7 +601,7 @@ int find_type_by_name(const char *name, const char *type)
":", 1) != 0) {
filename = malloc(strlen(iio_dir) + strlen(type)
+ numstrlen + 6);
if (filename == NULL) {
if (!filename) {
ret = -ENOMEM;
goto error_close_dir;
}
@ -654,7 +660,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
int test;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
if (temp == NULL)
if (!temp)
return -ENOMEM;
ret = sprintf(temp, "%s/%s", basedir, filename);
@ -662,9 +668,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
goto error_free;
sysfsfp = fopen(temp, "w");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("failed to open %s\n", temp);
fprintf(stderr, "failed to open %s\n", temp);
goto error_free;
}
@ -683,9 +689,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
if (verify) {
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("failed to open %s\n", temp);
fprintf(stderr, "failed to open %s\n", temp);
goto error_free;
}
@ -703,8 +709,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
}
if (test != val) {
printf("Possible failure in int write %d to %s/%s\n",
val, basedir, filename);
fprintf(stderr,
"Possible failure in int write %d to %s/%s\n",
val, basedir, filename);
ret = -1;
}
}
@ -749,8 +756,8 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
if (temp == NULL) {
printf("Memory allocation failed\n");
if (!temp) {
fprintf(stderr, "Memory allocation failed\n");
return -ENOMEM;
}
@ -759,9 +766,9 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
goto error_free;
sysfsfp = fopen(temp, "w");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("Could not open %s\n", temp);
fprintf(stderr, "Could not open %s\n", temp);
goto error_free;
}
@ -780,9 +787,9 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
if (verify) {
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
printf("Could not open file to verify\n");
fprintf(stderr, "Could not open file to verify\n");
goto error_free;
}
@ -800,9 +807,10 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
}
if (strcmp(temp, val) != 0) {
printf("Possible failure in string write of %s "
"Should be %s written to %s/%s\n", temp, val,
basedir, filename);
fprintf(stderr,
"Possible failure in string write of %s "
"Should be %s written to %s/%s\n", temp, val,
basedir, filename);
ret = -1;
}
}
@ -855,8 +863,8 @@ int read_sysfs_posint(const char *filename, const char *basedir)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
if (temp == NULL) {
printf("Memory allocation failed");
if (!temp) {
fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@ -865,7 +873,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
goto error_free;
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@ -902,8 +910,8 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
if (temp == NULL) {
printf("Memory allocation failed");
if (!temp) {
fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@ -912,7 +920,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
goto error_free;
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@ -949,8 +957,8 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
if (temp == NULL) {
printf("Memory allocation failed");
if (!temp) {
fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@ -959,7 +967,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
goto error_free;
sysfsfp = fopen(temp, "r");
if (sysfsfp == NULL) {
if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@ -981,5 +989,3 @@ error_free:
return ret;
}
#endif /* _IIO_UTILS_H */

View File

@ -18,6 +18,8 @@
#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
#define FORMAT_TYPE_FILE "%s_type"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
extern const char *iio_dir;
/**
@ -58,7 +60,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
int iioutils_get_param_float(float *output, const char *param_name,
const char *device_dir, const char *name,
const char *generic_name);
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt);
void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt);
int build_channel_array(const char *device_dir,
struct iio_channel_info **ci_array, int *counter);
int find_type_by_name(const char *name, const char *type);

View File

@ -46,10 +46,10 @@ static int dump_channels(const char *dev_dir_name)
const struct dirent *ent;
dp = opendir(dev_dir_name);
if (dp == NULL)
if (!dp)
return -errno;
while (ent = readdir(dp), ent != NULL)
while (ent = readdir(dp), ent)
if (check_prefix(ent->d_name, "in_") &&
check_postfix(ent->d_name, "_raw"))
printf(" %-10s\n", ent->d_name);
@ -69,7 +69,7 @@ static int dump_one_device(const char *dev_dir_name)
return -EINVAL;
ret = read_sysfs_string("name", dev_dir_name, name);
if (ret)
if (ret < 0)
return ret;
printf("Device %03d: %s\n", dev_idx, name);
@ -92,7 +92,7 @@ static int dump_one_trigger(const char *dev_dir_name)
return -EINVAL;
ret = read_sysfs_string("name", dev_dir_name, name);
if (ret)
if (ret < 0)
return ret;
printf("Trigger %03d: %s\n", dev_idx, name);
@ -107,12 +107,12 @@ static int dump_devices(void)
DIR *dp;
dp = opendir(iio_dir);
if (dp == NULL) {
printf("No industrial I/O devices available\n");
if (!dp) {
fprintf(stderr, "No industrial I/O devices available\n");
return -ENODEV;
}
while (ent = readdir(dp), ent != NULL) {
while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, type_device)) {
char *dev_dir_name;
@ -134,7 +134,7 @@ static int dump_devices(void)
}
}
rewinddir(dp);
while (ent = readdir(dp), ent != NULL) {
while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, type_trigger)) {
char *dev_dir_name;