提交 b79013b2 编写于 作者: L Linus Torvalds

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

Pull staging driver updates from Greg KH:
 "Here's the big staging driver patchset for 4.1-rc1.

  There's a lot of patches here, the Outreachy application period
  happened during this development cycle, so that means that there was a
  lot of cleanup patches accepted.  Other than the normal coding style
  and sparse fixes here, there are some driver updates and work toward
  making some of the drivers into "mergable" shape (like the Unisys
  drivers.)

  All of these have been in linux-next for a while"

* tag 'staging-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1214 commits)
  staging: lustre: orthography & coding style
  staging: lustre: lnet: lnet: fix error return code
  staging: lustre: fix sparse warning
  Revert "Staging: sm750fb: Fix C99 Comments"
  Staging: rtl8192u: use correct array for debug output
  staging: rtl8192e: Remove dead code
  staging: rtl8192e: Comment cleanup (style/format)
  staging: rtl8192e: Fix indentation in rtllib_rx_auth_resp()
  staging: rtl8192e: Decrease nesting of rtllib_rx_auth_resp()
  staging: rtl8192e: Divide rtllib_rx_auth()
  staging: rtl8192e: Fix PRINTK_WITHOUT_KERN_LEVEL warnings
  staging: rtl8192e: Fix DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON warning
  staging: rtl8192e: Fix BRACES warning
  staging: rtl8192e: Fix LINE_CONTINUATIONS warning
  staging: rtl8192e: Fix UNNECESSARY_PARENTHESES warnings
  staging: rtl8192e: remove unused EXPORT_SYMBOL_RSL macro
  staging: rtl8192e: Fix RETURN_VOID warnings
  staging: rtl8192e: Fix UNNECESSARY_ELSE warning
  staging: rtl8723au: Remove unneeded comments
  staging: rtl8723au: Use __func__ in trace logs
  ...
......@@ -253,6 +253,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
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:
......@@ -296,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:
......@@ -336,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:
......@@ -347,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
......@@ -358,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).
......@@ -375,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
......@@ -612,6 +616,8 @@ Description:
a given event type is enabled a future point (and not those for
whatever event was previously enabled).
What: /sys/.../events/in_accel_thresh_rising_value
What: /sys/.../events/in_accel_thresh_falling_value
What: /sys/.../events/in_accel_x_raw_thresh_rising_value
What: /sys/.../events/in_accel_x_raw_thresh_falling_value
What: /sys/.../events/in_accel_y_raw_thresh_rising_value
......@@ -661,6 +667,24 @@ Description:
value is in raw device units or in processed units (as _raw
and _input do on sysfs direct channel read attributes).
What: /sys/.../events/in_accel_scale
What: /sys/.../events/in_accel_peak_scale
What: /sys/.../events/in_anglvel_scale
What: /sys/.../events/in_magn_scale
What: /sys/.../events/in_rot_from_north_magnetic_scale
What: /sys/.../events/in_rot_from_north_true_scale
What: /sys/.../events/in_voltage_scale
What: /sys/.../events/in_voltage_supply_scale
What: /sys/.../events/in_temp_scale
What: /sys/.../events/in_illuminance_scale
What: /sys/.../events/in_proximity_scale
KernelVersion: 3.21
Contact: linux-iio@vger.kernel.org
Description:
Specifies the conversion factor from the standard units
to device specific units used to set the event trigger
threshold.
What: /sys/.../events/in_accel_x_thresh_rising_hysteresis
What: /sys/.../events/in_accel_x_thresh_falling_hysteresis
What: /sys/.../events/in_accel_x_thresh_either_hysteresis
......@@ -776,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
......@@ -923,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
......@@ -932,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
......@@ -997,6 +1021,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en
What: /sys/.../iio:deviceX/scan_elements/in_pressure_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en
What: /sys/.../iio:deviceX/scan_elements/in_proximity_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
......@@ -1013,6 +1038,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type
What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type
What: /sys/.../iio:deviceX/scan_elements/in_proximity_type
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
......@@ -1064,6 +1090,7 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index
What: /sys/.../iio:deviceX/scan_elements/in_pressure_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index
What: /sys/.../iio:deviceX/scan_elements/in_proximity_index
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
......@@ -1104,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
......@@ -1113,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
......@@ -1143,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:
......@@ -1174,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.
......@@ -1236,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
......@@ -1244,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.
* Microchip Analog to Digital Converter (ADC)
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"mcp3001"
"mcp3002"
"mcp3004"
"mcp3008"
"mcp3201"
"mcp3202"
"mcp3204"
"mcp3208"
Examples:
spi_controller {
mcp3x0x@0 {
compatible = "mcp3002";
reg = <0>;
spi-max-frequency = <1000000>;
};
};
* Microchip mcp3422/3/4/6/7/8 chip family (ADC)
Required properties:
- compatible: Should be
"microchip,mcp3422" or
"microchip,mcp3423" or
"microchip,mcp3424" or
"microchip,mcp3426" or
"microchip,mcp3427" or
"microchip,mcp3428"
- reg: I2C address for the device
Example:
adc@0 {
compatible = "microchip,mcp3424";
reg = <0x68>;
};
* Texas Instruments' ADC128S052 ADC chip
Required properties:
- compatible: Should be "ti,adc128s052"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc128s052";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
......@@ -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
......
......@@ -724,7 +724,7 @@ F: staging/iio/trigger/iio-trig-bfin-timer.c
ANDROID DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Arve Hjønnevåg <arve@android.com>
M: Arve Hjønnevåg <arve@android.com>
M: Riley Andrews <riandrews@android.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git
L: devel@driverdev.osuosl.org
......@@ -4169,6 +4169,12 @@ F: sound/soc/fsl/fsl*
F: sound/soc/fsl/imx*
F: sound/soc/fsl/mpc8610_hpcd.c
FREESCALE QORIQ MANAGEMENT COMPLEX DRIVER
M: J. German Rivera <German.Rivera@freescale.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-mc/
FREEVXFS FILESYSTEM
M: Christoph Hellwig <hch@infradead.org>
W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
......@@ -4954,6 +4960,7 @@ S: Maintained
F: drivers/iio/
F: drivers/staging/iio/
F: include/linux/iio/
F: tools/iio/
IKANOS/ADI EAGLE ADSL USB DRIVER
M: Matthieu Castet <castet.matthieu@free.fr>
......@@ -9363,6 +9370,14 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/staging/sm7xxfb/
STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Teddy Wang <teddy.wang@siliconmotion.com>
M: Sudip Mukherjee <sudip@vectorindia.org>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/staging/sm750fb/
STAGING - SLICOSS
M: Lior Dotan <liodot@gmail.com>
M: Christopher Harrer <charrer@alacritech.com>
......
......@@ -3548,7 +3548,7 @@ static int __init d40_probe(struct platform_device *pdev)
if (!plat_data) {
if (np) {
if(d40_of_probe(pdev, np)) {
if (d40_of_probe(pdev, np)) {
ret = -ENOMEM;
goto failure;
}
......
此差异已折叠。
......@@ -1169,16 +1169,12 @@ static int kxcjk1013_gpio_probe(struct i2c_client *client,
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0);
gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
......
......@@ -418,17 +418,18 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev)
struct device *dev = &data->client->dev;
for (i = 0; i < MMA9551_GPIO_COUNT; i++) {
gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i);
gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i,
GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
ret = gpiod_to_irq(gpio);
if (ret < 0)
return ret;
data->irqs[i] = gpiod_to_irq(gpio);
data->irqs[i] = ret;
ret = devm_request_threaded_irq(dev, data->irqs[i],
NULL, mma9551_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
......
......@@ -1109,16 +1109,12 @@ static int mma9553_gpio_probe(struct i2c_client *client)
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), 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,
......
......@@ -196,10 +196,11 @@ config MAX1363
data via the iio dev interface.
config MCP320X
tristate "Microchip Technology MCP3204/08"
tristate "Microchip Technology MCP3x01/02/04/08"
depends on SPI
help
Say yes here to build support for Microchip Technology's MCP3204 or
Say yes here to build support for Microchip Technology's
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or
MCP3208 analog to digital converter.
This driver can also be built as a module. If so, the module will be
......
......@@ -861,5 +861,5 @@ static struct spi_driver ad7793_driver = {
module_spi_driver(ad7793_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs");
MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs");
MODULE_LICENSE("GPL v2");
......@@ -275,7 +275,6 @@ static void vf610_adc_cfg_post_set(struct vf610_adc *info)
static void vf610_adc_calibration(struct vf610_adc *info)
{
int adc_gc, hc_cfg;
int timeout;
if (!info->adc_feature.calibration)
return;
......@@ -287,9 +286,7 @@ static void vf610_adc_calibration(struct vf610_adc *info)
adc_gc = readl(info->regs + VF610_REG_ADC_GC);
writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
timeout = wait_for_completion_timeout
(&info->completion, VF610_ADC_TIMEOUT);
if (timeout == 0)
if (!wait_for_completion_timeout(&info->completion, VF610_ADC_TIMEOUT))
dev_err(info->dev, "Timeout for adc calibration\n");
adc_gc = readl(info->regs + VF610_REG_ADC_GS);
......
......@@ -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");
......@@ -1001,16 +1001,12 @@ static int bmg160_gpio_probe(struct i2c_client *client,
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0);
gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
......
......@@ -223,6 +223,10 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
int ret;
u8 val;
ret = itg3200_reset(indio_dev);
if (ret)
goto err_ret;
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_ADDRESS, &val);
if (ret)
goto err_ret;
......@@ -233,10 +237,6 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
goto err_ret;
}
ret = itg3200_reset(indio_dev);
if (ret)
goto err_ret;
ret = itg3200_enable_full_scale(indio_dev);
err_ret:
return ret;
......@@ -351,6 +351,26 @@ static int itg3200_remove(struct i2c_client *client)
return 0;
}
static int __maybe_unused itg3200_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct itg3200 *st = iio_priv(indio_dev);
dev_dbg(&st->i2c->dev, "suspend device");
return itg3200_write_reg_8(indio_dev, ITG3200_REG_POWER_MANAGEMENT,
ITG3200_SLEEP);
}
static int __maybe_unused itg3200_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
return itg3200_initial_setup(indio_dev);
}
static SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend, itg3200_resume);
static const struct i2c_device_id itg3200_id[] = {
{ "itg3200", 0 },
{ }
......@@ -361,6 +381,7 @@ static struct i2c_driver itg3200_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "itg3200",
.pm = &itg3200_pm_ops,
},
.id_table = itg3200_id,
.probe = itg3200_probe,
......
......@@ -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,
......
......@@ -3,4 +3,4 @@
#
obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o inv_mpu_acpi.o
/*
* inv_mpu_acpi: ACPI processing for creating client devices
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifdef CONFIG_ACPI
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
#include "inv_mpu_iio.h"
enum inv_mpu_product_name {
INV_MPU_NOT_MATCHED,
INV_MPU_ASUS_T100TA,
};
static enum inv_mpu_product_name matched_product_name;
static int __init asus_t100_matched(const struct dmi_system_id *d)
{
matched_product_name = INV_MPU_ASUS_T100TA;
return 0;
}
static const struct dmi_system_id inv_mpu_dev_list[] = {
{
.callback = asus_t100_matched,
.ident = "Asus Transformer Book T100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC"),
DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
},
},
/* Add more matching tables here..*/
{}
};
static int asus_acpi_get_sensor_info(struct acpi_device *adev,
struct i2c_client *client,
struct i2c_board_info *info)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
int i;
acpi_status status;
union acpi_object *cpm;
status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);
if (ACPI_FAILURE(status))
return -ENODEV;
cpm = buffer.pointer;
for (i = 0; i < cpm->package.count; ++i) {
union acpi_object *elem;
int j;
elem = &(cpm->package.elements[i]);
for (j = 0; j < elem->package.count; ++j) {
union acpi_object *sub_elem;
sub_elem = &(elem->package.elements[j]);
if (sub_elem->type == ACPI_TYPE_STRING)
strlcpy(info->type, sub_elem->string.pointer,
sizeof(info->type));
else if (sub_elem->type == ACPI_TYPE_INTEGER) {
if (sub_elem->integer.value != client->addr) {
info->addr = sub_elem->integer.value;
break; /* Not a MPU6500 primary */
}
}
}
}
kfree(buffer.pointer);
return cpm->package.count;
}
static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
{
u32 *addr = data;
if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
struct acpi_resource_i2c_serialbus *sb;
sb = &ares->data.i2c_serial_bus;
if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
if (*addr)
*addr |= (sb->slave_address << 16);
else
*addr = sb->slave_address;
}
}
/* Tell the ACPI core that we already copied this address */
return 1;
}
static int inv_mpu_process_acpi_config(struct i2c_client *client,
unsigned short *primary_addr,
unsigned short *secondary_addr)
{
const struct acpi_device_id *id;
struct acpi_device *adev;
u32 i2c_addr = 0;
LIST_HEAD(resources);
int ret;
id = acpi_match_device(client->dev.driver->acpi_match_table,
&client->dev);
if (!id)
return -ENODEV;
adev = ACPI_COMPANION(&client->dev);
if (!adev)
return -ENODEV;
ret = acpi_dev_get_resources(adev, &resources,
acpi_i2c_check_resource, &i2c_addr);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&resources);
*primary_addr = i2c_addr & 0x0000ffff;
*secondary_addr = (i2c_addr & 0xffff0000) >> 16;
return 0;
}
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
{
st->mux_client = NULL;
if (ACPI_HANDLE(&st->client->dev)) {
struct i2c_board_info info;
struct acpi_device *adev;
int ret = -1;
adev = ACPI_COMPANION(&st->client->dev);
memset(&info, 0, sizeof(info));
dmi_check_system(inv_mpu_dev_list);
switch (matched_product_name) {
case INV_MPU_ASUS_T100TA:
ret = asus_acpi_get_sensor_info(adev, st->client,
&info);
break;
/* Add more matched product processing here */
default:
break;
}
if (ret < 0) {
/* No matching DMI, so create device on INV6XX type */
unsigned short primary, secondary;
ret = inv_mpu_process_acpi_config(st->client, &primary,
&secondary);
if (!ret && secondary) {
char *name;
info.addr = secondary;
strlcpy(info.type, dev_name(&adev->dev),
sizeof(info.type));
name = strchr(info.type, ':');
if (name)
*name = '\0';
strlcat(info.type, "-client",
sizeof(info.type));
} else
return 0; /* no secondary addr, which is OK */
}
st->mux_client = i2c_new_device(st->mux_adapter, &info);
if (!st->mux_client)
return -ENODEV;
}
return 0;
}
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st)
{
if (st->mux_client)
i2c_unregister_device(st->mux_client);
}
#else
#include "inv_mpu_iio.h"
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
{
return 0;
}
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st)
{
}
#endif
......@@ -829,8 +829,14 @@ static int inv_mpu_probe(struct i2c_client *client,
goto out_unreg_device;
}
result = inv_mpu_acpi_create_mux_client(st);
if (result)
goto out_del_mux;
return 0;
out_del_mux:
i2c_del_mux_adapter(st->mux_adapter);
out_unreg_device:
iio_device_unregister(indio_dev);
out_remove_trigger:
......@@ -845,6 +851,7 @@ static int inv_mpu_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
inv_mpu_acpi_delete_mux_client(st);
i2c_del_mux_adapter(st->mux_adapter);
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
......
......@@ -121,6 +121,7 @@ struct inv_mpu6050_state {
spinlock_t time_stamp_lock;
struct i2c_client *client;
struct i2c_adapter *mux_adapter;
struct i2c_client *mux_client;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
......@@ -251,3 +252,5 @@ int inv_reset_fifo(struct iio_dev *indio_dev);
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st);
void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st);
......@@ -169,19 +169,18 @@ static const u16 kmx61_uscale_table[] = {9582, 19163, 38326};
static const struct {
int val;
int val2;
u8 odr_bits;
} kmx61_samp_freq_table[] = { {12, 500000, 0x00},
{25, 0, 0x01},
{50, 0, 0x02},
{100, 0, 0x03},
{200, 0, 0x04},
{400, 0, 0x05},
{800, 0, 0x06},
{1600, 0, 0x07},
{0, 781000, 0x08},
{1, 563000, 0x09},
{3, 125000, 0x0A},
{6, 250000, 0x0B} };
} kmx61_samp_freq_table[] = { {12, 500000},
{25, 0},
{50, 0},
{100, 0},
{200, 0},
{400, 0},
{800, 0},
{1600, 0},
{0, 781000},
{1, 563000},
{3, 125000},
{6, 250000} };
static const struct {
int val;
......@@ -302,24 +301,10 @@ static int kmx61_convert_freq_to_bit(int val, int val2)
for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
if (val == kmx61_samp_freq_table[i].val &&
val2 == kmx61_samp_freq_table[i].val2)
return kmx61_samp_freq_table[i].odr_bits;
return i;
return -EINVAL;
}
static int kmx61_convert_bit_to_freq(u8 odr_bits, int *val, int *val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
if (odr_bits == kmx61_samp_freq_table[i].odr_bits) {
*val = kmx61_samp_freq_table[i].val;
*val2 = kmx61_samp_freq_table[i].val2;
return 0;
}
return -EINVAL;
}
static int kmx61_convert_wake_up_odr_to_bit(int val, int val2)
{
int i;
......@@ -478,7 +463,7 @@ static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device)
static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
u8 device)
{ int i;
{
u8 lodr_bits;
if (device & KMX61_ACC)
......@@ -490,13 +475,13 @@ static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
else
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) {
*val = kmx61_samp_freq_table[i].val;
*val2 = kmx61_samp_freq_table[i].val2;
return 0;
}
return -EINVAL;
if (lodr_bits >= ARRAY_SIZE(kmx61_samp_freq_table))
return -EINVAL;
*val = kmx61_samp_freq_table[lodr_bits].val;
*val2 = kmx61_samp_freq_table[lodr_bits].val2;
return 0;
}
static int kmx61_set_range(struct kmx61_data *data, u8 range)
......@@ -580,8 +565,11 @@ static int kmx61_chip_init(struct kmx61_data *data)
}
data->odr_bits = ret;
/* set output data rate for wake up (motion detection) function */
ret = kmx61_convert_bit_to_freq(data->odr_bits, &val, &val2);
/*
* set output data rate for wake up (motion detection) function
* to match data rate for accelerometer sampling
*/
ret = kmx61_get_odr(data, &val, &val2, KMX61_ACC);
if (ret < 0)
return ret;
......@@ -1267,16 +1255,12 @@ static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0);
gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
......
......@@ -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;
datum_size = rb->bytes_per_datum;
/*
* 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 {
if (!iio_buffer_data_available(rb)) {
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
ret = wait_event_interruptible(rb->pollq,
iio_buffer_ready(indio_dev, rb, to_wait, to_read));
if (ret)
return ret;
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 (!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,12 +815,68 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
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)
{
......@@ -778,21 +895,23 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
attrcount++;
}
buffer->buffer_group.name = "buffer";
buffer->buffer_group.attrs = kcalloc(attrcount + 3,
sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
if (!buffer->buffer_group.attrs)
attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1,
sizeof(struct attribute *), GFP_KERNEL);
if (!attr)
return -ENOMEM;
if (buffer->access->set_length)
buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
else
buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs));
if (!buffer->access->set_length)
attr[0] = &dev_attr_length_ro.attr;
if (buffer->attrs)
memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
sizeof(*&buffer->buffer_group.attrs) * attrcount);
buffer->buffer_group.attrs[attrcount+2] = NULL;
memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
sizeof(struct attribute *) * attrcount);
attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL;
buffer->buffer_group.name = "buffer";
buffer->buffer_group.attrs = attr;
indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
......@@ -937,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)
......
......@@ -59,6 +59,16 @@ config CM3232
To compile this driver as a module, choose M here:
the module will be called cm3232.
config CM3323
depends on I2C
tristate "Capella CM3323 color light sensor"
help
Say Y here if you want to build a driver for Capela CM3323
color sensor.
To compile this driver as a module, choose M here: the module will
be called cm3323.
config CM36651
depends on I2C
tristate "CM36651 driver"
......
......@@ -8,6 +8,7 @@ obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
obj-$(CONFIG_CM3323) += cm3323.o
obj-$(CONFIG_CM36651) += cm36651.o
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
......
......@@ -378,6 +378,39 @@ static const struct i2c_device_id cm3232_id[] = {
{}
};
#ifdef CONFIG_PM_SLEEP
static int cm3232_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct cm3232_chip *chip = iio_priv(indio_dev);
struct i2c_client *client = chip->client;
int ret;
chip->regs_cmd |= CM3232_CMD_ALS_DISABLE;
ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
chip->regs_cmd);
return ret;
}
static int cm3232_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct cm3232_chip *chip = iio_priv(indio_dev);
struct i2c_client *client = chip->client;
int ret;
chip->regs_cmd &= ~CM3232_CMD_ALS_DISABLE;
ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
chip->regs_cmd | CM3232_CMD_ALS_RESET);
return ret;
}
static const struct dev_pm_ops cm3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)};
#endif
MODULE_DEVICE_TABLE(i2c, cm3232_id);
static const struct of_device_id cm3232_of_match[] = {
......@@ -390,6 +423,9 @@ static struct i2c_driver cm3232_driver = {
.name = "cm3232",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(cm3232_of_match),
#ifdef CONFIG_PM_SLEEP
.pm = &cm3232_pm_ops,
#endif
},
.id_table = cm3232_id,
.probe = cm3232_probe,
......
/*
* CM3323 - Capella Color Light Sensor
*
* Copyright (c) 2015, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* IIO driver for CM3323 (7-bit I2C slave address 0x10)
*
* TODO: calibscale to correct the lens factor
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define CM3323_DRV_NAME "cm3323"
#define CM3323_CMD_CONF 0x00
#define CM3323_CMD_RED_DATA 0x08
#define CM3323_CMD_GREEN_DATA 0x09
#define CM3323_CMD_BLUE_DATA 0x0A
#define CM3323_CMD_CLEAR_DATA 0x0B
#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */
#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */
#define CM3323_CONF_IT_MASK (BIT(4) | BIT(5) | BIT(6))
#define CM3323_CONF_IT_SHIFT 4
#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
static const struct {
int val;
int val2;
} cm3323_int_time[] = {
{0, 40000}, /* 40 ms */
{0, 80000}, /* 80 ms */
{0, 160000}, /* 160 ms */
{0, 320000}, /* 320 ms */
{0, 640000}, /* 640 ms */
{1, 280000}, /* 1280 ms */
};
struct cm3323_data {
struct i2c_client *client;
u16 reg_conf;
struct mutex mutex;
};
#define CM3323_COLOR_CHANNEL(_color, _addr) { \
.type = IIO_INTENSITY, \
.modified = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
.channel2 = IIO_MOD_LIGHT_##_color, \
.address = _addr, \
}
static const struct iio_chan_spec cm3323_channels[] = {
CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),
CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),
CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),
CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),
};
static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);
static struct attribute *cm3323_attributes[] = {
&iio_const_attr_integration_time_available.dev_attr.attr,
NULL
};
static const struct attribute_group cm3323_attribute_group = {
.attrs = cm3323_attributes,
};
static int cm3323_init(struct iio_dev *indio_dev)
{
int ret;
struct cm3323_data *data = iio_priv(indio_dev);
ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_conf\n");
return ret;
}
/* enable sensor and set auto force mode */
ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_conf\n");
return ret;
}
data->reg_conf = ret;
return 0;
}
static void cm3323_disable(struct iio_dev *indio_dev)
{
int ret;
struct cm3323_data *data = iio_priv(indio_dev);
ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF,
CM3323_CONF_SD_BIT);
if (ret < 0)
dev_err(&data->client->dev, "Error writing reg_conf\n");
}
static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
{
int i, ret;
u16 reg_conf;
for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
if (val == cm3323_int_time[i].val &&
val2 == cm3323_int_time[i].val2) {
reg_conf = data->reg_conf;
reg_conf |= i << CM3323_CONF_IT_SHIFT;
ret = i2c_smbus_write_word_data(data->client,
CM3323_CMD_CONF,
reg_conf);
if (ret < 0)
return ret;
data->reg_conf = reg_conf;
return 0;
}
}
return -EINVAL;
}
static int cm3323_get_it_bits(struct cm3323_data *data)
{
int bits;
bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>
CM3323_CONF_IT_SHIFT;
if (bits >= ARRAY_SIZE(cm3323_int_time))
return -EINVAL;
return bits;
}
static int cm3323_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int i, ret;
struct cm3323_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = i2c_smbus_read_word_data(data->client, chan->address);
if (ret < 0) {
mutex_unlock(&data->mutex);
return ret;
}
*val = ret;
mutex_unlock(&data->mutex);
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
mutex_lock(&data->mutex);
i = cm3323_get_it_bits(data);
if (i < 0) {
mutex_unlock(&data->mutex);
return -EINVAL;
}
*val = cm3323_int_time[i].val;
*val2 = cm3323_int_time[i].val2;
mutex_unlock(&data->mutex);
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int cm3323_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct cm3323_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
mutex_lock(&data->mutex);
ret = cm3323_set_it_bits(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info cm3323_info = {
.driver_module = THIS_MODULE,
.read_raw = cm3323_read_raw,
.write_raw = cm3323_write_raw,
.attrs = &cm3323_attribute_group,
};
static int cm3323_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cm3323_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &cm3323_info;
indio_dev->name = CM3323_DRV_NAME;
indio_dev->channels = cm3323_channels;
indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = cm3323_init(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "cm3323 chip init failed\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "failed to register iio dev\n");
goto err_init;
}
return 0;
err_init:
cm3323_disable(indio_dev);
return ret;
}
static int cm3323_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
cm3323_disable(indio_dev);
return 0;
}
static const struct i2c_device_id cm3323_id[] = {
{"cm3323", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, cm3323_id);
static struct i2c_driver cm3323_driver = {
.driver = {
.name = CM3323_DRV_NAME,
},
.probe = cm3323_probe,
.remove = cm3323_remove,
.id_table = cm3323_id,
};
module_i2c_driver(cm3323_driver);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");
MODULE_LICENSE("GPL v2");
......@@ -46,6 +46,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
......@@ -966,7 +967,6 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
struct iio_dev *indio_dev = pf->indio_dev;
struct gp2ap020a00f_data *priv = iio_priv(indio_dev);
size_t d_size = 0;
__le32 light_lux;
int i, out_val, ret;
for_each_set_bit(i, indio_dev->active_scan_mask,
......@@ -981,8 +981,8 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) {
out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]);
gp2ap020a00f_output_to_lux(priv, &out_val);
light_lux = cpu_to_le32(out_val);
memcpy(&priv->buffer[d_size], (u8 *)&light_lux, 4);
put_unaligned_le32(out_val, &priv->buffer[d_size]);
d_size += 4;
} else {
d_size += 2;
......
......@@ -308,7 +308,7 @@ static bool jsa1212_is_volatile_reg(struct device *dev, unsigned int reg)
}
}
static struct regmap_config jsa1212_regmap_config = {
static const struct regmap_config jsa1212_regmap_config = {
.name = JSA1212_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
......
......@@ -333,6 +333,13 @@ static int ltr501_init(struct ltr501_data *data)
data->ps_contr);
}
static int ltr501_powerdown(struct ltr501_data *data)
{
return ltr501_write_contr(data->client,
data->als_contr & ~LTR501_CONTR_ACTIVE,
data->ps_contr & ~LTR501_CONTR_ACTIVE);
}
static int ltr501_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -370,7 +377,7 @@ static int ltr501_probe(struct i2c_client *client,
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ltr501_trigger_handler, NULL);
if (ret)
return ret;
goto powerdown_on_error;
ret = iio_device_register(indio_dev);
if (ret)
......@@ -380,16 +387,11 @@ static int ltr501_probe(struct i2c_client *client,
error_unreg_buffer:
iio_triggered_buffer_cleanup(indio_dev);
powerdown_on_error:
ltr501_powerdown(data);
return ret;
}
static int ltr501_powerdown(struct ltr501_data *data)
{
return ltr501_write_contr(data->client,
data->als_contr & ~LTR501_CONTR_ACTIVE,
data->ps_contr & ~LTR501_CONTR_ACTIVE);
}
static int ltr501_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
......
......@@ -321,6 +321,12 @@ static const struct iio_info mag3110_info = {
static const unsigned long mag3110_scan_masks[] = {0x7, 0xf, 0};
static int mag3110_standby(struct mag3110_data *data)
{
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 & ~MAG3110_CTRL_AC);
}
static int mag3110_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -360,12 +366,12 @@ static int mag3110_probe(struct i2c_client *client,
ret = i2c_smbus_write_byte_data(client, MAG3110_CTRL_REG2,
MAG3110_CTRL_AUTO_MRST_EN);
if (ret < 0)
return ret;
goto standby_on_error;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mag3110_trigger_handler, NULL);
if (ret < 0)
return ret;
goto standby_on_error;
ret = iio_device_register(indio_dev);
if (ret < 0)
......@@ -374,15 +380,11 @@ static int mag3110_probe(struct i2c_client *client,
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
standby_on_error:
mag3110_standby(iio_priv(indio_dev));
return ret;
}
static int mag3110_standby(struct mag3110_data *data)
{
return i2c_smbus_write_byte_data(data->client, MAG3110_CTRL_REG1,
data->ctrl_reg1 & ~MAG3110_CTRL_AC);
}
static int mag3110_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
......
......@@ -52,6 +52,33 @@ config MPL3115
To compile this driver as a module, choose M here: the module
will be called mpl3115.
config MS5611
tristate "Measurement Specialities MS5611 pressure sensor driver"
help
Say Y here to build support for the Measurement Specialities
MS5611 pressure and temperature sensor.
To compile this driver as a module, choose M here: the module will
be called ms5611_core.
config MS5611_I2C
tristate "support I2C bus connection"
depends on I2C && MS5611
help
Say Y here to build I2C bus support for MS5611.
To compile this driver as a module, choose M here: the module will
be called ms5611_i2c.
config MS5611_SPI
tristate "support SPI bus connection"
depends on SPI_MASTER && MS5611
help
Say Y here to build SPI bus support for MS5611.
To compile this driver as a module, choose M here: the module will
be called ms5611_spi.
config IIO_ST_PRESS
tristate "STMicroelectronics pressure sensor Driver"
depends on (I2C || SPI_MASTER) && SYSFS
......
......@@ -7,6 +7,9 @@ obj-$(CONFIG_BMP280) += bmp280.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_MPL115) += mpl115.o
obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_MS5611) += ms5611_core.o
obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
......
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _MS5611_H
#define _MS5611_H
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/mutex.h>
#define MS5611_RESET 0x1e
#define MS5611_READ_ADC 0x00
#define MS5611_READ_PROM_WORD 0xA0
#define MS5611_START_TEMP_CONV 0x58
#define MS5611_START_PRESSURE_CONV 0x48
#define MS5611_CONV_TIME_MIN 9040
#define MS5611_CONV_TIME_MAX 10000
#define MS5611_PROM_WORDS_NB 8
struct ms5611_state {
void *client;
struct mutex lock;
int (*reset)(struct device *dev);
int (*read_prom_word)(struct device *dev, int index, u16 *word);
int (*read_adc_temp_and_pressure)(struct device *dev,
s32 *temp, s32 *pressure);
u16 prom[MS5611_PROM_WORDS_NB];
};
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev);
#endif /* _MS5611_H */
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Data sheet:
* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
*
*/
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/delay.h>
#include "ms5611.h"
static bool ms5611_prom_is_valid(u16 *prom, size_t len)
{
int i, j;
uint16_t crc = 0, crc_orig = prom[7] & 0x000F;
prom[7] &= 0xFF00;
for (i = 0; i < len * 2; i++) {
if (i % 2 == 1)
crc ^= prom[i >> 1] & 0x00FF;
else
crc ^= prom[i >> 1] >> 8;
for (j = 0; j < 8; j++) {
if (crc & 0x8000)
crc = (crc << 1) ^ 0x3000;
else
crc <<= 1;
}
}
crc = (crc >> 12) & 0x000F;
return crc_orig != 0x0000 && crc == crc_orig;
}
static int ms5611_read_prom(struct iio_dev *indio_dev)
{
int ret, i;
struct ms5611_state *st = iio_priv(indio_dev);
for (i = 0; i < MS5611_PROM_WORDS_NB; i++) {
ret = st->read_prom_word(&indio_dev->dev, i, &st->prom[i]);
if (ret < 0) {
dev_err(&indio_dev->dev,
"failed to read prom at %d\n", i);
return ret;
}
}
if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) {
dev_err(&indio_dev->dev, "PROM integrity check failed\n");
return -ENODEV;
}
return 0;
}
static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev,
s32 *temp, s32 *pressure)
{
int ret;
s32 t, p;
s64 off, sens, dt;
struct ms5611_state *st = iio_priv(indio_dev);
ret = st->read_adc_temp_and_pressure(&indio_dev->dev, &t, &p);
if (ret < 0) {
dev_err(&indio_dev->dev,
"failed to read temperature and pressure\n");
return ret;
}
dt = t - (st->prom[5] << 8);
off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7);
sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8);
t = 2000 + ((st->prom[6] * dt) >> 23);
if (t < 2000) {
s64 off2, sens2, t2;
t2 = (dt * dt) >> 31;
off2 = (5 * (t - 2000) * (t - 2000)) >> 1;
sens2 = off2 >> 1;
if (t < -1500) {
s64 tmp = (t + 1500) * (t + 1500);
off2 += 7 * tmp;
sens2 += (11 * tmp) >> 1;
}
t -= t2;
off -= off2;
sens -= sens2;
}
*temp = t;
*pressure = (((p * sens) >> 21) - off) >> 15;
return 0;
}
static int ms5611_reset(struct iio_dev *indio_dev)
{
int ret;
struct ms5611_state *st = iio_priv(indio_dev);
ret = st->reset(&indio_dev->dev);
if (ret < 0) {
dev_err(&indio_dev->dev, "failed to reset device\n");
return ret;
}
usleep_range(3000, 4000);
return 0;
}
static int ms5611_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
s32 temp, pressure;
struct ms5611_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&st->lock);
ret = ms5611_read_temp_and_pressure(indio_dev,
&temp, &pressure);
mutex_unlock(&st->lock);
if (ret < 0)
return ret;
switch (chan->type) {
case IIO_TEMP:
*val = temp * 10;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = pressure / 1000;
*val2 = (pressure % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static const struct iio_chan_spec ms5611_channels[] = {
{
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_SCALE)
},
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_SCALE)
}
};
static const struct iio_info ms5611_info = {
.read_raw = &ms5611_read_raw,
.driver_module = THIS_MODULE,
};
static int ms5611_init(struct iio_dev *indio_dev)
{
int ret;
ret = ms5611_reset(indio_dev);
if (ret < 0)
return ret;
return ms5611_read_prom(indio_dev);
}
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev)
{
int ret;
struct ms5611_state *st = iio_priv(indio_dev);
mutex_init(&st->lock);
indio_dev->dev.parent = dev;
indio_dev->name = dev->driver->name;
indio_dev->info = &ms5611_info;
indio_dev->channels = ms5611_channels;
indio_dev->num_channels = ARRAY_SIZE(ms5611_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = ms5611_init(indio_dev);
if (ret < 0)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL(ms5611_probe);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 core driver");
MODULE_LICENSE("GPL v2");
/*
* MS5611 pressure and temperature sensor driver (I2C bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 7-bit I2C slave addresses:
*
* 0x77 (CSB pin low)
* 0x76 (CSB pin high)
*
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include "ms5611.h"
static int ms5611_i2c_reset(struct device *dev)
{
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
return i2c_smbus_write_byte(st->client, MS5611_RESET);
}
static int ms5611_i2c_read_prom_word(struct device *dev, int index, u16 *word)
{
int ret;
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
ret = i2c_smbus_read_word_swapped(st->client,
MS5611_READ_PROM_WORD + (index << 1));
if (ret < 0)
return ret;
*word = ret;
return 0;
}
static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val)
{
int ret;
u8 buf[3];
ret = i2c_smbus_read_i2c_block_data(st->client, MS5611_READ_ADC,
3, buf);
if (ret < 0)
return ret;
*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
return 0;
}
static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev,
s32 *temp, s32 *pressure)
{
int ret;
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
ret = i2c_smbus_write_byte(st->client, MS5611_START_TEMP_CONV);
if (ret < 0)
return ret;
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
ret = ms5611_i2c_read_adc(st, temp);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte(st->client, MS5611_START_PRESSURE_CONV);
if (ret < 0)
return ret;
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
return ms5611_i2c_read_adc(st, pressure);
}
static int ms5611_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ms5611_state *st;
struct iio_dev *indio_dev;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_READ_I2C_BLOCK))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->reset = ms5611_i2c_reset;
st->read_prom_word = ms5611_i2c_read_prom_word;
st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure;
st->client = client;
return ms5611_probe(indio_dev, &client->dev);
}
static const struct i2c_device_id ms5611_id[] = {
{ "ms5611", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ms5611_id);
static struct i2c_driver ms5611_driver = {
.driver = {
.name = "ms5611",
.owner = THIS_MODULE,
},
.id_table = ms5611_id,
.probe = ms5611_i2c_probe,
};
module_i2c_driver(ms5611_driver);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 i2c driver");
MODULE_LICENSE("GPL v2");
/*
* MS5611 pressure and temperature sensor driver (SPI bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include "ms5611.h"
static int ms5611_spi_reset(struct device *dev)
{
u8 cmd = MS5611_RESET;
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
return spi_write_then_read(st->client, &cmd, 1, NULL, 0);
}
static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word)
{
int ret;
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1));
if (ret < 0)
return ret;
*word = ret;
return 0;
}
static int ms5611_spi_read_adc(struct device *dev, s32 *val)
{
int ret;
u8 buf[3] = { MS5611_READ_ADC };
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
ret = spi_write_then_read(st->client, buf, 1, buf, 3);
if (ret < 0)
return ret;
*val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
return 0;
}
static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev,
s32 *temp, s32 *pressure)
{
u8 cmd;
int ret;
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
cmd = MS5611_START_TEMP_CONV;
ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
if (ret < 0)
return ret;
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
ret = ms5611_spi_read_adc(dev, temp);
if (ret < 0)
return ret;
cmd = MS5611_START_PRESSURE_CONV;
ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
if (ret < 0)
return ret;
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
return ms5611_spi_read_adc(dev, pressure);
}
static int ms5611_spi_probe(struct spi_device *spi)
{
int ret;
struct ms5611_state *st;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
spi->mode = SPI_MODE_0;
spi->max_speed_hz = 20000000;
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0)
return ret;
st = iio_priv(indio_dev);
st->reset = ms5611_spi_reset;
st->read_prom_word = ms5611_spi_read_prom_word;
st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure;
st->client = spi;
return ms5611_probe(indio_dev, &spi->dev);
}
static const struct spi_device_id ms5611_id[] = {
{ "ms5611", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, ms5611_id);
static struct spi_driver ms5611_driver = {
.driver = {
.name = "ms5611",
.owner = THIS_MODULE,
},
.id_table = ms5611_id,
.probe = ms5611_spi_probe,
};
module_spi_driver(ms5611_driver);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("MS5611 spi driver");
MODULE_LICENSE("GPL v2");
......@@ -618,16 +618,12 @@ static int sx9500_gpio_probe(struct i2c_client *client,
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0);
gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0, GPIOD_IN);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
......
......@@ -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_TA 0x06 /* ambient temperature */
#define MLX90614_TOBJ1 0x07 /* object temperature */
#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_OP_RAM | 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_OP_RAM | 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");
......@@ -58,6 +58,8 @@ source "drivers/staging/iio/Kconfig"
source "drivers/staging/sm7xxfb/Kconfig"
source "drivers/staging/sm750fb/Kconfig"
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/emxx_udc/Kconfig"
......@@ -108,4 +110,6 @@ source "drivers/staging/fbtft/Kconfig"
source "drivers/staging/i2o/Kconfig"
source "drivers/staging/fsl-mc/Kconfig"
endif # STAGING
......@@ -23,6 +23,7 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_SM7XX) += sm7xxfb/
obj-$(CONFIG_FB_SM7XX) += sm750fb/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_FT1000) += ft1000/
......@@ -46,3 +47,4 @@ obj-$(CONFIG_UNISYSSPAR) += unisys/
obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
obj-$(CONFIG_FB_TFT) += fbtft/
obj-$(CONFIG_I2O) += i2o/
obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
......@@ -566,8 +566,8 @@ int ion_phys(struct ion_client *client, struct ion_handle *handle,
buffer = handle->buffer;
if (!buffer->heap->ops->phys) {
pr_err("%s: ion_phys is not implemented by this heap.\n",
__func__);
pr_err("%s: ion_phys is not implemented by this heap (name=%s, type=%d).\n",
__func__, buffer->heap->name, buffer->heap->type);
mutex_unlock(&client->lock);
return -ENODEV;
}
......@@ -1395,7 +1395,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
size_t total_size = 0;
size_t total_orphaned_size = 0;
seq_printf(s, "%16.s %16.s %16.s\n", "client", "pid", "size");
seq_printf(s, "%16s %16s %16s\n", "client", "pid", "size");
seq_puts(s, "----------------------------------------------------\n");
for (n = rb_first(&dev->clients); n; n = rb_next(n)) {
......@@ -1409,10 +1409,10 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
char task_comm[TASK_COMM_LEN];
get_task_comm(task_comm, client->task);
seq_printf(s, "%16.s %16u %16zu\n", task_comm,
seq_printf(s, "%16s %16u %16zu\n", task_comm,
client->pid, size);
} else {
seq_printf(s, "%16.s %16u %16zu\n", client->name,
seq_printf(s, "%16s %16u %16zu\n", client->name,
client->pid, size);
}
}
......@@ -1426,7 +1426,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
continue;
total_size += buffer->size;
if (!buffer->handle_count) {
seq_printf(s, "%16.s %16u %16zu %d %d\n",
seq_printf(s, "%16s %16u %16zu %d %d\n",
buffer->task_comm, buffer->pid,
buffer->size, buffer->kmap_cnt,
atomic_read(&buffer->ref.refcount));
......@@ -1435,11 +1435,11 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
}
mutex_unlock(&dev->buffer_lock);
seq_puts(s, "----------------------------------------------------\n");
seq_printf(s, "%16.s %16zu\n", "total orphaned",
seq_printf(s, "%16s %16zu\n", "total orphaned",
total_orphaned_size);
seq_printf(s, "%16.s %16zu\n", "total ", total_size);
seq_printf(s, "%16s %16zu\n", "total ", total_size);
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
seq_printf(s, "%16.s %16zu\n", "deferred free",
seq_printf(s, "%16s %16zu\n", "deferred free",
heap->free_list_size);
seq_puts(s, "----------------------------------------------------\n");
......
......@@ -280,3 +280,4 @@ static void __exit ion_test_exit(void)
module_init(ion_test_init);
module_exit(ion_test_exit);
MODULE_LICENSE("GPL v2");
......@@ -114,7 +114,7 @@ void sync_timeline_signal(struct sync_timeline *obj)
list_for_each_entry_safe(pt, next, &obj->active_list_head,
active_list) {
if (fence_is_signaled_locked(&pt->base))
list_del(&pt->active_list);
list_del_init(&pt->active_list);
}
spin_unlock_irqrestore(&obj->child_list_lock, flags);
......
......@@ -108,6 +108,7 @@ if COMEDI_ISA_DRIVERS
config COMEDI_PCL711
tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support"
select COMEDI_8254
---help---
Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112
......@@ -169,6 +170,7 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
......@@ -180,6 +182,7 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
......@@ -189,6 +192,7 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
......@@ -259,6 +263,7 @@ config COMEDI_DAC02
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
......@@ -282,6 +287,7 @@ config COMEDI_DAS08_ISA
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS16
......@@ -298,6 +304,7 @@ config COMEDI_DAS16
config COMEDI_DAS800
tristate "DAS800 and compatible ISA card support"
select COMEDI_8254
---help---
Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
Keithley Metrabyte DAS-800, DAS-801, DAS-802
......@@ -310,6 +317,7 @@ config COMEDI_DAS800
config COMEDI_DAS1800
tristate "DAS1800 and compatible ISA card support"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
---help---
Enable support for DAS1800 and compatible ISA cards
Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
......@@ -323,6 +331,7 @@ config COMEDI_DAS1800
config COMEDI_DAS6402
tristate "DAS6402 and compatible ISA card support"
select COMEDI_8254
---help---
Enable support for DAS6402 and compatible ISA cards
Computerboards, Keithley Metrabyte DAS6402 and compatibles
......@@ -463,6 +472,7 @@ config COMEDI_ADQ12B
config COMEDI_NI_AT_A2150
tristate "NI AT-A2150 ISA card support"
select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8254
---help---
Enable support for National Instruments AT-A2150 cards
......@@ -471,6 +481,7 @@ config COMEDI_NI_AT_A2150
config COMEDI_NI_AT_AO
tristate "NI AT-AO-6/10 EISA card support"
select COMEDI_8254
---help---
Enable support for National Instruments AT-AO-6/10 cards
......@@ -715,6 +726,7 @@ config COMEDI_ADL_PCI8164
config COMEDI_ADL_PCI9111
tristate "ADLink PCI-9111HR support"
select COMEDI_8254
---help---
Enable support for ADlink PCI9111 cards
......@@ -724,6 +736,7 @@ config COMEDI_ADL_PCI9111
config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
depends on HAS_DMA
select COMEDI_8254
---help---
Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
......@@ -732,6 +745,7 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
select COMEDI_8254
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
PCI-1713, PCI-1720 and PCI-1731
......@@ -759,6 +773,7 @@ config COMEDI_ADV_PCI1724
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for Advantech PCI DIO cards
......@@ -799,6 +814,7 @@ config COMEDI_AMPLC_PC263_PCI
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
select COMEDI_8254
---help---
Enable support for Amplicon PCI224 and PCI234 AO boards
......@@ -807,6 +823,7 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
......@@ -912,6 +929,7 @@ config COMEDI_CB_PCIDAS64
config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
......@@ -935,6 +953,7 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support"
select COMEDI_8254
select COMEDI_8255
---help---
Enable support for ComputerBoards/MeasurementComputing PCI Migration
......@@ -954,6 +973,7 @@ config COMEDI_CB_PCIMDDA
config COMEDI_ME4000
tristate "Meilhaus ME-4000 support"
select COMEDI_8254
---help---
Enable support for Meilhaus PCI data acquisition cards
ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is
......@@ -1091,6 +1111,7 @@ if COMEDI_PCMCIA_DRIVERS
config COMEDI_CB_DAS16_CS
tristate "CB DAS16 series PCMCIA support"
select COMEDI_8254
---help---
Enable support for the ComputerBoards/MeasurementComputing PCMCIA
cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16
......@@ -1222,6 +1243,9 @@ config COMEDI_VMK80XX
endif # COMEDI_USB_DRIVERS
config COMEDI_8254
tristate
config COMEDI_8255
tristate "Generic 8255 support"
---help---
......@@ -1252,6 +1276,7 @@ config COMEDI_KCOMEDILIB
called kcomedilib.
config COMEDI_AMPLC_DIO200
select COMEDI_8254
tristate
config COMEDI_AMPLC_PC236
......@@ -1260,6 +1285,7 @@ config COMEDI_AMPLC_PC236
config COMEDI_DAS08
tristate
select COMEDI_8254
select COMEDI_8255
config COMEDI_ISADMA
......@@ -1267,6 +1293,7 @@ config COMEDI_ISADMA
config COMEDI_NI_LABPC
tristate
select COMEDI_8254
select COMEDI_8255
config COMEDI_NI_LABPC_ISADMA
......
......@@ -144,7 +144,7 @@ static void comedi_device_cleanup(struct comedi_device *dev)
{
struct module *driver_module = NULL;
if (dev == NULL)
if (!dev)
return;
mutex_lock(&dev->mutex);
if (dev->attached)
......@@ -260,7 +260,7 @@ comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
if (minor >= COMEDI_NUM_BOARD_MINORS) {
s = comedi_subdevice_from_minor(dev, minor);
if (s == NULL || (s->subdev_flags & SDF_CMD_READ))
if (!s || (s->subdev_flags & SDF_CMD_READ))
return s;
}
return dev->read_subdev;
......@@ -273,7 +273,7 @@ comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
if (minor >= COMEDI_NUM_BOARD_MINORS) {
s = comedi_subdevice_from_minor(dev, minor);
if (s == NULL || (s->subdev_flags & SDF_CMD_WRITE))
if (!s || (s->subdev_flags & SDF_CMD_WRITE))
return s;
}
return dev->write_subdev;
......@@ -290,9 +290,9 @@ static void comedi_file_reset(struct file *file)
write_s = dev->write_subdev;
if (minor >= COMEDI_NUM_BOARD_MINORS) {
s = comedi_subdevice_from_minor(dev, minor);
if (s == NULL || s->subdev_flags & SDF_CMD_READ)
if (!s || s->subdev_flags & SDF_CMD_READ)
read_s = s;
if (s == NULL || s->subdev_flags & SDF_CMD_WRITE)
if (!s || s->subdev_flags & SDF_CMD_WRITE)
write_s = s;
}
cfp->last_attached = dev->attached;
......@@ -601,28 +601,55 @@ static struct attribute *comedi_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(comedi_dev);
static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
unsigned mask, unsigned bits)
static void __comedi_clear_subdevice_runflags(struct comedi_subdevice *s,
unsigned bits)
{
s->runflags &= ~bits;
}
static void __comedi_set_subdevice_runflags(struct comedi_subdevice *s,
unsigned bits)
{
s->runflags |= bits;
}
static void comedi_update_subdevice_runflags(struct comedi_subdevice *s,
unsigned mask, unsigned bits)
{
unsigned long flags;
spin_lock_irqsave(&s->spin_lock, flags);
s->runflags &= ~mask;
s->runflags |= (bits & mask);
__comedi_clear_subdevice_runflags(s, mask);
__comedi_set_subdevice_runflags(s, bits & mask);
spin_unlock_irqrestore(&s->spin_lock, flags);
}
static unsigned __comedi_get_subdevice_runflags(struct comedi_subdevice *s)
{
return s->runflags;
}
static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
{
unsigned long flags;
unsigned runflags;
spin_lock_irqsave(&s->spin_lock, flags);
runflags = s->runflags;
runflags = __comedi_get_subdevice_runflags(s);
spin_unlock_irqrestore(&s->spin_lock, flags);
return runflags;
}
static bool comedi_is_runflags_running(unsigned runflags)
{
return runflags & COMEDI_SRF_RUNNING;
}
static bool comedi_is_runflags_in_error(unsigned runflags)
{
return runflags & COMEDI_SRF_ERROR;
}
/**
* comedi_is_subdevice_running - check if async command running on subdevice
* @s: comedi_subdevice struct
......@@ -634,22 +661,22 @@ bool comedi_is_subdevice_running(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
return (runflags & COMEDI_SRF_RUNNING) ? true : false;
return comedi_is_runflags_running(runflags);
}
EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
static bool __comedi_is_subdevice_running(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
unsigned runflags = __comedi_get_subdevice_runflags(s);
return (runflags & COMEDI_SRF_ERROR) ? true : false;
return comedi_is_runflags_running(runflags);
}
static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
return (runflags & COMEDI_SRF_BUSY_MASK) ? false : true;
return !(runflags & COMEDI_SRF_BUSY_MASK);
}
/**
......@@ -677,14 +704,14 @@ static void do_become_nonbusy(struct comedi_device *dev,
{
struct comedi_async *async = s->async;
comedi_set_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
if (async) {
comedi_buf_reset(s);
async->inttrig = NULL;
kfree(async->cmd.chanlist);
async->cmd.chanlist = NULL;
s->busy = NULL;
wake_up_interruptible_all(&s->async->wait_head);
wake_up_interruptible_all(&async->wait_head);
} else {
dev_err(dev->class_dev,
"BUG: (?) do_become_nonbusy called with async=NULL\n");
......@@ -759,7 +786,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (arg == NULL) {
if (!arg) {
if (is_device_busy(dev))
return -EBUSY;
if (dev->attached) {
......@@ -1678,8 +1705,8 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (async->cmd.flags & CMDF_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
comedi_set_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
COMEDI_SRF_RUNNING);
comedi_update_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
COMEDI_SRF_RUNNING);
/*
* Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
......@@ -1840,7 +1867,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
if (arg >= dev->n_subdevices)
return -EINVAL;
s = &dev->subdevices[arg];
if (s->async == NULL)
if (!s->async)
return -EINVAL;
if (!s->busy)
......@@ -2282,13 +2309,16 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
add_wait_queue(&async->wait_head, &wait);
on_wait_queue = true;
while (nbytes > 0 && !retval) {
unsigned runflags;
set_current_state(TASK_INTERRUPTIBLE);
if (!comedi_is_subdevice_running(s)) {
runflags = comedi_get_subdevice_runflags(s);
if (!comedi_is_runflags_running(runflags)) {
if (count == 0) {
struct comedi_subdevice *new_s;
if (comedi_is_subdevice_in_error(s))
if (comedi_is_runflags_in_error(runflags))
retval = -EPIPE;
else
retval = 0;
......@@ -2435,8 +2465,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
n = m;
if (n == 0) {
if (!comedi_is_subdevice_running(s)) {
if (comedi_is_subdevice_in_error(s))
unsigned runflags = comedi_get_subdevice_runflags(s);
if (!comedi_is_runflags_running(runflags)) {
if (comedi_is_runflags_in_error(runflags))
retval = -EPIPE;
else
retval = 0;
......@@ -2638,39 +2670,38 @@ static const struct file_operations comedi_fops = {
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
unsigned runflags = 0;
unsigned runflags_mask = 0;
unsigned int events;
int si_code = 0;
unsigned long flags;
if (!comedi_is_subdevice_running(s))
spin_lock_irqsave(&s->spin_lock, flags);
events = async->events;
async->events = 0;
if (!__comedi_is_subdevice_running(s)) {
spin_unlock_irqrestore(&s->spin_lock, flags);
return;
}
if (s->async->events & COMEDI_CB_CANCEL_MASK)
runflags_mask |= COMEDI_SRF_RUNNING;
if (events & COMEDI_CB_CANCEL_MASK)
__comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING);
/*
* Remember if an error event has occurred, so an error
* can be returned the next time the user does a read().
* Remember if an error event has occurred, so an error can be
* returned the next time the user does a read() or write().
*/
if (s->async->events & COMEDI_CB_ERROR_MASK) {
runflags_mask |= COMEDI_SRF_ERROR;
runflags |= COMEDI_SRF_ERROR;
}
if (runflags_mask) {
/*
* Sets COMEDI_SRF_ERROR and COMEDI_SRF_RUNNING together
* atomically.
*/
comedi_set_subdevice_runflags(s, runflags_mask, runflags);
}
if (events & COMEDI_CB_ERROR_MASK)
__comedi_set_subdevice_runflags(s, COMEDI_SRF_ERROR);
if (async->cb_mask & s->async->events) {
if (async->cb_mask & events) {
wake_up_interruptible(&async->wait_head);
if (s->subdev_flags & SDF_CMD_READ)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
if (s->subdev_flags & SDF_CMD_WRITE)
kill_fasync(&dev->async_queue, SIGIO, POLL_OUT);
si_code = async->cmd.flags & CMDF_WRITE ? POLL_OUT : POLL_IN;
}
s->async->events = 0;
spin_unlock_irqrestore(&s->spin_lock, flags);
if (si_code)
kill_fasync(&dev->async_queue, SIGIO, si_code);
}
EXPORT_SYMBOL_GPL(comedi_event);
......@@ -2682,7 +2713,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
unsigned i;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
if (!dev)
return ERR_PTR(-ENOMEM);
comedi_device_init(dev);
comedi_set_hw_dev(dev, hardware_device);
......@@ -2690,7 +2721,7 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
mutex_lock(&comedi_board_minor_table_lock);
for (i = hardware_device ? comedi_num_legacy_minors : 0;
i < COMEDI_NUM_BOARD_MINORS; ++i) {
if (comedi_board_minor_table[i] == NULL) {
if (!comedi_board_minor_table[i]) {
comedi_board_minor_table[i] = dev;
break;
}
......@@ -2700,7 +2731,8 @@ struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
mutex_unlock(&dev->mutex);
comedi_device_cleanup(dev);
comedi_dev_put(dev);
pr_err("ran out of minor numbers for board device files\n");
dev_err(hardware_device,
"ran out of minor numbers for board device files\n");
return ERR_PTR(-EBUSY);
}
dev->minor = i;
......@@ -2746,14 +2778,15 @@ int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
mutex_lock(&comedi_subdevice_minor_table_lock);
for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
if (comedi_subdevice_minor_table[i] == NULL) {
if (!comedi_subdevice_minor_table[i]) {
comedi_subdevice_minor_table[i] = s;
break;
}
}
mutex_unlock(&comedi_subdevice_minor_table_lock);
if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
pr_err("ran out of minor numbers for subdevice files\n");
dev_err(dev->class_dev,
"ran out of minor numbers for subdevice files\n");
return -EBUSY;
}
i += COMEDI_NUM_BOARD_MINORS;
......@@ -2771,7 +2804,7 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
unsigned int i;
if (s == NULL)
if (!s)
return;
if (s->minor < 0)
return;
......
#ifndef _COMEDI_INTERNAL_H
#define _COMEDI_INTERNAL_H
#include <linux/compiler.h>
#include <linux/types.h>
/*
* various internal comedi stuff
*/
struct comedi_buf_map;
struct comedi_devconfig;
struct comedi_device;
struct comedi_insn;
struct comedi_rangeinfo;
struct comedi_subdevice;
struct device;
int do_rangeinfo_ioctl(struct comedi_device *dev,
struct comedi_rangeinfo __user *arg);
struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device);
......
......@@ -17,10 +17,9 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include "comedidev.h"
#include "comedi_pci.h"
/**
* comedi_to_pci_dev() - comedi_device pointer to pci_dev pointer.
......
/*
* comedi_pci.h
* header file for Comedi PCI drivers
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _COMEDI_PCI_H
#define _COMEDI_PCI_H
#include <linux/pci.h>
#include "comedidev.h"
/*
* PCI Vendor IDs not in <linux/pci_ids.h>
*/
#define PCI_VENDOR_ID_KOLTER 0x1001
#define PCI_VENDOR_ID_ICP 0x104c
#define PCI_VENDOR_ID_DT 0x1116
#define PCI_VENDOR_ID_IOTECH 0x1616
#define PCI_VENDOR_ID_CONTEC 0x1221
#define PCI_VENDOR_ID_RTD 0x1435
#define PCI_VENDOR_ID_HUMUSOFT 0x186c
struct pci_dev *comedi_to_pci_dev(struct comedi_device *);
int comedi_pci_enable(struct comedi_device *);
void comedi_pci_disable(struct comedi_device *);
void comedi_pci_detach(struct comedi_device *);
int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *,
unsigned long context);
void comedi_pci_auto_unconfig(struct pci_dev *);
int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
/**
* module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
* @__comedi_driver: comedi_driver struct
* @__pci_driver: pci_driver struct
*
* Helper macro for comedi PCI drivers which do not do anything special
* in module init/exit. This eliminates a lot of boilerplate. Each
* module may only use this macro once, and calling it replaces
* module_init() and module_exit()
*/
#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \
module_driver(__comedi_driver, comedi_pci_driver_register, \
comedi_pci_driver_unregister, &(__pci_driver))
#endif /* _COMEDI_PCI_H */
......@@ -256,6 +256,7 @@ struct comedi_driver {
struct comedi_device {
int use_count;
struct comedi_driver *driver;
struct comedi_8254 *pacer;
void *private;
struct device *class_dev;
......@@ -463,6 +464,84 @@ static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s,
return nsamples << comedi_sample_shift(s);
}
/**
* comedi_check_trigger_src() - trivially validate a comedi_cmd trigger source
* @src: pointer to the trigger source to validate
* @flags: bitmask of valid TRIG_* for the trigger
*
* This is used in "step 1" of the do_cmdtest functions of comedi drivers
* to vaildate the comedi_cmd triggers. The mask of the @src against the
* @flags allows the userspace comedilib to pass all the comedi_cmd
* triggers as TRIG_ANY and get back a bitmask of the valid trigger sources.
*/
static inline int comedi_check_trigger_src(unsigned int *src,
unsigned int flags)
{
unsigned int orig_src = *src;
*src = orig_src & flags;
if (*src == TRIG_INVALID || *src != orig_src)
return -EINVAL;
return 0;
}
/**
* comedi_check_trigger_is_unique() - make sure a trigger source is unique
* @src: the trigger source to check
*/
static inline int comedi_check_trigger_is_unique(unsigned int src)
{
/* this test is true if more than one _src bit is set */
if ((src & (src - 1)) != 0)
return -EINVAL;
return 0;
}
/**
* comedi_check_trigger_arg_is() - trivially validate a trigger argument
* @arg: pointer to the trigger arg to validate
* @val: the value the argument should be
*/
static inline int comedi_check_trigger_arg_is(unsigned int *arg,
unsigned int val)
{
if (*arg != val) {
*arg = val;
return -EINVAL;
}
return 0;
}
/**
* comedi_check_trigger_arg_min() - trivially validate a trigger argument
* @arg: pointer to the trigger arg to validate
* @val: the minimum value the argument should be
*/
static inline int comedi_check_trigger_arg_min(unsigned int *arg,
unsigned int val)
{
if (*arg < val) {
*arg = val;
return -EINVAL;
}
return 0;
}
/**
* comedi_check_trigger_arg_max() - trivially validate a trigger argument
* @arg: pointer to the trigger arg to validate
* @val: the maximum value the argument should be
*/
static inline int comedi_check_trigger_arg_max(unsigned int *arg,
unsigned int val)
{
if (*arg > val) {
*arg = val;
return -EINVAL;
}
return 0;
}
/*
* Must set dev->hw_dev if you wish to dma directly into comedi's buffer.
* Also useful for retrieving a previously configured hardware device of
......@@ -553,47 +632,4 @@ void comedi_driver_unregister(struct comedi_driver *);
module_driver(__comedi_driver, comedi_driver_register, \
comedi_driver_unregister)
/* comedi_pci.c - comedi PCI driver specific functions */
/*
* PCI Vendor IDs not in <linux/pci_ids.h>
*/
#define PCI_VENDOR_ID_KOLTER 0x1001
#define PCI_VENDOR_ID_ICP 0x104c
#define PCI_VENDOR_ID_DT 0x1116
#define PCI_VENDOR_ID_IOTECH 0x1616
#define PCI_VENDOR_ID_CONTEC 0x1221
#define PCI_VENDOR_ID_RTD 0x1435
#define PCI_VENDOR_ID_HUMUSOFT 0x186c
struct pci_dev;
struct pci_driver;
struct pci_dev *comedi_to_pci_dev(struct comedi_device *);
int comedi_pci_enable(struct comedi_device *);
void comedi_pci_disable(struct comedi_device *);
void comedi_pci_detach(struct comedi_device *);
int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *,
unsigned long context);
void comedi_pci_auto_unconfig(struct pci_dev *);
int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
/**
* module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
* @__comedi_driver: comedi_driver struct
* @__pci_driver: pci_driver struct
*
* Helper macro for comedi PCI drivers which do not do anything special
* in module init/exit. This eliminates a lot of boilerplate. Each
* module may only use this macro once, and calling it replaces
* module_init() and module_exit()
*/
#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \
module_driver(__comedi_driver, comedi_pci_driver_register, \
comedi_pci_driver_unregister, &(__pci_driver))
#endif /* _COMEDIDEV_H */
......@@ -46,7 +46,7 @@ int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev)
{
if (hw_dev == dev->hw_dev)
return 0;
if (dev->hw_dev != NULL)
if (dev->hw_dev)
return -EEXIST;
dev->hw_dev = get_device(hw_dev);
return 0;
......@@ -139,7 +139,9 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
dev->n_subdevices = 0;
}
kfree(dev->private);
kfree(dev->pacer);
dev->private = NULL;
dev->pacer = NULL;
dev->driver = NULL;
dev->board_name = NULL;
dev->board_ptr = NULL;
......@@ -800,7 +802,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
module_put(driv->module);
}
if (driv == NULL) {
if (!driv) {
/* recognize has failed if we get here */
/* report valid board names before returning error */
for (driv = comedi_drivers; driv; driv = driv->next) {
......@@ -812,7 +814,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
ret = -EIO;
goto out;
}
if (driv->attach == NULL) {
if (!driv->attach) {
/* driver does not support manual configuration */
dev_warn(dev->class_dev,
"driver '%s' does not support attach using comedi_config\n",
......@@ -896,7 +898,7 @@ EXPORT_SYMBOL_GPL(comedi_auto_config);
void comedi_auto_unconfig(struct device *hardware_device)
{
if (hardware_device == NULL)
if (!hardware_device)
return;
comedi_release_hardware_device(hardware_device);
}
......
此差异已折叠。
......@@ -51,7 +51,6 @@
#include <linux/module.h>
#include "../comedidev.h"
#include "comedi_fc.h"
#include "8255.h"
struct subdev_8255_private {
......
......@@ -62,9 +62,8 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
#include "../comedi_pci.h"
#include "8255.h"
......@@ -178,7 +177,7 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = {
},
};
/* ripped from mite.h and mite_setup2() to avoid mite dependancy */
/* ripped from mite.h and mite_setup2() to avoid mite dependency */
#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */
#define WENAB (1 << 7) /* window enable */
......
......@@ -3,6 +3,7 @@
ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
# Comedi "helper" modules
obj-$(CONFIG_COMEDI_8254) += comedi_8254.o
obj-$(CONFIG_COMEDI_ISADMA) += comedi_isadma.o
# Comedi misc drivers
......
......@@ -71,11 +71,9 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
#include "comedi_fc.h"
#include "../comedi_pci.h"
#include "amcc_s5933.h"
/*
......@@ -196,11 +194,11 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev,
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
if (err)
return 1;
......@@ -210,11 +208,12 @@ static int apci1032_cos_cmdtest(struct comedi_device *dev,
/* Step 3: check if arguments are trivially valid */
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
cmd->chanlist_len);
err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
return 3;
......@@ -238,7 +237,7 @@ static int apci1032_cos_cmd(struct comedi_device *dev,
if (!devpriv->ctrl) {
dev_warn(dev->class_dev,
"Interrupts disabled due to mode configuration!\n");
"Interrupts disabled due to mode configuration!\n");
return -EINVAL;
}
......@@ -296,7 +295,7 @@ static int apci1032_di_insn_bits(struct comedi_device *dev,
}
static int apci1032_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct apci1032_private *devpriv;
......
......@@ -22,11 +22,9 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
#include "comedi_fc.h"
#include "../comedi_pci.h"
#include "amcc_s5933.h"
#include "z8536.h"
......@@ -249,8 +247,8 @@ static irqreturn_t apci1500_interrupt(int irq, void *d)
*
* Mask Meaning
* ---------- ------------------------------------------
* 0x00000001 Event 1 has occured
* 0x00000010 Event 2 has occured
* 0x00000001 Event 1 has occurred
* 0x00000010 Event 2 has occurred
* 0x00000100 Counter/timer 1 has run down (not implemented)
* 0x00001000 Counter/timer 2 has run down (not implemented)
* 0x00010000 Counter 3 has run down (not implemented)
......@@ -386,11 +384,11 @@ static int apci1500_di_cmdtest(struct comedi_device *dev,
/* Step 1 : check if triggers are trivially valid */
err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
if (err)
return 1;
......@@ -415,12 +413,13 @@ static int apci1500_di_cmdtest(struct comedi_device *dev,
* 3 OR mode for Port A (digital inputs 0-7)
* OR mode for Port B (digital inputs 8-13 and internal signals)
*/
err |= cfc_check_trigger_arg_max(&cmd->start_arg, 3);
err |= comedi_check_trigger_arg_max(&cmd->start_arg, 3);
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
cmd->chanlist_len);
err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
if (err)
return 3;
......@@ -514,11 +513,11 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev,
src = pt & 0xff;
if (src)
ret |= cfc_check_trigger_is_unique(src);
ret |= comedi_check_trigger_is_unique(src);
src = (pt >> 8) & 0xff;
if (src)
ret |= cfc_check_trigger_is_unique(src);
ret |= comedi_check_trigger_is_unique(src);
if (ret) {
dev_dbg(dev->class_dev,
......
......@@ -23,11 +23,9 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
#include "../comedidev.h"
#include "../comedi_pci.h"
#include "addi_watchdog.h"
#include "comedi_fc.h"
/*
* PCI bar 1 I/O Register map - Digital input/output
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册