mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-10 07:00:48 +00:00
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.
This commit is contained in:
commit
1c46ae0af6
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
697
Documentation/DocBook/iio.tmpl
Normal file
697
Documentation/DocBook/iio.tmpl
Normal 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 = &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
|
||||
-->
|
@ -18,6 +18,7 @@ Required properties:
|
||||
"mcp3202"
|
||||
"mcp3204"
|
||||
"mcp3208"
|
||||
"mcp3301"
|
||||
|
||||
|
||||
Examples:
|
||||
|
@ -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 {
|
||||
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
},
|
||||
|
@ -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},
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
{}
|
||||
};
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
804
drivers/iio/light/opt3001.c
Normal file
804
drivers/iio/light/opt3001.c
Normal 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, ®, 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, ®, 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, ®, 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, ®, 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");
|
483
drivers/iio/light/pa12203001.c
Normal file
483
drivers/iio/light/pa12203001.c
Normal 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,
|
||||
®_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,
|
||||
®_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, ®_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, ®_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");
|
@ -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},
|
||||
|
@ -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));
|
||||
|
@ -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),
|
||||
},
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(¤t->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(¤t->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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user