mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 16:44:10 +08:00
Merge lustre patches based on 4.0-rc5 into staging-testing
This is done to handle some lustre patches that were made against the wrong kernel branch, which was my fault, as I gave a lecture where I messed things up for the students, it wasn't their fault. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
7928848997
@ -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.
|
||||
|
30
Documentation/devicetree/bindings/iio/adc/mcp320x.txt
Normal file
30
Documentation/devicetree/bindings/iio/adc/mcp320x.txt
Normal file
@ -0,0 +1,30 @@
|
||||
* 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>;
|
||||
};
|
||||
};
|
17
Documentation/devicetree/bindings/iio/adc/mcp3422.txt
Normal file
17
Documentation/devicetree/bindings/iio/adc/mcp3422.txt
Normal file
@ -0,0 +1,17 @@
|
||||
* 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>;
|
||||
};
|
18
Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
Normal file
18
Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
Normal file
@ -0,0 +1,18 @@
|
||||
* 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
|
||||
|
17
MAINTAINERS
17
MAINTAINERS
@ -725,7 +725,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
|
||||
@ -4156,6 +4156,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
|
||||
@ -4941,6 +4947,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>
|
||||
@ -9358,6 +9365,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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -186,10 +186,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");
|
||||
|
@ -259,7 +259,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;
|
||||
@ -271,9 +270,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
|
||||
|
211
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
Normal file
211
drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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
|
@ -825,8 +825,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:
|
||||
@ -841,6 +847,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;
|
||||
|
||||
do {
|
||||
if (!iio_buffer_data_available(rb)) {
|
||||
if (filp->f_flags & O_NONBLOCK)
|
||||
return -EAGAIN;
|
||||
datum_size = rb->bytes_per_datum;
|
||||
|
||||
ret = wait_event_interruptible(rb->pollq,
|
||||
iio_buffer_data_available(rb) ||
|
||||
indio_dev->info == NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (indio_dev->info == NULL)
|
||||
return -ENODEV;
|
||||
}
|
||||
/*
|
||||
* If datum_size is 0 there will never be anything to read from the
|
||||
* buffer, so signal end of file now.
|
||||
*/
|
||||
if (!datum_size)
|
||||
return 0;
|
||||
|
||||
to_read = min_t(size_t, n / datum_size, rb->watermark);
|
||||
|
||||
if (!(filp->f_flags & O_NONBLOCK))
|
||||
to_wait = to_read;
|
||||
|
||||
do {
|
||||
ret = wait_event_interruptible(rb->pollq,
|
||||
iio_buffer_ready(indio_dev, rb, to_wait, to_read));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
ret = rb->access->read_first_n(rb, n, buf);
|
||||
if (ret == 0 && (filp->f_flags & O_NONBLOCK))
|
||||
@ -96,9 +154,8 @@ unsigned int iio_buffer_poll(struct file *filp,
|
||||
return -ENODEV;
|
||||
|
||||
poll_wait(filp, &rb->pollq, wait);
|
||||
if (iio_buffer_data_available(rb))
|
||||
if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0))
|
||||
return POLLIN | POLLRDNORM;
|
||||
/* need a way of knowing if there may be enough data... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -123,6 +180,7 @@ void iio_buffer_init(struct iio_buffer *buffer)
|
||||
INIT_LIST_HEAD(&buffer->buffer_list);
|
||||
init_waitqueue_head(&buffer->pollq);
|
||||
kref_init(&buffer->ref);
|
||||
buffer->watermark = 1;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_buffer_init);
|
||||
|
||||
@ -416,6 +474,11 @@ static ssize_t iio_buffer_write_length(struct device *dev,
|
||||
buffer->access->set_length(buffer, val);
|
||||
ret = 0;
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
if (buffer->length && buffer->length < buffer->watermark)
|
||||
buffer->watermark = buffer->length;
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
@ -472,6 +535,7 @@ static void iio_buffer_activate(struct iio_dev *indio_dev,
|
||||
static void iio_buffer_deactivate(struct iio_buffer *buffer)
|
||||
{
|
||||
list_del_init(&buffer->buffer_list);
|
||||
wake_up_interruptible(&buffer->pollq);
|
||||
iio_buffer_put(buffer);
|
||||
}
|
||||
|
||||
@ -629,19 +693,16 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
/* Definitely possible for devices to support both of these. */
|
||||
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
|
||||
if (!indio_dev->trig) {
|
||||
printk(KERN_INFO "Buffer not started: no trigger\n");
|
||||
ret = -EINVAL;
|
||||
/* Can only occur on first buffer */
|
||||
goto error_run_postdisable;
|
||||
}
|
||||
if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
|
||||
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
|
||||
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
|
||||
indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
|
||||
} else { /* Should never be reached */
|
||||
/* Can only occur on first buffer */
|
||||
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
|
||||
pr_info("Buffer not started: no trigger\n");
|
||||
ret = -EINVAL;
|
||||
goto error_run_postdisable;
|
||||
}
|
||||
@ -754,12 +815,68 @@ done:
|
||||
|
||||
static const char * const iio_scan_elements_group_name = "scan_elements";
|
||||
|
||||
static ssize_t iio_buffer_show_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_buffer *buffer = indio_dev->buffer;
|
||||
|
||||
return sprintf(buf, "%u\n", buffer->watermark);
|
||||
}
|
||||
|
||||
static ssize_t iio_buffer_store_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_buffer *buffer = indio_dev->buffer;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if (val > buffer->length) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iio_buffer_is_active(indio_dev->buffer)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer->watermark = val;
|
||||
|
||||
if (indio_dev->info->hwfifo_set_watermark)
|
||||
indio_dev->info->hwfifo_set_watermark(indio_dev, val);
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
|
||||
iio_buffer_write_length);
|
||||
static struct device_attribute dev_attr_length_ro = __ATTR(length,
|
||||
S_IRUGO, iio_buffer_read_length, NULL);
|
||||
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
|
||||
iio_buffer_show_enable, iio_buffer_store_enable);
|
||||
static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR,
|
||||
iio_buffer_show_watermark, iio_buffer_store_watermark);
|
||||
|
||||
static struct attribute *iio_buffer_attrs[] = {
|
||||
&dev_attr_length.attr,
|
||||
&dev_attr_enable.attr,
|
||||
&dev_attr_watermark.attr,
|
||||
};
|
||||
|
||||
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
|
||||
{
|
||||
@ -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,
|
||||
|
286
drivers/iio/light/cm3323.c
Normal file
286
drivers/iio/light/cm3323.c
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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
|
||||
|
44
drivers/iio/pressure/ms5611.h
Normal file
44
drivers/iio/pressure/ms5611.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 */
|
215
drivers/iio/pressure/ms5611_core.c
Normal file
215
drivers/iio/pressure/ms5611_core.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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");
|
128
drivers/iio/pressure/ms5611_i2c.c
Normal file
128
drivers/iio/pressure/ms5611_i2c.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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");
|
127
drivers/iio/pressure/ms5611_spi.c
Normal file
127
drivers/iio/pressure/ms5611_spi.c
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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");
|
||||
|
||||
|
@ -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;
|
||||
@ -759,7 +759,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) {
|
||||
@ -1840,7 +1840,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)
|
||||
@ -2682,7 +2682,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 +2690,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 +2700,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 +2747,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 +2773,7 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (s == NULL)
|
||||
if (!s)
|
||||
return;
|
||||
if (s->minor < 0)
|
||||
return;
|
||||
|
@ -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.
|
||||
|
64
drivers/staging/comedi/comedi_pci.h
Normal file
64
drivers/staging/comedi/comedi_pci.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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;
|
||||
@ -553,47 +554,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);
|
||||
}
|
||||
|
@ -1,347 +0,0 @@
|
||||
/*
|
||||
* comedi/drivers/8253.h
|
||||
* Header file for 8253
|
||||
*
|
||||
* COMEDI - Linux Control and Measurement Device Interface
|
||||
* Copyright (C) 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 _8253_H
|
||||
#define _8253_H
|
||||
|
||||
#include "../comedi.h"
|
||||
|
||||
/*
|
||||
* Common oscillator base values in nanoseconds
|
||||
*/
|
||||
#define I8254_OSC_BASE_10MHZ 100
|
||||
#define I8254_OSC_BASE_5MHZ 200
|
||||
#define I8254_OSC_BASE_4MHZ 250
|
||||
#define I8254_OSC_BASE_2MHZ 500
|
||||
#define I8254_OSC_BASE_1MHZ 1000
|
||||
|
||||
static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
|
||||
unsigned int *d1,
|
||||
unsigned int *d2,
|
||||
unsigned int *nanosec,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int divider;
|
||||
unsigned int div1, div2;
|
||||
unsigned int div1_glb, div2_glb, ns_glb;
|
||||
unsigned int div1_lub, div2_lub, ns_lub;
|
||||
unsigned int ns;
|
||||
unsigned int start;
|
||||
unsigned int ns_low, ns_high;
|
||||
static const unsigned int max_count = 0x10000;
|
||||
/*
|
||||
* exit early if everything is already correct (this can save time
|
||||
* since this function may be called repeatedly during command tests
|
||||
* and execution)
|
||||
*/
|
||||
div1 = *d1 ? *d1 : max_count;
|
||||
div2 = *d2 ? *d2 : max_count;
|
||||
divider = div1 * div2;
|
||||
if (div1 * div2 * i8253_osc_base == *nanosec &&
|
||||
div1 > 1 && div1 <= max_count && div2 > 1 && div2 <= max_count &&
|
||||
/* check for overflow */
|
||||
divider > div1 && divider > div2 &&
|
||||
divider * i8253_osc_base > divider &&
|
||||
divider * i8253_osc_base > i8253_osc_base) {
|
||||
return;
|
||||
}
|
||||
|
||||
divider = *nanosec / i8253_osc_base;
|
||||
|
||||
div1_lub = div2_lub = 0;
|
||||
div1_glb = div2_glb = 0;
|
||||
|
||||
ns_glb = 0;
|
||||
ns_lub = 0xffffffff;
|
||||
|
||||
div2 = max_count;
|
||||
start = divider / div2;
|
||||
if (start < 2)
|
||||
start = 2;
|
||||
for (div1 = start; div1 <= divider / div1 + 1 && div1 <= max_count;
|
||||
div1++) {
|
||||
for (div2 = divider / div1;
|
||||
div1 * div2 <= divider + div1 + 1 && div2 <= max_count;
|
||||
div2++) {
|
||||
ns = i8253_osc_base * div1 * div2;
|
||||
if (ns <= *nanosec && ns > ns_glb) {
|
||||
ns_glb = ns;
|
||||
div1_glb = div1;
|
||||
div2_glb = div2;
|
||||
}
|
||||
if (ns >= *nanosec && ns < ns_lub) {
|
||||
ns_lub = ns;
|
||||
div1_lub = div1;
|
||||
div2_lub = div2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (flags & CMDF_ROUND_MASK) {
|
||||
case CMDF_ROUND_NEAREST:
|
||||
default:
|
||||
ns_high = div1_lub * div2_lub * i8253_osc_base;
|
||||
ns_low = div1_glb * div2_glb * i8253_osc_base;
|
||||
if (ns_high - *nanosec < *nanosec - ns_low) {
|
||||
div1 = div1_lub;
|
||||
div2 = div2_lub;
|
||||
} else {
|
||||
div1 = div1_glb;
|
||||
div2 = div2_glb;
|
||||
}
|
||||
break;
|
||||
case CMDF_ROUND_UP:
|
||||
div1 = div1_lub;
|
||||
div2 = div2_lub;
|
||||
break;
|
||||
case CMDF_ROUND_DOWN:
|
||||
div1 = div1_glb;
|
||||
div2 = div2_glb;
|
||||
break;
|
||||
}
|
||||
|
||||
*nanosec = div1 * div2 * i8253_osc_base;
|
||||
/* masking is done since counter maps zero to 0x10000 */
|
||||
*d1 = div1 & 0xffff;
|
||||
*d2 = div2 & 0xffff;
|
||||
}
|
||||
|
||||
#ifndef CMDTEST
|
||||
/*
|
||||
* i8254_load programs 8254 counter chip. It should also work for the 8253.
|
||||
* base_address is the lowest io address
|
||||
* for the chip (the address of counter 0).
|
||||
* counter_number is the counter you want to load (0,1 or 2)
|
||||
* count is the number to load into the counter.
|
||||
*
|
||||
* You probably want to use mode 2.
|
||||
*
|
||||
* Use i8254_mm_load() if you board uses memory-mapped io, it is
|
||||
* the same as i8254_load() except it uses writeb() instead of outb().
|
||||
*
|
||||
* Neither i8254_load() or i8254_read() do their loading/reading
|
||||
* atomically. The 16 bit read/writes are performed with two successive
|
||||
* 8 bit read/writes. So if two parts of your driver do a load/read on
|
||||
* the same counter, it may be necessary to protect these functions
|
||||
* with a spinlock.
|
||||
*
|
||||
* FMH
|
||||
*/
|
||||
|
||||
#define i8254_control_reg 3
|
||||
|
||||
static inline int i8254_load(unsigned long base_address, unsigned int regshift,
|
||||
unsigned int counter_number, unsigned int count,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (count > 0xffff)
|
||||
return -1;
|
||||
if (mode > 5)
|
||||
return -1;
|
||||
if ((mode == 2 || mode == 3) && count == 1)
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
byte |= 0x30; /* load low then high byte */
|
||||
byte |= (mode << 1); /* set counter mode */
|
||||
outb(byte, base_address + (i8254_control_reg << regshift));
|
||||
byte = count & 0xff; /* lsb of counter value */
|
||||
outb(byte, base_address + (counter_number << regshift));
|
||||
byte = (count >> 8) & 0xff; /* msb of counter value */
|
||||
outb(byte, base_address + (counter_number << regshift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int i8254_mm_load(void __iomem *base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number,
|
||||
unsigned int count,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (count > 0xffff)
|
||||
return -1;
|
||||
if (mode > 5)
|
||||
return -1;
|
||||
if ((mode == 2 || mode == 3) && count == 1)
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
byte |= 0x30; /* load low then high byte */
|
||||
byte |= (mode << 1); /* set counter mode */
|
||||
writeb(byte, base_address + (i8254_control_reg << regshift));
|
||||
byte = count & 0xff; /* lsb of counter value */
|
||||
writeb(byte, base_address + (counter_number << regshift));
|
||||
byte = (count >> 8) & 0xff; /* msb of counter value */
|
||||
writeb(byte, base_address + (counter_number << regshift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 16 bit counter value, should work for 8253 also. */
|
||||
static inline int i8254_read(unsigned long base_address, unsigned int regshift,
|
||||
unsigned int counter_number)
|
||||
{
|
||||
unsigned int byte;
|
||||
int ret;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
|
||||
/* latch counter */
|
||||
byte = counter_number << 6;
|
||||
outb(byte, base_address + (i8254_control_reg << regshift));
|
||||
|
||||
/* read lsb */
|
||||
ret = inb(base_address + (counter_number << regshift));
|
||||
/* read msb */
|
||||
ret += inb(base_address + (counter_number << regshift)) << 8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int i8254_mm_read(void __iomem *base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number)
|
||||
{
|
||||
unsigned int byte;
|
||||
int ret;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
|
||||
/* latch counter */
|
||||
byte = counter_number << 6;
|
||||
writeb(byte, base_address + (i8254_control_reg << regshift));
|
||||
|
||||
/* read lsb */
|
||||
ret = readb(base_address + (counter_number << regshift));
|
||||
/* read msb */
|
||||
ret += readb(base_address + (counter_number << regshift)) << 8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Loads 16 bit initial counter value, should work for 8253 also. */
|
||||
static inline void i8254_write(unsigned long base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number, unsigned int count)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return;
|
||||
|
||||
byte = count & 0xff; /* lsb of counter value */
|
||||
outb(byte, base_address + (counter_number << regshift));
|
||||
byte = (count >> 8) & 0xff; /* msb of counter value */
|
||||
outb(byte, base_address + (counter_number << regshift));
|
||||
}
|
||||
|
||||
static inline void i8254_mm_write(void __iomem *base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return;
|
||||
|
||||
byte = count & 0xff; /* lsb of counter value */
|
||||
writeb(byte, base_address + (counter_number << regshift));
|
||||
byte = (count >> 8) & 0xff; /* msb of counter value */
|
||||
writeb(byte, base_address + (counter_number << regshift));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set counter mode, should work for 8253 also.
|
||||
* Note: the 'mode' value is different to that for i8254_load() and comes
|
||||
* from the INSN_CONFIG_8254_SET_MODE command:
|
||||
* I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
|
||||
* OR'ed with:
|
||||
* I8254_BCD, I8254_BINARY
|
||||
*/
|
||||
static inline int i8254_set_mode(unsigned long base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number, unsigned int mode)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
byte |= 0x30; /* load low then high byte */
|
||||
byte |= mode; /* set counter mode and BCD|binary */
|
||||
outb(byte, base_address + (i8254_control_reg << regshift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int i8254_mm_set_mode(void __iomem *base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -1;
|
||||
|
||||
byte = counter_number << 6;
|
||||
byte |= 0x30; /* load low then high byte */
|
||||
byte |= mode; /* set counter mode and BCD|binary */
|
||||
writeb(byte, base_address + (i8254_control_reg << regshift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int i8254_status(unsigned long base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number)
|
||||
{
|
||||
outb(0xE0 | (2 << counter_number),
|
||||
base_address + (i8254_control_reg << regshift));
|
||||
return inb(base_address + (counter_number << regshift));
|
||||
}
|
||||
|
||||
static inline int i8254_mm_status(void __iomem *base_address,
|
||||
unsigned int regshift,
|
||||
unsigned int counter_number)
|
||||
{
|
||||
writeb(0xE0 | (2 << counter_number),
|
||||
base_address + (i8254_control_reg << regshift));
|
||||
return readb(base_address + (counter_number << regshift));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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,10 +71,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "amcc_s5933.h"
|
||||
|
||||
@ -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,10 +22,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "amcc_s5933.h"
|
||||
#include "z8536.h"
|
||||
@ -249,8 +248,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)
|
||||
|
@ -23,9 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "addi_watchdog.h"
|
||||
#include "comedi_fc.h"
|
||||
|
||||
|
@ -22,11 +22,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "addi_tcw.h"
|
||||
#include "addi_watchdog.h"
|
||||
@ -107,12 +106,12 @@
|
||||
#define APCI1564_COUNTER(x) ((x) * 0x20)
|
||||
|
||||
struct apci1564_private {
|
||||
unsigned long eeprom; /* base address of EEPROM register */
|
||||
unsigned long timer; /* base address of 12-bit timer */
|
||||
unsigned long counters; /* base address of 32-bit counters */
|
||||
unsigned int mode1; /* riding-edge/high level channels */
|
||||
unsigned int mode2; /* falling-edge/low level channels */
|
||||
unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */
|
||||
unsigned long eeprom; /* base address of EEPROM register */
|
||||
unsigned long timer; /* base address of 12-bit timer */
|
||||
unsigned long counters; /* base address of 32-bit counters */
|
||||
unsigned int mode1; /* riding-edge/high level channels */
|
||||
unsigned int mode2; /* falling-edge/low level channels */
|
||||
unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */
|
||||
struct task_struct *tsk_current;
|
||||
};
|
||||
|
||||
@ -407,7 +406,7 @@ static int apci1564_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;
|
||||
}
|
||||
|
||||
@ -430,7 +429,7 @@ static int apci1564_cos_cancel(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int apci1564_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct apci1564_private *devpriv;
|
||||
|
@ -23,9 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* Register I/O map
|
||||
|
@ -23,11 +23,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "addi_watchdog.h"
|
||||
#include "comedi_fc.h"
|
||||
|
||||
|
@ -23,9 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "addi_watchdog.h"
|
||||
|
||||
/*
|
||||
|
@ -22,10 +22,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "amcc_s5933.h"
|
||||
|
||||
|
@ -23,11 +23,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "amcc_s5933.h"
|
||||
|
||||
@ -203,7 +202,7 @@ static unsigned short apci3501_eeprom_readw(unsigned long iobase,
|
||||
outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD);
|
||||
apci3501_eeprom_wait(iobase);
|
||||
outb(((addr + i) >> 8) & 0xff,
|
||||
iobase + AMCC_OP_REG_MCSR_NVDATA);
|
||||
iobase + AMCC_OP_REG_MCSR_NVDATA);
|
||||
apci3501_eeprom_wait(iobase);
|
||||
|
||||
/* Read the eeprom data byte */
|
||||
@ -270,7 +269,7 @@ static irqreturn_t apci3501_interrupt(int irq, void *d)
|
||||
|
||||
/* Disable Interrupt */
|
||||
ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
|
||||
ul_Command1 = (ul_Command1 & 0xFFFFF9FDul);
|
||||
ul_Command1 = ul_Command1 & 0xFFFFF9FDul;
|
||||
outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG);
|
||||
|
||||
ui_Timer_AOWatchdog = inl(dev->iobase + APCI3501_TIMER_IRQ_REG) & 0x1;
|
||||
@ -282,7 +281,7 @@ static irqreturn_t apci3501_interrupt(int irq, void *d)
|
||||
/* Enable Interrupt Send a signal to from kernel to user space */
|
||||
send_sig(SIGIO, devpriv->tsk_Current, 0);
|
||||
ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
|
||||
ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1);
|
||||
ul_Command1 = (ul_Command1 & 0xFFFFF9FDul) | 1 << 1;
|
||||
outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG);
|
||||
inl(dev->iobase + APCI3501_TIMER_STATUS_REG);
|
||||
|
||||
|
@ -23,10 +23,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
|
||||
|
@ -54,7 +54,7 @@ static int addi_watchdog_insn_config(struct comedi_device *dev,
|
||||
|
||||
/* Time base is 20ms, let the user know the timeout */
|
||||
dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n",
|
||||
20 * reload + 20);
|
||||
20 * reload + 20);
|
||||
break;
|
||||
case INSN_CONFIG_DISARM:
|
||||
spriv->wdog_ctrl = 0;
|
||||
|
@ -19,19 +19,22 @@
|
||||
/*
|
||||
* Driver: adl_pci6208
|
||||
* Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
|
||||
* Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216 (adl_pci6216)
|
||||
* Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216
|
||||
* Author: nsyeow <nsyeow@pd.jaring.my>
|
||||
* Updated: Fri, 30 Jan 2004 14:44:27 +0800
|
||||
* Updated: Wed, 11 Feb 2015 11:37:18 +0000
|
||||
* Status: untested
|
||||
*
|
||||
* Configuration Options: not applicable, uses PCI auto config
|
||||
*
|
||||
* All supported devices share the same PCI device ID and are treated as a
|
||||
* PCI-6216 with 16 analog output channels. On a PCI-6208, the upper 8
|
||||
* channels exist in registers, but don't go to DAC chips.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* PCI-6208/6216-GL register map
|
||||
@ -45,27 +48,6 @@
|
||||
#define PCI6208_DIO_DI_MASK (0xf0)
|
||||
#define PCI6208_DIO_DI_SHIFT (4)
|
||||
|
||||
enum pci6208_boardid {
|
||||
BOARD_PCI6208,
|
||||
BOARD_PCI6216,
|
||||
};
|
||||
|
||||
struct pci6208_board {
|
||||
const char *name;
|
||||
int ao_chans;
|
||||
};
|
||||
|
||||
static const struct pci6208_board pci6208_boards[] = {
|
||||
[BOARD_PCI6208] = {
|
||||
.name = "adl_pci6208",
|
||||
.ao_chans = 8,
|
||||
},
|
||||
[BOARD_PCI6216] = {
|
||||
.name = "adl_pci6216",
|
||||
.ao_chans = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static int pci6208_ao_eoc(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
@ -136,21 +118,13 @@ static int pci6208_do_insn_bits(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int pci6208_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
const struct pci6208_board *boardinfo = NULL;
|
||||
struct comedi_subdevice *s;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (context < ARRAY_SIZE(pci6208_boards))
|
||||
boardinfo = &pci6208_boards[context];
|
||||
if (!boardinfo)
|
||||
return -ENODEV;
|
||||
dev->board_ptr = boardinfo;
|
||||
dev->board_name = boardinfo->name;
|
||||
|
||||
ret = comedi_pci_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -164,7 +138,7 @@ static int pci6208_auto_attach(struct comedi_device *dev,
|
||||
/* analog output subdevice */
|
||||
s->type = COMEDI_SUBD_AO;
|
||||
s->subdev_flags = SDF_WRITABLE;
|
||||
s->n_chan = boardinfo->ao_chans;
|
||||
s->n_chan = 16; /* Only 8 usable on PCI-6208 */
|
||||
s->maxdata = 0xffff;
|
||||
s->range_table = &range_bipolar10;
|
||||
s->insn_write = pci6208_ao_insn_write;
|
||||
@ -217,8 +191,9 @@ static int adl_pci6208_pci_probe(struct pci_dev *dev,
|
||||
}
|
||||
|
||||
static const struct pci_device_id adl_pci6208_pci_table[] = {
|
||||
{ PCI_VDEVICE(ADLINK, 0x6208), BOARD_PCI6208 },
|
||||
{ PCI_VDEVICE(ADLINK, 0x6216), BOARD_PCI6216 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
|
||||
0x9999, 0x6208) },
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
|
||||
|
@ -53,9 +53,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* Register I/O map (32-bit access only)
|
||||
|
@ -28,9 +28,8 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#define PCI8164_AXIS(x) ((x) * 0x08)
|
||||
#define PCI8164_CMD_MSTS_REG 0x00
|
||||
@ -69,7 +68,7 @@ static int adl_pci8164_insn_write(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int adl_pci8164_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct comedi_subdevice *s;
|
||||
|
@ -65,15 +65,14 @@ TODO:
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8253.h"
|
||||
#include "plx9052.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "comedi_8254.h"
|
||||
|
||||
#define PCI9111_FIFO_HALF_SIZE 512
|
||||
|
||||
@ -137,9 +136,6 @@ struct pci9111_private_data {
|
||||
unsigned int chunk_counter;
|
||||
unsigned int chunk_num_samples;
|
||||
|
||||
unsigned int div1;
|
||||
unsigned int div2;
|
||||
|
||||
unsigned short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
|
||||
};
|
||||
|
||||
@ -167,21 +163,6 @@ static void plx9050_interrupt_control(unsigned long io_base,
|
||||
outb(flags, io_base + PLX9052_INTCSR);
|
||||
}
|
||||
|
||||
static void pci9111_timer_set(struct comedi_device *dev)
|
||||
{
|
||||
struct pci9111_private_data *dev_private = dev->private;
|
||||
unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG;
|
||||
|
||||
i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY);
|
||||
i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
|
||||
|
||||
udelay(1);
|
||||
|
||||
i8254_write(timer_base, 1, 2, dev_private->div2);
|
||||
i8254_write(timer_base, 1, 1, dev_private->div1);
|
||||
}
|
||||
|
||||
enum pci9111_ISC0_sources {
|
||||
irq_on_eoc,
|
||||
irq_on_fifo_half_full
|
||||
@ -281,7 +262,6 @@ static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_cmd *cmd)
|
||||
{
|
||||
struct pci9111_private_data *dev_private = dev->private;
|
||||
int err = 0;
|
||||
unsigned int arg;
|
||||
|
||||
@ -345,10 +325,7 @@ static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
|
||||
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
arg = cmd->convert_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ,
|
||||
&dev_private->div1,
|
||||
&dev_private->div2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
}
|
||||
|
||||
@ -376,7 +353,6 @@ static int pci9111_ai_do_cmd_test(struct comedi_device *dev,
|
||||
return 5;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int pci9111_ai_do_cmd(struct comedi_device *dev,
|
||||
@ -400,13 +376,14 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev,
|
||||
/* This is the same gain on every channel */
|
||||
|
||||
outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK,
|
||||
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
|
||||
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
|
||||
|
||||
/* Set timer pacer */
|
||||
dev_private->scan_delay = 0;
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
trig |= PCI9111_AI_TRIG_CTRL_TPST;
|
||||
pci9111_timer_set(dev);
|
||||
comedi_8254_update_divisors(dev->pacer);
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
|
||||
pci9111_fifo_reset(dev);
|
||||
pci9111_interrupt_source_set(dev, irq_on_fifo_half_full,
|
||||
irq_on_timer_tick);
|
||||
@ -593,7 +570,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev,
|
||||
status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
|
||||
if ((status & PCI9111_AI_RANGE_MASK) != range) {
|
||||
outb(range & PCI9111_AI_RANGE_MASK,
|
||||
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
|
||||
dev->iobase + PCI9111_AI_RANGE_STAT_REG);
|
||||
}
|
||||
|
||||
pci9111_fifo_reset(dev);
|
||||
@ -667,16 +644,11 @@ static int pci9111_reset(struct comedi_device *dev)
|
||||
/* disable A/D triggers (software trigger mode) and auto scan off */
|
||||
outb(0, dev->iobase + PCI9111_AI_TRIG_CTRL_REG);
|
||||
|
||||
/* Reset 8254 chip */
|
||||
dev_private->div1 = 0;
|
||||
dev_private->div2 = 0;
|
||||
pci9111_timer_set(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci9111_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct pci9111_private_data *dev_private;
|
||||
@ -702,6 +674,11 @@ static int pci9111_auto_attach(struct comedi_device *dev,
|
||||
dev->irq = pcidev->irq;
|
||||
}
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + PCI9111_8254_BASE_REG,
|
||||
I8254_OSC_BASE_2MHZ, I8254_IO16, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -73,16 +73,15 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "amcc_s5933.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
#include "comedi_fc.h"
|
||||
|
||||
#define IORANGE_9118 64 /* I hope */
|
||||
@ -94,8 +93,7 @@
|
||||
/*
|
||||
* PCI BAR2 Register map (dev->iobase)
|
||||
*/
|
||||
#define PCI9118_TIMER_REG(x) (0x00 + ((x) * 4))
|
||||
#define PCI9118_TIMER_CTRL_REG 0x0c
|
||||
#define PCI9118_TIMER_BASE 0x00
|
||||
#define PCI9118_AI_FIFO_REG 0x10
|
||||
#define PCI9118_AO_REG(x) (0x10 + ((x) * 4))
|
||||
#define PCI9118_AI_STATUS_REG 0x18
|
||||
@ -239,10 +237,6 @@ struct pci9118_private {
|
||||
* measure can start/stop
|
||||
* on external trigger
|
||||
*/
|
||||
unsigned int ai_divisor1, ai_divisor2; /*
|
||||
* divisors for start of measure
|
||||
* on external start
|
||||
*/
|
||||
unsigned int dma_actbuf; /* which buffer is used now */
|
||||
struct pci9118_dmabuf dmabuf[2];
|
||||
int softsshdelay; /*
|
||||
@ -297,24 +291,6 @@ static void pci9118_amcc_int_ena(struct comedi_device *dev, bool enable)
|
||||
outl(intcsr, devpriv->iobase_a + AMCC_OP_REG_INTCSR);
|
||||
}
|
||||
|
||||
static void pci9118_timer_write(struct comedi_device *dev,
|
||||
unsigned int timer, unsigned int val)
|
||||
{
|
||||
outl(val & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
|
||||
outl((val >> 8) & 0xff, dev->iobase + PCI9118_TIMER_REG(timer));
|
||||
}
|
||||
|
||||
static void pci9118_timer_set_mode(struct comedi_device *dev,
|
||||
unsigned int timer, unsigned int mode)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = timer << 6; /* select timer */
|
||||
val |= 0x30; /* load low then high byte */
|
||||
val |= mode; /* set timer mode and BCD|binary */
|
||||
outl(val, dev->iobase + PCI9118_TIMER_CTRL_REG);
|
||||
}
|
||||
|
||||
static void pci9118_ai_reset_fifo(struct comedi_device *dev)
|
||||
{
|
||||
/* writing any value resets the A/D FIFO */
|
||||
@ -440,8 +416,8 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev,
|
||||
devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG |
|
||||
PCI9118_AI_CFG_AM;
|
||||
outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
|
||||
pci9118_timer_set_mode(dev, 0, I8254_MODE0);
|
||||
pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
|
||||
comedi_8254_load(dev->pacer, 0, dmabuf->hw >> 1,
|
||||
I8254_MODE0 | I8254_BINARY);
|
||||
devpriv->ai_cfg |= PCI9118_AI_CFG_START;
|
||||
outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
|
||||
}
|
||||
@ -577,15 +553,16 @@ static void pci9118_calc_divisors(struct comedi_device *dev,
|
||||
unsigned int *div1, unsigned int *div2,
|
||||
unsigned int chnsshfront)
|
||||
{
|
||||
struct comedi_8254 *pacer = dev->pacer;
|
||||
struct comedi_cmd *cmd = &s->async->cmd;
|
||||
|
||||
*div1 = *tim2 / I8254_OSC_BASE_4MHZ; /* convert timer (burst) */
|
||||
*div2 = *tim1 / I8254_OSC_BASE_4MHZ; /* scan timer */
|
||||
*div1 = *tim2 / pacer->osc_base; /* convert timer (burst) */
|
||||
*div2 = *tim1 / pacer->osc_base; /* scan timer */
|
||||
*div2 = *div2 / *div1; /* major timer is c1*c2 */
|
||||
if (*div2 < chans)
|
||||
*div2 = chans;
|
||||
|
||||
*tim2 = *div1 * I8254_OSC_BASE_4MHZ; /* real convert timer */
|
||||
*tim2 = *div1 * pacer->osc_base; /* real convert timer */
|
||||
|
||||
if (cmd->convert_src == TRIG_NOW && !chnsshfront) {
|
||||
/* use BSSH signal */
|
||||
@ -593,21 +570,13 @@ static void pci9118_calc_divisors(struct comedi_device *dev,
|
||||
*div2 = chans + 2;
|
||||
}
|
||||
|
||||
*tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ;
|
||||
*tim1 = *div1 * *div2 * pacer->osc_base;
|
||||
}
|
||||
|
||||
static void pci9118_start_pacer(struct comedi_device *dev, int mode)
|
||||
{
|
||||
struct pci9118_private *devpriv = dev->private;
|
||||
|
||||
pci9118_timer_set_mode(dev, 1, I8254_MODE2);
|
||||
pci9118_timer_set_mode(dev, 2, I8254_MODE2);
|
||||
udelay(1);
|
||||
|
||||
if ((mode == 1) || (mode == 2) || (mode == 4)) {
|
||||
pci9118_timer_write(dev, 2, devpriv->ai_divisor2);
|
||||
pci9118_timer_write(dev, 1, devpriv->ai_divisor1);
|
||||
}
|
||||
if (mode == 1 || mode == 2 || mode == 4)
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
|
||||
}
|
||||
|
||||
static int pci9118_ai_cancel(struct comedi_device *dev,
|
||||
@ -618,7 +587,7 @@ static int pci9118_ai_cancel(struct comedi_device *dev,
|
||||
if (devpriv->usedma)
|
||||
pci9118_amcc_dma_ena(dev, false);
|
||||
pci9118_exttrg_enable(dev, false);
|
||||
pci9118_start_pacer(dev, 0); /* stop 8254 counters */
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
|
||||
/* set default config (disable burst and triggers) */
|
||||
devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
|
||||
outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
|
||||
@ -663,7 +632,6 @@ static void pci9118_ai_munge(struct comedi_device *dev,
|
||||
array[i] ^= 0x8000;
|
||||
else
|
||||
array[i] = (array[i] >> 4) & 0x0fff;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,7 +934,7 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
|
||||
/* outl(0x02000000|AINT_WRITE_COMPL, devpriv->iobase_a+AMCC_OP_REG_INTCSR); */
|
||||
pci9118_amcc_dma_ena(dev, true);
|
||||
outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | EN_A2P_TRANSFERS,
|
||||
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
|
||||
devpriv->iobase_a + AMCC_OP_REG_INTCSR);
|
||||
/* allow bus mastering */
|
||||
|
||||
return 0;
|
||||
@ -975,6 +943,7 @@ static int Compute_and_setup_dma(struct comedi_device *dev,
|
||||
static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
{
|
||||
struct pci9118_private *devpriv = dev->private;
|
||||
struct comedi_8254 *pacer = dev->pacer;
|
||||
struct comedi_cmd *cmd = &s->async->cmd;
|
||||
unsigned int addchans = 0;
|
||||
|
||||
@ -1093,12 +1062,10 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
else
|
||||
devpriv->ai_do = 1;
|
||||
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
|
||||
&devpriv->ai_divisor1,
|
||||
&devpriv->ai_divisor2,
|
||||
&cmd->convert_arg,
|
||||
devpriv->ai_flags &
|
||||
CMDF_ROUND_NEAREST);
|
||||
comedi_8254_cascade_ns_to_timer(pacer, &cmd->convert_arg,
|
||||
devpriv->ai_flags &
|
||||
CMDF_ROUND_NEAREST);
|
||||
comedi_8254_update_divisors(pacer);
|
||||
|
||||
devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
|
||||
|
||||
@ -1112,8 +1079,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
|
||||
devpriv->ai_cfg |= PCI9118_AI_CFG_AM;
|
||||
outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
|
||||
pci9118_timer_set_mode(dev, 0, I8254_MODE0);
|
||||
pci9118_timer_write(dev, 0, dmabuf->hw >> 1);
|
||||
comedi_8254_load(pacer, 0, dmabuf->hw >> 1,
|
||||
I8254_MODE0 | I8254_BINARY);
|
||||
devpriv->ai_cfg |= PCI9118_AI_CFG_START;
|
||||
}
|
||||
}
|
||||
@ -1133,8 +1100,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
&cmd->scan_begin_arg, &cmd->convert_arg,
|
||||
devpriv->ai_flags,
|
||||
devpriv->ai_n_realscanlen,
|
||||
&devpriv->ai_divisor1,
|
||||
&devpriv->ai_divisor2,
|
||||
&pacer->divisor1,
|
||||
&pacer->divisor2,
|
||||
devpriv->ai_add_front);
|
||||
|
||||
devpriv->ai_ctrl |= PCI9118_AI_CTRL_TMRTR;
|
||||
@ -1162,8 +1129,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
if (devpriv->usedma)
|
||||
devpriv->ai_ctrl |= PCI9118_AI_CTRL_DMA;
|
||||
|
||||
pci9118_start_pacer(dev, -1); /* stop pacer */
|
||||
|
||||
/* set default config (disable burst and triggers) */
|
||||
devpriv->ai_cfg = PCI9118_AI_CFG_PDTRG | PCI9118_AI_CFG_PETRG;
|
||||
outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG);
|
||||
@ -1206,7 +1171,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
|
||||
int err = 0;
|
||||
unsigned int flags;
|
||||
unsigned int arg;
|
||||
unsigned int divisor1 = 0, divisor2 = 0;
|
||||
|
||||
/* Step 1 : check if triggers are trivially valid */
|
||||
|
||||
@ -1323,17 +1287,13 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev,
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
arg = cmd->scan_begin_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
|
||||
&divisor1, &divisor2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
|
||||
}
|
||||
|
||||
if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) {
|
||||
arg = cmd->convert_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_4MHZ,
|
||||
&divisor1, &divisor2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_TIMER &&
|
||||
@ -1482,10 +1442,6 @@ static void pci9118_reset(struct comedi_device *dev)
|
||||
inl(dev->iobase + PCI9118_INT_CTRL_REG);
|
||||
inl(dev->iobase + PCI9118_AI_STATUS_REG);
|
||||
|
||||
/* reset and stop counters */
|
||||
pci9118_timer_set_mode(dev, 0, I8254_MODE0);
|
||||
pci9118_start_pacer(dev, 0);
|
||||
|
||||
/* reset DMA and scan queue */
|
||||
outl(0, dev->iobase + PCI9118_AI_BURST_NUM_REG);
|
||||
outl(1, dev->iobase + PCI9118_AI_AUTOSCAN_MODE_REG);
|
||||
@ -1590,6 +1546,11 @@ static int pci9118_common_attach(struct comedi_device *dev,
|
||||
devpriv->iobase_a = pci_resource_start(pcidev, 0);
|
||||
dev->iobase = pci_resource_start(pcidev, 2);
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + PCI9118_TIMER_BASE,
|
||||
I8254_OSC_BASE_4MHZ, I8254_IO32, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
pci9118_reset(dev);
|
||||
|
||||
if (pcidev->irq) {
|
||||
|
@ -69,8 +69,6 @@ If you do not specify any options, they will default to
|
||||
|
||||
13-oct-2007
|
||||
+ first try
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -170,7 +168,6 @@ static int adq12b_di_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
|
||||
/* only bits 0-4 have information about digital inputs */
|
||||
data[1] = (inb(dev->iobase + ADQ12B_STINR) & ADQ12B_STINR_IN_MASK);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Author: Michal Dobes <dobes@tesnet.cz>
|
||||
*
|
||||
* Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
|
||||
* for testing and informations.
|
||||
* for testing and information.
|
||||
*
|
||||
* hardware driver for Advantech cards:
|
||||
* card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
|
||||
@ -42,13 +42,12 @@ Configuration options:
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
#include "amcc_s5933.h"
|
||||
|
||||
#define PCI171x_AD_DATA 0 /* R: A/D data */
|
||||
@ -67,11 +66,6 @@ Configuration options:
|
||||
|
||||
#define PCI171X_TIMER_BASE 0x18
|
||||
|
||||
#define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
|
||||
#define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
|
||||
#define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
|
||||
#define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
|
||||
|
||||
/* upper bits from status register (PCI171x_STATUS) (lower is same with control
|
||||
* reg) */
|
||||
#define Status_FE 0x0100 /* 1=FIFO is empty */
|
||||
@ -87,16 +81,6 @@ Configuration options:
|
||||
#define Control_EXT 0x0004 /* 1=external trigger source */
|
||||
#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
|
||||
#define Control_SW 0x0001 /* 1=enable software trigger source */
|
||||
/* bits from counter control register (PCI171x_CNTCTRL) */
|
||||
#define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
|
||||
#define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
|
||||
#define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
|
||||
#define Counter_M2 0x0008
|
||||
#define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
|
||||
#define Counter_RW1 0x0020
|
||||
#define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
|
||||
#define Counter_SC1 0x0080 /* be used, 00 for CNT0,
|
||||
* 11 for read-back command */
|
||||
|
||||
#define PCI1720_DA0 0 /* W: D/A register 0 */
|
||||
#define PCI1720_DA1 2 /* W: D/A register 1 */
|
||||
@ -265,15 +249,9 @@ struct pci1710_private {
|
||||
unsigned char ai_et;
|
||||
unsigned int ai_et_CntrlReg;
|
||||
unsigned int ai_et_MuxVal;
|
||||
unsigned int next_divisor1;
|
||||
unsigned int next_divisor2;
|
||||
unsigned int divisor1;
|
||||
unsigned int divisor2;
|
||||
unsigned int act_chanlist[32]; /* list of scanned channel */
|
||||
unsigned char saved_seglen; /* len of the non-repeating chanlist */
|
||||
unsigned char da_ranges; /* copy of D/A outpit range register */
|
||||
unsigned int cnt0_write_wait; /* after a write, wait for update of the
|
||||
* internal state */
|
||||
};
|
||||
|
||||
static int pci171x_ai_check_chanlist(struct comedi_device *dev,
|
||||
@ -508,105 +486,6 @@ static int pci171x_do_insn_bits(struct comedi_device *dev,
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static void pci171x_start_pacer(struct comedi_device *dev,
|
||||
bool load_counters)
|
||||
{
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
|
||||
|
||||
i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
|
||||
|
||||
if (load_counters) {
|
||||
i8254_write(timer_base, 1, 2, devpriv->divisor2);
|
||||
i8254_write(timer_base, 1, 1, devpriv->divisor1);
|
||||
}
|
||||
}
|
||||
|
||||
static int pci171x_counter_insn_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
unsigned int msb, lsb, ccntrl;
|
||||
int i;
|
||||
|
||||
ccntrl = 0xD2; /* count only */
|
||||
for (i = 0; i < insn->n; i++) {
|
||||
outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
|
||||
|
||||
lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
|
||||
msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
|
||||
|
||||
data[0] = lsb | (msb << 8);
|
||||
}
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int pci171x_counter_insn_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
uint msb, lsb, ccntrl, status;
|
||||
|
||||
lsb = data[0] & 0x00FF;
|
||||
msb = (data[0] & 0xFF00) >> 8;
|
||||
|
||||
/* write lsb, then msb */
|
||||
outw(lsb, dev->iobase + PCI171x_CNT0);
|
||||
outw(msb, dev->iobase + PCI171x_CNT0);
|
||||
|
||||
if (devpriv->cnt0_write_wait) {
|
||||
/* wait for the new count to be loaded */
|
||||
ccntrl = 0xE2;
|
||||
do {
|
||||
outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
|
||||
status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
|
||||
} while (status & 0x40);
|
||||
}
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int pci171x_counter_insn_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
#ifdef unused
|
||||
/* This doesn't work like a normal Comedi counter config */
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
uint ccntrl = 0;
|
||||
|
||||
devpriv->cnt0_write_wait = data[0] & 0x20;
|
||||
|
||||
/* internal or external clock? */
|
||||
if (!(data[0] & 0x10)) { /* internal */
|
||||
devpriv->CntrlReg &= ~Control_CNT0;
|
||||
} else {
|
||||
devpriv->CntrlReg |= Control_CNT0;
|
||||
}
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
|
||||
if (data[0] & 0x01)
|
||||
ccntrl |= Counter_M0;
|
||||
if (data[0] & 0x02)
|
||||
ccntrl |= Counter_M1;
|
||||
if (data[0] & 0x04)
|
||||
ccntrl |= Counter_M2;
|
||||
if (data[0] & 0x08)
|
||||
ccntrl |= Counter_BCD;
|
||||
ccntrl |= Counter_RW0; /* set read/write mode */
|
||||
ccntrl |= Counter_RW1;
|
||||
outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pci1720_ao_insn_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
@ -646,7 +525,7 @@ static int pci171x_ai_cancel(struct comedi_device *dev,
|
||||
devpriv->CntrlReg |= Control_SW;
|
||||
/* reset any operations */
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
pci171x_start_pacer(dev, false);
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
|
||||
outb(0, dev->iobase + PCI171x_CLRFIFO);
|
||||
outb(0, dev->iobase + PCI171x_CLRINT);
|
||||
|
||||
@ -767,7 +646,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
|
||||
outb(0, dev->iobase + PCI171x_CLRINT);
|
||||
outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
pci171x_start_pacer(dev, true);
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -786,8 +665,6 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
struct comedi_cmd *cmd = &s->async->cmd;
|
||||
|
||||
pci171x_start_pacer(dev, false);
|
||||
|
||||
pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
|
||||
devpriv->saved_seglen);
|
||||
|
||||
@ -798,10 +675,9 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
if ((cmd->flags & CMDF_WAKE_EOS) == 0)
|
||||
devpriv->CntrlReg |= Control_ONEFH;
|
||||
|
||||
devpriv->divisor1 = devpriv->next_divisor1;
|
||||
devpriv->divisor2 = devpriv->next_divisor2;
|
||||
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
comedi_8254_update_divisors(dev->pacer);
|
||||
|
||||
devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
|
||||
if (cmd->start_src == TRIG_EXT) {
|
||||
devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
|
||||
@ -815,7 +691,7 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
|
||||
if (cmd->start_src == TRIG_NOW)
|
||||
pci171x_start_pacer(dev, true);
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
|
||||
} else { /* TRIG_EXT */
|
||||
devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
@ -828,9 +704,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_cmd *cmd)
|
||||
{
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
int err = 0;
|
||||
unsigned int arg;
|
||||
|
||||
/* Step 1 : check if triggers are trivially valid */
|
||||
|
||||
@ -877,11 +751,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
|
||||
/* step 4: fix up any arguments */
|
||||
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
arg = cmd->convert_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
|
||||
&devpriv->next_divisor1,
|
||||
&devpriv->next_divisor2,
|
||||
&arg, cmd->flags);
|
||||
unsigned int arg = cmd->convert_arg;
|
||||
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
}
|
||||
|
||||
@ -898,19 +770,54 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci171x_insn_counter_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_SET_CLOCK_SRC:
|
||||
switch (data[1]) {
|
||||
case 0: /* internal */
|
||||
devpriv->ai_et_CntrlReg &= ~Control_CNT0;
|
||||
break;
|
||||
case 1: /* external */
|
||||
devpriv->ai_et_CntrlReg |= Control_CNT0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
break;
|
||||
case INSN_CONFIG_GET_CLOCK_SRC:
|
||||
if (devpriv->ai_et_CntrlReg & Control_CNT0) {
|
||||
data[1] = 1;
|
||||
data[2] = 0;
|
||||
} else {
|
||||
data[1] = 0;
|
||||
data[2] = I8254_OSC_BASE_10MHZ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int pci171x_reset(struct comedi_device *dev)
|
||||
{
|
||||
const struct boardtype *board = dev->board_ptr;
|
||||
struct pci1710_private *devpriv = dev->private;
|
||||
|
||||
outw(0x30, dev->iobase + PCI171x_CNTCTRL);
|
||||
/* Software trigger, CNT0=external */
|
||||
devpriv->CntrlReg = Control_SW | Control_CNT0;
|
||||
/* reset any operations */
|
||||
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
|
||||
outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
|
||||
outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
|
||||
pci171x_start_pacer(dev, false);
|
||||
devpriv->da_ranges = 0;
|
||||
if (board->has_ao) {
|
||||
/* set DACs to 0..5V */
|
||||
@ -977,6 +884,11 @@ static int pci1710_auto_attach(struct comedi_device *dev,
|
||||
return ret;
|
||||
dev->iobase = pci_resource_start(pcidev, 2);
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
|
||||
I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
n_subdevices = 0;
|
||||
if (board->n_aichan)
|
||||
n_subdevices++;
|
||||
@ -1073,16 +985,17 @@ static int pci1710_auto_attach(struct comedi_device *dev,
|
||||
subdev++;
|
||||
}
|
||||
|
||||
/* Counter subdevice (8254) */
|
||||
if (board->has_counter) {
|
||||
s = &dev->subdevices[subdev];
|
||||
s->type = COMEDI_SUBD_COUNTER;
|
||||
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
|
||||
s->n_chan = 1;
|
||||
s->maxdata = 0xffff;
|
||||
s->range_table = &range_unknown;
|
||||
s->insn_read = pci171x_counter_insn_read;
|
||||
s->insn_write = pci171x_counter_insn_write;
|
||||
s->insn_config = pci171x_counter_insn_config;
|
||||
comedi_8254_subdevice_init(s, dev->pacer);
|
||||
|
||||
dev->pacer->insn_config = pci171x_insn_counter_config;
|
||||
|
||||
/* counters 1 and 2 are used internally for the pacer */
|
||||
comedi_8254_set_busy(dev->pacer, 1, true);
|
||||
comedi_8254_set_busy(dev->pacer, 2, true);
|
||||
|
||||
subdev++;
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* PCI Bar 2 I/O Register map (dev->iobase)
|
||||
|
@ -47,9 +47,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* PCI bar 2 Register I/O map (dev->iobase)
|
||||
|
@ -30,13 +30,12 @@ Configuration options:
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8255.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
|
||||
/* hardware types of the cards */
|
||||
enum hw_cards_id {
|
||||
@ -60,12 +59,6 @@ enum hw_io_access {
|
||||
#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
|
||||
#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per
|
||||
* card */
|
||||
#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per
|
||||
* card */
|
||||
/* (could be more than one 8254 per
|
||||
* subdevice) */
|
||||
|
||||
#define SIZE_8254 4 /* 8254 IO space length */
|
||||
|
||||
#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
|
||||
|
||||
@ -230,7 +223,7 @@ struct diosubd_data {
|
||||
int chans; /* num of chans */
|
||||
int addr; /* PCI address ofset */
|
||||
int regs; /* number of registers to read or 8255
|
||||
subdevices or 8254 chips */
|
||||
subdevices */
|
||||
unsigned int specflags; /* addon subdevice flags */
|
||||
};
|
||||
|
||||
@ -243,7 +236,7 @@ struct dio_boardtype {
|
||||
struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */
|
||||
struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */
|
||||
struct diosubd_data boardid; /* card supports board ID switch */
|
||||
struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */
|
||||
unsigned long timer_regbase;
|
||||
enum hw_io_access io_access;
|
||||
};
|
||||
|
||||
@ -286,7 +279,7 @@ static const struct dio_boardtype boardtypes[] = {
|
||||
.sdi[0] = { 32, PCI1735_DI, 4, 0, },
|
||||
.sdo[0] = { 32, PCI1735_DO, 4, 0, },
|
||||
.boardid = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, },
|
||||
.s8254[0] = { 3, PCI1735_C8254, 1, 0, },
|
||||
.timer_regbase = PCI1735_C8254,
|
||||
.io_access = IO_8b,
|
||||
},
|
||||
[TYPE_PCI1736] = {
|
||||
@ -322,7 +315,7 @@ static const struct dio_boardtype boardtypes[] = {
|
||||
.cardtype = TYPE_PCI1751,
|
||||
.nsubdevs = 3,
|
||||
.sdio[0] = { 48, PCI1751_DIO, 2, 0, },
|
||||
.s8254[0] = { 3, PCI1751_CNT, 1, 0, },
|
||||
.timer_regbase = PCI1751_CNT,
|
||||
.io_access = IO_8b,
|
||||
},
|
||||
[TYPE_PCI1752] = {
|
||||
@ -425,7 +418,6 @@ static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
|
||||
for (i = 0; i < d->regs; i++)
|
||||
data[1] |= inb(dev->iobase + d->addr + i) << (8 * i);
|
||||
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
@ -484,83 +476,6 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
*/
|
||||
static int pci_8254_insn_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
|
||||
unsigned int chan, chip, chipchan;
|
||||
unsigned long flags;
|
||||
|
||||
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
|
||||
chip = chan / 3; /* chip on subdevice */
|
||||
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
|
||||
spin_lock_irqsave(&s->spin_lock, flags);
|
||||
data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip),
|
||||
0, chipchan);
|
||||
spin_unlock_irqrestore(&s->spin_lock, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
*/
|
||||
static int pci_8254_insn_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
|
||||
unsigned int chan, chip, chipchan;
|
||||
unsigned long flags;
|
||||
|
||||
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
|
||||
chip = chan / 3; /* chip on subdevice */
|
||||
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
|
||||
spin_lock_irqsave(&s->spin_lock, flags);
|
||||
i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip),
|
||||
0, chipchan, data[0]);
|
||||
spin_unlock_irqrestore(&s->spin_lock, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
*/
|
||||
static int pci_8254_insn_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
{
|
||||
const struct diosubd_data *d = (const struct diosubd_data *)s->private;
|
||||
unsigned int chan, chip, chipchan;
|
||||
unsigned long iobase;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
|
||||
chip = chan / 3; /* chip on subdevice */
|
||||
chipchan = chan - (3 * chip); /* channel on chip on subdevice */
|
||||
iobase = dev->iobase + d->addr + (SIZE_8254 * chip);
|
||||
spin_lock_irqsave(&s->spin_lock, flags);
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_SET_COUNTER_MODE:
|
||||
ret = i8254_set_mode(iobase, 0, chipchan, data[1]);
|
||||
if (ret < 0)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case INSN_CONFIG_8254_READ_STATUS:
|
||||
data[1] = i8254_status(iobase, 0, chipchan);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&s->spin_lock, flags);
|
||||
return ret < 0 ? ret : insn->n;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
*/
|
||||
@ -845,9 +760,6 @@ static int pci_dio_reset(struct comedi_device *dev)
|
||||
outb(0, dev->iobase + PCI1735_DO + 1);
|
||||
outb(0, dev->iobase + PCI1735_DO + 2);
|
||||
outb(0, dev->iobase + PCI1735_DO + 3);
|
||||
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0);
|
||||
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0);
|
||||
i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0);
|
||||
break;
|
||||
|
||||
case TYPE_PCI1736:
|
||||
@ -1029,26 +941,6 @@ static int pci_dio_add_do(struct comedi_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
*/
|
||||
static int pci_dio_add_8254(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
const struct diosubd_data *d)
|
||||
{
|
||||
s->type = COMEDI_SUBD_COUNTER;
|
||||
s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
|
||||
s->n_chan = d->chans;
|
||||
s->maxdata = 65535;
|
||||
s->len_chanlist = d->chans;
|
||||
s->insn_read = pci_8254_insn_read;
|
||||
s->insn_write = pci_8254_insn_write;
|
||||
s->insn_config = pci_8254_insn_config;
|
||||
s->private = (void *)d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
|
||||
unsigned long cardtype)
|
||||
{
|
||||
@ -1144,12 +1036,19 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
|
||||
subdev++;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_8254_SUBDEVS; i++)
|
||||
if (this_board->s8254[i].chans) {
|
||||
s = &dev->subdevices[subdev];
|
||||
pci_dio_add_8254(dev, s, &this_board->s8254[i]);
|
||||
subdev++;
|
||||
}
|
||||
if (this_board->timer_regbase) {
|
||||
s = &dev->subdevices[subdev];
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase +
|
||||
this_board->timer_regbase,
|
||||
0, I8254_IO8, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
comedi_8254_subdevice_init(s, dev->pacer);
|
||||
|
||||
subdev++;
|
||||
}
|
||||
|
||||
if (this_board->cardtype == TYPE_PCI1760)
|
||||
pci1760_attach(dev);
|
||||
|
@ -26,18 +26,14 @@
|
||||
|
||||
#include "amplc_dio200.h"
|
||||
#include "comedi_fc.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
#include "8255.h" /* only for register defines */
|
||||
|
||||
/* 200 series registers */
|
||||
#define DIO200_IO_SIZE 0x20
|
||||
#define DIO200_PCIE_IO_SIZE 0x4000
|
||||
#define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
|
||||
#define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
|
||||
#define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
|
||||
#define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
|
||||
#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
|
||||
#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
|
||||
#define DIO200_CLK_SCE(x) (0x18 + (x)) /* Group X/Y/Z clock sel reg */
|
||||
#define DIO200_GAT_SCE(x) (0x1b + (x)) /* Group X/Y/Z gate sel reg */
|
||||
#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
|
||||
/* Extra registers for new PCIe boards */
|
||||
#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */
|
||||
@ -101,16 +97,6 @@ static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
|
||||
1000000, /* 1 millisecond. */
|
||||
};
|
||||
|
||||
struct dio200_subdev_8254 {
|
||||
unsigned int ofs; /* Counter base offset */
|
||||
unsigned int clk_sce_ofs; /* CLK_SCE base address */
|
||||
unsigned int gat_sce_ofs; /* GAT_SCE base address */
|
||||
int which; /* Bit 5 of CLK_SCE or GAT_SCE */
|
||||
unsigned int clock_src[3]; /* Current clock sources */
|
||||
unsigned int gate_src[3]; /* Current gate sources */
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
struct dio200_subdev_8255 {
|
||||
unsigned int ofs; /* DIO base offset */
|
||||
};
|
||||
@ -177,6 +163,27 @@ static void dio200_write32(struct comedi_device *dev,
|
||||
outl(val, dev->iobase + offset);
|
||||
}
|
||||
|
||||
static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct comedi_8254 *i8254 = s->private;
|
||||
unsigned int offset;
|
||||
|
||||
/* get the offset that was passed to comedi_8254_*_init() */
|
||||
if (dev->mmio)
|
||||
offset = i8254->mmio - dev->mmio;
|
||||
else
|
||||
offset = i8254->iobase - dev->iobase;
|
||||
|
||||
/* remove the shift that was added for PCIe boards */
|
||||
if (board->is_pcie)
|
||||
offset >>= 3;
|
||||
|
||||
/* this offset now works for the dio200_{read,write} helpers */
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int dio200_subdev_intr_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
@ -482,175 +489,26 @@ static irqreturn_t dio200_interrupt(int irq, void *d)
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int chan)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
unsigned int val;
|
||||
|
||||
/* latch counter */
|
||||
val = chan << 6;
|
||||
dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
|
||||
/* read lsb, msb */
|
||||
val = dio200_read8(dev, subpriv->ofs + chan);
|
||||
val += dio200_read8(dev, subpriv->ofs + chan) << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void dio200_subdev_8254_write_chan(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int chan,
|
||||
unsigned int count)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
|
||||
/* write lsb, msb */
|
||||
dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
|
||||
dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
|
||||
}
|
||||
|
||||
static void dio200_subdev_8254_set_mode(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
unsigned int byte;
|
||||
|
||||
byte = chan << 6;
|
||||
byte |= 0x30; /* access order: lsb, msb */
|
||||
byte |= (mode & 0xf); /* counter mode and BCD|binary */
|
||||
dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
|
||||
}
|
||||
|
||||
static unsigned int dio200_subdev_8254_status(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int chan)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
|
||||
/* latch status */
|
||||
dio200_write8(dev, subpriv->ofs + i8254_control_reg,
|
||||
0xe0 | (2 << chan));
|
||||
/* read status */
|
||||
return dio200_read8(dev, subpriv->ofs + chan);
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int n;
|
||||
unsigned long flags;
|
||||
|
||||
for (n = 0; n < insn->n; n++) {
|
||||
spin_lock_irqsave(&subpriv->spinlock, flags);
|
||||
data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
|
||||
spin_unlock_irqrestore(&subpriv->spinlock, flags);
|
||||
}
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int n;
|
||||
unsigned long flags;
|
||||
|
||||
for (n = 0; n < insn->n; n++) {
|
||||
spin_lock_irqsave(&subpriv->spinlock, flags);
|
||||
dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
|
||||
spin_unlock_irqrestore(&subpriv->spinlock, flags);
|
||||
}
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int counter_number,
|
||||
unsigned int gate_src)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
unsigned char byte;
|
||||
|
||||
if (!board->has_clk_gat_sce)
|
||||
return -1;
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (gate_src > (board->is_pcie ? 31 : 7))
|
||||
return -1;
|
||||
|
||||
subpriv->gate_src[counter_number] = gate_src;
|
||||
byte = gat_sce(subpriv->which, counter_number, gate_src);
|
||||
dio200_write8(dev, subpriv->gat_sce_ofs, byte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int counter_number)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
|
||||
if (!board->has_clk_gat_sce)
|
||||
return -1;
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
|
||||
return subpriv->gate_src[counter_number];
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
|
||||
static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int counter_number,
|
||||
unsigned int clock_src)
|
||||
unsigned int chan,
|
||||
unsigned int src)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
unsigned char byte;
|
||||
unsigned int offset = dio200_subdev_8254_offset(dev, s);
|
||||
|
||||
if (!board->has_clk_gat_sce)
|
||||
return -1;
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
if (clock_src > (board->is_pcie ? 31 : 7))
|
||||
return -1;
|
||||
|
||||
subpriv->clock_src[counter_number] = clock_src;
|
||||
byte = clk_sce(subpriv->which, counter_number, clock_src);
|
||||
dio200_write8(dev, subpriv->clk_sce_ofs, byte);
|
||||
|
||||
return 0;
|
||||
dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
|
||||
gat_sce((offset >> 2) & 1, chan, src));
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int counter_number,
|
||||
unsigned int *period_ns)
|
||||
static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
unsigned int chan,
|
||||
unsigned int src)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
unsigned clock_src;
|
||||
unsigned int offset = dio200_subdev_8254_offset(dev, s);
|
||||
|
||||
if (!board->has_clk_gat_sce)
|
||||
return -1;
|
||||
if (counter_number > 2)
|
||||
return -1;
|
||||
|
||||
clock_src = subpriv->clock_src[counter_number];
|
||||
*period_ns = clock_period[clock_src];
|
||||
return clock_src;
|
||||
dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
|
||||
clk_sce((offset >> 2) & 1, chan, src));
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_config(struct comedi_device *dev,
|
||||
@ -658,54 +516,44 @@ static int dio200_subdev_8254_config(struct comedi_device *dev,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct dio200_subdev_8254 *subpriv = s->private;
|
||||
int ret = 0;
|
||||
int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned long flags;
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct comedi_8254 *i8254 = s->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int max_src = board->is_pcie ? 31 : 7;
|
||||
unsigned int src;
|
||||
|
||||
if (!board->has_clk_gat_sce)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&subpriv->spinlock, flags);
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_SET_COUNTER_MODE:
|
||||
if (data[1] > (I8254_MODE5 | I8254_BCD))
|
||||
ret = -EINVAL;
|
||||
else
|
||||
dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
|
||||
break;
|
||||
case INSN_CONFIG_8254_READ_STATUS:
|
||||
data[1] = dio200_subdev_8254_status(dev, s, chan);
|
||||
break;
|
||||
case INSN_CONFIG_SET_GATE_SRC:
|
||||
ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
|
||||
if (ret < 0)
|
||||
ret = -EINVAL;
|
||||
src = data[2];
|
||||
if (src > max_src)
|
||||
return -EINVAL;
|
||||
|
||||
dio200_subdev_8254_set_gate_src(dev, s, chan, src);
|
||||
i8254->gate_src[chan] = src;
|
||||
break;
|
||||
case INSN_CONFIG_GET_GATE_SRC:
|
||||
ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
|
||||
if (ret < 0) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
data[2] = ret;
|
||||
data[2] = i8254->gate_src[chan];
|
||||
break;
|
||||
case INSN_CONFIG_SET_CLOCK_SRC:
|
||||
ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
|
||||
if (ret < 0)
|
||||
ret = -EINVAL;
|
||||
src = data[1];
|
||||
if (src > max_src)
|
||||
return -EINVAL;
|
||||
|
||||
dio200_subdev_8254_set_clock_src(dev, s, chan, src);
|
||||
i8254->clock_src[chan] = src;
|
||||
break;
|
||||
case INSN_CONFIG_GET_CLOCK_SRC:
|
||||
ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
|
||||
if (ret < 0) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
data[1] = ret;
|
||||
data[1] = i8254->clock_src[chan];
|
||||
data[2] = clock_period[i8254->clock_src[chan]];
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&subpriv->spinlock, flags);
|
||||
return ret < 0 ? ret : insn->n;
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int dio200_subdev_8254_init(struct comedi_device *dev,
|
||||
@ -713,36 +561,46 @@ static int dio200_subdev_8254_init(struct comedi_device *dev,
|
||||
unsigned int offset)
|
||||
{
|
||||
const struct dio200_board *board = dev->board_ptr;
|
||||
struct dio200_subdev_8254 *subpriv;
|
||||
unsigned int chan;
|
||||
struct comedi_8254 *i8254;
|
||||
unsigned int regshift;
|
||||
int chan;
|
||||
|
||||
subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
|
||||
if (!subpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
s->type = COMEDI_SUBD_COUNTER;
|
||||
s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
|
||||
s->n_chan = 3;
|
||||
s->maxdata = 0xFFFF;
|
||||
s->insn_read = dio200_subdev_8254_read;
|
||||
s->insn_write = dio200_subdev_8254_write;
|
||||
s->insn_config = dio200_subdev_8254_config;
|
||||
|
||||
spin_lock_init(&subpriv->spinlock);
|
||||
subpriv->ofs = offset;
|
||||
if (board->has_clk_gat_sce) {
|
||||
/* Derive CLK_SCE and GAT_SCE register offsets from
|
||||
* 8254 offset. */
|
||||
subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
|
||||
subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3);
|
||||
subpriv->which = (offset >> 2) & 1;
|
||||
/*
|
||||
* PCIe boards need the offset shifted in order to get the
|
||||
* correct base address of the timer.
|
||||
*/
|
||||
if (board->is_pcie) {
|
||||
offset <<= 3;
|
||||
regshift = 3;
|
||||
} else {
|
||||
regshift = 0;
|
||||
}
|
||||
|
||||
if (dev->mmio)
|
||||
i8254 = comedi_8254_mm_init(dev->mmio + offset,
|
||||
0, I8254_IO8, regshift);
|
||||
else
|
||||
i8254 = comedi_8254_init(dev->iobase + offset,
|
||||
0, I8254_IO8, regshift);
|
||||
if (!i8254)
|
||||
return -ENOMEM;
|
||||
|
||||
comedi_8254_subdevice_init(s, i8254);
|
||||
|
||||
i8254->insn_config = dio200_subdev_8254_config;
|
||||
|
||||
/*
|
||||
* There could be multiple timers so this driver does not
|
||||
* use dev->pacer to save the i8254 pointer. Instead,
|
||||
* comedi_8254_subdevice_init() saved the i8254 pointer in
|
||||
* s->private. Set the runflag bit so that the core will
|
||||
* automatically free it when the driver is detached.
|
||||
*/
|
||||
s->runflags |= COMEDI_SRF_FREE_SPRIV;
|
||||
|
||||
/* Initialize channels. */
|
||||
for (chan = 0; chan < 3; chan++) {
|
||||
dio200_subdev_8254_set_mode(dev, s, chan,
|
||||
I8254_MODE0 | I8254_BINARY);
|
||||
if (board->has_clk_gat_sce) {
|
||||
if (board->has_clk_gat_sce) {
|
||||
for (chan = 0; chan < 3; chan++) {
|
||||
/* Gate source 0 is VCC (logic 1). */
|
||||
dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
|
||||
/* Clock source 0 is the dedicated clock input. */
|
||||
|
@ -221,10 +221,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "amplc_dio200.h"
|
||||
|
||||
|
@ -195,7 +195,6 @@ static void __exit amplc_pc236_common_exit(void)
|
||||
}
|
||||
module_exit(amplc_pc236_common_exit);
|
||||
|
||||
|
||||
MODULE_AUTHOR("Comedi http://www.comedi.org");
|
||||
MODULE_DESCRIPTION("Comedi helper for amplc_pc236 and amplc_pci236");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -103,22 +103,18 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
|
||||
/*
|
||||
* PCI224/234 i/o space 1 (PCIBAR2) registers.
|
||||
*/
|
||||
#define PCI224_Z2_CT0 0x14 /* 82C54 counter/timer 0 */
|
||||
#define PCI224_Z2_CT1 0x15 /* 82C54 counter/timer 1 */
|
||||
#define PCI224_Z2_CT2 0x16 /* 82C54 counter/timer 2 */
|
||||
#define PCI224_Z2_CTC 0x17 /* 82C54 counter/timer control word */
|
||||
#define PCI224_Z2_BASE 0x14 /* 82C54 counter/timer */
|
||||
#define PCI224_ZCLK_SCE 0x1A /* Group Z Clock Configuration Register */
|
||||
#define PCI224_ZGAT_SCE 0x1D /* Group Z Gate Configuration Register */
|
||||
#define PCI224_INT_SCE 0x1E /* ISR Interrupt source mask register */
|
||||
@ -379,8 +375,6 @@ struct pci224_private {
|
||||
int intr_cpuid;
|
||||
short intr_running;
|
||||
unsigned short daccon;
|
||||
unsigned int cached_div1;
|
||||
unsigned int cached_div2;
|
||||
unsigned short ao_enab; /* max 16 channels so 'short' will do */
|
||||
unsigned char intsce;
|
||||
};
|
||||
@ -451,7 +445,6 @@ static void pci224_ao_stop(struct comedi_device *dev,
|
||||
if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
|
||||
return;
|
||||
|
||||
|
||||
spin_lock_irqsave(&devpriv->ao_spinlock, flags);
|
||||
/* Kill the interrupts. */
|
||||
devpriv->intsce = 0;
|
||||
@ -668,7 +661,6 @@ static int
|
||||
pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
struct comedi_cmd *cmd)
|
||||
{
|
||||
struct pci224_private *devpriv = dev->private;
|
||||
int err = 0;
|
||||
unsigned int arg;
|
||||
|
||||
@ -793,10 +785,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
arg = cmd->scan_begin_arg;
|
||||
/* Use two timers. */
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
|
||||
&devpriv->cached_div1,
|
||||
&devpriv->cached_div2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
|
||||
}
|
||||
|
||||
@ -817,7 +806,6 @@ static void pci224_ao_start_pacer(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
struct pci224_private *devpriv = dev->private;
|
||||
unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0;
|
||||
|
||||
/*
|
||||
* The output of timer Z2-0 will be used as the scan trigger
|
||||
@ -830,14 +818,10 @@ static void pci224_ao_start_pacer(struct comedi_device *dev,
|
||||
outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
|
||||
/* Z2-2 needs 10 MHz clock. */
|
||||
outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE);
|
||||
/* Load Z2-2 mode (2) and counter (div1). */
|
||||
i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_write(timer_base, 0, 2, devpriv->cached_div1);
|
||||
/* Z2-0 is clocked from Z2-2's output. */
|
||||
outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE);
|
||||
/* Load Z2-0 mode (2) and counter (div2). */
|
||||
i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_write(timer_base, 0, 0, devpriv->cached_div2);
|
||||
|
||||
comedi_8254_pacer_enable(dev->pacer, 2, 0, false);
|
||||
}
|
||||
|
||||
static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
@ -852,10 +836,9 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
unsigned long flags;
|
||||
|
||||
/* Cannot handle null/empty chanlist. */
|
||||
if (cmd->chanlist == NULL || cmd->chanlist_len == 0)
|
||||
if (!cmd->chanlist || cmd->chanlist_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
/* Determine which channels are enabled and their load order. */
|
||||
devpriv->ao_enab = 0;
|
||||
|
||||
@ -893,8 +876,10 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
|
||||
dev->iobase + PCI224_DACCON);
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_TIMER)
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
comedi_8254_update_divisors(dev->pacer);
|
||||
pci224_ao_start_pacer(dev, s);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&devpriv->ao_spinlock, flags);
|
||||
if (cmd->start_src == TRIG_INT) {
|
||||
@ -1042,14 +1027,12 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
|
||||
if (!devpriv->ao_scan_vals)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
/* Allocate buffer to hold AO channel scan order. */
|
||||
devpriv->ao_scan_order = kmalloc(sizeof(devpriv->ao_scan_order[0]) *
|
||||
thisboard->ao_chans, GFP_KERNEL);
|
||||
if (!devpriv->ao_scan_order)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
/* Disable interrupt sources. */
|
||||
devpriv->intsce = 0;
|
||||
outb(0, devpriv->iobase1 + PCI224_INT_SCE);
|
||||
@ -1063,6 +1046,11 @@ pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
|
||||
outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
|
||||
dev->iobase + PCI224_DACCON);
|
||||
|
||||
dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE,
|
||||
I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -181,14 +181,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
#include "8255.h"
|
||||
|
||||
/*
|
||||
@ -206,10 +205,6 @@
|
||||
#define PCI230_PPI_X_C 0x02 /* User PPI (82C55) port C */
|
||||
#define PCI230_PPI_X_CMD 0x03 /* User PPI (82C55) control word */
|
||||
#define PCI230_Z2_CT_BASE 0x14 /* 82C54 counter/timer base */
|
||||
#define PCI230_Z2_CT0 0x14 /* 82C54 counter/timer 0 */
|
||||
#define PCI230_Z2_CT1 0x15 /* 82C54 counter/timer 1 */
|
||||
#define PCI230_Z2_CT2 0x16 /* 82C54 counter/timer 2 */
|
||||
#define PCI230_Z2_CTC 0x17 /* 82C54 counter/timer control word */
|
||||
#define PCI230_ZCLK_SCE 0x1A /* Group Z Clock Configuration */
|
||||
#define PCI230_ZGAT_SCE 0x1D /* Group Z Gate Configuration */
|
||||
#define PCI230_INT_SCE 0x1E /* Interrupt source mask (w) */
|
||||
@ -377,12 +372,6 @@
|
||||
#define CLK_EXT 7 /* external clock */
|
||||
/* Macro to construct clock input configuration register value. */
|
||||
#define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7))
|
||||
/* Timebases in ns. */
|
||||
#define TIMEBASE_10MHZ 100
|
||||
#define TIMEBASE_1MHZ 1000
|
||||
#define TIMEBASE_100KHZ 10000
|
||||
#define TIMEBASE_10KHZ 100000
|
||||
#define TIMEBASE_1KHZ 1000000
|
||||
|
||||
/*
|
||||
* Counter/timer gate input configuration sources.
|
||||
@ -507,11 +496,11 @@ struct pci230_private {
|
||||
|
||||
/* PCI230 clock source periods in ns */
|
||||
static const unsigned int pci230_timebase[8] = {
|
||||
[CLK_10MHZ] = TIMEBASE_10MHZ,
|
||||
[CLK_1MHZ] = TIMEBASE_1MHZ,
|
||||
[CLK_100KHZ] = TIMEBASE_100KHZ,
|
||||
[CLK_10KHZ] = TIMEBASE_10KHZ,
|
||||
[CLK_1KHZ] = TIMEBASE_1KHZ,
|
||||
[CLK_10MHZ] = I8254_OSC_BASE_10MHZ,
|
||||
[CLK_1MHZ] = I8254_OSC_BASE_1MHZ,
|
||||
[CLK_100KHZ] = I8254_OSC_BASE_100KHZ,
|
||||
[CLK_10KHZ] = I8254_OSC_BASE_10KHZ,
|
||||
[CLK_1KHZ] = I8254_OSC_BASE_1KHZ,
|
||||
};
|
||||
|
||||
/* PCI230 analogue input range table */
|
||||
@ -695,7 +684,7 @@ static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
|
||||
unsigned int count;
|
||||
|
||||
/* Set mode. */
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, mode);
|
||||
comedi_8254_set_mode(dev->pacer, ct, mode);
|
||||
/* Determine clock source and count. */
|
||||
clk_src = pci230_choose_clk_count(ns, &count, flags);
|
||||
/* Program clock source. */
|
||||
@ -704,13 +693,13 @@ static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
|
||||
if (count >= 65536)
|
||||
count = 0;
|
||||
|
||||
i8254_write(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, count);
|
||||
comedi_8254_write(dev->pacer, ct, count);
|
||||
}
|
||||
|
||||
static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
|
||||
{
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, ct, I8254_MODE1);
|
||||
/* Counter ct, 8254 mode 1, initial count not written. */
|
||||
comedi_8254_set_mode(dev->pacer, ct, I8254_MODE1);
|
||||
}
|
||||
|
||||
static int pci230_ai_eoc(struct comedi_device *dev,
|
||||
@ -760,7 +749,7 @@ static int pci230_ai_insn_read(struct comedi_device *dev,
|
||||
*/
|
||||
adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
|
||||
/* Set Z2-CT2 output low to avoid any false triggers. */
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE0);
|
||||
devpriv->ai_bipolar = comedi_range_is_bipolar(s, range);
|
||||
if (aref == AREF_DIFF) {
|
||||
/* Differential. */
|
||||
@ -811,10 +800,8 @@ static int pci230_ai_insn_read(struct comedi_device *dev,
|
||||
* Trigger conversion by toggling Z2-CT2 output
|
||||
* (finish with output high).
|
||||
*/
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0,
|
||||
2, I8254_MODE0);
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0,
|
||||
2, I8254_MODE1);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE0);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE1);
|
||||
|
||||
/* wait for conversion to end */
|
||||
ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0);
|
||||
@ -1767,8 +1754,8 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev,
|
||||
* Trigger conversion by toggling Z2-CT2 output.
|
||||
* Finish with output high.
|
||||
*/
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE0);
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE0);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE1);
|
||||
/*
|
||||
* Delay. Should driver be responsible for this? An
|
||||
* alternative would be to wait until conversion is complete,
|
||||
@ -2189,7 +2176,7 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
* Set counter/timer 2 output high for use as the initial start
|
||||
* conversion source.
|
||||
*/
|
||||
i8254_set_mode(dev->iobase + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1);
|
||||
comedi_8254_set_mode(dev->pacer, 2, I8254_MODE1);
|
||||
|
||||
/*
|
||||
* Temporarily use CT2 output as conversion trigger source and
|
||||
@ -2393,7 +2380,7 @@ static int pci230_auto_attach(struct comedi_device *dev,
|
||||
spin_lock_init(&devpriv->ao_stop_spinlock);
|
||||
|
||||
dev->board_ptr = pci230_find_pci_board(pci_dev);
|
||||
if (dev->board_ptr == NULL) {
|
||||
if (!dev->board_ptr) {
|
||||
dev_err(dev->class_dev,
|
||||
"amplc_pci230: BUG! cannot determine board type!\n");
|
||||
return -EINVAL;
|
||||
@ -2481,6 +2468,11 @@ static int pci230_auto_attach(struct comedi_device *dev,
|
||||
dev->irq = pci_dev->irq;
|
||||
}
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + PCI230_Z2_CT_BASE,
|
||||
0, I8254_IO8, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = comedi_alloc_subdevices(dev, 3);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -42,10 +42,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "amplc_pc236.h"
|
||||
#include "plx9052.h"
|
||||
|
@ -33,9 +33,8 @@ The state of the outputs can be read.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
static int pci263_do_insn_bits(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
|
@ -30,8 +30,6 @@ Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO
|
||||
Author: ds
|
||||
Updated: Mon, 04 Nov 2002 20:04:21 -0800
|
||||
Status: experimental
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -41,16 +39,13 @@ Status: experimental
|
||||
#include "../comedi_pcmcia.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
|
||||
#define DAS16CS_ADC_DATA 0
|
||||
#define DAS16CS_DIO_MUX 2
|
||||
#define DAS16CS_MISC1 4
|
||||
#define DAS16CS_MISC2 6
|
||||
#define DAS16CS_CTR0 8
|
||||
#define DAS16CS_CTR1 10
|
||||
#define DAS16CS_CTR2 12
|
||||
#define DAS16CS_CTR_CONTROL 14
|
||||
#define DAS16CS_TIMER_BASE 8
|
||||
#define DAS16CS_DIO 16
|
||||
|
||||
struct das16cs_board {
|
||||
@ -279,6 +274,11 @@ static int das16cs_auto_attach(struct comedi_device *dev,
|
||||
if (!devpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + DAS16CS_TIMER_BASE,
|
||||
I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 3);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -62,13 +62,12 @@ analog triggering on 1602 series
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8253.h"
|
||||
#include "comedi_8254.h"
|
||||
#include "8255.h"
|
||||
#include "amcc_s5933.h"
|
||||
#include "comedi_fc.h"
|
||||
@ -338,14 +337,12 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
|
||||
};
|
||||
|
||||
struct cb_pcidas_private {
|
||||
struct comedi_8254 *ao_pacer;
|
||||
/* base addresses */
|
||||
unsigned long s5933_config;
|
||||
unsigned long control_status;
|
||||
unsigned long adc_fifo;
|
||||
unsigned long ao_registers;
|
||||
/* divisors of master clock for analog input pacing */
|
||||
unsigned int divisor1;
|
||||
unsigned int divisor2;
|
||||
/* bits to write to registers */
|
||||
unsigned int adc_fifo_bits;
|
||||
unsigned int s5933_intcsr_bits;
|
||||
@ -353,9 +350,6 @@ struct cb_pcidas_private {
|
||||
/* fifo buffers */
|
||||
unsigned short ai_buffer[AI_BUFFER_SIZE];
|
||||
unsigned short ao_buffer[AO_BUFFER_SIZE];
|
||||
/* divisors of master clock for analog output pacing */
|
||||
unsigned int ao_divisor1;
|
||||
unsigned int ao_divisor2;
|
||||
unsigned int calibration_source;
|
||||
};
|
||||
|
||||
@ -530,7 +524,7 @@ static int wait_for_nvram_ready(unsigned long s5933_base_addr)
|
||||
}
|
||||
|
||||
static int nvram_read(struct comedi_device *dev, unsigned int address,
|
||||
uint8_t *data)
|
||||
uint8_t *data)
|
||||
{
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
unsigned long iobase = devpriv->s5933_config;
|
||||
@ -778,7 +772,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
|
||||
struct comedi_cmd *cmd)
|
||||
{
|
||||
const struct cb_pcidas_board *thisboard = dev->board_ptr;
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
int err = 0;
|
||||
unsigned int arg;
|
||||
|
||||
@ -858,18 +851,12 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
arg = cmd->scan_begin_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
|
||||
&devpriv->divisor1,
|
||||
&devpriv->divisor2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
|
||||
}
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
arg = cmd->convert_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
|
||||
&devpriv->divisor1,
|
||||
&devpriv->divisor2,
|
||||
&arg, cmd->flags);
|
||||
comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
|
||||
}
|
||||
|
||||
@ -886,18 +873,6 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cb_pcidas_ai_load_counters(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
unsigned long timer_base = dev->iobase + ADC8254;
|
||||
|
||||
i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
|
||||
|
||||
i8254_write(timer_base, 0, 1, devpriv->divisor1);
|
||||
i8254_write(timer_base, 0, 2, devpriv->divisor2);
|
||||
}
|
||||
|
||||
static int cb_pcidas_ai_cmd(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
@ -933,8 +908,11 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev,
|
||||
outw(bits, devpriv->control_status + ADCMUX_CONT);
|
||||
|
||||
/* load counters */
|
||||
if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER)
|
||||
cb_pcidas_ai_load_counters(dev);
|
||||
if (cmd->scan_begin_src == TRIG_TIMER ||
|
||||
cmd->convert_src == TRIG_TIMER) {
|
||||
comedi_8254_update_divisors(dev->pacer);
|
||||
comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
|
||||
}
|
||||
|
||||
/* enable interrupts */
|
||||
spin_lock_irqsave(&dev->spinlock, flags);
|
||||
@ -1004,7 +982,6 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
|
||||
const struct cb_pcidas_board *thisboard = dev->board_ptr;
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
int err = 0;
|
||||
unsigned int arg;
|
||||
|
||||
/* Step 1 : check if triggers are trivially valid */
|
||||
|
||||
@ -1049,11 +1026,10 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
|
||||
/* step 4: fix up any arguments */
|
||||
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
arg = cmd->scan_begin_arg;
|
||||
i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
|
||||
&devpriv->ao_divisor1,
|
||||
&devpriv->ao_divisor2,
|
||||
&arg, cmd->flags);
|
||||
unsigned int arg = cmd->scan_begin_arg;
|
||||
|
||||
comedi_8254_cascade_ns_to_timer(devpriv->ao_pacer,
|
||||
&arg, cmd->flags);
|
||||
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
|
||||
}
|
||||
|
||||
@ -1139,18 +1115,6 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cb_pcidas_ao_load_counters(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
unsigned long timer_base = dev->iobase + DAC8254;
|
||||
|
||||
i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
|
||||
i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
|
||||
|
||||
i8254_write(timer_base, 0, 1, devpriv->ao_divisor1);
|
||||
i8254_write(timer_base, 0, 2, devpriv->ao_divisor2);
|
||||
}
|
||||
|
||||
static int cb_pcidas_ao_cmd(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s)
|
||||
{
|
||||
@ -1180,8 +1144,10 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev,
|
||||
outw(0, devpriv->ao_registers + DACFIFOCLR);
|
||||
|
||||
/* load counters */
|
||||
if (cmd->scan_begin_src == TRIG_TIMER)
|
||||
cb_pcidas_ao_load_counters(dev);
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
comedi_8254_update_divisors(devpriv->ao_pacer);
|
||||
comedi_8254_pacer_enable(devpriv->ao_pacer, 1, 2, true);
|
||||
}
|
||||
|
||||
/* set pacer source */
|
||||
spin_lock_irqsave(&dev->spinlock, flags);
|
||||
@ -1408,6 +1374,17 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
|
||||
}
|
||||
dev->irq = pcidev->irq;
|
||||
|
||||
dev->pacer = comedi_8254_init(dev->iobase + ADC8254,
|
||||
I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
devpriv->ao_pacer = comedi_8254_init(dev->iobase + DAC8254,
|
||||
I8254_OSC_BASE_10MHZ,
|
||||
I8254_IO8, 0);
|
||||
if (!devpriv->ao_pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 7);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1530,8 +1507,9 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
|
||||
dac08_write(dev, s->maxdata / 2);
|
||||
s->readback[i] = s->maxdata / 2;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* make sure mailbox 4 is empty */
|
||||
inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
|
||||
@ -1550,9 +1528,11 @@ static void cb_pcidas_detach(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcidas_private *devpriv = dev->private;
|
||||
|
||||
if (devpriv && devpriv->s5933_config) {
|
||||
outl(INTCSR_INBOX_INTR_STATUS,
|
||||
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
|
||||
if (devpriv) {
|
||||
if (devpriv->s5933_config)
|
||||
outl(INTCSR_INBOX_INTR_STATUS,
|
||||
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
|
||||
kfree(devpriv->ao_pacer);
|
||||
}
|
||||
comedi_pci_detach(dev);
|
||||
}
|
||||
|
@ -81,13 +81,11 @@ TODO:
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8253.h"
|
||||
#include "8255.h"
|
||||
#include "plx9080.h"
|
||||
#include "comedi_fc.h"
|
||||
@ -1474,9 +1472,8 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
|
||||
devpriv->ai_buffer[i] =
|
||||
pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
|
||||
&devpriv->ai_buffer_bus_addr[i]);
|
||||
if (devpriv->ai_buffer[i] == NULL)
|
||||
if (!devpriv->ai_buffer[i])
|
||||
return -ENOMEM;
|
||||
|
||||
}
|
||||
for (i = 0; i < AO_DMA_RING_COUNT; i++) {
|
||||
if (ao_cmd_is_supported(thisboard)) {
|
||||
@ -1484,9 +1481,8 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
|
||||
pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
|
||||
&devpriv->
|
||||
ao_buffer_bus_addr[i]);
|
||||
if (devpriv->ao_buffer[i] == NULL)
|
||||
if (!devpriv->ao_buffer[i])
|
||||
return -ENOMEM;
|
||||
|
||||
}
|
||||
}
|
||||
/* allocate dma descriptors */
|
||||
@ -1494,7 +1490,7 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
|
||||
pci_alloc_consistent(pcidev, sizeof(struct plx_dma_desc) *
|
||||
ai_dma_ring_count(thisboard),
|
||||
&devpriv->ai_dma_desc_bus_addr);
|
||||
if (devpriv->ai_dma_desc == NULL)
|
||||
if (!devpriv->ai_dma_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ao_cmd_is_supported(thisboard)) {
|
||||
@ -1503,7 +1499,7 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
|
||||
sizeof(struct plx_dma_desc) *
|
||||
AO_DMA_RING_COUNT,
|
||||
&devpriv->ao_dma_desc_bus_addr);
|
||||
if (devpriv->ao_dma_desc == NULL)
|
||||
if (!devpriv->ao_dma_desc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* initialize dma descriptors */
|
||||
@ -1704,8 +1700,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
|
||||
|
||||
/* get acknowledge */
|
||||
if (i2c_read_ack(dev) != 0) {
|
||||
dev_err(dev->class_dev, "%s failed: no acknowledge\n",
|
||||
__func__);
|
||||
dev_err(dev->class_dev, "failed: no acknowledge\n");
|
||||
i2c_stop(dev);
|
||||
return;
|
||||
}
|
||||
@ -1713,8 +1708,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
|
||||
for (i = 0; i < length; i++) {
|
||||
i2c_write_byte(dev, data[i]);
|
||||
if (i2c_read_ack(dev) != 0) {
|
||||
dev_err(dev->class_dev, "%s failed: no acknowledge\n",
|
||||
__func__);
|
||||
dev_err(dev->class_dev, "failed: no acknowledge\n");
|
||||
i2c_stop(dev);
|
||||
return;
|
||||
}
|
||||
@ -1841,7 +1835,6 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
}
|
||||
|
||||
for (n = 0; n < insn->n; n++) {
|
||||
|
||||
/* clear adc buffer (inside loop for 4020 sake) */
|
||||
writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG);
|
||||
|
||||
@ -1903,7 +1896,6 @@ static int ai_config_block_size(struct comedi_device *dev, unsigned int *data)
|
||||
retval = set_ai_fifo_size(dev, fifo_size);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
block_size = ai_fifo_size(dev) / fifo->num_segments * bytes_in_sample;
|
||||
@ -2001,7 +1993,8 @@ static unsigned int get_divisor(unsigned int ns, unsigned int flags)
|
||||
static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
|
||||
{
|
||||
const struct pcidas64_board *thisboard = dev->board_ptr;
|
||||
unsigned int convert_divisor = 0, scan_divisor;
|
||||
unsigned long long convert_divisor = 0;
|
||||
unsigned int scan_divisor;
|
||||
static const int min_convert_divisor = 3;
|
||||
static const int max_convert_divisor =
|
||||
max_counter_value + min_convert_divisor;
|
||||
@ -2027,7 +2020,6 @@ static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd)
|
||||
if (cmd->scan_begin_src == TRIG_TIMER) {
|
||||
scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags);
|
||||
if (cmd->convert_src == TRIG_TIMER) {
|
||||
/* XXX check for integer overflows */
|
||||
min_scan_divisor = convert_divisor * cmd->chanlist_len;
|
||||
max_scan_divisor =
|
||||
(convert_divisor * cmd->chanlist_len - 1) +
|
||||
@ -2637,8 +2629,9 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
|
||||
bits |= ADC_START_TRIG_EXT_BITS;
|
||||
if (cmd->start_arg & CR_INVERT)
|
||||
bits |= ADC_START_TRIG_FALLING_BIT;
|
||||
} else if (cmd->start_src == TRIG_NOW)
|
||||
} else if (cmd->start_src == TRIG_NOW) {
|
||||
bits |= ADC_START_TRIG_SOFT_BITS;
|
||||
}
|
||||
if (use_hw_sample_counter(cmd))
|
||||
bits |= ADC_SAMPLE_COUNTER_EN_BIT;
|
||||
writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG);
|
||||
@ -2827,8 +2820,9 @@ static void handle_ai_interrupt(struct comedi_device *dev,
|
||||
if (devpriv->ai_cmd_running) {
|
||||
spin_unlock_irqrestore(&dev->spinlock, flags);
|
||||
pio_drain_ai_fifo(dev);
|
||||
} else
|
||||
} else {
|
||||
spin_unlock_irqrestore(&dev->spinlock, flags);
|
||||
}
|
||||
}
|
||||
/* if we are have all the data, then quit */
|
||||
if ((cmd->stop_src == TRIG_COUNT &&
|
||||
@ -2978,7 +2972,7 @@ static void handle_ao_interrupt(struct comedi_device *dev,
|
||||
unsigned long flags;
|
||||
|
||||
/* board might not support ao, in which case write_subdev is NULL */
|
||||
if (s == NULL)
|
||||
if (!s)
|
||||
return;
|
||||
async = s->async;
|
||||
cmd = &async->cmd;
|
||||
@ -3817,8 +3811,9 @@ static int setup_subdevices(struct comedi_device *dev)
|
||||
s->maxdata = 1;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_bits = di_rbits;
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* digital output */
|
||||
if (thisboard->layout == LAYOUT_64XX) {
|
||||
@ -3829,8 +3824,9 @@ static int setup_subdevices(struct comedi_device *dev)
|
||||
s->maxdata = 1;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_bits = do_wbits;
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* 8255 */
|
||||
s = &dev->subdevices[4];
|
||||
@ -3858,8 +3854,9 @@ static int setup_subdevices(struct comedi_device *dev)
|
||||
s->range_table = &range_digital;
|
||||
s->insn_config = dio_60xx_config_insn;
|
||||
s->insn_bits = dio_60xx_wbits;
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* caldac */
|
||||
s = &dev->subdevices[6];
|
||||
@ -3898,8 +3895,9 @@ static int setup_subdevices(struct comedi_device *dev)
|
||||
ad8402_write(dev, i, s->maxdata / 2);
|
||||
s->readback[i] = s->maxdata / 2;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* serial EEPROM, if present */
|
||||
s = &dev->subdevices[8];
|
||||
@ -3909,8 +3907,9 @@ static int setup_subdevices(struct comedi_device *dev)
|
||||
s->n_chan = 128;
|
||||
s->maxdata = 0xffff;
|
||||
s->insn_read = eeprom_read_insn;
|
||||
} else
|
||||
} else {
|
||||
s->type = COMEDI_SUBD_UNUSED;
|
||||
}
|
||||
|
||||
/* user counter subd XXX */
|
||||
s = &dev->subdevices[9];
|
||||
|
@ -36,9 +36,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_fc.h"
|
||||
#include "8255.h"
|
||||
|
@ -42,37 +42,112 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "comedi_8254.h"
|
||||
#include "plx9052.h"
|
||||
#include "8255.h"
|
||||
|
||||
/* Registers for the PCIM-DAS1602/16 and PCIe-DAS1602/16 */
|
||||
/*
|
||||
* PCI Bar 1 Register map
|
||||
* see plx9052.h for register and bit defines
|
||||
*/
|
||||
|
||||
/* DAC Offsets */
|
||||
#define ADC_TRIG 0
|
||||
#define DAC0_OFFSET 2
|
||||
#define DAC1_OFFSET 4
|
||||
/*
|
||||
* PCI Bar 2 Register map (devpriv->daqio)
|
||||
*/
|
||||
#define PCIMDAS_AI_REG 0x00
|
||||
#define PCIMDAS_AI_SOFTTRIG_REG 0x00
|
||||
#define PCIMDAS_AO_REG(x) (0x02 + ((x) * 2))
|
||||
|
||||
/* AI and Counter Constants */
|
||||
#define MUX_LIMITS 0
|
||||
#define MAIN_CONN_DIO 1
|
||||
#define ADC_STAT 2
|
||||
#define ADC_CONV_STAT 3
|
||||
#define ADC_INT 4
|
||||
#define ADC_PACER 5
|
||||
#define BURST_MODE 6
|
||||
#define PROG_GAIN 7
|
||||
#define CLK8254_1_DATA 8
|
||||
#define CLK8254_2_DATA 9
|
||||
#define CLK8254_3_DATA 10
|
||||
#define CLK8254_CONTROL 11
|
||||
#define USER_COUNTER 12
|
||||
#define RESID_COUNT_H 13
|
||||
#define RESID_COUNT_L 14
|
||||
/*
|
||||
* PCI Bar 3 Register map (devpriv->BADR3)
|
||||
*/
|
||||
#define PCIMDAS_MUX_REG 0x00
|
||||
#define PCIMDAS_MUX(_lo, _hi) ((_lo) | ((_hi) << 4))
|
||||
#define PCIMDAS_DI_DO_REG 0x01
|
||||
#define PCIMDAS_STATUS_REG 0x02
|
||||
#define PCIMDAS_STATUS_EOC BIT(7)
|
||||
#define PCIMDAS_STATUS_UB BIT(6)
|
||||
#define PCIMDAS_STATUS_MUX BIT(5)
|
||||
#define PCIMDAS_STATUS_CLK BIT(4)
|
||||
#define PCIMDAS_STATUS_TO_CURR_MUX(x) ((x) & 0xf)
|
||||
#define PCIMDAS_CONV_STATUS_REG 0x03
|
||||
#define PCIMDAS_CONV_STATUS_EOC BIT(7)
|
||||
#define PCIMDAS_CONV_STATUS_EOB BIT(6)
|
||||
#define PCIMDAS_CONV_STATUS_EOA BIT(5)
|
||||
#define PCIMDAS_CONV_STATUS_FNE BIT(4)
|
||||
#define PCIMDAS_CONV_STATUS_FHF BIT(3)
|
||||
#define PCIMDAS_CONV_STATUS_OVERRUN BIT(2)
|
||||
#define PCIMDAS_IRQ_REG 0x04
|
||||
#define PCIMDAS_IRQ_INTE BIT(7)
|
||||
#define PCIMDAS_IRQ_INT BIT(6)
|
||||
#define PCIMDAS_IRQ_OVERRUN BIT(4)
|
||||
#define PCIMDAS_IRQ_EOA BIT(3)
|
||||
#define PCIMDAS_IRQ_EOA_INT_SEL BIT(2)
|
||||
#define PCIMDAS_IRQ_INTSEL(x) ((x) << 0)
|
||||
#define PCIMDAS_IRQ_INTSEL_EOC PCIMDAS_IRQ_INTSEL(0)
|
||||
#define PCIMDAS_IRQ_INTSEL_FNE PCIMDAS_IRQ_INTSEL(1)
|
||||
#define PCIMDAS_IRQ_INTSEL_EOB PCIMDAS_IRQ_INTSEL(2)
|
||||
#define PCIMDAS_IRQ_INTSEL_FHF_EOA PCIMDAS_IRQ_INTSEL(3)
|
||||
#define PCIMDAS_PACER_REG 0x05
|
||||
#define PCIMDAS_PACER_GATE_STATUS BIT(6)
|
||||
#define PCIMDAS_PACER_GATE_POL BIT(5)
|
||||
#define PCIMDAS_PACER_GATE_LATCH BIT(4)
|
||||
#define PCIMDAS_PACER_GATE_EN BIT(3)
|
||||
#define PCIMDAS_PACER_EXT_PACER_POL BIT(2)
|
||||
#define PCIMDAS_PACER_SRC(x) ((x) << 0)
|
||||
#define PCIMDAS_PACER_SRC_POLLED PCIMDAS_PACER_SRC(0)
|
||||
#define PCIMDAS_PACER_SRC_EXT PCIMDAS_PACER_SRC(2)
|
||||
#define PCIMDAS_PACER_SRC_INT PCIMDAS_PACER_SRC(3)
|
||||
#define PCIMDAS_PACER_SRC_MASK (3 << 0)
|
||||
#define PCIMDAS_BURST_REG 0x06
|
||||
#define PCIMDAS_BURST_BME BIT(1)
|
||||
#define PCIMDAS_BURST_CONV_EN BIT(0)
|
||||
#define PCIMDAS_GAIN_REG 0x07
|
||||
#define PCIMDAS_8254_BASE 0x08
|
||||
#define PCIMDAS_USER_CNTR_REG 0x0c
|
||||
#define PCIMDAS_USER_CNTR_CTR1_CLK_SEL BIT(0)
|
||||
#define PCIMDAS_RESIDUE_MSB_REG 0x0d
|
||||
#define PCIMDAS_RESIDUE_LSB_REG 0x0e
|
||||
|
||||
/*
|
||||
* PCI Bar 4 Register map (dev->iobase)
|
||||
*/
|
||||
#define PCIMDAS_8255_BASE 0x00
|
||||
|
||||
static const struct comedi_lrange cb_pcimdas_ai_bip_range = {
|
||||
4, {
|
||||
BIP_RANGE(10),
|
||||
BIP_RANGE(5),
|
||||
BIP_RANGE(2.5),
|
||||
BIP_RANGE(1.25)
|
||||
}
|
||||
};
|
||||
|
||||
static const struct comedi_lrange cb_pcimdas_ai_uni_range = {
|
||||
4, {
|
||||
UNI_RANGE(10),
|
||||
UNI_RANGE(5),
|
||||
UNI_RANGE(2.5),
|
||||
UNI_RANGE(1.25)
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The Analog Output range is not programmable. The DAC ranges are
|
||||
* jumper-settable on the board. The settings are not software-readable.
|
||||
*/
|
||||
static const struct comedi_lrange cb_pcimdas_ao_range = {
|
||||
4, {
|
||||
BIP_RANGE(10),
|
||||
BIP_RANGE(5),
|
||||
UNI_RANGE(10),
|
||||
UNI_RANGE(5)
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* this structure is for data unique to this hardware driver. If
|
||||
@ -94,59 +169,47 @@ static int cb_pcimdas_ai_eoc(struct comedi_device *dev,
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int status;
|
||||
|
||||
status = inb(devpriv->BADR3 + 2);
|
||||
if ((status & 0x80) == 0)
|
||||
status = inb(devpriv->BADR3 + PCIMDAS_STATUS_REG);
|
||||
if ((status & PCIMDAS_STATUS_EOC) == 0)
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data)
|
||||
static int cb_pcimdas_ai_insn_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int range = CR_RANGE(insn->chanspec);
|
||||
int n;
|
||||
unsigned int d;
|
||||
int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned short chanlims;
|
||||
int maxchans;
|
||||
int ret;
|
||||
|
||||
/* only support sw initiated reads from a single channel */
|
||||
|
||||
/* check channel number */
|
||||
if ((inb(devpriv->BADR3 + 2) & 0x20) == 0) /* differential mode */
|
||||
maxchans = s->n_chan / 2;
|
||||
else
|
||||
maxchans = s->n_chan;
|
||||
|
||||
if (chan > (maxchans - 1))
|
||||
return -ETIMEDOUT; /* *** Wrong error code. Fixme. */
|
||||
|
||||
/* configure for sw initiated read */
|
||||
d = inb(devpriv->BADR3 + 5);
|
||||
if ((d & 0x03) > 0) { /* only reset if needed. */
|
||||
d = d & 0xfd;
|
||||
outb(d, devpriv->BADR3 + 5);
|
||||
d = inb(devpriv->BADR3 + PCIMDAS_PACER_REG);
|
||||
if ((d & PCIMDAS_PACER_SRC_MASK) != PCIMDAS_PACER_SRC_POLLED) {
|
||||
d &= ~PCIMDAS_PACER_SRC_MASK;
|
||||
d |= PCIMDAS_PACER_SRC_POLLED;
|
||||
outb(d, devpriv->BADR3 + PCIMDAS_PACER_REG);
|
||||
}
|
||||
|
||||
/* set bursting off, conversions on */
|
||||
outb(0x01, devpriv->BADR3 + 6);
|
||||
outb(PCIMDAS_BURST_CONV_EN, devpriv->BADR3 + PCIMDAS_BURST_REG);
|
||||
|
||||
/* set range to 10V. UP/BP is controlled by a switch on the board */
|
||||
outb(0x00, devpriv->BADR3 + 7);
|
||||
/* set range */
|
||||
outb(range, devpriv->BADR3 + PCIMDAS_GAIN_REG);
|
||||
|
||||
/*
|
||||
* write channel limits to multiplexer, set Low (bits 0-3) and
|
||||
* High (bits 4-7) channels to chan.
|
||||
*/
|
||||
chanlims = chan | (chan << 4);
|
||||
outb(chanlims, devpriv->BADR3 + 0);
|
||||
/* set mux for single channel scan */
|
||||
outb(PCIMDAS_MUX(chan, chan), devpriv->BADR3 + PCIMDAS_MUX_REG);
|
||||
|
||||
/* convert n samples */
|
||||
for (n = 0; n < insn->n; n++) {
|
||||
/* trigger conversion */
|
||||
outw(0, devpriv->daqio + 0);
|
||||
outw(0, devpriv->daqio + PCIMDAS_AI_SOFTTRIG_REG);
|
||||
|
||||
/* wait for conversion to end */
|
||||
ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0);
|
||||
@ -154,7 +217,7 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
|
||||
return ret;
|
||||
|
||||
/* read data */
|
||||
data[n] = inw(devpriv->daqio + 0);
|
||||
data[n] = inw(devpriv->daqio + PCIMDAS_AI_REG);
|
||||
}
|
||||
|
||||
/* return the number of samples read/written */
|
||||
@ -169,20 +232,128 @@ static int cb_pcimdas_ao_insn_write(struct comedi_device *dev,
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
unsigned int val = s->readback[chan];
|
||||
unsigned int reg = (chan) ? DAC1_OFFSET : DAC0_OFFSET;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < insn->n; i++) {
|
||||
val = data[i];
|
||||
outw(val, devpriv->daqio + reg);
|
||||
outw(val, devpriv->daqio + PCIMDAS_AO_REG(chan));
|
||||
}
|
||||
s->readback[chan] = val;
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int cb_pcimdas_di_insn_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int val;
|
||||
|
||||
val = inb(devpriv->BADR3 + PCIMDAS_DI_DO_REG);
|
||||
|
||||
data[1] = val & 0x0f;
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int cb_pcimdas_do_insn_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
|
||||
if (comedi_dio_update_state(s, data))
|
||||
outb(s->state, devpriv->BADR3 + PCIMDAS_DI_DO_REG);
|
||||
|
||||
data[1] = s->state;
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int cb_pcimdas_counter_insn_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int ctrl;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_SET_CLOCK_SRC:
|
||||
switch (data[1]) {
|
||||
case 0: /* internal 100 kHz clock */
|
||||
ctrl = PCIMDAS_USER_CNTR_CTR1_CLK_SEL;
|
||||
break;
|
||||
case 1: /* external clk on pin 21 */
|
||||
ctrl = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
outb(ctrl, devpriv->BADR3 + PCIMDAS_USER_CNTR_REG);
|
||||
break;
|
||||
case INSN_CONFIG_GET_CLOCK_SRC:
|
||||
ctrl = inb(devpriv->BADR3 + PCIMDAS_USER_CNTR_REG);
|
||||
if (ctrl & PCIMDAS_USER_CNTR_CTR1_CLK_SEL) {
|
||||
data[1] = 0;
|
||||
data[2] = I8254_OSC_BASE_100KHZ;
|
||||
} else {
|
||||
data[1] = 1;
|
||||
data[2] = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static unsigned int cb_pcimdas_pacer_clk(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int status;
|
||||
|
||||
/* The Pacer Clock jumper selects a 10 MHz or 1 MHz clock */
|
||||
status = inb(devpriv->BADR3 + PCIMDAS_STATUS_REG);
|
||||
if (status & PCIMDAS_STATUS_CLK)
|
||||
return I8254_OSC_BASE_10MHZ;
|
||||
return I8254_OSC_BASE_1MHZ;
|
||||
}
|
||||
|
||||
static bool cb_pcimdas_is_ai_se(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int status;
|
||||
|
||||
/*
|
||||
* The number of Analog Input channels is set with the
|
||||
* Analog Input Mode Switch on the board. The board can
|
||||
* have 16 single-ended or 8 differential channels.
|
||||
*/
|
||||
status = inb(devpriv->BADR3 + PCIMDAS_STATUS_REG);
|
||||
return status & PCIMDAS_STATUS_MUX;
|
||||
}
|
||||
|
||||
static bool cb_pcimdas_is_ai_uni(struct comedi_device *dev)
|
||||
{
|
||||
struct cb_pcimdas_private *devpriv = dev->private;
|
||||
unsigned int status;
|
||||
|
||||
/*
|
||||
* The Analog Input range polarity is set with the
|
||||
* Analog Input Polarity Switch on the board. The
|
||||
* inputs can be set to Unipolar or Bipolar ranges.
|
||||
*/
|
||||
status = inb(devpriv->BADR3 + PCIMDAS_STATUS_REG);
|
||||
return status & PCIMDAS_STATUS_UB;
|
||||
}
|
||||
|
||||
static int cb_pcimdas_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct cb_pcimdas_private *devpriv;
|
||||
@ -201,42 +372,79 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
|
||||
devpriv->BADR3 = pci_resource_start(pcidev, 3);
|
||||
dev->iobase = pci_resource_start(pcidev, 4);
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 3);
|
||||
dev->pacer = comedi_8254_init(devpriv->BADR3 + PCIMDAS_8254_BASE,
|
||||
cb_pcimdas_pacer_clk(dev),
|
||||
I8254_IO8, 0);
|
||||
if (!dev->pacer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = comedi_alloc_subdevices(dev, 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Analog Input subdevice */
|
||||
s = &dev->subdevices[0];
|
||||
/* dev->read_subdev=s; */
|
||||
/* analog input subdevice */
|
||||
s->type = COMEDI_SUBD_AI;
|
||||
s->subdev_flags = SDF_READABLE | SDF_GROUND;
|
||||
s->n_chan = 16;
|
||||
s->maxdata = 0xffff;
|
||||
s->range_table = &range_unknown;
|
||||
s->len_chanlist = 1; /* This is the maximum chanlist length that */
|
||||
/* the board can handle */
|
||||
s->insn_read = cb_pcimdas_ai_rinsn;
|
||||
s->type = COMEDI_SUBD_AI;
|
||||
s->subdev_flags = SDF_READABLE;
|
||||
if (cb_pcimdas_is_ai_se(dev)) {
|
||||
s->subdev_flags |= SDF_GROUND;
|
||||
s->n_chan = 16;
|
||||
} else {
|
||||
s->subdev_flags |= SDF_DIFF;
|
||||
s->n_chan = 8;
|
||||
}
|
||||
s->maxdata = 0xffff;
|
||||
s->range_table = cb_pcimdas_is_ai_uni(dev) ? &cb_pcimdas_ai_uni_range
|
||||
: &cb_pcimdas_ai_bip_range;
|
||||
s->insn_read = cb_pcimdas_ai_insn_read;
|
||||
|
||||
/* Analog Output subdevice */
|
||||
s = &dev->subdevices[1];
|
||||
/* analog output subdevice */
|
||||
s->type = COMEDI_SUBD_AO;
|
||||
s->subdev_flags = SDF_WRITABLE;
|
||||
s->n_chan = 2;
|
||||
s->maxdata = 0xfff;
|
||||
/* ranges are hardware settable, but not software readable. */
|
||||
s->range_table = &range_unknown;
|
||||
s->insn_write = cb_pcimdas_ao_insn_write;
|
||||
s->type = COMEDI_SUBD_AO;
|
||||
s->subdev_flags = SDF_WRITABLE;
|
||||
s->n_chan = 2;
|
||||
s->maxdata = 0xfff;
|
||||
s->range_table = &cb_pcimdas_ao_range;
|
||||
s->insn_write = cb_pcimdas_ao_insn_write;
|
||||
|
||||
ret = comedi_alloc_subdev_readback(s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Digital I/O subdevice */
|
||||
s = &dev->subdevices[2];
|
||||
/* digital i/o subdevice */
|
||||
ret = subdev_8255_init(dev, s, NULL, 0x00);
|
||||
ret = subdev_8255_init(dev, s, NULL, PCIMDAS_8255_BASE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Digital Input subdevice (main connector) */
|
||||
s = &dev->subdevices[3];
|
||||
s->type = COMEDI_SUBD_DI;
|
||||
s->subdev_flags = SDF_READABLE;
|
||||
s->n_chan = 4;
|
||||
s->maxdata = 1;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_read = cb_pcimdas_di_insn_read;
|
||||
|
||||
/* Digital Output subdevice (main connector) */
|
||||
s = &dev->subdevices[4];
|
||||
s->type = COMEDI_SUBD_DO;
|
||||
s->subdev_flags = SDF_WRITABLE;
|
||||
s->n_chan = 4;
|
||||
s->maxdata = 1;
|
||||
s->range_table = &range_digital;
|
||||
s->insn_write = cb_pcimdas_do_insn_write;
|
||||
|
||||
/* Counter subdevice (8254) */
|
||||
s = &dev->subdevices[5];
|
||||
comedi_8254_subdevice_init(s, dev->pacer);
|
||||
|
||||
dev->pacer->insn_config = cb_pcimdas_counter_insn_config;
|
||||
|
||||
/* counters 1 and 2 are used internally for the pacer */
|
||||
comedi_8254_set_busy(dev->pacer, 1, true);
|
||||
comedi_8254_set_busy(dev->pacer, 2, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -75,9 +75,8 @@ Configuration Options: not applicable, uses PCI auto config
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8255.h"
|
||||
|
||||
@ -134,7 +133,7 @@ static int cb_pcimdda_ao_insn_read(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int cb_pcimdda_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct comedi_subdevice *s;
|
||||
|
664
drivers/staging/comedi/drivers/comedi_8254.c
Normal file
664
drivers/staging/comedi/drivers/comedi_8254.c
Normal file
@ -0,0 +1,664 @@
|
||||
/*
|
||||
* comedi_8254.c
|
||||
* Generic 8254 timer/counter support
|
||||
* Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
*
|
||||
* Based on 8253.h and various subdevice implementations in comedi drivers.
|
||||
*
|
||||
* COMEDI - Linux Control and Measurement Device Interface
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Module: comedi_8254
|
||||
* Description: Generic 8254 timer/counter support
|
||||
* Author: H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
* Updated: Thu Jan 8 16:45:45 MST 2015
|
||||
* Status: works
|
||||
*
|
||||
* This module is not used directly by end-users. Rather, it is used by other
|
||||
* drivers to provide support for an 8254 Programmable Interval Timer. These
|
||||
* counters are typically used to generate the pacer clock used for data
|
||||
* acquisition. Some drivers also expose the counters for general purpose use.
|
||||
*
|
||||
* This module provides the following basic functions:
|
||||
*
|
||||
* comedi_8254_init() / comedi_8254_mm_init()
|
||||
* Initializes this module to access the 8254 registers. The _mm version
|
||||
* sets up the module for MMIO register access the other for PIO access.
|
||||
* The pointer returned from these functions is normally stored in the
|
||||
* comedi_device dev->pacer and will be freed by the comedi core during
|
||||
* the driver (*detach). If a driver has multiple 8254 devices, they need
|
||||
* to be stored in the drivers private data and freed when the driver is
|
||||
* detached.
|
||||
*
|
||||
* NOTE: The counters are reset by setting them to I8254_MODE0 as part of
|
||||
* this initialization.
|
||||
*
|
||||
* comedi_8254_set_mode()
|
||||
* Sets a counters operation mode:
|
||||
* I8254_MODE0 Interrupt on terminal count
|
||||
* I8254_MODE1 Hardware retriggerable one-shot
|
||||
* I8254_MODE2 Rate generator
|
||||
* I8254_MODE3 Square wave mode
|
||||
* I8254_MODE4 Software triggered strobe
|
||||
* I8254_MODE5 Hardware triggered strobe (retriggerable)
|
||||
*
|
||||
* In addition I8254_BCD and I8254_BINARY specify the counting mode:
|
||||
* I8254_BCD BCD counting
|
||||
* I8254_BINARY Binary counting
|
||||
*
|
||||
* comedi_8254_write()
|
||||
* Writes an initial value to a counter.
|
||||
*
|
||||
* The largest possible initial count is 0; this is equivalent to 2^16
|
||||
* for binary counting and 10^4 for BCD counting.
|
||||
*
|
||||
* NOTE: The counter does not stop when it reaches zero. In Mode 0, 1, 4,
|
||||
* and 5 the counter "wraps around" to the highest count, either 0xffff
|
||||
* for binary counting or 9999 for BCD counting, and continues counting.
|
||||
* Modes 2 and 3 are periodic; the counter reloads itself with the initial
|
||||
* count and continues counting from there.
|
||||
*
|
||||
* comedi_8254_read()
|
||||
* Reads the current value from a counter.
|
||||
*
|
||||
* comedi_8254_status()
|
||||
* Reads the status of a counter.
|
||||
*
|
||||
* comedi_8254_load()
|
||||
* Sets a counters operation mode and writes the initial value.
|
||||
*
|
||||
* Typically the pacer clock is created by cascading two of the 16-bit counters
|
||||
* to create a 32-bit rate generator (I8254_MODE2). These functions are
|
||||
* provided to handle the cascaded counters:
|
||||
*
|
||||
* comedi_8254_ns_to_timer()
|
||||
* Calculates the divisor value needed for a single counter to generate
|
||||
* ns timing.
|
||||
*
|
||||
* comedi_8254_cascade_ns_to_timer()
|
||||
* Calculates the two divisor values needed to the generate the pacer
|
||||
* clock (in ns).
|
||||
*
|
||||
* comedi_8254_update_divisors()
|
||||
* Transfers the intermediate divisor values to the current divisors.
|
||||
*
|
||||
* comedi_8254_pacer_enable()
|
||||
* Programs the mode of the cascaded counters and writes the current
|
||||
* divisor values.
|
||||
*
|
||||
* To expose the counters as a subdevice for general purpose use the following
|
||||
* functions a provided:
|
||||
*
|
||||
* comedi_8254_subdevice_init()
|
||||
* Initializes a comedi_subdevice to use the 8254 timer.
|
||||
*
|
||||
* comedi_8254_set_busy()
|
||||
* Internally flags a counter as "busy". This is done to protect the
|
||||
* counters that are used for the cascaded 32-bit pacer.
|
||||
*
|
||||
* The subdevice provides (*insn_read) and (*insn_write) operations to read
|
||||
* the current value and write an initial value to a counter. A (*insn_config)
|
||||
* operation is also provided to handle the following comedi instructions:
|
||||
*
|
||||
* INSN_CONFIG_SET_COUNTER_MODE calls comedi_8254_set_mode()
|
||||
* INSN_CONFIG_8254_READ_STATUS calls comedi_8254_status()
|
||||
*
|
||||
* The (*insn_config) member of comedi_8254 can be initialized by the external
|
||||
* driver to handle any additional instructions.
|
||||
*
|
||||
* NOTE: Gate control, clock routing, and any interrupt handling for the
|
||||
* counters is not handled by this module. These features are driver dependent.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
|
||||
#include "comedi_8254.h"
|
||||
|
||||
static unsigned int __i8254_read(struct comedi_8254 *i8254, unsigned int reg)
|
||||
{
|
||||
unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
|
||||
unsigned int val;
|
||||
|
||||
switch (i8254->iosize) {
|
||||
default:
|
||||
case I8254_IO8:
|
||||
if (i8254->mmio)
|
||||
val = readb(i8254->mmio + reg_offset);
|
||||
else
|
||||
val = inb(i8254->iobase + reg_offset);
|
||||
break;
|
||||
case I8254_IO16:
|
||||
if (i8254->mmio)
|
||||
val = readw(i8254->mmio + reg_offset);
|
||||
else
|
||||
val = inw(i8254->iobase + reg_offset);
|
||||
break;
|
||||
case I8254_IO32:
|
||||
if (i8254->mmio)
|
||||
val = readl(i8254->mmio + reg_offset);
|
||||
else
|
||||
val = inl(i8254->iobase + reg_offset);
|
||||
break;
|
||||
}
|
||||
return val & 0xff;
|
||||
}
|
||||
|
||||
static void __i8254_write(struct comedi_8254 *i8254,
|
||||
unsigned int val, unsigned int reg)
|
||||
{
|
||||
unsigned int reg_offset = (reg * i8254->iosize) << i8254->regshift;
|
||||
|
||||
switch (i8254->iosize) {
|
||||
default:
|
||||
case I8254_IO8:
|
||||
if (i8254->mmio)
|
||||
writeb(val, i8254->mmio + reg_offset);
|
||||
else
|
||||
outb(val, i8254->iobase + reg_offset);
|
||||
break;
|
||||
case I8254_IO16:
|
||||
if (i8254->mmio)
|
||||
writew(val, i8254->mmio + reg_offset);
|
||||
else
|
||||
outw(val, i8254->iobase + reg_offset);
|
||||
break;
|
||||
case I8254_IO32:
|
||||
if (i8254->mmio)
|
||||
writel(val, i8254->mmio + reg_offset);
|
||||
else
|
||||
outl(val, i8254->iobase + reg_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* comedi_8254_status - return the status of a counter
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
*/
|
||||
unsigned int comedi_8254_status(struct comedi_8254 *i8254, unsigned int counter)
|
||||
{
|
||||
unsigned int cmd;
|
||||
|
||||
if (counter > 2)
|
||||
return 0;
|
||||
|
||||
cmd = I8254_CTRL_READBACK_STATUS | I8254_CTRL_READBACK_SEL_CTR(counter);
|
||||
__i8254_write(i8254, cmd, I8254_CTRL_REG);
|
||||
|
||||
return __i8254_read(i8254, counter);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_status);
|
||||
|
||||
/**
|
||||
* comedi_8254_read - read the current counter value
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
*/
|
||||
unsigned int comedi_8254_read(struct comedi_8254 *i8254, unsigned int counter)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (counter > 2)
|
||||
return 0;
|
||||
|
||||
/* latch counter */
|
||||
__i8254_write(i8254, I8254_CTRL_SEL_CTR(counter) | I8254_CTRL_LATCH,
|
||||
I8254_CTRL_REG);
|
||||
|
||||
/* read LSB then MSB */
|
||||
val = __i8254_read(i8254, counter);
|
||||
val |= (__i8254_read(i8254, counter) << 8);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_read);
|
||||
|
||||
/**
|
||||
* comedi_8254_write - load a 16-bit initial counter value
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
* @val: the initial value
|
||||
*/
|
||||
void comedi_8254_write(struct comedi_8254 *i8254,
|
||||
unsigned int counter, unsigned int val)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter > 2)
|
||||
return;
|
||||
if (val > 0xffff)
|
||||
return;
|
||||
|
||||
/* load LSB then MSB */
|
||||
byte = val & 0xff;
|
||||
__i8254_write(i8254, byte, counter);
|
||||
byte = (val >> 8) & 0xff;
|
||||
__i8254_write(i8254, byte, counter);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_write);
|
||||
|
||||
/**
|
||||
* comedi_8254_set_mode - set the mode of a counter
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
* @mode: the I8254_MODEx and I8254_BCD|I8254_BINARY
|
||||
*/
|
||||
int comedi_8254_set_mode(struct comedi_8254 *i8254, unsigned int counter,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned int byte;
|
||||
|
||||
if (counter > 2)
|
||||
return -EINVAL;
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -EINVAL;
|
||||
|
||||
byte = I8254_CTRL_SEL_CTR(counter) | /* select counter */
|
||||
I8254_CTRL_LSB_MSB | /* load LSB then MSB */
|
||||
mode; /* mode and BCD|binary */
|
||||
__i8254_write(i8254, byte, I8254_CTRL_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_set_mode);
|
||||
|
||||
/**
|
||||
* comedi_8254_load - program the mode and initial count of a counter
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
* @mode: the I8254_MODEx and I8254_BCD|I8254_BINARY
|
||||
* @val: the initial value
|
||||
*/
|
||||
int comedi_8254_load(struct comedi_8254 *i8254, unsigned int counter,
|
||||
unsigned int val, unsigned int mode)
|
||||
{
|
||||
if (counter > 2)
|
||||
return -EINVAL;
|
||||
if (val > 0xffff)
|
||||
return -EINVAL;
|
||||
if (mode > (I8254_MODE5 | I8254_BCD))
|
||||
return -EINVAL;
|
||||
|
||||
comedi_8254_set_mode(i8254, counter, mode);
|
||||
comedi_8254_write(i8254, counter, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_load);
|
||||
|
||||
/**
|
||||
* comedi_8254_pacer_enable - set the mode and load the cascaded counters
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter1: the counter number for the first divisor
|
||||
* @counter2: the counter number for the second divisor
|
||||
* @enable: flag to enable (load) the counters
|
||||
*/
|
||||
void comedi_8254_pacer_enable(struct comedi_8254 *i8254,
|
||||
unsigned int counter1,
|
||||
unsigned int counter2,
|
||||
bool enable)
|
||||
{
|
||||
unsigned int mode;
|
||||
|
||||
if (counter1 > 2 || counter2 > 2 || counter1 == counter2)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
mode = I8254_MODE2 | I8254_BINARY;
|
||||
else
|
||||
mode = I8254_MODE0 | I8254_BINARY;
|
||||
|
||||
comedi_8254_set_mode(i8254, counter1, mode);
|
||||
comedi_8254_set_mode(i8254, counter2, mode);
|
||||
|
||||
if (enable) {
|
||||
/*
|
||||
* Divisors are loaded second counter then first counter to
|
||||
* avoid possible issues with the first counter expiring
|
||||
* before the second counter is loaded.
|
||||
*/
|
||||
comedi_8254_write(i8254, counter2, i8254->divisor2);
|
||||
comedi_8254_write(i8254, counter1, i8254->divisor1);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_pacer_enable);
|
||||
|
||||
/**
|
||||
* comedi_8254_update_divisors - update the divisors for the cascaded counters
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
*/
|
||||
void comedi_8254_update_divisors(struct comedi_8254 *i8254)
|
||||
{
|
||||
/* masking is done since counter maps zero to 0x10000 */
|
||||
i8254->divisor = i8254->next_div & 0xffff;
|
||||
i8254->divisor1 = i8254->next_div1 & 0xffff;
|
||||
i8254->divisor2 = i8254->next_div2 & 0xffff;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_update_divisors);
|
||||
|
||||
/**
|
||||
* comedi_8254_cascade_ns_to_timer - calculate the cascaded divisor values
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @nanosec: the desired ns time
|
||||
* @flags: comedi_cmd flags
|
||||
*/
|
||||
void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *i8254,
|
||||
unsigned int *nanosec,
|
||||
unsigned int flags)
|
||||
{
|
||||
unsigned int d1 = i8254->next_div1 ? i8254->next_div1 : I8254_MAX_COUNT;
|
||||
unsigned int d2 = i8254->next_div2 ? i8254->next_div2 : I8254_MAX_COUNT;
|
||||
unsigned int div = d1 * d2;
|
||||
unsigned int ns_lub = 0xffffffff;
|
||||
unsigned int ns_glb = 0;
|
||||
unsigned int d1_lub = 0;
|
||||
unsigned int d1_glb = 0;
|
||||
unsigned int d2_lub = 0;
|
||||
unsigned int d2_glb = 0;
|
||||
unsigned int start;
|
||||
unsigned int ns;
|
||||
unsigned int ns_low;
|
||||
unsigned int ns_high;
|
||||
|
||||
/* exit early if everything is already correct */
|
||||
if (div * i8254->osc_base == *nanosec &&
|
||||
d1 > 1 && d1 <= I8254_MAX_COUNT &&
|
||||
d2 > 1 && d2 <= I8254_MAX_COUNT &&
|
||||
/* check for overflow */
|
||||
div > d1 && div > d2 &&
|
||||
div * i8254->osc_base > div &&
|
||||
div * i8254->osc_base > i8254->osc_base)
|
||||
return;
|
||||
|
||||
div = *nanosec / i8254->osc_base;
|
||||
d2 = I8254_MAX_COUNT;
|
||||
start = div / d2;
|
||||
if (start < 2)
|
||||
start = 2;
|
||||
for (d1 = start; d1 <= div / d1 + 1 && d1 <= I8254_MAX_COUNT; d1++) {
|
||||
for (d2 = div / d1;
|
||||
d1 * d2 <= div + d1 + 1 && d2 <= I8254_MAX_COUNT; d2++) {
|
||||
ns = i8254->osc_base * d1 * d2;
|
||||
if (ns <= *nanosec && ns > ns_glb) {
|
||||
ns_glb = ns;
|
||||
d1_glb = d1;
|
||||
d2_glb = d2;
|
||||
}
|
||||
if (ns >= *nanosec && ns < ns_lub) {
|
||||
ns_lub = ns;
|
||||
d1_lub = d1;
|
||||
d2_lub = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (flags & CMDF_ROUND_MASK) {
|
||||
case CMDF_ROUND_NEAREST:
|
||||
default:
|
||||
ns_high = d1_lub * d2_lub * i8254->osc_base;
|
||||
ns_low = d1_glb * d2_glb * i8254->osc_base;
|
||||
if (ns_high - *nanosec < *nanosec - ns_low) {
|
||||
d1 = d1_lub;
|
||||
d2 = d2_lub;
|
||||
} else {
|
||||
d1 = d1_glb;
|
||||
d2 = d2_glb;
|
||||
}
|
||||
break;
|
||||
case CMDF_ROUND_UP:
|
||||
d1 = d1_lub;
|
||||
d2 = d2_lub;
|
||||
break;
|
||||
case CMDF_ROUND_DOWN:
|
||||
d1 = d1_glb;
|
||||
d2 = d2_glb;
|
||||
break;
|
||||
}
|
||||
|
||||
*nanosec = d1 * d2 * i8254->osc_base;
|
||||
i8254->next_div1 = d1;
|
||||
i8254->next_div2 = d2;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_cascade_ns_to_timer);
|
||||
|
||||
/**
|
||||
* comedi_8254_ns_to_timer - calculate the divisor value for nanosec timing
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @nanosec: the desired ns time
|
||||
* @flags: comedi_cmd flags
|
||||
*/
|
||||
void comedi_8254_ns_to_timer(struct comedi_8254 *i8254,
|
||||
unsigned int *nanosec, unsigned int flags)
|
||||
{
|
||||
unsigned int divisor;
|
||||
|
||||
switch (flags & CMDF_ROUND_MASK) {
|
||||
default:
|
||||
case CMDF_ROUND_NEAREST:
|
||||
divisor = DIV_ROUND_CLOSEST(*nanosec, i8254->osc_base);
|
||||
break;
|
||||
case CMDF_ROUND_UP:
|
||||
divisor = DIV_ROUND_UP(*nanosec, i8254->osc_base);
|
||||
break;
|
||||
case CMDF_ROUND_DOWN:
|
||||
divisor = *nanosec / i8254->osc_base;
|
||||
break;
|
||||
}
|
||||
if (divisor < 2)
|
||||
divisor = 2;
|
||||
if (divisor > I8254_MAX_COUNT)
|
||||
divisor = I8254_MAX_COUNT;
|
||||
|
||||
*nanosec = divisor * i8254->osc_base;
|
||||
i8254->next_div = divisor;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_ns_to_timer);
|
||||
|
||||
/**
|
||||
* comedi_8254_set_busy - set/clear the "busy" flag for a given counter
|
||||
* @i8254: comedi_8254 struct for the timer
|
||||
* @counter: the counter number
|
||||
* @busy: set/clear flag
|
||||
*/
|
||||
void comedi_8254_set_busy(struct comedi_8254 *i8254,
|
||||
unsigned int counter, bool busy)
|
||||
{
|
||||
if (counter < 3)
|
||||
i8254->busy[counter] = busy;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_set_busy);
|
||||
|
||||
static int comedi_8254_insn_read(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct comedi_8254 *i8254 = s->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
int i;
|
||||
|
||||
if (i8254->busy[chan])
|
||||
return -EBUSY;
|
||||
|
||||
for (i = 0; i < insn->n; i++)
|
||||
data[i] = comedi_8254_read(i8254, chan);
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int comedi_8254_insn_write(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct comedi_8254 *i8254 = s->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
|
||||
if (i8254->busy[chan])
|
||||
return -EBUSY;
|
||||
|
||||
if (insn->n)
|
||||
comedi_8254_write(i8254, chan, data[insn->n - 1]);
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
static int comedi_8254_insn_config(struct comedi_device *dev,
|
||||
struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn,
|
||||
unsigned int *data)
|
||||
{
|
||||
struct comedi_8254 *i8254 = s->private;
|
||||
unsigned int chan = CR_CHAN(insn->chanspec);
|
||||
int ret;
|
||||
|
||||
if (i8254->busy[chan])
|
||||
return -EBUSY;
|
||||
|
||||
switch (data[0]) {
|
||||
case INSN_CONFIG_RESET:
|
||||
ret = comedi_8254_set_mode(i8254, chan,
|
||||
I8254_MODE0 | I8254_BINARY);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case INSN_CONFIG_SET_COUNTER_MODE:
|
||||
ret = comedi_8254_set_mode(i8254, chan, data[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case INSN_CONFIG_8254_READ_STATUS:
|
||||
data[1] = comedi_8254_status(i8254, chan);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* If available, call the driver provided (*insn_config)
|
||||
* to handle any driver implemented instructions.
|
||||
*/
|
||||
if (i8254->insn_config)
|
||||
return i8254->insn_config(dev, s, insn, data);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return insn->n;
|
||||
}
|
||||
|
||||
/**
|
||||
* comedi_8254_subdevice_init - initialize a comedi_subdevice for the 8254 timer
|
||||
* @s: comedi_subdevice struct
|
||||
*/
|
||||
void comedi_8254_subdevice_init(struct comedi_subdevice *s,
|
||||
struct comedi_8254 *i8254)
|
||||
{
|
||||
s->type = COMEDI_SUBD_COUNTER;
|
||||
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
|
||||
s->n_chan = 3;
|
||||
s->maxdata = 0xffff;
|
||||
s->range_table = &range_unknown;
|
||||
s->insn_read = comedi_8254_insn_read;
|
||||
s->insn_write = comedi_8254_insn_write;
|
||||
s->insn_config = comedi_8254_insn_config;
|
||||
|
||||
s->private = i8254;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_subdevice_init);
|
||||
|
||||
static struct comedi_8254 *__i8254_init(unsigned long iobase,
|
||||
void __iomem *mmio,
|
||||
unsigned int osc_base,
|
||||
unsigned int iosize,
|
||||
unsigned int regshift)
|
||||
{
|
||||
struct comedi_8254 *i8254;
|
||||
int i;
|
||||
|
||||
/* sanity check that the iosize is valid */
|
||||
if (!(iosize == I8254_IO8 || iosize == I8254_IO16 ||
|
||||
iosize == I8254_IO32))
|
||||
return NULL;
|
||||
|
||||
i8254 = kzalloc(sizeof(*i8254), GFP_KERNEL);
|
||||
if (!i8254)
|
||||
return NULL;
|
||||
|
||||
i8254->iobase = iobase;
|
||||
i8254->mmio = mmio;
|
||||
i8254->iosize = iosize;
|
||||
i8254->regshift = regshift;
|
||||
|
||||
/* default osc_base to the max speed of a generic 8254 timer */
|
||||
i8254->osc_base = osc_base ? osc_base : I8254_OSC_BASE_10MHZ;
|
||||
|
||||
/* reset all the counters by setting them to I8254_MODE0 */
|
||||
for (i = 0; i < 3; i++)
|
||||
comedi_8254_set_mode(i8254, i, I8254_MODE0 | I8254_BINARY);
|
||||
|
||||
return i8254;
|
||||
}
|
||||
|
||||
/**
|
||||
* comedi_8254_init - allocate and initialize the 8254 device for pio access
|
||||
* @mmio: port I/O base address
|
||||
* @osc_base: base time of the counter in ns
|
||||
* OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
|
||||
* @iosize: I/O register size
|
||||
* @regshift: register gap shift
|
||||
*/
|
||||
struct comedi_8254 *comedi_8254_init(unsigned long iobase,
|
||||
unsigned int osc_base,
|
||||
unsigned int iosize,
|
||||
unsigned int regshift)
|
||||
{
|
||||
return __i8254_init(iobase, NULL, osc_base, iosize, regshift);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_init);
|
||||
|
||||
/**
|
||||
* comedi_8254_mm_init - allocate and initialize the 8254 device for mmio access
|
||||
* @mmio: memory mapped I/O base address
|
||||
* @osc_base: base time of the counter in ns
|
||||
* OPTIONAL - only used by comedi_8254_cascade_ns_to_timer()
|
||||
* @iosize: I/O register size
|
||||
* @regshift: register gap shift
|
||||
*/
|
||||
struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio,
|
||||
unsigned int osc_base,
|
||||
unsigned int iosize,
|
||||
unsigned int regshift)
|
||||
{
|
||||
return __i8254_init(0, mmio, osc_base, iosize, regshift);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(comedi_8254_mm_init);
|
||||
|
||||
static int __init comedi_8254_module_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
module_init(comedi_8254_module_init);
|
||||
|
||||
static void __exit comedi_8254_module_exit(void)
|
||||
{
|
||||
}
|
||||
module_exit(comedi_8254_module_exit);
|
||||
|
||||
MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
|
||||
MODULE_DESCRIPTION("Comedi: Generic 8254 timer/counter support");
|
||||
MODULE_LICENSE("GPL");
|
133
drivers/staging/comedi/drivers/comedi_8254.h
Normal file
133
drivers/staging/comedi/drivers/comedi_8254.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* comedi_8254.h
|
||||
* Generic 8254 timer/counter support
|
||||
* Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
*
|
||||
* COMEDI - Linux Control and Measurement Device Interface
|
||||
* Copyright (C) 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_8254_H
|
||||
#define _COMEDI_8254_H
|
||||
|
||||
/*
|
||||
* Common oscillator base values in nanoseconds
|
||||
*/
|
||||
#define I8254_OSC_BASE_10MHZ 100
|
||||
#define I8254_OSC_BASE_5MHZ 200
|
||||
#define I8254_OSC_BASE_4MHZ 250
|
||||
#define I8254_OSC_BASE_2MHZ 500
|
||||
#define I8254_OSC_BASE_1MHZ 1000
|
||||
#define I8254_OSC_BASE_100KHZ 10000
|
||||
#define I8254_OSC_BASE_10KHZ 100000
|
||||
#define I8254_OSC_BASE_1KHZ 1000000
|
||||
|
||||
/*
|
||||
* I/O access size used to read/write registers
|
||||
*/
|
||||
#define I8254_IO8 1
|
||||
#define I8254_IO16 2
|
||||
#define I8254_IO32 4
|
||||
|
||||
/*
|
||||
* Register map for generic 8254 timer (I8254_IO8 with 0 regshift)
|
||||
*/
|
||||
#define I8254_COUNTER0_REG 0x00
|
||||
#define I8254_COUNTER1_REG 0x01
|
||||
#define I8254_COUNTER2_REG 0x02
|
||||
#define I8254_CTRL_REG 0x03
|
||||
#define I8254_CTRL_SEL_CTR(x) ((x) << 6)
|
||||
#define I8254_CTRL_READBACK_COUNT ((3 << 6) | (1 << 4))
|
||||
#define I8254_CTRL_READBACK_STATUS ((3 << 6) | (1 << 5))
|
||||
#define I8254_CTRL_READBACK_SEL_CTR(x) (2 << (x))
|
||||
#define I8254_CTRL_LATCH (0 << 4)
|
||||
#define I8254_CTRL_LSB_ONLY (1 << 4)
|
||||
#define I8254_CTRL_MSB_ONLY (2 << 4)
|
||||
#define I8254_CTRL_LSB_MSB (3 << 4)
|
||||
|
||||
/* counter maps zero to 0x10000 */
|
||||
#define I8254_MAX_COUNT 0x10000
|
||||
|
||||
/**
|
||||
* struct comedi_8254 - private data used by this module
|
||||
* @iobase: PIO base address of the registers (in/out)
|
||||
* @mmio: MMIO base address of the registers (read/write)
|
||||
* @iosize: I/O size used to access the registers (b/w/l)
|
||||
* @regshift: register gap shift
|
||||
* @osc_base: cascaded oscillator speed in ns
|
||||
* @divisor: divisor for single counter
|
||||
* @divisor1: divisor loaded into first cascaded counter
|
||||
* @divisor2: divisor loaded into second cascaded counter
|
||||
* #next_div: next divisor for single counter
|
||||
* @next_div1: next divisor to use for first cascaded counter
|
||||
* @next_div2: next divisor to use for second cascaded counter
|
||||
* @clock_src; current clock source for each counter (driver specific)
|
||||
* @gate_src; current gate source for each counter (driver specific)
|
||||
* @busy: flags used to indicate that a counter is "busy"
|
||||
* @insn_config: driver specific (*insn_config) callback
|
||||
*/
|
||||
struct comedi_8254 {
|
||||
unsigned long iobase;
|
||||
void __iomem *mmio;
|
||||
unsigned int iosize;
|
||||
unsigned int regshift;
|
||||
unsigned int osc_base;
|
||||
unsigned int divisor;
|
||||
unsigned int divisor1;
|
||||
unsigned int divisor2;
|
||||
unsigned int next_div;
|
||||
unsigned int next_div1;
|
||||
unsigned int next_div2;
|
||||
unsigned int clock_src[3];
|
||||
unsigned int gate_src[3];
|
||||
bool busy[3];
|
||||
|
||||
int (*insn_config)(struct comedi_device *, struct comedi_subdevice *s,
|
||||
struct comedi_insn *, unsigned int *data);
|
||||
};
|
||||
|
||||
unsigned int comedi_8254_status(struct comedi_8254 *, unsigned int counter);
|
||||
unsigned int comedi_8254_read(struct comedi_8254 *, unsigned int counter);
|
||||
void comedi_8254_write(struct comedi_8254 *,
|
||||
unsigned int counter, unsigned int val);
|
||||
|
||||
int comedi_8254_set_mode(struct comedi_8254 *,
|
||||
unsigned int counter, unsigned int mode);
|
||||
int comedi_8254_load(struct comedi_8254 *,
|
||||
unsigned int counter, unsigned int val, unsigned int mode);
|
||||
|
||||
void comedi_8254_pacer_enable(struct comedi_8254 *,
|
||||
unsigned int counter1, unsigned int counter2,
|
||||
bool enable);
|
||||
void comedi_8254_update_divisors(struct comedi_8254 *);
|
||||
void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *,
|
||||
unsigned int *nanosec, unsigned int flags);
|
||||
void comedi_8254_ns_to_timer(struct comedi_8254 *,
|
||||
unsigned int *nanosec, unsigned int flags);
|
||||
|
||||
void comedi_8254_set_busy(struct comedi_8254 *,
|
||||
unsigned int counter, bool busy);
|
||||
|
||||
void comedi_8254_subdevice_init(struct comedi_subdevice *,
|
||||
struct comedi_8254 *);
|
||||
|
||||
struct comedi_8254 *comedi_8254_init(unsigned long iobase,
|
||||
unsigned int osc_base,
|
||||
unsigned int iosize,
|
||||
unsigned int regshift);
|
||||
struct comedi_8254 *comedi_8254_mm_init(void __iomem *mmio,
|
||||
unsigned int osc_base,
|
||||
unsigned int iosize,
|
||||
unsigned int regshift);
|
||||
|
||||
#endif /* _COMEDI_8254_H */
|
@ -267,7 +267,6 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
|
||||
strlcat(devpriv->name, buf,
|
||||
sizeof(devpriv->name));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,9 +312,9 @@ static int bonding_attach(struct comedi_device *dev,
|
||||
s->insn_config = bonding_dio_insn_config;
|
||||
|
||||
dev_info(dev->class_dev,
|
||||
"%s: %s attached, %u channels from %u devices\n",
|
||||
dev->driver->driver_name, dev->board_name,
|
||||
devpriv->nchans, devpriv->ndevs);
|
||||
"%s: %s attached, %u channels from %u devices\n",
|
||||
dev->driver->driver_name, dev->board_name,
|
||||
devpriv->nchans, devpriv->ndevs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -235,7 +235,8 @@ void comedi_isadma_free(struct comedi_isadma *dma)
|
||||
desc = &dma->desc[i];
|
||||
if (desc->virt_addr)
|
||||
dma_free_coherent(NULL, desc->maxsize,
|
||||
desc->virt_addr, desc->hw_addr);
|
||||
desc->virt_addr,
|
||||
desc->hw_addr);
|
||||
}
|
||||
kfree(dma->desc);
|
||||
}
|
||||
|
@ -420,9 +420,8 @@ static int waveform_attach(struct comedi_device *dev,
|
||||
for (i = 0; i < s->n_chan; i++)
|
||||
devpriv->ao_loopbacks[i] = s->maxdata / 2;
|
||||
|
||||
init_timer(&devpriv->timer);
|
||||
devpriv->timer.function = waveform_ai_interrupt;
|
||||
devpriv->timer.data = (unsigned long)dev;
|
||||
setup_timer(&devpriv->timer, waveform_ai_interrupt,
|
||||
(unsigned long)dev);
|
||||
|
||||
dev_info(dev->class_dev,
|
||||
"%s: %i microvolt, %li microsecond waveform attached\n",
|
||||
|
@ -26,9 +26,8 @@ Configuration Options: not applicable, uses comedi PCI auto config
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
/*
|
||||
* Register map
|
||||
@ -59,7 +58,7 @@ static int contec_di_insn_bits(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int contec_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
struct comedi_subdevice *s;
|
||||
|
@ -103,11 +103,10 @@ Configuration options: not applicable, uses PCI auto config
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "../comedidev.h"
|
||||
#include "../comedi_pci.h"
|
||||
|
||||
#include "8255.h"
|
||||
|
||||
@ -649,7 +648,7 @@ static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
|
||||
}
|
||||
|
||||
static int daqboard2000_auto_attach(struct comedi_device *dev,
|
||||
unsigned long context_unused)
|
||||
unsigned long context_unused)
|
||||
{
|
||||
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
|
||||
const struct daq200_boardtype *board;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user