Commit 67573270 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.1b' of...

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.
parents f8da055a e0631a31
...@@ -254,6 +254,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset ...@@ -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_pressure_offset
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_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_magn_offset
What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -297,6 +298,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale ...@@ -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_pressure_scale
What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_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_velocity_sqrt(x^2+y^2+z^2)_scale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -337,6 +339,7 @@ what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale ...@@ -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_proximity0_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_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_pressure_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibscale
KernelVersion: 2.6.35 KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -348,7 +351,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_activity_calibgender ...@@ -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_energy_calibgender
What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender What: /sys/bus/iio/devices/iio:deviceX/in_velocity_calibgender
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Gender of the user (e.g.: male, female) used by some pedometers 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 ...@@ -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_energy_calibgender_available
What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender_available What: /sys/bus/iio/devices/iio:deviceX/in_distance_calibgender_available
What: /sys/bus/iio/devices/iio:deviceX/in_velocity_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 Contact: linux-iio@vger.kernel.org
Description: Description:
Lists all available gender values (e.g.: male, female). Lists all available gender values (e.g.: male, female).
...@@ -376,7 +379,7 @@ Description: ...@@ -376,7 +379,7 @@ Description:
type. type.
What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibweight What: /sys/bus/iio/devices/iio:deviceX/in_energy_calibweight
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Weight of the user (in kg). It is needed by some pedometers Weight of the user (in kg). It is needed by some pedometers
...@@ -797,7 +800,7 @@ Description: ...@@ -797,7 +800,7 @@ Description:
What: /sys/.../events/in_accel_x_thresh_rising_period What: /sys/.../events/in_accel_x_thresh_rising_period
What: /sys/.../events/in_accel_x_thresh_falling_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_x_roc_falling_period
What: /sys/.../events/in_accel_y_thresh_rising_period What: /sys/.../events/in_accel_y_thresh_rising_period
What: /sys/.../events/in_accel_y_thresh_falling_period What: /sys/.../events/in_accel_y_thresh_falling_period
...@@ -944,7 +947,7 @@ Description: ...@@ -944,7 +947,7 @@ Description:
this type. this type.
What: /sys/.../events/in_steps_change_en What: /sys/.../events/in_steps_change_en
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Event generated when channel passes a threshold on the absolute Event generated when channel passes a threshold on the absolute
...@@ -953,7 +956,7 @@ Description: ...@@ -953,7 +956,7 @@ Description:
in_steps_change_value. in_steps_change_value.
What: /sys/.../events/in_steps_change_value What: /sys/.../events/in_steps_change_value
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Specifies the value of change threshold that the Specifies the value of change threshold that the
...@@ -1128,7 +1131,7 @@ Description: ...@@ -1128,7 +1131,7 @@ Description:
What: /sys/.../iio:deviceX/in_energy_input What: /sys/.../iio:deviceX/in_energy_input
What: /sys/.../iio:deviceX/in_energy_raw What: /sys/.../iio:deviceX/in_energy_raw
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
This attribute is used to read the energy value reported by the This attribute is used to read the energy value reported by the
...@@ -1137,7 +1140,7 @@ Description: ...@@ -1137,7 +1140,7 @@ Description:
What: /sys/.../iio:deviceX/in_distance_input What: /sys/.../iio:deviceX/in_distance_input
What: /sys/.../iio:deviceX/in_distance_raw What: /sys/.../iio:deviceX/in_distance_raw
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
This attribute is used to read the distance covered by the user This attribute is used to read the distance covered by the user
...@@ -1167,9 +1170,13 @@ Description: ...@@ -1167,9 +1170,13 @@ Description:
values should behave in the same way as a distance, i.e. lower values should behave in the same way as a distance, i.e. lower
values indicate something is closer to the sensor. 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_input
What: /sys/.../iio:deviceX/in_illuminanceY_raw What: /sys/.../iio:deviceX/in_illuminanceY_raw
What: /sys/.../iio:deviceX/in_illuminanceY_mean_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 KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -1198,7 +1205,7 @@ Description: ...@@ -1198,7 +1205,7 @@ Description:
seconds. seconds.
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time 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 Contact: linux-iio@vger.kernel.org
Description: Description:
Number of seconds in which to compute speed. Number of seconds in which to compute speed.
...@@ -1260,7 +1267,7 @@ Description: ...@@ -1260,7 +1267,7 @@ Description:
Units after application of scale are m/s. Units after application of scale are m/s.
What: /sys/.../iio:deviceX/in_steps_debounce_count What: /sys/.../iio:deviceX/in_steps_debounce_count
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Specifies the number of steps that must occur within Specifies the number of steps that must occur within
...@@ -1268,8 +1275,92 @@ Description: ...@@ -1268,8 +1275,92 @@ Description:
consumer is making steps. consumer is making steps.
What: /sys/.../iio:deviceX/in_steps_debounce_time What: /sys/.../iio:deviceX/in_steps_debounce_time
KernelVersion: 3.20 KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Specifies number of seconds in which we compute the steps Specifies number of seconds in which we compute the steps
that occur in order to decide if the consumer is making 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. ...@@ -23,6 +23,7 @@ standard bindings from pinctrl/pinctrl-bindings.txt.
Valid compatible strings: Valid compatible strings:
Accelerometers: Accelerometers:
- st,lis3lv02dl-accel
- st,lsm303dlh-accel - st,lsm303dlh-accel
- st,lsm303dlhc-accel - st,lsm303dlhc-accel
- st,lis3dh-accel - st,lis3dh-accel
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define BMC150_ACCEL_REG_INT_MAP_1 0x1A #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_REG_INT_RST_LATCH 0x21
#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 #define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80
...@@ -84,6 +86,8 @@ ...@@ -84,6 +86,8 @@
#define BMC150_ACCEL_REG_INT_EN_1 0x17 #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_REG_INT_OUT_CTRL 0x20
#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) #define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0)
...@@ -122,6 +126,12 @@ ...@@ -122,6 +126,12 @@
#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) #define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2))
#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 #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 { enum bmc150_accel_axis {
AXIS_X, AXIS_X,
AXIS_Y, AXIS_Y,
...@@ -179,13 +189,14 @@ struct bmc150_accel_data { ...@@ -179,13 +189,14 @@ struct bmc150_accel_data {
atomic_t active_intr; atomic_t active_intr;
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
struct mutex mutex; struct mutex mutex;
u8 fifo_mode, watermark;
s16 buffer[8]; s16 buffer[8];
u8 bw_bits; u8 bw_bits;
u32 slope_dur; u32 slope_dur;
u32 slope_thres; u32 slope_thres;
u32 range; u32 range;
int ev_enable_state; int ev_enable_state;
int64_t timestamp; int64_t timestamp, old_timestamp;
const struct bmc150_accel_chip_info *chip_info; const struct bmc150_accel_chip_info *chip_info;
}; };
...@@ -470,6 +481,12 @@ static const struct bmc150_accel_interrupt_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_Y |
BMC150_ACCEL_INT_EN_BIT_SLP_Z 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, 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, ...@@ -823,6 +840,214 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev,
return -EINVAL; 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 = &reg_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( static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"7.810000 15.630000 31.250000 62.500000 125 250 500 1000"); "7.810000 15.630000 31.250000 62.500000 125 250 500 1000");
...@@ -962,6 +1187,20 @@ static const struct iio_info bmc150_accel_info = { ...@@ -962,6 +1187,20 @@ static const struct iio_info bmc150_accel_info = {
.driver_module = THIS_MODULE, .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) static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
{ {
struct iio_poll_func *pf = p; struct iio_poll_func *pf = p;
...@@ -1057,18 +1296,17 @@ static const struct iio_trigger_ops bmc150_accel_trigger_ops = { ...@@ -1057,18 +1296,17 @@ static const struct iio_trigger_ops bmc150_accel_trigger_ops = {
.owner = THIS_MODULE, .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); struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
int dir; int dir;
int ret;
ret = i2c_smbus_read_byte_data(data->client, ret = i2c_smbus_read_byte_data(data->client,
BMC150_ACCEL_REG_INT_STATUS_2); BMC150_ACCEL_REG_INT_STATUS_2);
if (ret < 0) { if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); 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) if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
...@@ -1097,35 +1335,73 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private) ...@@ -1097,35 +1335,73 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private)
IIO_EV_TYPE_ROC, IIO_EV_TYPE_ROC,
dir), dir),
data->timestamp); data->timestamp);
ack_intr_status: return ret;
if (!data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY].enabled) }
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, ret = i2c_smbus_write_byte_data(data->client,
BMC150_ACCEL_REG_INT_RST_LATCH, BMC150_ACCEL_REG_INT_RST_LATCH,
BMC150_ACCEL_INT_MODE_LATCH_INT | BMC150_ACCEL_INT_MODE_LATCH_INT |
BMC150_ACCEL_INT_MODE_LATCH_RESET); 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 iio_dev *indio_dev = private;
struct bmc150_accel_data *data = iio_priv(indio_dev); struct bmc150_accel_data *data = iio_priv(indio_dev);
bool ack = false;
int i; int i;
data->old_timestamp = data->timestamp;
data->timestamp = iio_get_time_ns(); data->timestamp = iio_get_time_ns();
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
if (data->triggers[i].enabled) { if (data->triggers[i].enabled) {
iio_trigger_poll(data->triggers[i].indio_trig); iio_trigger_poll(data->triggers[i].indio_trig);
ack = true;
break; break;
} }
} }
if (data->ev_enable_state) if (data->ev_enable_state || data->fifo_mode)
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
else
if (ack)
return IRQ_HANDLED; return IRQ_HANDLED;
return IRQ_NONE;
} }
static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) 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, ...@@ -1232,6 +1508,94 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
return ret; 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, static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -1278,8 +1642,8 @@ static int bmc150_accel_probe(struct i2c_client *client, ...@@ -1278,8 +1642,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (client->irq >= 0) { if (client->irq >= 0) {
ret = devm_request_threaded_irq( ret = devm_request_threaded_irq(
&client->dev, client->irq, &client->dev, client->irq,
bmc150_accel_data_rdy_trig_poll, bmc150_accel_irq_handler,
bmc150_accel_event_handler, bmc150_accel_irq_thread_handler,
IRQF_TRIGGER_RISING, IRQF_TRIGGER_RISING,
BMC150_ACCEL_IRQ_NAME, BMC150_ACCEL_IRQ_NAME,
indio_dev); indio_dev);
...@@ -1309,12 +1673,20 @@ static int bmc150_accel_probe(struct i2c_client *client, ...@@ -1309,12 +1673,20 @@ static int bmc150_accel_probe(struct i2c_client *client,
ret = iio_triggered_buffer_setup(indio_dev, ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time, &iio_pollfunc_store_time,
bmc150_accel_trigger_handler, bmc150_accel_trigger_handler,
NULL); &bmc150_accel_buffer_ops);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, dev_err(&client->dev,
"Failed: iio triggered buffer setup\n"); "Failed: iio triggered buffer setup\n");
goto err_trigger_unregister; 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); ret = iio_device_register(indio_dev);
...@@ -1386,6 +1758,7 @@ static int bmc150_accel_resume(struct device *dev) ...@@ -1386,6 +1758,7 @@ static int bmc150_accel_resume(struct device *dev)
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
if (atomic_read(&data->active_intr)) if (atomic_read(&data->active_intr))
bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
bmc150_accel_fifo_set_mode(data);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
return 0; return 0;
...@@ -1417,6 +1790,9 @@ static int bmc150_accel_runtime_resume(struct device *dev) ...@@ -1417,6 +1790,9 @@ static int bmc150_accel_runtime_resume(struct device *dev)
dev_dbg(&data->client->dev, __func__); dev_dbg(&data->client->dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); 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) if (ret < 0)
return ret; return ret;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors.h>
#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel"
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel" #define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
#define LIS3DH_ACCEL_DEV_NAME "lis3dh" #define LIS3DH_ACCEL_DEV_NAME "lis3dh"
#define LSM330D_ACCEL_DEV_NAME "lsm330d_accel" #define LSM330D_ACCEL_DEV_NAME "lsm330d_accel"
......
...@@ -129,6 +129,30 @@ ...@@ -129,6 +129,30 @@
#define ST_ACCEL_3_IG1_EN_MASK 0x08 #define ST_ACCEL_3_IG1_EN_MASK 0x08
#define ST_ACCEL_3_MULTIREAD_BIT false #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[] = { static const struct iio_chan_spec st_accel_12bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
...@@ -373,6 +397,63 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { ...@@ -373,6 +397,63 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT, .multi_read_bit = ST_ACCEL_3_MULTIREAD_BIT,
.bootime = 2, .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, static int st_accel_read_raw(struct iio_dev *indio_dev,
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id st_accel_of_match[] = { static const struct of_device_id st_accel_of_match[] = {
{
.compatible = "st,lis3lv02dl-accel",
.data = LIS3LV02DL_ACCEL_DEV_NAME,
},
{ {
.compatible = "st,lsm303dlh-accel", .compatible = "st,lsm303dlh-accel",
.data = LSM303DLH_ACCEL_DEV_NAME, .data = LSM303DLH_ACCEL_DEV_NAME,
......
...@@ -437,7 +437,7 @@ int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay) ...@@ -437,7 +437,7 @@ int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct of_device_id ssp_of_match[] = { static const struct of_device_id ssp_of_match[] = {
{ {
.compatible = "samsung,sensorhub-rinato", .compatible = "samsung,sensorhub-rinato",
.data = &ssp_rinato_info, .data = &ssp_rinato_info,
......
...@@ -143,11 +143,16 @@ config AD7303 ...@@ -143,11 +143,16 @@ config AD7303
ad7303. ad7303.
config MAX517 config MAX517
tristate "Maxim MAX517/518/519 DAC driver" tristate "Maxim MAX517/518/519/520/521 DAC driver"
depends on I2C depends on I2C
help help
If you say yes here you get support for the Maxim chips MAX517, If you say yes here you get support for the following Maxim chips
MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs). (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 This driver can also be built as a module. If so, the module
will be called max517. will be called max517.
......
...@@ -39,11 +39,13 @@ enum max517_device_ids { ...@@ -39,11 +39,13 @@ enum max517_device_ids {
ID_MAX517, ID_MAX517,
ID_MAX518, ID_MAX518,
ID_MAX519, ID_MAX519,
ID_MAX520,
ID_MAX521,
}; };
struct max517_data { struct max517_data {
struct i2c_client *client; 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 = { ...@@ -149,7 +151,13 @@ static const struct iio_info max517_info = {
static const struct iio_chan_spec max517_channels[] = { static const struct iio_chan_spec max517_channels[] = {
MAX517_CHANNEL(0), 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, static int max517_probe(struct i2c_client *client,
...@@ -158,6 +166,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 max517_data *data;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct max517_platform_data *platform_data = client->dev.platform_data; struct max517_platform_data *platform_data = client->dev.platform_data;
int chan;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) if (!indio_dev)
...@@ -169,11 +178,21 @@ static int max517_probe(struct i2c_client *client, ...@@ -169,11 +178,21 @@ static int max517_probe(struct i2c_client *client,
/* establish that the iio_dev is a child of the i2c device */ /* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
/* reduced channel set for MAX517 */ switch (id->driver_data) {
if (id->driver_data == ID_MAX517) case ID_MAX521:
indio_dev->num_channels = 1; indio_dev->num_channels = 8;
else break;
case ID_MAX520:
indio_dev->num_channels = 4;
break;
case ID_MAX519:
case ID_MAX518:
indio_dev->num_channels = 2; indio_dev->num_channels = 2;
break;
default: /* single channel for MAX517 */
indio_dev->num_channels = 1;
break;
}
indio_dev->channels = max517_channels; indio_dev->channels = max517_channels;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &max517_info; indio_dev->info = &max517_info;
...@@ -182,11 +201,11 @@ static int max517_probe(struct i2c_client *client, ...@@ -182,11 +201,11 @@ static int max517_probe(struct i2c_client *client,
* Reference voltage on MAX518 and default is 5V, else take vref_mv * Reference voltage on MAX518 and default is 5V, else take vref_mv
* from platform_data * from platform_data
*/ */
if (id->driver_data == ID_MAX518 || !platform_data) { for (chan = 0; chan < indio_dev->num_channels; chan++) {
data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */ if (id->driver_data == ID_MAX518 || !platform_data)
} else { data->vref_mv[chan] = 5000; /* mV */
data->vref_mv[0] = platform_data->vref_mv[0]; else
data->vref_mv[1] = platform_data->vref_mv[1]; data->vref_mv[chan] = platform_data->vref_mv[chan];
} }
return iio_device_register(indio_dev); return iio_device_register(indio_dev);
...@@ -202,6 +221,8 @@ static const struct i2c_device_id max517_id[] = { ...@@ -202,6 +221,8 @@ static const struct i2c_device_id max517_id[] = {
{ "max517", ID_MAX517 }, { "max517", ID_MAX517 },
{ "max518", ID_MAX518 }, { "max518", ID_MAX518 },
{ "max519", ID_MAX519 }, { "max519", ID_MAX519 },
{ "max520", ID_MAX520 },
{ "max521", ID_MAX521 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, max517_id); MODULE_DEVICE_TABLE(i2c, max517_id);
...@@ -218,5 +239,5 @@ static struct i2c_driver max517_driver = { ...@@ -218,5 +239,5 @@ static struct i2c_driver max517_driver = {
module_i2c_driver(max517_driver); module_i2c_driver(max517_driver);
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); 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"); MODULE_LICENSE("GPL");
...@@ -87,6 +87,31 @@ ...@@ -87,6 +87,31 @@
#define ST_GYRO_2_DRDY_IRQ_INT2_MASK 0x08 #define ST_GYRO_2_DRDY_IRQ_INT2_MASK 0x08
#define ST_GYRO_2_MULTIREAD_BIT true #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[] = { static const struct iio_chan_spec st_gyro_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL, ST_SENSORS_LSM_CHANNELS(IIO_ANGL_VEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
...@@ -225,6 +250,64 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { ...@@ -225,6 +250,64 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.multi_read_bit = ST_GYRO_2_MULTIREAD_BIT, .multi_read_bit = ST_GYRO_2_MULTIREAD_BIT,
.bootime = 2, .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, 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) ...@@ -37,11 +37,57 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
return !list_empty(&buf->buffer_list); 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); 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 * 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, ...@@ -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_dev *indio_dev = filp->private_data;
struct iio_buffer *rb = indio_dev->buffer; struct iio_buffer *rb = indio_dev->buffer;
size_t datum_size;
size_t to_wait = 0;
size_t to_read;
int ret; int ret;
if (!indio_dev->info) if (!indio_dev->info)
...@@ -61,19 +110,28 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, ...@@ -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) if (!rb || !rb->access->read_first_n)
return -EINVAL; return -EINVAL;
do { datum_size = rb->bytes_per_datum;
if (!iio_buffer_data_available(rb)) {
if (filp->f_flags & O_NONBLOCK) /*
return -EAGAIN; * 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, ret = wait_event_interruptible(rb->pollq,
iio_buffer_data_available(rb) || iio_buffer_ready(indio_dev, rb, to_wait, to_read));
indio_dev->info == NULL);
if (ret) if (ret)
return ret; return ret;
if (indio_dev->info == NULL)
if (!indio_dev->info)
return -ENODEV; return -ENODEV;
}
ret = rb->access->read_first_n(rb, n, buf); ret = rb->access->read_first_n(rb, n, buf);
if (ret == 0 && (filp->f_flags & O_NONBLOCK)) if (ret == 0 && (filp->f_flags & O_NONBLOCK))
...@@ -96,9 +154,8 @@ unsigned int iio_buffer_poll(struct file *filp, ...@@ -96,9 +154,8 @@ unsigned int iio_buffer_poll(struct file *filp,
return -ENODEV; return -ENODEV;
poll_wait(filp, &rb->pollq, wait); 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; return POLLIN | POLLRDNORM;
/* need a way of knowing if there may be enough data... */
return 0; return 0;
} }
...@@ -123,6 +180,7 @@ void iio_buffer_init(struct iio_buffer *buffer) ...@@ -123,6 +180,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
INIT_LIST_HEAD(&buffer->buffer_list); INIT_LIST_HEAD(&buffer->buffer_list);
init_waitqueue_head(&buffer->pollq); init_waitqueue_head(&buffer->pollq);
kref_init(&buffer->ref); kref_init(&buffer->ref);
buffer->watermark = 1;
} }
EXPORT_SYMBOL(iio_buffer_init); EXPORT_SYMBOL(iio_buffer_init);
...@@ -416,6 +474,11 @@ static ssize_t iio_buffer_write_length(struct device *dev, ...@@ -416,6 +474,11 @@ static ssize_t iio_buffer_write_length(struct device *dev,
buffer->access->set_length(buffer, val); buffer->access->set_length(buffer, val);
ret = 0; ret = 0;
} }
if (ret)
goto out;
if (buffer->length && buffer->length < buffer->watermark)
buffer->watermark = buffer->length;
out:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret ? ret : len; return ret ? ret : len;
...@@ -472,6 +535,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev, ...@@ -472,6 +535,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
static void iio_buffer_deactivate(struct iio_buffer *buffer) static void iio_buffer_deactivate(struct iio_buffer *buffer)
{ {
list_del_init(&buffer->buffer_list); list_del_init(&buffer->buffer_list);
wake_up_interruptible(&buffer->pollq);
iio_buffer_put(buffer); iio_buffer_put(buffer);
} }
...@@ -629,19 +693,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev, ...@@ -629,19 +693,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
} }
} }
/* Definitely possible for devices to support both of these. */ /* Definitely possible for devices to support both of these. */
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
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;
}
indio_dev->currentmode = INDIO_BUFFER_TRIGGERED; indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) { } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
indio_dev->currentmode = INDIO_BUFFER_HARDWARE; indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) { } else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
indio_dev->currentmode = INDIO_BUFFER_SOFTWARE; indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
} else { /* Should never be reached */ } 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; ret = -EINVAL;
goto error_run_postdisable; goto error_run_postdisable;
} }
...@@ -754,16 +815,67 @@ static ssize_t iio_buffer_store_enable(struct device *dev, ...@@ -754,16 +815,67 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
static const char * const iio_scan_elements_group_name = "scan_elements"; 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, static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
iio_buffer_write_length); iio_buffer_write_length);
static struct device_attribute dev_attr_length_ro = __ATTR(length, static struct device_attribute dev_attr_length_ro = __ATTR(length,
S_IRUGO, iio_buffer_read_length, NULL); S_IRUGO, iio_buffer_read_length, NULL);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
iio_buffer_show_enable, iio_buffer_store_enable); 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[] = { static struct attribute *iio_buffer_attrs[] = {
&dev_attr_length.attr, &dev_attr_length.attr,
&dev_attr_enable.attr, &dev_attr_enable.attr,
&dev_attr_watermark.attr,
}; };
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) 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, ...@@ -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) static int iio_push_to_buffer(struct iio_buffer *buffer, const void *data)
{ {
const void *dataout = iio_demux(buffer, data); const void *dataout = iio_demux(buffer, data);
int ret;
ret = buffer->access->store_to(buffer, dataout);
if (ret)
return ret;
return buffer->access->store_to(buffer, dataout); /*
* 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) static void iio_buffer_demux_free(struct iio_buffer *buffer)
......
...@@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r, ...@@ -83,9 +83,6 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
ret = kfifo_in(&kf->kf, data, 1); ret = kfifo_in(&kf->kf, data, 1);
if (ret != 1) if (ret != 1)
return -EBUSY; return -EBUSY;
wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
return 0; return 0;
} }
...@@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, ...@@ -109,16 +106,16 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
return copied; 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); struct iio_kfifo *kf = iio_to_kfifo(r);
bool empty; size_t samples;
mutex_lock(&kf->user_lock); mutex_lock(&kf->user_lock);
empty = kfifo_is_empty(&kf->kf); samples = kfifo_len(&kf->kf);
mutex_unlock(&kf->user_lock); mutex_unlock(&kf->user_lock);
return !empty; return samples;
} }
static void iio_kfifo_buffer_release(struct iio_buffer *buffer) static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
* *
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> * 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 * 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 * the GNU General Public License. See the file COPYING in the main
...@@ -21,10 +22,34 @@ ...@@ -21,10 +22,34 @@
#include <linux/iio/iio.h> #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 */ /* 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_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */
#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 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 mlx90614_data {
struct i2c_client *client; struct i2c_client *client;
...@@ -35,26 +60,34 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, ...@@ -35,26 +60,34 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
int *val2, long mask) int *val2, long mask)
{ {
struct mlx90614_data *data = iio_priv(indio_dev); struct mlx90614_data *data = iio_priv(indio_dev);
u8 cmd;
s32 ret; s32 ret;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
switch (channel->channel2) { switch (channel->channel2) {
case IIO_MOD_TEMP_AMBIENT: case IIO_MOD_TEMP_AMBIENT:
ret = i2c_smbus_read_word_data(data->client, cmd = MLX90614_TA;
MLX90614_TA);
if (ret < 0)
return ret;
break; break;
case IIO_MOD_TEMP_OBJECT: case IIO_MOD_TEMP_OBJECT:
ret = i2c_smbus_read_word_data(data->client, switch (channel->channel) {
MLX90614_TOBJ1); case 0:
if (ret < 0) cmd = MLX90614_TOBJ1;
return ret; break;
case 1:
cmd = MLX90614_TOBJ2;
break;
default:
return -EINVAL;
}
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
ret = i2c_smbus_read_word_data(data->client, cmd);
if (ret < 0)
return ret;
*val = ret; *val = ret;
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
...@@ -86,6 +119,16 @@ static const struct iio_chan_spec mlx90614_channels[] = { ...@@ -86,6 +119,16 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE), 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 = { static const struct iio_info mlx90614_info = {
...@@ -93,11 +136,25 @@ static const struct iio_info mlx90614_info = { ...@@ -93,11 +136,25 @@ static const struct iio_info mlx90614_info = {
.driver_module = THIS_MODULE, .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, static int mlx90614_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct mlx90614_data *data; struct mlx90614_data *data;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV; return -ENODEV;
...@@ -115,8 +172,21 @@ static int mlx90614_probe(struct i2c_client *client, ...@@ -115,8 +172,21 @@ static int mlx90614_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mlx90614_info; indio_dev->info = &mlx90614_info;
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->channels = mlx90614_channels;
indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels); indio_dev->num_channels = 3;
break;
default:
return ret;
}
return iio_device_register(indio_dev); return iio_device_register(indio_dev);
} }
...@@ -146,5 +216,6 @@ static struct i2c_driver mlx90614_driver = { ...@@ -146,5 +216,6 @@ static struct i2c_driver mlx90614_driver = {
module_i2c_driver(mlx90614_driver); module_i2c_driver(mlx90614_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 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_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -129,9 +129,9 @@ static int sca3000_read_first_n_hw_rb(struct iio_buffer *r, ...@@ -129,9 +129,9 @@ static int sca3000_read_first_n_hw_rb(struct iio_buffer *r,
return ret ? ret : num_read; 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; ...@@ -21,8 +21,8 @@ struct iio_buffer;
* struct iio_buffer_access_funcs - access functions for buffers. * struct iio_buffer_access_funcs - access functions for buffers.
* @store_to: actually store stuff to the buffer * @store_to: actually store stuff to the buffer
* @read_first_n: try to get a specified number of bytes (must exist) * @read_first_n: try to get a specified number of bytes (must exist)
* @data_available: indicates whether data for reading from the buffer is * @data_available: indicates how much data is available for reading from
* available. * the buffer.
* @request_update: if a parameter change has been marked, update underlying * @request_update: if a parameter change has been marked, update underlying
* storage. * storage.
* @set_bytes_per_datum:set number of bytes per datum * @set_bytes_per_datum:set number of bytes per datum
...@@ -43,7 +43,7 @@ struct iio_buffer_access_funcs { ...@@ -43,7 +43,7 @@ struct iio_buffer_access_funcs {
int (*read_first_n)(struct iio_buffer *buffer, int (*read_first_n)(struct iio_buffer *buffer,
size_t n, size_t n,
char __user *buf); 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); int (*request_update)(struct iio_buffer *buffer);
...@@ -72,6 +72,7 @@ struct iio_buffer_access_funcs { ...@@ -72,6 +72,7 @@ struct iio_buffer_access_funcs {
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan. * @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
* @buffer_list: [INTERN] entry in the devices list of current buffers. * @buffer_list: [INTERN] entry in the devices list of current buffers.
* @ref: [INTERN] reference count of the buffer. * @ref: [INTERN] reference count of the buffer.
* @watermark: [INTERN] number of datums to wait for poll/read.
*/ */
struct iio_buffer { struct iio_buffer {
int length; int length;
...@@ -90,6 +91,7 @@ struct iio_buffer { ...@@ -90,6 +91,7 @@ struct iio_buffer {
void *demux_bounce; void *demux_bounce;
struct list_head buffer_list; struct list_head buffer_list;
struct kref ref; struct kref ref;
unsigned int watermark;
}; };
/** /**
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#define IIO_DAC_MAX517_H_ #define IIO_DAC_MAX517_H_
struct max517_platform_data { struct max517_platform_data {
u16 vref_mv[2]; u16 vref_mv[8];
}; };
#endif /* IIO_DAC_MAX517_H_ */ #endif /* IIO_DAC_MAX517_H_ */
...@@ -338,6 +338,16 @@ struct iio_dev; ...@@ -338,6 +338,16 @@ struct iio_dev;
* provide a custom of_xlate function that reads the * provide a custom of_xlate function that reads the
* *args* and returns the appropriate index in registered * *args* and returns the appropriate index in registered
* IIO channels array. * 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 iio_info {
struct module *driver_module; struct module *driver_module;
...@@ -399,6 +409,9 @@ struct iio_info { ...@@ -399,6 +409,9 @@ struct iio_info {
unsigned *readval); unsigned *readval);
int (*of_xlate)(struct iio_dev *indio_dev, int (*of_xlate)(struct iio_dev *indio_dev,
const struct of_phandle_args *iiospec); 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 @@ ...@@ -20,6 +20,11 @@
const char *iio_dir = "/sys/bus/iio/devices/"; 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 * iioutils_break_up_name() - extract generic name from full channel name
* @full_name: the full channel name * @full_name: the full channel name
...@@ -30,10 +35,19 @@ int iioutils_break_up_name(const char *full_name, ...@@ -30,10 +35,19 @@ int iioutils_break_up_name(const char *full_name,
{ {
char *current; char *current;
char *w, *r; 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"); working = strtok(current, "_\0");
w = working; w = working;
r = working; r = working;
...@@ -45,7 +59,7 @@ int iioutils_break_up_name(const char *full_name, ...@@ -45,7 +59,7 @@ int iioutils_break_up_name(const char *full_name,
r++; r++;
} }
*w = '\0'; *w = '\0';
*generic_name = strdup(working); asprintf(generic_name, "%s_%s", prefix, working);
free(current); free(current);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment