Second set of new devices, functionality and cleanup for IIO in the 4.1 cycle.
New Functionality * Watermark logic for buffers. Allows for blocking reads to block until their requested amount is available - previously they only blocked until a single scan of data was available. Also allows for polling for a watermark amount of data to be available. This feature was first proposed some time ago to good responses, but not taken further by the original author Octavian has picked up the gauntlet and taken it through to merging (along with the hardware fifo support that follows). * New approach to hardware fifo handling - in particular handling the interaction of a hardware fifo feeding into a software fifo and their watershed events. We don't have every possible case well covered yet, but this is certainly a good, flexible starting point. This will replace the previous approach used in ancient drivers (sca3000) where we just exposed the hardware buffer directly to userspace. Very few pieces of hardware have sufficiently long buffers for that to be an adequate solution. * bmc150_accel - hardware fifo support. * mlx90614 - support dual IR sensor devices + some refactoring to clean up the code and allow some other functionality currently under review. * L3GD20H gyroscope support added to the st_gyro driver. * lis3lv02d accelerometer added to the st_gyro driver. Note this part is also supported by the older lis3 driver under misc. A lengthy discussion took place and concluded that holding parts out on the basis that whole driver would be subsumed into this one was counter productive. Better to add part support and add additional features as people need them. Basically there was not advantage in not merging the support. * max517 driver gains support for MAX520 and MAX521 DACs. Documentation * 3.20 -> 4.0 renaming for recent docs. Whilst technically a fix, I think people will cope until the next merge merge window. * An ABI typo hat -> What: More ABIs should have hats. * Document in_rot_offset, illuminance_raw and illuminance_scale. Cleanups * Fix a scale extraction bug in generic_buffer.c example. * Constify a load of device tree related structures. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJVGapUAAoJEFSFNJnE9BaI6FAQAKBSW1Fl0cc4mweAfDmUnDzp jFxKKGeIDDOBQyChjANq5zI+X8r2Bh1iy6qShfooXsOoGYNYumL2DHWPTThwEcWp I2/qHPaKkArL9k7os+TYCG5e3y1TRCeZGgvDEcvzPGCuPMel5Y5x5gqd3e6YCc0j 59sIeyltMCIivyK+vo5gsNJoQQWzkcKdlUZ6eCFpYR8tEi23rgGTyaftd82Odncs pJ2B98If3iaicght6ffKU716r6zI5Nfo121tiZeBAuXWyZ4lBzlJ/RBohXAUOziP qLh0G0H3xhfo3K+Ph9tS8JOLweG8DnRJb2Sl2SE9FFyoXW1FqlgYvsstVXmkk4So JuLJvwfTvHJWmvuy5aP4QtaR57wwxLa6vNjd1qZfb4/0f5Ugdsve5fETfyTXla6g mhRnInuc6rwJBLEOLhPbZ8+e8CmnUB6KUuSISFTOJZA20ygbNIOdWXo17VXrGZdV qBU2F9TX12p9D85O8Ee+AhdlUCALwWruj0ccsPIt6v/UZUcJ9TOrB06yOBBCCfqL W9xdVj5xIGR54yLBONP9enLtNitbOogDF308I5QGEOAZUYzsrtjh9HhjN1UEcvKM D96uNKFCLFHgfrwN+3OKfIPeRWAnznanaTJUMfBSvkT6X5dEMt72prYpl1JIFiVO ZiWA/9hi70+Y/9bgqe1L =kqSc -----END PGP SIGNATURE----- Merge tag 'iio-for-4.1b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Second set of new devices, functionality and cleanup for IIO in the 4.1 cycle. New Functionality * Watermark logic for buffers. Allows for blocking reads to block until their requested amount is available - previously they only blocked until a single scan of data was available. Also allows for polling for a watermark amount of data to be available. This feature was first proposed some time ago to good responses, but not taken further by the original author Octavian has picked up the gauntlet and taken it through to merging (along with the hardware fifo support that follows). * New approach to hardware fifo handling - in particular handling the interaction of a hardware fifo feeding into a software fifo and their watershed events. We don't have every possible case well covered yet, but this is certainly a good, flexible starting point. This will replace the previous approach used in ancient drivers (sca3000) where we just exposed the hardware buffer directly to userspace. Very few pieces of hardware have sufficiently long buffers for that to be an adequate solution. * bmc150_accel - hardware fifo support. * mlx90614 - support dual IR sensor devices + some refactoring to clean up the code and allow some other functionality currently under review. * L3GD20H gyroscope support added to the st_gyro driver. * lis3lv02d accelerometer added to the st_gyro driver. Note this part is also supported by the older lis3 driver under misc. A lengthy discussion took place and concluded that holding parts out on the basis that whole driver would be subsumed into this one was counter productive. Better to add part support and add additional features as people need them. Basically there was not advantage in not merging the support. * max517 driver gains support for MAX520 and MAX521 DACs. Documentation * 3.20 -> 4.0 renaming for recent docs. Whilst technically a fix, I think people will cope until the next merge merge window. * An ABI typo hat -> What: More ABIs should have hats. * Document in_rot_offset, illuminance_raw and illuminance_scale. Cleanups * Fix a scale extraction bug in generic_buffer.c example. * Constify a load of device tree related structures.
This commit is contained in:
commit
675732707f
|
@ -254,6 +254,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -297,6 +298,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -337,6 +339,7 @@ what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
|
|||
what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibscale
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -348,7 +351,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibgender
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Gender of the user (e.g.: male, female) used by some pedometers
|
||||
|
@ -359,7 +362,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender_available
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibgender_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender_available
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Lists all available gender values (e.g.: male, female).
|
||||
|
@ -376,7 +379,7 @@ Description:
|
|||
type.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibweight
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Weight of the user (in kg). It is needed by some pedometers
|
||||
|
@ -797,7 +800,7 @@ Description:
|
|||
|
||||
What: /sys/.../events/in_accel_x_thresh_rising_period
|
||||
What: /sys/.../events/in_accel_x_thresh_falling_period
|
||||
hat: /sys/.../events/in_accel_x_roc_rising_period
|
||||
What: /sys/.../events/in_accel_x_roc_rising_period
|
||||
What: /sys/.../events/in_accel_x_roc_falling_period
|
||||
What: /sys/.../events/in_accel_y_thresh_rising_period
|
||||
What: /sys/.../events/in_accel_y_thresh_falling_period
|
||||
|
@ -944,7 +947,7 @@ Description:
|
|||
this type.
|
||||
|
||||
What: /sys/.../events/in_steps_change_en
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Event generated when channel passes a threshold on the absolute
|
||||
|
@ -953,7 +956,7 @@ Description:
|
|||
in_steps_change_value.
|
||||
|
||||
What: /sys/.../events/in_steps_change_value
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Specifies the value of change threshold that the
|
||||
|
@ -1128,7 +1131,7 @@ Description:
|
|||
|
||||
What: /sys/.../iio:deviceX/in_energy_input
|
||||
What: /sys/.../iio:deviceX/in_energy_raw
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute is used to read the energy value reported by the
|
||||
|
@ -1137,7 +1140,7 @@ Description:
|
|||
|
||||
What: /sys/.../iio:deviceX/in_distance_input
|
||||
What: /sys/.../iio:deviceX/in_distance_raw
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute is used to read the distance covered by the user
|
||||
|
@ -1167,9 +1170,13 @@ Description:
|
|||
values should behave in the same way as a distance, i.e. lower
|
||||
values indicate something is closer to the sensor.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_illuminance_input
|
||||
What: /sys/.../iio:deviceX/in_illuminance_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_input
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminance_ir_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminance_clear_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1198,7 +1205,7 @@ Description:
|
|||
seconds.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Number of seconds in which to compute speed.
|
||||
|
@ -1260,7 +1267,7 @@ Description:
|
|||
Units after application of scale are m/s.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_steps_debounce_count
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Specifies the number of steps that must occur within
|
||||
|
@ -1268,8 +1275,92 @@ Description:
|
|||
consumer is making steps.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_steps_debounce_time
|
||||
KernelVersion: 3.20
|
||||
KernelVersion: 4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Specifies number of seconds in which we compute the steps
|
||||
that occur in order to decide if the consumer is making steps.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A single positive integer specifying the maximum number of scan
|
||||
elements to wait for.
|
||||
Poll will block until the watermark is reached.
|
||||
Blocking read will wait until the minimum between the requested
|
||||
read amount or the low water mark is available.
|
||||
Non-blocking read will retrieve the available samples from the
|
||||
buffer even if there are less samples then watermark level. This
|
||||
allows the application to block on poll with a timeout and read
|
||||
the available samples after the timeout expires and thus have a
|
||||
maximum delay guarantee.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_enabled
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A read-only boolean value that indicates if the hardware fifo is
|
||||
currently enabled or disabled. If the device does not have a
|
||||
hardware fifo this entry is not present.
|
||||
The hardware fifo is enabled when the buffer is enabled if the
|
||||
current hardware fifo watermark level is set and other current
|
||||
device settings allows it (e.g. if a trigger is set that samples
|
||||
data differently that the hardware fifo does then hardware fifo
|
||||
will not enabled).
|
||||
If the hardware fifo is enabled and the level of the hardware
|
||||
fifo reaches the hardware fifo watermark level the device will
|
||||
flush its hardware fifo to the device buffer. Doing a non
|
||||
blocking read on the device when no samples are present in the
|
||||
device buffer will also force a flush.
|
||||
When the hardware fifo is enabled there is no need to use a
|
||||
trigger to use buffer mode since the watermark settings
|
||||
guarantees that the hardware fifo is flushed to the device
|
||||
buffer.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Read-only entry that contains a single integer specifying the
|
||||
current watermark level for the hardware fifo. If the device
|
||||
does not have a hardware fifo this entry is not present.
|
||||
The watermark level for the hardware fifo is set by the driver
|
||||
based on the value set by the user in buffer/watermark but
|
||||
taking into account hardware limitations (e.g. most hardware
|
||||
buffers are limited to 32-64 samples, some hardware buffers
|
||||
watermarks are fixed or have minimum levels). A value of 0
|
||||
means that the hardware watermark is unset.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_min
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A single positive integer specifying the minimum watermark level
|
||||
for the hardware fifo of this device. If the device does not
|
||||
have a hardware fifo this entry is not present.
|
||||
If the user sets buffer/watermark to a value less than this one,
|
||||
then the hardware watermark will remain unset.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_max
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A single positive integer specifying the maximum watermark level
|
||||
for the hardware fifo of this device. If the device does not
|
||||
have a hardware fifo this entry is not present.
|
||||
If the user sets buffer/watermark to a value greater than this
|
||||
one, then the hardware watermark will be capped at this value.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark_available
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A list of positive integers specifying the available watermark
|
||||
levels for the hardware fifo. This entry is optional and if it
|
||||
is not present it means that all the values between
|
||||
hwfifo_watermark_min and hwfifo_watermark_max are supported.
|
||||
If the user sets buffer/watermark to a value greater than
|
||||
hwfifo_watermak_min but not equal to any of the values in this
|
||||
list, the driver will chose an appropriate value for the
|
||||
hardware fifo watermark level.
|
||||
|
|
|
@ -23,6 +23,7 @@ standard bindings from pinctrl/pinctrl-bindings.txt.
|
|||
Valid compatible strings:
|
||||
|
||||
Accelerometers:
|
||||
- st,lis3lv02dl-accel
|
||||
- st,lsm303dlh-accel
|
||||
- st,lsm303dlhc-accel
|
||||
- st,lis3dh-accel
|
||||
|
|
|
@ -70,7 +70,9 @@
|
|||
#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_MAP_1 0x1A
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1)
|
||||
#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21
|
||||
#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80
|
||||
|
@ -83,7 +85,9 @@
|
|||
#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_EN_1 0x17
|
||||
#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4)
|
||||
#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4)
|
||||
#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN BIT(5)
|
||||
#define BMC150_ACCEL_INT_EN_BIT_FWM_EN BIT(6)
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20
|
||||
#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0)
|
||||
|
@ -122,6 +126,12 @@
|
|||
#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2))
|
||||
#define BMC150_AUTO_SUSPEND_DELAY_MS 2000
|
||||
|
||||
#define BMC150_ACCEL_REG_FIFO_STATUS 0x0E
|
||||
#define BMC150_ACCEL_REG_FIFO_CONFIG0 0x30
|
||||
#define BMC150_ACCEL_REG_FIFO_CONFIG1 0x3E
|
||||
#define BMC150_ACCEL_REG_FIFO_DATA 0x3F
|
||||
#define BMC150_ACCEL_FIFO_LENGTH 32
|
||||
|
||||
enum bmc150_accel_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
|
@ -179,13 +189,14 @@ struct bmc150_accel_data {
|
|||
atomic_t active_intr;
|
||||
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
|
||||
struct mutex mutex;
|
||||
u8 fifo_mode, watermark;
|
||||
s16 buffer[8];
|
||||
u8 bw_bits;
|
||||
u32 slope_dur;
|
||||
u32 slope_thres;
|
||||
u32 range;
|
||||
int ev_enable_state;
|
||||
int64_t timestamp;
|
||||
int64_t timestamp, old_timestamp;
|
||||
const struct bmc150_accel_chip_info *chip_info;
|
||||
};
|
||||
|
||||
|
@ -470,6 +481,12 @@ static const struct bmc150_accel_interrupt_info {
|
|||
BMC150_ACCEL_INT_EN_BIT_SLP_Y |
|
||||
BMC150_ACCEL_INT_EN_BIT_SLP_Z
|
||||
},
|
||||
{ /* fifo watermark interrupt */
|
||||
.map_reg = BMC150_ACCEL_REG_INT_MAP_1,
|
||||
.map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM,
|
||||
.en_reg = BMC150_ACCEL_REG_INT_EN_1,
|
||||
.en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN,
|
||||
},
|
||||
};
|
||||
|
||||
static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev,
|
||||
|
@ -823,6 +840,214 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int wm;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
wm = data->watermark;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return sprintf(buf, "%d\n", wm);
|
||||
}
|
||||
|
||||
static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
bool state;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
state = data->fifo_mode;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return sprintf(buf, "%d\n", state);
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
|
||||
static IIO_CONST_ATTR(hwfifo_watermark_max,
|
||||
__stringify(BMC150_ACCEL_FIFO_LENGTH));
|
||||
static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO,
|
||||
bmc150_accel_get_fifo_state, NULL, 0);
|
||||
static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO,
|
||||
bmc150_accel_get_fifo_watermark, NULL, 0);
|
||||
|
||||
static const struct attribute *bmc150_accel_fifo_attributes[] = {
|
||||
&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
|
||||
&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
|
||||
&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (val > BMC150_ACCEL_FIFO_LENGTH)
|
||||
val = BMC150_ACCEL_FIFO_LENGTH;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
data->watermark = val;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must read at least one full frame in one burst, otherwise the rest of the
|
||||
* frame data is discarded.
|
||||
*/
|
||||
static int bmc150_accel_fifo_transfer(const struct i2c_client *client,
|
||||
char *buffer, int samples)
|
||||
{
|
||||
int sample_length = 3 * 2;
|
||||
u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
|
||||
int ret = -EIO;
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.buf = ®_fifo_data,
|
||||
.len = sizeof(reg_fifo_data),
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.buf = (u8 *)buffer,
|
||||
.len = samples * sample_length,
|
||||
}
|
||||
};
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
if (ret != 2)
|
||||
ret = -EIO;
|
||||
else
|
||||
ret = 0;
|
||||
} else {
|
||||
int i, step = I2C_SMBUS_BLOCK_MAX / sample_length;
|
||||
|
||||
for (i = 0; i < samples * sample_length; i += step) {
|
||||
ret = i2c_smbus_read_i2c_block_data(client,
|
||||
reg_fifo_data, step,
|
||||
&buffer[i]);
|
||||
if (ret != step) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Error transferring data from fifo\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
|
||||
unsigned samples, bool irq)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int ret, i;
|
||||
u8 count;
|
||||
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
|
||||
int64_t tstamp;
|
||||
uint64_t sample_period;
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_FIFO_STATUS);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_fifo_status\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
count = ret & 0x7F;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we getting called from IRQ handler we know the stored timestamp is
|
||||
* fairly accurate for the last stored sample. Otherwise, if we are
|
||||
* called as a result of a read operation from userspace and hence
|
||||
* before the watermark interrupt was triggered, take a timestamp
|
||||
* now. We can fall anywhere in between two samples so the error in this
|
||||
* case is at most one sample period.
|
||||
*/
|
||||
if (!irq) {
|
||||
data->old_timestamp = data->timestamp;
|
||||
data->timestamp = iio_get_time_ns();
|
||||
}
|
||||
|
||||
/*
|
||||
* Approximate timestamps for each of the sample based on the sampling
|
||||
* frequency, timestamp for last sample and number of samples.
|
||||
*
|
||||
* Note that we can't use the current bandwidth settings to compute the
|
||||
* sample period because the sample rate varies with the device
|
||||
* (e.g. between 31.70ms to 32.20ms for a bandwidth of 15.63HZ). That
|
||||
* small variation adds when we store a large number of samples and
|
||||
* creates significant jitter between the last and first samples in
|
||||
* different batches (e.g. 32ms vs 21ms).
|
||||
*
|
||||
* To avoid this issue we compute the actual sample period ourselves
|
||||
* based on the timestamp delta between the last two flush operations.
|
||||
*/
|
||||
sample_period = (data->timestamp - data->old_timestamp);
|
||||
do_div(sample_period, count);
|
||||
tstamp = data->timestamp - (count - 1) * sample_period;
|
||||
|
||||
if (samples && count > samples)
|
||||
count = samples;
|
||||
|
||||
ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Ideally we want the IIO core to handle the demux when running in fifo
|
||||
* mode but not when running in triggered buffer mode. Unfortunately
|
||||
* this does not seem to be possible, so stick with driver demux for
|
||||
* now.
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
u16 sample[8];
|
||||
int j, bit;
|
||||
|
||||
j = 0;
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength)
|
||||
memcpy(&sample[j++], &buffer[i * 3 + bit], 2);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp);
|
||||
|
||||
tstamp += sample_period;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = __bmc150_accel_fifo_flush(indio_dev, samples, false);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
|
||||
|
||||
|
@ -962,6 +1187,20 @@ static const struct iio_info bmc150_accel_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info bmc150_accel_info_fifo = {
|
||||
.attrs = &bmc150_accel_attrs_group,
|
||||
.read_raw = bmc150_accel_read_raw,
|
||||
.write_raw = bmc150_accel_write_raw,
|
||||
.read_event_value = bmc150_accel_read_event,
|
||||
.write_event_value = bmc150_accel_write_event,
|
||||
.write_event_config = bmc150_accel_write_event_config,
|
||||
.read_event_config = bmc150_accel_read_event_config,
|
||||
.validate_trigger = bmc150_accel_validate_trigger,
|
||||
.hwfifo_set_watermark = bmc150_accel_set_watermark,
|
||||
.hwfifo_flush_to_buffer = bmc150_accel_fifo_flush,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
|
@ -1057,18 +1296,17 @@ static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
|
||||
static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
int dir;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_INT_STATUS_2);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_status_2\n");
|
||||
goto ack_intr_status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
|
||||
|
@ -1097,35 +1335,73 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
|
|||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
data->timestamp);
|
||||
ack_intr_status:
|
||||
if (!data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY].enabled)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
bool ack = false;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (data->fifo_mode) {
|
||||
ret = __bmc150_accel_fifo_flush(indio_dev,
|
||||
BMC150_ACCEL_FIFO_LENGTH, true);
|
||||
if (ret > 0)
|
||||
ack = true;
|
||||
}
|
||||
|
||||
if (data->ev_enable_state) {
|
||||
ret = bmc150_accel_handle_roc_event(indio_dev);
|
||||
if (ret > 0)
|
||||
ack = true;
|
||||
}
|
||||
|
||||
if (ack) {
|
||||
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)
|
||||
dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
|
||||
ret = IRQ_HANDLED;
|
||||
} else {
|
||||
ret = IRQ_NONE;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private)
|
||||
static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
bool ack = false;
|
||||
int i;
|
||||
|
||||
data->old_timestamp = data->timestamp;
|
||||
data->timestamp = iio_get_time_ns();
|
||||
|
||||
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
|
||||
if (data->triggers[i].enabled) {
|
||||
iio_trigger_poll(data->triggers[i].indio_trig);
|
||||
ack = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->ev_enable_state)
|
||||
if (data->ev_enable_state || data->fifo_mode)
|
||||
return IRQ_WAKE_THREAD;
|
||||
else
|
||||
|
||||
if (ack)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
|
||||
|
@ -1232,6 +1508,94 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define BMC150_ACCEL_FIFO_MODE_STREAM 0x80
|
||||
#define BMC150_ACCEL_FIFO_MODE_FIFO 0x40
|
||||
#define BMC150_ACCEL_FIFO_MODE_BYPASS 0x00
|
||||
|
||||
static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
|
||||
{
|
||||
u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!data->fifo_mode)
|
||||
return 0;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
BMC150_ACCEL_REG_FIFO_CONFIG0,
|
||||
data->watermark);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
||||
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED)
|
||||
return iio_triggered_buffer_postenable(indio_dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!data->watermark)
|
||||
goto out;
|
||||
|
||||
ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK,
|
||||
true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data->fifo_mode = BMC150_ACCEL_FIFO_MODE_FIFO;
|
||||
|
||||
ret = bmc150_accel_fifo_set_mode(data);
|
||||
if (ret) {
|
||||
data->fifo_mode = 0;
|
||||
bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK,
|
||||
false);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED)
|
||||
return iio_triggered_buffer_predisable(indio_dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!data->fifo_mode)
|
||||
goto out;
|
||||
|
||||
bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false);
|
||||
__bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false);
|
||||
data->fifo_mode = 0;
|
||||
bmc150_accel_fifo_set_mode(data);
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
|
||||
.postenable = bmc150_accel_buffer_postenable,
|
||||
.predisable = bmc150_accel_buffer_predisable,
|
||||
};
|
||||
|
||||
static int bmc150_accel_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -1278,8 +1642,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
if (client->irq >= 0) {
|
||||
ret = devm_request_threaded_irq(
|
||||
&client->dev, client->irq,
|
||||
bmc150_accel_data_rdy_trig_poll,
|
||||
bmc150_accel_event_handler,
|
||||
bmc150_accel_irq_handler,
|
||||
bmc150_accel_irq_thread_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
BMC150_ACCEL_IRQ_NAME,
|
||||
indio_dev);
|
||||
|
@ -1309,12 +1673,20 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
bmc150_accel_trigger_handler,
|
||||
NULL);
|
||||
&bmc150_accel_buffer_ops);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed: iio triggered buffer setup\n");
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
|
||||
i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->info = &bmc150_accel_info_fifo;
|
||||
indio_dev->buffer->attrs = bmc150_accel_fifo_attributes;
|
||||
}
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -1386,6 +1758,7 @@ static int bmc150_accel_resume(struct device *dev)
|
|||
mutex_lock(&data->mutex);
|
||||
if (atomic_read(&data->active_intr))
|
||||
bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
|
||||
bmc150_accel_fifo_set_mode(data);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
|
@ -1417,6 +1790,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
|
|||
dev_dbg(&data->client->dev, __func__);
|
||||
|
||||
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = bmc150_accel_fifo_set_mode(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
||||
#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel"
|
||||
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
|
||||
#define LIS3DH_ACCEL_DEV_NAME "lis3dh"
|
||||
#define LSM330D_ACCEL_DEV_NAME "lsm330d_accel"
|
||||
|
|
|
@ -129,6 +129,30 @@
|
|||
#define ST_ACCEL_3_IG1_EN_MASK 0x08
|
||||
#define ST_ACCEL_3_MULTIREAD_BIT false
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 4 */
|
||||
#define ST_ACCEL_4_WAI_EXP 0x3a
|
||||
#define ST_ACCEL_4_ODR_ADDR 0x20
|
||||
#define ST_ACCEL_4_ODR_MASK 0x30 /* DF1 and DF0 */
|
||||
#define ST_ACCEL_4_ODR_AVL_40HZ_VAL 0x00
|
||||
#define ST_ACCEL_4_ODR_AVL_160HZ_VAL 0x01
|
||||
#define ST_ACCEL_4_ODR_AVL_640HZ_VAL 0x02
|
||||
#define ST_ACCEL_4_ODR_AVL_2560HZ_VAL 0x03
|
||||
#define ST_ACCEL_4_PW_ADDR 0x20
|
||||
#define ST_ACCEL_4_PW_MASK 0xc0
|
||||
#define ST_ACCEL_4_FS_ADDR 0x21
|
||||
#define ST_ACCEL_4_FS_MASK 0x80
|
||||
#define ST_ACCEL_4_FS_AVL_2_VAL 0X00
|
||||
#define ST_ACCEL_4_FS_AVL_6_VAL 0X01
|
||||
#define ST_ACCEL_4_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1024)
|
||||
#define ST_ACCEL_4_FS_AVL_6_GAIN IIO_G_TO_M_S_2(340)
|
||||
#define ST_ACCEL_4_BDU_ADDR 0x21
|
||||
#define ST_ACCEL_4_BDU_MASK 0x40
|
||||
#define ST_ACCEL_4_DRDY_IRQ_ADDR 0x21
|
||||
#define ST_ACCEL_4_DRDY_IRQ_INT1_MASK 0x04
|
||||
#define ST_ACCEL_4_IG1_EN_ADDR 0x21
|
||||
#define ST_ACCEL_4_IG1_EN_MASK 0x08
|
||||
#define ST_ACCEL_4_MULTIREAD_BIT true
|
||||
|
||||
static const struct iio_chan_spec st_accel_12bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
|
@ -373,6 +397,63 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
{
|
||||
.wai = ST_ACCEL_4_WAI_EXP,
|
||||
.sensors_supported = {
|
||||
[0] = LIS3LV02DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
|
||||
.odr = {
|
||||
.addr = ST_ACCEL_4_ODR_ADDR,
|
||||
.mask = ST_ACCEL_4_ODR_MASK,
|
||||
.odr_avl = {
|
||||
{ 40, ST_ACCEL_4_ODR_AVL_40HZ_VAL },
|
||||
{ 160, ST_ACCEL_4_ODR_AVL_160HZ_VAL, },
|
||||
{ 640, ST_ACCEL_4_ODR_AVL_640HZ_VAL, },
|
||||
{ 2560, ST_ACCEL_4_ODR_AVL_2560HZ_VAL, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = ST_ACCEL_4_PW_ADDR,
|
||||
.mask = ST_ACCEL_4_PW_MASK,
|
||||
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
||||
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
||||
},
|
||||
.enable_axis = {
|
||||
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
|
||||
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
|
||||
},
|
||||
.fs = {
|
||||
.addr = ST_ACCEL_4_FS_ADDR,
|
||||
.mask = ST_ACCEL_4_FS_MASK,
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_ACCEL_FS_AVL_2G,
|
||||
.value = ST_ACCEL_4_FS_AVL_2_VAL,
|
||||
.gain = ST_ACCEL_4_FS_AVL_2_GAIN,
|
||||
},
|
||||
[1] = {
|
||||
.num = ST_ACCEL_FS_AVL_6G,
|
||||
.value = ST_ACCEL_4_FS_AVL_6_VAL,
|
||||
.gain = ST_ACCEL_4_FS_AVL_6_GAIN,
|
||||
},
|
||||
},
|
||||
},
|
||||
.bdu = {
|
||||
.addr = ST_ACCEL_4_BDU_ADDR,
|
||||
.mask = ST_ACCEL_4_BDU_MASK,
|
||||
},
|
||||
.drdy_irq = {
|
||||
.addr = ST_ACCEL_4_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_4_DRDY_IRQ_INT1_MASK,
|
||||
.ig1 = {
|
||||
.en_addr = ST_ACCEL_4_IG1_EN_ADDR,
|
||||
.en_mask = ST_ACCEL_4_IG1_EN_MASK,
|
||||
},
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
|
||||
.bootime = 2, /* guess */
|
||||
},
|
||||
};
|
||||
|
||||
static int st_accel_read_raw(struct iio_dev *indio_dev,
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st_accel_of_match[] = {
|
||||
{
|
||||
.compatible = "st,lis3lv02dl-accel",
|
||||
.data = LIS3LV02DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303dlh-accel",
|
||||
.data = LSM303DLH_ACCEL_DEV_NAME,
|
||||
|
|
|
@ -437,7 +437,7 @@ int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id ssp_of_match[] = {
|
||||
static const struct of_device_id ssp_of_match[] = {
|
||||
{
|
||||
.compatible = "samsung,sensorhub-rinato",
|
||||
.data = &ssp_rinato_info,
|
||||
|
|
|
@ -143,11 +143,16 @@ config AD7303
|
|||
ad7303.
|
||||
|
||||
config MAX517
|
||||
tristate "Maxim MAX517/518/519 DAC driver"
|
||||
tristate "Maxim MAX517/518/519/520/521 DAC driver"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Maxim chips MAX517,
|
||||
MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
|
||||
If you say yes here you get support for the following Maxim chips
|
||||
(I2C 8-Bit DACs with rail-to-rail outputs):
|
||||
MAX517 - Single channel, single reference
|
||||
MAX518 - Dual channel, ref=Vdd
|
||||
MAX519 - Dual channel, dual reference
|
||||
MAX520 - Quad channel, quad reference
|
||||
MAX521 - Octal channel, independent ref for ch0-3, shared ref for ch4-7
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max517.
|
||||
|
|
|
@ -39,11 +39,13 @@ enum max517_device_ids {
|
|||
ID_MAX517,
|
||||
ID_MAX518,
|
||||
ID_MAX519,
|
||||
ID_MAX520,
|
||||
ID_MAX521,
|
||||
};
|
||||
|
||||
struct max517_data {
|
||||
struct i2c_client *client;
|
||||
unsigned short vref_mv[2];
|
||||
unsigned short vref_mv[8];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -149,7 +151,13 @@ static const struct iio_info max517_info = {
|
|||
|
||||
static const struct iio_chan_spec max517_channels[] = {
|
||||
MAX517_CHANNEL(0),
|
||||
MAX517_CHANNEL(1)
|
||||
MAX517_CHANNEL(1),
|
||||
MAX517_CHANNEL(2),
|
||||
MAX517_CHANNEL(3),
|
||||
MAX517_CHANNEL(4),
|
||||
MAX517_CHANNEL(5),
|
||||
MAX517_CHANNEL(6),
|
||||
MAX517_CHANNEL(7),
|
||||
};
|
||||
|
||||
static int max517_probe(struct i2c_client *client,
|
||||
|
@ -158,6 +166,7 @@ static int max517_probe(struct i2c_client *client,
|
|||
struct max517_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
struct max517_platform_data *platform_data = client->dev.platform_data;
|
||||
int chan;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -169,11 +178,21 @@ static int max517_probe(struct i2c_client *client,
|
|||
/* establish that the iio_dev is a child of the i2c device */
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
|
||||
/* reduced channel set for MAX517 */
|
||||
if (id->driver_data == ID_MAX517)
|
||||
indio_dev->num_channels = 1;
|
||||
else
|
||||
switch (id->driver_data) {
|
||||
case ID_MAX521:
|
||||
indio_dev->num_channels = 8;
|
||||
break;
|
||||
case ID_MAX520:
|
||||
indio_dev->num_channels = 4;
|
||||
break;
|
||||
case ID_MAX519:
|
||||
case ID_MAX518:
|
||||
indio_dev->num_channels = 2;
|
||||
break;
|
||||
default: /* single channel for MAX517 */
|
||||
indio_dev->num_channels = 1;
|
||||
break;
|
||||
}
|
||||
indio_dev->channels = max517_channels;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &max517_info;
|
||||
|
@ -182,11 +201,11 @@ static int max517_probe(struct i2c_client *client,
|
|||
* Reference voltage on MAX518 and default is 5V, else take vref_mv
|
||||
* from platform_data
|
||||
*/
|
||||
if (id->driver_data == ID_MAX518 || !platform_data) {
|
||||
data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
|
||||
} else {
|
||||
data->vref_mv[0] = platform_data->vref_mv[0];
|
||||
data->vref_mv[1] = platform_data->vref_mv[1];
|
||||
for (chan = 0; chan < indio_dev->num_channels; chan++) {
|
||||
if (id->driver_data == ID_MAX518 || !platform_data)
|
||||
data->vref_mv[chan] = 5000; /* mV */
|
||||
else
|
||||
data->vref_mv[chan] = platform_data->vref_mv[chan];
|
||||
}
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
|
@ -202,6 +221,8 @@ static const struct i2c_device_id max517_id[] = {
|
|||
{ "max517", ID_MAX517 },
|
||||
{ "max518", ID_MAX518 },
|
||||
{ "max519", ID_MAX519 },
|
||||
{ "max520", ID_MAX520 },
|
||||
{ "max521", ID_MAX521 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max517_id);
|
||||
|
@ -218,5 +239,5 @@ static struct i2c_driver max517_driver = {
|
|||
module_i2c_driver(max517_driver);
|
||||
|
||||
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
|
||||
MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
|
||||
MODULE_DESCRIPTION("MAX517/518/519/520/521 8-bit DAC");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -87,6 +87,31 @@
|
|||
#define ST_GYRO_2_DRDY_IRQ_INT2_MASK 0x08
|
||||
#define ST_GYRO_2_MULTIREAD_BIT true
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 3 */
|
||||
#define ST_GYRO_3_WAI_EXP 0xd7
|
||||
#define ST_GYRO_3_ODR_ADDR 0x20
|
||||
#define ST_GYRO_3_ODR_MASK 0xc0
|
||||
#define ST_GYRO_3_ODR_AVL_95HZ_VAL 0x00
|
||||
#define ST_GYRO_3_ODR_AVL_190HZ_VAL 0x01
|
||||
#define ST_GYRO_3_ODR_AVL_380HZ_VAL 0x02
|
||||
#define ST_GYRO_3_ODR_AVL_760HZ_VAL 0x03
|
||||
#define ST_GYRO_3_PW_ADDR 0x20
|
||||
#define ST_GYRO_3_PW_MASK 0x08
|
||||
#define ST_GYRO_3_FS_ADDR 0x23
|
||||
#define ST_GYRO_3_FS_MASK 0x30
|
||||
#define ST_GYRO_3_FS_AVL_250_VAL 0x00
|
||||
#define ST_GYRO_3_FS_AVL_500_VAL 0x01
|
||||
#define ST_GYRO_3_FS_AVL_2000_VAL 0x02
|
||||
#define ST_GYRO_3_FS_AVL_250_GAIN IIO_DEGREE_TO_RAD(8750)
|
||||
#define ST_GYRO_3_FS_AVL_500_GAIN IIO_DEGREE_TO_RAD(17500)
|
||||
#define ST_GYRO_3_FS_AVL_2000_GAIN IIO_DEGREE_TO_RAD(70000)
|
||||
#define ST_GYRO_3_BDU_ADDR 0x23
|
||||
#define ST_GYRO_3_BDU_MASK 0x80
|
||||
#define ST_GYRO_3_DRDY_IRQ_ADDR 0x22
|
||||
#define ST_GYRO_3_DRDY_IRQ_INT2_MASK 0x08
|
||||
#define ST_GYRO_3_MULTIREAD_BIT true
|
||||
|
||||
|
||||
static const struct iio_chan_spec st_gyro_16bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
|
@ -225,6 +250,64 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
|
|||
.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
{
|
||||
.wai = ST_GYRO_3_WAI_EXP,
|
||||
.sensors_supported = {
|
||||
[0] = L3GD20_GYRO_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
|
||||
.odr = {
|
||||
.addr = ST_GYRO_3_ODR_ADDR,
|
||||
.mask = ST_GYRO_3_ODR_MASK,
|
||||
.odr_avl = {
|
||||
{ 95, ST_GYRO_3_ODR_AVL_95HZ_VAL, },
|
||||
{ 190, ST_GYRO_3_ODR_AVL_190HZ_VAL, },
|
||||
{ 380, ST_GYRO_3_ODR_AVL_380HZ_VAL, },
|
||||
{ 760, ST_GYRO_3_ODR_AVL_760HZ_VAL, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = ST_GYRO_3_PW_ADDR,
|
||||
.mask = ST_GYRO_3_PW_MASK,
|
||||
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
||||
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
||||
},
|
||||
.enable_axis = {
|
||||
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
|
||||
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
|
||||
},
|
||||
.fs = {
|
||||
.addr = ST_GYRO_3_FS_ADDR,
|
||||
.mask = ST_GYRO_3_FS_MASK,
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_GYRO_FS_AVL_250DPS,
|
||||
.value = ST_GYRO_3_FS_AVL_250_VAL,
|
||||
.gain = ST_GYRO_3_FS_AVL_250_GAIN,
|
||||
},
|
||||
[1] = {
|
||||
.num = ST_GYRO_FS_AVL_500DPS,
|
||||
.value = ST_GYRO_3_FS_AVL_500_VAL,
|
||||
.gain = ST_GYRO_3_FS_AVL_500_GAIN,
|
||||
},
|
||||
[2] = {
|
||||
.num = ST_GYRO_FS_AVL_2000DPS,
|
||||
.value = ST_GYRO_3_FS_AVL_2000_VAL,
|
||||
.gain = ST_GYRO_3_FS_AVL_2000_GAIN,
|
||||
},
|
||||
},
|
||||
},
|
||||
.bdu = {
|
||||
.addr = ST_GYRO_3_BDU_ADDR,
|
||||
.mask = ST_GYRO_3_BDU_MASK,
|
||||
},
|
||||
.drdy_irq = {
|
||||
.addr = ST_GYRO_3_DRDY_IRQ_ADDR,
|
||||
.mask_int2 = ST_GYRO_3_DRDY_IRQ_INT2_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_GYRO_3_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static int st_gyro_read_raw(struct iio_dev *indio_dev,
|
||||
|
|
|
@ -37,11 +37,57 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
|
|||
return !list_empty(&buf->buffer_list);
|
||||
}
|
||||
|
||||
static bool iio_buffer_data_available(struct iio_buffer *buf)
|
||||
static size_t iio_buffer_data_available(struct iio_buffer *buf)
|
||||
{
|
||||
return buf->access->data_available(buf);
|
||||
}
|
||||
|
||||
static int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *buf, size_t required)
|
||||
{
|
||||
if (!indio_dev->info->hwfifo_flush_to_buffer)
|
||||
return -ENODEV;
|
||||
|
||||
return indio_dev->info->hwfifo_flush_to_buffer(indio_dev, required);
|
||||
}
|
||||
|
||||
static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
|
||||
size_t to_wait, int to_flush)
|
||||
{
|
||||
size_t avail;
|
||||
int flushed = 0;
|
||||
|
||||
/* wakeup if the device was unregistered */
|
||||
if (!indio_dev->info)
|
||||
return true;
|
||||
|
||||
/* drain the buffer if it was disabled */
|
||||
if (!iio_buffer_is_active(buf)) {
|
||||
to_wait = min_t(size_t, to_wait, 1);
|
||||
to_flush = 0;
|
||||
}
|
||||
|
||||
avail = iio_buffer_data_available(buf);
|
||||
|
||||
if (avail >= to_wait) {
|
||||
/* force a flush for non-blocking reads */
|
||||
if (!to_wait && !avail && to_flush)
|
||||
iio_buffer_flush_hwfifo(indio_dev, buf, to_flush);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (to_flush)
|
||||
flushed = iio_buffer_flush_hwfifo(indio_dev, buf,
|
||||
to_wait - avail);
|
||||
if (flushed <= 0)
|
||||
return false;
|
||||
|
||||
if (avail + flushed >= to_wait)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
|
||||
*
|
||||
|
@ -53,6 +99,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
{
|
||||
struct iio_dev *indio_dev = filp->private_data;
|
||||
struct iio_buffer *rb = indio_dev->buffer;
|
||||
size_t datum_size;
|
||||
size_t to_wait = 0;
|
||||
size_t to_read;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
|
@ -61,19 +110,28 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
if (!rb || !rb->access->read_first_n)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
if (!iio_buffer_data_available(rb)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
datum_size = rb->bytes_per_datum;
|
||||
|
||||
ret = wait_event_interruptible(rb->pollq,
|
||||
iio_buffer_data_available(rb) ||
|
||||
indio_dev->info == NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (indio_dev->info == NULL)
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* If datum_size is 0 there will never be anything to read from the
|
||||
* buffer, so signal end of file now.
|
||||
*/
|
||||
if (!datum_size)
|
||||
return 0;
|
||||
|
||||
to_read = min_t(size_t, n / datum_size, rb->watermark);
|
||||
|
||||
if (!(filp->f_flags & O_NONBLOCK))
|
||||
to_wait = to_read;
|
||||
|
||||
do {
|
||||
ret = wait_event_interruptible(rb->pollq,
|
||||
iio_buffer_ready(indio_dev, rb, to_wait, to_read));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
ret = rb->access->read_first_n(rb, n, buf);
|
||||
if (ret == 0 && (filp->f_flags & O_NONBLOCK))
|
||||
|
@ -96,9 +154,8 @@ unsigned int iio_buffer_poll(struct file *filp,
|
|||
return -ENODEV;
|
||||
|
||||
poll_wait(filp, &rb->pollq, wait);
|
||||
if (iio_buffer_data_available(rb))
|
||||
if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0))
|
||||
return POLLIN | POLLRDNORM;
|
||||
/* need a way of knowing if there may be enough data... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -123,6 +180,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
|
|||
INIT_LIST_HEAD(&buffer->buffer_list);
|
||||
init_waitqueue_head(&buffer->pollq);
|
||||
kref_init(&buffer->ref);
|
||||
buffer->watermark = 1;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_buffer_init);
|
||||
|
||||
|
@ -416,6 +474,11 @@ static ssize_t iio_buffer_write_length(struct device *dev,
|
|||
buffer->access->set_length(buffer, val);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
if (buffer->length && buffer->length < buffer->watermark)
|
||||
buffer->watermark = buffer->length;
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
|
@ -472,6 +535,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
|
|||
static void iio_buffer_deactivate(struct iio_buffer *buffer)
|
||||
{
|
||||
list_del_init(&buffer->buffer_list);
|
||||
wake_up_interruptible(&buffer->pollq);
|
||||
iio_buffer_put(buffer);
|
||||
}
|
||||
|
||||
|
@ -629,19 +693,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
/* Definitely possible for devices to support both of these. */
|
||||
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
|
||||
if (!indio_dev->trig) {
|
||||
printk(KERN_INFO "Buffer not started: no trigger\n");
|
||||
ret = -EINVAL;
|
||||
/* Can only occur on first buffer */
|
||||
goto error_run_postdisable;
|
||||
}
|
||||
if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
|
||||
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
|
||||
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
|
||||
} else { /* Should never be reached */
|
||||
/* Can only occur on first buffer */
|
||||
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
|
||||
pr_info("Buffer not started: no trigger\n");
|
||||
ret = -EINVAL;
|
||||
goto error_run_postdisable;
|
||||
}
|
||||
|
@ -754,16 +815,67 @@ done:
|
|||
|
||||
static const char * const iio_scan_elements_group_name = "scan_elements";
|
||||
|
||||
static ssize_t iio_buffer_show_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_buffer *buffer = indio_dev->buffer;
|
||||
|
||||
return sprintf(buf, "%u\n", buffer->watermark);
|
||||
}
|
||||
|
||||
static ssize_t iio_buffer_store_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_buffer *buffer = indio_dev->buffer;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if (val > buffer->length) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iio_buffer_is_active(indio_dev->buffer)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer->watermark = val;
|
||||
|
||||
if (indio_dev->info->hwfifo_set_watermark)
|
||||
indio_dev->info->hwfifo_set_watermark(indio_dev, val);
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
|
||||
iio_buffer_write_length);
|
||||
static struct device_attribute dev_attr_length_ro = __ATTR(length,
|
||||
S_IRUGO, iio_buffer_read_length, NULL);
|
||||
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
|
||||
iio_buffer_show_enable, iio_buffer_store_enable);
|
||||
static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR,
|
||||
iio_buffer_show_watermark, iio_buffer_store_watermark);
|
||||
|
||||
static struct attribute *iio_buffer_attrs[] = {
|
||||
&dev_attr_length.attr,
|
||||
&dev_attr_enable.attr,
|
||||
&dev_attr_watermark.attr,
|
||||
};
|
||||
|
||||
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
|
||||
|
@ -944,8 +1056,18 @@ static const void *iio_demux(struct iio_buffer *buffer,
|
|||
static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
|
||||
{
|
||||
const void *dataout = iio_demux(buffer, data);
|
||||
int ret;
|
||||
|
||||
return buffer->access->store_to(buffer, dataout);
|
||||
ret = buffer->access->store_to(buffer, dataout);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We can't just test for watermark to decide if we wake the poll queue
|
||||
* because read may request less samples than the watermark.
|
||||
*/
|
||||
wake_up_interruptible_poll(&buffer->pollq, POLLIN | POLLRDNORM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iio_buffer_demux_free(struct iio_buffer *buffer)
|
||||
|
|
|
@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
|
|||
ret = kfifo_in(&kf->kf, data, 1);
|
||||
if (ret != 1)
|
||||
return -EBUSY;
|
||||
|
||||
wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
|
|||
return copied;
|
||||
}
|
||||
|
||||
static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
|
||||
static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
|
||||
{
|
||||
struct iio_kfifo *kf = iio_to_kfifo(r);
|
||||
bool empty;
|
||||
size_t samples;
|
||||
|
||||
mutex_lock(&kf->user_lock);
|
||||
empty = kfifo_is_empty(&kf->kf);
|
||||
samples = kfifo_len(&kf->kf);
|
||||
mutex_unlock(&kf->user_lock);
|
||||
|
||||
return !empty;
|
||||
return samples;
|
||||
}
|
||||
|
||||
static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
|
||||
*
|
||||
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
* Copyright (c) 2015 Essensium NV
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
|
@ -20,11 +21,35 @@
|
|||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define MLX90614_OP_RAM 0x00
|
||||
#define MLX90614_OP_RAM 0x00
|
||||
#define MLX90614_OP_EEPROM 0x20
|
||||
#define MLX90614_OP_SLEEP 0xff
|
||||
|
||||
/* RAM offsets with 16-bit data, MSB first */
|
||||
#define MLX90614_RAW1 (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */
|
||||
#define MLX90614_RAW2 (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */
|
||||
#define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */
|
||||
#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */
|
||||
#define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */
|
||||
|
||||
/* EEPROM offsets with 16-bit data, MSB first */
|
||||
#define MLX90614_EMISSIVITY (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */
|
||||
#define MLX90614_CONFIG (MLX90614_OP_EEPROM | 0x05) /* configuration register */
|
||||
|
||||
/* Control bits in configuration register */
|
||||
#define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */
|
||||
#define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT)
|
||||
#define MLX90614_CONFIG_DUAL_SHIFT 6 /* single (0) or dual (1) IR sensor */
|
||||
#define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT)
|
||||
#define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */
|
||||
#define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT)
|
||||
#define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */
|
||||
#define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT)
|
||||
|
||||
/* Timings (in ms) */
|
||||
#define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
|
||||
#define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */
|
||||
#define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */
|
||||
|
||||
struct mlx90614_data {
|
||||
struct i2c_client *client;
|
||||
|
@ -35,26 +60,34 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
|
|||
int *val2, long mask)
|
||||
{
|
||||
struct mlx90614_data *data = iio_priv(indio_dev);
|
||||
u8 cmd;
|
||||
s32 ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
|
||||
switch (channel->channel2) {
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
ret = i2c_smbus_read_word_data(data->client,
|
||||
MLX90614_TA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cmd = MLX90614_TA;
|
||||
break;
|
||||
case IIO_MOD_TEMP_OBJECT:
|
||||
ret = i2c_smbus_read_word_data(data->client,
|
||||
MLX90614_TOBJ1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
switch (channel->channel) {
|
||||
case 0:
|
||||
cmd = MLX90614_TOBJ1;
|
||||
break;
|
||||
case 1:
|
||||
cmd = MLX90614_TOBJ2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
|
@ -86,6 +119,16 @@ static const struct iio_chan_spec mlx90614_channels[] = {
|
|||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 1,
|
||||
.modified = 1,
|
||||
.channel = 1,
|
||||
.channel2 = IIO_MOD_TEMP_OBJECT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info mlx90614_info = {
|
||||
|
@ -93,11 +136,25 @@ static const struct iio_info mlx90614_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
/* Return 0 for single sensor, 1 for dual sensor, <0 on error. */
|
||||
static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int mlx90614_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct mlx90614_data *data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
@ -115,8 +172,21 @@ static int mlx90614_probe(struct i2c_client *client,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mlx90614_info;
|
||||
|
||||
indio_dev->channels = mlx90614_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels);
|
||||
ret = mlx90614_probe_num_ir_sensors(client);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
dev_dbg(&client->dev, "Found single sensor");
|
||||
indio_dev->channels = mlx90614_channels;
|
||||
indio_dev->num_channels = 2;
|
||||
break;
|
||||
case 1:
|
||||
dev_dbg(&client->dev, "Found dual sensor");
|
||||
indio_dev->channels = mlx90614_channels;
|
||||
indio_dev->num_channels = 3;
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
|
||||
return iio_device_register(indio_dev);
|
||||
}
|
||||
|
@ -146,5 +216,6 @@ static struct i2c_driver mlx90614_driver = {
|
|||
module_i2c_driver(mlx90614_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
|
||||
MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -129,9 +129,9 @@ error_ret:
|
|||
return ret ? ret : num_read;
|
||||
}
|
||||
|
||||
static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
|
||||
static size_t sca3000_ring_buf_data_available(struct iio_buffer *r)
|
||||
{
|
||||
return r->stufftoread;
|
||||
return r->stufftoread ? r->watermark : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,8 +21,8 @@ struct iio_buffer;
|
|||
* struct iio_buffer_access_funcs - access functions for buffers.
|
||||
* @store_to: actually store stuff to the buffer
|
||||
* @read_first_n: try to get a specified number of bytes (must exist)
|
||||
* @data_available: indicates whether data for reading from the buffer is
|
||||
* available.
|
||||
* @data_available: indicates how much data is available for reading from
|
||||
* the buffer.
|
||||
* @request_update: if a parameter change has been marked, update underlying
|
||||
* storage.
|
||||
* @set_bytes_per_datum:set number of bytes per datum
|
||||
|
@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
|
|||
int (*read_first_n)(struct iio_buffer *buffer,
|
||||
size_t n,
|
||||
char __user *buf);
|
||||
bool (*data_available)(struct iio_buffer *buffer);
|
||||
size_t (*data_available)(struct iio_buffer *buffer);
|
||||
|
||||
int (*request_update)(struct iio_buffer *buffer);
|
||||
|
||||
|
@ -72,6 +72,7 @@ struct iio_buffer_access_funcs {
|
|||
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
|
||||
* @buffer_list: [INTERN] entry in the devices list of current buffers.
|
||||
* @ref: [INTERN] reference count of the buffer.
|
||||
* @watermark: [INTERN] number of datums to wait for poll/read.
|
||||
*/
|
||||
struct iio_buffer {
|
||||
int length;
|
||||
|
@ -90,6 +91,7 @@ struct iio_buffer {
|
|||
void *demux_bounce;
|
||||
struct list_head buffer_list;
|
||||
struct kref ref;
|
||||
unsigned int watermark;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#define IIO_DAC_MAX517_H_
|
||||
|
||||
struct max517_platform_data {
|
||||
u16 vref_mv[2];
|
||||
u16 vref_mv[8];
|
||||
};
|
||||
|
||||
#endif /* IIO_DAC_MAX517_H_ */
|
||||
|
|
|
@ -338,6 +338,16 @@ struct iio_dev;
|
|||
* provide a custom of_xlate function that reads the
|
||||
* *args* and returns the appropriate index in registered
|
||||
* IIO channels array.
|
||||
* @hwfifo_set_watermark: function pointer to set the current hardware
|
||||
* fifo watermark level; see hwfifo_* entries in
|
||||
* Documentation/ABI/testing/sysfs-bus-iio for details on
|
||||
* how the hardware fifo operates
|
||||
* @hwfifo_flush_to_buffer: function pointer to flush the samples stored
|
||||
* in the hardware fifo to the device buffer. The driver
|
||||
* should not flush more than count samples. The function
|
||||
* must return the number of samples flushed, 0 if no
|
||||
* samples were flushed or a negative integer if no samples
|
||||
* were flushed and there was an error.
|
||||
**/
|
||||
struct iio_info {
|
||||
struct module *driver_module;
|
||||
|
@ -399,6 +409,9 @@ struct iio_info {
|
|||
unsigned *readval);
|
||||
int (*of_xlate)(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec);
|
||||
int (*hwfifo_set_watermark)(struct iio_dev *indio_dev, unsigned val);
|
||||
int (*hwfifo_flush_to_buffer)(struct iio_dev *indio_dev,
|
||||
unsigned count);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
const char *iio_dir = "/sys/bus/iio/devices/";
|
||||
|
||||
static char * const iio_direction[] = {
|
||||
"in",
|
||||
"out",
|
||||
};
|
||||
|
||||
/**
|
||||
* iioutils_break_up_name() - extract generic name from full channel name
|
||||
* @full_name: the full channel name
|
||||
|
@ -30,10 +35,19 @@ int iioutils_break_up_name(const char *full_name,
|
|||
{
|
||||
char *current;
|
||||
char *w, *r;
|
||||
char *working;
|
||||
char *working, *prefix = "";
|
||||
int i;
|
||||
|
||||
current = strdup(full_name);
|
||||
for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
|
||||
if (!strncmp(full_name, iio_direction[i],
|
||||
strlen(iio_direction[i]))) {
|
||||
prefix = iio_direction[i];
|
||||
break;
|
||||
}
|
||||
|
||||
current = strdup(full_name + strlen(prefix) + 1);
|
||||
working = strtok(current, "_\0");
|
||||
|
||||
w = working;
|
||||
r = working;
|
||||
|
||||
|
@ -45,7 +59,7 @@ int iioutils_break_up_name(const char *full_name,
|
|||
r++;
|
||||
}
|
||||
*w = '\0';
|
||||
*generic_name = strdup(working);
|
||||
asprintf(generic_name, "%s_%s", prefix, working);
|
||||
free(current);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue