Pull staging driver updates from Greg KH: "Here's the big staging driver update for 4.4-rc1. If you were disappointed for 4.3-rc1 that we didn't contribute enough changesets, you should be happy with this pull request of over 2400 patches. But overall we removed more lines of code than we added, which is nice to see. Full details in the shortlog. All of these have been in linux-next for a while" Greg, I've never been disappointed in how few commits Staging contributes to the kernel.. Never. * tag 'staging-4.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (2431 commits) Staging: rtl8192u: ieee80211: added missing blank lines Staging: rtl8192u: ieee80211: removed unnecessary braces Staging: rtl8192u: ieee80211: corrected block comments Staging: rtl8192u: ieee80211: corrected indent Staging: rtl8192u: ieee80211: added missing spaces after if Staging: rtl8192u: ieee80211: added missing space around '=' Staging: rtl8192u: ieee80211: fixed position of else statements Staging: rtl8192u: ieee80211: fixed open brace positions staging: rdma: ipath: Remove unneeded vairable. staging: rtl8188eu: pwrGrpCnt variable removed in store_pwrindex_offset function staging: rtl8188eu: new variable for hal_data->MCSTxPowerLevelOriginalOffset[pwrGrpCnt] in store_pwrindex_offset function staging: rtl8188eu: checkpatch fixes: 'Avoid CamelCase' in hal/bb_cfg.c staging: rtl8188eu: checkpatch fixes: line over 80 characters splited into two parts staging: rtl8188eu: checkpatch fixes: alignment should match open parenthesis staging: rtl8188eu: checkpatch fixes: unnecessary parentheses removed in hal/bb_cfg.c staging: rtl8188eu: checkpatch fixes: spaces preferred around that '|' in hal/bb_cfg.c staging: rtl8188eu: operator = replaced by += in loop increment staging: rtl8188eu: occurrence of the 5 GHz code marked staging: rtl8188eu: increment placed into for loop header staging: rtl8188eu: while loop replaced by for loop in rtw_restruct_wmm_ie ...
Unified · Split
| @@ -581,6 +581,7 @@ What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en · 580 unmodified lines | ||
| 581 | 581 | What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en |
| 582 | 582 | What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en |
| 583 | 583 | What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en |
| 584 | +What: /sys/.../iio:deviceX/events/in_voltageY_thresh_either_en | |
| 584 | 585 | What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en |
| 585 | 586 | What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en |
| 586 | 587 | KernelVersion: 2.6.37 |
| @@ -1459,3 +1460,34 @@ Description: · 872 unmodified lines | ||
| 1459 | 1460 | measurements and return the average value as output data. Each |
| 1460 | 1461 | value resulted from <type>[_name]_oversampling_ratio measurements |
| 1461 | 1462 | is considered as one sample for <type>[_name]_sampling_frequency. |
| 1463 | + | |
| 1464 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw | |
| 1465 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw | |
| 1466 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw | |
| 1467 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw | |
| 1468 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw | |
| 1469 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw | |
| 1470 | +KernelVersion: 4.3 | |
| 1471 | +Contact: linux-iio@vger.kernel.org | |
| 1472 | +Description: | |
| 1473 | + Raw (unscaled no offset etc.) percentage reading of a substance. | |
| 1474 | + | |
| 1475 | +What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw | |
| 1476 | +What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw | |
| 1477 | +What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw | |
| 1478 | +What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw | |
| 1479 | +KernelVersion: 4.3 | |
| 1480 | +Contact: linux-iio@vger.kernel.org | |
| 1481 | +Description: | |
| 1482 | + Raw (unscaled no offset etc.) resistance reading that can be processed | |
| 1483 | + into an ohm value. | |
| 1484 | + | |
| 1485 | +What: /sys/bus/iio/devices/iio:deviceX/heater_enable | |
| 1486 | +KernelVersion: 4.1.0 | |
| 1487 | +Contact: linux-iio@vger.kernel.org | |
| 1488 | +Description: | |
| 1489 | + '1' (enable) or '0' (disable) specifying the enable | |
| 1490 | + of heater function. Same reading values apply | |
| 1491 | + This ABI is especially applicable for humidity sensors | |
| 1492 | + to heatup the device and get rid of any condensation | |
| 1493 | + in some humidity environment | |
| @@ -0,0 +1,43 @@ | ||
| 1 | +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sensing_mode | |
| 2 | +Date: August 2015 | |
| 3 | +KernelVersion: 4.2.0 | |
| 4 | +Contact: source@cogentembedded.com | |
| 5 | +Description: | |
| 6 | + Program sensor type for threshold detector inputs. | |
| 7 | + Could be either "GND-Open" or "Supply-Open" mode. Y is a | |
| 8 | + threshold detector input channel. Channels 0..7, 8..15, 16..23 | |
| 9 | + and 24..31 has common sensor types. | |
| 10 | + | |
| 11 | +What: /sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_falling_value | |
| 12 | +Date: August 2015 | |
| 13 | +KernelVersion: 4.2.0 | |
| 14 | +Contact: source@cogentembedded.com | |
| 15 | +Description: | |
| 16 | + Channel Y low voltage threshold. If sensor input voltage goes lower then | |
| 17 | + this value then the threshold falling event is pushed. | |
| 18 | + Depending on in_voltageY_sensing_mode the low voltage threshold | |
| 19 | + is separately set for "GND-Open" and "Supply-Open" modes. | |
| 20 | + Channels 0..31 have common low threshold values, but could have different | |
| 21 | + sensing_modes. | |
| 22 | + The low voltage threshold range is between 2..21V. | |
| 23 | + Hysteresis between low and high thresholds can not be lower then 2 and | |
| 24 | + can not be odd. | |
| 25 | + If falling threshold results hysteresis to odd value then rising | |
| 26 | + threshold is automatically subtracted by one. | |
| 27 | + | |
| 28 | +What: /sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_rising_value | |
| 29 | +Date: August 2015 | |
| 30 | +KernelVersion: 4.2.0 | |
| 31 | +Contact: source@cogentembedded.com | |
| 32 | +Description: | |
| 33 | + Channel Y high voltage threshold. If sensor input voltage goes higher then | |
| 34 | + this value then the threshold rising event is pushed. | |
| 35 | + Depending on in_voltageY_sensing_mode the high voltage threshold | |
| 36 | + is separately set for "GND-Open" and "Supply-Open" modes. | |
| 37 | + Channels 0..31 have common high threshold values, but could have different | |
| 38 | + sensing_modes. | |
| 39 | + The high voltage threshold range is between 3..22V. | |
| 40 | + Hysteresis between low and high thresholds can not be lower then 2 and | |
| 41 | + can not be odd. | |
| 42 | + If rising threshold results hysteresis to odd value then falling | |
| 43 | + threshold is automatically appended by one. | |
| @@ -0,0 +1,7 @@ | ||
| 1 | +What: /sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw | |
| 2 | +Date: September 2015 | |
| 3 | +KernelVersion: 4.3 | |
| 4 | +Contact: Matt Ranostay <mranostay@gmail.com> | |
| 5 | +Description: | |
| 6 | + Get the raw calibration VOC value from the sensor. | |
| 7 | + This value has little application outside of calibration. | |
| @@ -0,0 +1,9 @@ | ||
| 1 | +What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw | |
| 2 | +What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available | |
| 3 | +KernelVersion: 4.3 | |
| 4 | +Contact: linux-iio@vger.kernel.org | |
| 5 | +Description: | |
| 6 | + Controls the heater device within the humidity sensor to get | |
| 7 | + rid of excess condensation. | |
| 8 | + | |
| 9 | + Valid control values are 0 = OFF, and 1 = ON. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +What: /sys/bus/iio/devices/iio:deviceX/battery_low | |
| 2 | +KernelVersion: 4.1.0 | |
| 3 | +Contact: linux-iio@vger.kernel.org | |
| 4 | +Description: | |
| 5 | + Reading returns either '1' or '0'. '1' means that the | |
| 6 | + battery level supplied to sensor is below 2.25V. | |
| 7 | + This ABI is available for tsys02d, htu21, ms8607 | |
| 8 | + This ABI is available for htu21, ms8607 | |
| @@ -18,3 +18,25 @@ Description: · 17 unmodified lines | ||
| 18 | 18 | trigger. In order to associate the trigger with an IIO device |
| 19 | 19 | one should write this name string to |
| 20 | 20 | /sys/bus/iio/devices/iio:deviceY/trigger/current_trigger. |
| 21 | + | |
| 22 | +What: /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger | |
| 23 | +KernelVersion: 2.6.39 | |
| 24 | +Contact: linux-iio@vger.kernel.org | |
| 25 | +Description: | |
| 26 | + This attribute is provided by the iio-trig-sysfs stand-alone | |
| 27 | + driver and it is used to activate the creation of a new trigger. | |
| 28 | + In order to achieve this, one should write a positive integer | |
| 29 | + into the associated file, which will serve as the id of the | |
| 30 | + trigger. If the trigger with the specified id is already present | |
| 31 | + in the system, an invalid argument message will be returned. | |
| 32 | + | |
| 33 | +What: /sys/bus/iio/devices/iio_sysfs_trigger/remove_trigger | |
| 34 | +KernelVersion: 2.6.39 | |
| 35 | +Contact: linux-iio@vger.kernel.org | |
| 36 | +Description: | |
| 37 | + This attribute is used to unregister and delete a previously | |
| 38 | + created trigger from the list of available triggers. In order to | |
| 39 | + achieve this, one should write a positive integer into the | |
| 40 | + associated file, representing the id of the trigger that needs | |
| 41 | + to be removed. If the trigger can't be found, an invalid | |
| 42 | + argument message will be returned to the user. | |
| @@ -578,7 +578,7 @@ · 577 unmodified lines | ||
| 578 | 578 | work together. |
| 579 | 579 | </para> |
| 580 | 580 | <sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title> |
| 581 | −!Edrivers/iio/industrialio-triggered-buffer.c | |
| 581 | +!Edrivers/iio/buffer/industrialio-triggered-buffer.c | |
| 582 | 582 | !Finclude/linux/iio/iio.h iio_buffer_setup_ops |
| 583 | 583 | |
| 584 | 584 | |
| @@ -54,7 +54,6 @@ epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE · 53 unmodified lines | ||
| 54 | 54 | fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer |
| 55 | 55 | fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51 |
| 56 | 56 | fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer |
| 57 | −fsl,mma8452 MMA8452Q: 3-axis 12-bit / 8-bit Digital Accelerometer | |
| 58 | 57 | fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller |
| 59 | 58 | fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec |
| 60 | 59 | gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface |
| @@ -80,6 +79,7 @@ oki,ml86v7667 OKI ML86V7667 video decoder · 19 unmodified lines | ||
| 80 | 79 | ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus |
| 81 | 80 | pericom,pt7c4338 Real-time Clock Module |
| 82 | 81 | plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch |
| 82 | +pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor | |
| 83 | 83 | ramtron,24c64 i2c serial eeprom (24cxx) |
| 84 | 84 | ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC |
| 85 | 85 | ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC |
| @@ -88,6 +88,7 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC · 2 unmodified lines | ||
| 88 | 88 | ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC |
| 89 | 89 | ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC |
| 90 | 90 | samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power) |
| 91 | +sgx,vz89x SGX Sensortech VZ89X Sensors | |
| 91 | 92 | sii,s35390a 2-wire CMOS real-time clock |
| 92 | 93 | skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply |
| 93 | 94 | st-micro,24c256 i2c serial eeprom (24cxx) |
| @@ -0,0 +1,24 @@ | ||
| 1 | +Freescale MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC triaxial accelerometer | |
| 2 | + | |
| 3 | +Required properties: | |
| 4 | + | |
| 5 | + - compatible: should contain one of | |
| 6 | + * "fsl,mma8452" | |
| 7 | + * "fsl,mma8453" | |
| 8 | + * "fsl,mma8652" | |
| 9 | + * "fsl,mma8653" | |
| 10 | + - reg: the I2C address of the chip | |
| 11 | + | |
| 12 | +Optional properties: | |
| 13 | + | |
| 14 | + - interrupt-parent: should be the phandle for the interrupt controller | |
| 15 | + - interrupts: interrupt mapping for GPIO IRQ | |
| 16 | + | |
| 17 | +Example: | |
| 18 | + | |
| 19 | + mma8453fc@1d { | |
| 20 | + compatible = "fsl,mma8453"; | |
| 21 | + reg = <0x1d>; | |
| 22 | + interrupt-parent = <&gpio1>; | |
| 23 | + interrupts = <5 0>; | |
| 24 | + }; | |
| @@ -0,0 +1,21 @@ | ||
| 1 | +Holt Integrated Circuits HI-8435 threshold detector bindings | |
| 2 | + | |
| 3 | +Required properties: | |
| 4 | + - compatible: should be "holt,hi8435" | |
| 5 | + - reg: spi chip select number for the device | |
| 6 | + | |
| 7 | +Recommended properties: | |
| 8 | + - spi-max-frequency: definition as per | |
| 9 | + Documentation/devicetree/bindings/spi/spi-bus.txt | |
| 10 | + | |
| 11 | +Optional properties: | |
| 12 | + - gpios: GPIO used for controlling the reset pin | |
| 13 | + | |
| 14 | +Example: | |
| 15 | +sensor@0 { | |
| 16 | + compatible = "holt,hi8435"; | |
| 17 | + reg = <0>; | |
| 18 | + gpios = <&gpio6 1 0>; | |
| 19 | + | |
| 20 | + spi-max-frequency = <1000000>; | |
| 21 | +}; | |
| @@ -0,0 +1,22 @@ | ||
| 1 | +* Avago APDS9960 gesture/RGB/ALS/proximity sensor | |
| 2 | + | |
| 3 | +http://www.avagotech.com/docs/AV02-4191EN | |
| 4 | + | |
| 5 | +Required properties: | |
| 6 | + | |
| 7 | + - compatible: must be "avago,apds9960" | |
| 8 | + - reg: the I2c address of the sensor | |
| 9 | + - interrupt-parent: should be the phandle for the interrupt controller | |
| 10 | + - interrupts : the sole interrupt generated by the device | |
| 11 | + | |
| 12 | + Refer to interrupt-controller/interrupts.txt for generic interrupt client | |
| 13 | + node bindings. | |
| 14 | + | |
| 15 | +Example: | |
| 16 | + | |
| 17 | +apds9960@39 { | |
| 18 | + compatible = "avago,apds9960"; | |
| 19 | + reg = <0x39>; | |
| 20 | + interrupt-parent = <&gpio1>; | |
| 21 | + interrupts = <16 1>; | |
| 22 | +}; | |
| @@ -0,0 +1,34 @@ | ||
| 1 | +* UPISEMI us5182d I2C ALS and Proximity sensor | |
| 2 | + | |
| 3 | +Required properties: | |
| 4 | +- compatible: must be "upisemi,usd5182" | |
| 5 | +- reg: the I2C address of the device | |
| 6 | + | |
| 7 | +Optional properties: | |
| 8 | +- upisemi,glass-coef: glass attenuation factor - compensation factor of | |
| 9 | + resolution 1000 for material transmittance. | |
| 10 | +- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc | |
| 11 | + counts) corresponding to every scale. | |
| 12 | +- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4 | |
| 13 | + fractional bits - Q4.4) applied when light > threshold | |
| 14 | +- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4 | |
| 15 | + fractional bits - Q4.4) applied when light < threshold | |
| 16 | + | |
| 17 | +If the optional properties are not specified these factors will default to the | |
| 18 | +values in the below example. | |
| 19 | +The glass-coef defaults to no compensation for the covering material. | |
| 20 | +The threshold array defaults to experimental values that work with US5182D | |
| 21 | +sensor on evaluation board - roughly between 12-32 lux. | |
| 22 | +There will be no dark-gain compensation by default when ALS > thresh | |
| 23 | +(0 * dark-gain), and a 1.35 compensation factor when ALS < thresh. | |
| 24 | + | |
| 25 | +Example: | |
| 26 | + | |
| 27 | + usd5182@39 { | |
| 28 | + compatible = "upisemi,usd5182"; | |
| 29 | + reg = <0x39>; | |
| 30 | + upisemi,glass-coef = < 1000 >; | |
| 31 | + upisemi,dark-ths = /bits/ 16 <170 200 512 512 800 2000 4000 8000>; | |
| 32 | + upisemi,upper-dark-gain = /bits/ 8 <0x00>; | |
| 33 | + upisemi,lower-dark-gain = /bits/ 8 <0x16>; | |
| 34 | + }; | |
| @@ -101,6 +101,7 @@ himax Himax Technologies, Inc. · 100 unmodified lines | ||
| 101 | 101 | hisilicon Hisilicon Limited. |
| 102 | 102 | hit Hitachi Ltd. |
| 103 | 103 | hitex Hitex Development Tools |
| 104 | +holt Holt Integrated Circuits, Inc. | |
| 104 | 105 | honeywell Honeywell |
| 105 | 106 | hp Hewlett Packard |
| 106 | 107 | i2se I2SE GmbH |
| @@ -169,6 +170,7 @@ phytec PHYTEC Messtechnik GmbH · 62 unmodified lines | ||
| 169 | 170 | picochip Picochip Ltd |
| 170 | 171 | plathome Plat'Home Co., Ltd. |
| 171 | 172 | pixcir PIXCIR MICROELECTRONICS Co., Ltd |
| 173 | +pulsedlight PulsedLight, Inc | |
| 172 | 174 | powervr PowerVR (deprecated, use img) |
| 173 | 175 | qca Qualcomm Atheros, Inc. |
| 174 | 176 | qcom Qualcomm Technologies, Inc |
| @@ -191,6 +193,7 @@ sbs Smart Battery System · 16 unmodified lines | ||
| 191 | 193 | schindler Schindler |
| 192 | 194 | seagate Seagate Technology PLC |
| 193 | 195 | semtech Semtech Corporation |
| 196 | +sgx SGX Sensortech | |
| 194 | 197 | sharp Sharp Corporation |
| 195 | 198 | sil Silicon Image |
| 196 | 199 | silabs Silicon Laboratories |
| @@ -223,6 +226,7 @@ toshiba Toshiba Corporation · 26 unmodified lines | ||
| 223 | 226 | toumaz Toumaz |
| 224 | 227 | tplink TP-LINK Technologies Co., Ltd. |
| 225 | 228 | truly Truly Semiconductors Limited |
| 229 | +upisemi uPI Semiconductor Corp. | |
| 226 | 230 | usi Universal Scientific Industrial Co., Ltd. |
| 227 | 231 | v3 V3 Semiconductor |
| 228 | 232 | variscite Variscite Ltd. |
| @@ -6740,6 +6740,12 @@ W: http://linuxtv.org · 6739 unmodified lines | ||
| 6740 | 6740 | S: Maintained |
| 6741 | 6741 | F: drivers/media/radio/radio-maxiradio* |
| 6742 | 6742 | |
| 6743 | +MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER | |
| 6744 | +M: Peter Rosin <peda@axentia.se> | |
| 6745 | +L: linux-iio@vger.kernel.org | |
| 6746 | +S: Maintained | |
| 6747 | +F: drivers/iio/potentiometer/mcp4531.c | |
| 6748 | + | |
| 6743 | 6749 | MEDIA DRIVERS FOR RENESAS - VSP1 |
| 6744 | 6750 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 6745 | 6751 | L: linux-media@vger.kernel.org |
| @@ -6975,6 +6981,13 @@ S: Supported · 229 unmodified lines | ||
| 6975 | 6981 | F: include/linux/mlx5/ |
| 6976 | 6982 | F: drivers/infiniband/hw/mlx5/ |
| 6977 | 6983 | |
| 6984 | +MELEXIS MLX90614 DRIVER | |
| 6985 | +M: Crt Mori <cmo@melexis.com> | |
| 6986 | +L: linux-iio@vger.kernel.org | |
| 6987 | +W: http://www.melexis.com | |
| 6988 | +S: Supported | |
| 6989 | +F: drivers/iio/temperature/mlx90614.c | |
| 6990 | + | |
| 6978 | 6991 | MN88472 MEDIA DRIVER |
| 6979 | 6992 | M: Antti Palosaari <crope@iki.fi> |
| 6980 | 6993 | L: linux-media@vger.kernel.org |
| @@ -10069,9 +10082,11 @@ F: drivers/staging/vt665?/ · 3088 unmodified lines | ||
| 10069 | 10082 | |
| 10070 | 10083 | STAGING - WILC1000 WIFI DRIVER |
| 10071 | 10084 | M: Johnny Kim <johnny.kim@atmel.com> |
| 10072 | −M: Rachel Kim <rachel.kim@atmel.com> | |
| 10073 | −M: Dean Lee <dean.lee@atmel.com> | |
| 10085 | +M: Austin Shin <austin.shin@atmel.com> | |
| 10074 | 10086 | M: Chris Park <chris.park@atmel.com> |
| 10087 | +M: Tony Cho <tony.cho@atmel.com> | |
| 10088 | +M: Glen Lee <glen.lee@atmel.com> | |
| 10089 | +M: Leo Kim <leo.kim@atmel.com> | |
| 10075 | 10090 | L: linux-wireless@vger.kernel.org |
| 10076 | 10091 | S: Supported |
| 10077 | 10092 | F: drivers/staging/wilc1000/ |
| @@ -19,27 +19,7 @@ config IIO_BUFFER · 18 unmodified lines | ||
| 19 | 19 | acquisition methods. |
| 20 | 20 | |
| 21 | 21 | if IIO_BUFFER |
| 22 | − | |
| 23 | −config IIO_BUFFER_CB | |
| 24 | − bool "IIO callback buffer used for push in-kernel interfaces" | |
| 25 | − help | |
| 26 | − Should be selected by any drivers that do in-kernel push | |
| 27 | − usage. That is, those where the data is pushed to the consumer. | |
| 28 | − | |
| 29 | −config IIO_KFIFO_BUF | |
| 30 | − tristate "Industrial I/O buffering based on kfifo" | |
| 31 | − help | |
| 32 | − A simple fifo based on kfifo. Note that this currently provides | |
| 33 | − no buffer events so it is up to userspace to work out how | |
| 34 | − often to read from the buffer. | |
| 35 | − | |
| 36 | −config IIO_TRIGGERED_BUFFER | |
| 37 | − tristate | |
| 38 | − select IIO_TRIGGER | |
| 39 | − select IIO_KFIFO_BUF | |
| 40 | − help | |
| 41 | − Provides helper functions for setting up triggered buffers. | |
| 42 | − | |
| 22 | + source "drivers/iio/buffer/Kconfig" | |
| 43 | 23 | endif # IIO_BUFFER |
| 44 | 24 | |
| 45 | 25 | config IIO_TRIGGER |
| @@ -58,9 +38,16 @@ config IIO_CONSUMERS_PER_TRIGGER · 12 unmodified lines | ||
| 58 | 38 | This value controls the maximum number of consumers that a |
| 59 | 39 | given trigger may handle. Default is 2. |
| 60 | 40 | |
| 41 | +config IIO_TRIGGERED_EVENT | |
| 42 | + tristate | |
| 43 | + select IIO_TRIGGER | |
| 44 | + help | |
| 45 | + Provides helper functions for setting up triggered events. | |
| 46 | + | |
| 61 | 47 | source "drivers/iio/accel/Kconfig" |
| 62 | 48 | source "drivers/iio/adc/Kconfig" |
| 63 | 49 | source "drivers/iio/amplifiers/Kconfig" |
| 50 | +source "drivers/iio/chemical/Kconfig" | |
| 64 | 51 | source "drivers/iio/common/Kconfig" |
| 65 | 52 | source "drivers/iio/dac/Kconfig" |
| 66 | 53 | source "drivers/iio/frequency/Kconfig" |
| @@ -73,6 +60,7 @@ source "drivers/iio/orientation/Kconfig" · 6 unmodified lines | ||
| 73 | 60 | if IIO_TRIGGER |
| 74 | 61 | source "drivers/iio/trigger/Kconfig" |
| 75 | 62 | endif #IIO_TRIGGER |
| 63 | +source "drivers/iio/potentiometer/Kconfig" | |
| 76 | 64 | source "drivers/iio/pressure/Kconfig" |
| 77 | 65 | source "drivers/iio/proximity/Kconfig" |
| 78 | 66 | source "drivers/iio/temperature/Kconfig" |
| @@ -6,14 +6,14 @@ obj-$(CONFIG_IIO) += industrialio.o · 5 unmodified lines | ||
| 6 | 6 | industrialio-y := industrialio-core.o industrialio-event.o inkern.o |
| 7 | 7 | industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o |
| 8 | 8 | industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o |
| 9 | −industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o | |
| 10 | 9 | |
| 11 | −obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o | |
| 12 | −obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o | |
| 10 | +obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o | |
| 13 | 11 | |
| 14 | 12 | obj-y += accel/ |
| 15 | 13 | obj-y += adc/ |
| 16 | 14 | obj-y += amplifiers/ |
| 15 | +obj-y += buffer/ | |
| 16 | +obj-y += chemical/ | |
| 17 | 17 | obj-y += common/ |
| 18 | 18 | obj-y += dac/ |
| 19 | 19 | obj-y += gyro/ |
| @@ -23,6 +23,7 @@ obj-y += imu/ · 3 unmodified lines | ||
| 23 | 23 | obj-y += light/ |
| 24 | 24 | obj-y += magnetometer/ |
| 25 | 25 | obj-y += orientation/ |
| 26 | +obj-y += potentiometer/ | |
| 26 | 27 | obj-y += pressure/ |
| 27 | 28 | obj-y += proximity/ |
| 28 | 29 | obj-y += temperature/ |
| @@ -19,19 +19,27 @@ config BMA180 · 18 unmodified lines | ||
| 19 | 19 | |
| 20 | 20 | config BMC150_ACCEL |
| 21 | 21 | tristate "Bosch BMC150 Accelerometer Driver" |
| 22 | − depends on I2C | |
| 23 | 22 | select IIO_BUFFER |
| 24 | 23 | select IIO_TRIGGERED_BUFFER |
| 24 | + select REGMAP | |
| 25 | + select BMC150_ACCEL_I2C if I2C | |
| 26 | + select BMC150_ACCEL_SPI if SPI | |
| 25 | 27 | help |
| 26 | 28 | Say yes here to build support for the following Bosch accelerometers: |
| 27 | 29 | BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. |
| 28 | 30 | |
| 29 | − Currently this only supports the device via an i2c interface. | |
| 30 | − | |
| 31 | 31 | This is a combo module with both accelerometer and magnetometer. |
| 32 | 32 | This driver is only implementing accelerometer part, which has |
| 33 | 33 | its own address and register map. |
| 34 | 34 | |
| 35 | +config BMC150_ACCEL_I2C | |
| 36 | + tristate | |
| 37 | + select REGMAP_I2C | |
| 38 | + | |
| 39 | +config BMC150_ACCEL_SPI | |
| 40 | + tristate | |
| 41 | + select REGMAP_SPI | |
| 42 | + | |
| 35 | 43 | config HID_SENSOR_ACCEL_3D |
| 36 | 44 | depends on HID_SENSOR_HUB |
| 37 | 45 | select IIO_BUFFER |
| @@ -100,13 +108,13 @@ config KXCJK1013 · 62 unmodified lines | ||
| 100 | 108 | be called kxcjk-1013. |
| 101 | 109 | |
| 102 | 110 | config MMA8452 |
| 103 | − tristate "Freescale MMA8452Q Accelerometer Driver" | |
| 111 | + tristate "Freescale MMA8452Q and similar Accelerometers Driver" | |
| 104 | 112 | depends on I2C |
| 105 | 113 | select IIO_BUFFER |
| 106 | 114 | select IIO_TRIGGERED_BUFFER |
| 107 | 115 | help |
| 108 | − Say yes here to build support for the Freescale MMA8452Q 3-axis | |
| 109 | − accelerometer. | |
| 116 | + Say yes here to build support for the following Freescale 3-axis | |
| 117 | + accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC. | |
| 110 | 118 | |
| 111 | 119 | To compile this driver as a module, choose M here: the module |
| 112 | 120 | will be called mma8452. |
| @@ -137,6 +145,19 @@ config MMA9553 · 24 unmodified lines | ||
| 137 | 145 | To compile this driver as a module, choose M here: the module |
| 138 | 146 | will be called mma9553. |
| 139 | 147 | |
| 148 | +config MXC4005 | |
| 149 | + tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" | |
| 150 | + depends on I2C | |
| 151 | + select IIO_BUFFER | |
| 152 | + select IIO_TRIGGERED_BUFFER | |
| 153 | + select REGMAP_I2C | |
| 154 | + help | |
| 155 | + Say yes here to build support for the Memsic MXC4005XC 3-axis | |
| 156 | + accelerometer. | |
| 157 | + | |
| 158 | + To compile this driver as a module, choose M. The module will be | |
| 159 | + called mxc4005. | |
| 160 | + | |
| 140 | 161 | config STK8312 |
| 141 | 162 | tristate "Sensortek STK8312 3-Axis Accelerometer Driver" |
| 142 | 163 | depends on I2C |
| @@ -4,7 +4,9 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | # When adding new entries keep the list in alphabetical order |
| 6 | 6 | obj-$(CONFIG_BMA180) += bma180.o |
| 7 | −obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o | |
| 7 | +obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o | |
| 8 | +obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o | |
| 9 | +obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o | |
| 8 | 10 | obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o |
| 9 | 11 | obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o |
| 10 | 12 | obj-$(CONFIG_KXSD9) += kxsd9.o |
| @@ -14,6 +16,8 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o · 3 unmodified lines | ||
| 14 | 16 | obj-$(CONFIG_MMA9551) += mma9551.o |
| 15 | 17 | obj-$(CONFIG_MMA9553) += mma9553.o |
| 16 | 18 | |
| 19 | +obj-$(CONFIG_MXC4005) += mxc4005.o | |
| 20 | + | |
| 17 | 21 | obj-$(CONFIG_STK8312) += stk8312.o |
| 18 | 22 | obj-$(CONFIG_STK8BA50) += stk8ba50.o |
| 19 | 23 | |
| @@ -35,10 +35,12 @@ · 34 unmodified lines | ||
| 35 | 35 | #include <linux/iio/trigger.h> |
| 36 | 36 | #include <linux/iio/trigger_consumer.h> |
| 37 | 37 | #include <linux/iio/triggered_buffer.h> |
| 38 | +#include <linux/regmap.h> | |
| 39 | + | |
| 40 | +#include "bmc150-accel.h" | |
| 38 | 41 | |
| 39 | 42 | #define BMC150_ACCEL_DRV_NAME "bmc150_accel" |
| 40 | 43 | #define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" |
| 41 | −#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" | |
| 42 | 44 | |
| 43 | 45 | #define BMC150_ACCEL_REG_CHIP_ID 0x00 |
| 44 | 46 | |
| @@ -185,7 +187,9 @@ enum bmc150_accel_trigger_id { · 140 unmodified lines | ||
| 185 | 187 | }; |
| 186 | 188 | |
| 187 | 189 | struct bmc150_accel_data { |
| 188 | − struct i2c_client *client; | |
| 190 | + struct regmap *regmap; | |
| 191 | + struct device *dev; | |
| 192 | + int irq; | |
| 189 | 193 | struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; |
| 190 | 194 | atomic_t active_intr; |
| 191 | 195 | struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; |
| @@ -242,6 +246,12 @@ static const struct { · 50 unmodified lines | ||
| 242 | 246 | {500000, BMC150_ACCEL_SLEEP_500_MS}, |
| 243 | 247 | {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; |
| 244 | 248 | |
| 249 | +static const struct regmap_config bmc150_i2c_regmap_conf = { | |
| 250 | + .reg_bits = 8, | |
| 251 | + .val_bits = 8, | |
| 252 | + .max_register = 0x3f, | |
| 253 | +}; | |
| 254 | + | |
| 245 | 255 | static int bmc150_accel_set_mode(struct bmc150_accel_data *data, |
| 246 | 256 | enum bmc150_power_modes mode, |
| 247 | 257 | int dur_us) |
| @@ -269,12 +279,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data, · 21 unmodified lines | ||
| 269 | 279 | lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; |
| 270 | 280 | lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); |
| 271 | 281 | |
| 272 | − dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits); | |
| 282 | + dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits); | |
| 273 | 283 | |
| 274 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 275 | − BMC150_ACCEL_REG_PMU_LPW, lpw_bits); | |
| 284 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits); | |
| 276 | 285 | if (ret < 0) { |
| 277 | − dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); | |
| 286 | + dev_err(data->dev, "Error writing reg_pmu_lpw\n"); | |
| 278 | 287 | return ret; |
| 279 | 288 | } |
| 280 | 289 | |
| @@ -290,8 +299,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, · 9 unmodified lines | ||
| 290 | 299 | for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { |
| 291 | 300 | if (bmc150_accel_samp_freq_table[i].val == val && |
| 292 | 301 | bmc150_accel_samp_freq_table[i].val2 == val2) { |
| 293 | − ret = i2c_smbus_write_byte_data( | |
| 294 | − data->client, | |
| 302 | + ret = regmap_write(data->regmap, | |
| 295 | 303 | BMC150_ACCEL_REG_PMU_BW, |
| 296 | 304 | bmc150_accel_samp_freq_table[i].bw_bits); |
| 297 | 305 | if (ret < 0) |
| @@ -308,30 +316,23 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, · 10 unmodified lines | ||
| 308 | 316 | |
| 309 | 317 | static int bmc150_accel_update_slope(struct bmc150_accel_data *data) |
| 310 | 318 | { |
| 311 | − int ret, val; | |
| 319 | + int ret; | |
| 312 | 320 | |
| 313 | − ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6, | |
| 321 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6, | |
| 314 | 322 | data->slope_thres); |
| 315 | 323 | if (ret < 0) { |
| 316 | − dev_err(&data->client->dev, "Error writing reg_int_6\n"); | |
| 317 | − return ret; | |
| 318 | − } | |
| 319 | − | |
| 320 | − ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); | |
| 321 | − if (ret < 0) { | |
| 322 | − dev_err(&data->client->dev, "Error reading reg_int_5\n"); | |
| 324 | + dev_err(data->dev, "Error writing reg_int_6\n"); | |
| 323 | 325 | return ret; |
| 324 | 326 | } |
| 325 | 327 | |
| 326 | − val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur; | |
| 327 | − ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5, | |
| 328 | − val); | |
| 328 | + ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5, | |
| 329 | + BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur); | |
| 329 | 330 | if (ret < 0) { |
| 330 | − dev_err(&data->client->dev, "Error write reg_int_5\n"); | |
| 331 | + dev_err(data->dev, "Error updating reg_int_5\n"); | |
| 331 | 332 | return ret; |
| 332 | 333 | } |
| 333 | 334 | |
| 334 | − dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres, | |
| 335 | + dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres, | |
| 335 | 336 | data->slope_dur); |
| 336 | 337 | |
| 337 | 338 | return ret; |
| @@ -380,17 +381,17 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) · 42 unmodified lines | ||
| 380 | 381 | int ret; |
| 381 | 382 | |
| 382 | 383 | if (on) { |
| 383 | − ret = pm_runtime_get_sync(&data->client->dev); | |
| 384 | + ret = pm_runtime_get_sync(data->dev); | |
| 384 | 385 | } else { |
| 385 | − pm_runtime_mark_last_busy(&data->client->dev); | |
| 386 | − ret = pm_runtime_put_autosuspend(&data->client->dev); | |
| 386 | + pm_runtime_mark_last_busy(data->dev); | |
| 387 | + ret = pm_runtime_put_autosuspend(data->dev); | |
| 387 | 388 | } |
| 388 | 389 | |
| 389 | 390 | if (ret < 0) { |
| 390 | − dev_err(&data->client->dev, | |
| 391 | + dev_err(data->dev, | |
| 391 | 392 | "Failed: bmc150_accel_set_power_state for %d\n", on); |
| 392 | 393 | if (on) |
| 393 | − pm_runtime_put_noidle(&data->client->dev); | |
| 394 | + pm_runtime_put_noidle(data->dev); | |
| 394 | 395 | |
| 395 | 396 | return ret; |
| 396 | 397 | } |
| @@ -470,38 +471,18 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, · 73 unmodified lines | ||
| 470 | 471 | return ret; |
| 471 | 472 | |
| 472 | 473 | /* map the interrupt to the appropriate pins */ |
| 473 | − ret = i2c_smbus_read_byte_data(data->client, info->map_reg); | |
| 474 | − if (ret < 0) { | |
| 475 | − dev_err(&data->client->dev, "Error reading reg_int_map\n"); | |
| 476 | − goto out_fix_power_state; | |
| 477 | − } | |
| 478 | − if (state) | |
| 479 | − ret |= info->map_bitmask; | |
| 480 | − else | |
| 481 | − ret &= ~info->map_bitmask; | |
| 482 | − | |
| 483 | − ret = i2c_smbus_write_byte_data(data->client, info->map_reg, | |
| 484 | − ret); | |
| 474 | + ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask, | |
| 475 | + (state ? info->map_bitmask : 0)); | |
| 485 | 476 | if (ret < 0) { |
| 486 | − dev_err(&data->client->dev, "Error writing reg_int_map\n"); | |
| 477 | + dev_err(data->dev, "Error updating reg_int_map\n"); | |
| 487 | 478 | goto out_fix_power_state; |
| 488 | 479 | } |
| 489 | 480 | |
| 490 | 481 | /* enable/disable the interrupt */ |
| 491 | − ret = i2c_smbus_read_byte_data(data->client, info->en_reg); | |
| 492 | − if (ret < 0) { | |
| 493 | − dev_err(&data->client->dev, "Error reading reg_int_en\n"); | |
| 494 | − goto out_fix_power_state; | |
| 495 | − } | |
| 496 | − | |
| 497 | − if (state) | |
| 498 | − ret |= info->en_bitmask; | |
| 499 | − else | |
| 500 | − ret &= ~info->en_bitmask; | |
| 501 | − | |
| 502 | − ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret); | |
| 482 | + ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask, | |
| 483 | + (state ? info->en_bitmask : 0)); | |
| 503 | 484 | if (ret < 0) { |
| 504 | − dev_err(&data->client->dev, "Error writing reg_int_en\n"); | |
| 485 | + dev_err(data->dev, "Error updating reg_int_en\n"); | |
| 505 | 486 | goto out_fix_power_state; |
| 506 | 487 | } |
| 507 | 488 | |
| @@ -523,12 +504,11 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) · 15 unmodified lines | ||
| 523 | 504 | |
| 524 | 505 | for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { |
| 525 | 506 | if (data->chip_info->scale_table[i].scale == val) { |
| 526 | − ret = i2c_smbus_write_byte_data( | |
| 527 | − data->client, | |
| 507 | + ret = regmap_write(data->regmap, | |
| 528 | 508 | BMC150_ACCEL_REG_PMU_RANGE, |
| 529 | 509 | data->chip_info->scale_table[i].reg_range); |
| 530 | 510 | if (ret < 0) { |
| 531 | − dev_err(&data->client->dev, | |
| 511 | + dev_err(data->dev, | |
| 532 | 512 | "Error writing pmu_range\n"); |
| 533 | 513 | return ret; |
| 534 | 514 | } |
| @@ -544,16 +524,17 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) · 9 unmodified lines | ||
| 544 | 524 | static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) |
| 545 | 525 | { |
| 546 | 526 | int ret; |
| 527 | + unsigned int value; | |
| 547 | 528 | |
| 548 | 529 | mutex_lock(&data->mutex); |
| 549 | 530 | |
| 550 | − ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP); | |
| 531 | + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value); | |
| 551 | 532 | if (ret < 0) { |
| 552 | − dev_err(&data->client->dev, "Error reading reg_temp\n"); | |
| 533 | + dev_err(data->dev, "Error reading reg_temp\n"); | |
| 553 | 534 | mutex_unlock(&data->mutex); |
| 554 | 535 | return ret; |
| 555 | 536 | } |
| 556 | − *val = sign_extend32(ret, 7); | |
| 537 | + *val = sign_extend32(value, 7); | |
| 557 | 538 | |
| 558 | 539 | mutex_unlock(&data->mutex); |
| 559 | 540 | |
| @@ -566,6 +547,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, · 6 unmodified lines | ||
| 566 | 547 | { |
| 567 | 548 | int ret; |
| 568 | 549 | int axis = chan->scan_index; |
| 550 | + unsigned int raw_val; | |
| 569 | 551 | |
| 570 | 552 | mutex_lock(&data->mutex); |
| 571 | 553 | ret = bmc150_accel_set_power_state(data, true); |
| @@ -574,15 +556,15 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, · 2 unmodified lines | ||
| 574 | 556 | return ret; |
| 575 | 557 | } |
| 576 | 558 | |
| 577 | − ret = i2c_smbus_read_word_data(data->client, | |
| 578 | − BMC150_ACCEL_AXIS_TO_REG(axis)); | |
| 559 | + ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis), | |
| 560 | + &raw_val, 2); | |
| 579 | 561 | if (ret < 0) { |
| 580 | − dev_err(&data->client->dev, "Error reading axis %d\n", axis); | |
| 562 | + dev_err(data->dev, "Error reading axis %d\n", axis); | |
| 581 | 563 | bmc150_accel_set_power_state(data, false); |
| 582 | 564 | mutex_unlock(&data->mutex); |
| 583 | 565 | return ret; |
| 584 | 566 | } |
| 585 | − *val = sign_extend32(ret >> chan->scan_type.shift, | |
| 567 | + *val = sign_extend32(raw_val >> chan->scan_type.shift, | |
| 586 | 568 | chan->scan_type.realbits - 1); |
| 587 | 569 | ret = bmc150_accel_set_power_state(data, false); |
| 588 | 570 | mutex_unlock(&data->mutex); |
| @@ -846,52 +828,34 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val) · 257 unmodified lines | ||
| 846 | 828 | * We must read at least one full frame in one burst, otherwise the rest of the |
| 847 | 829 | * frame data is discarded. |
| 848 | 830 | */ |
| 849 | −static int bmc150_accel_fifo_transfer(const struct i2c_client *client, | |
| 831 | +static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data, | |
| 850 | 832 | char *buffer, int samples) |
| 851 | 833 | { |
| 852 | 834 | int sample_length = 3 * 2; |
| 853 | − u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA; | |
| 854 | − int ret = -EIO; | |
| 855 | − | |
| 856 | − if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | |
| 857 | − struct i2c_msg msg[2] = { | |
| 858 | − { | |
| 859 | − .addr = client->addr, | |
| 860 | − .flags = 0, | |
| 861 | − .buf = ®_fifo_data, | |
| 862 | − .len = sizeof(reg_fifo_data), | |
| 863 | − }, | |
| 864 | − { | |
| 865 | − .addr = client->addr, | |
| 866 | − .flags = I2C_M_RD, | |
| 867 | − .buf = (u8 *)buffer, | |
| 868 | − .len = samples * sample_length, | |
| 869 | − } | |
| 870 | − }; | |
| 835 | + int ret; | |
| 836 | + int total_length = samples * sample_length; | |
| 837 | + int i; | |
| 838 | + size_t step = regmap_get_raw_read_max(data->regmap); | |
| 871 | 839 | |
| 872 | − ret = i2c_transfer(client->adapter, msg, 2); | |
| 873 | − if (ret != 2) | |
| 874 | − ret = -EIO; | |
| 875 | − else | |
| 876 | − ret = 0; | |
| 877 | − } else { | |
| 878 | − int i, step = I2C_SMBUS_BLOCK_MAX / sample_length; | |
| 879 | − | |
| 880 | − for (i = 0; i < samples * sample_length; i += step) { | |
| 881 | − ret = i2c_smbus_read_i2c_block_data(client, | |
| 882 | − reg_fifo_data, step, | |
| 883 | − &buffer[i]); | |
| 884 | − if (ret != step) { | |
| 885 | − ret = -EIO; | |
| 886 | − break; | |
| 887 | − } | |
| 840 | + if (!step || step > total_length) | |
| 841 | + step = total_length; | |
| 842 | + else if (step < total_length) | |
| 843 | + step = sample_length; | |
| 888 | 844 | |
| 889 | − ret = 0; | |
| 890 | − } | |
| 845 | + /* | |
| 846 | + * Seems we have a bus with size limitation so we have to execute | |
| 847 | + * multiple reads | |
| 848 | + */ | |
| 849 | + for (i = 0; i < total_length; i += step) { | |
| 850 | + ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, | |
| 851 | + &buffer[i], step); | |
| 852 | + if (ret) | |
| 853 | + break; | |
| 891 | 854 | } |
| 892 | 855 | |
| 893 | 856 | if (ret) |
| 894 | − dev_err(&client->dev, "Error transferring data from fifo\n"); | |
| 857 | + dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n", | |
| 858 | + step); | |
| 895 | 859 | |
| 896 | 860 | return ret; |
| 897 | 861 | } |
| @@ -905,15 +869,15 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, · 7 unmodified lines | ||
| 905 | 869 | u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; |
| 906 | 870 | int64_t tstamp; |
| 907 | 871 | uint64_t sample_period; |
| 872 | + unsigned int val; | |
| 908 | 873 | |
| 909 | − ret = i2c_smbus_read_byte_data(data->client, | |
| 910 | − BMC150_ACCEL_REG_FIFO_STATUS); | |
| 874 | + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val); | |
| 911 | 875 | if (ret < 0) { |
| 912 | − dev_err(&data->client->dev, "Error reading reg_fifo_status\n"); | |
| 876 | + dev_err(data->dev, "Error reading reg_fifo_status\n"); | |
| 913 | 877 | return ret; |
| 914 | 878 | } |
| 915 | 879 | |
| 916 | − count = ret & 0x7F; | |
| 880 | + count = val & 0x7F; | |
| 917 | 881 | |
| 918 | 882 | if (!count) |
| 919 | 883 | return 0; |
| @@ -952,7 +916,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, · 32 unmodified lines | ||
| 952 | 916 | if (samples && count > samples) |
| 953 | 917 | count = samples; |
| 954 | 918 | |
| 955 | − ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count); | |
| 919 | + ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count); | |
| 956 | 920 | if (ret) |
| 957 | 921 | return ret; |
| 958 | 922 | |
| @@ -1052,15 +1016,6 @@ static const struct iio_chan_spec bmc150_accel_channels[] = · 93 unmodified lines | ||
| 1052 | 1016 | static const struct iio_chan_spec bma280_accel_channels[] = |
| 1053 | 1017 | BMC150_ACCEL_CHANNELS(14); |
| 1054 | 1018 | |
| 1055 | −enum { | |
| 1056 | − bmc150, | |
| 1057 | − bmi055, | |
| 1058 | − bma255, | |
| 1059 | − bma250e, | |
| 1060 | − bma222e, | |
| 1061 | − bma280, | |
| 1062 | −}; | |
| 1063 | − | |
| 1064 | 1019 | static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { |
| 1065 | 1020 | [bmc150] = { |
| 1066 | 1021 | .name = "BMC150A", |
| @@ -1155,17 +1110,19 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) · 88 unmodified lines | ||
| 1155 | 1110 | struct iio_dev *indio_dev = pf->indio_dev; |
| 1156 | 1111 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1157 | 1112 | int bit, ret, i = 0; |
| 1113 | + unsigned int raw_val; | |
| 1158 | 1114 | |
| 1159 | 1115 | mutex_lock(&data->mutex); |
| 1160 | 1116 | for_each_set_bit(bit, indio_dev->active_scan_mask, |
| 1161 | 1117 | indio_dev->masklength) { |
| 1162 | − ret = i2c_smbus_read_word_data(data->client, | |
| 1163 | − BMC150_ACCEL_AXIS_TO_REG(bit)); | |
| 1118 | + ret = regmap_bulk_read(data->regmap, | |
| 1119 | + BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val, | |
| 1120 | + 2); | |
| 1164 | 1121 | if (ret < 0) { |
| 1165 | 1122 | mutex_unlock(&data->mutex); |
| 1166 | 1123 | goto err_read; |
| 1167 | 1124 | } |
| 1168 | − data->buffer[i++] = ret; | |
| 1125 | + data->buffer[i++] = raw_val; | |
| 1169 | 1126 | } |
| 1170 | 1127 | mutex_unlock(&data->mutex); |
| 1171 | 1128 | |
| @@ -1189,13 +1146,12 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) · 17 unmodified lines | ||
| 1189 | 1146 | |
| 1190 | 1147 | mutex_lock(&data->mutex); |
| 1191 | 1148 | /* clear any latched interrupt */ |
| 1192 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1193 | − BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1194 | − BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1195 | − BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1149 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1150 | + BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1151 | + BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1196 | 1152 | mutex_unlock(&data->mutex); |
| 1197 | 1153 | if (ret < 0) { |
| 1198 | − dev_err(&data->client->dev, | |
| 1154 | + dev_err(data->dev, | |
| 1199 | 1155 | "Error writing reg_int_rst_latch\n"); |
| 1200 | 1156 | return ret; |
| 1201 | 1157 | } |
| @@ -1249,20 +1205,20 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) · 47 unmodified lines | ||
| 1249 | 1205 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1250 | 1206 | int dir; |
| 1251 | 1207 | int ret; |
| 1208 | + unsigned int val; | |
| 1252 | 1209 | |
| 1253 | − ret = i2c_smbus_read_byte_data(data->client, | |
| 1254 | − BMC150_ACCEL_REG_INT_STATUS_2); | |
| 1210 | + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val); | |
| 1255 | 1211 | if (ret < 0) { |
| 1256 | − dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); | |
| 1212 | + dev_err(data->dev, "Error reading reg_int_status_2\n"); | |
| 1257 | 1213 | return ret; |
| 1258 | 1214 | } |
| 1259 | 1215 | |
| 1260 | − if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) | |
| 1216 | + if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) | |
| 1261 | 1217 | dir = IIO_EV_DIR_FALLING; |
| 1262 | 1218 | else |
| 1263 | 1219 | dir = IIO_EV_DIR_RISING; |
| 1264 | 1220 | |
| 1265 | − if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) | |
| 1221 | + if (val & BMC150_ACCEL_ANY_MOTION_BIT_X) | |
| 1266 | 1222 | iio_push_event(indio_dev, |
| 1267 | 1223 | IIO_MOD_EVENT_CODE(IIO_ACCEL, |
| 1268 | 1224 | 0, |
| @@ -1271,7 +1227,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) · 2 unmodified lines | ||
| 1271 | 1227 | dir), |
| 1272 | 1228 | data->timestamp); |
| 1273 | 1229 | |
| 1274 | − if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) | |
| 1230 | + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y) | |
| 1275 | 1231 | iio_push_event(indio_dev, |
| 1276 | 1232 | IIO_MOD_EVENT_CODE(IIO_ACCEL, |
| 1277 | 1233 | 0, |
| @@ -1280,7 +1236,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) · 2 unmodified lines | ||
| 1280 | 1236 | dir), |
| 1281 | 1237 | data->timestamp); |
| 1282 | 1238 | |
| 1283 | − if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) | |
| 1239 | + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z) | |
| 1284 | 1240 | iio_push_event(indio_dev, |
| 1285 | 1241 | IIO_MOD_EVENT_CODE(IIO_ACCEL, |
| 1286 | 1242 | 0, |
| @@ -1315,13 +1271,11 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) · 28 unmodified lines | ||
| 1315 | 1271 | } |
| 1316 | 1272 | |
| 1317 | 1273 | if (ack) { |
| 1318 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1319 | − BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1320 | − BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1321 | − BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1274 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1275 | + BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1276 | + BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1322 | 1277 | if (ret) |
| 1323 | − dev_err(&data->client->dev, | |
| 1324 | − "Error writing reg_int_rst_latch\n"); | |
| 1278 | + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); | |
| 1325 | 1279 | |
| 1326 | 1280 | ret = IRQ_HANDLED; |
| 1327 | 1281 | } else { |
| @@ -1360,32 +1314,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) · 32 unmodified lines | ||
| 1360 | 1314 | return IRQ_NONE; |
| 1361 | 1315 | } |
| 1362 | 1316 | |
| 1363 | −static int bmc150_accel_gpio_probe(struct i2c_client *client, | |
| 1364 | − struct bmc150_accel_data *data) | |
| 1365 | −{ | |
| 1366 | − struct device *dev; | |
| 1367 | − struct gpio_desc *gpio; | |
| 1368 | − int ret; | |
| 1369 | − | |
| 1370 | − if (!client) | |
| 1371 | − return -EINVAL; | |
| 1372 | − | |
| 1373 | − dev = &client->dev; | |
| 1374 | − | |
| 1375 | − /* data ready gpio interrupt pin */ | |
| 1376 | − gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN); | |
| 1377 | − if (IS_ERR(gpio)) { | |
| 1378 | − dev_err(dev, "Failed: gpio get index\n"); | |
| 1379 | − return PTR_ERR(gpio); | |
| 1380 | − } | |
| 1381 | − | |
| 1382 | − ret = gpiod_to_irq(gpio); | |
| 1383 | − | |
| 1384 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 1385 | − | |
| 1386 | − return ret; | |
| 1387 | −} | |
| 1388 | − | |
| 1389 | 1317 | static const struct { |
| 1390 | 1318 | int intr; |
| 1391 | 1319 | const char *name; |
| @@ -1423,7 +1351,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, · 31 unmodified lines | ||
| 1423 | 1351 | for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { |
| 1424 | 1352 | struct bmc150_accel_trigger *t = &data->triggers[i]; |
| 1425 | 1353 | |
| 1426 | − t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, | |
| 1354 | + t->indio_trig = devm_iio_trigger_alloc(data->dev, | |
| 1427 | 1355 | bmc150_accel_triggers[i].name, |
| 1428 | 1356 | indio_dev->name, |
| 1429 | 1357 | indio_dev->id); |
| @@ -1432,7 +1360,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, · 2 unmodified lines | ||
| 1432 | 1360 | break; |
| 1433 | 1361 | } |
| 1434 | 1362 | |
| 1435 | − t->indio_trig->dev.parent = &data->client->dev; | |
| 1363 | + t->indio_trig->dev.parent = data->dev; | |
| 1436 | 1364 | t->indio_trig->ops = &bmc150_accel_trigger_ops; |
| 1437 | 1365 | t->intr = bmc150_accel_triggers[i].intr; |
| 1438 | 1366 | t->data = data; |
| @@ -1459,20 +1387,19 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data) · 20 unmodified lines | ||
| 1459 | 1387 | u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1; |
| 1460 | 1388 | int ret; |
| 1461 | 1389 | |
| 1462 | − ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode); | |
| 1390 | + ret = regmap_write(data->regmap, reg, data->fifo_mode); | |
| 1463 | 1391 | if (ret < 0) { |
| 1464 | − dev_err(&data->client->dev, "Error writing reg_fifo_config1\n"); | |
| 1392 | + dev_err(data->dev, "Error writing reg_fifo_config1\n"); | |
| 1465 | 1393 | return ret; |
| 1466 | 1394 | } |
| 1467 | 1395 | |
| 1468 | 1396 | if (!data->fifo_mode) |
| 1469 | 1397 | return 0; |
| 1470 | 1398 | |
| 1471 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1472 | − BMC150_ACCEL_REG_FIFO_CONFIG0, | |
| 1473 | − data->watermark); | |
| 1399 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0, | |
| 1400 | + data->watermark); | |
| 1474 | 1401 | if (ret < 0) |
| 1475 | − dev_err(&data->client->dev, "Error writing reg_fifo_config0\n"); | |
| 1402 | + dev_err(data->dev, "Error writing reg_fifo_config0\n"); | |
| 1476 | 1403 | |
| 1477 | 1404 | return ret; |
| 1478 | 1405 | } |
| @@ -1557,23 +1484,25 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { · 78 unmodified lines | ||
| 1557 | 1484 | static int bmc150_accel_chip_init(struct bmc150_accel_data *data) |
| 1558 | 1485 | { |
| 1559 | 1486 | int ret, i; |
| 1487 | + unsigned int val; | |
| 1560 | 1488 | |
| 1561 | − ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); | |
| 1489 | + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val); | |
| 1562 | 1490 | if (ret < 0) { |
| 1563 | − dev_err(&data->client->dev, "Error: Reading chip id\n"); | |
| 1491 | + dev_err(data->dev, | |
| 1492 | + "Error: Reading chip id\n"); | |
| 1564 | 1493 | return ret; |
| 1565 | 1494 | } |
| 1566 | 1495 | |
| 1567 | − dev_dbg(&data->client->dev, "Chip Id %x\n", ret); | |
| 1496 | + dev_dbg(data->dev, "Chip Id %x\n", val); | |
| 1568 | 1497 | for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { |
| 1569 | − if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { | |
| 1498 | + if (bmc150_accel_chip_info_tbl[i].chip_id == val) { | |
| 1570 | 1499 | data->chip_info = &bmc150_accel_chip_info_tbl[i]; |
| 1571 | 1500 | break; |
| 1572 | 1501 | } |
| 1573 | 1502 | } |
| 1574 | 1503 | |
| 1575 | 1504 | if (!data->chip_info) { |
| 1576 | − dev_err(&data->client->dev, "Unsupported chip %x\n", ret); | |
| 1505 | + dev_err(data->dev, "Invalid chip %x\n", val); | |
| 1577 | 1506 | return -ENODEV; |
| 1578 | 1507 | } |
| 1579 | 1508 | |
| @@ -1587,11 +1516,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) · 7 unmodified lines | ||
| 1587 | 1516 | return ret; |
| 1588 | 1517 | |
| 1589 | 1518 | /* Set Default Range */ |
| 1590 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1591 | − BMC150_ACCEL_REG_PMU_RANGE, | |
| 1592 | − BMC150_ACCEL_DEF_RANGE_4G); | |
| 1519 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE, | |
| 1520 | + BMC150_ACCEL_DEF_RANGE_4G); | |
| 1593 | 1521 | if (ret < 0) { |
| 1594 | − dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); | |
| 1522 | + dev_err(data->dev, | |
| 1523 | + "Error writing reg_pmu_range\n"); | |
| 1595 | 1524 | return ret; |
| 1596 | 1525 | } |
| 1597 | 1526 | |
| @@ -1605,12 +1534,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) · 7 unmodified lines | ||
| 1605 | 1534 | return ret; |
| 1606 | 1535 | |
| 1607 | 1536 | /* Set default as latched interrupts */ |
| 1608 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1609 | − BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1610 | − BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1611 | − BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1537 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1538 | + BMC150_ACCEL_INT_MODE_LATCH_INT | | |
| 1539 | + BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1612 | 1540 | if (ret < 0) { |
| 1613 | − dev_err(&data->client->dev, | |
| 1541 | + dev_err(data->dev, | |
| 1614 | 1542 | "Error writing reg_int_rst_latch\n"); |
| 1615 | 1543 | return ret; |
| 1616 | 1544 | } |
| @@ -1618,24 +1546,23 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) · 1 unmodified line | ||
| 1618 | 1546 | return 0; |
| 1619 | 1547 | } |
| 1620 | 1548 | |
| 1621 | −static int bmc150_accel_probe(struct i2c_client *client, | |
| 1622 | − const struct i2c_device_id *id) | |
| 1549 | +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, | |
| 1550 | + const char *name, bool block_supported) | |
| 1623 | 1551 | { |
| 1624 | 1552 | struct bmc150_accel_data *data; |
| 1625 | 1553 | struct iio_dev *indio_dev; |
| 1626 | 1554 | int ret; |
| 1627 | − const char *name = NULL; | |
| 1628 | 1555 | |
| 1629 | − indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 1556 | + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | |
| 1630 | 1557 | if (!indio_dev) |
| 1631 | 1558 | return -ENOMEM; |
| 1632 | 1559 | |
| 1633 | 1560 | data = iio_priv(indio_dev); |
| 1634 | − i2c_set_clientdata(client, indio_dev); | |
| 1635 | − data->client = client; | |
| 1561 | + dev_set_drvdata(dev, indio_dev); | |
| 1562 | + data->dev = dev; | |
| 1563 | + data->irq = irq; | |
| 1636 | 1564 | |
| 1637 | − if (id) | |
| 1638 | − name = id->name; | |
| 1565 | + data->regmap = regmap; | |
| 1639 | 1566 | |
| 1640 | 1567 | ret = bmc150_accel_chip_init(data); |
| 1641 | 1568 | if (ret < 0) |
| @@ -1643,7 +1570,7 @@ static int bmc150_accel_probe(struct i2c_client *client, · 1 unmodified line | ||
| 1643 | 1570 | |
| 1644 | 1571 | mutex_init(&data->mutex); |
| 1645 | 1572 | |
| 1646 | − indio_dev->dev.parent = &client->dev; | |
| 1573 | + indio_dev->dev.parent = dev; | |
| 1647 | 1574 | indio_dev->channels = data->chip_info->channels; |
| 1648 | 1575 | indio_dev->num_channels = data->chip_info->num_channels; |
| 1649 | 1576 | indio_dev->name = name ? name : data->chip_info->name; |
| @@ -1655,16 +1582,13 @@ static int bmc150_accel_probe(struct i2c_client *client, · 5 unmodified lines | ||
| 1655 | 1582 | bmc150_accel_trigger_handler, |
| 1656 | 1583 | &bmc150_accel_buffer_ops); |
| 1657 | 1584 | if (ret < 0) { |
| 1658 | − dev_err(&client->dev, "Failed: iio triggered buffer setup\n"); | |
| 1585 | + dev_err(data->dev, "Failed: iio triggered buffer setup\n"); | |
| 1659 | 1586 | return ret; |
| 1660 | 1587 | } |
| 1661 | 1588 | |
| 1662 | − if (client->irq < 0) | |
| 1663 | − client->irq = bmc150_accel_gpio_probe(client, data); | |
| 1664 | − | |
| 1665 | − if (client->irq > 0) { | |
| 1589 | + if (data->irq > 0) { | |
| 1666 | 1590 | ret = devm_request_threaded_irq( |
| 1667 | − &client->dev, client->irq, | |
| 1591 | + data->dev, data->irq, | |
| 1668 | 1592 | bmc150_accel_irq_handler, |
| 1669 | 1593 | bmc150_accel_irq_thread_handler, |
| 1670 | 1594 | IRQF_TRIGGER_RISING, |
| @@ -1679,11 +1603,10 @@ static int bmc150_accel_probe(struct i2c_client *client, · 8 unmodified lines | ||
| 1679 | 1603 | * want to use latch mode when we can to prevent interrupt |
| 1680 | 1604 | * flooding. |
| 1681 | 1605 | */ |
| 1682 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 1683 | − BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1684 | − BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1606 | + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, | |
| 1607 | + BMC150_ACCEL_INT_MODE_LATCH_RESET); | |
| 1685 | 1608 | if (ret < 0) { |
| 1686 | − dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n"); | |
| 1609 | + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); | |
| 1687 | 1610 | goto err_buffer_cleanup; |
| 1688 | 1611 | } |
| 1689 | 1612 | |
| @@ -1693,9 +1616,7 @@ static int bmc150_accel_probe(struct i2c_client *client, · 3 unmodified lines | ||
| 1693 | 1616 | if (ret) |
| 1694 | 1617 | goto err_buffer_cleanup; |
| 1695 | 1618 | |
| 1696 | − if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || | |
| 1697 | − i2c_check_functionality(client->adapter, | |
| 1698 | − I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | |
| 1619 | + if (block_supported) { | |
| 1699 | 1620 | indio_dev->modes |= INDIO_BUFFER_SOFTWARE; |
| 1700 | 1621 | indio_dev->info = &bmc150_accel_info_fifo; |
| 1701 | 1622 | indio_dev->buffer->attrs = bmc150_accel_fifo_attributes; |
| @@ -1704,18 +1625,17 @@ static int bmc150_accel_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 1704 | 1625 | |
| 1705 | 1626 | ret = iio_device_register(indio_dev); |
| 1706 | 1627 | if (ret < 0) { |
| 1707 | − dev_err(&client->dev, "Unable to register iio device\n"); | |
| 1628 | + dev_err(dev, "Unable to register iio device\n"); | |
| 1708 | 1629 | goto err_trigger_unregister; |
| 1709 | 1630 | } |
| 1710 | 1631 | |
| 1711 | − ret = pm_runtime_set_active(&client->dev); | |
| 1632 | + ret = pm_runtime_set_active(dev); | |
| 1712 | 1633 | if (ret) |
| 1713 | 1634 | goto err_iio_unregister; |
| 1714 | 1635 | |
| 1715 | − pm_runtime_enable(&client->dev); | |
| 1716 | − pm_runtime_set_autosuspend_delay(&client->dev, | |
| 1717 | − BMC150_AUTO_SUSPEND_DELAY_MS); | |
| 1718 | − pm_runtime_use_autosuspend(&client->dev); | |
| 1636 | + pm_runtime_enable(dev); | |
| 1637 | + pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS); | |
| 1638 | + pm_runtime_use_autosuspend(dev); | |
| 1719 | 1639 | |
| 1720 | 1640 | return 0; |
| 1721 | 1641 | |
| @@ -1728,15 +1648,16 @@ err_buffer_cleanup: · 6 unmodified lines | ||
| 1728 | 1648 | |
| 1729 | 1649 | return ret; |
| 1730 | 1650 | } |
| 1651 | +EXPORT_SYMBOL_GPL(bmc150_accel_core_probe); | |
| 1731 | 1652 | |
| 1732 | −static int bmc150_accel_remove(struct i2c_client *client) | |
| 1653 | +int bmc150_accel_core_remove(struct device *dev) | |
| 1733 | 1654 | { |
| 1734 | − struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
| 1655 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1735 | 1656 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1736 | 1657 | |
| 1737 | − pm_runtime_disable(&client->dev); | |
| 1738 | − pm_runtime_set_suspended(&client->dev); | |
| 1739 | − pm_runtime_put_noidle(&client->dev); | |
| 1658 | + pm_runtime_disable(data->dev); | |
| 1659 | + pm_runtime_set_suspended(data->dev); | |
| 1660 | + pm_runtime_put_noidle(data->dev); | |
| 1740 | 1661 | |
| 1741 | 1662 | iio_device_unregister(indio_dev); |
| 1742 | 1663 | |
| @@ -1750,11 +1671,12 @@ static int bmc150_accel_remove(struct i2c_client *client) · 7 unmodified lines | ||
| 1750 | 1671 | |
| 1751 | 1672 | return 0; |
| 1752 | 1673 | } |
| 1674 | +EXPORT_SYMBOL_GPL(bmc150_accel_core_remove); | |
| 1753 | 1675 | |
| 1754 | 1676 | #ifdef CONFIG_PM_SLEEP |
| 1755 | 1677 | static int bmc150_accel_suspend(struct device *dev) |
| 1756 | 1678 | { |
| 1757 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1679 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1758 | 1680 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1759 | 1681 | |
| 1760 | 1682 | mutex_lock(&data->mutex); |
| @@ -1766,7 +1688,7 @@ static int bmc150_accel_suspend(struct device *dev) · 5 unmodified lines | ||
| 1766 | 1688 | |
| 1767 | 1689 | static int bmc150_accel_resume(struct device *dev) |
| 1768 | 1690 | { |
| 1769 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1691 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1770 | 1692 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1771 | 1693 | |
| 1772 | 1694 | mutex_lock(&data->mutex); |
| @@ -1782,11 +1704,11 @@ static int bmc150_accel_resume(struct device *dev) · 9 unmodified lines | ||
| 1782 | 1704 | #ifdef CONFIG_PM |
| 1783 | 1705 | static int bmc150_accel_runtime_suspend(struct device *dev) |
| 1784 | 1706 | { |
| 1785 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1707 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1786 | 1708 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1787 | 1709 | int ret; |
| 1788 | 1710 | |
| 1789 | − dev_dbg(&data->client->dev, __func__); | |
| 1711 | + dev_dbg(data->dev, __func__); | |
| 1790 | 1712 | ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); |
| 1791 | 1713 | if (ret < 0) |
| 1792 | 1714 | return -EAGAIN; |
| @@ -1796,12 +1718,12 @@ static int bmc150_accel_runtime_suspend(struct device *dev) · 3 unmodified lines | ||
| 1796 | 1718 | |
| 1797 | 1719 | static int bmc150_accel_runtime_resume(struct device *dev) |
| 1798 | 1720 | { |
| 1799 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1721 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1800 | 1722 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
| 1801 | 1723 | int ret; |
| 1802 | 1724 | int sleep_val; |
| 1803 | 1725 | |
| 1804 | − dev_dbg(&data->client->dev, __func__); | |
| 1726 | + dev_dbg(data->dev, __func__); | |
| 1805 | 1727 | |
| 1806 | 1728 | ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); |
| 1807 | 1729 | if (ret < 0) |
| @@ -1820,47 +1742,12 @@ static int bmc150_accel_runtime_resume(struct device *dev) · 12 unmodified lines | ||
| 1820 | 1742 | } |
| 1821 | 1743 | #endif |
| 1822 | 1744 | |
| 1823 | −static const struct dev_pm_ops bmc150_accel_pm_ops = { | |
| 1745 | +const struct dev_pm_ops bmc150_accel_pm_ops = { | |
| 1824 | 1746 | SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) |
| 1825 | 1747 | SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, |
| 1826 | 1748 | bmc150_accel_runtime_resume, NULL) |
| 1827 | 1749 | }; |
| 1828 | − | |
| 1829 | −static const struct acpi_device_id bmc150_accel_acpi_match[] = { | |
| 1830 | − {"BSBA0150", bmc150}, | |
| 1831 | − {"BMC150A", bmc150}, | |
| 1832 | − {"BMI055A", bmi055}, | |
| 1833 | − {"BMA0255", bma255}, | |
| 1834 | − {"BMA250E", bma250e}, | |
| 1835 | − {"BMA222E", bma222e}, | |
| 1836 | − {"BMA0280", bma280}, | |
| 1837 | − { }, | |
| 1838 | −}; | |
| 1839 | −MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); | |
| 1840 | − | |
| 1841 | −static const struct i2c_device_id bmc150_accel_id[] = { | |
| 1842 | − {"bmc150_accel", bmc150}, | |
| 1843 | − {"bmi055_accel", bmi055}, | |
| 1844 | − {"bma255", bma255}, | |
| 1845 | − {"bma250e", bma250e}, | |
| 1846 | − {"bma222e", bma222e}, | |
| 1847 | − {"bma280", bma280}, | |
| 1848 | − {} | |
| 1849 | −}; | |
| 1850 | − | |
| 1851 | −MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); | |
| 1852 | − | |
| 1853 | −static struct i2c_driver bmc150_accel_driver = { | |
| 1854 | − .driver = { | |
| 1855 | − .name = BMC150_ACCEL_DRV_NAME, | |
| 1856 | − .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), | |
| 1857 | − .pm = &bmc150_accel_pm_ops, | |
| 1858 | − }, | |
| 1859 | − .probe = bmc150_accel_probe, | |
| 1860 | − .remove = bmc150_accel_remove, | |
| 1861 | − .id_table = bmc150_accel_id, | |
| 1862 | −}; | |
| 1863 | −module_i2c_driver(bmc150_accel_driver); | |
| 1750 | +EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops); | |
| 1864 | 1751 | |
| 1865 | 1752 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); |
| 1866 | 1753 | MODULE_LICENSE("GPL v2"); |
| @@ -0,0 +1,102 @@ | ||
| 1 | +/* | |
| 2 | + * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips: | |
| 3 | + * - BMC150 | |
| 4 | + * - BMI055 | |
| 5 | + * - BMA255 | |
| 6 | + * - BMA250E | |
| 7 | + * - BMA222E | |
| 8 | + * - BMA280 | |
| 9 | + * | |
| 10 | + * Copyright (c) 2014, Intel Corporation. | |
| 11 | + * | |
| 12 | + * This program is free software; you can redistribute it and/or modify it | |
| 13 | + * under the terms and conditions of the GNU General Public License, | |
| 14 | + * version 2, as published by the Free Software Foundation. | |
| 15 | + * | |
| 16 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
| 17 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 19 | + * more details. | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <linux/device.h> | |
| 23 | +#include <linux/mod_devicetable.h> | |
| 24 | +#include <linux/i2c.h> | |
| 25 | +#include <linux/module.h> | |
| 26 | +#include <linux/acpi.h> | |
| 27 | +#include <linux/regmap.h> | |
| 28 | + | |
| 29 | +#include "bmc150-accel.h" | |
| 30 | + | |
| 31 | +static const struct regmap_config bmc150_i2c_regmap_conf = { | |
| 32 | + .reg_bits = 8, | |
| 33 | + .val_bits = 8, | |
| 34 | +}; | |
| 35 | + | |
| 36 | +static int bmc150_accel_probe(struct i2c_client *client, | |
| 37 | + const struct i2c_device_id *id) | |
| 38 | +{ | |
| 39 | + struct regmap *regmap; | |
| 40 | + const char *name = NULL; | |
| 41 | + bool block_supported = | |
| 42 | + i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || | |
| 43 | + i2c_check_functionality(client->adapter, | |
| 44 | + I2C_FUNC_SMBUS_READ_I2C_BLOCK); | |
| 45 | + | |
| 46 | + regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf); | |
| 47 | + if (IS_ERR(regmap)) { | |
| 48 | + dev_err(&client->dev, "Failed to initialize i2c regmap\n"); | |
| 49 | + return PTR_ERR(regmap); | |
| 50 | + } | |
| 51 | + | |
| 52 | + if (id) | |
| 53 | + name = id->name; | |
| 54 | + | |
| 55 | + return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, | |
| 56 | + block_supported); | |
| 57 | +} | |
| 58 | + | |
| 59 | +static int bmc150_accel_remove(struct i2c_client *client) | |
| 60 | +{ | |
| 61 | + return bmc150_accel_core_remove(&client->dev); | |
| 62 | +} | |
| 63 | + | |
| 64 | +static const struct acpi_device_id bmc150_accel_acpi_match[] = { | |
| 65 | + {"BSBA0150", bmc150}, | |
| 66 | + {"BMC150A", bmc150}, | |
| 67 | + {"BMI055A", bmi055}, | |
| 68 | + {"BMA0255", bma255}, | |
| 69 | + {"BMA250E", bma250e}, | |
| 70 | + {"BMA222E", bma222e}, | |
| 71 | + {"BMA0280", bma280}, | |
| 72 | + { }, | |
| 73 | +}; | |
| 74 | +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); | |
| 75 | + | |
| 76 | +static const struct i2c_device_id bmc150_accel_id[] = { | |
| 77 | + {"bmc150_accel", bmc150}, | |
| 78 | + {"bmi055_accel", bmi055}, | |
| 79 | + {"bma255", bma255}, | |
| 80 | + {"bma250e", bma250e}, | |
| 81 | + {"bma222e", bma222e}, | |
| 82 | + {"bma280", bma280}, | |
| 83 | + {} | |
| 84 | +}; | |
| 85 | + | |
| 86 | +MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); | |
| 87 | + | |
| 88 | +static struct i2c_driver bmc150_accel_driver = { | |
| 89 | + .driver = { | |
| 90 | + .name = "bmc150_accel_i2c", | |
| 91 | + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), | |
| 92 | + .pm = &bmc150_accel_pm_ops, | |
| 93 | + }, | |
| 94 | + .probe = bmc150_accel_probe, | |
| 95 | + .remove = bmc150_accel_remove, | |
| 96 | + .id_table = bmc150_accel_id, | |
| 97 | +}; | |
| 98 | +module_i2c_driver(bmc150_accel_driver); | |
| 99 | + | |
| 100 | +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | |
| 101 | +MODULE_LICENSE("GPL v2"); | |
| 102 | +MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +/* | |
| 2 | + * 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip | |
| 3 | + * Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License as published by | |
| 7 | + * the Free Software Foundation; either version 2 of the License, or | |
| 8 | + * (at your option) any later version. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + * | |
| 15 | + * You should have received a copy of the GNU General Public License | |
| 16 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#include <linux/device.h> | |
| 20 | +#include <linux/mod_devicetable.h> | |
| 21 | +#include <linux/module.h> | |
| 22 | +#include <linux/acpi.h> | |
| 23 | +#include <linux/regmap.h> | |
| 24 | +#include <linux/spi/spi.h> | |
| 25 | + | |
| 26 | +#include "bmc150-accel.h" | |
| 27 | + | |
| 28 | +static const struct regmap_config bmc150_spi_regmap_conf = { | |
| 29 | + .reg_bits = 8, | |
| 30 | + .val_bits = 8, | |
| 31 | + .max_register = 0x3f, | |
| 32 | +}; | |
| 33 | + | |
| 34 | +static int bmc150_accel_probe(struct spi_device *spi) | |
| 35 | +{ | |
| 36 | + struct regmap *regmap; | |
| 37 | + const struct spi_device_id *id = spi_get_device_id(spi); | |
| 38 | + | |
| 39 | + regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf); | |
| 40 | + if (IS_ERR(regmap)) { | |
| 41 | + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); | |
| 42 | + return PTR_ERR(regmap); | |
| 43 | + } | |
| 44 | + | |
| 45 | + return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name, | |
| 46 | + true); | |
| 47 | +} | |
| 48 | + | |
| 49 | +static int bmc150_accel_remove(struct spi_device *spi) | |
| 50 | +{ | |
| 51 | + return bmc150_accel_core_remove(&spi->dev); | |
| 52 | +} | |
| 53 | + | |
| 54 | +static const struct acpi_device_id bmc150_accel_acpi_match[] = { | |
| 55 | + {"BSBA0150", bmc150}, | |
| 56 | + {"BMC150A", bmc150}, | |
| 57 | + {"BMI055A", bmi055}, | |
| 58 | + {"BMA0255", bma255}, | |
| 59 | + {"BMA250E", bma250e}, | |
| 60 | + {"BMA222E", bma222e}, | |
| 61 | + {"BMA0280", bma280}, | |
| 62 | + { }, | |
| 63 | +}; | |
| 64 | +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); | |
| 65 | + | |
| 66 | +static const struct spi_device_id bmc150_accel_id[] = { | |
| 67 | + {"bmc150_accel", bmc150}, | |
| 68 | + {"bmi055_accel", bmi055}, | |
| 69 | + {"bma255", bma255}, | |
| 70 | + {"bma250e", bma250e}, | |
| 71 | + {"bma222e", bma222e}, | |
| 72 | + {"bma280", bma280}, | |
| 73 | + {} | |
| 74 | +}; | |
| 75 | +MODULE_DEVICE_TABLE(spi, bmc150_accel_id); | |
| 76 | + | |
| 77 | +static struct spi_driver bmc150_accel_driver = { | |
| 78 | + .driver = { | |
| 79 | + .name = "bmc150_accel_spi", | |
| 80 | + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), | |
| 81 | + .pm = &bmc150_accel_pm_ops, | |
| 82 | + }, | |
| 83 | + .probe = bmc150_accel_probe, | |
| 84 | + .remove = bmc150_accel_remove, | |
| 85 | + .id_table = bmc150_accel_id, | |
| 86 | +}; | |
| 87 | +module_spi_driver(bmc150_accel_driver); | |
| 88 | + | |
| 89 | +MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); | |
| 90 | +MODULE_LICENSE("GPL v2"); | |
| 91 | +MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); | |
| @@ -0,0 +1,20 @@ | ||
| 1 | +#ifndef _BMC150_ACCEL_H_ | |
| 2 | +#define _BMC150_ACCEL_H_ | |
| 3 | + | |
| 4 | +struct regmap; | |
| 5 | + | |
| 6 | +enum { | |
| 7 | + bmc150, | |
| 8 | + bmi055, | |
| 9 | + bma255, | |
| 10 | + bma250e, | |
| 11 | + bma222e, | |
| 12 | + bma280, | |
| 13 | +}; | |
| 14 | + | |
| 15 | +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, | |
| 16 | + const char *name, bool block_supported); | |
| 17 | +int bmc150_accel_core_remove(struct device *dev); | |
| 18 | +extern const struct dev_pm_ops bmc150_accel_pm_ops; | |
| 19 | + | |
| 20 | +#endif /* _BMC150_ACCEL_H_ */ | |
| @@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, · 1161 unmodified lines | ||
| 1162 | 1162 | return dev_name(dev); |
| 1163 | 1163 | } |
| 1164 | 1164 | |
| 1165 | −static int kxcjk1013_gpio_probe(struct i2c_client *client, | |
| 1166 | − struct kxcjk1013_data *data) | |
| 1167 | −{ | |
| 1168 | − struct device *dev; | |
| 1169 | − struct gpio_desc *gpio; | |
| 1170 | − int ret; | |
| 1171 | − | |
| 1172 | − if (!client) | |
| 1173 | − return -EINVAL; | |
| 1174 | − | |
| 1175 | − if (data->is_smo8500_device) | |
| 1176 | − return -ENOTSUPP; | |
| 1177 | − | |
| 1178 | − dev = &client->dev; | |
| 1179 | − | |
| 1180 | − /* data ready gpio interrupt pin */ | |
| 1181 | − gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN); | |
| 1182 | − if (IS_ERR(gpio)) { | |
| 1183 | − dev_err(dev, "acpi gpio get index failed\n"); | |
| 1184 | − return PTR_ERR(gpio); | |
| 1185 | − } | |
| 1186 | − | |
| 1187 | − ret = gpiod_to_irq(gpio); | |
| 1188 | − | |
| 1189 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 1190 | − | |
| 1191 | − return ret; | |
| 1192 | −} | |
| 1193 | − | |
| 1194 | 1165 | static int kxcjk1013_probe(struct i2c_client *client, |
| 1195 | 1166 | const struct i2c_device_id *id) |
| 1196 | 1167 | { |
| @@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client, · 40 unmodified lines | ||
| 1237 | 1208 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 1238 | 1209 | indio_dev->info = &kxcjk1013_info; |
| 1239 | 1210 | |
| 1240 | − if (client->irq < 0) | |
| 1241 | − client->irq = kxcjk1013_gpio_probe(client, data); | |
| 1242 | − | |
| 1243 | − if (client->irq > 0) { | |
| 1211 | + if (client->irq > 0 && !data->is_smo8500_device) { | |
| 1244 | 1212 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 1245 | 1213 | kxcjk1013_data_rdy_trig_poll, |
| 1246 | 1214 | kxcjk1013_event_handler, |
| @@ -1,6 +1,12 @@ | ||
| 1 | 1 | /* |
| 2 | − * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer | |
| 2 | + * mma8452.c - Support for following Freescale 3-axis accelerometers: | |
| 3 | 3 | * |
| 4 | + * MMA8452Q (12 bit) | |
| 5 | + * MMA8453Q (10 bit) | |
| 6 | + * MMA8652FC (12 bit) | |
| 7 | + * MMA8653FC (10 bit) | |
| 8 | + * | |
| 9 | + * Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com> | |
| 4 | 10 | * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> |
| 5 | 11 | * |
| 6 | 12 | * This file is subject to the terms and conditions of version 2 of |
| @@ -22,10 +28,11 @@ · 15 unmodified lines | ||
| 22 | 28 | #include <linux/iio/triggered_buffer.h> |
| 23 | 29 | #include <linux/iio/events.h> |
| 24 | 30 | #include <linux/delay.h> |
| 31 | +#include <linux/of_device.h> | |
| 25 | 32 | |
| 26 | 33 | #define MMA8452_STATUS 0x00 |
| 27 | 34 | #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) |
| 28 | −#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ | |
| 35 | +#define MMA8452_OUT_X 0x01 /* MSB first */ | |
| 29 | 36 | #define MMA8452_OUT_Y 0x03 |
| 30 | 37 | #define MMA8452_OUT_Z 0x05 |
| 31 | 38 | #define MMA8452_INT_SRC 0x0c |
| @@ -38,6 +45,16 @@ · 6 unmodified lines | ||
| 38 | 45 | #define MMA8452_DATA_CFG_HPF_MASK BIT(4) |
| 39 | 46 | #define MMA8452_HP_FILTER_CUTOFF 0x0f |
| 40 | 47 | #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) |
| 48 | +#define MMA8452_FF_MT_CFG 0x15 | |
| 49 | +#define MMA8452_FF_MT_CFG_OAE BIT(6) | |
| 50 | +#define MMA8452_FF_MT_CFG_ELE BIT(7) | |
| 51 | +#define MMA8452_FF_MT_SRC 0x16 | |
| 52 | +#define MMA8452_FF_MT_SRC_XHE BIT(1) | |
| 53 | +#define MMA8452_FF_MT_SRC_YHE BIT(3) | |
| 54 | +#define MMA8452_FF_MT_SRC_ZHE BIT(5) | |
| 55 | +#define MMA8452_FF_MT_THS 0x17 | |
| 56 | +#define MMA8452_FF_MT_THS_MASK 0x7f | |
| 57 | +#define MMA8452_FF_MT_COUNT 0x18 | |
| 41 | 58 | #define MMA8452_TRANSIENT_CFG 0x1d |
| 42 | 59 | #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) |
| 43 | 60 | #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) |
| @@ -65,15 +82,65 @@ · 21 unmodified lines | ||
| 65 | 82 | #define MMA8452_MAX_REG 0x31 |
| 66 | 83 | |
| 67 | 84 | #define MMA8452_INT_DRDY BIT(0) |
| 85 | +#define MMA8452_INT_FF_MT BIT(2) | |
| 68 | 86 | #define MMA8452_INT_TRANS BIT(5) |
| 69 | 87 | |
| 70 | 88 | #define MMA8452_DEVICE_ID 0x2a |
| 89 | +#define MMA8453_DEVICE_ID 0x3a | |
| 90 | +#define MMA8652_DEVICE_ID 0x4a | |
| 91 | +#define MMA8653_DEVICE_ID 0x5a | |
| 71 | 92 | |
| 72 | 93 | struct mma8452_data { |
| 73 | 94 | struct i2c_client *client; |
| 74 | 95 | struct mutex lock; |
| 75 | 96 | u8 ctrl_reg1; |
| 76 | 97 | u8 data_cfg; |
| 98 | + const struct mma_chip_info *chip_info; | |
| 99 | +}; | |
| 100 | + | |
| 101 | +/** | |
| 102 | + * struct mma_chip_info - chip specific data for Freescale's accelerometers | |
| 103 | + * @chip_id: WHO_AM_I register's value | |
| 104 | + * @channels: struct iio_chan_spec matching the device's | |
| 105 | + * capabilities | |
| 106 | + * @num_channels: number of channels | |
| 107 | + * @mma_scales: scale factors for converting register values | |
| 108 | + * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers | |
| 109 | + * per mode: m/s^2 and micro m/s^2 | |
| 110 | + * @ev_cfg: event config register address | |
| 111 | + * @ev_cfg_ele: latch bit in event config register | |
| 112 | + * @ev_cfg_chan_shift: number of the bit to enable events in X | |
| 113 | + * direction; in event config register | |
| 114 | + * @ev_src: event source register address | |
| 115 | + * @ev_src_xe: bit in event source register that indicates | |
| 116 | + * an event in X direction | |
| 117 | + * @ev_src_ye: bit in event source register that indicates | |
| 118 | + * an event in Y direction | |
| 119 | + * @ev_src_ze: bit in event source register that indicates | |
| 120 | + * an event in Z direction | |
| 121 | + * @ev_ths: event threshold register address | |
| 122 | + * @ev_ths_mask: mask for the threshold value | |
| 123 | + * @ev_count: event count (period) register address | |
| 124 | + * | |
| 125 | + * Since not all chips supported by the driver support comparing high pass | |
| 126 | + * filtered data for events (interrupts), different interrupt sources are | |
| 127 | + * used for different chips and the relevant registers are included here. | |
| 128 | + */ | |
| 129 | +struct mma_chip_info { | |
| 130 | + u8 chip_id; | |
| 131 | + const struct iio_chan_spec *channels; | |
| 132 | + int num_channels; | |
| 133 | + const int mma_scales[3][2]; | |
| 134 | + u8 ev_cfg; | |
| 135 | + u8 ev_cfg_ele; | |
| 136 | + u8 ev_cfg_chan_shift; | |
| 137 | + u8 ev_src; | |
| 138 | + u8 ev_src_xe; | |
| 139 | + u8 ev_src_ye; | |
| 140 | + u8 ev_src_ze; | |
| 141 | + u8 ev_ths; | |
| 142 | + u8 ev_ths_mask; | |
| 143 | + u8 ev_count; | |
| 77 | 144 | }; |
| 78 | 145 | |
| 79 | 146 | static int mma8452_drdy(struct mma8452_data *data) |
| @@ -143,16 +210,6 @@ static const int mma8452_samp_freq[8][2] = { · 63 unmodified lines | ||
| 143 | 210 | {6, 250000}, {1, 560000} |
| 144 | 211 | }; |
| 145 | 212 | |
| 146 | −/* | |
| 147 | − * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 | |
| 148 | − * The userspace interface uses m/s^2 and we declare micro units | |
| 149 | − * So scale factor is given by: | |
| 150 | − * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 | |
| 151 | − */ | |
| 152 | −static const int mma8452_scales[3][2] = { | |
| 153 | − {0, 9577}, {0, 19154}, {0, 38307} | |
| 154 | −}; | |
| 155 | − | |
| 156 | 213 | /* Datasheet table 35 (step time vs sample frequency) */ |
| 157 | 214 | static const int mma8452_transient_time_step_us[8] = { |
| 158 | 215 | 1250, |
| @@ -189,8 +246,11 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, · 30 unmodified lines | ||
| 189 | 246 | struct device_attribute *attr, |
| 190 | 247 | char *buf) |
| 191 | 248 | { |
| 192 | − return mma8452_show_int_plus_micros(buf, mma8452_scales, | |
| 193 | − ARRAY_SIZE(mma8452_scales)); | |
| 249 | + struct mma8452_data *data = iio_priv(i2c_get_clientdata( | |
| 250 | + to_i2c_client(dev))); | |
| 251 | + | |
| 252 | + return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, | |
| 253 | + ARRAY_SIZE(data->chip_info->mma_scales)); | |
| 194 | 254 | } |
| 195 | 255 | |
| 196 | 256 | static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, |
| @@ -221,9 +281,8 @@ static int mma8452_get_samp_freq_index(struct mma8452_data *data, · 24 unmodified lines | ||
| 221 | 281 | |
| 222 | 282 | static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) |
| 223 | 283 | { |
| 224 | − return mma8452_get_int_plus_micros_index(mma8452_scales, | |
| 225 | − ARRAY_SIZE(mma8452_scales), | |
| 226 | − val, val2); | |
| 284 | + return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, | |
| 285 | + ARRAY_SIZE(data->chip_info->mma_scales), val, val2); | |
| 227 | 286 | } |
| 228 | 287 | |
| 229 | 288 | static int mma8452_get_hp_filter_index(struct mma8452_data *data, |
| @@ -270,14 +329,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, · 40 unmodified lines | ||
| 270 | 329 | if (ret < 0) |
| 271 | 330 | return ret; |
| 272 | 331 | |
| 273 | − *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, | |
| 274 | − 11); | |
| 332 | + *val = sign_extend32(be16_to_cpu( | |
| 333 | + buffer[chan->scan_index]) >> chan->scan_type.shift, | |
| 334 | + chan->scan_type.realbits - 1); | |
| 275 | 335 | |
| 276 | 336 | return IIO_VAL_INT; |
| 277 | 337 | case IIO_CHAN_INFO_SCALE: |
| 278 | 338 | i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; |
| 279 | − *val = mma8452_scales[i][0]; | |
| 280 | − *val2 = mma8452_scales[i][1]; | |
| 339 | + *val = data->chip_info->mma_scales[i][0]; | |
| 340 | + *val2 = data->chip_info->mma_scales[i][1]; | |
| 281 | 341 | |
| 282 | 342 | return IIO_VAL_INT_PLUS_MICRO; |
| 283 | 343 | case IIO_CHAN_INFO_SAMP_FREQ: |
| @@ -439,17 +499,17 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, · 155 unmodified lines | ||
| 439 | 499 | switch (info) { |
| 440 | 500 | case IIO_EV_INFO_VALUE: |
| 441 | 501 | ret = i2c_smbus_read_byte_data(data->client, |
| 442 | − MMA8452_TRANSIENT_THS); | |
| 502 | + data->chip_info->ev_ths); | |
| 443 | 503 | if (ret < 0) |
| 444 | 504 | return ret; |
| 445 | 505 | |
| 446 | − *val = ret & MMA8452_TRANSIENT_THS_MASK; | |
| 506 | + *val = ret & data->chip_info->ev_ths_mask; | |
| 447 | 507 | |
| 448 | 508 | return IIO_VAL_INT; |
| 449 | 509 | |
| 450 | 510 | case IIO_EV_INFO_PERIOD: |
| 451 | 511 | ret = i2c_smbus_read_byte_data(data->client, |
| 452 | − MMA8452_TRANSIENT_COUNT); | |
| 512 | + data->chip_info->ev_count); | |
| 453 | 513 | if (ret < 0) |
| 454 | 514 | return ret; |
| 455 | 515 | |
| @@ -497,7 +557,8 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, · 41 unmodified lines | ||
| 497 | 557 | if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) |
| 498 | 558 | return -EINVAL; |
| 499 | 559 | |
| 500 | − return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); | |
| 560 | + return mma8452_change_config(data, data->chip_info->ev_ths, | |
| 561 | + val); | |
| 501 | 562 | |
| 502 | 563 | case IIO_EV_INFO_PERIOD: |
| 503 | 564 | steps = (val * USEC_PER_SEC + val2) / |
| @@ -507,7 +568,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, · 3 unmodified lines | ||
| 507 | 568 | if (steps < 0 || steps > 0xff) |
| 508 | 569 | return -EINVAL; |
| 509 | 570 | |
| 510 | − return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, | |
| 571 | + return mma8452_change_config(data, data->chip_info->ev_count, | |
| 511 | 572 | steps); |
| 512 | 573 | |
| 513 | 574 | case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: |
| @@ -538,13 +599,15 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev, · 24 unmodified lines | ||
| 538 | 599 | enum iio_event_direction dir) |
| 539 | 600 | { |
| 540 | 601 | struct mma8452_data *data = iio_priv(indio_dev); |
| 602 | + const struct mma_chip_info *chip = data->chip_info; | |
| 541 | 603 | int ret; |
| 542 | 604 | |
| 543 | − ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); | |
| 605 | + ret = i2c_smbus_read_byte_data(data->client, | |
| 606 | + data->chip_info->ev_cfg); | |
| 544 | 607 | if (ret < 0) |
| 545 | 608 | return ret; |
| 546 | 609 | |
| 547 | − return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0; | |
| 610 | + return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift)); | |
| 548 | 611 | } |
| 549 | 612 | |
| 550 | 613 | static int mma8452_write_event_config(struct iio_dev *indio_dev, |
| @@ -554,20 +617,22 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, · 3 unmodified lines | ||
| 554 | 617 | int state) |
| 555 | 618 | { |
| 556 | 619 | struct mma8452_data *data = iio_priv(indio_dev); |
| 620 | + const struct mma_chip_info *chip = data->chip_info; | |
| 557 | 621 | int val; |
| 558 | 622 | |
| 559 | − val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); | |
| 623 | + val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg); | |
| 560 | 624 | if (val < 0) |
| 561 | 625 | return val; |
| 562 | 626 | |
| 563 | 627 | if (state) |
| 564 | − val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); | |
| 628 | + val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift); | |
| 565 | 629 | else |
| 566 | − val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); | |
| 630 | + val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift); | |
| 567 | 631 | |
| 568 | − val |= MMA8452_TRANSIENT_CFG_ELE; | |
| 632 | + val |= chip->ev_cfg_ele; | |
| 633 | + val |= MMA8452_FF_MT_CFG_OAE; | |
| 569 | 634 | |
| 570 | − return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val); | |
| 635 | + return mma8452_change_config(data, chip->ev_cfg, val); | |
| 571 | 636 | } |
| 572 | 637 | |
| 573 | 638 | static void mma8452_transient_interrupt(struct iio_dev *indio_dev) |
| @@ -576,25 +641,25 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev) · 2 unmodified lines | ||
| 576 | 641 | s64 ts = iio_get_time_ns(); |
| 577 | 642 | int src; |
| 578 | 643 | |
| 579 | − src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); | |
| 644 | + src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); | |
| 580 | 645 | if (src < 0) |
| 581 | 646 | return; |
| 582 | 647 | |
| 583 | − if (src & MMA8452_TRANSIENT_SRC_XTRANSE) | |
| 648 | + if (src & data->chip_info->ev_src_xe) | |
| 584 | 649 | iio_push_event(indio_dev, |
| 585 | 650 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, |
| 586 | 651 | IIO_EV_TYPE_MAG, |
| 587 | 652 | IIO_EV_DIR_RISING), |
| 588 | 653 | ts); |
| 589 | 654 | |
| 590 | − if (src & MMA8452_TRANSIENT_SRC_YTRANSE) | |
| 655 | + if (src & data->chip_info->ev_src_ye) | |
| 591 | 656 | iio_push_event(indio_dev, |
| 592 | 657 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, |
| 593 | 658 | IIO_EV_TYPE_MAG, |
| 594 | 659 | IIO_EV_DIR_RISING), |
| 595 | 660 | ts); |
| 596 | 661 | |
| 597 | − if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) | |
| 662 | + if (src & data->chip_info->ev_src_ze) | |
| 598 | 663 | iio_push_event(indio_dev, |
| 599 | 664 | IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, |
| 600 | 665 | IIO_EV_TYPE_MAG, |
| @@ -606,6 +671,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) · 5 unmodified lines | ||
| 606 | 671 | { |
| 607 | 672 | struct iio_dev *indio_dev = p; |
| 608 | 673 | struct mma8452_data *data = iio_priv(indio_dev); |
| 674 | + const struct mma_chip_info *chip = data->chip_info; | |
| 609 | 675 | int ret = IRQ_NONE; |
| 610 | 676 | int src; |
| 611 | 677 | |
| @@ -618,7 +684,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) · 6 unmodified lines | ||
| 618 | 684 | ret = IRQ_HANDLED; |
| 619 | 685 | } |
| 620 | 686 | |
| 621 | − if (src & MMA8452_INT_TRANS) { | |
| 687 | + if ((src & MMA8452_INT_TRANS && | |
| 688 | + chip->ev_src == MMA8452_TRANSIENT_SRC) || | |
| 689 | + (src & MMA8452_INT_FF_MT && | |
| 690 | + chip->ev_src == MMA8452_FF_MT_SRC)) { | |
| 622 | 691 | mma8452_transient_interrupt(indio_dev); |
| 623 | 692 | ret = IRQ_HANDLED; |
| 624 | 693 | } |
| @@ -680,6 +749,16 @@ static const struct iio_event_spec mma8452_transient_event[] = { · 55 unmodified lines | ||
| 680 | 749 | }, |
| 681 | 750 | }; |
| 682 | 751 | |
| 752 | +static const struct iio_event_spec mma8452_motion_event[] = { | |
| 753 | + { | |
| 754 | + .type = IIO_EV_TYPE_MAG, | |
| 755 | + .dir = IIO_EV_DIR_RISING, | |
| 756 | + .mask_separate = BIT(IIO_EV_INFO_ENABLE), | |
| 757 | + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | | |
| 758 | + BIT(IIO_EV_INFO_PERIOD) | |
| 759 | + }, | |
| 760 | +}; | |
| 761 | + | |
| 683 | 762 | /* |
| 684 | 763 | * Threshold is configured in fixed 8G/127 steps regardless of |
| 685 | 764 | * currently selected scale for measurement. |
| @@ -693,10 +772,9 @@ static struct attribute *mma8452_event_attributes[] = { · 7 unmodified lines | ||
| 693 | 772 | |
| 694 | 773 | static struct attribute_group mma8452_event_attribute_group = { |
| 695 | 774 | .attrs = mma8452_event_attributes, |
| 696 | − .name = "events", | |
| 697 | 775 | }; |
| 698 | 776 | |
| 699 | −#define MMA8452_CHANNEL(axis, idx) { \ | |
| 777 | +#define MMA8452_CHANNEL(axis, idx, bits) { \ | |
| 700 | 778 | .type = IIO_ACCEL, \ |
| 701 | 779 | .modified = 1, \ |
| 702 | 780 | .channel2 = IIO_MOD_##axis, \ |
| @@ -708,22 +786,144 @@ static struct attribute_group mma8452_event_attribute_group = { · 5 unmodified lines | ||
| 708 | 786 | .scan_index = idx, \ |
| 709 | 787 | .scan_type = { \ |
| 710 | 788 | .sign = 's', \ |
| 711 | − .realbits = 12, \ | |
| 789 | + .realbits = (bits), \ | |
| 712 | 790 | .storagebits = 16, \ |
| 713 | − .shift = 4, \ | |
| 791 | + .shift = 16 - (bits), \ | |
| 714 | 792 | .endianness = IIO_BE, \ |
| 715 | 793 | }, \ |
| 716 | 794 | .event_spec = mma8452_transient_event, \ |
| 717 | 795 | .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ |
| 718 | 796 | } |
| 719 | 797 | |
| 798 | +#define MMA8652_CHANNEL(axis, idx, bits) { \ | |
| 799 | + .type = IIO_ACCEL, \ | |
| 800 | + .modified = 1, \ | |
| 801 | + .channel2 = IIO_MOD_##axis, \ | |
| 802 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | |
| 803 | + BIT(IIO_CHAN_INFO_CALIBBIAS), \ | |
| 804 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ | |
| 805 | + BIT(IIO_CHAN_INFO_SCALE), \ | |
| 806 | + .scan_index = idx, \ | |
| 807 | + .scan_type = { \ | |
| 808 | + .sign = 's', \ | |
| 809 | + .realbits = (bits), \ | |
| 810 | + .storagebits = 16, \ | |
| 811 | + .shift = 16 - (bits), \ | |
| 812 | + .endianness = IIO_BE, \ | |
| 813 | + }, \ | |
| 814 | + .event_spec = mma8452_motion_event, \ | |
| 815 | + .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ | |
| 816 | +} | |
| 817 | + | |
| 720 | 818 | static const struct iio_chan_spec mma8452_channels[] = { |
| 721 | − MMA8452_CHANNEL(X, 0), | |
| 722 | − MMA8452_CHANNEL(Y, 1), | |
| 723 | − MMA8452_CHANNEL(Z, 2), | |
| 819 | + MMA8452_CHANNEL(X, 0, 12), | |
| 820 | + MMA8452_CHANNEL(Y, 1, 12), | |
| 821 | + MMA8452_CHANNEL(Z, 2, 12), | |
| 724 | 822 | IIO_CHAN_SOFT_TIMESTAMP(3), |
| 725 | 823 | }; |
| 726 | 824 | |
| 825 | +static const struct iio_chan_spec mma8453_channels[] = { | |
| 826 | + MMA8452_CHANNEL(X, 0, 10), | |
| 827 | + MMA8452_CHANNEL(Y, 1, 10), | |
| 828 | + MMA8452_CHANNEL(Z, 2, 10), | |
| 829 | + IIO_CHAN_SOFT_TIMESTAMP(3), | |
| 830 | +}; | |
| 831 | + | |
| 832 | +static const struct iio_chan_spec mma8652_channels[] = { | |
| 833 | + MMA8652_CHANNEL(X, 0, 12), | |
| 834 | + MMA8652_CHANNEL(Y, 1, 12), | |
| 835 | + MMA8652_CHANNEL(Z, 2, 12), | |
| 836 | + IIO_CHAN_SOFT_TIMESTAMP(3), | |
| 837 | +}; | |
| 838 | + | |
| 839 | +static const struct iio_chan_spec mma8653_channels[] = { | |
| 840 | + MMA8652_CHANNEL(X, 0, 10), | |
| 841 | + MMA8652_CHANNEL(Y, 1, 10), | |
| 842 | + MMA8652_CHANNEL(Z, 2, 10), | |
| 843 | + IIO_CHAN_SOFT_TIMESTAMP(3), | |
| 844 | +}; | |
| 845 | + | |
| 846 | +enum { | |
| 847 | + mma8452, | |
| 848 | + mma8453, | |
| 849 | + mma8652, | |
| 850 | + mma8653, | |
| 851 | +}; | |
| 852 | + | |
| 853 | +static const struct mma_chip_info mma_chip_info_table[] = { | |
| 854 | + [mma8452] = { | |
| 855 | + .chip_id = MMA8452_DEVICE_ID, | |
| 856 | + .channels = mma8452_channels, | |
| 857 | + .num_channels = ARRAY_SIZE(mma8452_channels), | |
| 858 | + /* | |
| 859 | + * Hardware has fullscale of -2G, -4G, -8G corresponding to | |
| 860 | + * raw value -2048 for 12 bit or -512 for 10 bit. | |
| 861 | + * The userspace interface uses m/s^2 and we declare micro units | |
| 862 | + * So scale factor for 12 bit here is given by: | |
| 863 | + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 | |
| 864 | + */ | |
| 865 | + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, | |
| 866 | + .ev_cfg = MMA8452_TRANSIENT_CFG, | |
| 867 | + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, | |
| 868 | + .ev_cfg_chan_shift = 1, | |
| 869 | + .ev_src = MMA8452_TRANSIENT_SRC, | |
| 870 | + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, | |
| 871 | + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, | |
| 872 | + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, | |
| 873 | + .ev_ths = MMA8452_TRANSIENT_THS, | |
| 874 | + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, | |
| 875 | + .ev_count = MMA8452_TRANSIENT_COUNT, | |
| 876 | + }, | |
| 877 | + [mma8453] = { | |
| 878 | + .chip_id = MMA8453_DEVICE_ID, | |
| 879 | + .channels = mma8453_channels, | |
| 880 | + .num_channels = ARRAY_SIZE(mma8453_channels), | |
| 881 | + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, | |
| 882 | + .ev_cfg = MMA8452_TRANSIENT_CFG, | |
| 883 | + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, | |
| 884 | + .ev_cfg_chan_shift = 1, | |
| 885 | + .ev_src = MMA8452_TRANSIENT_SRC, | |
| 886 | + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, | |
| 887 | + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, | |
| 888 | + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, | |
| 889 | + .ev_ths = MMA8452_TRANSIENT_THS, | |
| 890 | + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, | |
| 891 | + .ev_count = MMA8452_TRANSIENT_COUNT, | |
| 892 | + }, | |
| 893 | + [mma8652] = { | |
| 894 | + .chip_id = MMA8652_DEVICE_ID, | |
| 895 | + .channels = mma8652_channels, | |
| 896 | + .num_channels = ARRAY_SIZE(mma8652_channels), | |
| 897 | + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, | |
| 898 | + .ev_cfg = MMA8452_FF_MT_CFG, | |
| 899 | + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, | |
| 900 | + .ev_cfg_chan_shift = 3, | |
| 901 | + .ev_src = MMA8452_FF_MT_SRC, | |
| 902 | + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, | |
| 903 | + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, | |
| 904 | + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, | |
| 905 | + .ev_ths = MMA8452_FF_MT_THS, | |
| 906 | + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, | |
| 907 | + .ev_count = MMA8452_FF_MT_COUNT, | |
| 908 | + }, | |
| 909 | + [mma8653] = { | |
| 910 | + .chip_id = MMA8653_DEVICE_ID, | |
| 911 | + .channels = mma8653_channels, | |
| 912 | + .num_channels = ARRAY_SIZE(mma8653_channels), | |
| 913 | + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, | |
| 914 | + .ev_cfg = MMA8452_FF_MT_CFG, | |
| 915 | + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, | |
| 916 | + .ev_cfg_chan_shift = 3, | |
| 917 | + .ev_src = MMA8452_FF_MT_SRC, | |
| 918 | + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, | |
| 919 | + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, | |
| 920 | + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, | |
| 921 | + .ev_ths = MMA8452_FF_MT_THS, | |
| 922 | + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, | |
| 923 | + .ev_count = MMA8452_FF_MT_COUNT, | |
| 924 | + }, | |
| 925 | +}; | |
| 926 | + | |
| 727 | 927 | static struct attribute *mma8452_attributes[] = { |
| 728 | 928 | &iio_dev_attr_sampling_frequency_available.dev_attr.attr, |
| 729 | 929 | &iio_dev_attr_in_accel_scale_available.dev_attr.attr, |
| @@ -841,18 +1041,28 @@ static int mma8452_reset(struct i2c_client *client) · 111 unmodified lines | ||
| 841 | 1041 | return -ETIMEDOUT; |
| 842 | 1042 | } |
| 843 | 1043 | |
| 1044 | +static const struct of_device_id mma8452_dt_ids[] = { | |
| 1045 | + { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, | |
| 1046 | + { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, | |
| 1047 | + { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, | |
| 1048 | + { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, | |
| 1049 | + { } | |
| 1050 | +}; | |
| 1051 | +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); | |
| 1052 | + | |
| 844 | 1053 | static int mma8452_probe(struct i2c_client *client, |
| 845 | 1054 | const struct i2c_device_id *id) |
| 846 | 1055 | { |
| 847 | 1056 | struct mma8452_data *data; |
| 848 | 1057 | struct iio_dev *indio_dev; |
| 849 | 1058 | int ret; |
| 1059 | + const struct of_device_id *match; | |
| 850 | 1060 | |
| 851 | − ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); | |
| 852 | − if (ret < 0) | |
| 853 | − return ret; | |
| 854 | − if (ret != MMA8452_DEVICE_ID) | |
| 1061 | + match = of_match_device(mma8452_dt_ids, &client->dev); | |
| 1062 | + if (!match) { | |
| 1063 | + dev_err(&client->dev, "unknown device model\n"); | |
| 855 | 1064 | return -ENODEV; |
| 1065 | + } | |
| 856 | 1066 | |
| 857 | 1067 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
| 858 | 1068 | if (!indio_dev) |
| @@ -861,14 +1071,33 @@ static int mma8452_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 861 | 1071 | data = iio_priv(indio_dev); |
| 862 | 1072 | data->client = client; |
| 863 | 1073 | mutex_init(&data->lock); |
| 1074 | + data->chip_info = match->data; | |
| 1075 | + | |
| 1076 | + ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); | |
| 1077 | + if (ret < 0) | |
| 1078 | + return ret; | |
| 1079 | + | |
| 1080 | + switch (ret) { | |
| 1081 | + case MMA8452_DEVICE_ID: | |
| 1082 | + case MMA8453_DEVICE_ID: | |
| 1083 | + case MMA8652_DEVICE_ID: | |
| 1084 | + case MMA8653_DEVICE_ID: | |
| 1085 | + if (ret == data->chip_info->chip_id) | |
| 1086 | + break; | |
| 1087 | + default: | |
| 1088 | + return -ENODEV; | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", | |
| 1092 | + match->compatible, data->chip_info->chip_id); | |
| 864 | 1093 | |
| 865 | 1094 | i2c_set_clientdata(client, indio_dev); |
| 866 | 1095 | indio_dev->info = &mma8452_info; |
| 867 | 1096 | indio_dev->name = id->name; |
| 868 | 1097 | indio_dev->dev.parent = &client->dev; |
| 869 | 1098 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 870 | − indio_dev->channels = mma8452_channels; | |
| 871 | − indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); | |
| 1099 | + indio_dev->channels = data->chip_info->channels; | |
| 1100 | + indio_dev->num_channels = data->chip_info->num_channels; | |
| 872 | 1101 | indio_dev->available_scan_masks = mma8452_scan_masks; |
| 873 | 1102 | |
| 874 | 1103 | ret = mma8452_reset(client); |
| @@ -892,13 +1121,15 @@ static int mma8452_probe(struct i2c_client *client, · 17 unmodified lines | ||
| 892 | 1121 | |
| 893 | 1122 | if (client->irq) { |
| 894 | 1123 | /* |
| 895 | − * Although we enable the transient interrupt source once and | |
| 896 | − * for all here the transient event detection itself is not | |
| 897 | − * enabled until userspace asks for it by | |
| 898 | − * mma8452_write_event_config() | |
| 1124 | + * Although we enable the interrupt sources once and for | |
| 1125 | + * all here the event detection itself is not enabled until | |
| 1126 | + * userspace asks for it by mma8452_write_event_config() | |
| 899 | 1127 | */ |
| 900 | − int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS; | |
| 901 | − int enabled_interrupts = MMA8452_INT_TRANS; | |
| 1128 | + int supported_interrupts = MMA8452_INT_DRDY | | |
| 1129 | + MMA8452_INT_TRANS | | |
| 1130 | + MMA8452_INT_FF_MT; | |
| 1131 | + int enabled_interrupts = MMA8452_INT_TRANS | | |
| 1132 | + MMA8452_INT_FF_MT; | |
| 902 | 1133 | |
| 903 | 1134 | /* Assume wired to INT1 pin */ |
| 904 | 1135 | ret = i2c_smbus_write_byte_data(client, |
| @@ -987,17 +1218,14 @@ static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); · 82 unmodified lines | ||
| 987 | 1218 | #endif |
| 988 | 1219 | |
| 989 | 1220 | static const struct i2c_device_id mma8452_id[] = { |
| 990 | − { "mma8452", 0 }, | |
| 1221 | + { "mma8452", mma8452 }, | |
| 1222 | + { "mma8453", mma8453 }, | |
| 1223 | + { "mma8652", mma8652 }, | |
| 1224 | + { "mma8653", mma8653 }, | |
| 991 | 1225 | { } |
| 992 | 1226 | }; |
| 993 | 1227 | MODULE_DEVICE_TABLE(i2c, mma8452_id); |
| 994 | 1228 | |
| 995 | −static const struct of_device_id mma8452_dt_ids[] = { | |
| 996 | − { .compatible = "fsl,mma8452" }, | |
| 997 | − { } | |
| 998 | −}; | |
| 999 | −MODULE_DEVICE_TABLE(of, mma8452_dt_ids); | |
| 1000 | − | |
| 1001 | 1229 | static struct i2c_driver mma8452_driver = { |
| 1002 | 1230 | .driver = { |
| 1003 | 1231 | .name = "mma8452", |
| @@ -26,7 +26,6 @@ · 25 unmodified lines | ||
| 26 | 26 | |
| 27 | 27 | #define MMA9553_DRV_NAME "mma9553" |
| 28 | 28 | #define MMA9553_IRQ_NAME "mma9553_event" |
| 29 | −#define MMA9553_GPIO_NAME "mma9553_int" | |
| 30 | 29 | |
| 31 | 30 | /* Pedometer configuration registers (R/W) */ |
| 32 | 31 | #define MMA9553_REG_CONF_SLEEPMIN 0x00 |
| @@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) · 1040 unmodified lines | ||
| 1073 | 1072 | return IRQ_HANDLED; |
| 1074 | 1073 | } |
| 1075 | 1074 | |
| 1076 | −static int mma9553_gpio_probe(struct i2c_client *client) | |
| 1077 | −{ | |
| 1078 | − struct device *dev; | |
| 1079 | − struct gpio_desc *gpio; | |
| 1080 | − int ret; | |
| 1081 | − | |
| 1082 | − if (!client) | |
| 1083 | − return -EINVAL; | |
| 1084 | − | |
| 1085 | − dev = &client->dev; | |
| 1086 | − | |
| 1087 | − /* data ready GPIO interrupt pin */ | |
| 1088 | − gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN); | |
| 1089 | − if (IS_ERR(gpio)) { | |
| 1090 | − dev_err(dev, "ACPI GPIO get index failed\n"); | |
| 1091 | − return PTR_ERR(gpio); | |
| 1092 | − } | |
| 1093 | − | |
| 1094 | − ret = gpiod_to_irq(gpio); | |
| 1095 | − | |
| 1096 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 1097 | − | |
| 1098 | − return ret; | |
| 1099 | −} | |
| 1100 | − | |
| 1101 | 1075 | static const char *mma9553_match_acpi_device(struct device *dev) |
| 1102 | 1076 | { |
| 1103 | 1077 | const struct acpi_device_id *id; |
| @@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client, · 42 unmodified lines | ||
| 1146 | 1120 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 1147 | 1121 | indio_dev->info = &mma9553_info; |
| 1148 | 1122 | |
| 1149 | − if (client->irq < 0) | |
| 1150 | − client->irq = mma9553_gpio_probe(client); | |
| 1151 | − | |
| 1152 | 1123 | if (client->irq > 0) { |
| 1153 | 1124 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 1154 | 1125 | mma9553_irq_handler, |
| @@ -0,0 +1,567 @@ | ||
| 1 | +/* | |
| 2 | + * 3-axis accelerometer driver for MXC4005XC Memsic sensor | |
| 3 | + * | |
| 4 | + * Copyright (c) 2014, Intel Corporation. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify it | |
| 7 | + * under the terms and conditions of the GNU General Public License, | |
| 8 | + * version 2, as published by the Free Software Foundation. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
| 11 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 12 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 13 | + * more details. | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/i2c.h> | |
| 18 | +#include <linux/iio/iio.h> | |
| 19 | +#include <linux/acpi.h> | |
| 20 | +#include <linux/gpio/consumer.h> | |
| 21 | +#include <linux/regmap.h> | |
| 22 | +#include <linux/iio/sysfs.h> | |
| 23 | +#include <linux/iio/trigger.h> | |
| 24 | +#include <linux/iio/buffer.h> | |
| 25 | +#include <linux/iio/triggered_buffer.h> | |
| 26 | +#include <linux/iio/trigger_consumer.h> | |
| 27 | + | |
| 28 | +#define MXC4005_DRV_NAME "mxc4005" | |
| 29 | +#define MXC4005_IRQ_NAME "mxc4005_event" | |
| 30 | +#define MXC4005_REGMAP_NAME "mxc4005_regmap" | |
| 31 | + | |
| 32 | +#define MXC4005_REG_XOUT_UPPER 0x03 | |
| 33 | +#define MXC4005_REG_XOUT_LOWER 0x04 | |
| 34 | +#define MXC4005_REG_YOUT_UPPER 0x05 | |
| 35 | +#define MXC4005_REG_YOUT_LOWER 0x06 | |
| 36 | +#define MXC4005_REG_ZOUT_UPPER 0x07 | |
| 37 | +#define MXC4005_REG_ZOUT_LOWER 0x08 | |
| 38 | + | |
| 39 | +#define MXC4005_REG_INT_MASK1 0x0B | |
| 40 | +#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 | |
| 41 | + | |
| 42 | +#define MXC4005_REG_INT_CLR1 0x01 | |
| 43 | +#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 | |
| 44 | + | |
| 45 | +#define MXC4005_REG_CONTROL 0x0D | |
| 46 | +#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) | |
| 47 | +#define MXC4005_CONTROL_FSR_SHIFT 5 | |
| 48 | + | |
| 49 | +#define MXC4005_REG_DEVICE_ID 0x0E | |
| 50 | + | |
| 51 | +enum mxc4005_axis { | |
| 52 | + AXIS_X, | |
| 53 | + AXIS_Y, | |
| 54 | + AXIS_Z, | |
| 55 | +}; | |
| 56 | + | |
| 57 | +enum mxc4005_range { | |
| 58 | + MXC4005_RANGE_2G, | |
| 59 | + MXC4005_RANGE_4G, | |
| 60 | + MXC4005_RANGE_8G, | |
| 61 | +}; | |
| 62 | + | |
| 63 | +struct mxc4005_data { | |
| 64 | + struct device *dev; | |
| 65 | + struct mutex mutex; | |
| 66 | + struct regmap *regmap; | |
| 67 | + struct iio_trigger *dready_trig; | |
| 68 | + __be16 buffer[8]; | |
| 69 | + bool trigger_enabled; | |
| 70 | +}; | |
| 71 | + | |
| 72 | +/* | |
| 73 | + * MXC4005 can operate in the following ranges: | |
| 74 | + * +/- 2G, 4G, 8G (the default +/-2G) | |
| 75 | + * | |
| 76 | + * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582 | |
| 77 | + * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164 | |
| 78 | + * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329 | |
| 79 | + */ | |
| 80 | +static const struct { | |
| 81 | + u8 range; | |
| 82 | + int scale; | |
| 83 | +} mxc4005_scale_table[] = { | |
| 84 | + {MXC4005_RANGE_2G, 9582}, | |
| 85 | + {MXC4005_RANGE_4G, 19164}, | |
| 86 | + {MXC4005_RANGE_8G, 38329}, | |
| 87 | +}; | |
| 88 | + | |
| 89 | + | |
| 90 | +static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329"); | |
| 91 | + | |
| 92 | +static struct attribute *mxc4005_attributes[] = { | |
| 93 | + &iio_const_attr_in_accel_scale_available.dev_attr.attr, | |
| 94 | + NULL, | |
| 95 | +}; | |
| 96 | + | |
| 97 | +static const struct attribute_group mxc4005_attrs_group = { | |
| 98 | + .attrs = mxc4005_attributes, | |
| 99 | +}; | |
| 100 | + | |
| 101 | +static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) | |
| 102 | +{ | |
| 103 | + switch (reg) { | |
| 104 | + case MXC4005_REG_XOUT_UPPER: | |
| 105 | + case MXC4005_REG_XOUT_LOWER: | |
| 106 | + case MXC4005_REG_YOUT_UPPER: | |
| 107 | + case MXC4005_REG_YOUT_LOWER: | |
| 108 | + case MXC4005_REG_ZOUT_UPPER: | |
| 109 | + case MXC4005_REG_ZOUT_LOWER: | |
| 110 | + case MXC4005_REG_DEVICE_ID: | |
| 111 | + case MXC4005_REG_CONTROL: | |
| 112 | + return true; | |
| 113 | + default: | |
| 114 | + return false; | |
| 115 | + } | |
| 116 | +} | |
| 117 | + | |
| 118 | +static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) | |
| 119 | +{ | |
| 120 | + switch (reg) { | |
| 121 | + case MXC4005_REG_INT_CLR1: | |
| 122 | + case MXC4005_REG_INT_MASK1: | |
| 123 | + case MXC4005_REG_CONTROL: | |
| 124 | + return true; | |
| 125 | + default: | |
| 126 | + return false; | |
| 127 | + } | |
| 128 | +} | |
| 129 | + | |
| 130 | +static const struct regmap_config mxc4005_regmap_config = { | |
| 131 | + .name = MXC4005_REGMAP_NAME, | |
| 132 | + | |
| 133 | + .reg_bits = 8, | |
| 134 | + .val_bits = 8, | |
| 135 | + | |
| 136 | + .max_register = MXC4005_REG_DEVICE_ID, | |
| 137 | + | |
| 138 | + .readable_reg = mxc4005_is_readable_reg, | |
| 139 | + .writeable_reg = mxc4005_is_writeable_reg, | |
| 140 | +}; | |
| 141 | + | |
| 142 | +static int mxc4005_read_xyz(struct mxc4005_data *data) | |
| 143 | +{ | |
| 144 | + int ret; | |
| 145 | + | |
| 146 | + ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, | |
| 147 | + (u8 *) data->buffer, sizeof(data->buffer)); | |
| 148 | + if (ret < 0) { | |
| 149 | + dev_err(data->dev, "failed to read axes\n"); | |
| 150 | + return ret; | |
| 151 | + } | |
| 152 | + | |
| 153 | + return 0; | |
| 154 | +} | |
| 155 | + | |
| 156 | +static int mxc4005_read_axis(struct mxc4005_data *data, | |
| 157 | + unsigned int addr) | |
| 158 | +{ | |
| 159 | + __be16 reg; | |
| 160 | + int ret; | |
| 161 | + | |
| 162 | + ret = regmap_bulk_read(data->regmap, addr, (u8 *) ®, sizeof(reg)); | |
| 163 | + if (ret < 0) { | |
| 164 | + dev_err(data->dev, "failed to read reg %02x\n", addr); | |
| 165 | + return ret; | |
| 166 | + } | |
| 167 | + | |
| 168 | + return be16_to_cpu(reg); | |
| 169 | +} | |
| 170 | + | |
| 171 | +static int mxc4005_read_scale(struct mxc4005_data *data) | |
| 172 | +{ | |
| 173 | + unsigned int reg; | |
| 174 | + int ret; | |
| 175 | + int i; | |
| 176 | + | |
| 177 | + ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, ®); | |
| 178 | + if (ret < 0) { | |
| 179 | + dev_err(data->dev, "failed to read reg_control\n"); | |
| 180 | + return ret; | |
| 181 | + } | |
| 182 | + | |
| 183 | + i = reg >> MXC4005_CONTROL_FSR_SHIFT; | |
| 184 | + | |
| 185 | + if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table)) | |
| 186 | + return -EINVAL; | |
| 187 | + | |
| 188 | + return mxc4005_scale_table[i].scale; | |
| 189 | +} | |
| 190 | + | |
| 191 | +static int mxc4005_set_scale(struct mxc4005_data *data, int val) | |
| 192 | +{ | |
| 193 | + unsigned int reg; | |
| 194 | + int i; | |
| 195 | + int ret; | |
| 196 | + | |
| 197 | + for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) { | |
| 198 | + if (mxc4005_scale_table[i].scale == val) { | |
| 199 | + reg = i << MXC4005_CONTROL_FSR_SHIFT; | |
| 200 | + ret = regmap_update_bits(data->regmap, | |
| 201 | + MXC4005_REG_CONTROL, | |
| 202 | + MXC4005_REG_CONTROL_MASK_FSR, | |
| 203 | + reg); | |
| 204 | + if (ret < 0) | |
| 205 | + dev_err(data->dev, | |
| 206 | + "failed to write reg_control\n"); | |
| 207 | + return ret; | |
| 208 | + } | |
| 209 | + } | |
| 210 | + | |
| 211 | + return -EINVAL; | |
| 212 | +} | |
| 213 | + | |
| 214 | +static int mxc4005_read_raw(struct iio_dev *indio_dev, | |
| 215 | + struct iio_chan_spec const *chan, | |
| 216 | + int *val, int *val2, long mask) | |
| 217 | +{ | |
| 218 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 219 | + int ret; | |
| 220 | + | |
| 221 | + switch (mask) { | |
| 222 | + case IIO_CHAN_INFO_RAW: | |
| 223 | + switch (chan->type) { | |
| 224 | + case IIO_ACCEL: | |
| 225 | + if (iio_buffer_enabled(indio_dev)) | |
| 226 | + return -EBUSY; | |
| 227 | + | |
| 228 | + ret = mxc4005_read_axis(data, chan->address); | |
| 229 | + if (ret < 0) | |
| 230 | + return ret; | |
| 231 | + *val = sign_extend32(ret >> chan->scan_type.shift, | |
| 232 | + chan->scan_type.realbits - 1); | |
| 233 | + return IIO_VAL_INT; | |
| 234 | + default: | |
| 235 | + return -EINVAL; | |
| 236 | + } | |
| 237 | + case IIO_CHAN_INFO_SCALE: | |
| 238 | + ret = mxc4005_read_scale(data); | |
| 239 | + if (ret < 0) | |
| 240 | + return ret; | |
| 241 | + | |
| 242 | + *val = 0; | |
| 243 | + *val2 = ret; | |
| 244 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 245 | + default: | |
| 246 | + return -EINVAL; | |
| 247 | + } | |
| 248 | +} | |
| 249 | + | |
| 250 | +static int mxc4005_write_raw(struct iio_dev *indio_dev, | |
| 251 | + struct iio_chan_spec const *chan, | |
| 252 | + int val, int val2, long mask) | |
| 253 | +{ | |
| 254 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 255 | + | |
| 256 | + switch (mask) { | |
| 257 | + case IIO_CHAN_INFO_SCALE: | |
| 258 | + if (val != 0) | |
| 259 | + return -EINVAL; | |
| 260 | + | |
| 261 | + return mxc4005_set_scale(data, val2); | |
| 262 | + default: | |
| 263 | + return -EINVAL; | |
| 264 | + } | |
| 265 | +} | |
| 266 | + | |
| 267 | +static const struct iio_info mxc4005_info = { | |
| 268 | + .driver_module = THIS_MODULE, | |
| 269 | + .read_raw = mxc4005_read_raw, | |
| 270 | + .write_raw = mxc4005_write_raw, | |
| 271 | + .attrs = &mxc4005_attrs_group, | |
| 272 | +}; | |
| 273 | + | |
| 274 | +static const unsigned long mxc4005_scan_masks[] = { | |
| 275 | + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), | |
| 276 | + 0 | |
| 277 | +}; | |
| 278 | + | |
| 279 | +#define MXC4005_CHANNEL(_axis, _addr) { \ | |
| 280 | + .type = IIO_ACCEL, \ | |
| 281 | + .modified = 1, \ | |
| 282 | + .channel2 = IIO_MOD_##_axis, \ | |
| 283 | + .address = _addr, \ | |
| 284 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 285 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | |
| 286 | + .scan_index = AXIS_##_axis, \ | |
| 287 | + .scan_type = { \ | |
| 288 | + .sign = 's', \ | |
| 289 | + .realbits = 12, \ | |
| 290 | + .storagebits = 16, \ | |
| 291 | + .shift = 4, \ | |
| 292 | + .endianness = IIO_BE, \ | |
| 293 | + }, \ | |
| 294 | +} | |
| 295 | + | |
| 296 | +static const struct iio_chan_spec mxc4005_channels[] = { | |
| 297 | + MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), | |
| 298 | + MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), | |
| 299 | + MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), | |
| 300 | + IIO_CHAN_SOFT_TIMESTAMP(3), | |
| 301 | +}; | |
| 302 | + | |
| 303 | +static irqreturn_t mxc4005_trigger_handler(int irq, void *private) | |
| 304 | +{ | |
| 305 | + struct iio_poll_func *pf = private; | |
| 306 | + struct iio_dev *indio_dev = pf->indio_dev; | |
| 307 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 308 | + int ret; | |
| 309 | + | |
| 310 | + ret = mxc4005_read_xyz(data); | |
| 311 | + if (ret < 0) | |
| 312 | + goto err; | |
| 313 | + | |
| 314 | + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | |
| 315 | + pf->timestamp); | |
| 316 | + | |
| 317 | +err: | |
| 318 | + iio_trigger_notify_done(indio_dev->trig); | |
| 319 | + | |
| 320 | + return IRQ_HANDLED; | |
| 321 | +} | |
| 322 | + | |
| 323 | +static int mxc4005_clr_intr(struct mxc4005_data *data) | |
| 324 | +{ | |
| 325 | + int ret; | |
| 326 | + | |
| 327 | + /* clear interrupt */ | |
| 328 | + ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, | |
| 329 | + MXC4005_REG_INT_CLR1_BIT_DRDYC); | |
| 330 | + if (ret < 0) { | |
| 331 | + dev_err(data->dev, "failed to write to reg_int_clr1\n"); | |
| 332 | + return ret; | |
| 333 | + } | |
| 334 | + | |
| 335 | + return 0; | |
| 336 | +} | |
| 337 | + | |
| 338 | +static int mxc4005_set_trigger_state(struct iio_trigger *trig, | |
| 339 | + bool state) | |
| 340 | +{ | |
| 341 | + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | |
| 342 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 343 | + int ret; | |
| 344 | + | |
| 345 | + mutex_lock(&data->mutex); | |
| 346 | + if (state) { | |
| 347 | + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, | |
| 348 | + MXC4005_REG_INT_MASK1_BIT_DRDYE); | |
| 349 | + } else { | |
| 350 | + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, | |
| 351 | + ~MXC4005_REG_INT_MASK1_BIT_DRDYE); | |
| 352 | + } | |
| 353 | + | |
| 354 | + if (ret < 0) { | |
| 355 | + mutex_unlock(&data->mutex); | |
| 356 | + dev_err(data->dev, "failed to update reg_int_mask1"); | |
| 357 | + return ret; | |
| 358 | + } | |
| 359 | + | |
| 360 | + data->trigger_enabled = state; | |
| 361 | + mutex_unlock(&data->mutex); | |
| 362 | + | |
| 363 | + return 0; | |
| 364 | +} | |
| 365 | + | |
| 366 | +static int mxc4005_trigger_try_reen(struct iio_trigger *trig) | |
| 367 | +{ | |
| 368 | + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); | |
| 369 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 370 | + | |
| 371 | + if (!data->dready_trig) | |
| 372 | + return 0; | |
| 373 | + | |
| 374 | + return mxc4005_clr_intr(data); | |
| 375 | +} | |
| 376 | + | |
| 377 | +static const struct iio_trigger_ops mxc4005_trigger_ops = { | |
| 378 | + .set_trigger_state = mxc4005_set_trigger_state, | |
| 379 | + .try_reenable = mxc4005_trigger_try_reen, | |
| 380 | + .owner = THIS_MODULE, | |
| 381 | +}; | |
| 382 | + | |
| 383 | +static int mxc4005_gpio_probe(struct i2c_client *client, | |
| 384 | + struct mxc4005_data *data) | |
| 385 | +{ | |
| 386 | + struct device *dev; | |
| 387 | + struct gpio_desc *gpio; | |
| 388 | + int ret; | |
| 389 | + | |
| 390 | + if (!client) | |
| 391 | + return -EINVAL; | |
| 392 | + | |
| 393 | + dev = &client->dev; | |
| 394 | + | |
| 395 | + gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN); | |
| 396 | + if (IS_ERR(gpio)) { | |
| 397 | + dev_err(dev, "failed to get acpi gpio index\n"); | |
| 398 | + return PTR_ERR(gpio); | |
| 399 | + } | |
| 400 | + | |
| 401 | + ret = gpiod_to_irq(gpio); | |
| 402 | + | |
| 403 | + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 404 | + | |
| 405 | + return ret; | |
| 406 | +} | |
| 407 | + | |
| 408 | +static int mxc4005_chip_init(struct mxc4005_data *data) | |
| 409 | +{ | |
| 410 | + int ret; | |
| 411 | + unsigned int reg; | |
| 412 | + | |
| 413 | + ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, ®); | |
| 414 | + if (ret < 0) { | |
| 415 | + dev_err(data->dev, "failed to read chip id\n"); | |
| 416 | + return ret; | |
| 417 | + } | |
| 418 | + | |
| 419 | + dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); | |
| 420 | + | |
| 421 | + return 0; | |
| 422 | +} | |
| 423 | + | |
| 424 | +static int mxc4005_probe(struct i2c_client *client, | |
| 425 | + const struct i2c_device_id *id) | |
| 426 | +{ | |
| 427 | + struct mxc4005_data *data; | |
| 428 | + struct iio_dev *indio_dev; | |
| 429 | + struct regmap *regmap; | |
| 430 | + int ret; | |
| 431 | + | |
| 432 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 433 | + if (!indio_dev) | |
| 434 | + return -ENOMEM; | |
| 435 | + | |
| 436 | + regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config); | |
| 437 | + if (IS_ERR(regmap)) { | |
| 438 | + dev_err(&client->dev, "failed to initialize regmap\n"); | |
| 439 | + return PTR_ERR(regmap); | |
| 440 | + } | |
| 441 | + | |
| 442 | + data = iio_priv(indio_dev); | |
| 443 | + i2c_set_clientdata(client, indio_dev); | |
| 444 | + data->dev = &client->dev; | |
| 445 | + data->regmap = regmap; | |
| 446 | + | |
| 447 | + ret = mxc4005_chip_init(data); | |
| 448 | + if (ret < 0) { | |
| 449 | + dev_err(&client->dev, "failed to initialize chip\n"); | |
| 450 | + return ret; | |
| 451 | + } | |
| 452 | + | |
| 453 | + mutex_init(&data->mutex); | |
| 454 | + | |
| 455 | + indio_dev->dev.parent = &client->dev; | |
| 456 | + indio_dev->channels = mxc4005_channels; | |
| 457 | + indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); | |
| 458 | + indio_dev->available_scan_masks = mxc4005_scan_masks; | |
| 459 | + indio_dev->name = MXC4005_DRV_NAME; | |
| 460 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 461 | + indio_dev->info = &mxc4005_info; | |
| 462 | + | |
| 463 | + ret = iio_triggered_buffer_setup(indio_dev, | |
| 464 | + iio_pollfunc_store_time, | |
| 465 | + mxc4005_trigger_handler, | |
| 466 | + NULL); | |
| 467 | + if (ret < 0) { | |
| 468 | + dev_err(&client->dev, | |
| 469 | + "failed to setup iio triggered buffer\n"); | |
| 470 | + return ret; | |
| 471 | + } | |
| 472 | + | |
| 473 | + if (client->irq < 0) | |
| 474 | + client->irq = mxc4005_gpio_probe(client, data); | |
| 475 | + | |
| 476 | + if (client->irq > 0) { | |
| 477 | + data->dready_trig = devm_iio_trigger_alloc(&client->dev, | |
| 478 | + "%s-dev%d", | |
| 479 | + indio_dev->name, | |
| 480 | + indio_dev->id); | |
| 481 | + if (!data->dready_trig) | |
| 482 | + return -ENOMEM; | |
| 483 | + | |
| 484 | + ret = devm_request_threaded_irq(&client->dev, client->irq, | |
| 485 | + iio_trigger_generic_data_rdy_poll, | |
| 486 | + NULL, | |
| 487 | + IRQF_TRIGGER_FALLING | | |
| 488 | + IRQF_ONESHOT, | |
| 489 | + MXC4005_IRQ_NAME, | |
| 490 | + data->dready_trig); | |
| 491 | + if (ret) { | |
| 492 | + dev_err(&client->dev, | |
| 493 | + "failed to init threaded irq\n"); | |
| 494 | + goto err_buffer_cleanup; | |
| 495 | + } | |
| 496 | + | |
| 497 | + data->dready_trig->dev.parent = &client->dev; | |
| 498 | + data->dready_trig->ops = &mxc4005_trigger_ops; | |
| 499 | + iio_trigger_set_drvdata(data->dready_trig, indio_dev); | |
| 500 | + indio_dev->trig = data->dready_trig; | |
| 501 | + iio_trigger_get(indio_dev->trig); | |
| 502 | + ret = iio_trigger_register(data->dready_trig); | |
| 503 | + if (ret) { | |
| 504 | + dev_err(&client->dev, | |
| 505 | + "failed to register trigger\n"); | |
| 506 | + goto err_trigger_unregister; | |
| 507 | + } | |
| 508 | + } | |
| 509 | + | |
| 510 | + ret = iio_device_register(indio_dev); | |
| 511 | + if (ret < 0) { | |
| 512 | + dev_err(&client->dev, | |
| 513 | + "unable to register iio device %d\n", ret); | |
| 514 | + goto err_buffer_cleanup; | |
| 515 | + } | |
| 516 | + | |
| 517 | + return 0; | |
| 518 | + | |
| 519 | +err_trigger_unregister: | |
| 520 | + iio_trigger_unregister(data->dready_trig); | |
| 521 | +err_buffer_cleanup: | |
| 522 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 523 | + | |
| 524 | + return ret; | |
| 525 | +} | |
| 526 | + | |
| 527 | +static int mxc4005_remove(struct i2c_client *client) | |
| 528 | +{ | |
| 529 | + struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
| 530 | + struct mxc4005_data *data = iio_priv(indio_dev); | |
| 531 | + | |
| 532 | + iio_device_unregister(indio_dev); | |
| 533 | + | |
| 534 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 535 | + if (data->dready_trig) | |
| 536 | + iio_trigger_unregister(data->dready_trig); | |
| 537 | + | |
| 538 | + return 0; | |
| 539 | +} | |
| 540 | + | |
| 541 | +static const struct acpi_device_id mxc4005_acpi_match[] = { | |
| 542 | + {"MXC4005", 0}, | |
| 543 | + { }, | |
| 544 | +}; | |
| 545 | +MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); | |
| 546 | + | |
| 547 | +static const struct i2c_device_id mxc4005_id[] = { | |
| 548 | + {"mxc4005", 0}, | |
| 549 | + { }, | |
| 550 | +}; | |
| 551 | +MODULE_DEVICE_TABLE(i2c, mxc4005_id); | |
| 552 | + | |
| 553 | +static struct i2c_driver mxc4005_driver = { | |
| 554 | + .driver = { | |
| 555 | + .name = MXC4005_DRV_NAME, | |
| 556 | + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), | |
| 557 | + }, | |
| 558 | + .probe = mxc4005_probe, | |
| 559 | + .remove = mxc4005_remove, | |
| 560 | + .id_table = mxc4005_id, | |
| 561 | +}; | |
| 562 | + | |
| 563 | +module_i2c_driver(mxc4005_driver); | |
| 564 | + | |
| 565 | +MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>"); | |
| 566 | +MODULE_LICENSE("GPL v2"); | |
| 567 | +MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver"); | |
| @@ -612,6 +612,7 @@ static const struct iio_info accel_info = { · 611 unmodified lines | ||
| 612 | 612 | .attrs = &st_accel_attribute_group, |
| 613 | 613 | .read_raw = &st_accel_read_raw, |
| 614 | 614 | .write_raw = &st_accel_write_raw, |
| 615 | + .debugfs_reg_access = &st_sensors_debugfs_reg_access, | |
| 615 | 616 | }; |
| 616 | 617 | |
| 617 | 618 | #ifdef CONFIG_IIO_TRIGGER |
| @@ -50,7 +50,6 @@ · 49 unmodified lines | ||
| 50 | 50 | #define STK8312_ALL_CHANNEL_SIZE 3 |
| 51 | 51 | |
| 52 | 52 | #define STK8312_DRIVER_NAME "stk8312" |
| 53 | −#define STK8312_GPIO "stk8312_gpio" | |
| 54 | 53 | #define STK8312_IRQ_NAME "stk8312_event" |
| 55 | 54 | |
| 56 | 55 | /* |
| @@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = { · 447 unmodified lines | ||
| 504 | 503 | .postdisable = stk8312_buffer_postdisable, |
| 505 | 504 | }; |
| 506 | 505 | |
| 507 | −static int stk8312_gpio_probe(struct i2c_client *client) | |
| 508 | −{ | |
| 509 | − struct device *dev; | |
| 510 | − struct gpio_desc *gpio; | |
| 511 | − int ret; | |
| 512 | − | |
| 513 | − if (!client) | |
| 514 | − return -EINVAL; | |
| 515 | − | |
| 516 | − dev = &client->dev; | |
| 517 | − | |
| 518 | − /* data ready gpio interrupt pin */ | |
| 519 | − gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN); | |
| 520 | − if (IS_ERR(gpio)) { | |
| 521 | − dev_err(dev, "acpi gpio get index failed\n"); | |
| 522 | − return PTR_ERR(gpio); | |
| 523 | − } | |
| 524 | − | |
| 525 | − ret = gpiod_to_irq(gpio); | |
| 526 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 527 | − | |
| 528 | − return ret; | |
| 529 | −} | |
| 530 | − | |
| 531 | 506 | static int stk8312_probe(struct i2c_client *client, |
| 532 | 507 | const struct i2c_device_id *id) |
| 533 | 508 | { |
| @@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client, · 35 unmodified lines | ||
| 569 | 544 | if (ret < 0) |
| 570 | 545 | return ret; |
| 571 | 546 | |
| 572 | − if (client->irq < 0) | |
| 573 | − client->irq = stk8312_gpio_probe(client); | |
| 574 | − | |
| 575 | − if (client->irq >= 0) { | |
| 547 | + if (client->irq > 0) { | |
| 576 | 548 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 577 | 549 | stk8312_data_rdy_trig_poll, |
| 578 | 550 | NULL, |
| @@ -45,7 +45,6 @@ · 44 unmodified lines | ||
| 45 | 45 | #define STK8BA50_ALL_CHANNEL_SIZE 6 |
| 46 | 46 | |
| 47 | 47 | #define STK8BA50_DRIVER_NAME "stk8ba50" |
| 48 | −#define STK8BA50_GPIO "stk8ba50_gpio" | |
| 49 | 48 | #define STK8BA50_IRQ_NAME "stk8ba50_event" |
| 50 | 49 | |
| 51 | 50 | #define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069" |
| @@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = { · 336 unmodified lines | ||
| 388 | 387 | .postdisable = stk8ba50_buffer_postdisable, |
| 389 | 388 | }; |
| 390 | 389 | |
| 391 | −static int stk8ba50_gpio_probe(struct i2c_client *client) | |
| 392 | −{ | |
| 393 | − struct device *dev; | |
| 394 | − struct gpio_desc *gpio; | |
| 395 | − int ret; | |
| 396 | − | |
| 397 | − if (!client) | |
| 398 | − return -EINVAL; | |
| 399 | − | |
| 400 | − dev = &client->dev; | |
| 401 | − | |
| 402 | − /* data ready gpio interrupt pin */ | |
| 403 | − gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN); | |
| 404 | − if (IS_ERR(gpio)) { | |
| 405 | − dev_err(dev, "acpi gpio get index failed\n"); | |
| 406 | − return PTR_ERR(gpio); | |
| 407 | − } | |
| 408 | − | |
| 409 | − ret = gpiod_to_irq(gpio); | |
| 410 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 411 | − | |
| 412 | − return ret; | |
| 413 | −} | |
| 414 | − | |
| 415 | 390 | static int stk8ba50_probe(struct i2c_client *client, |
| 416 | 391 | const struct i2c_device_id *id) |
| 417 | 392 | { |
| @@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client, · 47 unmodified lines | ||
| 465 | 440 | goto err_power_off; |
| 466 | 441 | } |
| 467 | 442 | |
| 468 | − if (client->irq < 0) | |
| 469 | − client->irq = stk8ba50_gpio_probe(client); | |
| 470 | − | |
| 471 | − if (client->irq >= 0) { | |
| 443 | + if (client->irq > 0) { | |
| 472 | 444 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 473 | 445 | stk8ba50_data_rdy_trig_poll, |
| 474 | 446 | NULL, |
| @@ -149,6 +149,17 @@ config BERLIN2_ADC · 148 unmodified lines | ||
| 149 | 149 | Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for |
| 150 | 150 | temperature measurement. |
| 151 | 151 | |
| 152 | +config CC10001_ADC | |
| 153 | + tristate "Cosmic Circuits 10001 ADC driver" | |
| 154 | + depends on HAS_IOMEM && HAVE_CLK && REGULATOR | |
| 155 | + select IIO_BUFFER | |
| 156 | + select IIO_TRIGGERED_BUFFER | |
| 157 | + help | |
| 158 | + Say yes here to build support for Cosmic Circuits 10001 ADC. | |
| 159 | + | |
| 160 | + This driver can also be built as a module. If so, the module will be | |
| 161 | + called cc10001_adc. | |
| 162 | + | |
| 152 | 163 | config DA9150_GPADC |
| 153 | 164 | tristate "Dialog DA9150 GPADC driver support" |
| 154 | 165 | depends on MFD_DA9150 |
| @@ -161,17 +172,6 @@ config DA9150_GPADC · 6 unmodified lines | ||
| 161 | 172 | To compile this driver as a module, choose M here: the module will be |
| 162 | 173 | called berlin2-adc. |
| 163 | 174 | |
| 164 | −config CC10001_ADC | |
| 165 | − tristate "Cosmic Circuits 10001 ADC driver" | |
| 166 | − depends on HAS_IOMEM && HAVE_CLK && REGULATOR | |
| 167 | − select IIO_BUFFER | |
| 168 | − select IIO_TRIGGERED_BUFFER | |
| 169 | − help | |
| 170 | − Say yes here to build support for Cosmic Circuits 10001 ADC. | |
| 171 | − | |
| 172 | − This driver can also be built as a module. If so, the module will be | |
| 173 | − called cc10001_adc. | |
| 174 | − | |
| 175 | 175 | config EXYNOS_ADC |
| 176 | 176 | tristate "Exynos ADC driver support" |
| 177 | 177 | depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) |
| @@ -183,6 +183,17 @@ config EXYNOS_ADC · 5 unmodified lines | ||
| 183 | 183 | To compile this driver as a module, choose M here: the module will be |
| 184 | 184 | called exynos_adc. |
| 185 | 185 | |
| 186 | +config HI8435 | |
| 187 | + tristate "Holt Integrated Circuits HI-8435 threshold detector" | |
| 188 | + select IIO_TRIGGERED_EVENT | |
| 189 | + depends on SPI | |
| 190 | + help | |
| 191 | + If you say yes here you get support for Holt Integrated Circuits | |
| 192 | + HI-8435 chip. | |
| 193 | + | |
| 194 | + This driver can also be built as a module. If so, the module will be | |
| 195 | + called hi8435. | |
| 196 | + | |
| 186 | 197 | config LP8788_ADC |
| 187 | 198 | tristate "LP8788 ADC driver" |
| 188 | 199 | depends on MFD_LP8788 |
| @@ -361,6 +372,8 @@ config TWL6030_GPADC · 172 unmodified lines | ||
| 361 | 372 | config VF610_ADC |
| 362 | 373 | tristate "Freescale vf610 ADC driver" |
| 363 | 374 | depends on OF |
| 375 | + select IIO_BUFFER | |
| 376 | + select IIO_TRIGGERED_BUFFER | |
| 364 | 377 | help |
| 365 | 378 | Say yes here to support for Vybrid board analog-to-digital converter. |
| 366 | 379 | Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. |
| @@ -16,9 +16,10 @@ obj-$(CONFIG_AD799X) += ad799x.o · 15 unmodified lines | ||
| 16 | 16 | obj-$(CONFIG_AT91_ADC) += at91_adc.o |
| 17 | 17 | obj-$(CONFIG_AXP288_ADC) += axp288_adc.o |
| 18 | 18 | obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o |
| 19 | −obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o | |
| 20 | 19 | obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o |
| 20 | +obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o | |
| 21 | 21 | obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o |
| 22 | +obj-$(CONFIG_HI8435) += hi8435.o | |
| 22 | 23 | obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o |
| 23 | 24 | obj-$(CONFIG_MAX1027) += max1027.o |
| 24 | 25 | obj-$(CONFIG_MAX1363) += max1363.o |
| @@ -528,7 +528,6 @@ static struct attribute *ad799x_event_attributes[] = { · 527 unmodified lines | ||
| 528 | 528 | |
| 529 | 529 | static struct attribute_group ad799x_event_attrs_group = { |
| 530 | 530 | .attrs = ad799x_event_attributes, |
| 531 | − .name = "events", | |
| 532 | 531 | }; |
| 533 | 532 | |
| 534 | 533 | static const struct iio_info ad7991_info = { |
| @@ -27,13 +27,13 @@ · 26 unmodified lines | ||
| 27 | 27 | #define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1) |
| 28 | 28 | #define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2) |
| 29 | 29 | #define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */ |
| 30 | −#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5) | |
| 30 | +#define BERLIN2_SM_CTRL_ADC_SEL_MASK GENMASK(8, 5) | |
| 31 | 31 | #define BERLIN2_SM_CTRL_ADC_POWER BIT(9) |
| 32 | 32 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10) |
| 33 | 33 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10) |
| 34 | 34 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10) |
| 35 | 35 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10) |
| 36 | −#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK (0x3 << 10) | |
| 36 | +#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK GENMASK(11, 10) | |
| 37 | 37 | #define BERLIN2_SM_CTRL_ADC_START BIT(12) |
| 38 | 38 | #define BERLIN2_SM_CTRL_ADC_RESET BIT(13) |
| 39 | 39 | #define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14) |
| @@ -50,7 +50,7 @@ · 10 unmodified lines | ||
| 50 | 50 | #define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */ |
| 51 | 51 | #define BERLIN2_SM_CTRL_TSEN_RESET BIT(29) |
| 52 | 52 | #define BERLIN2_SM_ADC_DATA 0x20 |
| 53 | −#define BERLIN2_SM_ADC_MASK 0x3ff | |
| 53 | +#define BERLIN2_SM_ADC_MASK GENMASK(9, 0) | |
| 54 | 54 | #define BERLIN2_SM_ADC_STATUS 0x1c |
| 55 | 55 | #define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */ |
| 56 | 56 | #define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0) |
| @@ -65,9 +65,9 @@ · 8 unmodified lines | ||
| 65 | 65 | #define BERLIN2_SM_TSEN_CTRL_START BIT(8) |
| 66 | 66 | #define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */ |
| 67 | 67 | #define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */ |
| 68 | −#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK (0x1 << 21) | |
| 68 | +#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK BIT(21) | |
| 69 | 69 | #define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22) |
| 70 | −#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK (0xf << 22) | |
| 70 | +#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK GENMASK(25, 22) | |
| 71 | 71 | |
| 72 | 72 | struct berlin2_adc_priv { |
| 73 | 73 | struct regmap *regmap; |
| @@ -78,13 +78,13 @@ struct berlin2_adc_priv { · 4 unmodified lines | ||
| 78 | 78 | }; |
| 79 | 79 | |
| 80 | 80 | #define BERLIN2_ADC_CHANNEL(n, t) \ |
| 81 | − { \ | |
| 82 | − .channel = n, \ | |
| 83 | − .datasheet_name = "channel"#n, \ | |
| 84 | − .type = t, \ | |
| 85 | − .indexed = 1, \ | |
| 86 | − .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 87 | − } | |
| 81 | + { \ | |
| 82 | + .channel = n, \ | |
| 83 | + .datasheet_name = "channel"#n, \ | |
| 84 | + .type = t, \ | |
| 85 | + .indexed = 1, \ | |
| 86 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 87 | + } | |
| 88 | 88 | |
| 89 | 89 | static const struct iio_chan_spec berlin2_adc_channels[] = { |
| 90 | 90 | BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */ |
| @@ -111,18 +111,24 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) · 20 unmodified lines | ||
| 111 | 111 | |
| 112 | 112 | mutex_lock(&priv->lock); |
| 113 | 113 | |
| 114 | + /* Enable the interrupts */ | |
| 115 | + regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, | |
| 116 | + BERLIN2_SM_ADC_STATUS_INT_EN(channel)); | |
| 117 | + | |
| 114 | 118 | /* Configure the ADC */ |
| 115 | 119 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 116 | − BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK | |
| 117 | − | BERLIN2_SM_CTRL_ADC_START, | |
| 118 | − BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START); | |
| 120 | + BERLIN2_SM_CTRL_ADC_RESET | | |
| 121 | + BERLIN2_SM_CTRL_ADC_SEL_MASK | | |
| 122 | + BERLIN2_SM_CTRL_ADC_START, | |
| 123 | + BERLIN2_SM_CTRL_ADC_SEL(channel) | | |
| 124 | + BERLIN2_SM_CTRL_ADC_START); | |
| 119 | 125 | |
| 120 | 126 | ret = wait_event_interruptible_timeout(priv->wq, priv->data_available, |
| 121 | − msecs_to_jiffies(1000)); | |
| 127 | + msecs_to_jiffies(1000)); | |
| 122 | 128 | |
| 123 | 129 | /* Disable the interrupts */ |
| 124 | 130 | regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, |
| 125 | − BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0); | |
| 131 | + BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0); | |
| 126 | 132 | |
| 127 | 133 | if (ret == 0) |
| 128 | 134 | ret = -ETIMEDOUT; |
| @@ -132,7 +138,7 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) · 3 unmodified lines | ||
| 132 | 138 | } |
| 133 | 139 | |
| 134 | 140 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 135 | − BERLIN2_SM_CTRL_ADC_START, 0); | |
| 141 | + BERLIN2_SM_CTRL_ADC_START, 0); | |
| 136 | 142 | |
| 137 | 143 | data = priv->data; |
| 138 | 144 | priv->data_available = false; |
| @@ -149,24 +155,31 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) · 10 unmodified lines | ||
| 149 | 155 | |
| 150 | 156 | mutex_lock(&priv->lock); |
| 151 | 157 | |
| 158 | + /* Enable interrupts */ | |
| 159 | + regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, | |
| 160 | + BERLIN2_SM_TSEN_STATUS_INT_EN); | |
| 161 | + | |
| 152 | 162 | /* Configure the ADC */ |
| 153 | 163 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 154 | − BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE, | |
| 155 | − BERLIN2_SM_CTRL_ADC_ROTATE); | |
| 164 | + BERLIN2_SM_CTRL_TSEN_RESET | | |
| 165 | + BERLIN2_SM_CTRL_ADC_ROTATE, | |
| 166 | + BERLIN2_SM_CTRL_ADC_ROTATE); | |
| 156 | 167 | |
| 157 | 168 | /* Configure the temperature sensor */ |
| 158 | 169 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, |
| 159 | − BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK | |
| 160 | − | BERLIN2_SM_TSEN_CTRL_START, | |
| 161 | − BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12 | |
| 162 | − | BERLIN2_SM_TSEN_CTRL_START); | |
| 170 | + BERLIN2_SM_TSEN_CTRL_TRIM_MASK | | |
| 171 | + BERLIN2_SM_TSEN_CTRL_SETTLING_MASK | | |
| 172 | + BERLIN2_SM_TSEN_CTRL_START, | |
| 173 | + BERLIN2_SM_TSEN_CTRL_TRIM(3) | | |
| 174 | + BERLIN2_SM_TSEN_CTRL_SETTLING_12 | | |
| 175 | + BERLIN2_SM_TSEN_CTRL_START); | |
| 163 | 176 | |
| 164 | 177 | ret = wait_event_interruptible_timeout(priv->wq, priv->data_available, |
| 165 | − msecs_to_jiffies(1000)); | |
| 178 | + msecs_to_jiffies(1000)); | |
| 166 | 179 | |
| 167 | 180 | /* Disable interrupts */ |
| 168 | 181 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, |
| 169 | − BERLIN2_SM_TSEN_STATUS_INT_EN, 0); | |
| 182 | + BERLIN2_SM_TSEN_STATUS_INT_EN, 0); | |
| 170 | 183 | |
| 171 | 184 | if (ret == 0) |
| 172 | 185 | ret = -ETIMEDOUT; |
| @@ -176,7 +189,7 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) · 3 unmodified lines | ||
| 176 | 189 | } |
| 177 | 190 | |
| 178 | 191 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, |
| 179 | − BERLIN2_SM_TSEN_CTRL_START, 0); | |
| 192 | + BERLIN2_SM_TSEN_CTRL_START, 0); | |
| 180 | 193 | |
| 181 | 194 | data = priv->data; |
| 182 | 195 | priv->data_available = false; |
| @@ -187,10 +200,9 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) · 4 unmodified lines | ||
| 187 | 200 | } |
| 188 | 201 | |
| 189 | 202 | static int berlin2_adc_read_raw(struct iio_dev *indio_dev, |
| 190 | − struct iio_chan_spec const *chan, int *val, int *val2, | |
| 191 | − long mask) | |
| 203 | + struct iio_chan_spec const *chan, int *val, | |
| 204 | + int *val2, long mask) | |
| 192 | 205 | { |
| 193 | − struct berlin2_adc_priv *priv = iio_priv(indio_dev); | |
| 194 | 206 | int temp; |
| 195 | 207 | |
| 196 | 208 | switch (mask) { |
| @@ -198,10 +210,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev, · 1 unmodified line | ||
| 198 | 210 | if (chan->type != IIO_VOLTAGE) |
| 199 | 211 | return -EINVAL; |
| 200 | 212 | |
| 201 | − /* Enable the interrupts */ | |
| 202 | − regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, | |
| 203 | − BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel)); | |
| 204 | − | |
| 205 | 213 | *val = berlin2_adc_read(indio_dev, chan->channel); |
| 206 | 214 | if (*val < 0) |
| 207 | 215 | return *val; |
| @@ -211,10 +219,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev, · 3 unmodified lines | ||
| 211 | 219 | if (chan->type != IIO_TEMP) |
| 212 | 220 | return -EINVAL; |
| 213 | 221 | |
| 214 | − /* Enable interrupts */ | |
| 215 | − regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, | |
| 216 | − BERLIN2_SM_TSEN_STATUS_INT_EN); | |
| 217 | − | |
| 218 | 222 | temp = berlin2_adc_tsen_read(indio_dev); |
| 219 | 223 | if (temp < 0) |
| 220 | 224 | return temp; |
| @@ -306,12 +310,12 @@ static int berlin2_adc_probe(struct platform_device *pdev) · 85 unmodified lines | ||
| 306 | 310 | return tsen_irq; |
| 307 | 311 | |
| 308 | 312 | ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0, |
| 309 | − pdev->dev.driver->name, indio_dev); | |
| 313 | + pdev->dev.driver->name, indio_dev); | |
| 310 | 314 | if (ret) |
| 311 | 315 | return ret; |
| 312 | 316 | |
| 313 | 317 | ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq, |
| 314 | − 0, pdev->dev.driver->name, indio_dev); | |
| 318 | + 0, pdev->dev.driver->name, indio_dev); | |
| 315 | 319 | if (ret) |
| 316 | 320 | return ret; |
| 317 | 321 | |
| @@ -328,13 +332,14 @@ static int berlin2_adc_probe(struct platform_device *pdev) · 10 unmodified lines | ||
| 328 | 332 | |
| 329 | 333 | /* Power up the ADC */ |
| 330 | 334 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 331 | − BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER); | |
| 335 | + BERLIN2_SM_CTRL_ADC_POWER, | |
| 336 | + BERLIN2_SM_CTRL_ADC_POWER); | |
| 332 | 337 | |
| 333 | 338 | ret = iio_device_register(indio_dev); |
| 334 | 339 | if (ret) { |
| 335 | 340 | /* Power down the ADC */ |
| 336 | 341 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 337 | − BERLIN2_SM_CTRL_ADC_POWER, 0); | |
| 342 | + BERLIN2_SM_CTRL_ADC_POWER, 0); | |
| 338 | 343 | return ret; |
| 339 | 344 | } |
| 340 | 345 | |
| @@ -350,7 +355,7 @@ static int berlin2_adc_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 350 | 355 | |
| 351 | 356 | /* Power down the ADC */ |
| 352 | 357 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, |
| 353 | − BERLIN2_SM_CTRL_ADC_POWER, 0); | |
| 358 | + BERLIN2_SM_CTRL_ADC_POWER, 0); | |
| 354 | 359 | |
| 355 | 360 | return 0; |
| 356 | 361 | } |
| @@ -0,0 +1,534 @@ | ||
| 1 | +/* | |
| 2 | + * Holt Integrated Circuits HI-8435 threshold detector driver | |
| 3 | + * | |
| 4 | + * Copyright (C) 2015 Zodiac Inflight Innovations | |
| 5 | + * Copyright (C) 2015 Cogent Embedded, Inc. | |
| 6 | + * | |
| 7 | + * This program is free software; you can redistribute it and/or modify it | |
| 8 | + * under the terms of the GNU General Public License as published by the | |
| 9 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 10 | + * option) any later version. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/iio/events.h> | |
| 15 | +#include <linux/iio/iio.h> | |
| 16 | +#include <linux/iio/sysfs.h> | |
| 17 | +#include <linux/iio/trigger.h> | |
| 18 | +#include <linux/iio/trigger_consumer.h> | |
| 19 | +#include <linux/iio/triggered_event.h> | |
| 20 | +#include <linux/interrupt.h> | |
| 21 | +#include <linux/module.h> | |
| 22 | +#include <linux/of.h> | |
| 23 | +#include <linux/of_device.h> | |
| 24 | +#include <linux/of_gpio.h> | |
| 25 | +#include <linux/spi/spi.h> | |
| 26 | +#include <linux/gpio/consumer.h> | |
| 27 | + | |
| 28 | +#define DRV_NAME "hi8435" | |
| 29 | + | |
| 30 | +/* Register offsets for HI-8435 */ | |
| 31 | +#define HI8435_CTRL_REG 0x02 | |
| 32 | +#define HI8435_PSEN_REG 0x04 | |
| 33 | +#define HI8435_TMDATA_REG 0x1E | |
| 34 | +#define HI8435_GOCENHYS_REG 0x3A | |
| 35 | +#define HI8435_SOCENHYS_REG 0x3C | |
| 36 | +#define HI8435_SO7_0_REG 0x10 | |
| 37 | +#define HI8435_SO15_8_REG 0x12 | |
| 38 | +#define HI8435_SO23_16_REG 0x14 | |
| 39 | +#define HI8435_SO31_24_REG 0x16 | |
| 40 | +#define HI8435_SO31_0_REG 0x78 | |
| 41 | + | |
| 42 | +#define HI8435_WRITE_OPCODE 0x00 | |
| 43 | +#define HI8435_READ_OPCODE 0x80 | |
| 44 | + | |
| 45 | +/* CTRL register bits */ | |
| 46 | +#define HI8435_CTRL_TEST 0x01 | |
| 47 | +#define HI8435_CTRL_SRST 0x02 | |
| 48 | + | |
| 49 | +struct hi8435_priv { | |
| 50 | + struct spi_device *spi; | |
| 51 | + struct mutex lock; | |
| 52 | + | |
| 53 | + unsigned long event_scan_mask; /* soft mask/unmask channels events */ | |
| 54 | + unsigned int event_prev_val; | |
| 55 | + | |
| 56 | + unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */ | |
| 57 | + unsigned threshold_hi[2]; /* GND-Open and Supply-Open thresholds */ | |
| 58 | + u8 reg_buffer[3] ____cacheline_aligned; | |
| 59 | +}; | |
| 60 | + | |
| 61 | +static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val) | |
| 62 | +{ | |
| 63 | + reg |= HI8435_READ_OPCODE; | |
| 64 | + return spi_write_then_read(priv->spi, ®, 1, val, 1); | |
| 65 | +} | |
| 66 | + | |
| 67 | +static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val) | |
| 68 | +{ | |
| 69 | + int ret; | |
| 70 | + __be16 be_val; | |
| 71 | + | |
| 72 | + reg |= HI8435_READ_OPCODE; | |
| 73 | + ret = spi_write_then_read(priv->spi, ®, 1, &be_val, 2); | |
| 74 | + *val = be16_to_cpu(be_val); | |
| 75 | + | |
| 76 | + return ret; | |
| 77 | +} | |
| 78 | + | |
| 79 | +static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val) | |
| 80 | +{ | |
| 81 | + int ret; | |
| 82 | + __be32 be_val; | |
| 83 | + | |
| 84 | + reg |= HI8435_READ_OPCODE; | |
| 85 | + ret = spi_write_then_read(priv->spi, ®, 1, &be_val, 4); | |
| 86 | + *val = be32_to_cpu(be_val); | |
| 87 | + | |
| 88 | + return ret; | |
| 89 | +} | |
| 90 | + | |
| 91 | +static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val) | |
| 92 | +{ | |
| 93 | + priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE; | |
| 94 | + priv->reg_buffer[1] = val; | |
| 95 | + | |
| 96 | + return spi_write(priv->spi, priv->reg_buffer, 2); | |
| 97 | +} | |
| 98 | + | |
| 99 | +static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val) | |
| 100 | +{ | |
| 101 | + priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE; | |
| 102 | + priv->reg_buffer[1] = (val >> 8) & 0xff; | |
| 103 | + priv->reg_buffer[2] = val & 0xff; | |
| 104 | + | |
| 105 | + return spi_write(priv->spi, priv->reg_buffer, 3); | |
| 106 | +} | |
| 107 | + | |
| 108 | +static int hi8435_read_event_config(struct iio_dev *idev, | |
| 109 | + const struct iio_chan_spec *chan, | |
| 110 | + enum iio_event_type type, | |
| 111 | + enum iio_event_direction dir) | |
| 112 | +{ | |
| 113 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 114 | + | |
| 115 | + return !!(priv->event_scan_mask & BIT(chan->channel)); | |
| 116 | +} | |
| 117 | + | |
| 118 | +static int hi8435_write_event_config(struct iio_dev *idev, | |
| 119 | + const struct iio_chan_spec *chan, | |
| 120 | + enum iio_event_type type, | |
| 121 | + enum iio_event_direction dir, int state) | |
| 122 | +{ | |
| 123 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 124 | + | |
| 125 | + priv->event_scan_mask &= ~BIT(chan->channel); | |
| 126 | + if (state) | |
| 127 | + priv->event_scan_mask |= BIT(chan->channel); | |
| 128 | + | |
| 129 | + return 0; | |
| 130 | +} | |
| 131 | + | |
| 132 | +static int hi8435_read_event_value(struct iio_dev *idev, | |
| 133 | + const struct iio_chan_spec *chan, | |
| 134 | + enum iio_event_type type, | |
| 135 | + enum iio_event_direction dir, | |
| 136 | + enum iio_event_info info, | |
| 137 | + int *val, int *val2) | |
| 138 | +{ | |
| 139 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 140 | + int ret; | |
| 141 | + u8 mode, psen; | |
| 142 | + u16 reg; | |
| 143 | + | |
| 144 | + ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen); | |
| 145 | + if (ret < 0) | |
| 146 | + return ret; | |
| 147 | + | |
| 148 | + /* Supply-Open or GND-Open sensing mode */ | |
| 149 | + mode = !!(psen & BIT(chan->channel / 8)); | |
| 150 | + | |
| 151 | + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : | |
| 152 | + HI8435_GOCENHYS_REG, ®); | |
| 153 | + if (ret < 0) | |
| 154 | + return ret; | |
| 155 | + | |
| 156 | + if (dir == IIO_EV_DIR_FALLING) | |
| 157 | + *val = ((reg & 0xff) - (reg >> 8)) / 2; | |
| 158 | + else if (dir == IIO_EV_DIR_RISING) | |
| 159 | + *val = ((reg & 0xff) + (reg >> 8)) / 2; | |
| 160 | + | |
| 161 | + return IIO_VAL_INT; | |
| 162 | +} | |
| 163 | + | |
| 164 | +static int hi8435_write_event_value(struct iio_dev *idev, | |
| 165 | + const struct iio_chan_spec *chan, | |
| 166 | + enum iio_event_type type, | |
| 167 | + enum iio_event_direction dir, | |
| 168 | + enum iio_event_info info, | |
| 169 | + int val, int val2) | |
| 170 | +{ | |
| 171 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 172 | + int ret; | |
| 173 | + u8 mode, psen; | |
| 174 | + u16 reg; | |
| 175 | + | |
| 176 | + ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen); | |
| 177 | + if (ret < 0) | |
| 178 | + return ret; | |
| 179 | + | |
| 180 | + /* Supply-Open or GND-Open sensing mode */ | |
| 181 | + mode = !!(psen & BIT(chan->channel / 8)); | |
| 182 | + | |
| 183 | + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : | |
| 184 | + HI8435_GOCENHYS_REG, ®); | |
| 185 | + if (ret < 0) | |
| 186 | + return ret; | |
| 187 | + | |
| 188 | + if (dir == IIO_EV_DIR_FALLING) { | |
| 189 | + /* falling threshold range 2..21V, hysteresis minimum 2V */ | |
| 190 | + if (val < 2 || val > 21 || (val + 2) > priv->threshold_hi[mode]) | |
| 191 | + return -EINVAL; | |
| 192 | + | |
| 193 | + if (val == priv->threshold_lo[mode]) | |
| 194 | + return 0; | |
| 195 | + | |
| 196 | + priv->threshold_lo[mode] = val; | |
| 197 | + | |
| 198 | + /* hysteresis must not be odd */ | |
| 199 | + if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2) | |
| 200 | + priv->threshold_hi[mode]--; | |
| 201 | + } else if (dir == IIO_EV_DIR_RISING) { | |
| 202 | + /* rising threshold range 3..22V, hysteresis minimum 2V */ | |
| 203 | + if (val < 3 || val > 22 || val < (priv->threshold_lo[mode] + 2)) | |
| 204 | + return -EINVAL; | |
| 205 | + | |
| 206 | + if (val == priv->threshold_hi[mode]) | |
| 207 | + return 0; | |
| 208 | + | |
| 209 | + priv->threshold_hi[mode] = val; | |
| 210 | + | |
| 211 | + /* hysteresis must not be odd */ | |
| 212 | + if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2) | |
| 213 | + priv->threshold_lo[mode]++; | |
| 214 | + } | |
| 215 | + | |
| 216 | + /* program thresholds */ | |
| 217 | + mutex_lock(&priv->lock); | |
| 218 | + | |
| 219 | + ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG : | |
| 220 | + HI8435_GOCENHYS_REG, ®); | |
| 221 | + if (ret < 0) { | |
| 222 | + mutex_unlock(&priv->lock); | |
| 223 | + return ret; | |
| 224 | + } | |
| 225 | + | |
| 226 | + /* hysteresis */ | |
| 227 | + reg = priv->threshold_hi[mode] - priv->threshold_lo[mode]; | |
| 228 | + reg <<= 8; | |
| 229 | + /* threshold center */ | |
| 230 | + reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]); | |
| 231 | + | |
| 232 | + ret = hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG : | |
| 233 | + HI8435_GOCENHYS_REG, reg); | |
| 234 | + | |
| 235 | + mutex_unlock(&priv->lock); | |
| 236 | + | |
| 237 | + return ret; | |
| 238 | +} | |
| 239 | + | |
| 240 | +static int hi8435_debugfs_reg_access(struct iio_dev *idev, | |
| 241 | + unsigned reg, unsigned writeval, | |
| 242 | + unsigned *readval) | |
| 243 | +{ | |
| 244 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 245 | + int ret; | |
| 246 | + u8 val; | |
| 247 | + | |
| 248 | + if (readval != NULL) { | |
| 249 | + ret = hi8435_readb(priv, reg, &val); | |
| 250 | + *readval = val; | |
| 251 | + } else { | |
| 252 | + val = (u8)writeval; | |
| 253 | + ret = hi8435_writeb(priv, reg, val); | |
| 254 | + } | |
| 255 | + | |
| 256 | + return ret; | |
| 257 | +} | |
| 258 | + | |
| 259 | +static const struct iio_event_spec hi8435_events[] = { | |
| 260 | + { | |
| 261 | + .type = IIO_EV_TYPE_THRESH, | |
| 262 | + .dir = IIO_EV_DIR_RISING, | |
| 263 | + .mask_separate = BIT(IIO_EV_INFO_VALUE), | |
| 264 | + }, { | |
| 265 | + .type = IIO_EV_TYPE_THRESH, | |
| 266 | + .dir = IIO_EV_DIR_FALLING, | |
| 267 | + .mask_separate = BIT(IIO_EV_INFO_VALUE), | |
| 268 | + }, { | |
| 269 | + .type = IIO_EV_TYPE_THRESH, | |
| 270 | + .dir = IIO_EV_DIR_EITHER, | |
| 271 | + .mask_separate = BIT(IIO_EV_INFO_ENABLE), | |
| 272 | + }, | |
| 273 | +}; | |
| 274 | + | |
| 275 | +static int hi8435_get_sensing_mode(struct iio_dev *idev, | |
| 276 | + const struct iio_chan_spec *chan) | |
| 277 | +{ | |
| 278 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 279 | + int ret; | |
| 280 | + u8 reg; | |
| 281 | + | |
| 282 | + ret = hi8435_readb(priv, HI8435_PSEN_REG, ®); | |
| 283 | + if (ret < 0) | |
| 284 | + return ret; | |
| 285 | + | |
| 286 | + return !!(reg & BIT(chan->channel / 8)); | |
| 287 | +} | |
| 288 | + | |
| 289 | +static int hi8435_set_sensing_mode(struct iio_dev *idev, | |
| 290 | + const struct iio_chan_spec *chan, | |
| 291 | + unsigned int mode) | |
| 292 | +{ | |
| 293 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 294 | + int ret; | |
| 295 | + u8 reg; | |
| 296 | + | |
| 297 | + mutex_lock(&priv->lock); | |
| 298 | + | |
| 299 | + ret = hi8435_readb(priv, HI8435_PSEN_REG, ®); | |
| 300 | + if (ret < 0) { | |
| 301 | + mutex_unlock(&priv->lock); | |
| 302 | + return ret; | |
| 303 | + } | |
| 304 | + | |
| 305 | + reg &= ~BIT(chan->channel / 8); | |
| 306 | + if (mode) | |
| 307 | + reg |= BIT(chan->channel / 8); | |
| 308 | + | |
| 309 | + ret = hi8435_writeb(priv, HI8435_PSEN_REG, reg); | |
| 310 | + | |
| 311 | + mutex_unlock(&priv->lock); | |
| 312 | + | |
| 313 | + return ret; | |
| 314 | +} | |
| 315 | + | |
| 316 | +static const char * const hi8435_sensing_modes[] = { "GND-Open", | |
| 317 | + "Supply-Open" }; | |
| 318 | + | |
| 319 | +static const struct iio_enum hi8435_sensing_mode = { | |
| 320 | + .items = hi8435_sensing_modes, | |
| 321 | + .num_items = ARRAY_SIZE(hi8435_sensing_modes), | |
| 322 | + .get = hi8435_get_sensing_mode, | |
| 323 | + .set = hi8435_set_sensing_mode, | |
| 324 | +}; | |
| 325 | + | |
| 326 | +static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { | |
| 327 | + IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode), | |
| 328 | + {}, | |
| 329 | +}; | |
| 330 | + | |
| 331 | +#define HI8435_VOLTAGE_CHANNEL(num) \ | |
| 332 | +{ \ | |
| 333 | + .type = IIO_VOLTAGE, \ | |
| 334 | + .indexed = 1, \ | |
| 335 | + .channel = num, \ | |
| 336 | + .event_spec = hi8435_events, \ | |
| 337 | + .num_event_specs = ARRAY_SIZE(hi8435_events), \ | |
| 338 | + .ext_info = hi8435_ext_info, \ | |
| 339 | +} | |
| 340 | + | |
| 341 | +static const struct iio_chan_spec hi8435_channels[] = { | |
| 342 | + HI8435_VOLTAGE_CHANNEL(0), | |
| 343 | + HI8435_VOLTAGE_CHANNEL(1), | |
| 344 | + HI8435_VOLTAGE_CHANNEL(2), | |
| 345 | + HI8435_VOLTAGE_CHANNEL(3), | |
| 346 | + HI8435_VOLTAGE_CHANNEL(4), | |
| 347 | + HI8435_VOLTAGE_CHANNEL(5), | |
| 348 | + HI8435_VOLTAGE_CHANNEL(6), | |
| 349 | + HI8435_VOLTAGE_CHANNEL(7), | |
| 350 | + HI8435_VOLTAGE_CHANNEL(8), | |
| 351 | + HI8435_VOLTAGE_CHANNEL(9), | |
| 352 | + HI8435_VOLTAGE_CHANNEL(10), | |
| 353 | + HI8435_VOLTAGE_CHANNEL(11), | |
| 354 | + HI8435_VOLTAGE_CHANNEL(12), | |
| 355 | + HI8435_VOLTAGE_CHANNEL(13), | |
| 356 | + HI8435_VOLTAGE_CHANNEL(14), | |
| 357 | + HI8435_VOLTAGE_CHANNEL(15), | |
| 358 | + HI8435_VOLTAGE_CHANNEL(16), | |
| 359 | + HI8435_VOLTAGE_CHANNEL(17), | |
| 360 | + HI8435_VOLTAGE_CHANNEL(18), | |
| 361 | + HI8435_VOLTAGE_CHANNEL(19), | |
| 362 | + HI8435_VOLTAGE_CHANNEL(20), | |
| 363 | + HI8435_VOLTAGE_CHANNEL(21), | |
| 364 | + HI8435_VOLTAGE_CHANNEL(22), | |
| 365 | + HI8435_VOLTAGE_CHANNEL(23), | |
| 366 | + HI8435_VOLTAGE_CHANNEL(24), | |
| 367 | + HI8435_VOLTAGE_CHANNEL(25), | |
| 368 | + HI8435_VOLTAGE_CHANNEL(26), | |
| 369 | + HI8435_VOLTAGE_CHANNEL(27), | |
| 370 | + HI8435_VOLTAGE_CHANNEL(28), | |
| 371 | + HI8435_VOLTAGE_CHANNEL(29), | |
| 372 | + HI8435_VOLTAGE_CHANNEL(30), | |
| 373 | + HI8435_VOLTAGE_CHANNEL(31), | |
| 374 | + IIO_CHAN_SOFT_TIMESTAMP(32), | |
| 375 | +}; | |
| 376 | + | |
| 377 | +static const struct iio_info hi8435_info = { | |
| 378 | + .driver_module = THIS_MODULE, | |
| 379 | + .read_event_config = &hi8435_read_event_config, | |
| 380 | + .write_event_config = hi8435_write_event_config, | |
| 381 | + .read_event_value = &hi8435_read_event_value, | |
| 382 | + .write_event_value = &hi8435_write_event_value, | |
| 383 | + .debugfs_reg_access = &hi8435_debugfs_reg_access, | |
| 384 | +}; | |
| 385 | + | |
| 386 | +static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val) | |
| 387 | +{ | |
| 388 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 389 | + enum iio_event_direction dir; | |
| 390 | + unsigned int i; | |
| 391 | + unsigned int status = priv->event_prev_val ^ val; | |
| 392 | + | |
| 393 | + if (!status) | |
| 394 | + return; | |
| 395 | + | |
| 396 | + for_each_set_bit(i, &priv->event_scan_mask, 32) { | |
| 397 | + if (status & BIT(i)) { | |
| 398 | + dir = val & BIT(i) ? IIO_EV_DIR_RISING : | |
| 399 | + IIO_EV_DIR_FALLING; | |
| 400 | + iio_push_event(idev, | |
| 401 | + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i, | |
| 402 | + IIO_EV_TYPE_THRESH, dir), | |
| 403 | + iio_get_time_ns()); | |
| 404 | + } | |
| 405 | + } | |
| 406 | + | |
| 407 | + priv->event_prev_val = val; | |
| 408 | +} | |
| 409 | + | |
| 410 | +static irqreturn_t hi8435_trigger_handler(int irq, void *private) | |
| 411 | +{ | |
| 412 | + struct iio_poll_func *pf = private; | |
| 413 | + struct iio_dev *idev = pf->indio_dev; | |
| 414 | + struct hi8435_priv *priv = iio_priv(idev); | |
| 415 | + u32 val; | |
| 416 | + int ret; | |
| 417 | + | |
| 418 | + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val); | |
| 419 | + if (ret < 0) | |
| 420 | + goto err_read; | |
| 421 | + | |
| 422 | + hi8435_iio_push_event(idev, val); | |
| 423 | + | |
| 424 | +err_read: | |
| 425 | + iio_trigger_notify_done(idev->trig); | |
| 426 | + | |
| 427 | + return IRQ_HANDLED; | |
| 428 | +} | |
| 429 | + | |
| 430 | +static int hi8435_probe(struct spi_device *spi) | |
| 431 | +{ | |
| 432 | + struct iio_dev *idev; | |
| 433 | + struct hi8435_priv *priv; | |
| 434 | + struct gpio_desc *reset_gpio; | |
| 435 | + int ret; | |
| 436 | + | |
| 437 | + idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv)); | |
| 438 | + if (!idev) | |
| 439 | + return -ENOMEM; | |
| 440 | + | |
| 441 | + priv = iio_priv(idev); | |
| 442 | + priv->spi = spi; | |
| 443 | + | |
| 444 | + reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW); | |
| 445 | + if (IS_ERR(reset_gpio)) { | |
| 446 | + /* chip s/w reset if h/w reset failed */ | |
| 447 | + hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST); | |
| 448 | + hi8435_writeb(priv, HI8435_CTRL_REG, 0); | |
| 449 | + } else { | |
| 450 | + udelay(5); | |
| 451 | + gpiod_set_value(reset_gpio, 1); | |
| 452 | + } | |
| 453 | + | |
| 454 | + spi_set_drvdata(spi, idev); | |
| 455 | + mutex_init(&priv->lock); | |
| 456 | + | |
| 457 | + idev->dev.parent = &spi->dev; | |
| 458 | + idev->name = spi_get_device_id(spi)->name; | |
| 459 | + idev->modes = INDIO_DIRECT_MODE; | |
| 460 | + idev->info = &hi8435_info; | |
| 461 | + idev->channels = hi8435_channels; | |
| 462 | + idev->num_channels = ARRAY_SIZE(hi8435_channels); | |
| 463 | + | |
| 464 | + /* unmask all events */ | |
| 465 | + priv->event_scan_mask = ~(0); | |
| 466 | + /* | |
| 467 | + * There is a restriction in the chip - the hysteresis can not be odd. | |
| 468 | + * If the hysteresis is set to odd value then chip gets into lock state | |
| 469 | + * and not functional anymore. | |
| 470 | + * After chip reset the thresholds are in undefined state, so we need to | |
| 471 | + * initialize thresholds to some initial values and then prevent | |
| 472 | + * userspace setting odd hysteresis. | |
| 473 | + * | |
| 474 | + * Set threshold low voltage to 2V, threshold high voltage to 4V | |
| 475 | + * for both GND-Open and Supply-Open sensing modes. | |
| 476 | + */ | |
| 477 | + priv->threshold_lo[0] = priv->threshold_lo[1] = 2; | |
| 478 | + priv->threshold_hi[0] = priv->threshold_hi[1] = 4; | |
| 479 | + hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206); | |
| 480 | + hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206); | |
| 481 | + | |
| 482 | + ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler); | |
| 483 | + if (ret) | |
| 484 | + return ret; | |
| 485 | + | |
| 486 | + ret = iio_device_register(idev); | |
| 487 | + if (ret < 0) { | |
| 488 | + dev_err(&spi->dev, "unable to register device\n"); | |
| 489 | + goto unregister_triggered_event; | |
| 490 | + } | |
| 491 | + | |
| 492 | + return 0; | |
| 493 | + | |
| 494 | +unregister_triggered_event: | |
| 495 | + iio_triggered_event_cleanup(idev); | |
| 496 | + return ret; | |
| 497 | +} | |
| 498 | + | |
| 499 | +static int hi8435_remove(struct spi_device *spi) | |
| 500 | +{ | |
| 501 | + struct iio_dev *idev = spi_get_drvdata(spi); | |
| 502 | + | |
| 503 | + iio_device_unregister(idev); | |
| 504 | + iio_triggered_event_cleanup(idev); | |
| 505 | + | |
| 506 | + return 0; | |
| 507 | +} | |
| 508 | + | |
| 509 | +static const struct of_device_id hi8435_dt_ids[] = { | |
| 510 | + { .compatible = "holt,hi8435" }, | |
| 511 | + {}, | |
| 512 | +}; | |
| 513 | +MODULE_DEVICE_TABLE(of, hi8435_dt_ids); | |
| 514 | + | |
| 515 | +static const struct spi_device_id hi8435_id[] = { | |
| 516 | + { "hi8435", 0}, | |
| 517 | + { } | |
| 518 | +}; | |
| 519 | +MODULE_DEVICE_TABLE(spi, hi8435_id); | |
| 520 | + | |
| 521 | +static struct spi_driver hi8435_driver = { | |
| 522 | + .driver = { | |
| 523 | + .name = DRV_NAME, | |
| 524 | + .of_match_table = of_match_ptr(hi8435_dt_ids), | |
| 525 | + }, | |
| 526 | + .probe = hi8435_probe, | |
| 527 | + .remove = hi8435_remove, | |
| 528 | + .id_table = hi8435_id, | |
| 529 | +}; | |
| 530 | +module_spi_driver(hi8435_driver); | |
| 531 | + | |
| 532 | +MODULE_LICENSE("GPL"); | |
| 533 | +MODULE_AUTHOR("Vladimir Barinov"); | |
| 534 | +MODULE_DESCRIPTION("HI-8435 threshold detector"); | |
| @@ -508,6 +508,7 @@ static int max1027_remove(struct spi_device *spi) · 507 unmodified lines | ||
| 508 | 508 | static struct spi_driver max1027_driver = { |
| 509 | 509 | .driver = { |
| 510 | 510 | .name = "max1027", |
| 511 | + .of_match_table = of_match_ptr(max1027_adc_dt_ids), | |
| 511 | 512 | .owner = THIS_MODULE, |
| 512 | 513 | }, |
| 513 | 514 | .probe = max1027_probe, |
| @@ -1007,7 +1007,6 @@ static struct attribute *max1363_event_attributes[] = { · 1006 unmodified lines | ||
| 1007 | 1007 | |
| 1008 | 1008 | static struct attribute_group max1363_event_attribute_group = { |
| 1009 | 1009 | .attrs = max1363_event_attributes, |
| 1010 | − .name = "events", | |
| 1011 | 1010 | }; |
| 1012 | 1011 | |
| 1013 | 1012 | static int max1363_update_scan_mode(struct iio_dev *indio_dev, |
| @@ -404,6 +404,7 @@ MODULE_DEVICE_TABLE(spi, mcp320x_id); · 403 unmodified lines | ||
| 404 | 404 | static struct spi_driver mcp320x_driver = { |
| 405 | 405 | .driver = { |
| 406 | 406 | .name = "mcp320x", |
| 407 | + .of_match_table = of_match_ptr(mcp320x_dt_ids), | |
| 407 | 408 | .owner = THIS_MODULE, |
| 408 | 409 | }, |
| 409 | 410 | .probe = mcp320x_probe, |
| @@ -174,6 +174,13 @@ static int adc128_remove(struct spi_device *spi) · 173 unmodified lines | ||
| 174 | 174 | return 0; |
| 175 | 175 | } |
| 176 | 176 | |
| 177 | +static const struct of_device_id adc128_of_match[] = { | |
| 178 | + { .compatible = "ti,adc128s052", }, | |
| 179 | + { .compatible = "ti,adc122s021", }, | |
| 180 | + { /* sentinel */ }, | |
| 181 | +}; | |
| 182 | +MODULE_DEVICE_TABLE(of, adc128_of_match); | |
| 183 | + | |
| 177 | 184 | static const struct spi_device_id adc128_id[] = { |
| 178 | 185 | { "adc128s052", 0}, /* index into adc128_config */ |
| 179 | 186 | { "adc122s021", 1}, |
| @@ -184,6 +191,7 @@ MODULE_DEVICE_TABLE(spi, adc128_id); · 4 unmodified lines | ||
| 184 | 191 | static struct spi_driver adc128_driver = { |
| 185 | 192 | .driver = { |
| 186 | 193 | .name = "adc128s052", |
| 194 | + .of_match_table = of_match_ptr(adc128_of_match), | |
| 187 | 195 | .owner = THIS_MODULE, |
| 188 | 196 | }, |
| 189 | 197 | .probe = adc128_probe, |
| @@ -875,6 +875,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = { · 874 unmodified lines | ||
| 875 | 875 | }, |
| 876 | 876 | { /* end */ } |
| 877 | 877 | }; |
| 878 | +MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl); | |
| 878 | 879 | |
| 879 | 880 | static int twl6030_gpadc_probe(struct platform_device *pdev) |
| 880 | 881 | { |
| @@ -34,8 +34,11 @@ · 33 unmodified lines | ||
| 34 | 34 | #include <linux/err.h> |
| 35 | 35 | |
| 36 | 36 | #include <linux/iio/iio.h> |
| 37 | +#include <linux/iio/buffer.h> | |
| 37 | 38 | #include <linux/iio/sysfs.h> |
| 38 | −#include <linux/iio/driver.h> | |
| 39 | +#include <linux/iio/trigger.h> | |
| 40 | +#include <linux/iio/trigger_consumer.h> | |
| 41 | +#include <linux/iio/triggered_buffer.h> | |
| 39 | 42 | |
| 40 | 43 | /* This will be the driver name the kernel reports */ |
| 41 | 44 | #define DRIVER_NAME "vf610-adc" |
| @@ -170,6 +173,7 @@ struct vf610_adc { · 128 unmodified lines | ||
| 170 | 173 | u32 sample_freq_avail[5]; |
| 171 | 174 | |
| 172 | 175 | struct completion completion; |
| 176 | + u16 buffer[8]; | |
| 173 | 177 | }; |
| 174 | 178 | |
| 175 | 179 | static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; |
| @@ -505,12 +509,24 @@ static const struct iio_chan_spec_ext_info vf610_ext_info[] = { · 329 unmodified lines | ||
| 505 | 509 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
| 506 | 510 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
| 507 | 511 | .ext_info = vf610_ext_info, \ |
| 512 | + .scan_index = (_idx), \ | |
| 513 | + .scan_type = { \ | |
| 514 | + .sign = 'u', \ | |
| 515 | + .realbits = 12, \ | |
| 516 | + .storagebits = 16, \ | |
| 517 | + }, \ | |
| 508 | 518 | } |
| 509 | 519 | |
| 510 | 520 | #define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \ |
| 511 | 521 | .type = (_chan_type), \ |
| 512 | 522 | .channel = (_idx), \ |
| 513 | 523 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ |
| 524 | + .scan_index = (_idx), \ | |
| 525 | + .scan_type = { \ | |
| 526 | + .sign = 'u', \ | |
| 527 | + .realbits = 12, \ | |
| 528 | + .storagebits = 16, \ | |
| 529 | + }, \ | |
| 514 | 530 | } |
| 515 | 531 | |
| 516 | 532 | static const struct iio_chan_spec vf610_adc_iio_channels[] = { |
| @@ -531,6 +547,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = { · 14 unmodified lines | ||
| 531 | 547 | VF610_ADC_CHAN(14, IIO_VOLTAGE), |
| 532 | 548 | VF610_ADC_CHAN(15, IIO_VOLTAGE), |
| 533 | 549 | VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP), |
| 550 | + IIO_CHAN_SOFT_TIMESTAMP(32), | |
| 534 | 551 | /* sentinel */ |
| 535 | 552 | }; |
| 536 | 553 | |
| @@ -559,13 +576,20 @@ static int vf610_adc_read_data(struct vf610_adc *info) · 22 unmodified lines | ||
| 559 | 576 | |
| 560 | 577 | static irqreturn_t vf610_adc_isr(int irq, void *dev_id) |
| 561 | 578 | { |
| 562 | − struct vf610_adc *info = (struct vf610_adc *)dev_id; | |
| 579 | + struct iio_dev *indio_dev = (struct iio_dev *)dev_id; | |
| 580 | + struct vf610_adc *info = iio_priv(indio_dev); | |
| 563 | 581 | int coco; |
| 564 | 582 | |
| 565 | 583 | coco = readl(info->regs + VF610_REG_ADC_HS); |
| 566 | 584 | if (coco & VF610_ADC_HS_COCO0) { |
| 567 | 585 | info->value = vf610_adc_read_data(info); |
| 568 | − complete(&info->completion); | |
| 586 | + if (iio_buffer_enabled(indio_dev)) { | |
| 587 | + info->buffer[0] = info->value; | |
| 588 | + iio_push_to_buffers_with_timestamp(indio_dev, | |
| 589 | + info->buffer, iio_get_time_ns()); | |
| 590 | + iio_trigger_notify_done(indio_dev->trig); | |
| 591 | + } else | |
| 592 | + complete(&info->completion); | |
| 569 | 593 | } |
| 570 | 594 | |
| 571 | 595 | return IRQ_HANDLED; |
| @@ -613,8 +637,12 @@ static int vf610_read_raw(struct iio_dev *indio_dev, · 41 unmodified lines | ||
| 613 | 637 | case IIO_CHAN_INFO_RAW: |
| 614 | 638 | case IIO_CHAN_INFO_PROCESSED: |
| 615 | 639 | mutex_lock(&indio_dev->mlock); |
| 616 | − reinit_completion(&info->completion); | |
| 640 | + if (iio_buffer_enabled(indio_dev)) { | |
| 641 | + mutex_unlock(&indio_dev->mlock); | |
| 642 | + return -EBUSY; | |
| 643 | + } | |
| 617 | 644 | |
| 645 | + reinit_completion(&info->completion); | |
| 618 | 646 | hc_cfg = VF610_ADC_ADCHC(chan->channel); |
| 619 | 647 | hc_cfg |= VF610_ADC_AIEN; |
| 620 | 648 | writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); |
| @@ -694,6 +722,56 @@ static int vf610_write_raw(struct iio_dev *indio_dev, · 73 unmodified lines | ||
| 694 | 722 | return -EINVAL; |
| 695 | 723 | } |
| 696 | 724 | |
| 725 | +static int vf610_adc_buffer_postenable(struct iio_dev *indio_dev) | |
| 726 | +{ | |
| 727 | + struct vf610_adc *info = iio_priv(indio_dev); | |
| 728 | + unsigned int channel; | |
| 729 | + int ret; | |
| 730 | + int val; | |
| 731 | + | |
| 732 | + ret = iio_triggered_buffer_postenable(indio_dev); | |
| 733 | + if (ret) | |
| 734 | + return ret; | |
| 735 | + | |
| 736 | + val = readl(info->regs + VF610_REG_ADC_GC); | |
| 737 | + val |= VF610_ADC_ADCON; | |
| 738 | + writel(val, info->regs + VF610_REG_ADC_GC); | |
| 739 | + | |
| 740 | + channel = find_first_bit(indio_dev->active_scan_mask, | |
| 741 | + indio_dev->masklength); | |
| 742 | + | |
| 743 | + val = VF610_ADC_ADCHC(channel); | |
| 744 | + val |= VF610_ADC_AIEN; | |
| 745 | + | |
| 746 | + writel(val, info->regs + VF610_REG_ADC_HC0); | |
| 747 | + | |
| 748 | + return 0; | |
| 749 | +} | |
| 750 | + | |
| 751 | +static int vf610_adc_buffer_predisable(struct iio_dev *indio_dev) | |
| 752 | +{ | |
| 753 | + struct vf610_adc *info = iio_priv(indio_dev); | |
| 754 | + unsigned int hc_cfg = 0; | |
| 755 | + int val; | |
| 756 | + | |
| 757 | + val = readl(info->regs + VF610_REG_ADC_GC); | |
| 758 | + val &= ~VF610_ADC_ADCON; | |
| 759 | + writel(val, info->regs + VF610_REG_ADC_GC); | |
| 760 | + | |
| 761 | + hc_cfg |= VF610_ADC_CONV_DISABLE; | |
| 762 | + hc_cfg &= ~VF610_ADC_AIEN; | |
| 763 | + | |
| 764 | + writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); | |
| 765 | + | |
| 766 | + return iio_triggered_buffer_predisable(indio_dev); | |
| 767 | +} | |
| 768 | + | |
| 769 | +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { | |
| 770 | + .postenable = &vf610_adc_buffer_postenable, | |
| 771 | + .predisable = &vf610_adc_buffer_predisable, | |
| 772 | + .validate_scan_mask = &iio_validate_scan_mask_onehot, | |
| 773 | +}; | |
| 774 | + | |
| 697 | 775 | static int vf610_adc_reg_access(struct iio_dev *indio_dev, |
| 698 | 776 | unsigned reg, unsigned writeval, |
| 699 | 777 | unsigned *readval) |
| @@ -753,7 +831,7 @@ static int vf610_adc_probe(struct platform_device *pdev) · 53 unmodified lines | ||
| 753 | 831 | |
| 754 | 832 | ret = devm_request_irq(info->dev, irq, |
| 755 | 833 | vf610_adc_isr, 0, |
| 756 | − dev_name(&pdev->dev), info); | |
| 834 | + dev_name(&pdev->dev), indio_dev); | |
| 757 | 835 | if (ret < 0) { |
| 758 | 836 | dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); |
| 759 | 837 | return ret; |
| @@ -806,15 +884,23 @@ static int vf610_adc_probe(struct platform_device *pdev) · 46 unmodified lines | ||
| 806 | 884 | vf610_adc_cfg_init(info); |
| 807 | 885 | vf610_adc_hw_init(info); |
| 808 | 886 | |
| 887 | + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | |
| 888 | + NULL, &iio_triggered_buffer_setup_ops); | |
| 889 | + if (ret < 0) { | |
| 890 | + dev_err(&pdev->dev, "Couldn't initialise the buffer\n"); | |
| 891 | + goto error_iio_device_register; | |
| 892 | + } | |
| 893 | + | |
| 809 | 894 | ret = iio_device_register(indio_dev); |
| 810 | 895 | if (ret) { |
| 811 | 896 | dev_err(&pdev->dev, "Couldn't register the device.\n"); |
| 812 | − goto error_iio_device_register; | |
| 897 | + goto error_adc_buffer_init; | |
| 813 | 898 | } |
| 814 | 899 | |
| 815 | 900 | return 0; |
| 816 | 901 | |
| 817 | − | |
| 902 | +error_adc_buffer_init: | |
| 903 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 818 | 904 | error_iio_device_register: |
| 819 | 905 | clk_disable_unprepare(info->clk); |
| 820 | 906 | error_adc_clk_enable: |
| @@ -829,6 +915,7 @@ static int vf610_adc_remove(struct platform_device *pdev) · 8 unmodified lines | ||
| 829 | 915 | struct vf610_adc *info = iio_priv(indio_dev); |
| 830 | 916 | |
| 831 | 917 | iio_device_unregister(indio_dev); |
| 918 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 832 | 919 | regulator_disable(info->vref); |
| 833 | 920 | clk_disable_unprepare(info->clk); |
| 834 | 921 | |
| @@ -273,33 +273,13 @@ static void xadc_zynq_unmask_worker(struct work_struct *work) · 272 unmodified lines | ||
| 273 | 273 | schedule_delayed_work(&xadc->zynq_unmask_work, |
| 274 | 274 | msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); |
| 275 | 275 | } |
| 276 | −} | |
| 277 | − | |
| 278 | −static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid) | |
| 279 | −{ | |
| 280 | − struct iio_dev *indio_dev = devid; | |
| 281 | − struct xadc *xadc = iio_priv(indio_dev); | |
| 282 | − unsigned int alarm; | |
| 283 | − | |
| 284 | − spin_lock_irq(&xadc->lock); | |
| 285 | − alarm = xadc->zynq_alarm; | |
| 286 | − xadc->zynq_alarm = 0; | |
| 287 | − spin_unlock_irq(&xadc->lock); | |
| 288 | − | |
| 289 | − xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm)); | |
| 290 | 276 | |
| 291 | − /* unmask the required interrupts in timer. */ | |
| 292 | − schedule_delayed_work(&xadc->zynq_unmask_work, | |
| 293 | − msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); | |
| 294 | − | |
| 295 | − return IRQ_HANDLED; | |
| 296 | 277 | } |
| 297 | 278 | |
| 298 | 279 | static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) |
| 299 | 280 | { |
| 300 | 281 | struct iio_dev *indio_dev = devid; |
| 301 | 282 | struct xadc *xadc = iio_priv(indio_dev); |
| 302 | − irqreturn_t ret = IRQ_HANDLED; | |
| 303 | 283 | uint32_t status; |
| 304 | 284 | |
| 305 | 285 | xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status); |
| @@ -321,18 +301,23 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid) · 15 unmodified lines | ||
| 321 | 301 | |
| 322 | 302 | status &= XADC_ZYNQ_INT_ALARM_MASK; |
| 323 | 303 | if (status) { |
| 324 | − xadc->zynq_alarm |= status; | |
| 325 | 304 | xadc->zynq_masked_alarm |= status; |
| 326 | 305 | /* |
| 327 | 306 | * mask the current event interrupt, |
| 328 | 307 | * unmask it when the interrupt is no more active. |
| 329 | 308 | */ |
| 330 | 309 | xadc_zynq_update_intmsk(xadc, 0, 0); |
| 331 | − ret = IRQ_WAKE_THREAD; | |
| 310 | + | |
| 311 | + xadc_handle_events(indio_dev, | |
| 312 | + xadc_zynq_transform_alarm(status)); | |
| 313 | + | |
| 314 | + /* unmask the required interrupts in timer. */ | |
| 315 | + schedule_delayed_work(&xadc->zynq_unmask_work, | |
| 316 | + msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT)); | |
| 332 | 317 | } |
| 333 | 318 | spin_unlock(&xadc->lock); |
| 334 | 319 | |
| 335 | − return ret; | |
| 320 | + return IRQ_HANDLED; | |
| 336 | 321 | } |
| 337 | 322 | |
| 338 | 323 | #define XADC_ZYNQ_TCK_RATE_MAX 50000000 |
| @@ -437,7 +422,6 @@ static const struct xadc_ops xadc_zynq_ops = { · 98 unmodified lines | ||
| 437 | 422 | .setup = xadc_zynq_setup, |
| 438 | 423 | .get_dclk_rate = xadc_zynq_get_dclk_rate, |
| 439 | 424 | .interrupt_handler = xadc_zynq_interrupt_handler, |
| 440 | − .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler, | |
| 441 | 425 | .update_alarm = xadc_zynq_update_alarm, |
| 442 | 426 | }; |
| 443 | 427 | |
| @@ -1225,9 +1209,8 @@ static int xadc_probe(struct platform_device *pdev) · 781 unmodified lines | ||
| 1225 | 1209 | if (ret) |
| 1226 | 1210 | goto err_free_samplerate_trigger; |
| 1227 | 1211 | |
| 1228 | − ret = request_threaded_irq(irq, xadc->ops->interrupt_handler, | |
| 1229 | − xadc->ops->threaded_interrupt_handler, | |
| 1230 | − 0, dev_name(&pdev->dev), indio_dev); | |
| 1212 | + ret = request_irq(irq, xadc->ops->interrupt_handler, 0, | |
| 1213 | + dev_name(&pdev->dev), indio_dev); | |
| 1231 | 1214 | if (ret) |
| 1232 | 1215 | goto err_clk_disable_unprepare; |
| 1233 | 1216 | |
| @@ -60,7 +60,6 @@ struct xadc { · 59 unmodified lines | ||
| 60 | 60 | |
| 61 | 61 | enum xadc_external_mux_mode external_mux_mode; |
| 62 | 62 | |
| 63 | − unsigned int zynq_alarm; | |
| 64 | 63 | unsigned int zynq_masked_alarm; |
| 65 | 64 | unsigned int zynq_intmask; |
| 66 | 65 | struct delayed_work zynq_unmask_work; |
| @@ -79,7 +78,6 @@ struct xadc_ops { · 12 unmodified lines | ||
| 79 | 78 | void (*update_alarm)(struct xadc *, unsigned int); |
| 80 | 79 | unsigned long (*get_dclk_rate)(struct xadc *); |
| 81 | 80 | irqreturn_t (*interrupt_handler)(int, void *); |
| 82 | − irqreturn_t (*threaded_interrupt_handler)(int, void *); | |
| 83 | 81 | |
| 84 | 82 | unsigned int flags; |
| 85 | 83 | }; |
| @@ -195,6 +195,7 @@ static const struct spi_device_id ad8366_id[] = { · 194 unmodified lines | ||
| 195 | 195 | {"ad8366", 0}, |
| 196 | 196 | {} |
| 197 | 197 | }; |
| 198 | +MODULE_DEVICE_TABLE(spi, ad8366_id); | |
| 198 | 199 | |
| 199 | 200 | static struct spi_driver ad8366_driver = { |
| 200 | 201 | .driver = { |
| @@ -0,0 +1,24 @@ | ||
| 1 | +# | |
| 2 | +# Industrial I/O generic buffer implementations | |
| 3 | +# | |
| 4 | +# When adding new entries keep the list in alphabetical order | |
| 5 | + | |
| 6 | +config IIO_BUFFER_CB | |
| 7 | + tristate "IIO callback buffer used for push in-kernel interfaces" | |
| 8 | + help | |
| 9 | + Should be selected by any drivers that do in-kernel push | |
| 10 | + usage. That is, those where the data is pushed to the consumer. | |
| 11 | + | |
| 12 | +config IIO_KFIFO_BUF | |
| 13 | + tristate "Industrial I/O buffering based on kfifo" | |
| 14 | + help | |
| 15 | + A simple fifo based on kfifo. Note that this currently provides | |
| 16 | + no buffer events so it is up to userspace to work out how | |
| 17 | + often to read from the buffer. | |
| 18 | + | |
| 19 | +config IIO_TRIGGERED_BUFFER | |
| 20 | + tristate | |
| 21 | + select IIO_TRIGGER | |
| 22 | + select IIO_KFIFO_BUF | |
| 23 | + help | |
| 24 | + Provides helper functions for setting up triggered buffers. | |
| @@ -0,0 +1,8 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for the industrial I/O buffer implementations | |
| 3 | +# | |
| 4 | + | |
| 5 | +# When adding new entries keep the list in alphabetical order | |
| 6 | +obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o | |
| 7 | +obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o | |
| 8 | +obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o | |
| @@ -1,4 +1,12 @@ | ||
| 1 | +/* The industrial I/O callback buffer | |
| 2 | + * | |
| 3 | + * This program is free software; you can redistribute it and/or modify it | |
| 4 | + * under the terms of the GNU General Public License version 2 as published by | |
| 5 | + * the Free Software Foundation. | |
| 6 | + */ | |
| 7 | + | |
| 1 | 8 | #include <linux/kernel.h> |
| 9 | +#include <linux/module.h> | |
| 2 | 10 | #include <linux/slab.h> |
| 3 | 11 | #include <linux/err.h> |
| 4 | 12 | #include <linux/export.h> |
| @@ -124,3 +132,7 @@ struct iio_channel · 119 unmodified lines | ||
| 124 | 132 | return cb_buffer->channels; |
| 125 | 133 | } |
| 126 | 134 | EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels); |
| 135 | + | |
| 136 | +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); | |
| 137 | +MODULE_DESCRIPTION("Industrial I/O callback buffer"); | |
| 138 | +MODULE_LICENSE("GPL"); | |
File renamed without changes.
File renamed without changes.
| @@ -0,0 +1,15 @@ | ||
| 1 | +# | |
| 2 | +# Chemical sensors | |
| 3 | +# | |
| 4 | + | |
| 5 | +menu "Chemical Sensors" | |
| 6 | + | |
| 7 | +config VZ89X | |
| 8 | + tristate "SGX Sensortech MiCS VZ89X VOC sensor" | |
| 9 | + depends on I2C | |
| 10 | + help | |
| 11 | + Say Y here to build I2C interface support for the SGX | |
| 12 | + Sensortech MiCS VZ89X VOC (Volatile Organic Compounds) | |
| 13 | + sensors | |
| 14 | + | |
| 15 | +endmenu | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for IIO chemical sensors | |
| 3 | +# | |
| 4 | + | |
| 5 | +# When adding new entries keep the list in alphabetical order | |
| 6 | +obj-$(CONFIG_VZ89X) += vz89x.o | |
| @@ -0,0 +1,256 @@ | ||
| 1 | +/* | |
| 2 | + * vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors | |
| 3 | + * | |
| 4 | + * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + * | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/mutex.h> | |
| 20 | +#include <linux/init.h> | |
| 21 | +#include <linux/i2c.h> | |
| 22 | + | |
| 23 | +#include <linux/iio/iio.h> | |
| 24 | +#include <linux/iio/sysfs.h> | |
| 25 | + | |
| 26 | +#define VZ89X_REG_MEASUREMENT 0x09 | |
| 27 | +#define VZ89X_REG_MEASUREMENT_SIZE 6 | |
| 28 | + | |
| 29 | +#define VZ89X_VOC_CO2_IDX 0 | |
| 30 | +#define VZ89X_VOC_SHORT_IDX 1 | |
| 31 | +#define VZ89X_VOC_TVOC_IDX 2 | |
| 32 | +#define VZ89X_VOC_RESISTANCE_IDX 3 | |
| 33 | + | |
| 34 | +struct vz89x_data { | |
| 35 | + struct i2c_client *client; | |
| 36 | + struct mutex lock; | |
| 37 | + unsigned long last_update; | |
| 38 | + | |
| 39 | + u8 buffer[VZ89X_REG_MEASUREMENT_SIZE]; | |
| 40 | +}; | |
| 41 | + | |
| 42 | +static const struct iio_chan_spec vz89x_channels[] = { | |
| 43 | + { | |
| 44 | + .type = IIO_CONCENTRATION, | |
| 45 | + .channel2 = IIO_MOD_CO2, | |
| 46 | + .modified = 1, | |
| 47 | + .info_mask_separate = | |
| 48 | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), | |
| 49 | + .address = VZ89X_VOC_CO2_IDX, | |
| 50 | + }, | |
| 51 | + { | |
| 52 | + .type = IIO_CONCENTRATION, | |
| 53 | + .channel2 = IIO_MOD_VOC, | |
| 54 | + .modified = 1, | |
| 55 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| 56 | + .address = VZ89X_VOC_SHORT_IDX, | |
| 57 | + .extend_name = "short", | |
| 58 | + }, | |
| 59 | + { | |
| 60 | + .type = IIO_CONCENTRATION, | |
| 61 | + .channel2 = IIO_MOD_VOC, | |
| 62 | + .modified = 1, | |
| 63 | + .info_mask_separate = | |
| 64 | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), | |
| 65 | + .address = VZ89X_VOC_TVOC_IDX, | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + .type = IIO_RESISTANCE, | |
| 69 | + .info_mask_separate = | |
| 70 | + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | |
| 71 | + .address = VZ89X_VOC_RESISTANCE_IDX, | |
| 72 | + }, | |
| 73 | +}; | |
| 74 | + | |
| 75 | +static IIO_CONST_ATTR(in_concentration_co2_scale, "0.00000698689"); | |
| 76 | +static IIO_CONST_ATTR(in_concentration_voc_scale, "0.00000000436681223"); | |
| 77 | + | |
| 78 | +static struct attribute *vz89x_attributes[] = { | |
| 79 | + &iio_const_attr_in_concentration_co2_scale.dev_attr.attr, | |
| 80 | + &iio_const_attr_in_concentration_voc_scale.dev_attr.attr, | |
| 81 | + NULL, | |
| 82 | +}; | |
| 83 | + | |
| 84 | +static const struct attribute_group vz89x_attrs_group = { | |
| 85 | + .attrs = vz89x_attributes, | |
| 86 | +}; | |
| 87 | + | |
| 88 | +/* | |
| 89 | + * Chipset sometime updates in the middle of a reading causing it to reset the | |
| 90 | + * data pointer, and causing invalid reading of previous data. | |
| 91 | + * We can check for this by reading MSB of the resistance reading that is | |
| 92 | + * always zero, and by also confirming the VOC_short isn't zero. | |
| 93 | + */ | |
| 94 | + | |
| 95 | +static int vz89x_measurement_is_valid(struct vz89x_data *data) | |
| 96 | +{ | |
| 97 | + if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) | |
| 98 | + return 1; | |
| 99 | + | |
| 100 | + return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0); | |
| 101 | +} | |
| 102 | + | |
| 103 | +static int vz89x_get_measurement(struct vz89x_data *data) | |
| 104 | +{ | |
| 105 | + int ret; | |
| 106 | + int i; | |
| 107 | + | |
| 108 | + /* sensor can only be polled once a second max per datasheet */ | |
| 109 | + if (!time_after(jiffies, data->last_update + HZ)) | |
| 110 | + return 0; | |
| 111 | + | |
| 112 | + ret = i2c_smbus_write_word_data(data->client, | |
| 113 | + VZ89X_REG_MEASUREMENT, 0); | |
| 114 | + if (ret < 0) | |
| 115 | + return ret; | |
| 116 | + | |
| 117 | + for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) { | |
| 118 | + ret = i2c_smbus_read_byte(data->client); | |
| 119 | + if (ret < 0) | |
| 120 | + return ret; | |
| 121 | + data->buffer[i] = ret; | |
| 122 | + } | |
| 123 | + | |
| 124 | + ret = vz89x_measurement_is_valid(data); | |
| 125 | + if (ret) | |
| 126 | + return -EAGAIN; | |
| 127 | + | |
| 128 | + data->last_update = jiffies; | |
| 129 | + | |
| 130 | + return 0; | |
| 131 | +} | |
| 132 | + | |
| 133 | +static int vz89x_get_resistance_reading(struct vz89x_data *data) | |
| 134 | +{ | |
| 135 | + u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX]; | |
| 136 | + | |
| 137 | + return buf[0] | (buf[1] << 8); | |
| 138 | +} | |
| 139 | + | |
| 140 | +static int vz89x_read_raw(struct iio_dev *indio_dev, | |
| 141 | + struct iio_chan_spec const *chan, int *val, | |
| 142 | + int *val2, long mask) | |
| 143 | +{ | |
| 144 | + struct vz89x_data *data = iio_priv(indio_dev); | |
| 145 | + int ret = -EINVAL; | |
| 146 | + | |
| 147 | + switch (mask) { | |
| 148 | + case IIO_CHAN_INFO_RAW: | |
| 149 | + mutex_lock(&data->lock); | |
| 150 | + ret = vz89x_get_measurement(data); | |
| 151 | + mutex_unlock(&data->lock); | |
| 152 | + | |
| 153 | + if (ret) | |
| 154 | + return ret; | |
| 155 | + | |
| 156 | + switch (chan->address) { | |
| 157 | + case VZ89X_VOC_CO2_IDX: | |
| 158 | + case VZ89X_VOC_SHORT_IDX: | |
| 159 | + case VZ89X_VOC_TVOC_IDX: | |
| 160 | + *val = data->buffer[chan->address]; | |
| 161 | + return IIO_VAL_INT; | |
| 162 | + case VZ89X_VOC_RESISTANCE_IDX: | |
| 163 | + *val = vz89x_get_resistance_reading(data); | |
| 164 | + return IIO_VAL_INT; | |
| 165 | + default: | |
| 166 | + return -EINVAL; | |
| 167 | + } | |
| 168 | + break; | |
| 169 | + case IIO_CHAN_INFO_SCALE: | |
| 170 | + switch (chan->type) { | |
| 171 | + case IIO_RESISTANCE: | |
| 172 | + *val = 10; | |
| 173 | + return IIO_VAL_INT; | |
| 174 | + default: | |
| 175 | + return -EINVAL; | |
| 176 | + } | |
| 177 | + break; | |
| 178 | + case IIO_CHAN_INFO_OFFSET: | |
| 179 | + switch (chan->address) { | |
| 180 | + case VZ89X_VOC_CO2_IDX: | |
| 181 | + *val = 44; | |
| 182 | + *val2 = 250000; | |
| 183 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 184 | + case VZ89X_VOC_TVOC_IDX: | |
| 185 | + *val = -13; | |
| 186 | + return IIO_VAL_INT; | |
| 187 | + default: | |
| 188 | + return -EINVAL; | |
| 189 | + } | |
| 190 | + } | |
| 191 | + | |
| 192 | + return ret; | |
| 193 | +} | |
| 194 | + | |
| 195 | +static const struct iio_info vz89x_info = { | |
| 196 | + .attrs = &vz89x_attrs_group, | |
| 197 | + .read_raw = vz89x_read_raw, | |
| 198 | + .driver_module = THIS_MODULE, | |
| 199 | +}; | |
| 200 | + | |
| 201 | +static int vz89x_probe(struct i2c_client *client, | |
| 202 | + const struct i2c_device_id *id) | |
| 203 | +{ | |
| 204 | + struct iio_dev *indio_dev; | |
| 205 | + struct vz89x_data *data; | |
| 206 | + | |
| 207 | + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | | |
| 208 | + I2C_FUNC_SMBUS_BYTE)) | |
| 209 | + return -ENODEV; | |
| 210 | + | |
| 211 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 212 | + if (!indio_dev) | |
| 213 | + return -ENOMEM; | |
| 214 | + | |
| 215 | + data = iio_priv(indio_dev); | |
| 216 | + i2c_set_clientdata(client, indio_dev); | |
| 217 | + data->client = client; | |
| 218 | + data->last_update = jiffies - HZ; | |
| 219 | + mutex_init(&data->lock); | |
| 220 | + | |
| 221 | + indio_dev->dev.parent = &client->dev; | |
| 222 | + indio_dev->info = &vz89x_info, | |
| 223 | + indio_dev->name = dev_name(&client->dev); | |
| 224 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 225 | + | |
| 226 | + indio_dev->channels = vz89x_channels; | |
| 227 | + indio_dev->num_channels = ARRAY_SIZE(vz89x_channels); | |
| 228 | + | |
| 229 | + return devm_iio_device_register(&client->dev, indio_dev); | |
| 230 | +} | |
| 231 | + | |
| 232 | +static const struct i2c_device_id vz89x_id[] = { | |
| 233 | + { "vz89x", 0 }, | |
| 234 | + { } | |
| 235 | +}; | |
| 236 | +MODULE_DEVICE_TABLE(i2c, vz89x_id); | |
| 237 | + | |
| 238 | +static const struct of_device_id vz89x_dt_ids[] = { | |
| 239 | + { .compatible = "sgx,vz89x" }, | |
| 240 | + { } | |
| 241 | +}; | |
| 242 | +MODULE_DEVICE_TABLE(of, vz89x_dt_ids); | |
| 243 | + | |
| 244 | +static struct i2c_driver vz89x_driver = { | |
| 245 | + .driver = { | |
| 246 | + .name = "vz89x", | |
| 247 | + .of_match_table = of_match_ptr(vz89x_dt_ids), | |
| 248 | + }, | |
| 249 | + .probe = vz89x_probe, | |
| 250 | + .id_table = vz89x_id, | |
| 251 | +}; | |
| 252 | +module_i2c_driver(vz89x_driver); | |
| 253 | + | |
| 254 | +MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); | |
| 255 | +MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors"); | |
| 256 | +MODULE_LICENSE("GPL v2"); | |
| @@ -3,5 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | # |
| 4 | 4 | |
| 5 | 5 | source "drivers/iio/common/hid-sensors/Kconfig" |
| 6 | +source "drivers/iio/common/ms_sensors/Kconfig" | |
| 6 | 7 | source "drivers/iio/common/ssp_sensors/Kconfig" |
| 7 | 8 | source "drivers/iio/common/st_sensors/Kconfig" |
| @@ -8,5 +8,6 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | # When adding new entries keep the list in alphabetical order |
| 10 | 10 | obj-y += hid-sensors/ |
| 11 | +obj-y += ms_sensors/ | |
| 11 | 12 | obj-y += ssp_sensors/ |
| 12 | 13 | obj-y += st_sensors/ |
| @@ -0,0 +1,6 @@ | ||
| 1 | +# | |
| 2 | +# Measurements Specialties sensors common library | |
| 3 | +# | |
| 4 | + | |
| 5 | +config IIO_MS_SENSORS_I2C | |
| 6 | + tristate | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for the Measurement Specialties sensor common modules. | |
| 3 | +# | |
| 4 | + | |
| 5 | +obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o | |
| @@ -0,0 +1,652 @@ | ||
| 1 | +/* | |
| 2 | + * Measurements Specialties driver common i2c functions | |
| 3 | + * | |
| 4 | + * Copyright (c) 2015 Measurement-Specialties | |
| 5 | + * | |
| 6 | + * Licensed under the GPL-2. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/module.h> | |
| 10 | +#include <linux/iio/iio.h> | |
| 11 | +#include <linux/device.h> | |
| 12 | +#include <linux/delay.h> | |
| 13 | + | |
| 14 | +#include "ms_sensors_i2c.h" | |
| 15 | + | |
| 16 | +/* Conversion times in us */ | |
| 17 | +static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000, | |
| 18 | + 13000, 7000 }; | |
| 19 | +static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000, | |
| 20 | + 5000, 8000 }; | |
| 21 | +static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100, | |
| 22 | + 4100, 8220, 16440 }; | |
| 23 | + | |
| 24 | +#define MS_SENSORS_SERIAL_READ_MSB 0xFA0F | |
| 25 | +#define MS_SENSORS_SERIAL_READ_LSB 0xFCC9 | |
| 26 | +#define MS_SENSORS_CONFIG_REG_WRITE 0xE6 | |
| 27 | +#define MS_SENSORS_CONFIG_REG_READ 0xE7 | |
| 28 | +#define MS_SENSORS_HT_T_CONVERSION_START 0xF3 | |
| 29 | +#define MS_SENSORS_HT_H_CONVERSION_START 0xF5 | |
| 30 | + | |
| 31 | +#define MS_SENSORS_TP_PROM_READ 0xA0 | |
| 32 | +#define MS_SENSORS_TP_T_CONVERSION_START 0x50 | |
| 33 | +#define MS_SENSORS_TP_P_CONVERSION_START 0x40 | |
| 34 | +#define MS_SENSORS_TP_ADC_READ 0x00 | |
| 35 | + | |
| 36 | +#define MS_SENSORS_NO_READ_CMD 0xFF | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * ms_sensors_reset() - Reset function | |
| 40 | + * @cli: pointer to device client | |
| 41 | + * @cmd: reset cmd. Depends on device in use | |
| 42 | + * @delay: usleep minimal delay after reset command is issued | |
| 43 | + * | |
| 44 | + * Generic I2C reset function for Measurement Specialties devices. | |
| 45 | + * | |
| 46 | + * Return: 0 on success, negative errno otherwise. | |
| 47 | + */ | |
| 48 | +int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay) | |
| 49 | +{ | |
| 50 | + int ret; | |
| 51 | + struct i2c_client *client = cli; | |
| 52 | + | |
| 53 | + ret = i2c_smbus_write_byte(client, cmd); | |
| 54 | + if (ret) { | |
| 55 | + dev_err(&client->dev, "Failed to reset device\n"); | |
| 56 | + return ret; | |
| 57 | + } | |
| 58 | + usleep_range(delay, delay + 1000); | |
| 59 | + | |
| 60 | + return 0; | |
| 61 | +} | |
| 62 | +EXPORT_SYMBOL(ms_sensors_reset); | |
| 63 | + | |
| 64 | +/** | |
| 65 | + * ms_sensors_read_prom_word() - PROM word read function | |
| 66 | + * @cli: pointer to device client | |
| 67 | + * @cmd: PROM read cmd. Depends on device and prom id | |
| 68 | + * @word: pointer to word destination value | |
| 69 | + * | |
| 70 | + * Generic i2c prom word read function for Measurement Specialties devices. | |
| 71 | + * | |
| 72 | + * Return: 0 on success, negative errno otherwise. | |
| 73 | + */ | |
| 74 | +int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word) | |
| 75 | +{ | |
| 76 | + int ret; | |
| 77 | + struct i2c_client *client = (struct i2c_client *)cli; | |
| 78 | + | |
| 79 | + ret = i2c_smbus_read_word_swapped(client, cmd); | |
| 80 | + if (ret < 0) { | |
| 81 | + dev_err(&client->dev, "Failed to read prom word\n"); | |
| 82 | + return ret; | |
| 83 | + } | |
| 84 | + *word = ret; | |
| 85 | + | |
| 86 | + return 0; | |
| 87 | +} | |
| 88 | +EXPORT_SYMBOL(ms_sensors_read_prom_word); | |
| 89 | + | |
| 90 | +/** | |
| 91 | + * ms_sensors_convert_and_read() - ADC conversion & read function | |
| 92 | + * @cli: pointer to device client | |
| 93 | + * @conv: ADC conversion command. Depends on device in use | |
| 94 | + * @rd: ADC read command. Depends on device in use | |
| 95 | + * @delay: usleep minimal delay after conversion command is issued | |
| 96 | + * @adc: pointer to ADC destination value | |
| 97 | + * | |
| 98 | + * Generic ADC conversion & read function for Measurement Specialties | |
| 99 | + * devices. | |
| 100 | + * The function will issue conversion command, sleep appopriate delay, and | |
| 101 | + * issue command to read ADC. | |
| 102 | + * | |
| 103 | + * Return: 0 on success, negative errno otherwise. | |
| 104 | + */ | |
| 105 | +int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd, | |
| 106 | + unsigned int delay, u32 *adc) | |
| 107 | +{ | |
| 108 | + int ret; | |
| 109 | + __be32 buf = 0; | |
| 110 | + struct i2c_client *client = (struct i2c_client *)cli; | |
| 111 | + | |
| 112 | + /* Trigger conversion */ | |
| 113 | + ret = i2c_smbus_write_byte(client, conv); | |
| 114 | + if (ret) | |
| 115 | + goto err; | |
| 116 | + usleep_range(delay, delay + 1000); | |
| 117 | + | |
| 118 | + /* Retrieve ADC value */ | |
| 119 | + if (rd != MS_SENSORS_NO_READ_CMD) | |
| 120 | + ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf); | |
| 121 | + else | |
| 122 | + ret = i2c_master_recv(client, (u8 *)&buf, 3); | |
| 123 | + if (ret < 0) | |
| 124 | + goto err; | |
| 125 | + | |
| 126 | + dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8); | |
| 127 | + *adc = be32_to_cpu(buf) >> 8; | |
| 128 | + | |
| 129 | + return 0; | |
| 130 | +err: | |
| 131 | + dev_err(&client->dev, "Unable to make sensor adc conversion\n"); | |
| 132 | + return ret; | |
| 133 | +} | |
| 134 | +EXPORT_SYMBOL(ms_sensors_convert_and_read); | |
| 135 | + | |
| 136 | +/** | |
| 137 | + * ms_sensors_crc_valid() - CRC check function | |
| 138 | + * @value: input and CRC compare value | |
| 139 | + * | |
| 140 | + * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607. | |
| 141 | + * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC. | |
| 142 | + * The argument contains CRC value in LSB byte while the bytes 1 and 2 | |
| 143 | + * are used for CRC computation. | |
| 144 | + * | |
| 145 | + * Return: 1 if CRC is valid, 0 otherwise. | |
| 146 | + */ | |
| 147 | +static bool ms_sensors_crc_valid(u32 value) | |
| 148 | +{ | |
| 149 | + u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */ | |
| 150 | + u32 msb = 0x800000; | |
| 151 | + u32 mask = 0xFF8000; | |
| 152 | + u32 result = value & 0xFFFF00; | |
| 153 | + u8 crc = value & 0xFF; | |
| 154 | + | |
| 155 | + while (msb != 0x80) { | |
| 156 | + if (result & msb) | |
| 157 | + result = ((result ^ polynom) & mask) | |
| 158 | + | (result & ~mask); | |
| 159 | + msb >>= 1; | |
| 160 | + mask >>= 1; | |
| 161 | + polynom >>= 1; | |
| 162 | + } | |
| 163 | + | |
| 164 | + return result == crc; | |
| 165 | +} | |
| 166 | + | |
| 167 | +/** | |
| 168 | + * ms_sensors_read_serial() - Serial number read function | |
| 169 | + * @cli: pointer to i2c client | |
| 170 | + * @sn: pointer to 64-bits destination value | |
| 171 | + * | |
| 172 | + * Generic i2c serial number read function for Measurement Specialties devices. | |
| 173 | + * This function is used for TSYS02d, HTU21, MS8607 chipset. | |
| 174 | + * Refer to datasheet: | |
| 175 | + * http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf | |
| 176 | + * | |
| 177 | + * Sensor raw MSB serial number format is the following : | |
| 178 | + * [ SNB3, CRC, SNB2, CRC, SNB1, CRC, SNB0, CRC] | |
| 179 | + * Sensor raw LSB serial number format is the following : | |
| 180 | + * [ X, X, SNC1, SNC0, CRC, SNA1, SNA0, CRC] | |
| 181 | + * The resulting serial number is following : | |
| 182 | + * [ SNA1, SNA0, SNB3, SNB2, SNB1, SNB0, SNC1, SNC0] | |
| 183 | + * | |
| 184 | + * Return: 0 on success, negative errno otherwise. | |
| 185 | + */ | |
| 186 | +int ms_sensors_read_serial(struct i2c_client *client, u64 *sn) | |
| 187 | +{ | |
| 188 | + u8 i; | |
| 189 | + __be64 rcv_buf = 0; | |
| 190 | + u64 rcv_val; | |
| 191 | + __be16 send_buf; | |
| 192 | + int ret; | |
| 193 | + | |
| 194 | + struct i2c_msg msg[2] = { | |
| 195 | + { | |
| 196 | + .addr = client->addr, | |
| 197 | + .flags = client->flags, | |
| 198 | + .len = 2, | |
| 199 | + .buf = (__u8 *)&send_buf, | |
| 200 | + }, | |
| 201 | + { | |
| 202 | + .addr = client->addr, | |
| 203 | + .flags = client->flags | I2C_M_RD, | |
| 204 | + .buf = (__u8 *)&rcv_buf, | |
| 205 | + }, | |
| 206 | + }; | |
| 207 | + | |
| 208 | + /* Read MSB part of serial number */ | |
| 209 | + send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB); | |
| 210 | + msg[1].len = 8; | |
| 211 | + ret = i2c_transfer(client->adapter, msg, 2); | |
| 212 | + if (ret < 0) { | |
| 213 | + dev_err(&client->dev, "Unable to read device serial number"); | |
| 214 | + return ret; | |
| 215 | + } | |
| 216 | + | |
| 217 | + rcv_val = be64_to_cpu(rcv_buf); | |
| 218 | + dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val); | |
| 219 | + | |
| 220 | + for (i = 0; i < 64; i += 16) { | |
| 221 | + if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFF)) | |
| 222 | + return -ENODEV; | |
| 223 | + } | |
| 224 | + | |
| 225 | + *sn = (((rcv_val >> 32) & 0xFF000000) | | |
| 226 | + ((rcv_val >> 24) & 0x00FF0000) | | |
| 227 | + ((rcv_val >> 16) & 0x0000FF00) | | |
| 228 | + ((rcv_val >> 8) & 0x000000FF)) << 16; | |
| 229 | + | |
| 230 | + /* Read LSB part of serial number */ | |
| 231 | + send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB); | |
| 232 | + msg[1].len = 6; | |
| 233 | + rcv_buf = 0; | |
| 234 | + ret = i2c_transfer(client->adapter, msg, 2); | |
| 235 | + if (ret < 0) { | |
| 236 | + dev_err(&client->dev, "Unable to read device serial number"); | |
| 237 | + return ret; | |
| 238 | + } | |
| 239 | + | |
| 240 | + rcv_val = be64_to_cpu(rcv_buf) >> 16; | |
| 241 | + dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val); | |
| 242 | + | |
| 243 | + for (i = 0; i < 48; i += 24) { | |
| 244 | + if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFFFF)) | |
| 245 | + return -ENODEV; | |
| 246 | + } | |
| 247 | + | |
| 248 | + *sn |= (rcv_val & 0xFFFF00) << 40 | (rcv_val >> 32); | |
| 249 | + | |
| 250 | + return 0; | |
| 251 | +} | |
| 252 | +EXPORT_SYMBOL(ms_sensors_read_serial); | |
| 253 | + | |
| 254 | +static int ms_sensors_read_config_reg(struct i2c_client *client, | |
| 255 | + u8 *config_reg) | |
| 256 | +{ | |
| 257 | + int ret; | |
| 258 | + | |
| 259 | + ret = i2c_smbus_write_byte(client, MS_SENSORS_CONFIG_REG_READ); | |
| 260 | + if (ret) { | |
| 261 | + dev_err(&client->dev, "Unable to read config register"); | |
| 262 | + return ret; | |
| 263 | + } | |
| 264 | + | |
| 265 | + ret = i2c_master_recv(client, config_reg, 1); | |
| 266 | + if (ret < 0) { | |
| 267 | + dev_err(&client->dev, "Unable to read config register"); | |
| 268 | + return ret; | |
| 269 | + } | |
| 270 | + dev_dbg(&client->dev, "Config register :%x\n", *config_reg); | |
| 271 | + | |
| 272 | + return 0; | |
| 273 | +} | |
| 274 | + | |
| 275 | +/** | |
| 276 | + * ms_sensors_write_resolution() - Set resolution function | |
| 277 | + * @dev_data: pointer to temperature/humidity device data | |
| 278 | + * @i: resolution index to set | |
| 279 | + * | |
| 280 | + * This function will program the appropriate resolution based on the index | |
| 281 | + * provided when user space will set samp_freq channel. | |
| 282 | + * This function is used for TSYS02D, HTU21 and MS8607 chipsets. | |
| 283 | + * | |
| 284 | + * Return: 0 on success, negative errno otherwise. | |
| 285 | + */ | |
| 286 | +ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, | |
| 287 | + u8 i) | |
| 288 | +{ | |
| 289 | + u8 config_reg; | |
| 290 | + int ret; | |
| 291 | + | |
| 292 | + ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); | |
| 293 | + if (ret) | |
| 294 | + return ret; | |
| 295 | + | |
| 296 | + config_reg &= 0x7E; | |
| 297 | + config_reg |= ((i & 1) << 7) + ((i & 2) >> 1); | |
| 298 | + | |
| 299 | + return i2c_smbus_write_byte_data(dev_data->client, | |
| 300 | + MS_SENSORS_CONFIG_REG_WRITE, | |
| 301 | + config_reg); | |
| 302 | +} | |
| 303 | +EXPORT_SYMBOL(ms_sensors_write_resolution); | |
| 304 | + | |
| 305 | +/** | |
| 306 | + * ms_sensors_show_battery_low() - Show device battery low indicator | |
| 307 | + * @dev_data: pointer to temperature/humidity device data | |
| 308 | + * @buf: pointer to char buffer to write result | |
| 309 | + * | |
| 310 | + * This function will read battery indicator value in the device and | |
| 311 | + * return 1 if the device voltage is below 2.25V. | |
| 312 | + * This function is used for TSYS02D, HTU21 and MS8607 chipsets. | |
| 313 | + * | |
| 314 | + * Return: length of sprintf on success, negative errno otherwise. | |
| 315 | + */ | |
| 316 | +ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, | |
| 317 | + char *buf) | |
| 318 | +{ | |
| 319 | + int ret; | |
| 320 | + u8 config_reg; | |
| 321 | + | |
| 322 | + mutex_lock(&dev_data->lock); | |
| 323 | + ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); | |
| 324 | + mutex_unlock(&dev_data->lock); | |
| 325 | + if (ret) | |
| 326 | + return ret; | |
| 327 | + | |
| 328 | + return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6); | |
| 329 | +} | |
| 330 | +EXPORT_SYMBOL(ms_sensors_show_battery_low); | |
| 331 | + | |
| 332 | +/** | |
| 333 | + * ms_sensors_show_heater() - Show device heater | |
| 334 | + * @dev_data: pointer to temperature/humidity device data | |
| 335 | + * @buf: pointer to char buffer to write result | |
| 336 | + * | |
| 337 | + * This function will read heater enable value in the device and | |
| 338 | + * return 1 if the heater is enabled. | |
| 339 | + * This function is used for HTU21 and MS8607 chipsets. | |
| 340 | + * | |
| 341 | + * Return: length of sprintf on success, negative errno otherwise. | |
| 342 | + */ | |
| 343 | +ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, | |
| 344 | + char *buf) | |
| 345 | +{ | |
| 346 | + u8 config_reg; | |
| 347 | + int ret; | |
| 348 | + | |
| 349 | + mutex_lock(&dev_data->lock); | |
| 350 | + ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); | |
| 351 | + mutex_unlock(&dev_data->lock); | |
| 352 | + if (ret) | |
| 353 | + return ret; | |
| 354 | + | |
| 355 | + return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2); | |
| 356 | +} | |
| 357 | +EXPORT_SYMBOL(ms_sensors_show_heater); | |
| 358 | + | |
| 359 | +/** | |
| 360 | + * ms_sensors_write_heater() - Write device heater | |
| 361 | + * @dev_data: pointer to temperature/humidity device data | |
| 362 | + * @buf: pointer to char buffer from user space | |
| 363 | + * @len: length of buf | |
| 364 | + * | |
| 365 | + * This function will write 1 or 0 value in the device | |
| 366 | + * to enable or disable heater. | |
| 367 | + * This function is used for HTU21 and MS8607 chipsets. | |
| 368 | + * | |
| 369 | + * Return: length of buffer, negative errno otherwise. | |
| 370 | + */ | |
| 371 | +ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data, | |
| 372 | + const char *buf, size_t len) | |
| 373 | +{ | |
| 374 | + u8 val, config_reg; | |
| 375 | + int ret; | |
| 376 | + | |
| 377 | + ret = kstrtou8(buf, 10, &val); | |
| 378 | + if (ret) | |
| 379 | + return ret; | |
| 380 | + | |
| 381 | + if (val > 1) | |
| 382 | + return -EINVAL; | |
| 383 | + | |
| 384 | + mutex_lock(&dev_data->lock); | |
| 385 | + ret = ms_sensors_read_config_reg(dev_data->client, &config_reg); | |
| 386 | + if (ret) { | |
| 387 | + mutex_unlock(&dev_data->lock); | |
| 388 | + return ret; | |
| 389 | + } | |
| 390 | + | |
| 391 | + config_reg &= 0xFB; | |
| 392 | + config_reg |= val << 2; | |
| 393 | + | |
| 394 | + ret = i2c_smbus_write_byte_data(dev_data->client, | |
| 395 | + MS_SENSORS_CONFIG_REG_WRITE, | |
| 396 | + config_reg); | |
| 397 | + mutex_unlock(&dev_data->lock); | |
| 398 | + if (ret) { | |
| 399 | + dev_err(&dev_data->client->dev, "Unable to write config register\n"); | |
| 400 | + return ret; | |
| 401 | + } | |
| 402 | + | |
| 403 | + return len; | |
| 404 | +} | |
| 405 | +EXPORT_SYMBOL(ms_sensors_write_heater); | |
| 406 | + | |
| 407 | +/** | |
| 408 | + * ms_sensors_ht_read_temperature() - Read temperature | |
| 409 | + * @dev_data: pointer to temperature/humidity device data | |
| 410 | + * @temperature:pointer to temperature destination value | |
| 411 | + * | |
| 412 | + * This function will get temperature ADC value from the device, | |
| 413 | + * check the CRC and compute the temperature value. | |
| 414 | + * This function is used for TSYS02D, HTU21 and MS8607 chipsets. | |
| 415 | + * | |
| 416 | + * Return: 0 on success, negative errno otherwise. | |
| 417 | + */ | |
| 418 | +int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data, | |
| 419 | + s32 *temperature) | |
| 420 | +{ | |
| 421 | + int ret; | |
| 422 | + u32 adc; | |
| 423 | + u16 delay; | |
| 424 | + | |
| 425 | + mutex_lock(&dev_data->lock); | |
| 426 | + delay = ms_sensors_ht_t_conversion_time[dev_data->res_index]; | |
| 427 | + ret = ms_sensors_convert_and_read(dev_data->client, | |
| 428 | + MS_SENSORS_HT_T_CONVERSION_START, | |
| 429 | + MS_SENSORS_NO_READ_CMD, | |
| 430 | + delay, &adc); | |
| 431 | + mutex_unlock(&dev_data->lock); | |
| 432 | + if (ret) | |
| 433 | + return ret; | |
| 434 | + | |
| 435 | + if (!ms_sensors_crc_valid(adc)) { | |
| 436 | + dev_err(&dev_data->client->dev, | |
| 437 | + "Temperature read crc check error\n"); | |
| 438 | + return -ENODEV; | |
| 439 | + } | |
| 440 | + | |
| 441 | + /* Temperature algorithm */ | |
| 442 | + *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850; | |
| 443 | + | |
| 444 | + return 0; | |
| 445 | +} | |
| 446 | +EXPORT_SYMBOL(ms_sensors_ht_read_temperature); | |
| 447 | + | |
| 448 | +/** | |
| 449 | + * ms_sensors_ht_read_humidity() - Read humidity | |
| 450 | + * @dev_data: pointer to temperature/humidity device data | |
| 451 | + * @humidity: pointer to humidity destination value | |
| 452 | + * | |
| 453 | + * This function will get humidity ADC value from the device, | |
| 454 | + * check the CRC and compute the temperature value. | |
| 455 | + * This function is used for HTU21 and MS8607 chipsets. | |
| 456 | + * | |
| 457 | + * Return: 0 on success, negative errno otherwise. | |
| 458 | + */ | |
| 459 | +int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, | |
| 460 | + u32 *humidity) | |
| 461 | +{ | |
| 462 | + int ret; | |
| 463 | + u32 adc; | |
| 464 | + u16 delay; | |
| 465 | + | |
| 466 | + mutex_lock(&dev_data->lock); | |
| 467 | + delay = ms_sensors_ht_h_conversion_time[dev_data->res_index]; | |
| 468 | + ret = ms_sensors_convert_and_read(dev_data->client, | |
| 469 | + MS_SENSORS_HT_H_CONVERSION_START, | |
| 470 | + MS_SENSORS_NO_READ_CMD, | |
| 471 | + delay, &adc); | |
| 472 | + mutex_unlock(&dev_data->lock); | |
| 473 | + if (ret) | |
| 474 | + return ret; | |
| 475 | + | |
| 476 | + if (!ms_sensors_crc_valid(adc)) { | |
| 477 | + dev_err(&dev_data->client->dev, | |
| 478 | + "Humidity read crc check error\n"); | |
| 479 | + return -ENODEV; | |
| 480 | + } | |
| 481 | + | |
| 482 | + /* Humidity algorithm */ | |
| 483 | + *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000; | |
| 484 | + if (*humidity >= 100000) | |
| 485 | + *humidity = 100000; | |
| 486 | + | |
| 487 | + return 0; | |
| 488 | +} | |
| 489 | +EXPORT_SYMBOL(ms_sensors_ht_read_humidity); | |
| 490 | + | |
| 491 | +/** | |
| 492 | + * ms_sensors_tp_crc_valid() - CRC check function for | |
| 493 | + * Temperature and pressure devices. | |
| 494 | + * This function is only used when reading PROM coefficients | |
| 495 | + * | |
| 496 | + * @prom: pointer to PROM coefficients array | |
| 497 | + * @len: length of PROM coefficients array | |
| 498 | + * | |
| 499 | + * Return: True if CRC is ok. | |
| 500 | + */ | |
| 501 | +static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len) | |
| 502 | +{ | |
| 503 | + unsigned int cnt, n_bit; | |
| 504 | + u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12; | |
| 505 | + | |
| 506 | + prom[len - 1] = 0; | |
| 507 | + prom[0] &= 0x0FFF; /* Clear the CRC computation part */ | |
| 508 | + | |
| 509 | + for (cnt = 0; cnt < len * 2; cnt++) { | |
| 510 | + if (cnt % 2 == 1) | |
| 511 | + n_rem ^= prom[cnt >> 1] & 0x00FF; | |
| 512 | + else | |
| 513 | + n_rem ^= prom[cnt >> 1] >> 8; | |
| 514 | + | |
| 515 | + for (n_bit = 8; n_bit > 0; n_bit--) { | |
| 516 | + if (n_rem & 0x8000) | |
| 517 | + n_rem = (n_rem << 1) ^ 0x3000; | |
| 518 | + else | |
| 519 | + n_rem <<= 1; | |
| 520 | + } | |
| 521 | + } | |
| 522 | + n_rem >>= 12; | |
| 523 | + prom[0] = crc_read; | |
| 524 | + | |
| 525 | + return n_rem == crc; | |
| 526 | +} | |
| 527 | + | |
| 528 | +/** | |
| 529 | + * ms_sensors_tp_read_prom() - prom coeff read function | |
| 530 | + * @dev_data: pointer to temperature/pressure device data | |
| 531 | + * | |
| 532 | + * This function will read prom coefficients and check CRC. | |
| 533 | + * This function is used for MS5637 and MS8607 chipsets. | |
| 534 | + * | |
| 535 | + * Return: 0 on success, negative errno otherwise. | |
| 536 | + */ | |
| 537 | +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) | |
| 538 | +{ | |
| 539 | + int i, ret; | |
| 540 | + | |
| 541 | + for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) { | |
| 542 | + ret = ms_sensors_read_prom_word( | |
| 543 | + dev_data->client, | |
| 544 | + MS_SENSORS_TP_PROM_READ + (i << 1), | |
| 545 | + &dev_data->prom[i]); | |
| 546 | + | |
| 547 | + if (ret) | |
| 548 | + return ret; | |
| 549 | + } | |
| 550 | + | |
| 551 | + if (!ms_sensors_tp_crc_valid(dev_data->prom, | |
| 552 | + MS_SENSORS_TP_PROM_WORDS_NB + 1)) { | |
| 553 | + dev_err(&dev_data->client->dev, | |
| 554 | + "Calibration coefficients crc check error\n"); | |
| 555 | + return -ENODEV; | |
| 556 | + } | |
| 557 | + | |
| 558 | + return 0; | |
| 559 | +} | |
| 560 | +EXPORT_SYMBOL(ms_sensors_tp_read_prom); | |
| 561 | + | |
| 562 | +/** | |
| 563 | + * ms_sensors_read_temp_and_pressure() - read temp and pressure | |
| 564 | + * @dev_data: pointer to temperature/pressure device data | |
| 565 | + * @temperature:pointer to temperature destination value | |
| 566 | + * @pressure: pointer to pressure destination value | |
| 567 | + * | |
| 568 | + * This function will read ADC and compute pressure and temperature value. | |
| 569 | + * This function is used for MS5637 and MS8607 chipsets. | |
| 570 | + * | |
| 571 | + * Return: 0 on success, negative errno otherwise. | |
| 572 | + */ | |
| 573 | +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data, | |
| 574 | + int *temperature, | |
| 575 | + unsigned int *pressure) | |
| 576 | +{ | |
| 577 | + int ret; | |
| 578 | + u32 t_adc, p_adc; | |
| 579 | + s32 dt, temp; | |
| 580 | + s64 off, sens, t2, off2, sens2; | |
| 581 | + u16 *prom = dev_data->prom, delay; | |
| 582 | + | |
| 583 | + mutex_lock(&dev_data->lock); | |
| 584 | + delay = ms_sensors_tp_conversion_time[dev_data->res_index]; | |
| 585 | + | |
| 586 | + ret = ms_sensors_convert_and_read( | |
| 587 | + dev_data->client, | |
| 588 | + MS_SENSORS_TP_T_CONVERSION_START + | |
| 589 | + dev_data->res_index * 2, | |
| 590 | + MS_SENSORS_TP_ADC_READ, | |
| 591 | + delay, &t_adc); | |
| 592 | + if (ret) { | |
| 593 | + mutex_unlock(&dev_data->lock); | |
| 594 | + return ret; | |
| 595 | + } | |
| 596 | + | |
| 597 | + ret = ms_sensors_convert_and_read( | |
| 598 | + dev_data->client, | |
| 599 | + MS_SENSORS_TP_P_CONVERSION_START + | |
| 600 | + dev_data->res_index * 2, | |
| 601 | + MS_SENSORS_TP_ADC_READ, | |
| 602 | + delay, &p_adc); | |
| 603 | + mutex_unlock(&dev_data->lock); | |
| 604 | + if (ret) | |
| 605 | + return ret; | |
| 606 | + | |
| 607 | + dt = (s32)t_adc - (prom[5] << 8); | |
| 608 | + | |
| 609 | + /* Actual temperature = 2000 + dT * TEMPSENS */ | |
| 610 | + temp = 2000 + (((s64)dt * prom[6]) >> 23); | |
| 611 | + | |
| 612 | + /* Second order temperature compensation */ | |
| 613 | + if (temp < 2000) { | |
| 614 | + s64 tmp = (s64)temp - 2000; | |
| 615 | + | |
| 616 | + t2 = (3 * ((s64)dt * (s64)dt)) >> 33; | |
| 617 | + off2 = (61 * tmp * tmp) >> 4; | |
| 618 | + sens2 = (29 * tmp * tmp) >> 4; | |
| 619 | + | |
| 620 | + if (temp < -1500) { | |
| 621 | + s64 tmp = (s64)temp + 1500; | |
| 622 | + | |
| 623 | + off2 += 17 * tmp * tmp; | |
| 624 | + sens2 += 9 * tmp * tmp; | |
| 625 | + } | |
| 626 | + } else { | |
| 627 | + t2 = (5 * ((s64)dt * (s64)dt)) >> 38; | |
| 628 | + off2 = 0; | |
| 629 | + sens2 = 0; | |
| 630 | + } | |
| 631 | + | |
| 632 | + /* OFF = OFF_T1 + TCO * dT */ | |
| 633 | + off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6); | |
| 634 | + off -= off2; | |
| 635 | + | |
| 636 | + /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */ | |
| 637 | + sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7); | |
| 638 | + sens -= sens2; | |
| 639 | + | |
| 640 | + /* Temperature compensated pressure = D1 * SENS - OFF */ | |
| 641 | + *temperature = (temp - t2) * 10; | |
| 642 | + *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15); | |
| 643 | + | |
| 644 | + return 0; | |
| 645 | +} | |
| 646 | +EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure); | |
| 647 | + | |
| 648 | +MODULE_DESCRIPTION("Measurement-Specialties common i2c driver"); | |
| 649 | +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); | |
| 650 | +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); | |
| 651 | +MODULE_LICENSE("GPL v2"); | |
| 652 | + | |
| @@ -0,0 +1,66 @@ | ||
| 1 | +/* | |
| 2 | + * Measurements Specialties common sensor driver | |
| 3 | + * | |
| 4 | + * Copyright (c) 2015 Measurement-Specialties | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License version 2 as | |
| 8 | + * published by the Free Software Foundation. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef _MS_SENSORS_I2C_H | |
| 12 | +#define _MS_SENSORS_I2C_H | |
| 13 | + | |
| 14 | +#include <linux/i2c.h> | |
| 15 | +#include <linux/mutex.h> | |
| 16 | + | |
| 17 | +#define MS_SENSORS_TP_PROM_WORDS_NB 7 | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * struct ms_ht_dev - Humidity/Temperature sensor device structure | |
| 21 | + * @client: i2c client | |
| 22 | + * @lock: lock protecting the i2c conversion | |
| 23 | + * @res_index: index to selected sensor resolution | |
| 24 | + */ | |
| 25 | +struct ms_ht_dev { | |
| 26 | + struct i2c_client *client; | |
| 27 | + struct mutex lock; | |
| 28 | + u8 res_index; | |
| 29 | +}; | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * struct ms_tp_dev - Temperature/Pressure sensor device structure | |
| 33 | + * @client: i2c client | |
| 34 | + * @lock: lock protecting the i2c conversion | |
| 35 | + * @prom: array of PROM coefficients used for conversion. Added element | |
| 36 | + * for CRC computation | |
| 37 | + * @res_index: index to selected sensor resolution | |
| 38 | + */ | |
| 39 | +struct ms_tp_dev { | |
| 40 | + struct i2c_client *client; | |
| 41 | + struct mutex lock; | |
| 42 | + u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1]; | |
| 43 | + u8 res_index; | |
| 44 | +}; | |
| 45 | + | |
| 46 | +int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay); | |
| 47 | +int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word); | |
| 48 | +int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd, | |
| 49 | + unsigned int delay, u32 *adc); | |
| 50 | +int ms_sensors_read_serial(struct i2c_client *client, u64 *sn); | |
| 51 | +ssize_t ms_sensors_show_serial(struct ms_ht_dev *dev_data, char *buf); | |
| 52 | +ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, u8 i); | |
| 53 | +ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, char *buf); | |
| 54 | +ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, char *buf); | |
| 55 | +ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data, | |
| 56 | + const char *buf, size_t len); | |
| 57 | +int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data, | |
| 58 | + s32 *temperature); | |
| 59 | +int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, | |
| 60 | + u32 *humidity); | |
| 61 | +int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data); | |
| 62 | +int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data, | |
| 63 | + int *temperature, | |
| 64 | + unsigned int *pressure); | |
| 65 | + | |
| 66 | +#endif /* _MS_SENSORS_I2C_H */ | |
| @@ -44,6 +44,28 @@ st_sensors_write_data_with_mask_error: · 43 unmodified lines | ||
| 44 | 44 | return err; |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | +int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, | |
| 48 | + unsigned reg, unsigned writeval, | |
| 49 | + unsigned *readval) | |
| 50 | +{ | |
| 51 | + struct st_sensor_data *sdata = iio_priv(indio_dev); | |
| 52 | + u8 readdata; | |
| 53 | + int err; | |
| 54 | + | |
| 55 | + if (!readval) | |
| 56 | + return sdata->tf->write_byte(&sdata->tb, sdata->dev, | |
| 57 | + (u8)reg, (u8)writeval); | |
| 58 | + | |
| 59 | + err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata); | |
| 60 | + if (err < 0) | |
| 61 | + return err; | |
| 62 | + | |
| 63 | + *readval = (unsigned)readdata; | |
| 64 | + | |
| 65 | + return 0; | |
| 66 | +} | |
| 67 | +EXPORT_SYMBOL(st_sensors_debugfs_reg_access); | |
| 68 | + | |
| 47 | 69 | static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings, |
| 48 | 70 | unsigned int odr, struct st_sensor_odr_avl *odr_out) |
| 49 | 71 | { |
| @@ -214,7 +214,6 @@ static struct attribute *ad5504_ev_attributes[] = { · 213 unmodified lines | ||
| 214 | 214 | |
| 215 | 215 | static struct attribute_group ad5504_ev_attribute_group = { |
| 216 | 216 | .attrs = ad5504_ev_attributes, |
| 217 | − .name = "events", | |
| 218 | 217 | }; |
| 219 | 218 | |
| 220 | 219 | static irqreturn_t ad5504_event_handler(int irq, void *private) |
| @@ -281,6 +281,12 @@ static int ad7303_remove(struct spi_device *spi) · 280 unmodified lines | ||
| 281 | 281 | return 0; |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | +static const struct of_device_id ad7303_spi_of_match[] = { | |
| 285 | + { .compatible = "adi,ad7303", }, | |
| 286 | + { /* sentinel */ }, | |
| 287 | +}; | |
| 288 | +MODULE_DEVICE_TABLE(of, ad7303_spi_of_match); | |
| 289 | + | |
| 284 | 290 | static const struct spi_device_id ad7303_spi_ids[] = { |
| 285 | 291 | { "ad7303", 0 }, |
| 286 | 292 | {} |
| @@ -290,6 +296,7 @@ MODULE_DEVICE_TABLE(spi, ad7303_spi_ids); · 3 unmodified lines | ||
| 290 | 296 | static struct spi_driver ad7303_driver = { |
| 291 | 297 | .driver = { |
| 292 | 298 | .name = "ad7303", |
| 299 | + .of_match_table = of_match_ptr(ad7303_spi_of_match), | |
| 293 | 300 | .owner = THIS_MODULE, |
| 294 | 301 | }, |
| 295 | 302 | .probe = ad7303_probe, |
| @@ -31,7 +31,6 @@ · 30 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | struct m62332_data { |
| 33 | 33 | struct i2c_client *client; |
| 34 | − u16 vref_mv; | |
| 35 | 34 | struct regulator *vcc; |
| 36 | 35 | struct mutex mutex; |
| 37 | 36 | u8 raw[M62332_CHANNELS]; |
| @@ -40,8 +39,7 @@ struct m62332_data { · 2 unmodified lines | ||
| 40 | 39 | #endif |
| 41 | 40 | }; |
| 42 | 41 | |
| 43 | −static int m62332_set_value(struct iio_dev *indio_dev, | |
| 44 | − u8 val, int channel) | |
| 42 | +static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel) | |
| 45 | 43 | { |
| 46 | 44 | struct m62332_data *data = iio_priv(indio_dev); |
| 47 | 45 | struct i2c_client *client = data->client; |
| @@ -62,8 +60,8 @@ static int m62332_set_value(struct iio_dev *indio_dev, · 14 unmodified lines | ||
| 62 | 60 | goto out; |
| 63 | 61 | } |
| 64 | 62 | |
| 65 | − res = i2c_master_send(client, outbuf, 2); | |
| 66 | − if (res >= 0 && res != 2) | |
| 63 | + res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf)); | |
| 64 | + if (res >= 0 && res != ARRAY_SIZE(outbuf)) | |
| 67 | 65 | res = -EIO; |
| 68 | 66 | if (res < 0) |
| 69 | 67 | goto out; |
| @@ -87,46 +85,52 @@ static int m62332_read_raw(struct iio_dev *indio_dev, · 17 unmodified lines | ||
| 87 | 85 | struct iio_chan_spec const *chan, |
| 88 | 86 | int *val, |
| 89 | 87 | int *val2, |
| 90 | − long m) | |
| 88 | + long mask) | |
| 91 | 89 | { |
| 92 | 90 | struct m62332_data *data = iio_priv(indio_dev); |
| 91 | + int ret; | |
| 93 | 92 | |
| 94 | − switch (m) { | |
| 93 | + switch (mask) { | |
| 95 | 94 | case IIO_CHAN_INFO_SCALE: |
| 96 | 95 | /* Corresponds to Vref / 2^(bits) */ |
| 97 | − *val = data->vref_mv; | |
| 96 | + ret = regulator_get_voltage(data->vcc); | |
| 97 | + if (ret < 0) | |
| 98 | + return ret; | |
| 99 | + | |
| 100 | + *val = ret / 1000; /* mV */ | |
| 98 | 101 | *val2 = 8; |
| 102 | + | |
| 99 | 103 | return IIO_VAL_FRACTIONAL_LOG2; |
| 100 | 104 | case IIO_CHAN_INFO_RAW: |
| 101 | 105 | *val = data->raw[chan->channel]; |
| 106 | + | |
| 102 | 107 | return IIO_VAL_INT; |
| 103 | 108 | case IIO_CHAN_INFO_OFFSET: |
| 104 | 109 | *val = 1; |
| 110 | + | |
| 105 | 111 | return IIO_VAL_INT; |
| 106 | 112 | default: |
| 107 | 113 | break; |
| 108 | 114 | } |
| 115 | + | |
| 109 | 116 | return -EINVAL; |
| 110 | 117 | } |
| 111 | 118 | |
| 112 | 119 | static int m62332_write_raw(struct iio_dev *indio_dev, |
| 113 | − struct iio_chan_spec const *chan, int val, int val2, long mask) | |
| 120 | + struct iio_chan_spec const *chan, int val, int val2, | |
| 121 | + long mask) | |
| 114 | 122 | { |
| 115 | − int ret; | |
| 116 | − | |
| 117 | 123 | switch (mask) { |
| 118 | 124 | case IIO_CHAN_INFO_RAW: |
| 119 | 125 | if (val < 0 || val > 255) |
| 120 | 126 | return -EINVAL; |
| 121 | 127 | |
| 122 | − ret = m62332_set_value(indio_dev, val, chan->channel); | |
| 123 | − break; | |
| 128 | + return m62332_set_value(indio_dev, val, chan->channel); | |
| 124 | 129 | default: |
| 125 | − ret = -EINVAL; | |
| 126 | 130 | break; |
| 127 | 131 | } |
| 128 | 132 | |
| 129 | − return ret; | |
| 133 | + return -EINVAL; | |
| 130 | 134 | } |
| 131 | 135 | |
| 132 | 136 | #ifdef CONFIG_PM_SLEEP |
| @@ -173,15 +177,15 @@ static const struct iio_info m62332_info = { · 40 unmodified lines | ||
| 173 | 177 | .driver_module = THIS_MODULE, |
| 174 | 178 | }; |
| 175 | 179 | |
| 176 | −#define M62332_CHANNEL(chan) { \ | |
| 177 | − .type = IIO_VOLTAGE, \ | |
| 178 | − .indexed = 1, \ | |
| 179 | − .output = 1, \ | |
| 180 | − .channel = (chan), \ | |
| 181 | − .datasheet_name = "CH" #chan, \ | |
| 182 | − .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | |
| 183 | − BIT(IIO_CHAN_INFO_SCALE) | \ | |
| 184 | − BIT(IIO_CHAN_INFO_OFFSET), \ | |
| 180 | +#define M62332_CHANNEL(chan) { \ | |
| 181 | + .type = IIO_VOLTAGE, \ | |
| 182 | + .indexed = 1, \ | |
| 183 | + .output = 1, \ | |
| 184 | + .channel = (chan), \ | |
| 185 | + .datasheet_name = "CH" #chan, \ | |
| 186 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 187 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | |
| 188 | + BIT(IIO_CHAN_INFO_OFFSET), \ | |
| 185 | 189 | } |
| 186 | 190 | |
| 187 | 191 | static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = { |
| @@ -199,6 +203,7 @@ static int m62332_probe(struct i2c_client *client, · 11 unmodified lines | ||
| 199 | 203 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
| 200 | 204 | if (!indio_dev) |
| 201 | 205 | return -ENOMEM; |
| 206 | + | |
| 202 | 207 | data = iio_priv(indio_dev); |
| 203 | 208 | i2c_set_clientdata(client, indio_dev); |
| 204 | 209 | data->client = client; |
| @@ -212,16 +217,11 @@ static int m62332_probe(struct i2c_client *client, · 7 unmodified lines | ||
| 212 | 217 | /* establish that the iio_dev is a child of the i2c device */ |
| 213 | 218 | indio_dev->dev.parent = &client->dev; |
| 214 | 219 | |
| 215 | − indio_dev->num_channels = M62332_CHANNELS; | |
| 220 | + indio_dev->num_channels = ARRAY_SIZE(m62332_channels); | |
| 216 | 221 | indio_dev->channels = m62332_channels; |
| 217 | 222 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 218 | 223 | indio_dev->info = &m62332_info; |
| 219 | 224 | |
| 220 | − ret = regulator_get_voltage(data->vcc); | |
| 221 | − if (ret < 0) | |
| 222 | − return ret; | |
| 223 | − data->vref_mv = ret / 1000; /* mV */ | |
| 224 | − | |
| 225 | 225 | ret = iio_map_array_register(indio_dev, client->dev.platform_data); |
| 226 | 226 | if (ret < 0) |
| 227 | 227 | return ret; |
| @@ -234,6 +234,7 @@ static int m62332_probe(struct i2c_client *client, · 6 unmodified lines | ||
| 234 | 234 | |
| 235 | 235 | err: |
| 236 | 236 | iio_map_array_unregister(indio_dev); |
| 237 | + | |
| 237 | 238 | return ret; |
| 238 | 239 | } |
| 239 | 240 | |
| @@ -243,6 +244,8 @@ static int m62332_remove(struct i2c_client *client) · 3 unmodified lines | ||
| 243 | 244 | |
| 244 | 245 | iio_device_unregister(indio_dev); |
| 245 | 246 | iio_map_array_unregister(indio_dev); |
| 247 | + m62332_set_value(indio_dev, 0, 0); | |
| 248 | + m62332_set_value(indio_dev, 0, 1); | |
| 246 | 249 | |
| 247 | 250 | return 0; |
| 248 | 251 | } |
| @@ -387,6 +387,7 @@ static const struct of_device_id max5821_of_match[] = { · 386 unmodified lines | ||
| 387 | 387 | { .compatible = "maxim,max5821" }, |
| 388 | 388 | { } |
| 389 | 389 | }; |
| 390 | +MODULE_DEVICE_TABLE(of, max5821_of_match); | |
| 390 | 391 | |
| 391 | 392 | static struct i2c_driver max5821_driver = { |
| 392 | 393 | .driver = { |
| @@ -616,15 +616,24 @@ static int adf4350_remove(struct spi_device *spi) · 615 unmodified lines | ||
| 616 | 616 | return 0; |
| 617 | 617 | } |
| 618 | 618 | |
| 619 | +static const struct of_device_id adf4350_of_match[] = { | |
| 620 | + { .compatible = "adi,adf4350", }, | |
| 621 | + { .compatible = "adi,adf4351", }, | |
| 622 | + { /* sentinel */ }, | |
| 623 | +}; | |
| 624 | +MODULE_DEVICE_TABLE(of, adf4350_of_match); | |
| 625 | + | |
| 619 | 626 | static const struct spi_device_id adf4350_id[] = { |
| 620 | 627 | {"adf4350", 4350}, |
| 621 | 628 | {"adf4351", 4351}, |
| 622 | 629 | {} |
| 623 | 630 | }; |
| 631 | +MODULE_DEVICE_TABLE(spi, adf4350_id); | |
| 624 | 632 | |
| 625 | 633 | static struct spi_driver adf4350_driver = { |
| 626 | 634 | .driver = { |
| 627 | 635 | .name = "adf4350", |
| 636 | + .of_match_table = of_match_ptr(adf4350_of_match), | |
| 628 | 637 | .owner = THIS_MODULE, |
| 629 | 638 | }, |
| 630 | 639 | .probe = adf4350_probe, |
| @@ -52,15 +52,26 @@ config ADXRS450 · 51 unmodified lines | ||
| 52 | 52 | |
| 53 | 53 | config BMG160 |
| 54 | 54 | tristate "BOSCH BMG160 Gyro Sensor" |
| 55 | − depends on I2C | |
| 55 | + depends on (I2C || SPI_MASTER) | |
| 56 | 56 | select IIO_BUFFER |
| 57 | 57 | select IIO_TRIGGERED_BUFFER |
| 58 | + select BMG160_I2C if (I2C) | |
| 59 | + select BMG160_SPI if (SPI) | |
| 58 | 60 | help |
| 59 | − Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor | |
| 60 | − driver. This driver also supports BMI055 gyroscope. | |
| 61 | + Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor | |
| 62 | + driver connected via I2C or SPI. This driver also supports BMI055 | |
| 63 | + gyroscope. | |
| 61 | 64 | |
| 62 | 65 | This driver can also be built as a module. If so, the module |
| 63 | − will be called bmg160. | |
| 66 | + will be called bmg160_i2c or bmg160_spi. | |
| 67 | + | |
| 68 | +config BMG160_I2C | |
| 69 | + tristate | |
| 70 | + select REGMAP_I2C | |
| 71 | + | |
| 72 | +config BMG160_SPI | |
| 73 | + tristate | |
| 74 | + select REGMAP_SPI | |
| 64 | 75 | |
| 65 | 76 | config HID_SENSOR_GYRO_3D |
| 66 | 77 | depends on HID_SENSOR_HUB |
| @@ -8,7 +8,9 @@ obj-$(CONFIG_ADIS16130) += adis16130.o · 7 unmodified lines | ||
| 8 | 8 | obj-$(CONFIG_ADIS16136) += adis16136.o |
| 9 | 9 | obj-$(CONFIG_ADIS16260) += adis16260.o |
| 10 | 10 | obj-$(CONFIG_ADXRS450) += adxrs450.o |
| 11 | −obj-$(CONFIG_BMG160) += bmg160.o | |
| 11 | +obj-$(CONFIG_BMG160) += bmg160_core.o | |
| 12 | +obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o | |
| 13 | +obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o | |
| 12 | 14 | |
| 13 | 15 | obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o |
| 14 | 16 | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +#ifndef BMG160_H_ | |
| 2 | +#define BMG160_H_ | |
| 3 | + | |
| 4 | +extern const struct dev_pm_ops bmg160_pm_ops; | |
| 5 | + | |
| 6 | +int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, | |
| 7 | + const char *name); | |
| 8 | +void bmg160_core_remove(struct device *dev); | |
| 9 | + | |
| 10 | +#endif /* BMG160_H_ */ | |
| @@ -13,7 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | */ |
| 14 | 14 | |
| 15 | 15 | #include <linux/module.h> |
| 16 | −#include <linux/i2c.h> | |
| 17 | 16 | #include <linux/interrupt.h> |
| 18 | 17 | #include <linux/delay.h> |
| 19 | 18 | #include <linux/slab.h> |
| @@ -28,8 +27,9 @@ · 8 unmodified lines | ||
| 28 | 27 | #include <linux/iio/events.h> |
| 29 | 28 | #include <linux/iio/trigger_consumer.h> |
| 30 | 29 | #include <linux/iio/triggered_buffer.h> |
| 30 | +#include <linux/regmap.h> | |
| 31 | +#include "bmg160.h" | |
| 31 | 32 | |
| 32 | −#define BMG160_DRV_NAME "bmg160" | |
| 33 | 33 | #define BMG160_IRQ_NAME "bmg160_event" |
| 34 | 34 | #define BMG160_GPIO_NAME "gpio_int" |
| 35 | 35 | |
| @@ -97,7 +97,8 @@ · 61 unmodified lines | ||
| 97 | 97 | #define BMG160_AUTO_SUSPEND_DELAY_MS 2000 |
| 98 | 98 | |
| 99 | 99 | struct bmg160_data { |
| 100 | − struct i2c_client *client; | |
| 100 | + struct device *dev; | |
| 101 | + struct regmap *regmap; | |
| 101 | 102 | struct iio_trigger *dready_trig; |
| 102 | 103 | struct iio_trigger *motion_trig; |
| 103 | 104 | struct mutex mutex; |
| @@ -108,6 +109,7 @@ struct bmg160_data { · 4 unmodified lines | ||
| 108 | 109 | int slope_thres; |
| 109 | 110 | bool dready_trigger_on; |
| 110 | 111 | bool motion_trigger_on; |
| 112 | + int irq; | |
| 111 | 113 | }; |
| 112 | 114 | |
| 113 | 115 | enum bmg160_axis { |
| @@ -138,10 +140,9 @@ static int bmg160_set_mode(struct bmg160_data *data, u8 mode) · 24 unmodified lines | ||
| 138 | 140 | { |
| 139 | 141 | int ret; |
| 140 | 142 | |
| 141 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 142 | − BMG160_REG_PMU_LPW, mode); | |
| 143 | + ret = regmap_write(data->regmap, BMG160_REG_PMU_LPW, mode); | |
| 143 | 144 | if (ret < 0) { |
| 144 | − dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); | |
| 145 | + dev_err(data->dev, "Error writing reg_pmu_lpw\n"); | |
| 145 | 146 | return ret; |
| 146 | 147 | } |
| 147 | 148 | |
| @@ -169,10 +170,9 @@ static int bmg160_set_bw(struct bmg160_data *data, int val) · 21 unmodified lines | ||
| 169 | 170 | if (bw_bits < 0) |
| 170 | 171 | return bw_bits; |
| 171 | 172 | |
| 172 | − ret = i2c_smbus_write_byte_data(data->client, BMG160_REG_PMU_BW, | |
| 173 | − bw_bits); | |
| 173 | + ret = regmap_write(data->regmap, BMG160_REG_PMU_BW, bw_bits); | |
| 174 | 174 | if (ret < 0) { |
| 175 | − dev_err(&data->client->dev, "Error writing reg_pmu_bw\n"); | |
| 175 | + dev_err(data->dev, "Error writing reg_pmu_bw\n"); | |
| 176 | 176 | return ret; |
| 177 | 177 | } |
| 178 | 178 | |
| @@ -184,16 +184,17 @@ static int bmg160_set_bw(struct bmg160_data *data, int val) · 5 unmodified lines | ||
| 184 | 184 | static int bmg160_chip_init(struct bmg160_data *data) |
| 185 | 185 | { |
| 186 | 186 | int ret; |
| 187 | + unsigned int val; | |
| 187 | 188 | |
| 188 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_CHIP_ID); | |
| 189 | + ret = regmap_read(data->regmap, BMG160_REG_CHIP_ID, &val); | |
| 189 | 190 | if (ret < 0) { |
| 190 | − dev_err(&data->client->dev, "Error reading reg_chip_id\n"); | |
| 191 | + dev_err(data->dev, "Error reading reg_chip_id\n"); | |
| 191 | 192 | return ret; |
| 192 | 193 | } |
| 193 | 194 | |
| 194 | − dev_dbg(&data->client->dev, "Chip Id %x\n", ret); | |
| 195 | − if (ret != BMG160_CHIP_ID_VAL) { | |
| 196 | − dev_err(&data->client->dev, "invalid chip %x\n", ret); | |
| 195 | + dev_dbg(data->dev, "Chip Id %x\n", val); | |
| 196 | + if (val != BMG160_CHIP_ID_VAL) { | |
| 197 | + dev_err(data->dev, "invalid chip %x\n", val); | |
| 197 | 198 | return -ENODEV; |
| 198 | 199 | } |
| 199 | 200 | |
| @@ -210,42 +211,33 @@ static int bmg160_chip_init(struct bmg160_data *data) · 10 unmodified lines | ||
| 210 | 211 | return ret; |
| 211 | 212 | |
| 212 | 213 | /* Set Default Range */ |
| 213 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 214 | − BMG160_REG_RANGE, | |
| 215 | − BMG160_RANGE_500DPS); | |
| 214 | + ret = regmap_write(data->regmap, BMG160_REG_RANGE, BMG160_RANGE_500DPS); | |
| 216 | 215 | if (ret < 0) { |
| 217 | − dev_err(&data->client->dev, "Error writing reg_range\n"); | |
| 216 | + dev_err(data->dev, "Error writing reg_range\n"); | |
| 218 | 217 | return ret; |
| 219 | 218 | } |
| 220 | 219 | data->dps_range = BMG160_RANGE_500DPS; |
| 221 | 220 | |
| 222 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_SLOPE_THRES); | |
| 221 | + ret = regmap_read(data->regmap, BMG160_REG_SLOPE_THRES, &val); | |
| 223 | 222 | if (ret < 0) { |
| 224 | − dev_err(&data->client->dev, "Error reading reg_slope_thres\n"); | |
| 223 | + dev_err(data->dev, "Error reading reg_slope_thres\n"); | |
| 225 | 224 | return ret; |
| 226 | 225 | } |
| 227 | − data->slope_thres = ret; | |
| 226 | + data->slope_thres = val; | |
| 228 | 227 | |
| 229 | 228 | /* Set default interrupt mode */ |
| 230 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1); | |
| 229 | + ret = regmap_update_bits(data->regmap, BMG160_REG_INT_EN_1, | |
| 230 | + BMG160_INT1_BIT_OD, 0); | |
| 231 | 231 | if (ret < 0) { |
| 232 | − dev_err(&data->client->dev, "Error reading reg_int_en_1\n"); | |
| 233 | − return ret; | |
| 234 | − } | |
| 235 | − ret &= ~BMG160_INT1_BIT_OD; | |
| 236 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 237 | − BMG160_REG_INT_EN_1, ret); | |
| 238 | − if (ret < 0) { | |
| 239 | − dev_err(&data->client->dev, "Error writing reg_int_en_1\n"); | |
| 232 | + dev_err(data->dev, "Error updating bits in reg_int_en_1\n"); | |
| 240 | 233 | return ret; |
| 241 | 234 | } |
| 242 | 235 | |
| 243 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 244 | − BMG160_REG_INT_RST_LATCH, | |
| 245 | − BMG160_INT_MODE_LATCH_INT | | |
| 246 | − BMG160_INT_MODE_LATCH_RESET); | |
| 236 | + ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH, | |
| 237 | + BMG160_INT_MODE_LATCH_INT | | |
| 238 | + BMG160_INT_MODE_LATCH_RESET); | |
| 247 | 239 | if (ret < 0) { |
| 248 | − dev_err(&data->client->dev, | |
| 240 | + dev_err(data->dev, | |
| 249 | 241 | "Error writing reg_motion_intr\n"); |
| 250 | 242 | return ret; |
| 251 | 243 | } |
| @@ -259,17 +251,17 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on) · 7 unmodified lines | ||
| 259 | 251 | int ret; |
| 260 | 252 | |
| 261 | 253 | if (on) |
| 262 | − ret = pm_runtime_get_sync(&data->client->dev); | |
| 254 | + ret = pm_runtime_get_sync(data->dev); | |
| 263 | 255 | else { |
| 264 | − pm_runtime_mark_last_busy(&data->client->dev); | |
| 265 | − ret = pm_runtime_put_autosuspend(&data->client->dev); | |
| 256 | + pm_runtime_mark_last_busy(data->dev); | |
| 257 | + ret = pm_runtime_put_autosuspend(data->dev); | |
| 266 | 258 | } |
| 267 | 259 | |
| 268 | 260 | if (ret < 0) { |
| 269 | − dev_err(&data->client->dev, | |
| 261 | + dev_err(data->dev, | |
| 270 | 262 | "Failed: bmg160_set_power_state for %d\n", on); |
| 271 | 263 | if (on) |
| 272 | − pm_runtime_put_noidle(&data->client->dev); | |
| 264 | + pm_runtime_put_noidle(data->dev); | |
| 273 | 265 | |
| 274 | 266 | return ret; |
| 275 | 267 | } |
| @@ -284,43 +276,30 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data, · 8 unmodified lines | ||
| 284 | 276 | int ret; |
| 285 | 277 | |
| 286 | 278 | /* Enable/Disable INT_MAP0 mapping */ |
| 287 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_0); | |
| 288 | − if (ret < 0) { | |
| 289 | − dev_err(&data->client->dev, "Error reading reg_int_map0\n"); | |
| 290 | − return ret; | |
| 291 | − } | |
| 292 | − if (status) | |
| 293 | − ret |= BMG160_INT_MAP_0_BIT_ANY; | |
| 294 | − else | |
| 295 | − ret &= ~BMG160_INT_MAP_0_BIT_ANY; | |
| 296 | − | |
| 297 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 298 | − BMG160_REG_INT_MAP_0, | |
| 299 | − ret); | |
| 279 | + ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_0, | |
| 280 | + BMG160_INT_MAP_0_BIT_ANY, | |
| 281 | + (status ? BMG160_INT_MAP_0_BIT_ANY : 0)); | |
| 300 | 282 | if (ret < 0) { |
| 301 | − dev_err(&data->client->dev, "Error writing reg_int_map0\n"); | |
| 283 | + dev_err(data->dev, "Error updating bits reg_int_map0\n"); | |
| 302 | 284 | return ret; |
| 303 | 285 | } |
| 304 | 286 | |
| 305 | 287 | /* Enable/Disable slope interrupts */ |
| 306 | 288 | if (status) { |
| 307 | 289 | /* Update slope thres */ |
| 308 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 309 | − BMG160_REG_SLOPE_THRES, | |
| 310 | − data->slope_thres); | |
| 290 | + ret = regmap_write(data->regmap, BMG160_REG_SLOPE_THRES, | |
| 291 | + data->slope_thres); | |
| 311 | 292 | if (ret < 0) { |
| 312 | − dev_err(&data->client->dev, | |
| 293 | + dev_err(data->dev, | |
| 313 | 294 | "Error writing reg_slope_thres\n"); |
| 314 | 295 | return ret; |
| 315 | 296 | } |
| 316 | 297 | |
| 317 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 318 | − BMG160_REG_MOTION_INTR, | |
| 319 | − BMG160_INT_MOTION_X | | |
| 320 | − BMG160_INT_MOTION_Y | | |
| 321 | − BMG160_INT_MOTION_Z); | |
| 298 | + ret = regmap_write(data->regmap, BMG160_REG_MOTION_INTR, | |
| 299 | + BMG160_INT_MOTION_X | BMG160_INT_MOTION_Y | | |
| 300 | + BMG160_INT_MOTION_Z); | |
| 322 | 301 | if (ret < 0) { |
| 323 | − dev_err(&data->client->dev, | |
| 302 | + dev_err(data->dev, | |
| 324 | 303 | "Error writing reg_motion_intr\n"); |
| 325 | 304 | return ret; |
| 326 | 305 | } |
| @@ -331,28 +310,26 @@ static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data, · 4 unmodified lines | ||
| 331 | 310 | * to set latched mode, we will be flooded anyway with INTR |
| 332 | 311 | */ |
| 333 | 312 | if (!data->dready_trigger_on) { |
| 334 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 335 | − BMG160_REG_INT_RST_LATCH, | |
| 336 | − BMG160_INT_MODE_LATCH_INT | | |
| 337 | − BMG160_INT_MODE_LATCH_RESET); | |
| 313 | + ret = regmap_write(data->regmap, | |
| 314 | + BMG160_REG_INT_RST_LATCH, | |
| 315 | + BMG160_INT_MODE_LATCH_INT | | |
| 316 | + BMG160_INT_MODE_LATCH_RESET); | |
| 338 | 317 | if (ret < 0) { |
| 339 | − dev_err(&data->client->dev, | |
| 318 | + dev_err(data->dev, | |
| 340 | 319 | "Error writing reg_rst_latch\n"); |
| 341 | 320 | return ret; |
| 342 | 321 | } |
| 343 | 322 | } |
| 344 | 323 | |
| 345 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 346 | − BMG160_REG_INT_EN_0, | |
| 347 | − BMG160_DATA_ENABLE_INT); | |
| 324 | + ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, | |
| 325 | + BMG160_DATA_ENABLE_INT); | |
| 348 | 326 | |
| 349 | − } else | |
| 350 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 351 | − BMG160_REG_INT_EN_0, | |
| 352 | − 0); | |
| 327 | + } else { | |
| 328 | + ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0); | |
| 329 | + } | |
| 353 | 330 | |
| 354 | 331 | if (ret < 0) { |
| 355 | − dev_err(&data->client->dev, "Error writing reg_int_en0\n"); | |
| 332 | + dev_err(data->dev, "Error writing reg_int_en0\n"); | |
| 356 | 333 | return ret; |
| 357 | 334 | } |
| 358 | 335 | |
| @@ -365,59 +342,43 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data, · 6 unmodified lines | ||
| 365 | 342 | int ret; |
| 366 | 343 | |
| 367 | 344 | /* Enable/Disable INT_MAP1 mapping */ |
| 368 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_1); | |
| 369 | − if (ret < 0) { | |
| 370 | − dev_err(&data->client->dev, "Error reading reg_int_map1\n"); | |
| 371 | − return ret; | |
| 372 | − } | |
| 373 | − | |
| 374 | − if (status) | |
| 375 | − ret |= BMG160_INT_MAP_1_BIT_NEW_DATA; | |
| 376 | − else | |
| 377 | − ret &= ~BMG160_INT_MAP_1_BIT_NEW_DATA; | |
| 378 | − | |
| 379 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 380 | − BMG160_REG_INT_MAP_1, | |
| 381 | − ret); | |
| 345 | + ret = regmap_update_bits(data->regmap, BMG160_REG_INT_MAP_1, | |
| 346 | + BMG160_INT_MAP_1_BIT_NEW_DATA, | |
| 347 | + (status ? BMG160_INT_MAP_1_BIT_NEW_DATA : 0)); | |
| 382 | 348 | if (ret < 0) { |
| 383 | − dev_err(&data->client->dev, "Error writing reg_int_map1\n"); | |
| 349 | + dev_err(data->dev, "Error updating bits in reg_int_map1\n"); | |
| 384 | 350 | return ret; |
| 385 | 351 | } |
| 386 | 352 | |
| 387 | 353 | if (status) { |
| 388 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 389 | − BMG160_REG_INT_RST_LATCH, | |
| 390 | − BMG160_INT_MODE_NON_LATCH_INT | | |
| 391 | − BMG160_INT_MODE_LATCH_RESET); | |
| 354 | + ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH, | |
| 355 | + BMG160_INT_MODE_NON_LATCH_INT | | |
| 356 | + BMG160_INT_MODE_LATCH_RESET); | |
| 392 | 357 | if (ret < 0) { |
| 393 | − dev_err(&data->client->dev, | |
| 358 | + dev_err(data->dev, | |
| 394 | 359 | "Error writing reg_rst_latch\n"); |
| 395 | 360 | return ret; |
| 396 | 361 | } |
| 397 | 362 | |
| 398 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 399 | − BMG160_REG_INT_EN_0, | |
| 400 | − BMG160_DATA_ENABLE_INT); | |
| 363 | + ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, | |
| 364 | + BMG160_DATA_ENABLE_INT); | |
| 401 | 365 | |
| 402 | 366 | } else { |
| 403 | 367 | /* Restore interrupt mode */ |
| 404 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 405 | − BMG160_REG_INT_RST_LATCH, | |
| 406 | − BMG160_INT_MODE_LATCH_INT | | |
| 407 | − BMG160_INT_MODE_LATCH_RESET); | |
| 368 | + ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH, | |
| 369 | + BMG160_INT_MODE_LATCH_INT | | |
| 370 | + BMG160_INT_MODE_LATCH_RESET); | |
| 408 | 371 | if (ret < 0) { |
| 409 | − dev_err(&data->client->dev, | |
| 372 | + dev_err(data->dev, | |
| 410 | 373 | "Error writing reg_rst_latch\n"); |
| 411 | 374 | return ret; |
| 412 | 375 | } |
| 413 | 376 | |
| 414 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 415 | − BMG160_REG_INT_EN_0, | |
| 416 | − 0); | |
| 377 | + ret = regmap_write(data->regmap, BMG160_REG_INT_EN_0, 0); | |
| 417 | 378 | } |
| 418 | 379 | |
| 419 | 380 | if (ret < 0) { |
| 420 | − dev_err(&data->client->dev, "Error writing reg_int_en0\n"); | |
| 381 | + dev_err(data->dev, "Error writing reg_int_en0\n"); | |
| 421 | 382 | return ret; |
| 422 | 383 | } |
| 423 | 384 | |
| @@ -444,12 +405,10 @@ static int bmg160_set_scale(struct bmg160_data *data, int val) · 20 unmodified lines | ||
| 444 | 405 | |
| 445 | 406 | for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) { |
| 446 | 407 | if (bmg160_scale_table[i].scale == val) { |
| 447 | − ret = i2c_smbus_write_byte_data( | |
| 448 | − data->client, | |
| 449 | − BMG160_REG_RANGE, | |
| 450 | − bmg160_scale_table[i].dps_range); | |
| 408 | + ret = regmap_write(data->regmap, BMG160_REG_RANGE, | |
| 409 | + bmg160_scale_table[i].dps_range); | |
| 451 | 410 | if (ret < 0) { |
| 452 | − dev_err(&data->client->dev, | |
| 411 | + dev_err(data->dev, | |
| 453 | 412 | "Error writing reg_range\n"); |
| 454 | 413 | return ret; |
| 455 | 414 | } |
| @@ -464,6 +423,7 @@ static int bmg160_set_scale(struct bmg160_data *data, int val) · 8 unmodified lines | ||
| 464 | 423 | static int bmg160_get_temp(struct bmg160_data *data, int *val) |
| 465 | 424 | { |
| 466 | 425 | int ret; |
| 426 | + unsigned int raw_val; | |
| 467 | 427 | |
| 468 | 428 | mutex_lock(&data->mutex); |
| 469 | 429 | ret = bmg160_set_power_state(data, true); |
| @@ -472,15 +432,15 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val) · 2 unmodified lines | ||
| 472 | 432 | return ret; |
| 473 | 433 | } |
| 474 | 434 | |
| 475 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_TEMP); | |
| 435 | + ret = regmap_read(data->regmap, BMG160_REG_TEMP, &raw_val); | |
| 476 | 436 | if (ret < 0) { |
| 477 | − dev_err(&data->client->dev, "Error reading reg_temp\n"); | |
| 437 | + dev_err(data->dev, "Error reading reg_temp\n"); | |
| 478 | 438 | bmg160_set_power_state(data, false); |
| 479 | 439 | mutex_unlock(&data->mutex); |
| 480 | 440 | return ret; |
| 481 | 441 | } |
| 482 | 442 | |
| 483 | − *val = sign_extend32(ret, 7); | |
| 443 | + *val = sign_extend32(raw_val, 7); | |
| 484 | 444 | ret = bmg160_set_power_state(data, false); |
| 485 | 445 | mutex_unlock(&data->mutex); |
| 486 | 446 | if (ret < 0) |
| @@ -492,6 +452,7 @@ static int bmg160_get_temp(struct bmg160_data *data, int *val) · 5 unmodified lines | ||
| 492 | 452 | static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val) |
| 493 | 453 | { |
| 494 | 454 | int ret; |
| 455 | + unsigned int raw_val; | |
| 495 | 456 | |
| 496 | 457 | mutex_lock(&data->mutex); |
| 497 | 458 | ret = bmg160_set_power_state(data, true); |
| @@ -500,15 +461,16 @@ static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val) · 2 unmodified lines | ||
| 500 | 461 | return ret; |
| 501 | 462 | } |
| 502 | 463 | |
| 503 | − ret = i2c_smbus_read_word_data(data->client, BMG160_AXIS_TO_REG(axis)); | |
| 464 | + ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(axis), &raw_val, | |
| 465 | + 2); | |
| 504 | 466 | if (ret < 0) { |
| 505 | − dev_err(&data->client->dev, "Error reading axis %d\n", axis); | |
| 467 | + dev_err(data->dev, "Error reading axis %d\n", axis); | |
| 506 | 468 | bmg160_set_power_state(data, false); |
| 507 | 469 | mutex_unlock(&data->mutex); |
| 508 | 470 | return ret; |
| 509 | 471 | } |
| 510 | 472 | |
| 511 | − *val = sign_extend32(ret, 15); | |
| 473 | + *val = sign_extend32(raw_val, 15); | |
| 512 | 474 | ret = bmg160_set_power_state(data, false); |
| 513 | 475 | mutex_unlock(&data->mutex); |
| 514 | 476 | if (ret < 0) |
| @@ -807,12 +769,13 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p) · 292 unmodified lines | ||
| 807 | 769 | struct iio_dev *indio_dev = pf->indio_dev; |
| 808 | 770 | struct bmg160_data *data = iio_priv(indio_dev); |
| 809 | 771 | int bit, ret, i = 0; |
| 772 | + unsigned int val; | |
| 810 | 773 | |
| 811 | 774 | mutex_lock(&data->mutex); |
| 812 | 775 | for_each_set_bit(bit, indio_dev->active_scan_mask, |
| 813 | 776 | indio_dev->masklength) { |
| 814 | − ret = i2c_smbus_read_word_data(data->client, | |
| 815 | − BMG160_AXIS_TO_REG(bit)); | |
| 777 | + ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit), | |
| 778 | + &val, 2); | |
| 816 | 779 | if (ret < 0) { |
| 817 | 780 | mutex_unlock(&data->mutex); |
| 818 | 781 | goto err; |
| @@ -840,12 +803,11 @@ static int bmg160_trig_try_reen(struct iio_trigger *trig) · 21 unmodified lines | ||
| 840 | 803 | return 0; |
| 841 | 804 | |
| 842 | 805 | /* Set latched mode interrupt and clear any latched interrupt */ |
| 843 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 844 | − BMG160_REG_INT_RST_LATCH, | |
| 845 | − BMG160_INT_MODE_LATCH_INT | | |
| 846 | − BMG160_INT_MODE_LATCH_RESET); | |
| 806 | + ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH, | |
| 807 | + BMG160_INT_MODE_LATCH_INT | | |
| 808 | + BMG160_INT_MODE_LATCH_RESET); | |
| 847 | 809 | if (ret < 0) { |
| 848 | − dev_err(&data->client->dev, "Error writing reg_rst_latch\n"); | |
| 810 | + dev_err(data->dev, "Error writing reg_rst_latch\n"); | |
| 849 | 811 | return ret; |
| 850 | 812 | } |
| 851 | 813 | |
| @@ -907,33 +869,34 @@ static irqreturn_t bmg160_event_handler(int irq, void *private) · 55 unmodified lines | ||
| 907 | 869 | struct bmg160_data *data = iio_priv(indio_dev); |
| 908 | 870 | int ret; |
| 909 | 871 | int dir; |
| 872 | + unsigned int val; | |
| 910 | 873 | |
| 911 | − ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_STATUS_2); | |
| 874 | + ret = regmap_read(data->regmap, BMG160_REG_INT_STATUS_2, &val); | |
| 912 | 875 | if (ret < 0) { |
| 913 | − dev_err(&data->client->dev, "Error reading reg_int_status2\n"); | |
| 876 | + dev_err(data->dev, "Error reading reg_int_status2\n"); | |
| 914 | 877 | goto ack_intr_status; |
| 915 | 878 | } |
| 916 | 879 | |
| 917 | − if (ret & 0x08) | |
| 880 | + if (val & 0x08) | |
| 918 | 881 | dir = IIO_EV_DIR_RISING; |
| 919 | 882 | else |
| 920 | 883 | dir = IIO_EV_DIR_FALLING; |
| 921 | 884 | |
| 922 | − if (ret & BMG160_ANY_MOTION_BIT_X) | |
| 885 | + if (val & BMG160_ANY_MOTION_BIT_X) | |
| 923 | 886 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, |
| 924 | 887 | 0, |
| 925 | 888 | IIO_MOD_X, |
| 926 | 889 | IIO_EV_TYPE_ROC, |
| 927 | 890 | dir), |
| 928 | 891 | iio_get_time_ns()); |
| 929 | − if (ret & BMG160_ANY_MOTION_BIT_Y) | |
| 892 | + if (val & BMG160_ANY_MOTION_BIT_Y) | |
| 930 | 893 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, |
| 931 | 894 | 0, |
| 932 | 895 | IIO_MOD_Y, |
| 933 | 896 | IIO_EV_TYPE_ROC, |
| 934 | 897 | dir), |
| 935 | 898 | iio_get_time_ns()); |
| 936 | − if (ret & BMG160_ANY_MOTION_BIT_Z) | |
| 899 | + if (val & BMG160_ANY_MOTION_BIT_Z) | |
| 937 | 900 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, |
| 938 | 901 | 0, |
| 939 | 902 | IIO_MOD_Z, |
| @@ -943,12 +906,11 @@ static irqreturn_t bmg160_event_handler(int irq, void *private) · 3 unmodified lines | ||
| 943 | 906 | |
| 944 | 907 | ack_intr_status: |
| 945 | 908 | if (!data->dready_trigger_on) { |
| 946 | − ret = i2c_smbus_write_byte_data(data->client, | |
| 947 | − BMG160_REG_INT_RST_LATCH, | |
| 948 | − BMG160_INT_MODE_LATCH_INT | | |
| 949 | − BMG160_INT_MODE_LATCH_RESET); | |
| 909 | + ret = regmap_write(data->regmap, BMG160_REG_INT_RST_LATCH, | |
| 910 | + BMG160_INT_MODE_LATCH_INT | | |
| 911 | + BMG160_INT_MODE_LATCH_RESET); | |
| 950 | 912 | if (ret < 0) |
| 951 | − dev_err(&data->client->dev, | |
| 913 | + dev_err(data->dev, | |
| 952 | 914 | "Error writing reg_rst_latch\n"); |
| 953 | 915 | } |
| 954 | 916 | |
| @@ -993,18 +955,13 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = { · 38 unmodified lines | ||
| 993 | 955 | .postdisable = bmg160_buffer_postdisable, |
| 994 | 956 | }; |
| 995 | 957 | |
| 996 | −static int bmg160_gpio_probe(struct i2c_client *client, | |
| 997 | − struct bmg160_data *data) | |
| 958 | +static int bmg160_gpio_probe(struct bmg160_data *data) | |
| 998 | 959 | |
| 999 | 960 | { |
| 1000 | 961 | struct device *dev; |
| 1001 | 962 | struct gpio_desc *gpio; |
| 1002 | − int ret; | |
| 1003 | − | |
| 1004 | − if (!client) | |
| 1005 | − return -EINVAL; | |
| 1006 | 963 | |
| 1007 | − dev = &client->dev; | |
| 964 | + dev = data->dev; | |
| 1008 | 965 | |
| 1009 | 966 | /* data ready gpio interrupt pin */ |
| 1010 | 967 | gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN); |
| @@ -1013,11 +970,12 @@ static int bmg160_gpio_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 1013 | 970 | return PTR_ERR(gpio); |
| 1014 | 971 | } |
| 1015 | 972 | |
| 1016 | − ret = gpiod_to_irq(gpio); | |
| 973 | + data->irq = gpiod_to_irq(gpio); | |
| 1017 | 974 | |
| 1018 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 975 | + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), | |
| 976 | + data->irq); | |
| 1019 | 977 | |
| 1020 | − return ret; | |
| 978 | + return 0; | |
| 1021 | 979 | } |
| 1022 | 980 | |
| 1023 | 981 | static const char *bmg160_match_acpi_device(struct device *dev) |
| @@ -1031,21 +989,22 @@ static const char *bmg160_match_acpi_device(struct device *dev) · 7 unmodified lines | ||
| 1031 | 989 | return dev_name(dev); |
| 1032 | 990 | } |
| 1033 | 991 | |
| 1034 | −static int bmg160_probe(struct i2c_client *client, | |
| 1035 | − const struct i2c_device_id *id) | |
| 992 | +int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, | |
| 993 | + const char *name) | |
| 1036 | 994 | { |
| 1037 | 995 | struct bmg160_data *data; |
| 1038 | 996 | struct iio_dev *indio_dev; |
| 1039 | 997 | int ret; |
| 1040 | − const char *name = NULL; | |
| 1041 | 998 | |
| 1042 | − indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 999 | + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | |
| 1043 | 1000 | if (!indio_dev) |
| 1044 | 1001 | return -ENOMEM; |
| 1045 | 1002 | |
| 1046 | 1003 | data = iio_priv(indio_dev); |
| 1047 | − i2c_set_clientdata(client, indio_dev); | |
| 1048 | − data->client = client; | |
| 1004 | + dev_set_drvdata(dev, indio_dev); | |
| 1005 | + data->dev = dev; | |
| 1006 | + data->irq = irq; | |
| 1007 | + data->regmap = regmap; | |
| 1049 | 1008 | |
| 1050 | 1009 | ret = bmg160_chip_init(data); |
| 1051 | 1010 | if (ret < 0) |
| @@ -1053,25 +1012,22 @@ static int bmg160_probe(struct i2c_client *client, · 1 unmodified line | ||
| 1053 | 1012 | |
| 1054 | 1013 | mutex_init(&data->mutex); |
| 1055 | 1014 | |
| 1056 | − if (id) | |
| 1057 | − name = id->name; | |
| 1015 | + if (ACPI_HANDLE(dev)) | |
| 1016 | + name = bmg160_match_acpi_device(dev); | |
| 1058 | 1017 | |
| 1059 | − if (ACPI_HANDLE(&client->dev)) | |
| 1060 | − name = bmg160_match_acpi_device(&client->dev); | |
| 1061 | − | |
| 1062 | − indio_dev->dev.parent = &client->dev; | |
| 1018 | + indio_dev->dev.parent = dev; | |
| 1063 | 1019 | indio_dev->channels = bmg160_channels; |
| 1064 | 1020 | indio_dev->num_channels = ARRAY_SIZE(bmg160_channels); |
| 1065 | 1021 | indio_dev->name = name; |
| 1066 | 1022 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 1067 | 1023 | indio_dev->info = &bmg160_info; |
| 1068 | 1024 | |
| 1069 | − if (client->irq <= 0) | |
| 1070 | − client->irq = bmg160_gpio_probe(client, data); | |
| 1025 | + if (data->irq <= 0) | |
| 1026 | + bmg160_gpio_probe(data); | |
| 1071 | 1027 | |
| 1072 | − if (client->irq > 0) { | |
| 1073 | − ret = devm_request_threaded_irq(&client->dev, | |
| 1074 | − client->irq, | |
| 1028 | + if (data->irq > 0) { | |
| 1029 | + ret = devm_request_threaded_irq(dev, | |
| 1030 | + data->irq, | |
| 1075 | 1031 | bmg160_data_rdy_trig_poll, |
| 1076 | 1032 | bmg160_event_handler, |
| 1077 | 1033 | IRQF_TRIGGER_RISING, |
| @@ -1080,28 +1036,28 @@ static int bmg160_probe(struct i2c_client *client, · 2 unmodified lines | ||
| 1080 | 1036 | if (ret) |
| 1081 | 1037 | return ret; |
| 1082 | 1038 | |
| 1083 | − data->dready_trig = devm_iio_trigger_alloc(&client->dev, | |
| 1039 | + data->dready_trig = devm_iio_trigger_alloc(dev, | |
| 1084 | 1040 | "%s-dev%d", |
| 1085 | 1041 | indio_dev->name, |
| 1086 | 1042 | indio_dev->id); |
| 1087 | 1043 | if (!data->dready_trig) |
| 1088 | 1044 | return -ENOMEM; |
| 1089 | 1045 | |
| 1090 | − data->motion_trig = devm_iio_trigger_alloc(&client->dev, | |
| 1046 | + data->motion_trig = devm_iio_trigger_alloc(dev, | |
| 1091 | 1047 | "%s-any-motion-dev%d", |
| 1092 | 1048 | indio_dev->name, |
| 1093 | 1049 | indio_dev->id); |
| 1094 | 1050 | if (!data->motion_trig) |
| 1095 | 1051 | return -ENOMEM; |
| 1096 | 1052 | |
| 1097 | − data->dready_trig->dev.parent = &client->dev; | |
| 1053 | + data->dready_trig->dev.parent = dev; | |
| 1098 | 1054 | data->dready_trig->ops = &bmg160_trigger_ops; |
| 1099 | 1055 | iio_trigger_set_drvdata(data->dready_trig, indio_dev); |
| 1100 | 1056 | ret = iio_trigger_register(data->dready_trig); |
| 1101 | 1057 | if (ret) |
| 1102 | 1058 | return ret; |
| 1103 | 1059 | |
| 1104 | − data->motion_trig->dev.parent = &client->dev; | |
| 1060 | + data->motion_trig->dev.parent = dev; | |
| 1105 | 1061 | data->motion_trig->ops = &bmg160_trigger_ops; |
| 1106 | 1062 | iio_trigger_set_drvdata(data->motion_trig, indio_dev); |
| 1107 | 1063 | ret = iio_trigger_register(data->motion_trig); |
| @@ -1116,25 +1072,25 @@ static int bmg160_probe(struct i2c_client *client, · 8 unmodified lines | ||
| 1116 | 1072 | bmg160_trigger_handler, |
| 1117 | 1073 | &bmg160_buffer_setup_ops); |
| 1118 | 1074 | if (ret < 0) { |
| 1119 | − dev_err(&client->dev, | |
| 1075 | + dev_err(dev, | |
| 1120 | 1076 | "iio triggered buffer setup failed\n"); |
| 1121 | 1077 | goto err_trigger_unregister; |
| 1122 | 1078 | } |
| 1123 | 1079 | |
| 1124 | 1080 | ret = iio_device_register(indio_dev); |
| 1125 | 1081 | if (ret < 0) { |
| 1126 | − dev_err(&client->dev, "unable to register iio device\n"); | |
| 1082 | + dev_err(dev, "unable to register iio device\n"); | |
| 1127 | 1083 | goto err_buffer_cleanup; |
| 1128 | 1084 | } |
| 1129 | 1085 | |
| 1130 | − ret = pm_runtime_set_active(&client->dev); | |
| 1086 | + ret = pm_runtime_set_active(dev); | |
| 1131 | 1087 | if (ret) |
| 1132 | 1088 | goto err_iio_unregister; |
| 1133 | 1089 | |
| 1134 | − pm_runtime_enable(&client->dev); | |
| 1135 | − pm_runtime_set_autosuspend_delay(&client->dev, | |
| 1090 | + pm_runtime_enable(dev); | |
| 1091 | + pm_runtime_set_autosuspend_delay(dev, | |
| 1136 | 1092 | BMG160_AUTO_SUSPEND_DELAY_MS); |
| 1137 | − pm_runtime_use_autosuspend(&client->dev); | |
| 1093 | + pm_runtime_use_autosuspend(dev); | |
| 1138 | 1094 | |
| 1139 | 1095 | return 0; |
| 1140 | 1096 | |
| @@ -1150,15 +1106,16 @@ err_trigger_unregister: · 9 unmodified lines | ||
| 1150 | 1106 | |
| 1151 | 1107 | return ret; |
| 1152 | 1108 | } |
| 1109 | +EXPORT_SYMBOL_GPL(bmg160_core_probe); | |
| 1153 | 1110 | |
| 1154 | −static int bmg160_remove(struct i2c_client *client) | |
| 1111 | +void bmg160_core_remove(struct device *dev) | |
| 1155 | 1112 | { |
| 1156 | − struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
| 1113 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1157 | 1114 | struct bmg160_data *data = iio_priv(indio_dev); |
| 1158 | 1115 | |
| 1159 | − pm_runtime_disable(&client->dev); | |
| 1160 | − pm_runtime_set_suspended(&client->dev); | |
| 1161 | − pm_runtime_put_noidle(&client->dev); | |
| 1116 | + pm_runtime_disable(dev); | |
| 1117 | + pm_runtime_set_suspended(dev); | |
| 1118 | + pm_runtime_put_noidle(dev); | |
| 1162 | 1119 | |
| 1163 | 1120 | iio_device_unregister(indio_dev); |
| 1164 | 1121 | iio_triggered_buffer_cleanup(indio_dev); |
| @@ -1171,14 +1128,13 @@ static int bmg160_remove(struct i2c_client *client) · 6 unmodified lines | ||
| 1171 | 1128 | mutex_lock(&data->mutex); |
| 1172 | 1129 | bmg160_set_mode(data, BMG160_MODE_DEEP_SUSPEND); |
| 1173 | 1130 | mutex_unlock(&data->mutex); |
| 1174 | − | |
| 1175 | − return 0; | |
| 1176 | 1131 | } |
| 1132 | +EXPORT_SYMBOL_GPL(bmg160_core_remove); | |
| 1177 | 1133 | |
| 1178 | 1134 | #ifdef CONFIG_PM_SLEEP |
| 1179 | 1135 | static int bmg160_suspend(struct device *dev) |
| 1180 | 1136 | { |
| 1181 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1137 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1182 | 1138 | struct bmg160_data *data = iio_priv(indio_dev); |
| 1183 | 1139 | |
| 1184 | 1140 | mutex_lock(&data->mutex); |
| @@ -1190,7 +1146,7 @@ static int bmg160_suspend(struct device *dev) · 5 unmodified lines | ||
| 1190 | 1146 | |
| 1191 | 1147 | static int bmg160_resume(struct device *dev) |
| 1192 | 1148 | { |
| 1193 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1149 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1194 | 1150 | struct bmg160_data *data = iio_priv(indio_dev); |
| 1195 | 1151 | |
| 1196 | 1152 | mutex_lock(&data->mutex); |
| @@ -1206,13 +1162,13 @@ static int bmg160_resume(struct device *dev) · 9 unmodified lines | ||
| 1206 | 1162 | #ifdef CONFIG_PM |
| 1207 | 1163 | static int bmg160_runtime_suspend(struct device *dev) |
| 1208 | 1164 | { |
| 1209 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1165 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1210 | 1166 | struct bmg160_data *data = iio_priv(indio_dev); |
| 1211 | 1167 | int ret; |
| 1212 | 1168 | |
| 1213 | 1169 | ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND); |
| 1214 | 1170 | if (ret < 0) { |
| 1215 | − dev_err(&data->client->dev, "set mode failed\n"); | |
| 1171 | + dev_err(data->dev, "set mode failed\n"); | |
| 1216 | 1172 | return -EAGAIN; |
| 1217 | 1173 | } |
| 1218 | 1174 | |
| @@ -1221,7 +1177,7 @@ static int bmg160_runtime_suspend(struct device *dev) · 2 unmodified lines | ||
| 1221 | 1177 | |
| 1222 | 1178 | static int bmg160_runtime_resume(struct device *dev) |
| 1223 | 1179 | { |
| 1224 | − struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
| 1180 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
| 1225 | 1181 | struct bmg160_data *data = iio_priv(indio_dev); |
| 1226 | 1182 | int ret; |
| 1227 | 1183 | |
| @@ -1235,39 +1191,12 @@ static int bmg160_runtime_resume(struct device *dev) · 7 unmodified lines | ||
| 1235 | 1191 | } |
| 1236 | 1192 | #endif |
| 1237 | 1193 | |
| 1238 | −static const struct dev_pm_ops bmg160_pm_ops = { | |
| 1194 | +const struct dev_pm_ops bmg160_pm_ops = { | |
| 1239 | 1195 | SET_SYSTEM_SLEEP_PM_OPS(bmg160_suspend, bmg160_resume) |
| 1240 | 1196 | SET_RUNTIME_PM_OPS(bmg160_runtime_suspend, |
| 1241 | 1197 | bmg160_runtime_resume, NULL) |
| 1242 | 1198 | }; |
| 1243 | − | |
| 1244 | −static const struct acpi_device_id bmg160_acpi_match[] = { | |
| 1245 | − {"BMG0160", 0}, | |
| 1246 | − {"BMI055B", 0}, | |
| 1247 | − {}, | |
| 1248 | −}; | |
| 1249 | − | |
| 1250 | −MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); | |
| 1251 | − | |
| 1252 | −static const struct i2c_device_id bmg160_id[] = { | |
| 1253 | − {"bmg160", 0}, | |
| 1254 | − {"bmi055_gyro", 0}, | |
| 1255 | − {} | |
| 1256 | −}; | |
| 1257 | − | |
| 1258 | −MODULE_DEVICE_TABLE(i2c, bmg160_id); | |
| 1259 | − | |
| 1260 | −static struct i2c_driver bmg160_driver = { | |
| 1261 | − .driver = { | |
| 1262 | − .name = BMG160_DRV_NAME, | |
| 1263 | − .acpi_match_table = ACPI_PTR(bmg160_acpi_match), | |
| 1264 | − .pm = &bmg160_pm_ops, | |
| 1265 | − }, | |
| 1266 | − .probe = bmg160_probe, | |
| 1267 | − .remove = bmg160_remove, | |
| 1268 | − .id_table = bmg160_id, | |
| 1269 | −}; | |
| 1270 | −module_i2c_driver(bmg160_driver); | |
| 1199 | +EXPORT_SYMBOL_GPL(bmg160_pm_ops); | |
| 1271 | 1200 | |
| 1272 | 1201 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); |
| 1273 | 1202 | MODULE_LICENSE("GPL v2"); |
| @@ -0,0 +1,71 @@ | ||
| 1 | +#include <linux/i2c.h> | |
| 2 | +#include <linux/regmap.h> | |
| 3 | +#include <linux/iio/iio.h> | |
| 4 | +#include <linux/module.h> | |
| 5 | +#include <linux/acpi.h> | |
| 6 | + | |
| 7 | +#include "bmg160.h" | |
| 8 | + | |
| 9 | +static const struct regmap_config bmg160_regmap_i2c_conf = { | |
| 10 | + .reg_bits = 8, | |
| 11 | + .val_bits = 8, | |
| 12 | + .max_register = 0x3f | |
| 13 | +}; | |
| 14 | + | |
| 15 | +static int bmg160_i2c_probe(struct i2c_client *client, | |
| 16 | + const struct i2c_device_id *id) | |
| 17 | +{ | |
| 18 | + struct regmap *regmap; | |
| 19 | + const char *name = NULL; | |
| 20 | + | |
| 21 | + regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf); | |
| 22 | + if (IS_ERR(regmap)) { | |
| 23 | + dev_err(&client->dev, "Failed to register i2c regmap %d\n", | |
| 24 | + (int)PTR_ERR(regmap)); | |
| 25 | + return PTR_ERR(regmap); | |
| 26 | + } | |
| 27 | + | |
| 28 | + if (id) | |
| 29 | + name = id->name; | |
| 30 | + | |
| 31 | + return bmg160_core_probe(&client->dev, regmap, client->irq, name); | |
| 32 | +} | |
| 33 | + | |
| 34 | +static int bmg160_i2c_remove(struct i2c_client *client) | |
| 35 | +{ | |
| 36 | + bmg160_core_remove(&client->dev); | |
| 37 | + | |
| 38 | + return 0; | |
| 39 | +} | |
| 40 | + | |
| 41 | +static const struct acpi_device_id bmg160_acpi_match[] = { | |
| 42 | + {"BMG0160", 0}, | |
| 43 | + {"BMI055B", 0}, | |
| 44 | + {}, | |
| 45 | +}; | |
| 46 | + | |
| 47 | +MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); | |
| 48 | + | |
| 49 | +static const struct i2c_device_id bmg160_i2c_id[] = { | |
| 50 | + {"bmg160", 0}, | |
| 51 | + {"bmi055_gyro", 0}, | |
| 52 | + {} | |
| 53 | +}; | |
| 54 | + | |
| 55 | +MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); | |
| 56 | + | |
| 57 | +static struct i2c_driver bmg160_i2c_driver = { | |
| 58 | + .driver = { | |
| 59 | + .name = "bmg160_i2c", | |
| 60 | + .acpi_match_table = ACPI_PTR(bmg160_acpi_match), | |
| 61 | + .pm = &bmg160_pm_ops, | |
| 62 | + }, | |
| 63 | + .probe = bmg160_i2c_probe, | |
| 64 | + .remove = bmg160_i2c_remove, | |
| 65 | + .id_table = bmg160_i2c_id, | |
| 66 | +}; | |
| 67 | +module_i2c_driver(bmg160_i2c_driver); | |
| 68 | + | |
| 69 | +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | |
| 70 | +MODULE_LICENSE("GPL v2"); | |
| 71 | +MODULE_DESCRIPTION("BMG160 I2C Gyro driver"); | |
| @@ -0,0 +1,57 @@ | ||
| 1 | +#include <linux/spi/spi.h> | |
| 2 | +#include <linux/regmap.h> | |
| 3 | +#include <linux/iio/iio.h> | |
| 4 | +#include <linux/module.h> | |
| 5 | + | |
| 6 | +#include "bmg160.h" | |
| 7 | + | |
| 8 | +static const struct regmap_config bmg160_regmap_spi_conf = { | |
| 9 | + .reg_bits = 8, | |
| 10 | + .val_bits = 8, | |
| 11 | + .max_register = 0x3f, | |
| 12 | +}; | |
| 13 | + | |
| 14 | +static int bmg160_spi_probe(struct spi_device *spi) | |
| 15 | +{ | |
| 16 | + struct regmap *regmap; | |
| 17 | + const struct spi_device_id *id = spi_get_device_id(spi); | |
| 18 | + | |
| 19 | + regmap = devm_regmap_init_spi(spi, &bmg160_regmap_spi_conf); | |
| 20 | + if (IS_ERR(regmap)) { | |
| 21 | + dev_err(&spi->dev, "Failed to register spi regmap %d\n", | |
| 22 | + (int)PTR_ERR(regmap)); | |
| 23 | + return PTR_ERR(regmap); | |
| 24 | + } | |
| 25 | + | |
| 26 | + return bmg160_core_probe(&spi->dev, regmap, spi->irq, id->name); | |
| 27 | +} | |
| 28 | + | |
| 29 | +static int bmg160_spi_remove(struct spi_device *spi) | |
| 30 | +{ | |
| 31 | + bmg160_core_remove(&spi->dev); | |
| 32 | + | |
| 33 | + return 0; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static const struct spi_device_id bmg160_spi_id[] = { | |
| 37 | + {"bmg160", 0}, | |
| 38 | + {"bmi055_gyro", 0}, | |
| 39 | + {} | |
| 40 | +}; | |
| 41 | + | |
| 42 | +MODULE_DEVICE_TABLE(spi, bmg160_spi_id); | |
| 43 | + | |
| 44 | +static struct spi_driver bmg160_spi_driver = { | |
| 45 | + .driver = { | |
| 46 | + .name = "bmg160_spi", | |
| 47 | + .pm = &bmg160_pm_ops, | |
| 48 | + }, | |
| 49 | + .probe = bmg160_spi_probe, | |
| 50 | + .remove = bmg160_spi_remove, | |
| 51 | + .id_table = bmg160_spi_id, | |
| 52 | +}; | |
| 53 | +module_spi_driver(bmg160_spi_driver); | |
| 54 | + | |
| 55 | +MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); | |
| 56 | +MODULE_LICENSE("GPL v2"); | |
| 57 | +MODULE_DESCRIPTION("BMG160 SPI Gyro driver"); | |
| @@ -383,6 +383,7 @@ static const struct iio_info gyro_info = { · 382 unmodified lines | ||
| 383 | 383 | .attrs = &st_gyro_attribute_group, |
| 384 | 384 | .read_raw = &st_gyro_read_raw, |
| 385 | 385 | .write_raw = &st_gyro_write_raw, |
| 386 | + .debugfs_reg_access = &st_sensors_debugfs_reg_access, | |
| 386 | 387 | }; |
| 387 | 388 | |
| 388 | 389 | #ifdef CONFIG_IIO_TRIGGER |
| @@ -12,6 +12,29 @@ config DHT11 · 11 unmodified lines | ||
| 12 | 12 | Other sensors should work as well as long as they speak the |
| 13 | 13 | same protocol. |
| 14 | 14 | |
| 15 | +config HDC100X | |
| 16 | + tristate "TI HDC100x relative humidity and temperature sensor" | |
| 17 | + depends on I2C | |
| 18 | + help | |
| 19 | + Say yes here to build support for the TI HDC100x series of | |
| 20 | + relative humidity and temperature sensors. | |
| 21 | + | |
| 22 | + To compile this driver as a module, choose M here: the module | |
| 23 | + will be called hdc100x. | |
| 24 | + | |
| 25 | +config HTU21 | |
| 26 | + tristate "Measurement Specialties HTU21 humidity & temperature sensor" | |
| 27 | + depends on I2C | |
| 28 | + select IIO_MS_SENSORS_I2C | |
| 29 | + help | |
| 30 | + If you say yes here you get support for the Measurement Specialties | |
| 31 | + HTU21 humidity and temperature sensor. | |
| 32 | + This driver is also used for MS8607 temperature, pressure & humidity | |
| 33 | + sensor | |
| 34 | + | |
| 35 | + This driver can also be built as a module. If so, the module will | |
| 36 | + be called htu21. | |
| 37 | + | |
| 15 | 38 | config SI7005 |
| 16 | 39 | tristate "SI7005 relative humidity and temperature sensor" |
| 17 | 40 | depends on I2C |
| @@ -3,5 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | # |
| 4 | 4 | |
| 5 | 5 | obj-$(CONFIG_DHT11) += dht11.o |
| 6 | +obj-$(CONFIG_HDC100X) += hdc100x.o | |
| 7 | +obj-$(CONFIG_HTU21) += htu21.o | |
| 6 | 8 | obj-$(CONFIG_SI7005) += si7005.o |
| 7 | 9 | obj-$(CONFIG_SI7020) += si7020.o |
| @@ -0,0 +1,320 @@ | ||
| 1 | +/* | |
| 2 | + * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors | |
| 3 | + * | |
| 4 | + * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + * | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/delay.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/init.h> | |
| 21 | +#include <linux/i2c.h> | |
| 22 | + | |
| 23 | +#include <linux/iio/iio.h> | |
| 24 | +#include <linux/iio/sysfs.h> | |
| 25 | + | |
| 26 | +#define HDC100X_REG_TEMP 0x00 | |
| 27 | +#define HDC100X_REG_HUMIDITY 0x01 | |
| 28 | + | |
| 29 | +#define HDC100X_REG_CONFIG 0x02 | |
| 30 | +#define HDC100X_REG_CONFIG_HEATER_EN BIT(13) | |
| 31 | + | |
| 32 | +struct hdc100x_data { | |
| 33 | + struct i2c_client *client; | |
| 34 | + struct mutex lock; | |
| 35 | + u16 config; | |
| 36 | + | |
| 37 | + /* integration time of the sensor */ | |
| 38 | + int adc_int_us[2]; | |
| 39 | +}; | |
| 40 | + | |
| 41 | +/* integration time in us */ | |
| 42 | +static const int hdc100x_int_time[][3] = { | |
| 43 | + { 6350, 3650, 0 }, /* IIO_TEMP channel*/ | |
| 44 | + { 6500, 3850, 2500 }, /* IIO_HUMIDITYRELATIVE channel */ | |
| 45 | +}; | |
| 46 | + | |
| 47 | +/* HDC100X_REG_CONFIG shift and mask values */ | |
| 48 | +static const struct { | |
| 49 | + int shift; | |
| 50 | + int mask; | |
| 51 | +} hdc100x_resolution_shift[2] = { | |
| 52 | + { /* IIO_TEMP channel */ | |
| 53 | + .shift = 10, | |
| 54 | + .mask = 1 | |
| 55 | + }, | |
| 56 | + { /* IIO_HUMIDITYRELATIVE channel */ | |
| 57 | + .shift = 8, | |
| 58 | + .mask = 2, | |
| 59 | + }, | |
| 60 | +}; | |
| 61 | + | |
| 62 | +static IIO_CONST_ATTR(temp_integration_time_available, | |
| 63 | + "0.00365 0.00635"); | |
| 64 | + | |
| 65 | +static IIO_CONST_ATTR(humidityrelative_integration_time_available, | |
| 66 | + "0.0025 0.00385 0.0065"); | |
| 67 | + | |
| 68 | +static IIO_CONST_ATTR(out_current_heater_raw_available, | |
| 69 | + "0 1"); | |
| 70 | + | |
| 71 | +static struct attribute *hdc100x_attributes[] = { | |
| 72 | + &iio_const_attr_temp_integration_time_available.dev_attr.attr, | |
| 73 | + &iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr, | |
| 74 | + &iio_const_attr_out_current_heater_raw_available.dev_attr.attr, | |
| 75 | + NULL | |
| 76 | +}; | |
| 77 | + | |
| 78 | +static struct attribute_group hdc100x_attribute_group = { | |
| 79 | + .attrs = hdc100x_attributes, | |
| 80 | +}; | |
| 81 | + | |
| 82 | +static const struct iio_chan_spec hdc100x_channels[] = { | |
| 83 | + { | |
| 84 | + .type = IIO_TEMP, | |
| 85 | + .address = HDC100X_REG_TEMP, | |
| 86 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
| 87 | + BIT(IIO_CHAN_INFO_SCALE) | | |
| 88 | + BIT(IIO_CHAN_INFO_INT_TIME) | | |
| 89 | + BIT(IIO_CHAN_INFO_OFFSET), | |
| 90 | + }, | |
| 91 | + { | |
| 92 | + .type = IIO_HUMIDITYRELATIVE, | |
| 93 | + .address = HDC100X_REG_HUMIDITY, | |
| 94 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
| 95 | + BIT(IIO_CHAN_INFO_SCALE) | | |
| 96 | + BIT(IIO_CHAN_INFO_INT_TIME) | |
| 97 | + }, | |
| 98 | + { | |
| 99 | + .type = IIO_CURRENT, | |
| 100 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| 101 | + .extend_name = "heater", | |
| 102 | + .output = 1, | |
| 103 | + }, | |
| 104 | +}; | |
| 105 | + | |
| 106 | +static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val) | |
| 107 | +{ | |
| 108 | + int tmp = (~mask & data->config) | val; | |
| 109 | + int ret; | |
| 110 | + | |
| 111 | + ret = i2c_smbus_write_word_swapped(data->client, | |
| 112 | + HDC100X_REG_CONFIG, tmp); | |
| 113 | + if (!ret) | |
| 114 | + data->config = tmp; | |
| 115 | + | |
| 116 | + return ret; | |
| 117 | +} | |
| 118 | + | |
| 119 | +static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2) | |
| 120 | +{ | |
| 121 | + int shift = hdc100x_resolution_shift[chan].shift; | |
| 122 | + int ret = -EINVAL; | |
| 123 | + int i; | |
| 124 | + | |
| 125 | + for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) { | |
| 126 | + if (val2 && val2 == hdc100x_int_time[chan][i]) { | |
| 127 | + ret = hdc100x_update_config(data, | |
| 128 | + hdc100x_resolution_shift[chan].mask << shift, | |
| 129 | + i << shift); | |
| 130 | + if (!ret) | |
| 131 | + data->adc_int_us[chan] = val2; | |
| 132 | + break; | |
| 133 | + } | |
| 134 | + } | |
| 135 | + | |
| 136 | + return ret; | |
| 137 | +} | |
| 138 | + | |
| 139 | +static int hdc100x_get_measurement(struct hdc100x_data *data, | |
| 140 | + struct iio_chan_spec const *chan) | |
| 141 | +{ | |
| 142 | + struct i2c_client *client = data->client; | |
| 143 | + int delay = data->adc_int_us[chan->address]; | |
| 144 | + int ret; | |
| 145 | + int val; | |
| 146 | + | |
| 147 | + /* start measurement */ | |
| 148 | + ret = i2c_smbus_write_byte(client, chan->address); | |
| 149 | + if (ret < 0) { | |
| 150 | + dev_err(&client->dev, "cannot start measurement"); | |
| 151 | + return ret; | |
| 152 | + } | |
| 153 | + | |
| 154 | + /* wait for integration time to pass */ | |
| 155 | + usleep_range(delay, delay + 1000); | |
| 156 | + | |
| 157 | + /* | |
| 158 | + * i2c_smbus_read_word_data cannot() be used here due to the command | |
| 159 | + * value not being understood and causes NAKs preventing any reading | |
| 160 | + * from being accessed. | |
| 161 | + */ | |
| 162 | + ret = i2c_smbus_read_byte(client); | |
| 163 | + if (ret < 0) { | |
| 164 | + dev_err(&client->dev, "cannot read high byte measurement"); | |
| 165 | + return ret; | |
| 166 | + } | |
| 167 | + val = ret << 6; | |
| 168 | + | |
| 169 | + ret = i2c_smbus_read_byte(client); | |
| 170 | + if (ret < 0) { | |
| 171 | + dev_err(&client->dev, "cannot read low byte measurement"); | |
| 172 | + return ret; | |
| 173 | + } | |
| 174 | + val |= ret >> 2; | |
| 175 | + | |
| 176 | + return val; | |
| 177 | +} | |
| 178 | + | |
| 179 | +static int hdc100x_get_heater_status(struct hdc100x_data *data) | |
| 180 | +{ | |
| 181 | + return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN); | |
| 182 | +} | |
| 183 | + | |
| 184 | +static int hdc100x_read_raw(struct iio_dev *indio_dev, | |
| 185 | + struct iio_chan_spec const *chan, int *val, | |
| 186 | + int *val2, long mask) | |
| 187 | +{ | |
| 188 | + struct hdc100x_data *data = iio_priv(indio_dev); | |
| 189 | + | |
| 190 | + switch (mask) { | |
| 191 | + case IIO_CHAN_INFO_RAW: { | |
| 192 | + int ret; | |
| 193 | + | |
| 194 | + mutex_lock(&data->lock); | |
| 195 | + if (chan->type == IIO_CURRENT) { | |
| 196 | + *val = hdc100x_get_heater_status(data); | |
| 197 | + ret = IIO_VAL_INT; | |
| 198 | + } else { | |
| 199 | + ret = hdc100x_get_measurement(data, chan); | |
| 200 | + if (ret >= 0) { | |
| 201 | + *val = ret; | |
| 202 | + ret = IIO_VAL_INT; | |
| 203 | + } | |
| 204 | + } | |
| 205 | + mutex_unlock(&data->lock); | |
| 206 | + return ret; | |
| 207 | + } | |
| 208 | + case IIO_CHAN_INFO_INT_TIME: | |
| 209 | + *val = 0; | |
| 210 | + *val2 = data->adc_int_us[chan->address]; | |
| 211 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 212 | + case IIO_CHAN_INFO_SCALE: | |
| 213 | + if (chan->type == IIO_TEMP) { | |
| 214 | + *val = 165; | |
| 215 | + *val2 = 65536 >> 2; | |
| 216 | + return IIO_VAL_FRACTIONAL; | |
| 217 | + } else { | |
| 218 | + *val = 0; | |
| 219 | + *val2 = 10000; | |
| 220 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 221 | + } | |
| 222 | + break; | |
| 223 | + case IIO_CHAN_INFO_OFFSET: | |
| 224 | + *val = -3971; | |
| 225 | + *val2 = 879096; | |
| 226 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 227 | + default: | |
| 228 | + return -EINVAL; | |
| 229 | + } | |
| 230 | +} | |
| 231 | + | |
| 232 | +static int hdc100x_write_raw(struct iio_dev *indio_dev, | |
| 233 | + struct iio_chan_spec const *chan, | |
| 234 | + int val, int val2, long mask) | |
| 235 | +{ | |
| 236 | + struct hdc100x_data *data = iio_priv(indio_dev); | |
| 237 | + int ret = -EINVAL; | |
| 238 | + | |
| 239 | + switch (mask) { | |
| 240 | + case IIO_CHAN_INFO_INT_TIME: | |
| 241 | + if (val != 0) | |
| 242 | + return -EINVAL; | |
| 243 | + | |
| 244 | + mutex_lock(&data->lock); | |
| 245 | + ret = hdc100x_set_it_time(data, chan->address, val2); | |
| 246 | + mutex_unlock(&data->lock); | |
| 247 | + return ret; | |
| 248 | + case IIO_CHAN_INFO_RAW: | |
| 249 | + if (chan->type != IIO_CURRENT || val2 != 0) | |
| 250 | + return -EINVAL; | |
| 251 | + | |
| 252 | + mutex_lock(&data->lock); | |
| 253 | + ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN, | |
| 254 | + val ? HDC100X_REG_CONFIG_HEATER_EN : 0); | |
| 255 | + mutex_unlock(&data->lock); | |
| 256 | + return ret; | |
| 257 | + default: | |
| 258 | + return -EINVAL; | |
| 259 | + } | |
| 260 | +} | |
| 261 | + | |
| 262 | +static const struct iio_info hdc100x_info = { | |
| 263 | + .read_raw = hdc100x_read_raw, | |
| 264 | + .write_raw = hdc100x_write_raw, | |
| 265 | + .attrs = &hdc100x_attribute_group, | |
| 266 | + .driver_module = THIS_MODULE, | |
| 267 | +}; | |
| 268 | + | |
| 269 | +static int hdc100x_probe(struct i2c_client *client, | |
| 270 | + const struct i2c_device_id *id) | |
| 271 | +{ | |
| 272 | + struct iio_dev *indio_dev; | |
| 273 | + struct hdc100x_data *data; | |
| 274 | + | |
| 275 | + if (!i2c_check_functionality(client->adapter, | |
| 276 | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE)) | |
| 277 | + return -ENODEV; | |
| 278 | + | |
| 279 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 280 | + if (!indio_dev) | |
| 281 | + return -ENOMEM; | |
| 282 | + | |
| 283 | + data = iio_priv(indio_dev); | |
| 284 | + i2c_set_clientdata(client, indio_dev); | |
| 285 | + data->client = client; | |
| 286 | + mutex_init(&data->lock); | |
| 287 | + | |
| 288 | + indio_dev->dev.parent = &client->dev; | |
| 289 | + indio_dev->name = dev_name(&client->dev); | |
| 290 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 291 | + indio_dev->info = &hdc100x_info; | |
| 292 | + | |
| 293 | + indio_dev->channels = hdc100x_channels; | |
| 294 | + indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels); | |
| 295 | + | |
| 296 | + /* be sure we are in a known state */ | |
| 297 | + hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]); | |
| 298 | + hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]); | |
| 299 | + | |
| 300 | + return devm_iio_device_register(&client->dev, indio_dev); | |
| 301 | +} | |
| 302 | + | |
| 303 | +static const struct i2c_device_id hdc100x_id[] = { | |
| 304 | + { "hdc100x", 0 }, | |
| 305 | + { } | |
| 306 | +}; | |
| 307 | +MODULE_DEVICE_TABLE(i2c, hdc100x_id); | |
| 308 | + | |
| 309 | +static struct i2c_driver hdc100x_driver = { | |
| 310 | + .driver = { | |
| 311 | + .name = "hdc100x", | |
| 312 | + }, | |
| 313 | + .probe = hdc100x_probe, | |
| 314 | + .id_table = hdc100x_id, | |
| 315 | +}; | |
| 316 | +module_i2c_driver(hdc100x_driver); | |
| 317 | + | |
| 318 | +MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); | |
| 319 | +MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver"); | |
| 320 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,253 @@ | ||
| 1 | +/* | |
| 2 | + * htu21.c - Support for Measurement-Specialties | |
| 3 | + * htu21 temperature & humidity sensor | |
| 4 | + * and humidity part of MS8607 sensor | |
| 5 | + * | |
| 6 | + * Copyright (c) 2014 Measurement-Specialties | |
| 7 | + * | |
| 8 | + * Licensed under the GPL-2. | |
| 9 | + * | |
| 10 | + * (7-bit I2C slave address 0x40) | |
| 11 | + * | |
| 12 | + * Datasheet: | |
| 13 | + * http://www.meas-spec.com/downloads/HTU21D.pdf | |
| 14 | + * Datasheet: | |
| 15 | + * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/init.h> | |
| 19 | +#include <linux/device.h> | |
| 20 | +#include <linux/kernel.h> | |
| 21 | +#include <linux/stat.h> | |
| 22 | +#include <linux/module.h> | |
| 23 | +#include <linux/iio/iio.h> | |
| 24 | +#include <linux/iio/sysfs.h> | |
| 25 | + | |
| 26 | +#include "../common/ms_sensors/ms_sensors_i2c.h" | |
| 27 | + | |
| 28 | +#define HTU21_RESET 0xFE | |
| 29 | + | |
| 30 | +enum { | |
| 31 | + HTU21, | |
| 32 | + MS8607 | |
| 33 | +}; | |
| 34 | + | |
| 35 | +static const int htu21_samp_freq[4] = { 20, 40, 70, 120 }; | |
| 36 | +/* String copy of the above const for readability purpose */ | |
| 37 | +static const char htu21_show_samp_freq[] = "20 40 70 120"; | |
| 38 | + | |
| 39 | +static int htu21_read_raw(struct iio_dev *indio_dev, | |
| 40 | + struct iio_chan_spec const *channel, int *val, | |
| 41 | + int *val2, long mask) | |
| 42 | +{ | |
| 43 | + int ret, temperature; | |
| 44 | + unsigned int humidity; | |
| 45 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 46 | + | |
| 47 | + switch (mask) { | |
| 48 | + case IIO_CHAN_INFO_PROCESSED: | |
| 49 | + switch (channel->type) { | |
| 50 | + case IIO_TEMP: /* in milli °C */ | |
| 51 | + ret = ms_sensors_ht_read_temperature(dev_data, | |
| 52 | + &temperature); | |
| 53 | + if (ret) | |
| 54 | + return ret; | |
| 55 | + *val = temperature; | |
| 56 | + | |
| 57 | + return IIO_VAL_INT; | |
| 58 | + case IIO_HUMIDITYRELATIVE: /* in milli %RH */ | |
| 59 | + ret = ms_sensors_ht_read_humidity(dev_data, | |
| 60 | + &humidity); | |
| 61 | + if (ret) | |
| 62 | + return ret; | |
| 63 | + *val = humidity; | |
| 64 | + | |
| 65 | + return IIO_VAL_INT; | |
| 66 | + default: | |
| 67 | + return -EINVAL; | |
| 68 | + } | |
| 69 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 70 | + *val = htu21_samp_freq[dev_data->res_index]; | |
| 71 | + | |
| 72 | + return IIO_VAL_INT; | |
| 73 | + default: | |
| 74 | + return -EINVAL; | |
| 75 | + } | |
| 76 | +} | |
| 77 | + | |
| 78 | +static int htu21_write_raw(struct iio_dev *indio_dev, | |
| 79 | + struct iio_chan_spec const *chan, | |
| 80 | + int val, int val2, long mask) | |
| 81 | +{ | |
| 82 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 83 | + int i, ret; | |
| 84 | + | |
| 85 | + switch (mask) { | |
| 86 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 87 | + i = ARRAY_SIZE(htu21_samp_freq); | |
| 88 | + while (i-- > 0) | |
| 89 | + if (val == htu21_samp_freq[i]) | |
| 90 | + break; | |
| 91 | + if (i < 0) | |
| 92 | + return -EINVAL; | |
| 93 | + mutex_lock(&dev_data->lock); | |
| 94 | + dev_data->res_index = i; | |
| 95 | + ret = ms_sensors_write_resolution(dev_data, i); | |
| 96 | + mutex_unlock(&dev_data->lock); | |
| 97 | + | |
| 98 | + return ret; | |
| 99 | + default: | |
| 100 | + return -EINVAL; | |
| 101 | + } | |
| 102 | +} | |
| 103 | + | |
| 104 | +static const struct iio_chan_spec htu21_channels[] = { | |
| 105 | + { | |
| 106 | + .type = IIO_TEMP, | |
| 107 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 108 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 109 | + }, | |
| 110 | + { | |
| 111 | + .type = IIO_HUMIDITYRELATIVE, | |
| 112 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 113 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 114 | + } | |
| 115 | +}; | |
| 116 | + | |
| 117 | +/* | |
| 118 | + * Meas Spec recommendation is to not read temperature | |
| 119 | + * on this driver part for MS8607 | |
| 120 | + */ | |
| 121 | +static const struct iio_chan_spec ms8607_channels[] = { | |
| 122 | + { | |
| 123 | + .type = IIO_HUMIDITYRELATIVE, | |
| 124 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 125 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 126 | + } | |
| 127 | +}; | |
| 128 | + | |
| 129 | +static ssize_t htu21_show_battery_low(struct device *dev, | |
| 130 | + struct device_attribute *attr, char *buf) | |
| 131 | +{ | |
| 132 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
| 133 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 134 | + | |
| 135 | + return ms_sensors_show_battery_low(dev_data, buf); | |
| 136 | +} | |
| 137 | + | |
| 138 | +static ssize_t htu21_show_heater(struct device *dev, | |
| 139 | + struct device_attribute *attr, char *buf) | |
| 140 | +{ | |
| 141 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
| 142 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 143 | + | |
| 144 | + return ms_sensors_show_heater(dev_data, buf); | |
| 145 | +} | |
| 146 | + | |
| 147 | +static ssize_t htu21_write_heater(struct device *dev, | |
| 148 | + struct device_attribute *attr, | |
| 149 | + const char *buf, size_t len) | |
| 150 | +{ | |
| 151 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
| 152 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 153 | + | |
| 154 | + return ms_sensors_write_heater(dev_data, buf, len); | |
| 155 | +} | |
| 156 | + | |
| 157 | +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq); | |
| 158 | +static IIO_DEVICE_ATTR(battery_low, S_IRUGO, | |
| 159 | + htu21_show_battery_low, NULL, 0); | |
| 160 | +static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, | |
| 161 | + htu21_show_heater, htu21_write_heater, 0); | |
| 162 | + | |
| 163 | +static struct attribute *htu21_attributes[] = { | |
| 164 | + &iio_const_attr_sampling_frequency_available.dev_attr.attr, | |
| 165 | + &iio_dev_attr_battery_low.dev_attr.attr, | |
| 166 | + &iio_dev_attr_heater_enable.dev_attr.attr, | |
| 167 | + NULL, | |
| 168 | +}; | |
| 169 | + | |
| 170 | +static const struct attribute_group htu21_attribute_group = { | |
| 171 | + .attrs = htu21_attributes, | |
| 172 | +}; | |
| 173 | + | |
| 174 | +static const struct iio_info htu21_info = { | |
| 175 | + .read_raw = htu21_read_raw, | |
| 176 | + .write_raw = htu21_write_raw, | |
| 177 | + .attrs = &htu21_attribute_group, | |
| 178 | + .driver_module = THIS_MODULE, | |
| 179 | +}; | |
| 180 | + | |
| 181 | +static int htu21_probe(struct i2c_client *client, | |
| 182 | + const struct i2c_device_id *id) | |
| 183 | +{ | |
| 184 | + struct ms_ht_dev *dev_data; | |
| 185 | + struct iio_dev *indio_dev; | |
| 186 | + int ret; | |
| 187 | + u64 serial_number; | |
| 188 | + | |
| 189 | + if (!i2c_check_functionality(client->adapter, | |
| 190 | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | | |
| 191 | + I2C_FUNC_SMBUS_WRITE_BYTE | | |
| 192 | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | |
| 193 | + dev_err(&client->dev, | |
| 194 | + "Adapter does not support some i2c transaction\n"); | |
| 195 | + return -ENODEV; | |
| 196 | + } | |
| 197 | + | |
| 198 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); | |
| 199 | + if (!indio_dev) | |
| 200 | + return -ENOMEM; | |
| 201 | + | |
| 202 | + dev_data = iio_priv(indio_dev); | |
| 203 | + dev_data->client = client; | |
| 204 | + dev_data->res_index = 0; | |
| 205 | + mutex_init(&dev_data->lock); | |
| 206 | + | |
| 207 | + indio_dev->info = &htu21_info; | |
| 208 | + indio_dev->name = id->name; | |
| 209 | + indio_dev->dev.parent = &client->dev; | |
| 210 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 211 | + | |
| 212 | + if (id->driver_data == MS8607) { | |
| 213 | + indio_dev->channels = ms8607_channels; | |
| 214 | + indio_dev->num_channels = ARRAY_SIZE(ms8607_channels); | |
| 215 | + } else { | |
| 216 | + indio_dev->channels = htu21_channels; | |
| 217 | + indio_dev->num_channels = ARRAY_SIZE(htu21_channels); | |
| 218 | + } | |
| 219 | + | |
| 220 | + i2c_set_clientdata(client, indio_dev); | |
| 221 | + | |
| 222 | + ret = ms_sensors_reset(client, HTU21_RESET, 15000); | |
| 223 | + if (ret) | |
| 224 | + return ret; | |
| 225 | + | |
| 226 | + ret = ms_sensors_read_serial(client, &serial_number); | |
| 227 | + if (ret) | |
| 228 | + return ret; | |
| 229 | + dev_info(&client->dev, "Serial number : %llx", serial_number); | |
| 230 | + | |
| 231 | + return devm_iio_device_register(&client->dev, indio_dev); | |
| 232 | +} | |
| 233 | + | |
| 234 | +static const struct i2c_device_id htu21_id[] = { | |
| 235 | + {"htu21", HTU21}, | |
| 236 | + {"ms8607-humidity", MS8607}, | |
| 237 | + {} | |
| 238 | +}; | |
| 239 | + | |
| 240 | +static struct i2c_driver htu21_driver = { | |
| 241 | + .probe = htu21_probe, | |
| 242 | + .id_table = htu21_id, | |
| 243 | + .driver = { | |
| 244 | + .name = "htu21", | |
| 245 | + }, | |
| 246 | +}; | |
| 247 | + | |
| 248 | +module_i2c_driver(htu21_driver); | |
| 249 | + | |
| 250 | +MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver"); | |
| 251 | +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); | |
| 252 | +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); | |
| 253 | +MODULE_LICENSE("GPL v2"); | |
| @@ -57,8 +57,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev, · 56 unmodified lines | ||
| 57 | 57 | if (ret < 0) |
| 58 | 58 | return ret; |
| 59 | 59 | *val = ret >> 2; |
| 60 | + /* | |
| 61 | + * Humidity values can slightly exceed the 0-100%RH | |
| 62 | + * range and should be corrected by software | |
| 63 | + */ | |
| 60 | 64 | if (chan->type == IIO_HUMIDITYRELATIVE) |
| 61 | − *val &= GENMASK(11, 0); | |
| 65 | + *val = clamp_val(*val, 786, 13893); | |
| 62 | 66 | return IIO_VAL_INT; |
| 63 | 67 | case IIO_CHAN_INFO_SCALE: |
| 64 | 68 | if (chan->type == IIO_TEMP) |
| @@ -27,7 +27,6 @@ · 26 unmodified lines | ||
| 27 | 27 | #include <linux/iio/trigger_consumer.h> |
| 28 | 28 | |
| 29 | 29 | #define KMX61_DRV_NAME "kmx61" |
| 30 | −#define KMX61_GPIO_NAME "kmx61_int" | |
| 31 | 30 | #define KMX61_IRQ_NAME "kmx61_event" |
| 32 | 31 | |
| 33 | 32 | #define KMX61_REG_WHO_AM_I 0x00 |
| @@ -1243,30 +1242,6 @@ static const char *kmx61_match_acpi_device(struct device *dev) · 1209 unmodified lines | ||
| 1243 | 1242 | return dev_name(dev); |
| 1244 | 1243 | } |
| 1245 | 1244 | |
| 1246 | −static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data) | |
| 1247 | −{ | |
| 1248 | − struct device *dev; | |
| 1249 | − struct gpio_desc *gpio; | |
| 1250 | − int ret; | |
| 1251 | − | |
| 1252 | − if (!client) | |
| 1253 | − return -EINVAL; | |
| 1254 | − | |
| 1255 | − dev = &client->dev; | |
| 1256 | − | |
| 1257 | − /* data ready gpio interrupt pin */ | |
| 1258 | − gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN); | |
| 1259 | − if (IS_ERR(gpio)) { | |
| 1260 | − dev_err(dev, "acpi gpio get index failed\n"); | |
| 1261 | − return PTR_ERR(gpio); | |
| 1262 | − } | |
| 1263 | − | |
| 1264 | − ret = gpiod_to_irq(gpio); | |
| 1265 | − | |
| 1266 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 1267 | − return ret; | |
| 1268 | −} | |
| 1269 | − | |
| 1270 | 1245 | static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data, |
| 1271 | 1246 | const struct iio_info *info, |
| 1272 | 1247 | const struct iio_chan_spec *chan, |
| @@ -1360,9 +1335,6 @@ static int kmx61_probe(struct i2c_client *client, · 87 unmodified lines | ||
| 1360 | 1335 | if (ret < 0) |
| 1361 | 1336 | return ret; |
| 1362 | 1337 | |
| 1363 | − if (client->irq < 0) | |
| 1364 | − client->irq = kmx61_gpio_probe(client, data); | |
| 1365 | − | |
| 1366 | 1338 | if (client->irq > 0) { |
| 1367 | 1339 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 1368 | 1340 | kmx61_data_rdy_trig_poll, |
| @@ -75,6 +75,8 @@ static const char * const iio_chan_type_name_spec[] = { · 74 unmodified lines | ||
| 75 | 75 | [IIO_ENERGY] = "energy", |
| 76 | 76 | [IIO_DISTANCE] = "distance", |
| 77 | 77 | [IIO_VELOCITY] = "velocity", |
| 78 | + [IIO_CONCENTRATION] = "concentration", | |
| 79 | + [IIO_RESISTANCE] = "resistance", | |
| 78 | 80 | }; |
| 79 | 81 | |
| 80 | 82 | static const char * const iio_modifier_names[] = { |
| @@ -111,6 +113,8 @@ static const char * const iio_modifier_names[] = { · 30 unmodified lines | ||
| 111 | 113 | [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", |
| 112 | 114 | [IIO_MOD_I] = "i", |
| 113 | 115 | [IIO_MOD_Q] = "q", |
| 116 | + [IIO_MOD_CO2] = "co2", | |
| 117 | + [IIO_MOD_VOC] = "voc", | |
| 114 | 118 | }; |
| 115 | 119 | |
| 116 | 120 | /* relies on pairs of these shared then separate */ |
| @@ -962,7 +966,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) · 845 unmodified lines | ||
| 962 | 966 | static void iio_dev_release(struct device *device) |
| 963 | 967 | { |
| 964 | 968 | struct iio_dev *indio_dev = dev_to_iio_dev(device); |
| 965 | − if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) | |
| 969 | + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) | |
| 966 | 970 | iio_device_unregister_trigger_consumer(indio_dev); |
| 967 | 971 | iio_device_unregister_eventset(indio_dev); |
| 968 | 972 | iio_device_unregister_sysfs(indio_dev); |
| @@ -1153,6 +1157,8 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 184 unmodified lines | ||
| 1153 | 1157 | |
| 1154 | 1158 | if (cmd == IIO_GET_EVENT_FD_IOCTL) { |
| 1155 | 1159 | fd = iio_event_getfd(indio_dev); |
| 1160 | + if (fd < 0) | |
| 1161 | + return fd; | |
| 1156 | 1162 | if (copy_to_user(ip, &fd, sizeof(fd))) |
| 1157 | 1163 | return -EFAULT; |
| 1158 | 1164 | return 0; |
| @@ -1241,7 +1247,7 @@ int iio_device_register(struct iio_dev *indio_dev) · 82 unmodified lines | ||
| 1241 | 1247 | "Failed to register event set\n"); |
| 1242 | 1248 | goto error_free_sysfs; |
| 1243 | 1249 | } |
| 1244 | − if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) | |
| 1250 | + if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) | |
| 1245 | 1251 | iio_device_register_trigger_consumer(indio_dev); |
| 1246 | 1252 | |
| 1247 | 1253 | if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) && |
| @@ -366,10 +366,18 @@ static ssize_t iio_trigger_write_current(struct device *dev, · 365 unmodified lines | ||
| 366 | 366 | |
| 367 | 367 | indio_dev->trig = trig; |
| 368 | 368 | |
| 369 | − if (oldtrig) | |
| 369 | + if (oldtrig) { | |
| 370 | + if (indio_dev->modes & INDIO_EVENT_TRIGGERED) | |
| 371 | + iio_trigger_detach_poll_func(oldtrig, | |
| 372 | + indio_dev->pollfunc_event); | |
| 370 | 373 | iio_trigger_put(oldtrig); |
| 371 | − if (indio_dev->trig) | |
| 374 | + } | |
| 375 | + if (indio_dev->trig) { | |
| 372 | 376 | iio_trigger_get(indio_dev->trig); |
| 377 | + if (indio_dev->modes & INDIO_EVENT_TRIGGERED) | |
| 378 | + iio_trigger_attach_poll_func(indio_dev->trig, | |
| 379 | + indio_dev->pollfunc_event); | |
| 380 | + } | |
| 373 | 381 | |
| 374 | 382 | return len; |
| 375 | 383 | } |
| @@ -0,0 +1,68 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2015 Cogent Embedded, Inc. | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or modify it | |
| 5 | + * under the terms of the GNU General Public License as published by the | |
| 6 | + * Free Software Foundation; either version 2 of the License, or (at your | |
| 7 | + * option) any later version. | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include <linux/kernel.h> | |
| 11 | +#include <linux/export.h> | |
| 12 | +#include <linux/module.h> | |
| 13 | +#include <linux/iio/iio.h> | |
| 14 | +#include <linux/iio/triggered_event.h> | |
| 15 | +#include <linux/iio/trigger_consumer.h> | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * iio_triggered_event_setup() - Setup pollfunc_event for triggered event | |
| 19 | + * @indio_dev: IIO device structure | |
| 20 | + * @h: Function which will be used as pollfunc_event top half | |
| 21 | + * @thread: Function which will be used as pollfunc_event bottom half | |
| 22 | + * | |
| 23 | + * This function combines some common tasks which will normally be performed | |
| 24 | + * when setting up a triggered event. It will allocate the pollfunc_event and | |
| 25 | + * set mode to use it for triggered event. | |
| 26 | + * | |
| 27 | + * Before calling this function the indio_dev structure should already be | |
| 28 | + * completely initialized, but not yet registered. In practice this means that | |
| 29 | + * this function should be called right before iio_device_register(). | |
| 30 | + * | |
| 31 | + * To free the resources allocated by this function call | |
| 32 | + * iio_triggered_event_cleanup(). | |
| 33 | + */ | |
| 34 | +int iio_triggered_event_setup(struct iio_dev *indio_dev, | |
| 35 | + irqreturn_t (*h)(int irq, void *p), | |
| 36 | + irqreturn_t (*thread)(int irq, void *p)) | |
| 37 | +{ | |
| 38 | + indio_dev->pollfunc_event = iio_alloc_pollfunc(h, | |
| 39 | + thread, | |
| 40 | + IRQF_ONESHOT, | |
| 41 | + indio_dev, | |
| 42 | + "%s_consumer%d", | |
| 43 | + indio_dev->name, | |
| 44 | + indio_dev->id); | |
| 45 | + if (indio_dev->pollfunc_event == NULL) | |
| 46 | + return -ENOMEM; | |
| 47 | + | |
| 48 | + /* Flag that events polling is possible */ | |
| 49 | + indio_dev->modes |= INDIO_EVENT_TRIGGERED; | |
| 50 | + | |
| 51 | + return 0; | |
| 52 | +} | |
| 53 | +EXPORT_SYMBOL(iio_triggered_event_setup); | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup() | |
| 57 | + * @indio_dev: IIO device structure | |
| 58 | + */ | |
| 59 | +void iio_triggered_event_cleanup(struct iio_dev *indio_dev) | |
| 60 | +{ | |
| 61 | + indio_dev->modes &= ~INDIO_EVENT_TRIGGERED; | |
| 62 | + iio_dealloc_pollfunc(indio_dev->pollfunc_event); | |
| 63 | +} | |
| 64 | +EXPORT_SYMBOL(iio_triggered_event_cleanup); | |
| 65 | + | |
| 66 | +MODULE_AUTHOR("Vladimir Barinov"); | |
| 67 | +MODULE_DESCRIPTION("IIO helper functions for setting up triggered events"); | |
| 68 | +MODULE_LICENSE("GPL"); | |
| @@ -50,6 +50,19 @@ config APDS9300 · 49 unmodified lines | ||
| 50 | 50 | To compile this driver as a module, choose M here: the |
| 51 | 51 | module will be called apds9300. |
| 52 | 52 | |
| 53 | +config APDS9960 | |
| 54 | + tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" | |
| 55 | + select REGMAP_I2C | |
| 56 | + select IIO_BUFFER | |
| 57 | + select IIO_KFIFO_BUF | |
| 58 | + depends on I2C | |
| 59 | + help | |
| 60 | + Say Y here to build I2C interface support for the Avago | |
| 61 | + APDS9960 gesture/RGB/ALS/proximity sensor. | |
| 62 | + | |
| 63 | + To compile this driver as a module, choose M here: the | |
| 64 | + module will be called apds9960 | |
| 65 | + | |
| 53 | 66 | config BH1750 |
| 54 | 67 | tristate "ROHM BH1750 ambient light sensor" |
| 55 | 68 | depends on I2C |
| @@ -287,6 +300,16 @@ config TSL4531 · 231 unmodified lines | ||
| 287 | 300 | To compile this driver as a module, choose M here: the |
| 288 | 301 | module will be called tsl4531. |
| 289 | 302 | |
| 303 | +config US5182D | |
| 304 | + tristate "UPISEMI light and proximity sensor" | |
| 305 | + depends on I2C | |
| 306 | + help | |
| 307 | + If you say yes here you get support for the UPISEMI US5182D | |
| 308 | + ambient light and proximity sensor. | |
| 309 | + | |
| 310 | + This driver can also be built as a module. If so, the module | |
| 311 | + will be called us5182d. | |
| 312 | + | |
| 290 | 313 | config VCNL4000 |
| 291 | 314 | tristate "VCNL4000 combined ALS and proximity sensor" |
| 292 | 315 | depends on I2C |
| @@ -7,6 +7,7 @@ obj-$(CONFIG_ACPI_ALS) += acpi-als.o · 6 unmodified lines | ||
| 7 | 7 | obj-$(CONFIG_ADJD_S311) += adjd_s311.o |
| 8 | 8 | obj-$(CONFIG_AL3320A) += al3320a.o |
| 9 | 9 | obj-$(CONFIG_APDS9300) += apds9300.o |
| 10 | +obj-$(CONFIG_APDS9960) += apds9960.o | |
| 10 | 11 | obj-$(CONFIG_BH1750) += bh1750.o |
| 11 | 12 | obj-$(CONFIG_CM32181) += cm32181.o |
| 12 | 13 | obj-$(CONFIG_CM3232) += cm3232.o |
| @@ -27,4 +28,5 @@ obj-$(CONFIG_STK3310) += stk3310.o · 14 unmodified lines | ||
| 27 | 28 | obj-$(CONFIG_TCS3414) += tcs3414.o |
| 28 | 29 | obj-$(CONFIG_TCS3472) += tcs3472.o |
| 29 | 30 | obj-$(CONFIG_TSL4531) += tsl4531.o |
| 31 | +obj-$(CONFIG_US5182D) += us5182d.o | |
| 30 | 32 | obj-$(CONFIG_VCNL4000) += vcnl4000.o |
| @@ -0,0 +1,1130 @@ | ||
| 1 | +/* | |
| 2 | + * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor | |
| 3 | + * | |
| 4 | + * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + * | |
| 16 | + * TODO: gesture + proximity calib offsets | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/init.h> | |
| 21 | +#include <linux/interrupt.h> | |
| 22 | +#include <linux/delay.h> | |
| 23 | +#include <linux/mutex.h> | |
| 24 | +#include <linux/err.h> | |
| 25 | +#include <linux/irq.h> | |
| 26 | +#include <linux/gpio.h> | |
| 27 | +#include <linux/i2c.h> | |
| 28 | +#include <linux/pm_runtime.h> | |
| 29 | +#include <linux/regmap.h> | |
| 30 | +#include <linux/iio/iio.h> | |
| 31 | +#include <linux/iio/buffer.h> | |
| 32 | +#include <linux/iio/events.h> | |
| 33 | +#include <linux/iio/kfifo_buf.h> | |
| 34 | +#include <linux/iio/sysfs.h> | |
| 35 | +#include <linux/of_gpio.h> | |
| 36 | + | |
| 37 | +#define APDS9960_REGMAP_NAME "apds9960_regmap" | |
| 38 | +#define APDS9960_DRV_NAME "apds9960" | |
| 39 | + | |
| 40 | +#define APDS9960_REG_RAM_START 0x00 | |
| 41 | +#define APDS9960_REG_RAM_END 0x7f | |
| 42 | + | |
| 43 | +#define APDS9960_REG_ENABLE 0x80 | |
| 44 | +#define APDS9960_REG_ATIME 0x81 | |
| 45 | +#define APDS9960_REG_WTIME 0x83 | |
| 46 | + | |
| 47 | +#define APDS9960_REG_AILTL 0x84 | |
| 48 | +#define APDS9960_REG_AILTH 0x85 | |
| 49 | +#define APDS9960_REG_AIHTL 0x86 | |
| 50 | +#define APDS9960_REG_AIHTH 0x87 | |
| 51 | + | |
| 52 | +#define APDS9960_REG_PILT 0x89 | |
| 53 | +#define APDS9960_REG_PIHT 0x8b | |
| 54 | +#define APDS9960_REG_PERS 0x8c | |
| 55 | + | |
| 56 | +#define APDS9960_REG_CONFIG_1 0x8d | |
| 57 | +#define APDS9960_REG_PPULSE 0x8e | |
| 58 | + | |
| 59 | +#define APDS9960_REG_CONTROL 0x8f | |
| 60 | +#define APDS9960_REG_CONTROL_AGAIN_MASK 0x03 | |
| 61 | +#define APDS9960_REG_CONTROL_PGAIN_MASK 0x0c | |
| 62 | +#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT 0 | |
| 63 | +#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT 2 | |
| 64 | + | |
| 65 | +#define APDS9960_REG_CONFIG_2 0x90 | |
| 66 | +#define APDS9960_REG_CONFIG_2_GGAIN_MASK 0x60 | |
| 67 | +#define APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT 5 | |
| 68 | + | |
| 69 | +#define APDS9960_REG_ID 0x92 | |
| 70 | + | |
| 71 | +#define APDS9960_REG_STATUS 0x93 | |
| 72 | +#define APDS9960_REG_STATUS_PS_INT BIT(5) | |
| 73 | +#define APDS9960_REG_STATUS_ALS_INT BIT(4) | |
| 74 | +#define APDS9960_REG_STATUS_GINT BIT(2) | |
| 75 | + | |
| 76 | +#define APDS9960_REG_PDATA 0x9c | |
| 77 | +#define APDS9960_REG_POFFSET_UR 0x9d | |
| 78 | +#define APDS9960_REG_POFFSET_DL 0x9e | |
| 79 | +#define APDS9960_REG_CONFIG_3 0x9f | |
| 80 | + | |
| 81 | +#define APDS9960_REG_GPENTH 0xa0 | |
| 82 | +#define APDS9960_REG_GEXTH 0xa1 | |
| 83 | + | |
| 84 | +#define APDS9960_REG_GCONF_1 0xa2 | |
| 85 | +#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK 0xc0 | |
| 86 | +#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT 6 | |
| 87 | + | |
| 88 | +#define APDS9960_REG_GCONF_2 0xa3 | |
| 89 | +#define APDS9960_REG_GOFFSET_U 0xa4 | |
| 90 | +#define APDS9960_REG_GOFFSET_D 0xa5 | |
| 91 | +#define APDS9960_REG_GPULSE 0xa6 | |
| 92 | +#define APDS9960_REG_GOFFSET_L 0xa7 | |
| 93 | +#define APDS9960_REG_GOFFSET_R 0xa9 | |
| 94 | +#define APDS9960_REG_GCONF_3 0xaa | |
| 95 | + | |
| 96 | +#define APDS9960_REG_GCONF_4 0xab | |
| 97 | +#define APDS9960_REG_GFLVL 0xae | |
| 98 | +#define APDS9960_REG_GSTATUS 0xaf | |
| 99 | + | |
| 100 | +#define APDS9960_REG_IFORCE 0xe4 | |
| 101 | +#define APDS9960_REG_PICLEAR 0xe5 | |
| 102 | +#define APDS9960_REG_CICLEAR 0xe6 | |
| 103 | +#define APDS9960_REG_AICLEAR 0xe7 | |
| 104 | + | |
| 105 | +#define APDS9960_DEFAULT_PERS 0x33 | |
| 106 | +#define APDS9960_DEFAULT_GPENTH 0x50 | |
| 107 | +#define APDS9960_DEFAULT_GEXTH 0x40 | |
| 108 | + | |
| 109 | +#define APDS9960_MAX_PXS_THRES_VAL 255 | |
| 110 | +#define APDS9960_MAX_ALS_THRES_VAL 0xffff | |
| 111 | +#define APDS9960_MAX_INT_TIME_IN_US 1000000 | |
| 112 | + | |
| 113 | +enum apds9960_als_channel_idx { | |
| 114 | + IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE, | |
| 115 | +}; | |
| 116 | + | |
| 117 | +#define APDS9960_REG_ALS_BASE 0x94 | |
| 118 | +#define APDS9960_REG_ALS_CHANNEL(_colour) \ | |
| 119 | + (APDS9960_REG_ALS_BASE + (IDX_ALS_##_colour * 2)) | |
| 120 | + | |
| 121 | +enum apds9960_gesture_channel_idx { | |
| 122 | + IDX_DIR_UP, IDX_DIR_DOWN, IDX_DIR_LEFT, IDX_DIR_RIGHT, | |
| 123 | +}; | |
| 124 | + | |
| 125 | +#define APDS9960_REG_GFIFO_BASE 0xfc | |
| 126 | +#define APDS9960_REG_GFIFO_DIR(_dir) \ | |
| 127 | + (APDS9960_REG_GFIFO_BASE + IDX_DIR_##_dir) | |
| 128 | + | |
| 129 | +struct apds9960_data { | |
| 130 | + struct i2c_client *client; | |
| 131 | + struct iio_dev *indio_dev; | |
| 132 | + struct mutex lock; | |
| 133 | + | |
| 134 | + /* regmap fields */ | |
| 135 | + struct regmap *regmap; | |
| 136 | + struct regmap_field *reg_int_als; | |
| 137 | + struct regmap_field *reg_int_ges; | |
| 138 | + struct regmap_field *reg_int_pxs; | |
| 139 | + | |
| 140 | + struct regmap_field *reg_enable_als; | |
| 141 | + struct regmap_field *reg_enable_ges; | |
| 142 | + struct regmap_field *reg_enable_pxs; | |
| 143 | + | |
| 144 | + /* state */ | |
| 145 | + int als_int; | |
| 146 | + int pxs_int; | |
| 147 | + int gesture_mode_running; | |
| 148 | + | |
| 149 | + /* gain values */ | |
| 150 | + int als_gain; | |
| 151 | + int pxs_gain; | |
| 152 | + | |
| 153 | + /* integration time value in us */ | |
| 154 | + int als_adc_int_us; | |
| 155 | + | |
| 156 | + /* gesture buffer */ | |
| 157 | + u8 buffer[4]; /* 4 8-bit channels */ | |
| 158 | +}; | |
| 159 | + | |
| 160 | +static const struct reg_default apds9960_reg_defaults[] = { | |
| 161 | + /* Default ALS integration time = 2.48ms */ | |
| 162 | + { APDS9960_REG_ATIME, 0xff }, | |
| 163 | +}; | |
| 164 | + | |
| 165 | +static const struct regmap_range apds9960_volatile_ranges[] = { | |
| 166 | + regmap_reg_range(APDS9960_REG_STATUS, | |
| 167 | + APDS9960_REG_PDATA), | |
| 168 | + regmap_reg_range(APDS9960_REG_GFLVL, | |
| 169 | + APDS9960_REG_GSTATUS), | |
| 170 | + regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP), | |
| 171 | + APDS9960_REG_GFIFO_DIR(RIGHT)), | |
| 172 | + regmap_reg_range(APDS9960_REG_IFORCE, | |
| 173 | + APDS9960_REG_AICLEAR), | |
| 174 | +}; | |
| 175 | + | |
| 176 | +static const struct regmap_access_table apds9960_volatile_table = { | |
| 177 | + .yes_ranges = apds9960_volatile_ranges, | |
| 178 | + .n_yes_ranges = ARRAY_SIZE(apds9960_volatile_ranges), | |
| 179 | +}; | |
| 180 | + | |
| 181 | +static const struct regmap_range apds9960_precious_ranges[] = { | |
| 182 | + regmap_reg_range(APDS9960_REG_RAM_START, APDS9960_REG_RAM_END), | |
| 183 | +}; | |
| 184 | + | |
| 185 | +static const struct regmap_access_table apds9960_precious_table = { | |
| 186 | + .yes_ranges = apds9960_precious_ranges, | |
| 187 | + .n_yes_ranges = ARRAY_SIZE(apds9960_precious_ranges), | |
| 188 | +}; | |
| 189 | + | |
| 190 | +static const struct regmap_range apds9960_readable_ranges[] = { | |
| 191 | + regmap_reg_range(APDS9960_REG_ENABLE, | |
| 192 | + APDS9960_REG_GSTATUS), | |
| 193 | + regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP), | |
| 194 | + APDS9960_REG_GFIFO_DIR(RIGHT)), | |
| 195 | +}; | |
| 196 | + | |
| 197 | +static const struct regmap_access_table apds9960_readable_table = { | |
| 198 | + .yes_ranges = apds9960_readable_ranges, | |
| 199 | + .n_yes_ranges = ARRAY_SIZE(apds9960_readable_ranges), | |
| 200 | +}; | |
| 201 | + | |
| 202 | +static const struct regmap_range apds9960_writeable_ranges[] = { | |
| 203 | + regmap_reg_range(APDS9960_REG_ENABLE, APDS9960_REG_CONFIG_2), | |
| 204 | + regmap_reg_range(APDS9960_REG_POFFSET_UR, APDS9960_REG_GCONF_4), | |
| 205 | + regmap_reg_range(APDS9960_REG_IFORCE, APDS9960_REG_AICLEAR), | |
| 206 | +}; | |
| 207 | + | |
| 208 | +static const struct regmap_access_table apds9960_writeable_table = { | |
| 209 | + .yes_ranges = apds9960_writeable_ranges, | |
| 210 | + .n_yes_ranges = ARRAY_SIZE(apds9960_writeable_ranges), | |
| 211 | +}; | |
| 212 | + | |
| 213 | +static const struct regmap_config apds9960_regmap_config = { | |
| 214 | + .name = APDS9960_REGMAP_NAME, | |
| 215 | + .reg_bits = 8, | |
| 216 | + .val_bits = 8, | |
| 217 | + .use_single_rw = 1, | |
| 218 | + | |
| 219 | + .volatile_table = &apds9960_volatile_table, | |
| 220 | + .precious_table = &apds9960_precious_table, | |
| 221 | + .rd_table = &apds9960_readable_table, | |
| 222 | + .wr_table = &apds9960_writeable_table, | |
| 223 | + | |
| 224 | + .reg_defaults = apds9960_reg_defaults, | |
| 225 | + .num_reg_defaults = ARRAY_SIZE(apds9960_reg_defaults), | |
| 226 | + .max_register = APDS9960_REG_GFIFO_DIR(RIGHT), | |
| 227 | + .cache_type = REGCACHE_RBTREE, | |
| 228 | +}; | |
| 229 | + | |
| 230 | +static const struct iio_event_spec apds9960_pxs_event_spec[] = { | |
| 231 | + { | |
| 232 | + .type = IIO_EV_TYPE_THRESH, | |
| 233 | + .dir = IIO_EV_DIR_RISING, | |
| 234 | + .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
| 235 | + BIT(IIO_EV_INFO_ENABLE), | |
| 236 | + }, | |
| 237 | + { | |
| 238 | + .type = IIO_EV_TYPE_THRESH, | |
| 239 | + .dir = IIO_EV_DIR_FALLING, | |
| 240 | + .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
| 241 | + BIT(IIO_EV_INFO_ENABLE), | |
| 242 | + }, | |
| 243 | +}; | |
| 244 | + | |
| 245 | +static const struct iio_event_spec apds9960_als_event_spec[] = { | |
| 246 | + { | |
| 247 | + .type = IIO_EV_TYPE_THRESH, | |
| 248 | + .dir = IIO_EV_DIR_RISING, | |
| 249 | + .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
| 250 | + BIT(IIO_EV_INFO_ENABLE), | |
| 251 | + }, | |
| 252 | + { | |
| 253 | + .type = IIO_EV_TYPE_THRESH, | |
| 254 | + .dir = IIO_EV_DIR_FALLING, | |
| 255 | + .mask_separate = BIT(IIO_EV_INFO_VALUE) | | |
| 256 | + BIT(IIO_EV_INFO_ENABLE), | |
| 257 | + }, | |
| 258 | +}; | |
| 259 | + | |
| 260 | +#define APDS9960_GESTURE_CHANNEL(_dir, _si) { \ | |
| 261 | + .type = IIO_PROXIMITY, \ | |
| 262 | + .channel = _si + 1, \ | |
| 263 | + .scan_index = _si, \ | |
| 264 | + .indexed = 1, \ | |
| 265 | + .scan_type = { \ | |
| 266 | + .sign = 'u', \ | |
| 267 | + .realbits = 8, \ | |
| 268 | + .storagebits = 8, \ | |
| 269 | + }, \ | |
| 270 | +} | |
| 271 | + | |
| 272 | +#define APDS9960_INTENSITY_CHANNEL(_colour) { \ | |
| 273 | + .type = IIO_INTENSITY, \ | |
| 274 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 275 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | |
| 276 | + BIT(IIO_CHAN_INFO_INT_TIME), \ | |
| 277 | + .channel2 = IIO_MOD_LIGHT_##_colour, \ | |
| 278 | + .address = APDS9960_REG_ALS_CHANNEL(_colour), \ | |
| 279 | + .modified = 1, \ | |
| 280 | + .scan_index = -1, \ | |
| 281 | +} | |
| 282 | + | |
| 283 | +static const unsigned long apds9960_scan_masks[] = {0xf, 0}; | |
| 284 | + | |
| 285 | +static const struct iio_chan_spec apds9960_channels[] = { | |
| 286 | + { | |
| 287 | + .type = IIO_PROXIMITY, | |
| 288 | + .address = APDS9960_REG_PDATA, | |
| 289 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| 290 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), | |
| 291 | + .channel = 0, | |
| 292 | + .indexed = 0, | |
| 293 | + .scan_index = -1, | |
| 294 | + | |
| 295 | + .event_spec = apds9960_pxs_event_spec, | |
| 296 | + .num_event_specs = ARRAY_SIZE(apds9960_pxs_event_spec), | |
| 297 | + }, | |
| 298 | + /* Gesture Sensor */ | |
| 299 | + APDS9960_GESTURE_CHANNEL(UP, 0), | |
| 300 | + APDS9960_GESTURE_CHANNEL(DOWN, 1), | |
| 301 | + APDS9960_GESTURE_CHANNEL(LEFT, 2), | |
| 302 | + APDS9960_GESTURE_CHANNEL(RIGHT, 3), | |
| 303 | + /* ALS */ | |
| 304 | + { | |
| 305 | + .type = IIO_INTENSITY, | |
| 306 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| 307 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | | |
| 308 | + BIT(IIO_CHAN_INFO_INT_TIME), | |
| 309 | + .channel2 = IIO_MOD_LIGHT_CLEAR, | |
| 310 | + .address = APDS9960_REG_ALS_CHANNEL(CLEAR), | |
| 311 | + .modified = 1, | |
| 312 | + .scan_index = -1, | |
| 313 | + | |
| 314 | + .event_spec = apds9960_als_event_spec, | |
| 315 | + .num_event_specs = ARRAY_SIZE(apds9960_als_event_spec), | |
| 316 | + }, | |
| 317 | + /* RGB Sensor */ | |
| 318 | + APDS9960_INTENSITY_CHANNEL(RED), | |
| 319 | + APDS9960_INTENSITY_CHANNEL(GREEN), | |
| 320 | + APDS9960_INTENSITY_CHANNEL(BLUE), | |
| 321 | +}; | |
| 322 | + | |
| 323 | +/* integration time in us */ | |
| 324 | +static const int apds9960_int_time[][2] = | |
| 325 | + { {28000, 246}, {100000, 219}, {200000, 182}, {700000, 0} }; | |
| 326 | + | |
| 327 | +/* gain mapping */ | |
| 328 | +static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8}; | |
| 329 | +static const int apds9960_als_gain_map[] = {1, 4, 16, 64}; | |
| 330 | + | |
| 331 | +static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8"); | |
| 332 | +static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64"); | |
| 333 | +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7"); | |
| 334 | + | |
| 335 | +static struct attribute *apds9960_attributes[] = { | |
| 336 | + &iio_const_attr_proximity_scale_available.dev_attr.attr, | |
| 337 | + &iio_const_attr_intensity_scale_available.dev_attr.attr, | |
| 338 | + &iio_const_attr_integration_time_available.dev_attr.attr, | |
| 339 | + NULL, | |
| 340 | +}; | |
| 341 | + | |
| 342 | +static struct attribute_group apds9960_attribute_group = { | |
| 343 | + .attrs = apds9960_attributes, | |
| 344 | +}; | |
| 345 | + | |
| 346 | +static const struct reg_field apds9960_reg_field_int_als = | |
| 347 | + REG_FIELD(APDS9960_REG_ENABLE, 4, 4); | |
| 348 | + | |
| 349 | +static const struct reg_field apds9960_reg_field_int_ges = | |
| 350 | + REG_FIELD(APDS9960_REG_GCONF_4, 1, 1); | |
| 351 | + | |
| 352 | +static const struct reg_field apds9960_reg_field_int_pxs = | |
| 353 | + REG_FIELD(APDS9960_REG_ENABLE, 5, 5); | |
| 354 | + | |
| 355 | +static const struct reg_field apds9960_reg_field_enable_als = | |
| 356 | + REG_FIELD(APDS9960_REG_ENABLE, 1, 1); | |
| 357 | + | |
| 358 | +static const struct reg_field apds9960_reg_field_enable_ges = | |
| 359 | + REG_FIELD(APDS9960_REG_ENABLE, 6, 6); | |
| 360 | + | |
| 361 | +static const struct reg_field apds9960_reg_field_enable_pxs = | |
| 362 | + REG_FIELD(APDS9960_REG_ENABLE, 2, 2); | |
| 363 | + | |
| 364 | +static int apds9960_set_it_time(struct apds9960_data *data, int val2) | |
| 365 | +{ | |
| 366 | + int ret = -EINVAL; | |
| 367 | + int idx; | |
| 368 | + | |
| 369 | + for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) { | |
| 370 | + if (apds9960_int_time[idx][0] == val2) { | |
| 371 | + mutex_lock(&data->lock); | |
| 372 | + ret = regmap_write(data->regmap, APDS9960_REG_ATIME, | |
| 373 | + apds9960_int_time[idx][1]); | |
| 374 | + if (!ret) | |
| 375 | + data->als_adc_int_us = val2; | |
| 376 | + mutex_unlock(&data->lock); | |
| 377 | + break; | |
| 378 | + } | |
| 379 | + } | |
| 380 | + | |
| 381 | + return ret; | |
| 382 | +} | |
| 383 | + | |
| 384 | +static int apds9960_set_pxs_gain(struct apds9960_data *data, int val) | |
| 385 | +{ | |
| 386 | + int ret = -EINVAL; | |
| 387 | + int idx; | |
| 388 | + | |
| 389 | + for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) { | |
| 390 | + if (apds9960_pxs_gain_map[idx] == val) { | |
| 391 | + /* pxs + gesture gains are mirrored */ | |
| 392 | + mutex_lock(&data->lock); | |
| 393 | + ret = regmap_update_bits(data->regmap, | |
| 394 | + APDS9960_REG_CONTROL, | |
| 395 | + APDS9960_REG_CONTROL_PGAIN_MASK, | |
| 396 | + idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT); | |
| 397 | + if (ret) { | |
| 398 | + mutex_unlock(&data->lock); | |
| 399 | + break; | |
| 400 | + } | |
| 401 | + | |
| 402 | + ret = regmap_update_bits(data->regmap, | |
| 403 | + APDS9960_REG_CONFIG_2, | |
| 404 | + APDS9960_REG_CONFIG_2_GGAIN_MASK, | |
| 405 | + idx << APDS9960_REG_CONFIG_2_GGAIN_MASK_SHIFT); | |
| 406 | + if (!ret) | |
| 407 | + data->pxs_gain = idx; | |
| 408 | + mutex_unlock(&data->lock); | |
| 409 | + break; | |
| 410 | + } | |
| 411 | + } | |
| 412 | + | |
| 413 | + return ret; | |
| 414 | +} | |
| 415 | + | |
| 416 | +static int apds9960_set_als_gain(struct apds9960_data *data, int val) | |
| 417 | +{ | |
| 418 | + int ret = -EINVAL; | |
| 419 | + int idx; | |
| 420 | + | |
| 421 | + for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) { | |
| 422 | + if (apds9960_als_gain_map[idx] == val) { | |
| 423 | + mutex_lock(&data->lock); | |
| 424 | + ret = regmap_update_bits(data->regmap, | |
| 425 | + APDS9960_REG_CONTROL, | |
| 426 | + APDS9960_REG_CONTROL_AGAIN_MASK, idx); | |
| 427 | + if (!ret) | |
| 428 | + data->als_gain = idx; | |
| 429 | + mutex_unlock(&data->lock); | |
| 430 | + break; | |
| 431 | + } | |
| 432 | + } | |
| 433 | + | |
| 434 | + return ret; | |
| 435 | +} | |
| 436 | + | |
| 437 | +#ifdef CONFIG_PM | |
| 438 | +static int apds9960_set_power_state(struct apds9960_data *data, bool on) | |
| 439 | +{ | |
| 440 | + struct device *dev = &data->client->dev; | |
| 441 | + int ret = 0; | |
| 442 | + | |
| 443 | + mutex_lock(&data->lock); | |
| 444 | + | |
| 445 | + if (on) { | |
| 446 | + int suspended; | |
| 447 | + | |
| 448 | + suspended = pm_runtime_suspended(dev); | |
| 449 | + ret = pm_runtime_get_sync(dev); | |
| 450 | + | |
| 451 | + /* Allow one integration cycle before allowing a reading */ | |
| 452 | + if (suspended) | |
| 453 | + usleep_range(data->als_adc_int_us, | |
| 454 | + APDS9960_MAX_INT_TIME_IN_US); | |
| 455 | + } else { | |
| 456 | + ret = pm_runtime_put_autosuspend(dev); | |
| 457 | + } | |
| 458 | + | |
| 459 | + mutex_unlock(&data->lock); | |
| 460 | + | |
| 461 | + return ret; | |
| 462 | +} | |
| 463 | +#else | |
| 464 | +static int apds9960_set_power_state(struct apds9960_data *data, bool on) | |
| 465 | +{ | |
| 466 | + return 0; | |
| 467 | +} | |
| 468 | +#endif | |
| 469 | + | |
| 470 | +static int apds9960_read_raw(struct iio_dev *indio_dev, | |
| 471 | + struct iio_chan_spec const *chan, | |
| 472 | + int *val, int *val2, long mask) | |
| 473 | +{ | |
| 474 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 475 | + __le16 buf; | |
| 476 | + int ret = -EINVAL; | |
| 477 | + | |
| 478 | + if (data->gesture_mode_running) | |
| 479 | + return -EBUSY; | |
| 480 | + | |
| 481 | + switch (mask) { | |
| 482 | + case IIO_CHAN_INFO_RAW: | |
| 483 | + apds9960_set_power_state(data, true); | |
| 484 | + switch (chan->type) { | |
| 485 | + case IIO_PROXIMITY: | |
| 486 | + ret = regmap_read(data->regmap, chan->address, val); | |
| 487 | + if (!ret) | |
| 488 | + ret = IIO_VAL_INT; | |
| 489 | + break; | |
| 490 | + case IIO_INTENSITY: | |
| 491 | + ret = regmap_bulk_read(data->regmap, chan->address, | |
| 492 | + &buf, 2); | |
| 493 | + if (!ret) | |
| 494 | + ret = IIO_VAL_INT; | |
| 495 | + *val = le16_to_cpu(buf); | |
| 496 | + break; | |
| 497 | + default: | |
| 498 | + ret = -EINVAL; | |
| 499 | + } | |
| 500 | + apds9960_set_power_state(data, false); | |
| 501 | + break; | |
| 502 | + case IIO_CHAN_INFO_INT_TIME: | |
| 503 | + /* RGB + ALS sensors only have integration time */ | |
| 504 | + mutex_lock(&data->lock); | |
| 505 | + switch (chan->type) { | |
| 506 | + case IIO_INTENSITY: | |
| 507 | + *val = 0; | |
| 508 | + *val2 = data->als_adc_int_us; | |
| 509 | + ret = IIO_VAL_INT_PLUS_MICRO; | |
| 510 | + break; | |
| 511 | + default: | |
| 512 | + ret = -EINVAL; | |
| 513 | + } | |
| 514 | + mutex_unlock(&data->lock); | |
| 515 | + break; | |
| 516 | + case IIO_CHAN_INFO_SCALE: | |
| 517 | + mutex_lock(&data->lock); | |
| 518 | + switch (chan->type) { | |
| 519 | + case IIO_PROXIMITY: | |
| 520 | + *val = apds9960_pxs_gain_map[data->pxs_gain]; | |
| 521 | + ret = IIO_VAL_INT; | |
| 522 | + break; | |
| 523 | + case IIO_INTENSITY: | |
| 524 | + *val = apds9960_als_gain_map[data->als_gain]; | |
| 525 | + ret = IIO_VAL_INT; | |
| 526 | + break; | |
| 527 | + default: | |
| 528 | + ret = -EINVAL; | |
| 529 | + } | |
| 530 | + mutex_unlock(&data->lock); | |
| 531 | + break; | |
| 532 | + } | |
| 533 | + | |
| 534 | + return ret; | |
| 535 | +}; | |
| 536 | + | |
| 537 | +static int apds9960_write_raw(struct iio_dev *indio_dev, | |
| 538 | + struct iio_chan_spec const *chan, | |
| 539 | + int val, int val2, long mask) | |
| 540 | +{ | |
| 541 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 542 | + | |
| 543 | + switch (mask) { | |
| 544 | + case IIO_CHAN_INFO_INT_TIME: | |
| 545 | + /* RGB + ALS sensors only have int time */ | |
| 546 | + switch (chan->type) { | |
| 547 | + case IIO_INTENSITY: | |
| 548 | + if (val != 0) | |
| 549 | + return -EINVAL; | |
| 550 | + return apds9960_set_it_time(data, val2); | |
| 551 | + default: | |
| 552 | + return -EINVAL; | |
| 553 | + } | |
| 554 | + case IIO_CHAN_INFO_SCALE: | |
| 555 | + if (val2 != 0) | |
| 556 | + return -EINVAL; | |
| 557 | + switch (chan->type) { | |
| 558 | + case IIO_PROXIMITY: | |
| 559 | + return apds9960_set_pxs_gain(data, val); | |
| 560 | + case IIO_INTENSITY: | |
| 561 | + return apds9960_set_als_gain(data, val); | |
| 562 | + default: | |
| 563 | + return -EINVAL; | |
| 564 | + } | |
| 565 | + default: | |
| 566 | + return -EINVAL; | |
| 567 | + }; | |
| 568 | + | |
| 569 | + return 0; | |
| 570 | +} | |
| 571 | + | |
| 572 | +static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan, | |
| 573 | + enum iio_event_direction dir, | |
| 574 | + u8 *reg) | |
| 575 | +{ | |
| 576 | + switch (dir) { | |
| 577 | + case IIO_EV_DIR_RISING: | |
| 578 | + switch (chan->type) { | |
| 579 | + case IIO_PROXIMITY: | |
| 580 | + *reg = APDS9960_REG_PIHT; | |
| 581 | + break; | |
| 582 | + case IIO_INTENSITY: | |
| 583 | + *reg = APDS9960_REG_AIHTL; | |
| 584 | + break; | |
| 585 | + default: | |
| 586 | + return -EINVAL; | |
| 587 | + } | |
| 588 | + break; | |
| 589 | + case IIO_EV_DIR_FALLING: | |
| 590 | + switch (chan->type) { | |
| 591 | + case IIO_PROXIMITY: | |
| 592 | + *reg = APDS9960_REG_PILT; | |
| 593 | + break; | |
| 594 | + case IIO_INTENSITY: | |
| 595 | + *reg = APDS9960_REG_AILTL; | |
| 596 | + break; | |
| 597 | + default: | |
| 598 | + return -EINVAL; | |
| 599 | + } | |
| 600 | + break; | |
| 601 | + default: | |
| 602 | + return -EINVAL; | |
| 603 | + } | |
| 604 | + | |
| 605 | + return 0; | |
| 606 | +} | |
| 607 | + | |
| 608 | +static int apds9960_read_event(struct iio_dev *indio_dev, | |
| 609 | + const struct iio_chan_spec *chan, | |
| 610 | + enum iio_event_type type, | |
| 611 | + enum iio_event_direction dir, | |
| 612 | + enum iio_event_info info, | |
| 613 | + int *val, int *val2) | |
| 614 | +{ | |
| 615 | + u8 reg; | |
| 616 | + __le16 buf; | |
| 617 | + int ret = 0; | |
| 618 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 619 | + | |
| 620 | + if (info != IIO_EV_INFO_VALUE) | |
| 621 | + return -EINVAL; | |
| 622 | + | |
| 623 | + ret = apds9960_get_thres_reg(chan, dir, ®); | |
| 624 | + if (ret < 0) | |
| 625 | + return ret; | |
| 626 | + | |
| 627 | + if (chan->type == IIO_PROXIMITY) { | |
| 628 | + ret = regmap_read(data->regmap, reg, val); | |
| 629 | + if (ret < 0) | |
| 630 | + return ret; | |
| 631 | + } else if (chan->type == IIO_INTENSITY) { | |
| 632 | + ret = regmap_bulk_read(data->regmap, reg, &buf, 2); | |
| 633 | + if (ret < 0) | |
| 634 | + return ret; | |
| 635 | + *val = le16_to_cpu(buf); | |
| 636 | + } else | |
| 637 | + return -EINVAL; | |
| 638 | + | |
| 639 | + *val2 = 0; | |
| 640 | + | |
| 641 | + return IIO_VAL_INT; | |
| 642 | +} | |
| 643 | + | |
| 644 | +static int apds9960_write_event(struct iio_dev *indio_dev, | |
| 645 | + const struct iio_chan_spec *chan, | |
| 646 | + enum iio_event_type type, | |
| 647 | + enum iio_event_direction dir, | |
| 648 | + enum iio_event_info info, | |
| 649 | + int val, int val2) | |
| 650 | +{ | |
| 651 | + u8 reg; | |
| 652 | + __le16 buf; | |
| 653 | + int ret = 0; | |
| 654 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 655 | + | |
| 656 | + if (info != IIO_EV_INFO_VALUE) | |
| 657 | + return -EINVAL; | |
| 658 | + | |
| 659 | + ret = apds9960_get_thres_reg(chan, dir, ®); | |
| 660 | + if (ret < 0) | |
| 661 | + return ret; | |
| 662 | + | |
| 663 | + if (chan->type == IIO_PROXIMITY) { | |
| 664 | + if (val < 0 || val > APDS9960_MAX_PXS_THRES_VAL) | |
| 665 | + return -EINVAL; | |
| 666 | + ret = regmap_write(data->regmap, reg, val); | |
| 667 | + if (ret < 0) | |
| 668 | + return ret; | |
| 669 | + } else if (chan->type == IIO_INTENSITY) { | |
| 670 | + if (val < 0 || val > APDS9960_MAX_ALS_THRES_VAL) | |
| 671 | + return -EINVAL; | |
| 672 | + buf = cpu_to_le16(val); | |
| 673 | + ret = regmap_bulk_write(data->regmap, reg, &buf, 2); | |
| 674 | + if (ret < 0) | |
| 675 | + return ret; | |
| 676 | + } else | |
| 677 | + return -EINVAL; | |
| 678 | + | |
| 679 | + return 0; | |
| 680 | +} | |
| 681 | + | |
| 682 | +static int apds9960_read_event_config(struct iio_dev *indio_dev, | |
| 683 | + const struct iio_chan_spec *chan, | |
| 684 | + enum iio_event_type type, | |
| 685 | + enum iio_event_direction dir) | |
| 686 | +{ | |
| 687 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 688 | + | |
| 689 | + switch (chan->type) { | |
| 690 | + case IIO_PROXIMITY: | |
| 691 | + return data->pxs_int; | |
| 692 | + case IIO_INTENSITY: | |
| 693 | + return data->als_int; | |
| 694 | + default: | |
| 695 | + return -EINVAL; | |
| 696 | + } | |
| 697 | + | |
| 698 | + return 0; | |
| 699 | +} | |
| 700 | + | |
| 701 | +static int apds9960_write_event_config(struct iio_dev *indio_dev, | |
| 702 | + const struct iio_chan_spec *chan, | |
| 703 | + enum iio_event_type type, | |
| 704 | + enum iio_event_direction dir, | |
| 705 | + int state) | |
| 706 | +{ | |
| 707 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 708 | + int ret; | |
| 709 | + | |
| 710 | + state = !!state; | |
| 711 | + | |
| 712 | + switch (chan->type) { | |
| 713 | + case IIO_PROXIMITY: | |
| 714 | + if (data->pxs_int == state) | |
| 715 | + return -EINVAL; | |
| 716 | + | |
| 717 | + ret = regmap_field_write(data->reg_int_pxs, state); | |
| 718 | + if (ret) | |
| 719 | + return ret; | |
| 720 | + data->pxs_int = state; | |
| 721 | + apds9960_set_power_state(data, state); | |
| 722 | + break; | |
| 723 | + case IIO_INTENSITY: | |
| 724 | + if (data->als_int == state) | |
| 725 | + return -EINVAL; | |
| 726 | + | |
| 727 | + ret = regmap_field_write(data->reg_int_als, state); | |
| 728 | + if (ret) | |
| 729 | + return ret; | |
| 730 | + data->als_int = state; | |
| 731 | + apds9960_set_power_state(data, state); | |
| 732 | + break; | |
| 733 | + default: | |
| 734 | + return -EINVAL; | |
| 735 | + } | |
| 736 | + | |
| 737 | + return 0; | |
| 738 | +} | |
| 739 | + | |
| 740 | +static const struct iio_info apds9960_info = { | |
| 741 | + .driver_module = THIS_MODULE, | |
| 742 | + .attrs = &apds9960_attribute_group, | |
| 743 | + .read_raw = apds9960_read_raw, | |
| 744 | + .write_raw = apds9960_write_raw, | |
| 745 | + .read_event_value = apds9960_read_event, | |
| 746 | + .write_event_value = apds9960_write_event, | |
| 747 | + .read_event_config = apds9960_read_event_config, | |
| 748 | + .write_event_config = apds9960_write_event_config, | |
| 749 | + | |
| 750 | +}; | |
| 751 | + | |
| 752 | +static inline int apds9660_fifo_is_empty(struct apds9960_data *data) | |
| 753 | +{ | |
| 754 | + int cnt; | |
| 755 | + int ret; | |
| 756 | + | |
| 757 | + ret = regmap_read(data->regmap, APDS9960_REG_GFLVL, &cnt); | |
| 758 | + if (ret) | |
| 759 | + return ret; | |
| 760 | + | |
| 761 | + return cnt; | |
| 762 | +} | |
| 763 | + | |
| 764 | +static void apds9960_read_gesture_fifo(struct apds9960_data *data) | |
| 765 | +{ | |
| 766 | + int ret, cnt = 0; | |
| 767 | + | |
| 768 | + mutex_lock(&data->lock); | |
| 769 | + data->gesture_mode_running = 1; | |
| 770 | + | |
| 771 | + while (cnt-- || (cnt = apds9660_fifo_is_empty(data) > 0)) { | |
| 772 | + ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE, | |
| 773 | + &data->buffer, 4); | |
| 774 | + | |
| 775 | + if (ret) | |
| 776 | + goto err_read; | |
| 777 | + | |
| 778 | + iio_push_to_buffers(data->indio_dev, data->buffer); | |
| 779 | + } | |
| 780 | + | |
| 781 | +err_read: | |
| 782 | + data->gesture_mode_running = 0; | |
| 783 | + mutex_unlock(&data->lock); | |
| 784 | +} | |
| 785 | + | |
| 786 | +static irqreturn_t apds9960_interrupt_handler(int irq, void *private) | |
| 787 | +{ | |
| 788 | + struct iio_dev *indio_dev = private; | |
| 789 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 790 | + int ret, status; | |
| 791 | + | |
| 792 | + ret = regmap_read(data->regmap, APDS9960_REG_STATUS, &status); | |
| 793 | + if (ret < 0) { | |
| 794 | + dev_err(&data->client->dev, "irq status reg read failed\n"); | |
| 795 | + return IRQ_HANDLED; | |
| 796 | + } | |
| 797 | + | |
| 798 | + if ((status & APDS9960_REG_STATUS_ALS_INT) && data->als_int) { | |
| 799 | + iio_push_event(indio_dev, | |
| 800 | + IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0, | |
| 801 | + IIO_EV_TYPE_THRESH, | |
| 802 | + IIO_EV_DIR_EITHER), | |
| 803 | + iio_get_time_ns()); | |
| 804 | + regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1); | |
| 805 | + } | |
| 806 | + | |
| 807 | + if ((status & APDS9960_REG_STATUS_PS_INT) && data->pxs_int) { | |
| 808 | + iio_push_event(indio_dev, | |
| 809 | + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, | |
| 810 | + IIO_EV_TYPE_THRESH, | |
| 811 | + IIO_EV_DIR_EITHER), | |
| 812 | + iio_get_time_ns()); | |
| 813 | + regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1); | |
| 814 | + } | |
| 815 | + | |
| 816 | + if (status & APDS9960_REG_STATUS_GINT) | |
| 817 | + apds9960_read_gesture_fifo(data); | |
| 818 | + | |
| 819 | + return IRQ_HANDLED; | |
| 820 | +} | |
| 821 | + | |
| 822 | +static int apds9960_set_powermode(struct apds9960_data *data, bool state) | |
| 823 | +{ | |
| 824 | + return regmap_update_bits(data->regmap, APDS9960_REG_ENABLE, 1, state); | |
| 825 | +} | |
| 826 | + | |
| 827 | +static int apds9960_buffer_postenable(struct iio_dev *indio_dev) | |
| 828 | +{ | |
| 829 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 830 | + int ret; | |
| 831 | + | |
| 832 | + ret = regmap_field_write(data->reg_int_ges, 1); | |
| 833 | + if (ret) | |
| 834 | + return ret; | |
| 835 | + | |
| 836 | + ret = regmap_field_write(data->reg_enable_ges, 1); | |
| 837 | + if (ret) | |
| 838 | + return ret; | |
| 839 | + | |
| 840 | + pm_runtime_get_sync(&data->client->dev); | |
| 841 | + | |
| 842 | + return 0; | |
| 843 | +} | |
| 844 | + | |
| 845 | +static int apds9960_buffer_predisable(struct iio_dev *indio_dev) | |
| 846 | +{ | |
| 847 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 848 | + int ret; | |
| 849 | + | |
| 850 | + ret = regmap_field_write(data->reg_enable_ges, 0); | |
| 851 | + if (ret) | |
| 852 | + return ret; | |
| 853 | + | |
| 854 | + ret = regmap_field_write(data->reg_int_ges, 0); | |
| 855 | + if (ret) | |
| 856 | + return ret; | |
| 857 | + | |
| 858 | + pm_runtime_put_autosuspend(&data->client->dev); | |
| 859 | + | |
| 860 | + return 0; | |
| 861 | +} | |
| 862 | + | |
| 863 | +static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops = { | |
| 864 | + .postenable = apds9960_buffer_postenable, | |
| 865 | + .predisable = apds9960_buffer_predisable, | |
| 866 | +}; | |
| 867 | + | |
| 868 | +static int apds9960_regfield_init(struct apds9960_data *data) | |
| 869 | +{ | |
| 870 | + struct device *dev = &data->client->dev; | |
| 871 | + struct regmap *regmap = data->regmap; | |
| 872 | + | |
| 873 | + data->reg_int_als = devm_regmap_field_alloc(dev, regmap, | |
| 874 | + apds9960_reg_field_int_als); | |
| 875 | + if (IS_ERR(data->reg_int_als)) { | |
| 876 | + dev_err(dev, "INT ALS reg field init failed\n"); | |
| 877 | + return PTR_ERR(data->reg_int_als); | |
| 878 | + } | |
| 879 | + | |
| 880 | + data->reg_int_ges = devm_regmap_field_alloc(dev, regmap, | |
| 881 | + apds9960_reg_field_int_ges); | |
| 882 | + if (IS_ERR(data->reg_int_ges)) { | |
| 883 | + dev_err(dev, "INT gesture reg field init failed\n"); | |
| 884 | + return PTR_ERR(data->reg_int_ges); | |
| 885 | + } | |
| 886 | + | |
| 887 | + data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap, | |
| 888 | + apds9960_reg_field_int_pxs); | |
| 889 | + if (IS_ERR(data->reg_int_pxs)) { | |
| 890 | + dev_err(dev, "INT pxs reg field init failed\n"); | |
| 891 | + return PTR_ERR(data->reg_int_pxs); | |
| 892 | + } | |
| 893 | + | |
| 894 | + data->reg_enable_als = devm_regmap_field_alloc(dev, regmap, | |
| 895 | + apds9960_reg_field_enable_als); | |
| 896 | + if (IS_ERR(data->reg_enable_als)) { | |
| 897 | + dev_err(dev, "Enable ALS reg field init failed\n"); | |
| 898 | + return PTR_ERR(data->reg_enable_als); | |
| 899 | + } | |
| 900 | + | |
| 901 | + data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap, | |
| 902 | + apds9960_reg_field_enable_ges); | |
| 903 | + if (IS_ERR(data->reg_enable_ges)) { | |
| 904 | + dev_err(dev, "Enable gesture reg field init failed\n"); | |
| 905 | + return PTR_ERR(data->reg_enable_ges); | |
| 906 | + } | |
| 907 | + | |
| 908 | + data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap, | |
| 909 | + apds9960_reg_field_enable_pxs); | |
| 910 | + if (IS_ERR(data->reg_enable_pxs)) { | |
| 911 | + dev_err(dev, "Enable PXS reg field init failed\n"); | |
| 912 | + return PTR_ERR(data->reg_enable_pxs); | |
| 913 | + } | |
| 914 | + | |
| 915 | + return 0; | |
| 916 | +} | |
| 917 | + | |
| 918 | +static int apds9960_chip_init(struct apds9960_data *data) | |
| 919 | +{ | |
| 920 | + int ret; | |
| 921 | + | |
| 922 | + /* Default IT for ALS of 28 ms */ | |
| 923 | + ret = apds9960_set_it_time(data, 28000); | |
| 924 | + if (ret) | |
| 925 | + return ret; | |
| 926 | + | |
| 927 | + /* Ensure gesture interrupt is OFF */ | |
| 928 | + ret = regmap_field_write(data->reg_int_ges, 0); | |
| 929 | + if (ret) | |
| 930 | + return ret; | |
| 931 | + | |
| 932 | + /* Disable gesture sensor, since polling is useless from user-space */ | |
| 933 | + ret = regmap_field_write(data->reg_enable_ges, 0); | |
| 934 | + if (ret) | |
| 935 | + return ret; | |
| 936 | + | |
| 937 | + /* Ensure proximity interrupt is OFF */ | |
| 938 | + ret = regmap_field_write(data->reg_int_pxs, 0); | |
| 939 | + if (ret) | |
| 940 | + return ret; | |
| 941 | + | |
| 942 | + /* Enable proximity sensor for polling */ | |
| 943 | + ret = regmap_field_write(data->reg_enable_pxs, 1); | |
| 944 | + if (ret) | |
| 945 | + return ret; | |
| 946 | + | |
| 947 | + /* Ensure ALS interrupt is OFF */ | |
| 948 | + ret = regmap_field_write(data->reg_int_als, 0); | |
| 949 | + if (ret) | |
| 950 | + return ret; | |
| 951 | + | |
| 952 | + /* Enable ALS sensor for polling */ | |
| 953 | + ret = regmap_field_write(data->reg_enable_als, 1); | |
| 954 | + if (ret) | |
| 955 | + return ret; | |
| 956 | + /* | |
| 957 | + * When enabled trigger an interrupt after 3 readings | |
| 958 | + * outside threshold for ALS + PXS | |
| 959 | + */ | |
| 960 | + ret = regmap_write(data->regmap, APDS9960_REG_PERS, | |
| 961 | + APDS9960_DEFAULT_PERS); | |
| 962 | + if (ret) | |
| 963 | + return ret; | |
| 964 | + | |
| 965 | + /* | |
| 966 | + * Wait for 4 event outside gesture threshold to prevent interrupt | |
| 967 | + * flooding. | |
| 968 | + */ | |
| 969 | + ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1, | |
| 970 | + APDS9960_REG_GCONF_1_GFIFO_THRES_MASK, | |
| 971 | + BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT); | |
| 972 | + if (ret) | |
| 973 | + return ret; | |
| 974 | + | |
| 975 | + /* Default ENTER and EXIT thresholds for the GESTURE engine. */ | |
| 976 | + ret = regmap_write(data->regmap, APDS9960_REG_GPENTH, | |
| 977 | + APDS9960_DEFAULT_GPENTH); | |
| 978 | + if (ret) | |
| 979 | + return ret; | |
| 980 | + | |
| 981 | + ret = regmap_write(data->regmap, APDS9960_REG_GEXTH, | |
| 982 | + APDS9960_DEFAULT_GEXTH); | |
| 983 | + if (ret) | |
| 984 | + return ret; | |
| 985 | + | |
| 986 | + return apds9960_set_powermode(data, 1); | |
| 987 | +} | |
| 988 | + | |
| 989 | +static int apds9960_probe(struct i2c_client *client, | |
| 990 | + const struct i2c_device_id *id) | |
| 991 | +{ | |
| 992 | + struct apds9960_data *data; | |
| 993 | + struct iio_buffer *buffer; | |
| 994 | + struct iio_dev *indio_dev; | |
| 995 | + int ret; | |
| 996 | + | |
| 997 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 998 | + if (!indio_dev) | |
| 999 | + return -ENOMEM; | |
| 1000 | + | |
| 1001 | + buffer = devm_iio_kfifo_allocate(&client->dev); | |
| 1002 | + if (!buffer) | |
| 1003 | + return -ENOMEM; | |
| 1004 | + | |
| 1005 | + iio_device_attach_buffer(indio_dev, buffer); | |
| 1006 | + | |
| 1007 | + indio_dev->info = &apds9960_info; | |
| 1008 | + indio_dev->name = APDS9960_DRV_NAME; | |
| 1009 | + indio_dev->channels = apds9960_channels; | |
| 1010 | + indio_dev->num_channels = ARRAY_SIZE(apds9960_channels); | |
| 1011 | + indio_dev->available_scan_masks = apds9960_scan_masks; | |
| 1012 | + indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE); | |
| 1013 | + indio_dev->setup_ops = &apds9960_buffer_setup_ops; | |
| 1014 | + | |
| 1015 | + data = iio_priv(indio_dev); | |
| 1016 | + i2c_set_clientdata(client, indio_dev); | |
| 1017 | + | |
| 1018 | + data->regmap = devm_regmap_init_i2c(client, &apds9960_regmap_config); | |
| 1019 | + if (IS_ERR(data->regmap)) { | |
| 1020 | + dev_err(&client->dev, "regmap initialization failed.\n"); | |
| 1021 | + return PTR_ERR(data->regmap); | |
| 1022 | + } | |
| 1023 | + | |
| 1024 | + data->client = client; | |
| 1025 | + data->indio_dev = indio_dev; | |
| 1026 | + mutex_init(&data->lock); | |
| 1027 | + | |
| 1028 | + ret = pm_runtime_set_active(&client->dev); | |
| 1029 | + if (ret) | |
| 1030 | + goto error_power_down; | |
| 1031 | + | |
| 1032 | + pm_runtime_enable(&client->dev); | |
| 1033 | + pm_runtime_set_autosuspend_delay(&client->dev, 5000); | |
| 1034 | + pm_runtime_use_autosuspend(&client->dev); | |
| 1035 | + | |
| 1036 | + apds9960_set_power_state(data, true); | |
| 1037 | + | |
| 1038 | + ret = apds9960_regfield_init(data); | |
| 1039 | + if (ret) | |
| 1040 | + goto error_power_down; | |
| 1041 | + | |
| 1042 | + ret = apds9960_chip_init(data); | |
| 1043 | + if (ret) | |
| 1044 | + goto error_power_down; | |
| 1045 | + | |
| 1046 | + if (client->irq <= 0) { | |
| 1047 | + dev_err(&client->dev, "no valid irq defined\n"); | |
| 1048 | + ret = -EINVAL; | |
| 1049 | + goto error_power_down; | |
| 1050 | + } | |
| 1051 | + ret = devm_request_threaded_irq(&client->dev, client->irq, | |
| 1052 | + NULL, apds9960_interrupt_handler, | |
| 1053 | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | |
| 1054 | + "apds9960_event", | |
| 1055 | + indio_dev); | |
| 1056 | + if (ret) { | |
| 1057 | + dev_err(&client->dev, "request irq (%d) failed\n", client->irq); | |
| 1058 | + goto error_power_down; | |
| 1059 | + } | |
| 1060 | + | |
| 1061 | + ret = iio_device_register(indio_dev); | |
| 1062 | + if (ret) | |
| 1063 | + goto error_power_down; | |
| 1064 | + | |
| 1065 | + apds9960_set_power_state(data, false); | |
| 1066 | + | |
| 1067 | + return 0; | |
| 1068 | + | |
| 1069 | +error_power_down: | |
| 1070 | + apds9960_set_power_state(data, false); | |
| 1071 | + | |
| 1072 | + return ret; | |
| 1073 | +} | |
| 1074 | + | |
| 1075 | +static int apds9960_remove(struct i2c_client *client) | |
| 1076 | +{ | |
| 1077 | + struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
| 1078 | + struct apds9960_data *data = iio_priv(indio_dev); | |
| 1079 | + | |
| 1080 | + iio_device_unregister(indio_dev); | |
| 1081 | + pm_runtime_disable(&client->dev); | |
| 1082 | + pm_runtime_set_suspended(&client->dev); | |
| 1083 | + apds9960_set_powermode(data, 0); | |
| 1084 | + | |
| 1085 | + return 0; | |
| 1086 | +} | |
| 1087 | + | |
| 1088 | +#ifdef CONFIG_PM | |
| 1089 | +static int apds9960_runtime_suspend(struct device *dev) | |
| 1090 | +{ | |
| 1091 | + struct apds9960_data *data = | |
| 1092 | + iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
| 1093 | + | |
| 1094 | + return apds9960_set_powermode(data, 0); | |
| 1095 | +} | |
| 1096 | + | |
| 1097 | +static int apds9960_runtime_resume(struct device *dev) | |
| 1098 | +{ | |
| 1099 | + struct apds9960_data *data = | |
| 1100 | + iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
| 1101 | + | |
| 1102 | + return apds9960_set_powermode(data, 1); | |
| 1103 | +} | |
| 1104 | +#endif | |
| 1105 | + | |
| 1106 | +static const struct dev_pm_ops apds9960_pm_ops = { | |
| 1107 | + SET_RUNTIME_PM_OPS(apds9960_runtime_suspend, | |
| 1108 | + apds9960_runtime_resume, NULL) | |
| 1109 | +}; | |
| 1110 | + | |
| 1111 | +static const struct i2c_device_id apds9960_id[] = { | |
| 1112 | + { "apds9960", 0 }, | |
| 1113 | + {} | |
| 1114 | +}; | |
| 1115 | +MODULE_DEVICE_TABLE(i2c, apds9960_id); | |
| 1116 | + | |
| 1117 | +static struct i2c_driver apds9960_driver = { | |
| 1118 | + .driver = { | |
| 1119 | + .name = APDS9960_DRV_NAME, | |
| 1120 | + .pm = &apds9960_pm_ops, | |
| 1121 | + }, | |
| 1122 | + .probe = apds9960_probe, | |
| 1123 | + .remove = apds9960_remove, | |
| 1124 | + .id_table = apds9960_id, | |
| 1125 | +}; | |
| 1126 | +module_i2c_driver(apds9960_driver); | |
| 1127 | + | |
| 1128 | +MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); | |
| 1129 | +MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor"); | |
| 1130 | +MODULE_LICENSE("GPL"); | |
| @@ -793,7 +793,6 @@ static struct i2c_driver opt3001_driver = { · 792 unmodified lines | ||
| 793 | 793 | .driver = { |
| 794 | 794 | .name = "opt3001", |
| 795 | 795 | .of_match_table = of_match_ptr(opt3001_of_match), |
| 796 | − .owner = THIS_MODULE, | |
| 797 | 796 | }, |
| 798 | 797 | }; |
| 799 | 798 | |
| @@ -35,8 +35,8 @@ · 34 unmodified lines | ||
| 35 | 35 | #define STK3310_REG_ID 0x3E |
| 36 | 36 | #define STK3310_MAX_REG 0x80 |
| 37 | 37 | |
| 38 | −#define STK3310_STATE_EN_PS 0x01 | |
| 39 | −#define STK3310_STATE_EN_ALS 0x02 | |
| 38 | +#define STK3310_STATE_EN_PS BIT(0) | |
| 39 | +#define STK3310_STATE_EN_ALS BIT(1) | |
| 40 | 40 | #define STK3310_STATE_STANDBY 0x00 |
| 41 | 41 | |
| 42 | 42 | #define STK3310_CHIP_ID_VAL 0x13 |
| @@ -47,7 +47,6 @@ · 4 unmodified lines | ||
| 47 | 47 | #define STK3310_DRIVER_NAME "stk3310" |
| 48 | 48 | #define STK3310_REGMAP_NAME "stk3310_regmap" |
| 49 | 49 | #define STK3310_EVENT "stk3310_event" |
| 50 | −#define STK3310_GPIO "stk3310_gpio" | |
| 51 | 50 | |
| 52 | 51 | #define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1" |
| 53 | 52 | |
| @@ -241,8 +240,11 @@ static int stk3310_write_event(struct iio_dev *indio_dev, · 187 unmodified lines | ||
| 241 | 240 | struct stk3310_data *data = iio_priv(indio_dev); |
| 242 | 241 | struct i2c_client *client = data->client; |
| 243 | 242 | |
| 244 | − regmap_field_read(data->reg_ps_gain, &index); | |
| 245 | − if (val > stk3310_ps_max[index]) | |
| 243 | + ret = regmap_field_read(data->reg_ps_gain, &index); | |
| 244 | + if (ret < 0) | |
| 245 | + return ret; | |
| 246 | + | |
| 247 | + if (val < 0 || val > stk3310_ps_max[index]) | |
| 246 | 248 | return -EINVAL; |
| 247 | 249 | |
| 248 | 250 | if (dir == IIO_EV_DIR_RISING) |
| @@ -266,9 +268,12 @@ static int stk3310_read_event_config(struct iio_dev *indio_dev, · 17 unmodified lines | ||
| 266 | 268 | enum iio_event_direction dir) |
| 267 | 269 | { |
| 268 | 270 | unsigned int event_val; |
| 271 | + int ret; | |
| 269 | 272 | struct stk3310_data *data = iio_priv(indio_dev); |
| 270 | 273 | |
| 271 | − regmap_field_read(data->reg_int_ps, &event_val); | |
| 274 | + ret = regmap_field_read(data->reg_int_ps, &event_val); | |
| 275 | + if (ret < 0) | |
| 276 | + return ret; | |
| 272 | 277 | |
| 273 | 278 | return event_val; |
| 274 | 279 | } |
| @@ -307,14 +312,16 @@ static int stk3310_read_raw(struct iio_dev *indio_dev, · 32 unmodified lines | ||
| 307 | 312 | struct stk3310_data *data = iio_priv(indio_dev); |
| 308 | 313 | struct i2c_client *client = data->client; |
| 309 | 314 | |
| 315 | + if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY) | |
| 316 | + return -EINVAL; | |
| 317 | + | |
| 310 | 318 | switch (mask) { |
| 311 | 319 | case IIO_CHAN_INFO_RAW: |
| 312 | 320 | if (chan->type == IIO_LIGHT) |
| 313 | 321 | reg = STK3310_REG_ALS_DATA_MSB; |
| 314 | − else if (chan->type == IIO_PROXIMITY) | |
| 315 | − reg = STK3310_REG_PS_DATA_MSB; | |
| 316 | 322 | else |
| 317 | − return -EINVAL; | |
| 323 | + reg = STK3310_REG_PS_DATA_MSB; | |
| 324 | + | |
| 318 | 325 | mutex_lock(&data->lock); |
| 319 | 326 | ret = regmap_bulk_read(data->regmap, reg, &buf, 2); |
| 320 | 327 | if (ret < 0) { |
| @@ -327,17 +334,23 @@ static int stk3310_read_raw(struct iio_dev *indio_dev, · 6 unmodified lines | ||
| 327 | 334 | return IIO_VAL_INT; |
| 328 | 335 | case IIO_CHAN_INFO_INT_TIME: |
| 329 | 336 | if (chan->type == IIO_LIGHT) |
| 330 | − regmap_field_read(data->reg_als_it, &index); | |
| 337 | + ret = regmap_field_read(data->reg_als_it, &index); | |
| 331 | 338 | else |
| 332 | − regmap_field_read(data->reg_ps_it, &index); | |
| 339 | + ret = regmap_field_read(data->reg_ps_it, &index); | |
| 340 | + if (ret < 0) | |
| 341 | + return ret; | |
| 342 | + | |
| 333 | 343 | *val = stk3310_it_table[index][0]; |
| 334 | 344 | *val2 = stk3310_it_table[index][1]; |
| 335 | 345 | return IIO_VAL_INT_PLUS_MICRO; |
| 336 | 346 | case IIO_CHAN_INFO_SCALE: |
| 337 | 347 | if (chan->type == IIO_LIGHT) |
| 338 | − regmap_field_read(data->reg_als_gain, &index); | |
| 348 | + ret = regmap_field_read(data->reg_als_gain, &index); | |
| 339 | 349 | else |
| 340 | − regmap_field_read(data->reg_ps_gain, &index); | |
| 350 | + ret = regmap_field_read(data->reg_ps_gain, &index); | |
| 351 | + if (ret < 0) | |
| 352 | + return ret; | |
| 353 | + | |
| 341 | 354 | *val = stk3310_scale_table[index][0]; |
| 342 | 355 | *val2 = stk3310_scale_table[index][1]; |
| 343 | 356 | return IIO_VAL_INT_PLUS_MICRO; |
| @@ -354,6 +367,9 @@ static int stk3310_write_raw(struct iio_dev *indio_dev, · 10 unmodified lines | ||
| 354 | 367 | int index; |
| 355 | 368 | struct stk3310_data *data = iio_priv(indio_dev); |
| 356 | 369 | |
| 370 | + if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY) | |
| 371 | + return -EINVAL; | |
| 372 | + | |
| 357 | 373 | switch (mask) { |
| 358 | 374 | case IIO_CHAN_INFO_INT_TIME: |
| 359 | 375 | index = stk3310_get_index(stk3310_it_table, |
| @@ -368,7 +384,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev, · 8 unmodified lines | ||
| 368 | 384 | ret = regmap_field_write(data->reg_ps_it, index); |
| 369 | 385 | if (ret < 0) |
| 370 | 386 | dev_err(&data->client->dev, |
| 371 | − "sensor configuration failed\n"); | |
| 387 | + "sensor configuration failed\n"); | |
| 372 | 388 | mutex_unlock(&data->lock); |
| 373 | 389 | return ret; |
| 374 | 390 | |
| @@ -385,7 +401,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev, · 10 unmodified lines | ||
| 385 | 401 | ret = regmap_field_write(data->reg_ps_gain, index); |
| 386 | 402 | if (ret < 0) |
| 387 | 403 | dev_err(&data->client->dev, |
| 388 | − "sensor configuration failed\n"); | |
| 404 | + "sensor configuration failed\n"); | |
| 389 | 405 | mutex_unlock(&data->lock); |
| 390 | 406 | return ret; |
| 391 | 407 | } |
| @@ -419,8 +435,8 @@ static int stk3310_set_state(struct stk3310_data *data, u8 state) · 27 unmodified lines | ||
| 419 | 435 | dev_err(&client->dev, "failed to change sensor state\n"); |
| 420 | 436 | } else if (state != STK3310_STATE_STANDBY) { |
| 421 | 437 | /* Don't reset the 'enabled' flags if we're going in standby */ |
| 422 | − data->ps_enabled = !!(state & 0x01); | |
| 423 | − data->als_enabled = !!(state & 0x02); | |
| 438 | + data->ps_enabled = !!(state & STK3310_STATE_EN_PS); | |
| 439 | + data->als_enabled = !!(state & STK3310_STATE_EN_ALS); | |
| 424 | 440 | } |
| 425 | 441 | mutex_unlock(&data->lock); |
| 426 | 442 | |
| @@ -435,7 +451,10 @@ static int stk3310_init(struct iio_dev *indio_dev) · 8 unmodified lines | ||
| 435 | 451 | struct stk3310_data *data = iio_priv(indio_dev); |
| 436 | 452 | struct i2c_client *client = data->client; |
| 437 | 453 | |
| 438 | − regmap_read(data->regmap, STK3310_REG_ID, &chipid); | |
| 454 | + ret = regmap_read(data->regmap, STK3310_REG_ID, &chipid); | |
| 455 | + if (ret < 0) | |
| 456 | + return ret; | |
| 457 | + | |
| 439 | 458 | if (chipid != STK3310_CHIP_ID_VAL && |
| 440 | 459 | chipid != STK3311_CHIP_ID_VAL) { |
| 441 | 460 | dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid); |
| @@ -457,30 +476,6 @@ static int stk3310_init(struct iio_dev *indio_dev) · 15 unmodified lines | ||
| 457 | 476 | return ret; |
| 458 | 477 | } |
| 459 | 478 | |
| 460 | −static int stk3310_gpio_probe(struct i2c_client *client) | |
| 461 | −{ | |
| 462 | − struct device *dev; | |
| 463 | − struct gpio_desc *gpio; | |
| 464 | − int ret; | |
| 465 | − | |
| 466 | − if (!client) | |
| 467 | − return -EINVAL; | |
| 468 | − | |
| 469 | − dev = &client->dev; | |
| 470 | − | |
| 471 | − /* gpio interrupt pin */ | |
| 472 | − gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN); | |
| 473 | − if (IS_ERR(gpio)) { | |
| 474 | − dev_err(dev, "acpi gpio get index failed\n"); | |
| 475 | − return PTR_ERR(gpio); | |
| 476 | − } | |
| 477 | − | |
| 478 | − ret = gpiod_to_irq(gpio); | |
| 479 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 480 | − | |
| 481 | − return ret; | |
| 482 | −} | |
| 483 | − | |
| 484 | 479 | static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg) |
| 485 | 480 | { |
| 486 | 481 | switch (reg) { |
| @@ -604,27 +599,30 @@ static int stk3310_probe(struct i2c_client *client, · 117 unmodified lines | ||
| 604 | 599 | if (ret < 0) |
| 605 | 600 | return ret; |
| 606 | 601 | |
| 607 | − if (client->irq < 0) | |
| 608 | − client->irq = stk3310_gpio_probe(client); | |
| 609 | − | |
| 610 | − if (client->irq >= 0) { | |
| 602 | + if (client->irq > 0) { | |
| 611 | 603 | ret = devm_request_threaded_irq(&client->dev, client->irq, |
| 612 | 604 | stk3310_irq_handler, |
| 613 | 605 | stk3310_irq_event_handler, |
| 614 | 606 | IRQF_TRIGGER_FALLING | |
| 615 | 607 | IRQF_ONESHOT, |
| 616 | 608 | STK3310_EVENT, indio_dev); |
| 617 | − if (ret < 0) | |
| 609 | + if (ret < 0) { | |
| 618 | 610 | dev_err(&client->dev, "request irq %d failed\n", |
| 619 | − client->irq); | |
| 611 | + client->irq); | |
| 612 | + goto err_standby; | |
| 613 | + } | |
| 620 | 614 | } |
| 621 | 615 | |
| 622 | 616 | ret = iio_device_register(indio_dev); |
| 623 | 617 | if (ret < 0) { |
| 624 | 618 | dev_err(&client->dev, "device_register failed\n"); |
| 625 | − stk3310_set_state(data, STK3310_STATE_STANDBY); | |
| 619 | + goto err_standby; | |
| 626 | 620 | } |
| 627 | 621 | |
| 622 | + return 0; | |
| 623 | + | |
| 624 | +err_standby: | |
| 625 | + stk3310_set_state(data, STK3310_STATE_STANDBY); | |
| 628 | 626 | return ret; |
| 629 | 627 | } |
| 630 | 628 | |
| @@ -648,7 +646,7 @@ static int stk3310_suspend(struct device *dev) · 17 unmodified lines | ||
| 648 | 646 | |
| 649 | 647 | static int stk3310_resume(struct device *dev) |
| 650 | 648 | { |
| 651 | − int state = 0; | |
| 649 | + u8 state = 0; | |
| 652 | 650 | struct stk3310_data *data; |
| 653 | 651 | |
| 654 | 652 | data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); |
| @@ -158,9 +158,9 @@ static int tsl4531_check_id(struct i2c_client *client) · 157 unmodified lines | ||
| 158 | 158 | case TSL45313_ID: |
| 159 | 159 | case TSL45315_ID: |
| 160 | 160 | case TSL45317_ID: |
| 161 | − return 1; | |
| 162 | − default: | |
| 163 | 161 | return 0; |
| 162 | + default: | |
| 163 | + return -ENODEV; | |
| 164 | 164 | } |
| 165 | 165 | } |
| 166 | 166 | |
| @@ -180,9 +180,10 @@ static int tsl4531_probe(struct i2c_client *client, · 13 unmodified lines | ||
| 180 | 180 | data->client = client; |
| 181 | 181 | mutex_init(&data->lock); |
| 182 | 182 | |
| 183 | − if (!tsl4531_check_id(client)) { | |
| 183 | + ret = tsl4531_check_id(client); | |
| 184 | + if (ret) { | |
| 184 | 185 | dev_err(&client->dev, "no TSL4531 sensor\n"); |
| 185 | − return -ENODEV; | |
| 186 | + return ret; | |
| 186 | 187 | } |
| 187 | 188 | |
| 188 | 189 | ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL, |
| @@ -0,0 +1,507 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2015 Intel Corporation | |
| 3 | + * | |
| 4 | + * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify it | |
| 7 | + * under the terms of the GNU General Public License version 2 as published by | |
| 8 | + * the Free Software Foundation. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
| 11 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 12 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 13 | + * more details. | |
| 14 | + * | |
| 15 | + * To do: Interrupt support. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/kernel.h> | |
| 19 | +#include <linux/module.h> | |
| 20 | +#include <linux/acpi.h> | |
| 21 | +#include <linux/delay.h> | |
| 22 | +#include <linux/i2c.h> | |
| 23 | +#include <linux/iio/iio.h> | |
| 24 | +#include <linux/iio/sysfs.h> | |
| 25 | +#include <linux/mutex.h> | |
| 26 | + | |
| 27 | +#define US5182D_REG_CFG0 0x00 | |
| 28 | +#define US5182D_CFG0_ONESHOT_EN BIT(6) | |
| 29 | +#define US5182D_CFG0_SHUTDOWN_EN BIT(7) | |
| 30 | +#define US5182D_CFG0_WORD_ENABLE BIT(0) | |
| 31 | + | |
| 32 | +#define US5182D_REG_CFG1 0x01 | |
| 33 | +#define US5182D_CFG1_ALS_RES16 BIT(4) | |
| 34 | +#define US5182D_CFG1_AGAIN_DEFAULT 0x00 | |
| 35 | + | |
| 36 | +#define US5182D_REG_CFG2 0x02 | |
| 37 | +#define US5182D_CFG2_PX_RES16 BIT(4) | |
| 38 | +#define US5182D_CFG2_PXGAIN_DEFAULT BIT(2) | |
| 39 | + | |
| 40 | +#define US5182D_REG_CFG3 0x03 | |
| 41 | +#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5)) | |
| 42 | + | |
| 43 | +#define US5182D_REG_CFG4 0x10 | |
| 44 | + | |
| 45 | +/* | |
| 46 | + * Registers for tuning the auto dark current cancelling feature. | |
| 47 | + * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling. | |
| 48 | + * when ALS > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark | |
| 49 | + * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark | |
| 50 | + */ | |
| 51 | +#define US5182D_REG_UDARK_TH 0x27 | |
| 52 | +#define US5182D_REG_DARK_AUTO_EN 0x2b | |
| 53 | +#define US5182D_REG_AUTO_LDARK_GAIN 0x29 | |
| 54 | +#define US5182D_REG_AUTO_HDARK_GAIN 0x2a | |
| 55 | + | |
| 56 | +#define US5182D_OPMODE_ALS 0x01 | |
| 57 | +#define US5182D_OPMODE_PX 0x02 | |
| 58 | +#define US5182D_OPMODE_SHIFT 4 | |
| 59 | + | |
| 60 | +#define US5182D_REG_DARK_AUTO_EN_DEFAULT 0x80 | |
| 61 | +#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT 0x16 | |
| 62 | +#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT 0x00 | |
| 63 | + | |
| 64 | +#define US5182D_REG_ADL 0x0c | |
| 65 | +#define US5182D_REG_PDL 0x0e | |
| 66 | + | |
| 67 | +#define US5182D_REG_MODE_STORE 0x21 | |
| 68 | +#define US5182D_STORE_MODE 0x01 | |
| 69 | + | |
| 70 | +#define US5182D_REG_CHIPID 0xb2 | |
| 71 | + | |
| 72 | +#define US5182D_OPMODE_MASK GENMASK(5, 4) | |
| 73 | +#define US5182D_AGAIN_MASK 0x07 | |
| 74 | +#define US5182D_RESET_CHIP 0x01 | |
| 75 | + | |
| 76 | +#define US5182D_CHIPID 0x26 | |
| 77 | +#define US5182D_DRV_NAME "us5182d" | |
| 78 | + | |
| 79 | +#define US5182D_GA_RESOLUTION 1000 | |
| 80 | + | |
| 81 | +#define US5182D_READ_BYTE 1 | |
| 82 | +#define US5182D_READ_WORD 2 | |
| 83 | +#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */ | |
| 84 | + | |
| 85 | +/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */ | |
| 86 | +static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600, | |
| 87 | + 3900, 2100}; | |
| 88 | + | |
| 89 | +/* | |
| 90 | + * Experimental thresholds that work with US5182D sensor on evaluation board | |
| 91 | + * roughly between 12-32 lux | |
| 92 | + */ | |
| 93 | +static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000, | |
| 94 | + 8000}; | |
| 95 | + | |
| 96 | +enum mode { | |
| 97 | + US5182D_ALS_PX, | |
| 98 | + US5182D_ALS_ONLY, | |
| 99 | + US5182D_PX_ONLY | |
| 100 | +}; | |
| 101 | + | |
| 102 | +struct us5182d_data { | |
| 103 | + struct i2c_client *client; | |
| 104 | + struct mutex lock; | |
| 105 | + | |
| 106 | + /* Glass attenuation factor */ | |
| 107 | + u32 ga; | |
| 108 | + | |
| 109 | + /* Dark gain tuning */ | |
| 110 | + u8 lower_dark_gain; | |
| 111 | + u8 upper_dark_gain; | |
| 112 | + u16 *us5182d_dark_ths; | |
| 113 | + | |
| 114 | + u8 opmode; | |
| 115 | +}; | |
| 116 | + | |
| 117 | +static IIO_CONST_ATTR(in_illuminance_scale_available, | |
| 118 | + "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885"); | |
| 119 | + | |
| 120 | +static struct attribute *us5182d_attrs[] = { | |
| 121 | + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, | |
| 122 | + NULL | |
| 123 | +}; | |
| 124 | + | |
| 125 | +static const struct attribute_group us5182d_attr_group = { | |
| 126 | + .attrs = us5182d_attrs, | |
| 127 | +}; | |
| 128 | + | |
| 129 | +static const struct { | |
| 130 | + u8 reg; | |
| 131 | + u8 val; | |
| 132 | +} us5182d_regvals[] = { | |
| 133 | + {US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN | | |
| 134 | + US5182D_CFG0_WORD_ENABLE)}, | |
| 135 | + {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16}, | |
| 136 | + {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 | | |
| 137 | + US5182D_CFG2_PXGAIN_DEFAULT)}, | |
| 138 | + {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100}, | |
| 139 | + {US5182D_REG_MODE_STORE, US5182D_STORE_MODE}, | |
| 140 | + {US5182D_REG_CFG4, 0x00}, | |
| 141 | +}; | |
| 142 | + | |
| 143 | +static const struct iio_chan_spec us5182d_channels[] = { | |
| 144 | + { | |
| 145 | + .type = IIO_LIGHT, | |
| 146 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
| 147 | + BIT(IIO_CHAN_INFO_SCALE), | |
| 148 | + }, | |
| 149 | + { | |
| 150 | + .type = IIO_PROXIMITY, | |
| 151 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
| 152 | + } | |
| 153 | +}; | |
| 154 | + | |
| 155 | +static int us5182d_get_als(struct us5182d_data *data) | |
| 156 | +{ | |
| 157 | + int ret; | |
| 158 | + unsigned long result; | |
| 159 | + | |
| 160 | + ret = i2c_smbus_read_word_data(data->client, | |
| 161 | + US5182D_REG_ADL); | |
| 162 | + if (ret < 0) | |
| 163 | + return ret; | |
| 164 | + | |
| 165 | + result = ret * data->ga / US5182D_GA_RESOLUTION; | |
| 166 | + if (result > 0xffff) | |
| 167 | + result = 0xffff; | |
| 168 | + | |
| 169 | + return result; | |
| 170 | +} | |
| 171 | + | |
| 172 | +static int us5182d_set_opmode(struct us5182d_data *data, u8 mode) | |
| 173 | +{ | |
| 174 | + int ret; | |
| 175 | + | |
| 176 | + ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0); | |
| 177 | + if (ret < 0) | |
| 178 | + return ret; | |
| 179 | + | |
| 180 | + /* | |
| 181 | + * In oneshot mode the chip will power itself down after taking the | |
| 182 | + * required measurement. | |
| 183 | + */ | |
| 184 | + ret = ret | US5182D_CFG0_ONESHOT_EN; | |
| 185 | + | |
| 186 | + /* update mode */ | |
| 187 | + ret = ret & ~US5182D_OPMODE_MASK; | |
| 188 | + ret = ret | (mode << US5182D_OPMODE_SHIFT); | |
| 189 | + | |
| 190 | + /* | |
| 191 | + * After updating the operating mode, the chip requires that | |
| 192 | + * the operation is stored, by writing 1 in the STORE_MODE | |
| 193 | + * register (auto-clearing). | |
| 194 | + */ | |
| 195 | + ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret); | |
| 196 | + if (ret < 0) | |
| 197 | + return ret; | |
| 198 | + | |
| 199 | + if (mode == data->opmode) | |
| 200 | + return 0; | |
| 201 | + | |
| 202 | + ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE, | |
| 203 | + US5182D_STORE_MODE); | |
| 204 | + if (ret < 0) | |
| 205 | + return ret; | |
| 206 | + | |
| 207 | + data->opmode = mode; | |
| 208 | + msleep(US5182D_OPSTORE_SLEEP_TIME); | |
| 209 | + | |
| 210 | + return 0; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static int us5182d_read_raw(struct iio_dev *indio_dev, | |
| 214 | + struct iio_chan_spec const *chan, int *val, | |
| 215 | + int *val2, long mask) | |
| 216 | +{ | |
| 217 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 218 | + int ret; | |
| 219 | + | |
| 220 | + switch (mask) { | |
| 221 | + case IIO_CHAN_INFO_RAW: | |
| 222 | + switch (chan->type) { | |
| 223 | + case IIO_LIGHT: | |
| 224 | + mutex_lock(&data->lock); | |
| 225 | + ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS); | |
| 226 | + if (ret < 0) | |
| 227 | + goto out_err; | |
| 228 | + | |
| 229 | + ret = us5182d_get_als(data); | |
| 230 | + if (ret < 0) | |
| 231 | + goto out_err; | |
| 232 | + mutex_unlock(&data->lock); | |
| 233 | + *val = ret; | |
| 234 | + return IIO_VAL_INT; | |
| 235 | + case IIO_PROXIMITY: | |
| 236 | + mutex_lock(&data->lock); | |
| 237 | + ret = us5182d_set_opmode(data, US5182D_OPMODE_PX); | |
| 238 | + if (ret < 0) | |
| 239 | + goto out_err; | |
| 240 | + | |
| 241 | + ret = i2c_smbus_read_word_data(data->client, | |
| 242 | + US5182D_REG_PDL); | |
| 243 | + if (ret < 0) | |
| 244 | + goto out_err; | |
| 245 | + mutex_unlock(&data->lock); | |
| 246 | + *val = ret; | |
| 247 | + return IIO_VAL_INT; | |
| 248 | + default: | |
| 249 | + return -EINVAL; | |
| 250 | + } | |
| 251 | + | |
| 252 | + case IIO_CHAN_INFO_SCALE: | |
| 253 | + ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1); | |
| 254 | + if (ret < 0) | |
| 255 | + return ret; | |
| 256 | + | |
| 257 | + *val = 0; | |
| 258 | + *val2 = us5182d_scales[ret & US5182D_AGAIN_MASK]; | |
| 259 | + | |
| 260 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 261 | + default: | |
| 262 | + return -EINVAL; | |
| 263 | + } | |
| 264 | + | |
| 265 | + return -EINVAL; | |
| 266 | +out_err: | |
| 267 | + mutex_unlock(&data->lock); | |
| 268 | + return ret; | |
| 269 | +} | |
| 270 | + | |
| 271 | +/** | |
| 272 | + * us5182d_update_dark_th - update Darh_Th registers | |
| 273 | + * @data us5182d_data structure | |
| 274 | + * @index index in us5182d_dark_ths array to use for the updated value | |
| 275 | + * | |
| 276 | + * Function needs to be called with a lock held because it needs two i2c write | |
| 277 | + * byte operations as these registers (0x27 0x28) don't work in word mode | |
| 278 | + * accessing. | |
| 279 | + */ | |
| 280 | +static int us5182d_update_dark_th(struct us5182d_data *data, int index) | |
| 281 | +{ | |
| 282 | + __be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]); | |
| 283 | + int ret; | |
| 284 | + | |
| 285 | + ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH, | |
| 286 | + ((u8 *)&dark_th)[0]); | |
| 287 | + if (ret < 0) | |
| 288 | + return ret; | |
| 289 | + | |
| 290 | + return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1, | |
| 291 | + ((u8 *)&dark_th)[1]); | |
| 292 | +} | |
| 293 | + | |
| 294 | +/** | |
| 295 | + * us5182d_apply_scale - update the ALS scale | |
| 296 | + * @data us5182d_data structure | |
| 297 | + * @index index in us5182d_scales array to use for the updated value | |
| 298 | + * | |
| 299 | + * Function needs to be called with a lock held as we're having more than one | |
| 300 | + * i2c operation. | |
| 301 | + */ | |
| 302 | +static int us5182d_apply_scale(struct us5182d_data *data, int index) | |
| 303 | +{ | |
| 304 | + int ret; | |
| 305 | + | |
| 306 | + ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1); | |
| 307 | + if (ret < 0) | |
| 308 | + return ret; | |
| 309 | + | |
| 310 | + ret = ret & (~US5182D_AGAIN_MASK); | |
| 311 | + ret |= index; | |
| 312 | + | |
| 313 | + ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret); | |
| 314 | + if (ret < 0) | |
| 315 | + return ret; | |
| 316 | + | |
| 317 | + return us5182d_update_dark_th(data, index); | |
| 318 | +} | |
| 319 | + | |
| 320 | +static int us5182d_write_raw(struct iio_dev *indio_dev, | |
| 321 | + struct iio_chan_spec const *chan, int val, | |
| 322 | + int val2, long mask) | |
| 323 | +{ | |
| 324 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 325 | + int ret, i; | |
| 326 | + | |
| 327 | + switch (mask) { | |
| 328 | + case IIO_CHAN_INFO_SCALE: | |
| 329 | + if (val != 0) | |
| 330 | + return -EINVAL; | |
| 331 | + for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++) | |
| 332 | + if (val2 == us5182d_scales[i]) { | |
| 333 | + mutex_lock(&data->lock); | |
| 334 | + ret = us5182d_apply_scale(data, i); | |
| 335 | + mutex_unlock(&data->lock); | |
| 336 | + return ret; | |
| 337 | + } | |
| 338 | + break; | |
| 339 | + default: | |
| 340 | + return -EINVAL; | |
| 341 | + } | |
| 342 | + | |
| 343 | + return -EINVAL; | |
| 344 | +} | |
| 345 | + | |
| 346 | +static const struct iio_info us5182d_info = { | |
| 347 | + .driver_module = THIS_MODULE, | |
| 348 | + .read_raw = us5182d_read_raw, | |
| 349 | + .write_raw = us5182d_write_raw, | |
| 350 | + .attrs = &us5182d_attr_group, | |
| 351 | +}; | |
| 352 | + | |
| 353 | +static int us5182d_reset(struct iio_dev *indio_dev) | |
| 354 | +{ | |
| 355 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 356 | + | |
| 357 | + return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3, | |
| 358 | + US5182D_RESET_CHIP); | |
| 359 | +} | |
| 360 | + | |
| 361 | +static int us5182d_init(struct iio_dev *indio_dev) | |
| 362 | +{ | |
| 363 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 364 | + int i, ret; | |
| 365 | + | |
| 366 | + ret = us5182d_reset(indio_dev); | |
| 367 | + if (ret < 0) | |
| 368 | + return ret; | |
| 369 | + | |
| 370 | + data->opmode = 0; | |
| 371 | + for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) { | |
| 372 | + ret = i2c_smbus_write_byte_data(data->client, | |
| 373 | + us5182d_regvals[i].reg, | |
| 374 | + us5182d_regvals[i].val); | |
| 375 | + if (ret < 0) | |
| 376 | + return ret; | |
| 377 | + } | |
| 378 | + | |
| 379 | + return 0; | |
| 380 | +} | |
| 381 | + | |
| 382 | +static void us5182d_get_platform_data(struct iio_dev *indio_dev) | |
| 383 | +{ | |
| 384 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 385 | + | |
| 386 | + if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef", | |
| 387 | + &data->ga)) | |
| 388 | + data->ga = US5182D_GA_RESOLUTION; | |
| 389 | + if (device_property_read_u16_array(&data->client->dev, | |
| 390 | + "upisemi,dark-ths", | |
| 391 | + data->us5182d_dark_ths, | |
| 392 | + ARRAY_SIZE(us5182d_dark_ths_vals))) | |
| 393 | + data->us5182d_dark_ths = us5182d_dark_ths_vals; | |
| 394 | + if (device_property_read_u8(&data->client->dev, | |
| 395 | + "upisemi,upper-dark-gain", | |
| 396 | + &data->upper_dark_gain)) | |
| 397 | + data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT; | |
| 398 | + if (device_property_read_u8(&data->client->dev, | |
| 399 | + "upisemi,lower-dark-gain", | |
| 400 | + &data->lower_dark_gain)) | |
| 401 | + data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT; | |
| 402 | +} | |
| 403 | + | |
| 404 | +static int us5182d_dark_gain_config(struct iio_dev *indio_dev) | |
| 405 | +{ | |
| 406 | + struct us5182d_data *data = iio_priv(indio_dev); | |
| 407 | + int ret; | |
| 408 | + | |
| 409 | + ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT); | |
| 410 | + if (ret < 0) | |
| 411 | + return ret; | |
| 412 | + | |
| 413 | + ret = i2c_smbus_write_byte_data(data->client, | |
| 414 | + US5182D_REG_AUTO_LDARK_GAIN, | |
| 415 | + data->lower_dark_gain); | |
| 416 | + if (ret < 0) | |
| 417 | + return ret; | |
| 418 | + | |
| 419 | + ret = i2c_smbus_write_byte_data(data->client, | |
| 420 | + US5182D_REG_AUTO_HDARK_GAIN, | |
| 421 | + data->upper_dark_gain); | |
| 422 | + if (ret < 0) | |
| 423 | + return ret; | |
| 424 | + | |
| 425 | + return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN, | |
| 426 | + US5182D_REG_DARK_AUTO_EN_DEFAULT); | |
| 427 | +} | |
| 428 | + | |
| 429 | +static int us5182d_probe(struct i2c_client *client, | |
| 430 | + const struct i2c_device_id *id) | |
| 431 | +{ | |
| 432 | + struct us5182d_data *data; | |
| 433 | + struct iio_dev *indio_dev; | |
| 434 | + int ret; | |
| 435 | + | |
| 436 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 437 | + if (!indio_dev) | |
| 438 | + return -ENOMEM; | |
| 439 | + | |
| 440 | + data = iio_priv(indio_dev); | |
| 441 | + i2c_set_clientdata(client, indio_dev); | |
| 442 | + data->client = client; | |
| 443 | + | |
| 444 | + mutex_init(&data->lock); | |
| 445 | + | |
| 446 | + indio_dev->dev.parent = &client->dev; | |
| 447 | + indio_dev->info = &us5182d_info; | |
| 448 | + indio_dev->name = US5182D_DRV_NAME; | |
| 449 | + indio_dev->channels = us5182d_channels; | |
| 450 | + indio_dev->num_channels = ARRAY_SIZE(us5182d_channels); | |
| 451 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 452 | + | |
| 453 | + ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID); | |
| 454 | + if (ret != US5182D_CHIPID) { | |
| 455 | + dev_err(&data->client->dev, | |
| 456 | + "Failed to detect US5182 light chip\n"); | |
| 457 | + return (ret < 0) ? ret : -ENODEV; | |
| 458 | + } | |
| 459 | + | |
| 460 | + us5182d_get_platform_data(indio_dev); | |
| 461 | + ret = us5182d_init(indio_dev); | |
| 462 | + if (ret < 0) | |
| 463 | + return ret; | |
| 464 | + | |
| 465 | + ret = us5182d_dark_gain_config(indio_dev); | |
| 466 | + if (ret < 0) | |
| 467 | + return ret; | |
| 468 | + | |
| 469 | + return iio_device_register(indio_dev); | |
| 470 | +} | |
| 471 | + | |
| 472 | +static int us5182d_remove(struct i2c_client *client) | |
| 473 | +{ | |
| 474 | + iio_device_unregister(i2c_get_clientdata(client)); | |
| 475 | + return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0, | |
| 476 | + US5182D_CFG0_SHUTDOWN_EN); | |
| 477 | +} | |
| 478 | + | |
| 479 | +static const struct acpi_device_id us5182d_acpi_match[] = { | |
| 480 | + { "USD5182", 0}, | |
| 481 | + {} | |
| 482 | +}; | |
| 483 | + | |
| 484 | +MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match); | |
| 485 | + | |
| 486 | +static const struct i2c_device_id us5182d_id[] = { | |
| 487 | + {"usd5182", 0}, | |
| 488 | + {} | |
| 489 | +}; | |
| 490 | + | |
| 491 | +MODULE_DEVICE_TABLE(i2c, us5182d_id); | |
| 492 | + | |
| 493 | +static struct i2c_driver us5182d_driver = { | |
| 494 | + .driver = { | |
| 495 | + .name = US5182D_DRV_NAME, | |
| 496 | + .acpi_match_table = ACPI_PTR(us5182d_acpi_match), | |
| 497 | + }, | |
| 498 | + .probe = us5182d_probe, | |
| 499 | + .remove = us5182d_remove, | |
| 500 | + .id_table = us5182d_id, | |
| 501 | + | |
| 502 | +}; | |
| 503 | +module_i2c_driver(us5182d_driver); | |
| 504 | + | |
| 505 | +MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>"); | |
| 506 | +MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor"); | |
| 507 | +MODULE_LICENSE("GPL v2"); | |
| @@ -24,6 +24,24 @@ config AK09911 · 23 unmodified lines | ||
| 24 | 24 | help |
| 25 | 25 | Deprecated: AK09911 is now supported by AK8975 driver. |
| 26 | 26 | |
| 27 | +config BMC150_MAGN | |
| 28 | + tristate "Bosch BMC150 Magnetometer Driver" | |
| 29 | + depends on I2C | |
| 30 | + select REGMAP_I2C | |
| 31 | + select IIO_BUFFER | |
| 32 | + select IIO_TRIGGERED_BUFFER | |
| 33 | + help | |
| 34 | + Say yes here to build support for the BMC150 magnetometer. | |
| 35 | + | |
| 36 | + Currently this only supports the device via an i2c interface. | |
| 37 | + | |
| 38 | + This is a combo module with both accelerometer and magnetometer. | |
| 39 | + This driver is only implementing magnetometer part, which has | |
| 40 | + its own address and register map. | |
| 41 | + | |
| 42 | + To compile this driver as a module, choose M here: the module will be | |
| 43 | + called bmc150_magn. | |
| 44 | + | |
| 27 | 45 | config MAG3110 |
| 28 | 46 | tristate "Freescale MAG3110 3-Axis Magnetometer" |
| 29 | 47 | depends on I2C |
| @@ -87,19 +105,4 @@ config IIO_ST_MAGN_SPI_3AXIS · 57 unmodified lines | ||
| 87 | 105 | depends on IIO_ST_MAGN_3AXIS |
| 88 | 106 | depends on IIO_ST_SENSORS_SPI |
| 89 | 107 | |
| 90 | −config BMC150_MAGN | |
| 91 | − tristate "Bosch BMC150 Magnetometer Driver" | |
| 92 | − depends on I2C | |
| 93 | − select REGMAP_I2C | |
| 94 | − select IIO_BUFFER | |
| 95 | − select IIO_TRIGGERED_BUFFER | |
| 96 | − help | |
| 97 | − Say yes here to build support for the BMC150 magnetometer. | |
| 98 | − | |
| 99 | − Currently this only supports the device via an i2c interface. | |
| 100 | − | |
| 101 | − This is a combo module with both accelerometer and magnetometer. | |
| 102 | − This driver is only implementing magnetometer part, which has | |
| 103 | − its own address and register map. | |
| 104 | − | |
| 105 | 108 | endmenu |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | # When adding new entries keep the list in alphabetical order |
| 6 | 6 | obj-$(CONFIG_AK8975) += ak8975.o |
| 7 | +obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o | |
| 7 | 8 | obj-$(CONFIG_MAG3110) += mag3110.o |
| 8 | 9 | obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o |
| 9 | 10 | obj-$(CONFIG_MMC35240) += mmc35240.o |
| @@ -14,5 +15,3 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o · 4 unmodified lines | ||
| 14 | 15 | |
| 15 | 16 | obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o |
| 16 | 17 | obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o |
| 17 | − | |
| 18 | −obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o | |
| @@ -37,7 +37,6 @@ · 36 unmodified lines | ||
| 37 | 37 | |
| 38 | 38 | #define BMC150_MAGN_DRV_NAME "bmc150_magn" |
| 39 | 39 | #define BMC150_MAGN_IRQ_NAME "bmc150_magn_event" |
| 40 | −#define BMC150_MAGN_GPIO_INT "interrupt" | |
| 41 | 40 | |
| 42 | 41 | #define BMC150_MAGN_REG_CHIP_ID 0x40 |
| 43 | 42 | #define BMC150_MAGN_CHIP_ID_VAL 0x32 |
| @@ -833,31 +832,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = { · 789 unmodified lines | ||
| 833 | 832 | .postdisable = bmc150_magn_buffer_postdisable, |
| 834 | 833 | }; |
| 835 | 834 | |
| 836 | −static int bmc150_magn_gpio_probe(struct i2c_client *client) | |
| 837 | −{ | |
| 838 | − struct device *dev; | |
| 839 | − struct gpio_desc *gpio; | |
| 840 | − int ret; | |
| 841 | − | |
| 842 | − if (!client) | |
| 843 | − return -EINVAL; | |
| 844 | − | |
| 845 | − dev = &client->dev; | |
| 846 | − | |
| 847 | − /* data ready GPIO interrupt pin */ | |
| 848 | − gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN); | |
| 849 | − if (IS_ERR(gpio)) { | |
| 850 | − dev_err(dev, "ACPI GPIO get index failed\n"); | |
| 851 | − return PTR_ERR(gpio); | |
| 852 | − } | |
| 853 | − | |
| 854 | − ret = gpiod_to_irq(gpio); | |
| 855 | − | |
| 856 | − dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
| 857 | − | |
| 858 | − return ret; | |
| 859 | −} | |
| 860 | − | |
| 861 | 835 | static const char *bmc150_magn_match_acpi_device(struct device *dev) |
| 862 | 836 | { |
| 863 | 837 | const struct acpi_device_id *id; |
| @@ -911,9 +885,6 @@ static int bmc150_magn_probe(struct i2c_client *client, · 47 unmodified lines | ||
| 911 | 885 | indio_dev->modes = INDIO_DIRECT_MODE; |
| 912 | 886 | indio_dev->info = &bmc150_magn_info; |
| 913 | 887 | |
| 914 | − if (client->irq <= 0) | |
| 915 | − client->irq = bmc150_magn_gpio_probe(client); | |
| 916 | − | |
| 917 | 888 | if (client->irq > 0) { |
| 918 | 889 | data->dready_trig = devm_iio_trigger_alloc(&client->dev, |
| 919 | 890 | "%s-dev%d", |
| @@ -560,6 +560,7 @@ static const struct iio_info magn_info = { · 559 unmodified lines | ||
| 560 | 560 | .attrs = &st_magn_attribute_group, |
| 561 | 561 | .read_raw = &st_magn_read_raw, |
| 562 | 562 | .write_raw = &st_magn_write_raw, |
| 563 | + .debugfs_reg_access = &st_sensors_debugfs_reg_access, | |
| 563 | 564 | }; |
| 564 | 565 | |
| 565 | 566 | #ifdef CONFIG_IIO_TRIGGER |
| @@ -0,0 +1,20 @@ | ||
| 1 | +# | |
| 2 | +# Potentiometer drivers | |
| 3 | +# | |
| 4 | +# When adding new entries keep the list in alphabetical order | |
| 5 | + | |
| 6 | +menu "Digital potentiometers" | |
| 7 | + | |
| 8 | +config MCP4531 | |
| 9 | + tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver" | |
| 10 | + depends on I2C | |
| 11 | + help | |
| 12 | + Say yes here to build support for the Microchip | |
| 13 | + MCP4531, MCP4532, MCP4551, MCP4552, | |
| 14 | + MCP4631, MCP4632, MCP4651, MCP4652 | |
| 15 | + digital potentiomenter chips. | |
| 16 | + | |
| 17 | + To compile this driver as a module, choose M here: the | |
| 18 | + module will be called mcp4531. | |
| 19 | + | |
| 20 | +endmenu | |
| @@ -0,0 +1,6 @@ | ||
| 1 | +# | |
| 2 | +# Makefile for industrial I/O potentiometer drivers | |
| 3 | +# | |
| 4 | + | |
| 5 | +# When adding new entries keep the list in alphabetical order | |
| 6 | +obj-$(CONFIG_MCP4531) += mcp4531.o | |
| @@ -0,0 +1,231 @@ | ||
| 1 | +/* | |
| 2 | + * Industrial I/O driver for Microchip digital potentiometers | |
| 3 | + * Copyright (c) 2015 Axentia Technologies AB | |
| 4 | + * Author: Peter Rosin <peda@axentia.se> | |
| 5 | + * | |
| 6 | + * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf | |
| 7 | + * | |
| 8 | + * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address | |
| 9 | + * mcp4531 1 129 5, 10, 50, 100 010111x | |
| 10 | + * mcp4532 1 129 5, 10, 50, 100 01011xx | |
| 11 | + * mcp4551 1 257 5, 10, 50, 100 010111x | |
| 12 | + * mcp4552 1 257 5, 10, 50, 100 01011xx | |
| 13 | + * mcp4631 2 129 5, 10, 50, 100 0101xxx | |
| 14 | + * mcp4632 2 129 5, 10, 50, 100 01011xx | |
| 15 | + * mcp4651 2 257 5, 10, 50, 100 0101xxx | |
| 16 | + * mcp4652 2 257 5, 10, 50, 100 01011xx | |
| 17 | + * | |
| 18 | + * This program is free software; you can redistribute it and/or modify it | |
| 19 | + * under the terms of the GNU General Public License version 2 as published by | |
| 20 | + * the Free Software Foundation. | |
| 21 | + */ | |
| 22 | + | |
| 23 | +#include <linux/module.h> | |
| 24 | +#include <linux/i2c.h> | |
| 25 | +#include <linux/err.h> | |
| 26 | + | |
| 27 | +#include <linux/iio/iio.h> | |
| 28 | + | |
| 29 | +struct mcp4531_cfg { | |
| 30 | + int wipers; | |
| 31 | + int max_pos; | |
| 32 | + int kohms; | |
| 33 | +}; | |
| 34 | + | |
| 35 | +enum mcp4531_type { | |
| 36 | + MCP453x_502, | |
| 37 | + MCP453x_103, | |
| 38 | + MCP453x_503, | |
| 39 | + MCP453x_104, | |
| 40 | + MCP455x_502, | |
| 41 | + MCP455x_103, | |
| 42 | + MCP455x_503, | |
| 43 | + MCP455x_104, | |
| 44 | + MCP463x_502, | |
| 45 | + MCP463x_103, | |
| 46 | + MCP463x_503, | |
| 47 | + MCP463x_104, | |
| 48 | + MCP465x_502, | |
| 49 | + MCP465x_103, | |
| 50 | + MCP465x_503, | |
| 51 | + MCP465x_104, | |
| 52 | +}; | |
| 53 | + | |
| 54 | +static const struct mcp4531_cfg mcp4531_cfg[] = { | |
| 55 | + [MCP453x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, }, | |
| 56 | + [MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, }, | |
| 57 | + [MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, }, | |
| 58 | + [MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, }, | |
| 59 | + [MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, }, | |
| 60 | + [MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, }, | |
| 61 | + [MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, }, | |
| 62 | + [MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, }, | |
| 63 | + [MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, }, | |
| 64 | + [MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, }, | |
| 65 | + [MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, }, | |
| 66 | + [MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, }, | |
| 67 | + [MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, }, | |
| 68 | + [MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, }, | |
| 69 | + [MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, }, | |
| 70 | + [MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, }, | |
| 71 | +}; | |
| 72 | + | |
| 73 | +#define MCP4531_WRITE (0 << 2) | |
| 74 | +#define MCP4531_INCR (1 << 2) | |
| 75 | +#define MCP4531_DECR (2 << 2) | |
| 76 | +#define MCP4531_READ (3 << 2) | |
| 77 | + | |
| 78 | +#define MCP4531_WIPER_SHIFT (4) | |
| 79 | + | |
| 80 | +struct mcp4531_data { | |
| 81 | + struct i2c_client *client; | |
| 82 | + unsigned long devid; | |
| 83 | +}; | |
| 84 | + | |
| 85 | +#define MCP4531_CHANNEL(ch) { \ | |
| 86 | + .type = IIO_RESISTANCE, \ | |
| 87 | + .indexed = 1, \ | |
| 88 | + .output = 1, \ | |
| 89 | + .channel = (ch), \ | |
| 90 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
| 91 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | |
| 92 | +} | |
| 93 | + | |
| 94 | +static const struct iio_chan_spec mcp4531_channels[] = { | |
| 95 | + MCP4531_CHANNEL(0), | |
| 96 | + MCP4531_CHANNEL(1), | |
| 97 | +}; | |
| 98 | + | |
| 99 | +static int mcp4531_read_raw(struct iio_dev *indio_dev, | |
| 100 | + struct iio_chan_spec const *chan, | |
| 101 | + int *val, int *val2, long mask) | |
| 102 | +{ | |
| 103 | + struct mcp4531_data *data = iio_priv(indio_dev); | |
| 104 | + int address = chan->channel << MCP4531_WIPER_SHIFT; | |
| 105 | + s32 ret; | |
| 106 | + | |
| 107 | + switch (mask) { | |
| 108 | + case IIO_CHAN_INFO_RAW: | |
| 109 | + ret = i2c_smbus_read_word_swapped(data->client, | |
| 110 | + MCP4531_READ | address); | |
| 111 | + if (ret < 0) | |
| 112 | + return ret; | |
| 113 | + *val = ret; | |
| 114 | + return IIO_VAL_INT; | |
| 115 | + case IIO_CHAN_INFO_SCALE: | |
| 116 | + *val = 1000 * mcp4531_cfg[data->devid].kohms; | |
| 117 | + *val2 = mcp4531_cfg[data->devid].max_pos; | |
| 118 | + return IIO_VAL_FRACTIONAL; | |
| 119 | + } | |
| 120 | + | |
| 121 | + return -EINVAL; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static int mcp4531_write_raw(struct iio_dev *indio_dev, | |
| 125 | + struct iio_chan_spec const *chan, | |
| 126 | + int val, int val2, long mask) | |
| 127 | +{ | |
| 128 | + struct mcp4531_data *data = iio_priv(indio_dev); | |
| 129 | + int address = chan->channel << MCP4531_WIPER_SHIFT; | |
| 130 | + | |
| 131 | + switch (mask) { | |
| 132 | + case IIO_CHAN_INFO_RAW: | |
| 133 | + if (val > mcp4531_cfg[data->devid].max_pos || val < 0) | |
| 134 | + return -EINVAL; | |
| 135 | + break; | |
| 136 | + default: | |
| 137 | + return -EINVAL; | |
| 138 | + } | |
| 139 | + | |
| 140 | + return i2c_smbus_write_byte_data(data->client, | |
| 141 | + MCP4531_WRITE | address | (val >> 8), | |
| 142 | + val & 0xff); | |
| 143 | +} | |
| 144 | + | |
| 145 | +static const struct iio_info mcp4531_info = { | |
| 146 | + .read_raw = mcp4531_read_raw, | |
| 147 | + .write_raw = mcp4531_write_raw, | |
| 148 | + .driver_module = THIS_MODULE, | |
| 149 | +}; | |
| 150 | + | |
| 151 | +static int mcp4531_probe(struct i2c_client *client, | |
| 152 | + const struct i2c_device_id *id) | |
| 153 | +{ | |
| 154 | + struct device *dev = &client->dev; | |
| 155 | + unsigned long devid = id->driver_data; | |
| 156 | + struct mcp4531_data *data; | |
| 157 | + struct iio_dev *indio_dev; | |
| 158 | + | |
| 159 | + if (!i2c_check_functionality(client->adapter, | |
| 160 | + I2C_FUNC_SMBUS_WORD_DATA)) { | |
| 161 | + dev_err(dev, "SMBUS Word Data not supported\n"); | |
| 162 | + return -EIO; | |
| 163 | + } | |
| 164 | + | |
| 165 | + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | |
| 166 | + if (!indio_dev) | |
| 167 | + return -ENOMEM; | |
| 168 | + data = iio_priv(indio_dev); | |
| 169 | + i2c_set_clientdata(client, indio_dev); | |
| 170 | + data->client = client; | |
| 171 | + data->devid = devid; | |
| 172 | + | |
| 173 | + indio_dev->dev.parent = dev; | |
| 174 | + indio_dev->info = &mcp4531_info; | |
| 175 | + indio_dev->channels = mcp4531_channels; | |
| 176 | + indio_dev->num_channels = mcp4531_cfg[devid].wipers; | |
| 177 | + indio_dev->name = client->name; | |
| 178 | + | |
| 179 | + return devm_iio_device_register(dev, indio_dev); | |
| 180 | +} | |
| 181 | + | |
| 182 | +static const struct i2c_device_id mcp4531_id[] = { | |
| 183 | + { "mcp4531-502", MCP453x_502 }, | |
| 184 | + { "mcp4531-103", MCP453x_103 }, | |
| 185 | + { "mcp4531-503", MCP453x_503 }, | |
| 186 | + { "mcp4531-104", MCP453x_104 }, | |
| 187 | + { "mcp4532-502", MCP453x_502 }, | |
| 188 | + { "mcp4532-103", MCP453x_103 }, | |
| 189 | + { "mcp4532-503", MCP453x_503 }, | |
| 190 | + { "mcp4532-104", MCP453x_104 }, | |
| 191 | + { "mcp4551-502", MCP455x_502 }, | |
| 192 | + { "mcp4551-103", MCP455x_103 }, | |
| 193 | + { "mcp4551-503", MCP455x_503 }, | |
| 194 | + { "mcp4551-104", MCP455x_104 }, | |
| 195 | + { "mcp4552-502", MCP455x_502 }, | |
| 196 | + { "mcp4552-103", MCP455x_103 }, | |
| 197 | + { "mcp4552-503", MCP455x_503 }, | |
| 198 | + { "mcp4552-104", MCP455x_104 }, | |
| 199 | + { "mcp4631-502", MCP463x_502 }, | |
| 200 | + { "mcp4631-103", MCP463x_103 }, | |
| 201 | + { "mcp4631-503", MCP463x_503 }, | |
| 202 | + { "mcp4631-104", MCP463x_104 }, | |
| 203 | + { "mcp4632-502", MCP463x_502 }, | |
| 204 | + { "mcp4632-103", MCP463x_103 }, | |
| 205 | + { "mcp4632-503", MCP463x_503 }, | |
| 206 | + { "mcp4632-104", MCP463x_104 }, | |
| 207 | + { "mcp4651-502", MCP465x_502 }, | |
| 208 | + { "mcp4651-103", MCP465x_103 }, | |
| 209 | + { "mcp4651-503", MCP465x_503 }, | |
| 210 | + { "mcp4651-104", MCP465x_104 }, | |
| 211 | + { "mcp4652-502", MCP465x_502 }, | |
| 212 | + { "mcp4652-103", MCP465x_103 }, | |
| 213 | + { "mcp4652-503", MCP465x_503 }, | |
| 214 | + { "mcp4652-104", MCP465x_104 }, | |
| 215 | + {} | |
| 216 | +}; | |
| 217 | +MODULE_DEVICE_TABLE(i2c, mcp4531_id); | |
| 218 | + | |
| 219 | +static struct i2c_driver mcp4531_driver = { | |
| 220 | + .driver = { | |
| 221 | + .name = "mcp4531", | |
| 222 | + }, | |
| 223 | + .probe = mcp4531_probe, | |
| 224 | + .id_table = mcp4531_id, | |
| 225 | +}; | |
| 226 | + | |
| 227 | +module_i2c_driver(mcp4531_driver); | |
| 228 | + | |
| 229 | +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); | |
| 230 | +MODULE_DESCRIPTION("MCP4531 digital potentiometer"); | |
| 231 | +MODULE_LICENSE("GPL"); | |
| @@ -79,6 +79,19 @@ config MS5611_SPI · 78 unmodified lines | ||
| 79 | 79 | To compile this driver as a module, choose M here: the module will |
| 80 | 80 | be called ms5611_spi. |
| 81 | 81 | |
| 82 | +config MS5637 | |
| 83 | + tristate "Measurement Specialties MS5637 pressure & temperature sensor" | |
| 84 | + depends on I2C | |
| 85 | + select IIO_MS_SENSORS_I2C | |
| 86 | + help | |
| 87 | + If you say yes here you get support for the Measurement Specialties | |
| 88 | + MS5637 pressure and temperature sensor. | |
| 89 | + This driver is also used for MS8607 temperature, pressure & humidity | |
| 90 | + sensor | |
| 91 | + | |
| 92 | + This driver can also be built as a module. If so, the module will | |
| 93 | + be called ms5637. | |
| 94 | + | |
| 82 | 95 | config IIO_ST_PRESS |
| 83 | 96 | tristate "STMicroelectronics pressure sensor Driver" |
| 84 | 97 | depends on (I2C || SPI_MASTER) && SYSFS |
| @@ -10,6 +10,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o · 9 unmodified lines | ||
| 10 | 10 | obj-$(CONFIG_MS5611) += ms5611_core.o |
| 11 | 11 | obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o |
| 12 | 12 | obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o |
| 13 | +obj-$(CONFIG_MS5637) += ms5637.o | |
| 13 | 14 | obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o |
| 14 | 15 | st_pressure-y := st_pressure_core.o |
| 15 | 16 | st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o |
| @@ -0,0 +1,190 @@ | ||
| 1 | +/* | |
| 2 | + * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607 | |
| 3 | + * pressure & temperature sensor | |
| 4 | + * | |
| 5 | + * Copyright (c) 2015 Measurement-Specialties | |
| 6 | + * | |
| 7 | + * Licensed under the GPL-2. | |
| 8 | + * | |
| 9 | + * (7-bit I2C slave address 0x76) | |
| 10 | + * | |
| 11 | + * Datasheet: | |
| 12 | + * http://www.meas-spec.com/downloads/MS5637-02BA03.pdf | |
| 13 | + * Datasheet: | |
| 14 | + * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/init.h> | |
| 18 | +#include <linux/device.h> | |
| 19 | +#include <linux/kernel.h> | |
| 20 | +#include <linux/stat.h> | |
| 21 | +#include <linux/module.h> | |
| 22 | +#include <linux/i2c.h> | |
| 23 | +#include <linux/iio/iio.h> | |
| 24 | +#include <linux/iio/sysfs.h> | |
| 25 | +#include <linux/mutex.h> | |
| 26 | + | |
| 27 | +#include "../common/ms_sensors/ms_sensors_i2c.h" | |
| 28 | + | |
| 29 | +static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 }; | |
| 30 | +/* String copy of the above const for readability purpose */ | |
| 31 | +static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30"; | |
| 32 | + | |
| 33 | +static int ms5637_read_raw(struct iio_dev *indio_dev, | |
| 34 | + struct iio_chan_spec const *channel, int *val, | |
| 35 | + int *val2, long mask) | |
| 36 | +{ | |
| 37 | + int ret; | |
| 38 | + int temperature; | |
| 39 | + unsigned int pressure; | |
| 40 | + struct ms_tp_dev *dev_data = iio_priv(indio_dev); | |
| 41 | + | |
| 42 | + switch (mask) { | |
| 43 | + case IIO_CHAN_INFO_PROCESSED: | |
| 44 | + ret = ms_sensors_read_temp_and_pressure(dev_data, | |
| 45 | + &temperature, | |
| 46 | + &pressure); | |
| 47 | + if (ret) | |
| 48 | + return ret; | |
| 49 | + | |
| 50 | + switch (channel->type) { | |
| 51 | + case IIO_TEMP: /* in milli °C */ | |
| 52 | + *val = temperature; | |
| 53 | + | |
| 54 | + return IIO_VAL_INT; | |
| 55 | + case IIO_PRESSURE: /* in kPa */ | |
| 56 | + *val = pressure / 1000; | |
| 57 | + *val2 = (pressure % 1000) * 1000; | |
| 58 | + | |
| 59 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 60 | + default: | |
| 61 | + return -EINVAL; | |
| 62 | + } | |
| 63 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 64 | + *val = ms5637_samp_freq[dev_data->res_index]; | |
| 65 | + | |
| 66 | + return IIO_VAL_INT; | |
| 67 | + default: | |
| 68 | + return -EINVAL; | |
| 69 | + } | |
| 70 | +} | |
| 71 | + | |
| 72 | +static int ms5637_write_raw(struct iio_dev *indio_dev, | |
| 73 | + struct iio_chan_spec const *chan, | |
| 74 | + int val, int val2, long mask) | |
| 75 | +{ | |
| 76 | + struct ms_tp_dev *dev_data = iio_priv(indio_dev); | |
| 77 | + int i; | |
| 78 | + | |
| 79 | + switch (mask) { | |
| 80 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 81 | + i = ARRAY_SIZE(ms5637_samp_freq); | |
| 82 | + while (i-- > 0) | |
| 83 | + if (val == ms5637_samp_freq[i]) | |
| 84 | + break; | |
| 85 | + if (i < 0) | |
| 86 | + return -EINVAL; | |
| 87 | + dev_data->res_index = i; | |
| 88 | + | |
| 89 | + return 0; | |
| 90 | + default: | |
| 91 | + return -EINVAL; | |
| 92 | + } | |
| 93 | +} | |
| 94 | + | |
| 95 | +static const struct iio_chan_spec ms5637_channels[] = { | |
| 96 | + { | |
| 97 | + .type = IIO_TEMP, | |
| 98 | + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 99 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 100 | + }, | |
| 101 | + { | |
| 102 | + .type = IIO_PRESSURE, | |
| 103 | + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 104 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 105 | + } | |
| 106 | +}; | |
| 107 | + | |
| 108 | +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq); | |
| 109 | + | |
| 110 | +static struct attribute *ms5637_attributes[] = { | |
| 111 | + &iio_const_attr_sampling_frequency_available.dev_attr.attr, | |
| 112 | + NULL, | |
| 113 | +}; | |
| 114 | + | |
| 115 | +static const struct attribute_group ms5637_attribute_group = { | |
| 116 | + .attrs = ms5637_attributes, | |
| 117 | +}; | |
| 118 | + | |
| 119 | +static const struct iio_info ms5637_info = { | |
| 120 | + .read_raw = ms5637_read_raw, | |
| 121 | + .write_raw = ms5637_write_raw, | |
| 122 | + .attrs = &ms5637_attribute_group, | |
| 123 | + .driver_module = THIS_MODULE, | |
| 124 | +}; | |
| 125 | + | |
| 126 | +static int ms5637_probe(struct i2c_client *client, | |
| 127 | + const struct i2c_device_id *id) | |
| 128 | +{ | |
| 129 | + struct ms_tp_dev *dev_data; | |
| 130 | + struct iio_dev *indio_dev; | |
| 131 | + int ret; | |
| 132 | + | |
| 133 | + if (!i2c_check_functionality(client->adapter, | |
| 134 | + I2C_FUNC_SMBUS_READ_WORD_DATA | | |
| 135 | + I2C_FUNC_SMBUS_WRITE_BYTE | | |
| 136 | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | |
| 137 | + dev_err(&client->dev, | |
| 138 | + "Adapter does not support some i2c transaction\n"); | |
| 139 | + return -ENODEV; | |
| 140 | + } | |
| 141 | + | |
| 142 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); | |
| 143 | + if (!indio_dev) | |
| 144 | + return -ENOMEM; | |
| 145 | + | |
| 146 | + dev_data = iio_priv(indio_dev); | |
| 147 | + dev_data->client = client; | |
| 148 | + dev_data->res_index = 5; | |
| 149 | + mutex_init(&dev_data->lock); | |
| 150 | + | |
| 151 | + indio_dev->info = &ms5637_info; | |
| 152 | + indio_dev->name = id->name; | |
| 153 | + indio_dev->dev.parent = &client->dev; | |
| 154 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 155 | + indio_dev->channels = ms5637_channels; | |
| 156 | + indio_dev->num_channels = ARRAY_SIZE(ms5637_channels); | |
| 157 | + | |
| 158 | + i2c_set_clientdata(client, indio_dev); | |
| 159 | + | |
| 160 | + ret = ms_sensors_reset(client, 0x1E, 3000); | |
| 161 | + if (ret) | |
| 162 | + return ret; | |
| 163 | + | |
| 164 | + ret = ms_sensors_tp_read_prom(dev_data); | |
| 165 | + if (ret) | |
| 166 | + return ret; | |
| 167 | + | |
| 168 | + return devm_iio_device_register(&client->dev, indio_dev); | |
| 169 | +} | |
| 170 | + | |
| 171 | +static const struct i2c_device_id ms5637_id[] = { | |
| 172 | + {"ms5637", 0}, | |
| 173 | + {"ms8607-temppressure", 1}, | |
| 174 | + {} | |
| 175 | +}; | |
| 176 | + | |
| 177 | +static struct i2c_driver ms5637_driver = { | |
| 178 | + .probe = ms5637_probe, | |
| 179 | + .id_table = ms5637_id, | |
| 180 | + .driver = { | |
| 181 | + .name = "ms5637" | |
| 182 | + }, | |
| 183 | +}; | |
| 184 | + | |
| 185 | +module_i2c_driver(ms5637_driver); | |
| 186 | + | |
| 187 | +MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver"); | |
| 188 | +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); | |
| 189 | +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); | |
| 190 | +MODULE_LICENSE("GPL v2"); | |
| @@ -400,6 +400,7 @@ static const struct iio_info press_info = { · 399 unmodified lines | ||
| 400 | 400 | .attrs = &st_press_attribute_group, |
| 401 | 401 | .read_raw = &st_press_read_raw, |
| 402 | 402 | .write_raw = &st_press_write_raw, |
| 403 | + .debugfs_reg_access = &st_sensors_debugfs_reg_access, | |
| 403 | 404 | }; |
| 404 | 405 | |
| 405 | 406 | #ifdef CONFIG_IIO_TRIGGER |
| @@ -20,6 +20,18 @@ endmenu · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | menu "Proximity sensors" |
| 22 | 22 | |
| 23 | +config LIDAR_LITE_V2 | |
| 24 | + tristate "PulsedLight LIDAR sensor" | |
| 25 | + select IIO_BUFFER | |
| 26 | + select IIO_TRIGGERED_BUFFER | |
| 27 | + depends on I2C | |
| 28 | + help | |
| 29 | + Say Y to build a driver for PulsedLight LIDAR range finding | |
| 30 | + sensor. | |
| 31 | + | |
| 32 | + To compile this driver as a module, choose M here: the | |
| 33 | + module will be called pulsedlight-lite-v2 | |
| 34 | + | |
| 23 | 35 | config SX9500 |
| 24 | 36 | tristate "SX9500 Semtech proximity sensor" |
| 25 | 37 | select IIO_BUFFER |
| @@ -4,4 +4,5 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | # When adding new entries keep the list in alphabetical order |
| 6 | 6 | obj-$(CONFIG_AS3935) += as3935.o |
| 7 | +obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o | |
| 7 | 8 | obj-$(CONFIG_SX9500) += sx9500.o |
| @@ -434,6 +434,12 @@ static int as3935_remove(struct spi_device *spi) · 433 unmodified lines | ||
| 434 | 434 | return 0; |
| 435 | 435 | } |
| 436 | 436 | |
| 437 | +static const struct of_device_id as3935_of_match[] = { | |
| 438 | + { .compatible = "ams,as3935", }, | |
| 439 | + { /* sentinel */ }, | |
| 440 | +}; | |
| 441 | +MODULE_DEVICE_TABLE(of, as3935_of_match); | |
| 442 | + | |
| 437 | 443 | static const struct spi_device_id as3935_id[] = { |
| 438 | 444 | {"as3935", 0}, |
| 439 | 445 | {}, |
| @@ -443,6 +449,7 @@ MODULE_DEVICE_TABLE(spi, as3935_id); · 3 unmodified lines | ||
| 443 | 449 | static struct spi_driver as3935_driver = { |
| 444 | 450 | .driver = { |
| 445 | 451 | .name = "as3935", |
| 452 | + .of_match_table = of_match_ptr(as3935_of_match), | |
| 446 | 453 | .owner = THIS_MODULE, |
| 447 | 454 | .pm = AS3935_PM_OPS, |
| 448 | 455 | }, |
| @@ -0,0 +1,289 @@ | ||
| 1 | +/* | |
| 2 | + * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor | |
| 3 | + * | |
| 4 | + * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + * | |
| 16 | + * TODO: runtime pm, interrupt mode, and signal strength reporting | |
| 17 | + */ | |
| 18 | + | |
| 19 | +#include <linux/err.h> | |
| 20 | +#include <linux/init.h> | |
| 21 | +#include <linux/i2c.h> | |
| 22 | +#include <linux/delay.h> | |
| 23 | +#include <linux/module.h> | |
| 24 | +#include <linux/iio/iio.h> | |
| 25 | +#include <linux/iio/sysfs.h> | |
| 26 | +#include <linux/iio/buffer.h> | |
| 27 | +#include <linux/iio/trigger.h> | |
| 28 | +#include <linux/iio/triggered_buffer.h> | |
| 29 | +#include <linux/iio/trigger_consumer.h> | |
| 30 | + | |
| 31 | +#define LIDAR_REG_CONTROL 0x00 | |
| 32 | +#define LIDAR_REG_CONTROL_ACQUIRE BIT(2) | |
| 33 | + | |
| 34 | +#define LIDAR_REG_STATUS 0x01 | |
| 35 | +#define LIDAR_REG_STATUS_INVALID BIT(3) | |
| 36 | +#define LIDAR_REG_STATUS_READY BIT(0) | |
| 37 | + | |
| 38 | +#define LIDAR_REG_DATA_HBYTE 0x0f | |
| 39 | +#define LIDAR_REG_DATA_LBYTE 0x10 | |
| 40 | + | |
| 41 | +#define LIDAR_DRV_NAME "lidar" | |
| 42 | + | |
| 43 | +struct lidar_data { | |
| 44 | + struct iio_dev *indio_dev; | |
| 45 | + struct i2c_client *client; | |
| 46 | + | |
| 47 | + u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */ | |
| 48 | +}; | |
| 49 | + | |
| 50 | +static const struct iio_chan_spec lidar_channels[] = { | |
| 51 | + { | |
| 52 | + .type = IIO_DISTANCE, | |
| 53 | + .info_mask_separate = | |
| 54 | + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), | |
| 55 | + .scan_index = 0, | |
| 56 | + .scan_type = { | |
| 57 | + .sign = 'u', | |
| 58 | + .realbits = 16, | |
| 59 | + .storagebits = 16, | |
| 60 | + }, | |
| 61 | + }, | |
| 62 | + IIO_CHAN_SOFT_TIMESTAMP(1), | |
| 63 | +}; | |
| 64 | + | |
| 65 | +static int lidar_read_byte(struct lidar_data *data, int reg) | |
| 66 | +{ | |
| 67 | + struct i2c_client *client = data->client; | |
| 68 | + int ret; | |
| 69 | + | |
| 70 | + /* | |
| 71 | + * Device needs a STOP condition between address write, and data read | |
| 72 | + * so in turn i2c_smbus_read_byte_data cannot be used | |
| 73 | + */ | |
| 74 | + | |
| 75 | + ret = i2c_smbus_write_byte(client, reg); | |
| 76 | + if (ret < 0) { | |
| 77 | + dev_err(&client->dev, "cannot write addr value"); | |
| 78 | + return ret; | |
| 79 | + } | |
| 80 | + | |
| 81 | + ret = i2c_smbus_read_byte(client); | |
| 82 | + if (ret < 0) | |
| 83 | + dev_err(&client->dev, "cannot read data value"); | |
| 84 | + | |
| 85 | + return ret; | |
| 86 | +} | |
| 87 | + | |
| 88 | +static inline int lidar_write_control(struct lidar_data *data, int val) | |
| 89 | +{ | |
| 90 | + return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val); | |
| 91 | +} | |
| 92 | + | |
| 93 | +static int lidar_read_measurement(struct lidar_data *data, u16 *reg) | |
| 94 | +{ | |
| 95 | + int ret; | |
| 96 | + int val; | |
| 97 | + | |
| 98 | + ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE); | |
| 99 | + if (ret < 0) | |
| 100 | + return ret; | |
| 101 | + val = ret << 8; | |
| 102 | + | |
| 103 | + ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE); | |
| 104 | + if (ret < 0) | |
| 105 | + return ret; | |
| 106 | + | |
| 107 | + val |= ret; | |
| 108 | + *reg = val; | |
| 109 | + | |
| 110 | + return 0; | |
| 111 | +} | |
| 112 | + | |
| 113 | +static int lidar_get_measurement(struct lidar_data *data, u16 *reg) | |
| 114 | +{ | |
| 115 | + struct i2c_client *client = data->client; | |
| 116 | + int tries = 10; | |
| 117 | + int ret; | |
| 118 | + | |
| 119 | + /* start sample */ | |
| 120 | + ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE); | |
| 121 | + if (ret < 0) { | |
| 122 | + dev_err(&client->dev, "cannot send start measurement command"); | |
| 123 | + return ret; | |
| 124 | + } | |
| 125 | + | |
| 126 | + while (tries--) { | |
| 127 | + usleep_range(1000, 2000); | |
| 128 | + | |
| 129 | + ret = lidar_read_byte(data, LIDAR_REG_STATUS); | |
| 130 | + if (ret < 0) | |
| 131 | + break; | |
| 132 | + | |
| 133 | + /* return 0 since laser is likely pointed out of range */ | |
| 134 | + if (ret & LIDAR_REG_STATUS_INVALID) { | |
| 135 | + *reg = 0; | |
| 136 | + ret = 0; | |
| 137 | + break; | |
| 138 | + } | |
| 139 | + | |
| 140 | + /* sample ready to read */ | |
| 141 | + if (!(ret & LIDAR_REG_STATUS_READY)) { | |
| 142 | + ret = lidar_read_measurement(data, reg); | |
| 143 | + break; | |
| 144 | + } | |
| 145 | + ret = -EIO; | |
| 146 | + } | |
| 147 | + | |
| 148 | + return ret; | |
| 149 | +} | |
| 150 | + | |
| 151 | +static int lidar_read_raw(struct iio_dev *indio_dev, | |
| 152 | + struct iio_chan_spec const *chan, | |
| 153 | + int *val, int *val2, long mask) | |
| 154 | +{ | |
| 155 | + struct lidar_data *data = iio_priv(indio_dev); | |
| 156 | + int ret = -EINVAL; | |
| 157 | + | |
| 158 | + mutex_lock(&indio_dev->mlock); | |
| 159 | + | |
| 160 | + if (iio_buffer_enabled(indio_dev) && mask == IIO_CHAN_INFO_RAW) { | |
| 161 | + ret = -EBUSY; | |
| 162 | + goto error_busy; | |
| 163 | + } | |
| 164 | + | |
| 165 | + switch (mask) { | |
| 166 | + case IIO_CHAN_INFO_RAW: { | |
| 167 | + u16 reg; | |
| 168 | + | |
| 169 | + ret = lidar_get_measurement(data, ®); | |
| 170 | + if (!ret) { | |
| 171 | + *val = reg; | |
| 172 | + ret = IIO_VAL_INT; | |
| 173 | + } | |
| 174 | + break; | |
| 175 | + } | |
| 176 | + case IIO_CHAN_INFO_SCALE: | |
| 177 | + *val = 0; | |
| 178 | + *val2 = 10000; | |
| 179 | + ret = IIO_VAL_INT_PLUS_MICRO; | |
| 180 | + break; | |
| 181 | + } | |
| 182 | + | |
| 183 | +error_busy: | |
| 184 | + mutex_unlock(&indio_dev->mlock); | |
| 185 | + | |
| 186 | + return ret; | |
| 187 | +} | |
| 188 | + | |
| 189 | +static irqreturn_t lidar_trigger_handler(int irq, void *private) | |
| 190 | +{ | |
| 191 | + struct iio_poll_func *pf = private; | |
| 192 | + struct iio_dev *indio_dev = pf->indio_dev; | |
| 193 | + struct lidar_data *data = iio_priv(indio_dev); | |
| 194 | + int ret; | |
| 195 | + | |
| 196 | + ret = lidar_get_measurement(data, data->buffer); | |
| 197 | + if (!ret) { | |
| 198 | + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | |
| 199 | + iio_get_time_ns()); | |
| 200 | + } else { | |
| 201 | + dev_err(&data->client->dev, "cannot read LIDAR measurement"); | |
| 202 | + } | |
| 203 | + | |
| 204 | + iio_trigger_notify_done(indio_dev->trig); | |
| 205 | + | |
| 206 | + return IRQ_HANDLED; | |
| 207 | +} | |
| 208 | + | |
| 209 | +static const struct iio_info lidar_info = { | |
| 210 | + .driver_module = THIS_MODULE, | |
| 211 | + .read_raw = lidar_read_raw, | |
| 212 | +}; | |
| 213 | + | |
| 214 | +static int lidar_probe(struct i2c_client *client, | |
| 215 | + const struct i2c_device_id *id) | |
| 216 | +{ | |
| 217 | + struct lidar_data *data; | |
| 218 | + struct iio_dev *indio_dev; | |
| 219 | + int ret; | |
| 220 | + | |
| 221 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
| 222 | + if (!indio_dev) | |
| 223 | + return -ENOMEM; | |
| 224 | + | |
| 225 | + indio_dev->info = &lidar_info; | |
| 226 | + indio_dev->name = LIDAR_DRV_NAME; | |
| 227 | + indio_dev->channels = lidar_channels; | |
| 228 | + indio_dev->num_channels = ARRAY_SIZE(lidar_channels); | |
| 229 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 230 | + | |
| 231 | + data = iio_priv(indio_dev); | |
| 232 | + i2c_set_clientdata(client, indio_dev); | |
| 233 | + | |
| 234 | + data->client = client; | |
| 235 | + data->indio_dev = indio_dev; | |
| 236 | + | |
| 237 | + ret = iio_triggered_buffer_setup(indio_dev, NULL, | |
| 238 | + lidar_trigger_handler, NULL); | |
| 239 | + if (ret) | |
| 240 | + return ret; | |
| 241 | + | |
| 242 | + ret = iio_device_register(indio_dev); | |
| 243 | + if (ret) | |
| 244 | + goto error_unreg_buffer; | |
| 245 | + | |
| 246 | + return 0; | |
| 247 | + | |
| 248 | +error_unreg_buffer: | |
| 249 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 250 | + | |
| 251 | + return ret; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static int lidar_remove(struct i2c_client *client) | |
| 255 | +{ | |
| 256 | + struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
| 257 | + | |
| 258 | + iio_device_unregister(indio_dev); | |
| 259 | + iio_triggered_buffer_cleanup(indio_dev); | |
| 260 | + | |
| 261 | + return 0; | |
| 262 | +} | |
| 263 | + | |
| 264 | +static const struct i2c_device_id lidar_id[] = { | |
| 265 | + {"lidar-lite-v2", 0}, | |
| 266 | + { }, | |
| 267 | +}; | |
| 268 | +MODULE_DEVICE_TABLE(i2c, lidar_id); | |
| 269 | + | |
| 270 | +static const struct of_device_id lidar_dt_ids[] = { | |
| 271 | + { .compatible = "pulsedlight,lidar-lite-v2" }, | |
| 272 | + { } | |
| 273 | +}; | |
| 274 | +MODULE_DEVICE_TABLE(of, lidar_dt_ids); | |
| 275 | + | |
| 276 | +static struct i2c_driver lidar_driver = { | |
| 277 | + .driver = { | |
| 278 | + .name = LIDAR_DRV_NAME, | |
| 279 | + .of_match_table = of_match_ptr(lidar_dt_ids), | |
| 280 | + }, | |
| 281 | + .probe = lidar_probe, | |
| 282 | + .remove = lidar_remove, | |
| 283 | + .id_table = lidar_id, | |
| 284 | +}; | |
| 285 | +module_i2c_driver(lidar_driver); | |
| 286 | + | |
| 287 | +MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); | |
| 288 | +MODULE_DESCRIPTION("PulsedLight LIDAR sensor"); | |
| 289 | +MODULE_LICENSE("GPL"); | |
| @@ -868,21 +868,12 @@ static void sx9500_gpio_probe(struct i2c_client *client, · 867 unmodified lines | ||
| 868 | 868 | struct sx9500_data *data) |
| 869 | 869 | { |
| 870 | 870 | struct device *dev; |
| 871 | − struct gpio_desc *gpio; | |
| 872 | 871 | |
| 873 | 872 | if (!client) |
| 874 | 873 | return; |
| 875 | 874 | |
| 876 | 875 | dev = &client->dev; |
| 877 | 876 | |
| 878 | − if (client->irq <= 0) { | |
| 879 | − gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN); | |
| 880 | − if (IS_ERR(gpio)) | |
| 881 | − dev_err(dev, "gpio get irq failed\n"); | |
| 882 | − else | |
| 883 | − client->irq = gpiod_to_irq(gpio); | |
| 884 | − } | |
| 885 | − | |
| 886 | 877 | data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET, |
| 887 | 878 | 0, GPIOD_OUT_HIGH); |
| 888 | 879 | if (IS_ERR(data->gpiod_rst)) { |
| @@ -23,4 +23,26 @@ config TMP006 · 22 unmodified lines | ||
| 23 | 23 | This driver can also be built as a module. If so, the module will |
| 24 | 24 | be called tmp006. |
| 25 | 25 | |
| 26 | +config TSYS01 | |
| 27 | + tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" | |
| 28 | + depends on I2C | |
| 29 | + select IIO_MS_SENSORS_I2C | |
| 30 | + help | |
| 31 | + If you say yes here you get support for the Measurement Specialties | |
| 32 | + TSYS01 I2C temperature sensor. | |
| 33 | + | |
| 34 | + This driver can also be built as a module. If so, the module will | |
| 35 | + be called tsys01. | |
| 36 | + | |
| 37 | +config TSYS02D | |
| 38 | + tristate "Measurement Specialties TSYS02D temperature sensor" | |
| 39 | + depends on I2C | |
| 40 | + select IIO_MS_SENSORS_I2C | |
| 41 | + help | |
| 42 | + If you say yes here you get support for the Measurement Specialties | |
| 43 | + TSYS02D temperature sensor. | |
| 44 | + | |
| 45 | + This driver can also be built as a module. If so, the module will | |
| 46 | + be called tsys02d. | |
| 47 | + | |
| 26 | 48 | endmenu |
| @@ -4,3 +4,5 @@ · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | obj-$(CONFIG_MLX90614) += mlx90614.o |
| 6 | 6 | obj-$(CONFIG_TMP006) += tmp006.o |
| 7 | +obj-$(CONFIG_TSYS01) += tsys01.o | |
| 8 | +obj-$(CONFIG_TSYS02D) += tsys02d.o | |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * |
| 4 | 4 | * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> |
| 5 | 5 | * Copyright (c) 2015 Essensium NV |
| 6 | + * Copyright (c) 2015 Melexis | |
| 6 | 7 | * |
| 7 | 8 | * This file is subject to the terms and conditions of version 2 of |
| 8 | 9 | * the GNU General Public License. See the file COPYING in the main |
| @@ -20,7 +21,6 @@ · 11 unmodified lines | ||
| 20 | 21 | * always has a pull-up so we do not need an extra GPIO to drive it high. If |
| 21 | 22 | * the "wakeup" GPIO is not given, power management will be disabled. |
| 22 | 23 | * |
| 23 | − * TODO: filter configuration | |
| 24 | 24 | */ |
| 25 | 25 | |
| 26 | 26 | #include <linux/err.h> |
| @@ -32,6 +32,7 @@ · 5 unmodified lines | ||
| 32 | 32 | #include <linux/pm_runtime.h> |
| 33 | 33 | |
| 34 | 34 | #include <linux/iio/iio.h> |
| 35 | +#include <linux/iio/sysfs.h> | |
| 35 | 36 | |
| 36 | 37 | #define MLX90614_OP_RAM 0x00 |
| 37 | 38 | #define MLX90614_OP_EEPROM 0x20 |
| @@ -71,6 +72,7 @@ · 33 unmodified lines | ||
| 71 | 72 | #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ |
| 72 | 73 | #define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */ |
| 73 | 74 | #define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */ |
| 75 | +#define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ | |
| 74 | 76 | |
| 75 | 77 | struct mlx90614_data { |
| 76 | 78 | struct i2c_client *client; |
| @@ -79,6 +81,20 @@ struct mlx90614_data { · 2 unmodified lines | ||
| 79 | 81 | unsigned long ready_timestamp; /* in jiffies */ |
| 80 | 82 | }; |
| 81 | 83 | |
| 84 | +/* Bandwidth values for IIR filtering */ | |
| 85 | +static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86}; | |
| 86 | +static IIO_CONST_ATTR(in_temp_object_filter_low_pass_3db_frequency_available, | |
| 87 | + "0.15 0.20 0.31 0.77 0.86 1.10 1.53 7.23"); | |
| 88 | + | |
| 89 | +static struct attribute *mlx90614_attributes[] = { | |
| 90 | + &iio_const_attr_in_temp_object_filter_low_pass_3db_frequency_available.dev_attr.attr, | |
| 91 | + NULL, | |
| 92 | +}; | |
| 93 | + | |
| 94 | +static const struct attribute_group mlx90614_attr_group = { | |
| 95 | + .attrs = mlx90614_attributes, | |
| 96 | +}; | |
| 97 | + | |
| 82 | 98 | /* |
| 83 | 99 | * Erase an address and write word. |
| 84 | 100 | * The mutex must be locked before calling. |
| @@ -117,6 +133,43 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command, · 32 unmodified lines | ||
| 117 | 133 | return ret; |
| 118 | 134 | } |
| 119 | 135 | |
| 136 | +/* | |
| 137 | + * Find the IIR value inside mlx90614_iir_values array and return its position | |
| 138 | + * which is equivalent to the bit value in sensor register | |
| 139 | + */ | |
| 140 | +static inline s32 mlx90614_iir_search(const struct i2c_client *client, | |
| 141 | + int value) | |
| 142 | +{ | |
| 143 | + int i; | |
| 144 | + s32 ret; | |
| 145 | + | |
| 146 | + for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) { | |
| 147 | + if (value == mlx90614_iir_values[i]) | |
| 148 | + break; | |
| 149 | + } | |
| 150 | + | |
| 151 | + if (i == ARRAY_SIZE(mlx90614_iir_values)) | |
| 152 | + return -EINVAL; | |
| 153 | + | |
| 154 | + /* | |
| 155 | + * CONFIG register values must not be changed so | |
| 156 | + * we must read them before we actually write | |
| 157 | + * changes | |
| 158 | + */ | |
| 159 | + ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG); | |
| 160 | + if (ret < 0) | |
| 161 | + return ret; | |
| 162 | + | |
| 163 | + ret &= ~MLX90614_CONFIG_FIR_MASK; | |
| 164 | + ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT; | |
| 165 | + ret &= ~MLX90614_CONFIG_IIR_MASK; | |
| 166 | + ret |= i << MLX90614_CONFIG_IIR_SHIFT; | |
| 167 | + | |
| 168 | + /* Write changed values */ | |
| 169 | + ret = mlx90614_write_word(client, MLX90614_CONFIG, ret); | |
| 170 | + return ret; | |
| 171 | +} | |
| 172 | + | |
| 120 | 173 | #ifdef CONFIG_PM |
| 121 | 174 | /* |
| 122 | 175 | * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since |
| @@ -236,6 +289,21 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, · 113 unmodified lines | ||
| 236 | 289 | *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION; |
| 237 | 290 | } |
| 238 | 291 | return IIO_VAL_INT_PLUS_NANO; |
| 292 | + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with | |
| 293 | + FIR = 1024 */ | |
| 294 | + mlx90614_power_get(data, false); | |
| 295 | + mutex_lock(&data->lock); | |
| 296 | + ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); | |
| 297 | + mutex_unlock(&data->lock); | |
| 298 | + mlx90614_power_put(data); | |
| 299 | + | |
| 300 | + if (ret < 0) | |
| 301 | + return ret; | |
| 302 | + | |
| 303 | + *val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100; | |
| 304 | + *val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) * | |
| 305 | + 10000; | |
| 306 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 239 | 307 | default: |
| 240 | 308 | return -EINVAL; |
| 241 | 309 | } |
| @@ -262,6 +330,18 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, · 20 unmodified lines | ||
| 262 | 330 | mutex_unlock(&data->lock); |
| 263 | 331 | mlx90614_power_put(data); |
| 264 | 332 | |
| 333 | + return ret; | |
| 334 | + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR Filter setting */ | |
| 335 | + if (val < 0 || val2 < 0) | |
| 336 | + return -EINVAL; | |
| 337 | + | |
| 338 | + mlx90614_power_get(data, false); | |
| 339 | + mutex_lock(&data->lock); | |
| 340 | + ret = mlx90614_iir_search(data->client, | |
| 341 | + val * 100 + val2 / 10000); | |
| 342 | + mutex_unlock(&data->lock); | |
| 343 | + mlx90614_power_put(data); | |
| 344 | + | |
| 265 | 345 | return ret; |
| 266 | 346 | default: |
| 267 | 347 | return -EINVAL; |
| @@ -275,6 +355,8 @@ static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev, · 7 unmodified lines | ||
| 275 | 355 | switch (mask) { |
| 276 | 356 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
| 277 | 357 | return IIO_VAL_INT_PLUS_NANO; |
| 358 | + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
| 359 | + return IIO_VAL_INT_PLUS_MICRO; | |
| 278 | 360 | default: |
| 279 | 361 | return -EINVAL; |
| 280 | 362 | } |
| @@ -294,7 +376,8 @@ static const struct iio_chan_spec mlx90614_channels[] = { · 13 unmodified lines | ||
| 294 | 376 | .modified = 1, |
| 295 | 377 | .channel2 = IIO_MOD_TEMP_OBJECT, |
| 296 | 378 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 297 | − BIT(IIO_CHAN_INFO_CALIBEMISSIVITY), | |
| 379 | + BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | | |
| 380 | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), | |
| 298 | 381 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | |
| 299 | 382 | BIT(IIO_CHAN_INFO_SCALE), |
| 300 | 383 | }, |
| @@ -305,7 +388,8 @@ static const struct iio_chan_spec mlx90614_channels[] = { · 4 unmodified lines | ||
| 305 | 388 | .channel = 1, |
| 306 | 389 | .channel2 = IIO_MOD_TEMP_OBJECT, |
| 307 | 390 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
| 308 | − BIT(IIO_CHAN_INFO_CALIBEMISSIVITY), | |
| 391 | + BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | | |
| 392 | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), | |
| 309 | 393 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | |
| 310 | 394 | BIT(IIO_CHAN_INFO_SCALE), |
| 311 | 395 | }, |
| @@ -315,6 +399,7 @@ static const struct iio_info mlx90614_info = { · 3 unmodified lines | ||
| 315 | 399 | .read_raw = mlx90614_read_raw, |
| 316 | 400 | .write_raw = mlx90614_write_raw, |
| 317 | 401 | .write_raw_get_fmt = mlx90614_write_raw_get_fmt, |
| 402 | + .attrs = &mlx90614_attr_group, | |
| 318 | 403 | .driver_module = THIS_MODULE, |
| 319 | 404 | }; |
| 320 | 405 | |
| @@ -569,5 +654,6 @@ module_i2c_driver(mlx90614_driver); · 248 unmodified lines | ||
| 569 | 654 | |
| 570 | 655 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); |
| 571 | 656 | MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>"); |
| 657 | +MODULE_AUTHOR("Crt Mori <cmo@melexis.com>"); | |
| 572 | 658 | MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver"); |
| 573 | 659 | MODULE_LICENSE("GPL"); |
| @@ -0,0 +1,230 @@ | ||
| 1 | +/* | |
| 2 | + * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor | |
| 3 | + * | |
| 4 | + * Copyright (c) 2015 Measurement-Specialties | |
| 5 | + * | |
| 6 | + * Licensed under the GPL-2. | |
| 7 | + * | |
| 8 | + * Datasheet: | |
| 9 | + * http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/iio/iio.h> | |
| 13 | +#include <linux/iio/sysfs.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/mutex.h> | |
| 16 | +#include <linux/module.h> | |
| 17 | +#include <linux/init.h> | |
| 18 | +#include <linux/kernel.h> | |
| 19 | +#include <linux/stat.h> | |
| 20 | +#include "../common/ms_sensors/ms_sensors_i2c.h" | |
| 21 | + | |
| 22 | +/* TSYS01 Commands */ | |
| 23 | +#define TSYS01_RESET 0x1E | |
| 24 | +#define TSYS01_CONVERSION_START 0x48 | |
| 25 | +#define TSYS01_ADC_READ 0x00 | |
| 26 | +#define TSYS01_PROM_READ 0xA0 | |
| 27 | + | |
| 28 | +#define TSYS01_PROM_WORDS_NB 8 | |
| 29 | + | |
| 30 | +struct tsys01_dev { | |
| 31 | + void *client; | |
| 32 | + struct mutex lock; /* lock during conversion */ | |
| 33 | + | |
| 34 | + int (*reset)(void *cli, u8 cmd, unsigned int delay); | |
| 35 | + int (*convert_and_read)(void *cli, u8 conv, u8 rd, | |
| 36 | + unsigned int delay, u32 *adc); | |
| 37 | + int (*read_prom_word)(void *cli, int cmd, u16 *word); | |
| 38 | + | |
| 39 | + u16 prom[TSYS01_PROM_WORDS_NB]; | |
| 40 | +}; | |
| 41 | + | |
| 42 | +/* Multiplication coefficients for temperature computation */ | |
| 43 | +static const int coeff_mul[] = { -1500000, 1000000, -2000000, | |
| 44 | + 4000000, -2000000 }; | |
| 45 | + | |
| 46 | +static int tsys01_read_temperature(struct iio_dev *indio_dev, | |
| 47 | + s32 *temperature) | |
| 48 | +{ | |
| 49 | + int ret, i; | |
| 50 | + u32 adc; | |
| 51 | + s64 temp = 0; | |
| 52 | + struct tsys01_dev *dev_data = iio_priv(indio_dev); | |
| 53 | + | |
| 54 | + mutex_lock(&dev_data->lock); | |
| 55 | + ret = dev_data->convert_and_read(dev_data->client, | |
| 56 | + TSYS01_CONVERSION_START, | |
| 57 | + TSYS01_ADC_READ, 9000, &adc); | |
| 58 | + mutex_unlock(&dev_data->lock); | |
| 59 | + if (ret) | |
| 60 | + return ret; | |
| 61 | + | |
| 62 | + adc >>= 8; | |
| 63 | + | |
| 64 | + /* Temperature algorithm */ | |
| 65 | + for (i = 4; i > 0; i--) { | |
| 66 | + temp += coeff_mul[i] * | |
| 67 | + (s64)dev_data->prom[5 - i]; | |
| 68 | + temp *= (s64)adc; | |
| 69 | + temp = div64_s64(temp, 100000); | |
| 70 | + } | |
| 71 | + temp *= 10; | |
| 72 | + temp += coeff_mul[0] * (s64)dev_data->prom[5]; | |
| 73 | + temp = div64_s64(temp, 100000); | |
| 74 | + | |
| 75 | + *temperature = temp; | |
| 76 | + | |
| 77 | + return 0; | |
| 78 | +} | |
| 79 | + | |
| 80 | +static int tsys01_read_raw(struct iio_dev *indio_dev, | |
| 81 | + struct iio_chan_spec const *channel, int *val, | |
| 82 | + int *val2, long mask) | |
| 83 | +{ | |
| 84 | + int ret; | |
| 85 | + s32 temperature; | |
| 86 | + | |
| 87 | + switch (mask) { | |
| 88 | + case IIO_CHAN_INFO_PROCESSED: | |
| 89 | + switch (channel->type) { | |
| 90 | + case IIO_TEMP: /* in milli °C */ | |
| 91 | + ret = tsys01_read_temperature(indio_dev, &temperature); | |
| 92 | + if (ret) | |
| 93 | + return ret; | |
| 94 | + *val = temperature; | |
| 95 | + | |
| 96 | + return IIO_VAL_INT; | |
| 97 | + default: | |
| 98 | + return -EINVAL; | |
| 99 | + } | |
| 100 | + default: | |
| 101 | + return -EINVAL; | |
| 102 | + } | |
| 103 | +} | |
| 104 | + | |
| 105 | +static const struct iio_chan_spec tsys01_channels[] = { | |
| 106 | + { | |
| 107 | + .type = IIO_TEMP, | |
| 108 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 109 | + } | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static const struct iio_info tsys01_info = { | |
| 113 | + .read_raw = tsys01_read_raw, | |
| 114 | + .driver_module = THIS_MODULE, | |
| 115 | +}; | |
| 116 | + | |
| 117 | +static bool tsys01_crc_valid(u16 *n_prom) | |
| 118 | +{ | |
| 119 | + u8 cnt; | |
| 120 | + u8 sum = 0; | |
| 121 | + | |
| 122 | + for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++) | |
| 123 | + sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF)); | |
| 124 | + | |
| 125 | + return (sum == 0); | |
| 126 | +} | |
| 127 | + | |
| 128 | +static int tsys01_read_prom(struct iio_dev *indio_dev) | |
| 129 | +{ | |
| 130 | + int i, ret; | |
| 131 | + struct tsys01_dev *dev_data = iio_priv(indio_dev); | |
| 132 | + char buf[7 * TSYS01_PROM_WORDS_NB + 1]; | |
| 133 | + char *ptr = buf; | |
| 134 | + | |
| 135 | + for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) { | |
| 136 | + ret = dev_data->read_prom_word(dev_data->client, | |
| 137 | + TSYS01_PROM_READ + (i << 1), | |
| 138 | + &dev_data->prom[i]); | |
| 139 | + if (ret) | |
| 140 | + return ret; | |
| 141 | + | |
| 142 | + ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]); | |
| 143 | + ptr += ret; | |
| 144 | + } | |
| 145 | + | |
| 146 | + if (!tsys01_crc_valid(dev_data->prom)) { | |
| 147 | + dev_err(&indio_dev->dev, "prom crc check error\n"); | |
| 148 | + return -ENODEV; | |
| 149 | + } | |
| 150 | + *ptr = 0; | |
| 151 | + dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf); | |
| 152 | + | |
| 153 | + return 0; | |
| 154 | +} | |
| 155 | + | |
| 156 | +static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev) | |
| 157 | +{ | |
| 158 | + int ret; | |
| 159 | + struct tsys01_dev *dev_data = iio_priv(indio_dev); | |
| 160 | + | |
| 161 | + mutex_init(&dev_data->lock); | |
| 162 | + | |
| 163 | + indio_dev->info = &tsys01_info; | |
| 164 | + indio_dev->name = dev->driver->name; | |
| 165 | + indio_dev->dev.parent = dev; | |
| 166 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 167 | + indio_dev->channels = tsys01_channels; | |
| 168 | + indio_dev->num_channels = ARRAY_SIZE(tsys01_channels); | |
| 169 | + | |
| 170 | + ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000); | |
| 171 | + if (ret) | |
| 172 | + return ret; | |
| 173 | + | |
| 174 | + ret = tsys01_read_prom(indio_dev); | |
| 175 | + if (ret) | |
| 176 | + return ret; | |
| 177 | + | |
| 178 | + return devm_iio_device_register(dev, indio_dev); | |
| 179 | +} | |
| 180 | + | |
| 181 | +static int tsys01_i2c_probe(struct i2c_client *client, | |
| 182 | + const struct i2c_device_id *id) | |
| 183 | +{ | |
| 184 | + struct tsys01_dev *dev_data; | |
| 185 | + struct iio_dev *indio_dev; | |
| 186 | + | |
| 187 | + if (!i2c_check_functionality(client->adapter, | |
| 188 | + I2C_FUNC_SMBUS_WORD_DATA | | |
| 189 | + I2C_FUNC_SMBUS_WRITE_BYTE | | |
| 190 | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | |
| 191 | + dev_err(&client->dev, | |
| 192 | + "Adapter does not support some i2c transaction\n"); | |
| 193 | + return -ENODEV; | |
| 194 | + } | |
| 195 | + | |
| 196 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); | |
| 197 | + if (!indio_dev) | |
| 198 | + return -ENOMEM; | |
| 199 | + | |
| 200 | + dev_data = iio_priv(indio_dev); | |
| 201 | + dev_data->client = client; | |
| 202 | + dev_data->reset = ms_sensors_reset; | |
| 203 | + dev_data->read_prom_word = ms_sensors_read_prom_word; | |
| 204 | + dev_data->convert_and_read = ms_sensors_convert_and_read; | |
| 205 | + | |
| 206 | + i2c_set_clientdata(client, indio_dev); | |
| 207 | + | |
| 208 | + return tsys01_probe(indio_dev, &client->dev); | |
| 209 | +} | |
| 210 | + | |
| 211 | +static const struct i2c_device_id tsys01_id[] = { | |
| 212 | + {"tsys01", 0}, | |
| 213 | + {} | |
| 214 | +}; | |
| 215 | +MODULE_DEVICE_TABLE(i2c, tsys01_id); | |
| 216 | + | |
| 217 | +static struct i2c_driver tsys01_driver = { | |
| 218 | + .probe = tsys01_i2c_probe, | |
| 219 | + .id_table = tsys01_id, | |
| 220 | + .driver = { | |
| 221 | + .name = "tsys01", | |
| 222 | + }, | |
| 223 | +}; | |
| 224 | + | |
| 225 | +module_i2c_driver(tsys01_driver); | |
| 226 | + | |
| 227 | +MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver"); | |
| 228 | +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); | |
| 229 | +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); | |
| 230 | +MODULE_LICENSE("GPL v2"); | |
| @@ -0,0 +1,191 @@ | ||
| 1 | +/* | |
| 2 | + * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor | |
| 3 | + * | |
| 4 | + * Copyright (c) 2015 Measurement-Specialties | |
| 5 | + * | |
| 6 | + * Licensed under the GPL-2. | |
| 7 | + * | |
| 8 | + * (7-bit I2C slave address 0x40) | |
| 9 | + * | |
| 10 | + * Datasheet: | |
| 11 | + * http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf | |
| 12 | + */ | |
| 13 | + | |
| 14 | +#include <linux/init.h> | |
| 15 | +#include <linux/device.h> | |
| 16 | +#include <linux/kernel.h> | |
| 17 | +#include <linux/stat.h> | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/iio/iio.h> | |
| 20 | +#include <linux/iio/sysfs.h> | |
| 21 | + | |
| 22 | +#include "../common/ms_sensors/ms_sensors_i2c.h" | |
| 23 | + | |
| 24 | +#define TSYS02D_RESET 0xFE | |
| 25 | + | |
| 26 | +static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 }; | |
| 27 | +/* String copy of the above const for readability purpose */ | |
| 28 | +static const char tsys02d_show_samp_freq[] = "20 40 70 140"; | |
| 29 | + | |
| 30 | +static int tsys02d_read_raw(struct iio_dev *indio_dev, | |
| 31 | + struct iio_chan_spec const *channel, int *val, | |
| 32 | + int *val2, long mask) | |
| 33 | +{ | |
| 34 | + int ret; | |
| 35 | + s32 temperature; | |
| 36 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 37 | + | |
| 38 | + switch (mask) { | |
| 39 | + case IIO_CHAN_INFO_PROCESSED: | |
| 40 | + switch (channel->type) { | |
| 41 | + case IIO_TEMP: /* in milli °C */ | |
| 42 | + ret = ms_sensors_ht_read_temperature(dev_data, | |
| 43 | + &temperature); | |
| 44 | + if (ret) | |
| 45 | + return ret; | |
| 46 | + *val = temperature; | |
| 47 | + | |
| 48 | + return IIO_VAL_INT; | |
| 49 | + default: | |
| 50 | + return -EINVAL; | |
| 51 | + } | |
| 52 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 53 | + *val = tsys02d_samp_freq[dev_data->res_index]; | |
| 54 | + | |
| 55 | + return IIO_VAL_INT; | |
| 56 | + default: | |
| 57 | + return -EINVAL; | |
| 58 | + } | |
| 59 | +} | |
| 60 | + | |
| 61 | +static int tsys02d_write_raw(struct iio_dev *indio_dev, | |
| 62 | + struct iio_chan_spec const *chan, | |
| 63 | + int val, int val2, long mask) | |
| 64 | +{ | |
| 65 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 66 | + int i, ret; | |
| 67 | + | |
| 68 | + switch (mask) { | |
| 69 | + case IIO_CHAN_INFO_SAMP_FREQ: | |
| 70 | + i = ARRAY_SIZE(tsys02d_samp_freq); | |
| 71 | + while (i-- > 0) | |
| 72 | + if (val == tsys02d_samp_freq[i]) | |
| 73 | + break; | |
| 74 | + if (i < 0) | |
| 75 | + return -EINVAL; | |
| 76 | + mutex_lock(&dev_data->lock); | |
| 77 | + dev_data->res_index = i; | |
| 78 | + ret = ms_sensors_write_resolution(dev_data, i); | |
| 79 | + mutex_unlock(&dev_data->lock); | |
| 80 | + | |
| 81 | + return ret; | |
| 82 | + default: | |
| 83 | + return -EINVAL; | |
| 84 | + } | |
| 85 | +} | |
| 86 | + | |
| 87 | +static const struct iio_chan_spec tsys02d_channels[] = { | |
| 88 | + { | |
| 89 | + .type = IIO_TEMP, | |
| 90 | + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED), | |
| 91 | + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), | |
| 92 | + } | |
| 93 | +}; | |
| 94 | + | |
| 95 | +static ssize_t tsys02_read_battery_low(struct device *dev, | |
| 96 | + struct device_attribute *attr, | |
| 97 | + char *buf) | |
| 98 | +{ | |
| 99 | + struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
| 100 | + struct ms_ht_dev *dev_data = iio_priv(indio_dev); | |
| 101 | + | |
| 102 | + return ms_sensors_show_battery_low(dev_data, buf); | |
| 103 | +} | |
| 104 | + | |
| 105 | +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq); | |
| 106 | +static IIO_DEVICE_ATTR(battery_low, S_IRUGO, | |
| 107 | + tsys02_read_battery_low, NULL, 0); | |
| 108 | + | |
| 109 | +static struct attribute *tsys02d_attributes[] = { | |
| 110 | + &iio_const_attr_sampling_frequency_available.dev_attr.attr, | |
| 111 | + &iio_dev_attr_battery_low.dev_attr.attr, | |
| 112 | + NULL, | |
| 113 | +}; | |
| 114 | + | |
| 115 | +static const struct attribute_group tsys02d_attribute_group = { | |
| 116 | + .attrs = tsys02d_attributes, | |
| 117 | +}; | |
| 118 | + | |
| 119 | +static const struct iio_info tsys02d_info = { | |
| 120 | + .read_raw = tsys02d_read_raw, | |
| 121 | + .write_raw = tsys02d_write_raw, | |
| 122 | + .attrs = &tsys02d_attribute_group, | |
| 123 | + .driver_module = THIS_MODULE, | |
| 124 | +}; | |
| 125 | + | |
| 126 | +static int tsys02d_probe(struct i2c_client *client, | |
| 127 | + const struct i2c_device_id *id) | |
| 128 | +{ | |
| 129 | + struct ms_ht_dev *dev_data; | |
| 130 | + struct iio_dev *indio_dev; | |
| 131 | + int ret; | |
| 132 | + u64 serial_number; | |
| 133 | + | |
| 134 | + if (!i2c_check_functionality(client->adapter, | |
| 135 | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | | |
| 136 | + I2C_FUNC_SMBUS_WRITE_BYTE | | |
| 137 | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | |
| 138 | + dev_err(&client->dev, | |
| 139 | + "Adapter does not support some i2c transaction\n"); | |
| 140 | + return -ENODEV; | |
| 141 | + } | |
| 142 | + | |
| 143 | + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); | |
| 144 | + if (!indio_dev) | |
| 145 | + return -ENOMEM; | |
| 146 | + | |
| 147 | + dev_data = iio_priv(indio_dev); | |
| 148 | + dev_data->client = client; | |
| 149 | + dev_data->res_index = 0; | |
| 150 | + mutex_init(&dev_data->lock); | |
| 151 | + | |
| 152 | + indio_dev->info = &tsys02d_info; | |
| 153 | + indio_dev->name = id->name; | |
| 154 | + indio_dev->dev.parent = &client->dev; | |
| 155 | + indio_dev->modes = INDIO_DIRECT_MODE; | |
| 156 | + indio_dev->channels = tsys02d_channels; | |
| 157 | + indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels); | |
| 158 | + | |
| 159 | + i2c_set_clientdata(client, indio_dev); | |
| 160 | + | |
| 161 | + ret = ms_sensors_reset(client, TSYS02D_RESET, 15000); | |
| 162 | + if (ret) | |
| 163 | + return ret; | |
| 164 | + | |
| 165 | + ret = ms_sensors_read_serial(client, &serial_number); | |
| 166 | + if (ret) | |
| 167 | + return ret; | |
| 168 | + dev_info(&client->dev, "Serial number : %llx", serial_number); | |
| 169 | + | |
| 170 | + return devm_iio_device_register(&client->dev, indio_dev); | |
| 171 | +} | |
| 172 | + | |
| 173 | +static const struct i2c_device_id tsys02d_id[] = { | |
| 174 | + {"tsys02d", 0}, | |
| 175 | + {} | |
| 176 | +}; | |
| 177 | + | |
| 178 | +static struct i2c_driver tsys02d_driver = { | |
| 179 | + .probe = tsys02d_probe, | |
| 180 | + .id_table = tsys02d_id, | |
| 181 | + .driver = { | |
| 182 | + .name = "tsys02d", | |
| 183 | + }, | |
| 184 | +}; | |
| 185 | + | |
| 186 | +module_i2c_driver(tsys02d_driver); | |
| 187 | + | |
| 188 | +MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver"); | |
| 189 | +MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); | |
| 190 | +MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); | |
| 191 | +MODULE_LICENSE("GPL v2"); | |
| @@ -62,8 +62,6 @@ source "drivers/staging/xgifb/Kconfig" · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | source "drivers/staging/emxx_udc/Kconfig" |
| 64 | 64 | |
| 65 | −source "drivers/staging/ft1000/Kconfig" | |
| 66 | − | |
| 67 | 65 | source "drivers/staging/speakup/Kconfig" |
| 68 | 66 | |
| 69 | 67 | source "drivers/staging/ste_rmi4/Kconfig" |
| @@ -25,7 +25,6 @@ obj-$(CONFIG_IIO) += iio/ · 24 unmodified lines | ||
| 25 | 25 | obj-$(CONFIG_FB_SM750) += sm750fb/ |
| 26 | 26 | obj-$(CONFIG_FB_XGI) += xgifb/ |
| 27 | 27 | obj-$(CONFIG_USB_EMXX) += emxx_udc/ |
| 28 | −obj-$(CONFIG_FT1000) += ft1000/ | |
| 29 | 28 | obj-$(CONFIG_SPEAKUP) += speakup/ |
| 30 | 29 | obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ |
| 31 | 30 | obj-$(CONFIG_MFD_NVEC) += nvec/ |
| @@ -54,7 +54,7 @@ config SW_SYNC · 53 unmodified lines | ||
| 54 | 54 | depends on SYNC |
| 55 | 55 | ---help--- |
| 56 | 56 | A sync object driver that uses a 32bit counter to coordinate |
| 57 | − syncrhronization. Useful when there is no hardware primitive backing | |
| 57 | + synchronization. Useful when there is no hardware primitive backing | |
| 58 | 58 | the synchronization. |
| 59 | 59 | |
| 60 | 60 | config SW_SYNC_USER |
| @@ -18,7 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #define pr_fmt(fmt) "ashmem: " fmt |
| 20 | 20 | |
| 21 | −#include <linux/module.h> | |
| 21 | +#include <linux/init.h> | |
| 22 | +#include <linux/export.h> | |
| 22 | 23 | #include <linux/file.h> |
| 23 | 24 | #include <linux/fs.h> |
| 24 | 25 | #include <linux/falloc.h> |
| @@ -43,7 +44,7 @@ · 18 unmodified lines | ||
| 43 | 44 | * @unpinned_list: The list of all ashmem areas |
| 44 | 45 | * @file: The shmem-based backing file |
| 45 | 46 | * @size: The size of the mapping, in bytes |
| 46 | − * @prot_masks: The allowed protection bits, as vm_flags | |
| 47 | + * @prot_mask: The allowed protection bits, as vm_flags | |
| 47 | 48 | * |
| 48 | 49 | * The lifecycle of this structure is from our parent file's open() until |
| 49 | 50 | * its release(). It is also protected by 'ashmem_mutex' |
| @@ -82,14 +83,14 @@ struct ashmem_range { · 32 unmodified lines | ||
| 82 | 83 | /* LRU list of unpinned pages, protected by ashmem_mutex */ |
| 83 | 84 | static LIST_HEAD(ashmem_lru_list); |
| 84 | 85 | |
| 85 | −/** | |
| 86 | +/* | |
| 86 | 87 | * long lru_count - The count of pages on our LRU list. |
| 87 | 88 | * |
| 88 | 89 | * This is protected by ashmem_mutex. |
| 89 | 90 | */ |
| 90 | 91 | static unsigned long lru_count; |
| 91 | 92 | |
| 92 | −/** | |
| 93 | +/* | |
| 93 | 94 | * ashmem_mutex - protects the list of and each individual ashmem_area |
| 94 | 95 | * |
| 95 | 96 | * Lock Ordering: ashmex_mutex -> i_mutex -> i_alloc_sem |
| @@ -311,10 +312,9 @@ static ssize_t ashmem_read(struct file *file, char __user *buf, · 215 unmodified lines | ||
| 311 | 312 | * ashmem_release is called. |
| 312 | 313 | */ |
| 313 | 314 | ret = __vfs_read(asma->file, buf, len, pos); |
| 314 | − if (ret >= 0) { | |
| 315 | + if (ret >= 0) | |
| 315 | 316 | /** Update backing file pos, since f_ops->read() doesn't */ |
| 316 | 317 | asma->file->f_pos = *pos; |
| 317 | − } | |
| 318 | 318 | return ret; |
| 319 | 319 | |
| 320 | 320 | out_unlock: |
| @@ -618,7 +618,8 @@ static int ashmem_pin(struct ashmem_area *asma, size_t pgstart, size_t pgend) · 297 unmodified lines | ||
| 618 | 618 | |
| 619 | 619 | /* Case #3: We overlap from the rear, so adjust it */ |
| 620 | 620 | if (range->pgend <= pgend) { |
| 621 | − range_shrink(range, range->pgstart, pgstart-1); | |
| 621 | + range_shrink(range, range->pgstart, | |
| 622 | + pgstart - 1); | |
| 622 | 623 | continue; |
| 623 | 624 | } |
| 624 | 625 | |
| @@ -715,7 +716,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, · 90 unmodified lines | ||
| 715 | 716 | if (unlikely((pin.offset | pin.len) & ~PAGE_MASK)) |
| 716 | 717 | return -EINVAL; |
| 717 | 718 | |
| 718 | − if (unlikely(((__u32) -1) - pin.offset < pin.len)) | |
| 719 | + if (unlikely(((__u32)-1) - pin.offset < pin.len)) | |
| 719 | 720 | return -EINVAL; |
| 720 | 721 | |
| 721 | 722 | if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len)) |
| @@ -759,7 +760,7 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) · 37 unmodified lines | ||
| 759 | 760 | ret = -EINVAL; |
| 760 | 761 | if (!asma->file) { |
| 761 | 762 | ret = 0; |
| 762 | − asma->size = (size_t) arg; | |
| 763 | + asma->size = (size_t)arg; | |
| 763 | 764 | } |
| 764 | 765 | break; |
| 765 | 766 | case ASHMEM_GET_SIZE: |
| @@ -833,16 +834,16 @@ static int __init ashmem_init(void) · 67 unmodified lines | ||
| 833 | 834 | int ret; |
| 834 | 835 | |
| 835 | 836 | ashmem_area_cachep = kmem_cache_create("ashmem_area_cache", |
| 836 | − sizeof(struct ashmem_area), | |
| 837 | − 0, 0, NULL); | |
| 837 | + sizeof(struct ashmem_area), | |
| 838 | + 0, 0, NULL); | |
| 838 | 839 | if (unlikely(!ashmem_area_cachep)) { |
| 839 | 840 | pr_err("failed to create slab cache\n"); |
| 840 | 841 | return -ENOMEM; |
| 841 | 842 | } |
| 842 | 843 | |
| 843 | 844 | ashmem_range_cachep = kmem_cache_create("ashmem_range_cache", |
| 844 | − sizeof(struct ashmem_range), | |
| 845 | − 0, 0, NULL); | |
| 845 | + sizeof(struct ashmem_range), | |
| 846 | + 0, 0, NULL); | |
| 846 | 847 | if (unlikely(!ashmem_range_cachep)) { |
| 847 | 848 | pr_err("failed to create slab cache\n"); |
| 848 | 849 | return -ENOMEM; |
| @@ -860,19 +861,4 @@ static int __init ashmem_init(void) · 11 unmodified lines | ||
| 860 | 861 | |
| 861 | 862 | return 0; |
| 862 | 863 | } |
| 863 | − | |
| 864 | −static void __exit ashmem_exit(void) | |
| 865 | −{ | |
| 866 | − unregister_shrinker(&ashmem_shrinker); | |
| 867 | − | |
| 868 | − misc_deregister(&ashmem_misc); | |
| 869 | − kmem_cache_destroy(ashmem_range_cachep); | |
| 870 | − kmem_cache_destroy(ashmem_area_cachep); | |
| 871 | − | |
| 872 | − pr_info("unloaded\n"); | |
| 873 | −} | |
| 874 | − | |
| 875 | −module_init(ashmem_init); | |
| 876 | −module_exit(ashmem_exit); | |
| 877 | − | |
| 878 | −MODULE_LICENSE("GPL"); | |
| 864 | +device_initcall(ashmem_init); | |
| @@ -1,5 +1,4 @@ | ||
| 1 | 1 | /* |
| 2 | − | |
| 3 | 2 | * drivers/staging/android/ion/compat_ion.h |
| 4 | 3 | * |
| 5 | 4 | * Copyright (C) 2013 Google, Inc. |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | /* |
| 2 | − | |
| 2 | + * | |
| 3 | 3 | * drivers/staging/android/ion/ion.c |
| 4 | 4 | * |
| 5 | 5 | * Copyright (C) 2011 Google, Inc. |
| @@ -213,10 +213,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, · 207 unmodified lines | ||
| 213 | 213 | "heap->ops->map_dma should return ERR_PTR on error")) |
| 214 | 214 | table = ERR_PTR(-EINVAL); |
| 215 | 215 | if (IS_ERR(table)) { |
| 216 | − heap->ops->free(buffer); | |
| 217 | − kfree(buffer); | |
| 218 | − return ERR_CAST(table); | |
| 216 | + ret = -EINVAL; | |
| 217 | + goto err1; | |
| 219 | 218 | } |
| 219 | + | |
| 220 | 220 | buffer->sg_table = table; |
| 221 | 221 | if (ion_buffer_fault_user_mappings(buffer)) { |
| 222 | 222 | int num_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; |
| @@ -226,7 +226,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, · 3 unmodified lines | ||
| 226 | 226 | buffer->pages = vmalloc(sizeof(struct page *) * num_pages); |
| 227 | 227 | if (!buffer->pages) { |
| 228 | 228 | ret = -ENOMEM; |
| 229 | − goto err1; | |
| 229 | + goto err; | |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | for_each_sg(table->sgl, sg, table->nents, i) { |
| @@ -235,23 +235,22 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, · 2 unmodified lines | ||
| 235 | 235 | for (j = 0; j < sg->length / PAGE_SIZE; j++) |
| 236 | 236 | buffer->pages[k++] = page++; |
| 237 | 237 | } |
| 238 | − | |
| 239 | − if (ret) | |
| 240 | − goto err; | |
| 241 | 238 | } |
| 242 | 239 | |
| 243 | 240 | buffer->dev = dev; |
| 244 | 241 | buffer->size = len; |
| 245 | 242 | INIT_LIST_HEAD(&buffer->vmas); |
| 246 | 243 | mutex_init(&buffer->lock); |
| 247 | − /* this will set up dma addresses for the sglist -- it is not | |
| 248 | − technically correct as per the dma api -- a specific | |
| 249 | − device isn't really taking ownership here. However, in practice on | |
| 250 | − our systems the only dma_address space is physical addresses. | |
| 251 | − Additionally, we can't afford the overhead of invalidating every | |
| 252 | − allocation via dma_map_sg. The implicit contract here is that | |
| 253 | − memory coming from the heaps is ready for dma, ie if it has a | |
| 254 | − cached mapping that mapping has been invalidated */ | |
| 244 | + /* | |
| 245 | + * this will set up dma addresses for the sglist -- it is not | |
| 246 | + * technically correct as per the dma api -- a specific | |
| 247 | + * device isn't really taking ownership here. However, in practice on | |
| 248 | + * our systems the only dma_address space is physical addresses. | |
| 249 | + * Additionally, we can't afford the overhead of invalidating every | |
| 250 | + * allocation via dma_map_sg. The implicit contract here is that | |
| 251 | + * memory coming from the heaps is ready for dma, ie if it has a | |
| 252 | + * cached mapping that mapping has been invalidated | |
| 253 | + */ | |
| 255 | 254 | for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) |
| 256 | 255 | sg_dma_address(sg) = sg_phys(sg); |
| 257 | 256 | mutex_lock(&dev->buffer_lock); |
| @@ -261,9 +260,8 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, · 3 unmodified lines | ||
| 261 | 260 | |
| 262 | 261 | err: |
| 263 | 262 | heap->ops->unmap_dma(heap, buffer); |
| 264 | − heap->ops->free(buffer); | |
| 265 | 263 | err1: |
| 266 | − vfree(buffer->pages); | |
| 264 | + heap->ops->free(buffer); | |
| 267 | 265 | err2: |
| 268 | 266 | kfree(buffer); |
| 269 | 267 | return ERR_PTR(ret); |
| @@ -753,8 +751,10 @@ struct ion_client *ion_client_create(struct ion_device *dev, · 483 unmodified lines | ||
| 753 | 751 | get_task_struct(current->group_leader); |
| 754 | 752 | task_lock(current->group_leader); |
| 755 | 753 | pid = task_pid_nr(current->group_leader); |
| 756 | − /* don't bother to store task struct for kernel threads, | |
| 757 | − they can't be killed anyway */ | |
| 754 | + /* | |
| 755 | + * don't bother to store task struct for kernel threads, | |
| 756 | + * they can't be killed anyway | |
| 757 | + */ | |
| 758 | 758 | if (current->group_leader->flags & PF_KTHREAD) { |
| 759 | 759 | put_task_struct(current->group_leader); |
| 760 | 760 | task = NULL; |
| @@ -1521,8 +1521,10 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) · 760 unmodified lines | ||
| 1521 | 1521 | |
| 1522 | 1522 | heap->dev = dev; |
| 1523 | 1523 | down_write(&dev->lock); |
| 1524 | − /* use negative heap->id to reverse the priority -- when traversing | |
| 1525 | − the list later attempt higher id numbers first */ | |
| 1524 | + /* | |
| 1525 | + * use negative heap->id to reverse the priority -- when traversing | |
| 1526 | + * the list later attempt higher id numbers first | |
| 1527 | + */ | |
| 1526 | 1528 | plist_node_init(&heap->node, -heap->id); |
| 1527 | 1529 | plist_add(&heap->node, &dev->heaps); |
| 1528 | 1530 | debug_file = debugfs_create_file(heap->name, 0664, |
| @@ -1555,6 +1557,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) · 26 unmodified lines | ||
| 1555 | 1557 | |
| 1556 | 1558 | up_write(&dev->lock); |
| 1557 | 1559 | } |
| 1560 | +EXPORT_SYMBOL(ion_device_add_heap); | |
| 1558 | 1561 | |
| 1559 | 1562 | struct ion_device *ion_device_create(long (*custom_ioctl) |
| 1560 | 1563 | (struct ion_client *client, |
| @@ -1604,6 +1607,7 @@ debugfs_done: · 43 unmodified lines | ||
| 1604 | 1607 | idev->clients = RB_ROOT; |
| 1605 | 1608 | return idev; |
| 1606 | 1609 | } |
| 1610 | +EXPORT_SYMBOL(ion_device_create); | |
| 1607 | 1611 | |
| 1608 | 1612 | void ion_device_destroy(struct ion_device *dev) |
| 1609 | 1613 | { |
| @@ -1612,6 +1616,7 @@ void ion_device_destroy(struct ion_device *dev) · 2 unmodified lines | ||
| 1612 | 1616 | /* XXX need to free the heaps and clients ? */ |
| 1613 | 1617 | kfree(dev); |
| 1614 | 1618 | } |
| 1619 | +EXPORT_SYMBOL(ion_device_destroy); | |
| 1615 | 1620 | |
| 1616 | 1621 | void __init ion_reserve(struct ion_platform_data *data) |
| 1617 | 1622 | { |
| @@ -28,10 +28,12 @@ struct ion_mapper; · 27 unmodified lines | ||
| 28 | 28 | struct ion_client; |
| 29 | 29 | struct ion_buffer; |
| 30 | 30 | |
| 31 | −/* This should be removed some day when phys_addr_t's are fully | |
| 32 | − plumbed in the kernel, and all instances of ion_phys_addr_t should | |
| 33 | − be converted to phys_addr_t. For the time being many kernel interfaces | |
| 34 | − do not accept phys_addr_t's that would have to */ | |
| 31 | +/* | |
| 32 | + * This should be removed some day when phys_addr_t's are fully | |
| 33 | + * plumbed in the kernel, and all instances of ion_phys_addr_t should | |
| 34 | + * be converted to phys_addr_t. For the time being many kernel interfaces | |
| 35 | + * do not accept phys_addr_t's that would have to | |
| 36 | + */ | |
| 35 | 37 | #define ion_phys_addr_t unsigned long |
| 36 | 38 | |
| 37 | 39 | /** |
| @@ -180,8 +180,10 @@ struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) · 179 unmodified lines | ||
| 180 | 180 | return ERR_PTR(-ENOMEM); |
| 181 | 181 | |
| 182 | 182 | cma_heap->heap.ops = &ion_cma_ops; |
| 183 | − /* get device from private heaps data, later it will be | |
| 184 | − * used to make the link with reserved CMA memory */ | |
| 183 | + /* | |
| 184 | + * get device from private heaps data, later it will be | |
| 185 | + * used to make the link with reserved CMA memory | |
| 186 | + */ | |
| 185 | 187 | cma_heap->dev = data->priv; |
| 186 | 188 | cma_heap->heap.type = ION_HEAP_TYPE_DMA; |
| 187 | 189 | return &cma_heap->heap; |
| @@ -56,7 +56,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap, · 55 unmodified lines | ||
| 56 | 56 | vaddr = vmap(pages, npages, VM_MAP, pgprot); |
| 57 | 57 | vfree(pages); |
| 58 | 58 | |
| 59 | − if (vaddr == NULL) | |
| 59 | + if (!vaddr) | |
| 60 | 60 | return ERR_PTR(-ENOMEM); |
| 61 | 61 | |
| 62 | 62 | return vaddr; |
| @@ -352,6 +352,7 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) · 289 unmodified lines | ||
| 352 | 352 | heap->id = heap_data->id; |
| 353 | 353 | return heap; |
| 354 | 354 | } |
| 355 | +EXPORT_SYMBOL(ion_heap_create); | |
| 355 | 356 | |
| 356 | 357 | void ion_heap_destroy(struct ion_heap *heap) |
| 357 | 358 | { |
| @@ -379,3 +380,4 @@ void ion_heap_destroy(struct ion_heap *heap) · 21 unmodified lines | ||
| 379 | 380 | heap->type); |
| 380 | 381 | } |
| 381 | 382 | } |
| 383 | +EXPORT_SYMBOL(ion_heap_destroy); | |
| @@ -19,7 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/err.h> |
| 20 | 20 | #include <linux/fs.h> |
| 21 | 21 | #include <linux/list.h> |
| 22 | −#include <linux/module.h> | |
| 22 | +#include <linux/init.h> | |
| 23 | 23 | #include <linux/slab.h> |
| 24 | 24 | #include <linux/swap.h> |
| 25 | 25 | #include "ion_priv.h" |
| @@ -174,10 +174,4 @@ static int __init ion_page_pool_init(void) · 148 unmodified lines | ||
| 174 | 174 | { |
| 175 | 175 | return 0; |
| 176 | 176 | } |
| 177 | − | |
| 178 | −static void __exit ion_page_pool_exit(void) | |
| 179 | −{ | |
| 180 | −} | |
| 181 | − | |
| 182 | −module_init(ion_page_pool_init); | |
| 183 | −module_exit(ion_page_pool_exit); | |
| 177 | +device_initcall(ion_page_pool_init); | |
| @@ -346,7 +346,8 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, · 345 unmodified lines | ||
| 346 | 346 | * to keep a pool of pre allocated memory to use from your heap. Keeping |
| 347 | 347 | * a pool of memory that is ready for dma, ie any cached mapping have been |
| 348 | 348 | * invalidated from the cache, provides a significant performance benefit on |
| 349 | − * many systems */ | |
| 349 | + * many systems | |
| 350 | + */ | |
| 350 | 351 | |
| 351 | 352 | /** |
| 352 | 353 | * struct ion_page_pool - pagepool struct |
| @@ -185,8 +185,11 @@ static void ion_system_heap_free(struct ion_buffer *buffer) · 184 unmodified lines | ||
| 185 | 185 | struct scatterlist *sg; |
| 186 | 186 | int i; |
| 187 | 187 | |
| 188 | − /* uncached pages come from the page pools, zero them before returning | |
| 189 | − for security purposes (other allocations are zerod at alloc time */ | |
| 188 | + /* | |
| 189 | + * uncached pages come from the page pools, zero them before returning | |
| 190 | + * for security purposes (other allocations are zerod at | |
| 191 | + * alloc time | |
| 192 | + */ | |
| 190 | 193 | if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) |
| 191 | 194 | ion_heap_buffer_zero(buffer); |
| 192 | 195 | |
| @@ -1 +1 @@ | ||
| 1 | −obj-y += tegra_ion.o | |
| 1 | +obj-$(CONFIG_ION_TEGRA) += tegra_ion.o | |
| @@ -32,7 +32,8 @@ · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 34 | 34 | |
| 35 | −#include <linux/module.h> | |
| 35 | +#include <linux/init.h> | |
| 36 | +#include <linux/moduleparam.h> | |
| 36 | 37 | #include <linux/kernel.h> |
| 37 | 38 | #include <linux/mm.h> |
| 38 | 39 | #include <linux/oom.h> |
| @@ -157,26 +158,22 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) · 118 unmodified lines | ||
| 157 | 158 | } |
| 158 | 159 | if (selected) { |
| 159 | 160 | task_lock(selected); |
| 160 | − if (!selected->mm) { | |
| 161 | − /* Already exited, cannot do mark_tsk_oom_victim() */ | |
| 162 | − task_unlock(selected); | |
| 163 | − goto out; | |
| 164 | − } | |
| 161 | + send_sig(SIGKILL, selected, 0); | |
| 165 | 162 | /* |
| 166 | 163 | * FIXME: lowmemorykiller shouldn't abuse global OOM killer |
| 167 | 164 | * infrastructure. There is no real reason why the selected |
| 168 | 165 | * task should have access to the memory reserves. |
| 169 | 166 | */ |
| 170 | − mark_oom_victim(selected); | |
| 167 | + if (selected->mm) | |
| 168 | + mark_oom_victim(selected); | |
| 171 | 169 | task_unlock(selected); |
| 172 | 170 | lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n", |
| 173 | 171 | selected->pid, selected->comm, |
| 174 | 172 | selected_oom_score_adj, selected_tasksize); |
| 175 | 173 | lowmem_deathpending_timeout = jiffies + HZ; |
| 176 | − send_sig(SIGKILL, selected, 0); | |
| 177 | 174 | rem += selected_tasksize; |
| 178 | 175 | } |
| 179 | −out: | |
| 176 | + | |
| 180 | 177 | lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", |
| 181 | 178 | sc->nr_to_scan, sc->gfp_mask, rem); |
| 182 | 179 | rcu_read_unlock(); |
| @@ -194,12 +191,12 @@ static int __init lowmem_init(void) · 11 unmodified lines | ||
| 194 | 191 | register_shrinker(&lowmem_shrinker); |
| 195 | 192 | return 0; |
| 196 | 193 | } |
| 194 | +device_initcall(lowmem_init); | |
| 197 | 195 | |
| 198 | −static void __exit lowmem_exit(void) | |
| 199 | −{ | |
| 200 | − unregister_shrinker(&lowmem_shrinker); | |
| 201 | −} | |
| 202 | − | |
| 196 | +/* | |
| 197 | + * not really modular, but the easiest way to keep compat with existing | |
| 198 | + * bootargs behaviour is to continue using module_param here. | |
| 199 | + */ | |
| 203 | 200 | module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); |
| 204 | 201 | module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size, |
| 205 | 202 | S_IRUGO | S_IWUSR); |
| @@ -207,8 +204,3 @@ module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, · 1 unmodified line | ||
| 207 | 204 | S_IRUGO | S_IWUSR); |
| 208 | 205 | module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); |
| 209 | 206 | |
| 210 | −module_init(lowmem_init); | |
| 211 | −module_exit(lowmem_exit); | |
| 212 | − | |
| 213 | −MODULE_LICENSE("GPL"); | |
| 214 | − | |
| @@ -15,11 +15,11 @@ · 14 unmodified lines | ||
| 15 | 15 | */ |
| 16 | 16 | |
| 17 | 17 | #include <linux/kernel.h> |
| 18 | +#include <linux/init.h> | |
| 18 | 19 | #include <linux/export.h> |
| 19 | 20 | #include <linux/file.h> |
| 20 | 21 | #include <linux/fs.h> |
| 21 | 22 | #include <linux/miscdevice.h> |
| 22 | −#include <linux/module.h> | |
| 23 | 23 | #include <linux/syscalls.h> |
| 24 | 24 | #include <linux/uaccess.h> |
| 25 | 25 | |
| @@ -145,7 +145,7 @@ static int sw_sync_open(struct inode *inode, struct file *file) · 119 unmodified lines | ||
| 145 | 145 | get_task_comm(task_comm, current); |
| 146 | 146 | |
| 147 | 147 | obj = sw_sync_timeline_create(task_comm); |
| 148 | − if (obj == NULL) | |
| 148 | + if (!obj) | |
| 149 | 149 | return -ENOMEM; |
| 150 | 150 | |
| 151 | 151 | file->private_data = obj; |
| @@ -179,14 +179,14 @@ static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj, · 27 unmodified lines | ||
| 179 | 179 | } |
| 180 | 180 | |
| 181 | 181 | pt = sw_sync_pt_create(obj, data.value); |
| 182 | − if (pt == NULL) { | |
| 182 | + if (!pt) { | |
| 183 | 183 | err = -ENOMEM; |
| 184 | 184 | goto err; |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | 187 | data.name[sizeof(data.name) - 1] = '\0'; |
| 188 | 188 | fence = sync_fence_create(data.name, pt); |
| 189 | − if (fence == NULL) { | |
| 189 | + if (!fence) { | |
| 190 | 190 | sync_pt_free(pt); |
| 191 | 191 | err = -ENOMEM; |
| 192 | 192 | goto err; |
| @@ -255,13 +255,6 @@ static int __init sw_sync_device_init(void) · 62 unmodified lines | ||
| 255 | 255 | { |
| 256 | 256 | return misc_register(&sw_sync_dev); |
| 257 | 257 | } |
| 258 | − | |
| 259 | −static void __exit sw_sync_device_remove(void) | |
| 260 | −{ | |
| 261 | − misc_deregister(&sw_sync_dev); | |
| 262 | −} | |
| 263 | − | |
| 264 | −module_init(sw_sync_device_init); | |
| 265 | −module_exit(sw_sync_device_remove); | |
| 258 | +device_initcall(sw_sync_device_init); | |
| 266 | 259 | |
| 267 | 260 | #endif /* CONFIG_SW_SYNC_USER */ |
| @@ -16,7 +16,8 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | #define pr_fmt(fmt) "timed_output: " fmt |
| 18 | 18 | |
| 19 | −#include <linux/module.h> | |
| 19 | +#include <linux/init.h> | |
| 20 | +#include <linux/export.h> | |
| 20 | 21 | #include <linux/types.h> |
| 21 | 22 | #include <linux/device.h> |
| 22 | 23 | #include <linux/fs.h> |
| @@ -106,15 +107,4 @@ static int __init timed_output_init(void) · 83 unmodified lines | ||
| 106 | 107 | { |
| 107 | 108 | return create_timed_output_class(); |
| 108 | 109 | } |
| 109 | − | |
| 110 | −static void __exit timed_output_exit(void) | |
| 111 | −{ | |
| 112 | − class_destroy(timed_output_class); | |
| 113 | −} | |
| 114 | − | |
| 115 | −module_init(timed_output_init); | |
| 116 | −module_exit(timed_output_exit); | |
| 117 | − | |
| 118 | −MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | |
| 119 | −MODULE_DESCRIPTION("timed output class driver"); | |
| 120 | −MODULE_LICENSE("GPL"); | |
| 110 | +device_initcall(timed_output_init); | |
| @@ -40,8 +40,10 @@ enum ion_heap_type { · 39 unmodified lines | ||
| 40 | 40 | ION_HEAP_TYPE_CARVEOUT, |
| 41 | 41 | ION_HEAP_TYPE_CHUNK, |
| 42 | 42 | ION_HEAP_TYPE_DMA, |
| 43 | − ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always | |
| 44 | − are at the end of this enum */ | |
| 43 | + ION_HEAP_TYPE_CUSTOM, /* | |
| 44 | + * must be last so device specific heaps always | |
| 45 | + * are at the end of this enum | |
| 46 | + */ | |
| 45 | 47 | ION_NUM_HEAPS = 16, |
| 46 | 48 | }; |
| 47 | 49 | |
| @@ -56,13 +58,18 @@ enum ion_heap_type { · 8 unmodified lines | ||
| 56 | 58 | * allocation flags - the lower 16 bits are used by core ion, the upper 16 |
| 57 | 59 | * bits are reserved for use by the heaps themselves. |
| 58 | 60 | */ |
| 59 | −#define ION_FLAG_CACHED 1 /* mappings of this buffer should be | |
| 60 | − cached, ion will do cache | |
| 61 | − maintenance when the buffer is | |
| 62 | − mapped for dma */ | |
| 63 | −#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* mappings of this buffer will created | |
| 64 | − at mmap time, if this is set | |
| 65 | − caches must be managed manually */ | |
| 61 | +#define ION_FLAG_CACHED 1 /* | |
| 62 | + * mappings of this buffer should be | |
| 63 | + * cached, ion will do cache | |
| 64 | + * maintenance when the buffer is | |
| 65 | + * mapped for dma | |
| 66 | + */ | |
| 67 | +#define ION_FLAG_CACHED_NEEDS_SYNC 2 /* | |
| 68 | + * mappings of this buffer will created | |
| 69 | + * at mmap time, if this is set | |
| 70 | + * caches must be managed | |
| 71 | + * manually | |
| 72 | + */ | |
| 66 | 73 | |
| 67 | 74 | /** |
| 68 | 75 | * DOC: Ion Userspace API |
| @@ -187,6 +187,9 @@ int __init board_staging_register_device(const struct board_staging_dev *dev) · 186 unmodified lines | ||
| 187 | 187 | for (i = 0; i < dev->nclocks; i++) |
| 188 | 188 | board_staging_register_clock(&dev->clocks[i]); |
| 189 | 189 | |
| 190 | + if (dev->domain) | |
| 191 | + board_staging_add_dev_domain(pdev, dev->domain); | |
| 192 | + | |
| 190 | 193 | error = platform_device_register(pdev); |
| 191 | 194 | if (error) { |
| 192 | 195 | pr_err("Failed to register device %s (%d)\n", pdev->name, |
| @@ -194,9 +197,6 @@ int __init board_staging_register_device(const struct board_staging_dev *dev) · 1 unmodified line | ||
| 194 | 197 | return error; |
| 195 | 198 | } |
| 196 | 199 | |
| 197 | − if (dev->domain) | |
| 198 | − board_staging_add_dev_domain(pdev, dev->domain); | |
| 199 | − | |
| 200 | 200 | return error; |
| 201 | 201 | } |
| 202 | 202 | |
| @@ -400,14 +400,6 @@ config COMEDI_DMM32AT · 399 unmodified lines | ||
| 400 | 400 | To compile this driver as a module, choose M here: the module will be |
| 401 | 401 | called dmm32at. |
| 402 | 402 | |
| 403 | −config COMEDI_UNIOXX5 | |
| 404 | − tristate "Fastwel UNIOxx-5 analog and digital io board support" | |
| 405 | − ---help--- | |
| 406 | − Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards | |
| 407 | − | |
| 408 | − To compile this driver as a module, choose M here: the module will be | |
| 409 | − called unioxx5. | |
| 410 | − | |
| 411 | 403 | config COMEDI_FL512 |
| 412 | 404 | tristate "FL512 ISA card support" |
| 413 | 405 | ---help--- |
| @@ -418,6 +410,7 @@ config COMEDI_FL512 · 4 unmodified lines | ||
| 418 | 410 | |
| 419 | 411 | config COMEDI_AIO_AIO12_8 |
| 420 | 412 | tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" |
| 413 | + select COMEDI_8254 | |
| 421 | 414 | select COMEDI_8255 |
| 422 | 415 | ---help--- |
| 423 | 416 | Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board |
| @@ -1072,6 +1065,7 @@ config COMEDI_NI_PCIMIO · 648 unmodified lines | ||
| 1072 | 1065 | |
| 1073 | 1066 | config COMEDI_RTD520 |
| 1074 | 1067 | tristate "Real Time Devices PCI4520/DM7520 support" |
| 1068 | + select COMEDI_8254 | |
| 1075 | 1069 | ---help--- |
| 1076 | 1070 | Enable support for Real Time Devices PCI4520/DM7520 |
| 1077 | 1071 | |
| @@ -245,7 +245,7 @@ void comedi_buf_reset(struct comedi_subdevice *s) · 244 unmodified lines | ||
| 245 | 245 | async->events = 0; |
| 246 | 246 | } |
| 247 | 247 | |
| 248 | −static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) | |
| 248 | +static unsigned int comedi_buf_write_n_unalloc(struct comedi_subdevice *s) | |
| 249 | 249 | { |
| 250 | 250 | struct comedi_async *async = s->async; |
| 251 | 251 | unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; |
| @@ -253,15 +253,33 @@ static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) · 1 unmodified line | ||
| 253 | 253 | return free_end - async->buf_write_alloc_count; |
| 254 | 254 | } |
| 255 | 255 | |
| 256 | −/* allocates chunk for the writer from free buffer space */ | |
| 256 | +unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) | |
| 257 | +{ | |
| 258 | + struct comedi_async *async = s->async; | |
| 259 | + unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; | |
| 260 | + | |
| 261 | + return free_end - async->buf_write_count; | |
| 262 | +} | |
| 263 | + | |
| 264 | +/** | |
| 265 | + * comedi_buf_write_alloc() - Reserve buffer space for writing | |
| 266 | + * @s: COMEDI subdevice. | |
| 267 | + * @nbytes: Maximum space to reserve in bytes. | |
| 268 | + * | |
| 269 | + * Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition | |
| 270 | + * data buffer associated with the subdevice. The amount reserved is limited | |
| 271 | + * by the space available. | |
| 272 | + * | |
| 273 | + * Return: The amount of space reserved in bytes. | |
| 274 | + */ | |
| 257 | 275 | unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, |
| 258 | 276 | unsigned int nbytes) |
| 259 | 277 | { |
| 260 | 278 | struct comedi_async *async = s->async; |
| 261 | − unsigned int available = comedi_buf_write_n_available(s); | |
| 279 | + unsigned int unalloc = comedi_buf_write_n_unalloc(s); | |
| 262 | 280 | |
| 263 | − if (nbytes > available) | |
| 264 | − nbytes = available; | |
| 281 | + if (nbytes > unalloc) | |
| 282 | + nbytes = unalloc; | |
| 265 | 283 | |
| 266 | 284 | async->buf_write_alloc_count += nbytes; |
| 267 | 285 | |
| @@ -329,7 +347,21 @@ unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s) · 61 unmodified lines | ||
| 329 | 347 | return async->buf_write_alloc_count - async->buf_write_count; |
| 330 | 348 | } |
| 331 | 349 | |
| 332 | −/* transfers a chunk from writer to filled buffer space */ | |
| 350 | +/** | |
| 351 | + * comedi_buf_write_free() - Free buffer space after it is written | |
| 352 | + * @s: COMEDI subdevice. | |
| 353 | + * @nbytes: Maximum space to free in bytes. | |
| 354 | + * | |
| 355 | + * Free up to @nbytes bytes of space previously reserved for writing in the | |
| 356 | + * COMEDI acquisition data buffer associated with the subdevice. The amount of | |
| 357 | + * space freed is limited to the amount that was reserved. The freed space is | |
| 358 | + * assumed to have been filled with sample data by the writer. | |
| 359 | + * | |
| 360 | + * If the samples in the freed space need to be "munged", do so here. The | |
| 361 | + * freed space becomes available for allocation by the reader. | |
| 362 | + * | |
| 363 | + * Return: The amount of space freed in bytes. | |
| 364 | + */ | |
| 333 | 365 | unsigned int comedi_buf_write_free(struct comedi_subdevice *s, |
| 334 | 366 | unsigned int nbytes) |
| 335 | 367 | { |
| @@ -349,6 +381,17 @@ unsigned int comedi_buf_write_free(struct comedi_subdevice *s, · 13 unmodified lines | ||
| 349 | 381 | } |
| 350 | 382 | EXPORT_SYMBOL_GPL(comedi_buf_write_free); |
| 351 | 383 | |
| 384 | +/** | |
| 385 | + * comedi_buf_read_n_available() - Determine amount of readable buffer space | |
| 386 | + * @s: COMEDI subdevice. | |
| 387 | + * | |
| 388 | + * Determine the amount of readable buffer space in the COMEDI acquisition data | |
| 389 | + * buffer associated with the subdevice. The readable buffer space is that | |
| 390 | + * which has been freed by the writer and "munged" to the sample data format | |
| 391 | + * expected by COMEDI if necessary. | |
| 392 | + * | |
| 393 | + * Return: The amount of readable buffer space. | |
| 394 | + */ | |
| 352 | 395 | unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) |
| 353 | 396 | { |
| 354 | 397 | struct comedi_async *async = s->async; |
| @@ -369,7 +412,21 @@ unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) · 14 unmodified lines | ||
| 369 | 412 | } |
| 370 | 413 | EXPORT_SYMBOL_GPL(comedi_buf_read_n_available); |
| 371 | 414 | |
| 372 | −/* allocates a chunk for the reader from filled (and munged) buffer space */ | |
| 415 | +/** | |
| 416 | + * comedi_buf_read_alloc() - Reserve buffer space for reading | |
| 417 | + * @s: COMEDI subdevice. | |
| 418 | + * @nbytes: Maximum space to reserve in bytes. | |
| 419 | + * | |
| 420 | + * Reserve up to @nbytes bytes of previously written and "munged" buffer space | |
| 421 | + * for reading in the COMEDI acquisition data buffer associated with the | |
| 422 | + * subdevice. The amount reserved is limited to the space available. The | |
| 423 | + * reader can read from the reserved space and then free it. A reader is also | |
| 424 | + * allowed to read from the space before reserving it as long as it determines | |
| 425 | + * the amount of readable data available, but the space needs to be marked as | |
| 426 | + * reserved before it can be freed. | |
| 427 | + * | |
| 428 | + * Return: The amount of space reserved in bytes. | |
| 429 | + */ | |
| 373 | 430 | unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, |
| 374 | 431 | unsigned int nbytes) |
| 375 | 432 | { |
| @@ -397,7 +454,19 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) · 21 unmodified lines | ||
| 397 | 454 | return async->buf_read_alloc_count - async->buf_read_count; |
| 398 | 455 | } |
| 399 | 456 | |
| 400 | −/* transfers control of a chunk from reader to free buffer space */ | |
| 457 | +/** | |
| 458 | + * comedi_buf_read_free() - Free buffer space after it has been read | |
| 459 | + * @s: COMEDI subdevice. | |
| 460 | + * @nbytes: Maximum space to free in bytes. | |
| 461 | + * | |
| 462 | + * Free up to @nbytes bytes of buffer space previously reserved for reading in | |
| 463 | + * the COMEDI acquisition data buffer associated with the subdevice. The | |
| 464 | + * amount of space freed is limited to the amount that was reserved. | |
| 465 | + * | |
| 466 | + * The freed space becomes available for allocation by the writer. | |
| 467 | + * | |
| 468 | + * Return: The amount of space freed in bytes. | |
| 469 | + */ | |
| 401 | 470 | unsigned int comedi_buf_read_free(struct comedi_subdevice *s, |
| 402 | 471 | unsigned int nbytes) |
| 403 | 472 | { |
| @@ -469,15 +538,21 @@ static void comedi_buf_memcpy_from(struct comedi_subdevice *s, · 65 unmodified lines | ||
| 469 | 538 | } |
| 470 | 539 | |
| 471 | 540 | /** |
| 472 | − * comedi_buf_write_samples - write sample data to comedi buffer | |
| 473 | − * @s: comedi_subdevice struct | |
| 474 | − * @data: samples | |
| 475 | − * @nsamples: number of samples | |
| 541 | + * comedi_buf_write_samples() - Write sample data to COMEDI buffer | |
| 542 | + * @s: COMEDI subdevice. | |
| 543 | + * @data: Pointer to source samples. | |
| 544 | + * @nsamples: Number of samples to write. | |
| 476 | 545 | * |
| 477 | − * Writes nsamples to the comedi buffer associated with the subdevice, marks | |
| 478 | − * it as written and updates the acquisition scan progress. | |
| 546 | + * Write up to @nsamples samples to the COMEDI acquisition data buffer | |
| 547 | + * associated with the subdevice, mark it as written and update the | |
| 548 | + * acquisition scan progress. If there is not enough room for the specified | |
| 549 | + * number of samples, the number of samples written is limited to the number | |
| 550 | + * that will fit and the %COMEDI_CB_OVERFLOW event flag is set to cause the | |
| 551 | + * acquisition to terminate with an overrun error. Set the %COMEDI_CB_BLOCK | |
| 552 | + * event flag if any samples are written to cause waiting tasks to be woken | |
| 553 | + * when the event flags are processed. | |
| 479 | 554 | * |
| 480 | − * Returns the amount of data written in bytes. | |
| 555 | + * Return: The amount of data written in bytes. | |
| 481 | 556 | */ |
| 482 | 557 | unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, |
| 483 | 558 | const void *data, unsigned int nsamples) |
| @@ -490,8 +565,7 @@ unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, · 6 unmodified lines | ||
| 490 | 565 | * If not, clamp the nsamples to the number that will fit, flag the |
| 491 | 566 | * buffer overrun and add the samples that fit. |
| 492 | 567 | */ |
| 493 | − max_samples = comedi_bytes_to_samples(s, | |
| 494 | − comedi_buf_write_n_available(s)); | |
| 568 | + max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s)); | |
| 495 | 569 | if (nsamples > max_samples) { |
| 496 | 570 | dev_warn(s->device->class_dev, "buffer overrun\n"); |
| 497 | 571 | s->async->events |= COMEDI_CB_OVERFLOW; |
| @@ -513,15 +587,18 @@ unsigned int comedi_buf_write_samples(struct comedi_subdevice *s, · 15 unmodified lines | ||
| 513 | 587 | EXPORT_SYMBOL_GPL(comedi_buf_write_samples); |
| 514 | 588 | |
| 515 | 589 | /** |
| 516 | − * comedi_buf_read_samples - read sample data from comedi buffer | |
| 517 | − * @s: comedi_subdevice struct | |
| 518 | − * @data: destination | |
| 519 | − * @nsamples: maximum number of samples to read | |
| 590 | + * comedi_buf_read_samples() - Read sample data from COMEDI buffer | |
| 591 | + * @s: COMEDI subdevice. | |
| 592 | + * @data: Pointer to destination. | |
| 593 | + * @nsamples: Maximum number of samples to read. | |
| 520 | 594 | * |
| 521 | − * Reads up to nsamples from the comedi buffer associated with the subdevice, | |
| 522 | − * marks it as read and updates the acquisition scan progress. | |
| 595 | + * Read up to @nsamples samples from the COMEDI acquisition data buffer | |
| 596 | + * associated with the subdevice, mark it as read and update the acquisition | |
| 597 | + * scan progress. Limit the number of samples read to the number available. | |
| 598 | + * Set the %COMEDI_CB_BLOCK event flag if any samples are read to cause waiting | |
| 599 | + * tasks to be woken when the event flags are processed. | |
| 523 | 600 | * |
| 524 | − * Returns the amount of data read in bytes. | |
| 601 | + * Return: The amount of data read in bytes. | |
| 525 | 602 | */ |
| 526 | 603 | unsigned int comedi_buf_read_samples(struct comedi_subdevice *s, |
| 527 | 604 | void *data, unsigned int nsamples) |
| @@ -43,15 +43,15 @@ · 42 unmodified lines | ||
| 43 | 43 | |
| 44 | 44 | #include "comedi_internal.h" |
| 45 | 45 | |
| 46 | −/** | |
| 46 | +/* | |
| 47 | 47 | * comedi_subdevice "runflags" |
| 48 | − * @COMEDI_SRF_RT: DEPRECATED: command is running real-time | |
| 49 | − * @COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred | |
| 48 | + * COMEDI_SRF_RT: DEPRECATED: command is running real-time | |
| 49 | + * COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred | |
| 50 | 50 | * since the last command was started |
| 51 | − * @COMEDI_SRF_RUNNING: command is running | |
| 52 | − * @COMEDI_SRF_FREE_SPRIV: free s->private on detach | |
| 51 | + * COMEDI_SRF_RUNNING: command is running | |
| 52 | + * COMEDI_SRF_FREE_SPRIV: free s->private on detach | |
| 53 | 53 | * |
| 54 | − * @COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" | |
| 54 | + * COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy" | |
| 55 | 55 | */ |
| 56 | 56 | #define COMEDI_SRF_RT BIT(1) |
| 57 | 57 | #define COMEDI_SRF_ERROR BIT(2) |
| @@ -61,12 +61,12 @@ · 3 unmodified lines | ||
| 61 | 61 | #define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING) |
| 62 | 62 | |
| 63 | 63 | /** |
| 64 | − * struct comedi_file - per-file private data for comedi device | |
| 65 | − * @dev: comedi_device struct | |
| 66 | − * @read_subdev: current "read" subdevice | |
| 67 | − * @write_subdev: current "write" subdevice | |
| 68 | − * @last_detach_count: last known detach count | |
| 69 | − * @last_attached: last known attached/detached state | |
| 64 | + * struct comedi_file - Per-file private data for COMEDI device | |
| 65 | + * @dev: COMEDI device. | |
| 66 | + * @read_subdev: Current "read" subdevice. | |
| 67 | + * @write_subdev: Current "write" subdevice. | |
| 68 | + * @last_detach_count: Last known detach count. | |
| 69 | + * @last_attached: Last known attached/detached state. | |
| 70 | 70 | */ |
| 71 | 71 | struct comedi_file { |
| 72 | 72 | struct comedi_device *dev; |
| @@ -131,15 +131,15 @@ static void comedi_dev_kref_release(struct kref *kref) · 58 unmodified lines | ||
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | /** |
| 134 | − * comedi_dev_put - release a use of a comedi device structure | |
| 135 | − * @dev: comedi_device struct | |
| 134 | + * comedi_dev_put() - Release a use of a COMEDI device | |
| 135 | + * @dev: COMEDI device. | |
| 136 | 136 | * |
| 137 | − * Must be called when a user of a comedi device is finished with it. | |
| 138 | − * When the last user of the comedi device calls this function, the | |
| 139 | − * comedi device is destroyed. | |
| 137 | + * Must be called when a user of a COMEDI device is finished with it. | |
| 138 | + * When the last user of the COMEDI device calls this function, the | |
| 139 | + * COMEDI device is destroyed. | |
| 140 | 140 | * |
| 141 | − * Return 1 if the comedi device is destroyed by this call or dev is | |
| 142 | − * NULL, otherwise return 0. Callers must not assume the comedi | |
| 141 | + * Return: 1 if the COMEDI device is destroyed by this call or @dev is | |
| 142 | + * NULL, otherwise return 0. Callers must not assume the COMEDI | |
| 143 | 143 | * device is still valid if this function returns 0. |
| 144 | 144 | */ |
| 145 | 145 | int comedi_dev_put(struct comedi_device *dev) |
| @@ -247,15 +247,15 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor) · 101 unmodified lines | ||
| 247 | 247 | } |
| 248 | 248 | |
| 249 | 249 | /** |
| 250 | − * comedi_dev_get_from_minor - get comedi device by minor device number | |
| 251 | − * @minor: minor device number | |
| 250 | + * comedi_dev_get_from_minor() - Get COMEDI device by minor device number | |
| 251 | + * @minor: Minor device number. | |
| 252 | 252 | * |
| 253 | − * Finds the comedi device associated by the minor device number, if any, | |
| 254 | − * and increments its reference count. The comedi device is prevented from | |
| 253 | + * Finds the COMEDI device associated with the minor device number, if any, | |
| 254 | + * and increments its reference count. The COMEDI device is prevented from | |
| 255 | 255 | * being freed until a matching call is made to comedi_dev_put(). |
| 256 | 256 | * |
| 257 | − * Return a pointer to the comedi device if it exists, with its usage | |
| 258 | − * reference incremented. Return NULL if no comedi device exists with the | |
| 257 | + * Return: A pointer to the COMEDI device if it exists, with its usage | |
| 258 | + * reference incremented. Return NULL if no COMEDI device exists with the | |
| 259 | 259 | * specified minor device number. |
| 260 | 260 | */ |
| 261 | 261 | struct comedi_device *comedi_dev_get_from_minor(unsigned minor) |
| @@ -665,11 +665,11 @@ static bool comedi_is_runflags_in_error(unsigned runflags) · 403 unmodified lines | ||
| 665 | 665 | } |
| 666 | 666 | |
| 667 | 667 | /** |
| 668 | − * comedi_is_subdevice_running - check if async command running on subdevice | |
| 669 | − * @s: comedi_subdevice struct | |
| 668 | + * comedi_is_subdevice_running() - Check if async command running on subdevice | |
| 669 | + * @s: COMEDI subdevice. | |
| 670 | 670 | * |
| 671 | − * Return true if an asynchronous comedi command is active on the comedi | |
| 672 | − * subdevice, else return false. | |
| 671 | + * Return: %true if an asynchronous COMEDI command is active on the | |
| 672 | + * subdevice, else %false. | |
| 673 | 673 | */ |
| 674 | 674 | bool comedi_is_subdevice_running(struct comedi_subdevice *s) |
| 675 | 675 | { |
| @@ -701,11 +701,12 @@ bool comedi_can_auto_free_spriv(struct comedi_subdevice *s) · 25 unmodified lines | ||
| 701 | 701 | } |
| 702 | 702 | |
| 703 | 703 | /** |
| 704 | − * comedi_set_spriv_auto_free - mark subdevice private data as freeable | |
| 705 | − * @s: comedi_subdevice struct | |
| 704 | + * comedi_set_spriv_auto_free() - Mark subdevice private data as freeable | |
| 705 | + * @s: COMEDI subdevice. | |
| 706 | 706 | * |
| 707 | 707 | * Mark the subdevice as having a pointer to private data that can be |
| 708 | − * automatically freed by the comedi core during the detach. | |
| 708 | + * automatically freed when the COMEDI device is detached from the low-level | |
| 709 | + * driver. | |
| 709 | 710 | */ |
| 710 | 711 | void comedi_set_spriv_auto_free(struct comedi_subdevice *s) |
| 711 | 712 | { |
| @@ -714,12 +715,16 @@ void comedi_set_spriv_auto_free(struct comedi_subdevice *s) · 2 unmodified lines | ||
| 714 | 715 | EXPORT_SYMBOL_GPL(comedi_set_spriv_auto_free); |
| 715 | 716 | |
| 716 | 717 | /** |
| 717 | − * comedi_alloc_spriv - Allocate memory for the subdevice private data. | |
| 718 | − * @s: comedi_subdevice struct | |
| 719 | − * @size: size of the memory to allocate | |
| 718 | + * comedi_alloc_spriv - Allocate memory for the subdevice private data | |
| 719 | + * @s: COMEDI subdevice. | |
| 720 | + * @size: Size of the memory to allocate. | |
| 721 | + * | |
| 722 | + * Allocate memory for the subdevice private data and point @s->private | |
| 723 | + * to it. The memory will be freed automatically when the COMEDI device | |
| 724 | + * is detached from the low-level driver. | |
| 720 | 725 | * |
| 721 | − * This also sets the subdevice runflags to allow the core to automatically | |
| 722 | − * free the private data during the detach. | |
| 726 | + * Return: A pointer to the allocated memory @s->private on success. | |
| 727 | + * Return NULL on failure. | |
| 723 | 728 | */ |
| 724 | 729 | void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) |
| 725 | 730 | { |
| @@ -1141,7 +1146,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, · 415 unmodified lines | ||
| 1141 | 1146 | comedi_buf_read_free(s, bi.bytes_read); |
| 1142 | 1147 | |
| 1143 | 1148 | if (comedi_is_subdevice_idle(s) && |
| 1144 | − comedi_buf_n_bytes_ready(s) == 0) { | |
| 1149 | + comedi_buf_read_n_available(s) == 0) { | |
| 1145 | 1150 | do_become_nonbusy(dev, s); |
| 1146 | 1151 | } |
| 1147 | 1152 | } |
| @@ -1336,7 +1341,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, · 188 unmodified lines | ||
| 1336 | 1341 | goto out; |
| 1337 | 1342 | } |
| 1338 | 1343 | /* This looks arbitrary. It is. */ |
| 1339 | − s->busy = &parse_insn; | |
| 1344 | + s->busy = parse_insn; | |
| 1340 | 1345 | switch (insn->insn) { |
| 1341 | 1346 | case INSN_READ: |
| 1342 | 1347 | ret = s->insn_read(dev, s, insn, data); |
| @@ -2257,9 +2262,9 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) · 914 unmodified lines | ||
| 2257 | 2262 | unsigned int mask = 0; |
| 2258 | 2263 | struct comedi_file *cfp = file->private_data; |
| 2259 | 2264 | struct comedi_device *dev = cfp->dev; |
| 2260 | − struct comedi_subdevice *s; | |
| 2265 | + struct comedi_subdevice *s, *s_read; | |
| 2261 | 2266 | |
| 2262 | − mutex_lock(&dev->mutex); | |
| 2267 | + down_read(&dev->attach_lock); | |
| 2263 | 2268 | |
| 2264 | 2269 | if (!dev->attached) { |
| 2265 | 2270 | dev_dbg(dev->class_dev, "no driver attached\n"); |
| @@ -2267,9 +2272,10 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) · 1 unmodified line | ||
| 2267 | 2272 | } |
| 2268 | 2273 | |
| 2269 | 2274 | s = comedi_file_read_subdevice(file); |
| 2275 | + s_read = s; | |
| 2270 | 2276 | if (s && s->async) { |
| 2271 | 2277 | poll_wait(file, &s->async->wait_head, wait); |
| 2272 | − if (!s->busy || !comedi_is_subdevice_running(s) || | |
| 2278 | + if (s->busy != file || !comedi_is_subdevice_running(s) || | |
| 2273 | 2279 | (s->async->cmd.flags & CMDF_WRITE) || |
| 2274 | 2280 | comedi_buf_read_n_available(s) > 0) |
| 2275 | 2281 | mask |= POLLIN | POLLRDNORM; |
| @@ -2279,16 +2285,16 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait) · 3 unmodified lines | ||
| 2279 | 2285 | if (s && s->async) { |
| 2280 | 2286 | unsigned int bps = comedi_bytes_per_sample(s); |
| 2281 | 2287 | |
| 2282 | − poll_wait(file, &s->async->wait_head, wait); | |
| 2283 | − comedi_buf_write_alloc(s, s->async->prealloc_bufsz); | |
| 2284 | − if (!s->busy || !comedi_is_subdevice_running(s) || | |
| 2288 | + if (s != s_read) | |
| 2289 | + poll_wait(file, &s->async->wait_head, wait); | |
| 2290 | + if (s->busy != file || !comedi_is_subdevice_running(s) || | |
| 2285 | 2291 | !(s->async->cmd.flags & CMDF_WRITE) || |
| 2286 | − comedi_buf_write_n_allocated(s) >= bps) | |
| 2292 | + comedi_buf_write_n_available(s) >= bps) | |
| 2287 | 2293 | mask |= POLLOUT | POLLWRNORM; |
| 2288 | 2294 | } |
| 2289 | 2295 | |
| 2290 | 2296 | done: |
| 2291 | − mutex_unlock(&dev->mutex); | |
| 2297 | + up_read(&dev->attach_lock); | |
| 2292 | 2298 | return mask; |
| 2293 | 2299 | } |
| 2294 | 2300 | |
| @@ -2444,7 +2450,9 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 149 unmodified lines | ||
| 2444 | 2450 | { |
| 2445 | 2451 | struct comedi_subdevice *s; |
| 2446 | 2452 | struct comedi_async *async; |
| 2447 | − int n, m, count = 0, retval = 0; | |
| 2453 | + unsigned int n, m; | |
| 2454 | + ssize_t count = 0; | |
| 2455 | + int retval = 0; | |
| 2448 | 2456 | DECLARE_WAITQUEUE(wait, current); |
| 2449 | 2457 | struct comedi_file *cfp = file->private_data; |
| 2450 | 2458 | struct comedi_device *dev = cfp->dev; |
| @@ -2470,28 +2478,19 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 19 unmodified lines | ||
| 2470 | 2478 | } |
| 2471 | 2479 | |
| 2472 | 2480 | async = s->async; |
| 2473 | − if (!s->busy || !nbytes) | |
| 2474 | − goto out; | |
| 2475 | − if (s->busy != file) { | |
| 2476 | − retval = -EACCES; | |
| 2477 | − goto out; | |
| 2478 | − } | |
| 2479 | − if (async->cmd.flags & CMDF_WRITE) { | |
| 2481 | + if (s->busy != file || (async->cmd.flags & CMDF_WRITE)) { | |
| 2480 | 2482 | retval = -EINVAL; |
| 2481 | 2483 | goto out; |
| 2482 | 2484 | } |
| 2483 | 2485 | |
| 2484 | 2486 | add_wait_queue(&async->wait_head, &wait); |
| 2485 | − while (nbytes > 0 && !retval) { | |
| 2486 | − set_current_state(TASK_INTERRUPTIBLE); | |
| 2487 | + while (count == 0 && !retval) { | |
| 2488 | + unsigned int rp, n1, n2; | |
| 2487 | 2489 | |
| 2488 | − n = nbytes; | |
| 2490 | + set_current_state(TASK_INTERRUPTIBLE); | |
| 2489 | 2491 | |
| 2490 | 2492 | m = comedi_buf_read_n_available(s); |
| 2491 | − if (async->buf_read_ptr + m > async->prealloc_bufsz) | |
| 2492 | − m = async->prealloc_bufsz - async->buf_read_ptr; | |
| 2493 | − if (m < n) | |
| 2494 | − n = m; | |
| 2493 | + n = min_t(size_t, m, nbytes); | |
| 2495 | 2494 | |
| 2496 | 2495 | if (n == 0) { |
| 2497 | 2496 | unsigned runflags = comedi_get_subdevice_runflags(s); |
| @@ -2499,11 +2498,12 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 1 unmodified line | ||
| 2499 | 2498 | if (!comedi_is_runflags_running(runflags)) { |
| 2500 | 2499 | if (comedi_is_runflags_in_error(runflags)) |
| 2501 | 2500 | retval = -EPIPE; |
| 2502 | − else | |
| 2503 | − retval = 0; | |
| 2504 | − become_nonbusy = true; | |
| 2501 | + if (retval || nbytes) | |
| 2502 | + become_nonbusy = true; | |
| 2505 | 2503 | break; |
| 2506 | 2504 | } |
| 2505 | + if (nbytes == 0) | |
| 2506 | + break; | |
| 2507 | 2507 | if (file->f_flags & O_NONBLOCK) { |
| 2508 | 2508 | retval = -EAGAIN; |
| 2509 | 2509 | break; |
| @@ -2513,22 +2513,21 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 3 unmodified lines | ||
| 2513 | 2513 | retval = -ERESTARTSYS; |
| 2514 | 2514 | break; |
| 2515 | 2515 | } |
| 2516 | − if (!s->busy) { | |
| 2517 | − retval = 0; | |
| 2518 | − break; | |
| 2519 | − } | |
| 2520 | − if (s->busy != file) { | |
| 2521 | − retval = -EACCES; | |
| 2522 | − break; | |
| 2523 | − } | |
| 2524 | − if (async->cmd.flags & CMDF_WRITE) { | |
| 2516 | + if (s->busy != file || | |
| 2517 | + (async->cmd.flags & CMDF_WRITE)) { | |
| 2525 | 2518 | retval = -EINVAL; |
| 2526 | 2519 | break; |
| 2527 | 2520 | } |
| 2528 | 2521 | continue; |
| 2529 | 2522 | } |
| 2530 | − m = copy_to_user(buf, async->prealloc_buf + | |
| 2531 | − async->buf_read_ptr, n); | |
| 2523 | + rp = async->buf_read_ptr; | |
| 2524 | + n1 = min(n, async->prealloc_bufsz - rp); | |
| 2525 | + n2 = n - n1; | |
| 2526 | + m = copy_to_user(buf, async->prealloc_buf + rp, n1); | |
| 2527 | + if (m) | |
| 2528 | + m += n2; | |
| 2529 | + else if (n2) | |
| 2530 | + m = copy_to_user(buf + n1, async->prealloc_buf, n2); | |
| 2532 | 2531 | if (m) { |
| 2533 | 2532 | n -= m; |
| 2534 | 2533 | retval = -EFAULT; |
| @@ -2541,11 +2540,10 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 6 unmodified lines | ||
| 2541 | 2540 | nbytes -= n; |
| 2542 | 2541 | |
| 2543 | 2542 | buf += n; |
| 2544 | − break; /* makes device work like a pipe */ | |
| 2545 | 2543 | } |
| 2546 | 2544 | remove_wait_queue(&async->wait_head, &wait); |
| 2547 | 2545 | set_current_state(TASK_RUNNING); |
| 2548 | − if (become_nonbusy || comedi_is_subdevice_idle(s)) { | |
| 2546 | + if (become_nonbusy && count == 0) { | |
| 2549 | 2547 | struct comedi_subdevice *new_s; |
| 2550 | 2548 | |
| 2551 | 2549 | /* |
| @@ -2561,13 +2559,17 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, · 9 unmodified lines | ||
| 2561 | 2559 | * sufficient (unless there have been 2**32 detaches in the |
| 2562 | 2560 | * meantime!), but check the subdevice pointer as well just in |
| 2563 | 2561 | * case. |
| 2562 | + * | |
| 2563 | + * Also check the subdevice is still in a suitable state to | |
| 2564 | + * become non-busy in case it changed behind our back. | |
| 2564 | 2565 | */ |
| 2565 | 2566 | new_s = comedi_file_read_subdevice(file); |
| 2566 | 2567 | if (dev->attached && old_detach_count == dev->detach_count && |
| 2567 | − s == new_s && new_s->async == async) { | |
| 2568 | − if (become_nonbusy || comedi_buf_n_bytes_ready(s) == 0) | |
| 2569 | − do_become_nonbusy(dev, s); | |
| 2570 | − } | |
| 2568 | + s == new_s && new_s->async == async && s->busy == file && | |
| 2569 | + !(async->cmd.flags & CMDF_WRITE) && | |
| 2570 | + !comedi_is_subdevice_running(s) && | |
| 2571 | + comedi_buf_read_n_available(s) == 0) | |
| 2572 | + do_become_nonbusy(dev, s); | |
| 2571 | 2573 | mutex_unlock(&dev->mutex); |
| 2572 | 2574 | } |
| 2573 | 2575 | out: |
| @@ -2686,15 +2688,15 @@ static const struct file_operations comedi_fops = { · 112 unmodified lines | ||
| 2686 | 2688 | }; |
| 2687 | 2689 | |
| 2688 | 2690 | /** |
| 2689 | − * comedi_event - handle events for asynchronous comedi command | |
| 2690 | − * @dev: comedi_device struct | |
| 2691 | − * @s: comedi_subdevice struct associated with dev | |
| 2692 | − * Context: interrupt (usually), s->spin_lock spin-lock not held | |
| 2691 | + * comedi_event() - Handle events for asynchronous COMEDI command | |
| 2692 | + * @dev: COMEDI device. | |
| 2693 | + * @s: COMEDI subdevice. | |
| 2694 | + * Context: in_interrupt() (usually), @s->spin_lock spin-lock not held. | |
| 2693 | 2695 | * |
| 2694 | − * If an asynchronous comedi command is active on the subdevice, process | |
| 2695 | − * any COMEDI_CB_... event flags that have been set, usually by an | |
| 2696 | + * If an asynchronous COMEDI command is active on the subdevice, process | |
| 2697 | + * any %COMEDI_CB_... event flags that have been set, usually by an | |
| 2696 | 2698 | * interrupt handler. These may change the run state of the asynchronous |
| 2697 | − * command, wake a task, and/or send a SIGIO signal. | |
| 2699 | + * command, wake a task, and/or send a %SIGIO signal. | |
| 2698 | 2700 | */ |
| 2699 | 2701 | void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) |
| 2700 | 2702 | { |
| @@ -31,6 +31,7 @@ void comedi_buf_map_get(struct comedi_buf_map *bm); · 30 unmodified lines | ||
| 31 | 31 | int comedi_buf_map_put(struct comedi_buf_map *bm); |
| 32 | 32 | struct comedi_buf_map *comedi_buf_map_from_subdev_get( |
| 33 | 33 | struct comedi_subdevice *s); |
| 34 | +unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s); | |
| 34 | 35 | unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s); |
| 35 | 36 | void comedi_device_cancel_all(struct comedi_device *dev); |
| 36 | 37 | bool comedi_can_auto_free_spriv(struct comedi_subdevice *s); |
| @@ -22,8 +22,14 @@ · 21 unmodified lines | ||
| 22 | 22 | #include "comedi_pci.h" |
| 23 | 23 | |
| 24 | 24 | /** |
| 25 | − * comedi_to_pci_dev() - comedi_device pointer to pci_dev pointer. | |
| 26 | − * @dev: comedi_device struct | |
| 25 | + * comedi_to_pci_dev() - Return PCI device attached to COMEDI device | |
| 26 | + * @dev: COMEDI device. | |
| 27 | + * | |
| 28 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 29 | + * a &struct device embedded in a &struct pci_dev. | |
| 30 | + * | |
| 31 | + * Return: Attached PCI device if @dev->hw_dev is non-%NULL. | |
| 32 | + * Return %NULL if @dev->hw_dev is %NULL. | |
| 27 | 33 | */ |
| 28 | 34 | struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) |
| 29 | 35 | { |
| @@ -32,8 +38,22 @@ struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) · 2 unmodified lines | ||
| 32 | 38 | EXPORT_SYMBOL_GPL(comedi_to_pci_dev); |
| 33 | 39 | |
| 34 | 40 | /** |
| 35 | − * comedi_pci_enable() - Enable the PCI device and request the regions. | |
| 36 | − * @dev: comedi_device struct | |
| 41 | + * comedi_pci_enable() - Enable the PCI device and request the regions | |
| 42 | + * @dev: COMEDI device. | |
| 43 | + * | |
| 44 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 45 | + * a &struct device embedded in a &struct pci_dev. Enable the PCI device | |
| 46 | + * and request its regions. Set @dev->ioenabled to %true if successful, | |
| 47 | + * otherwise undo what was done. | |
| 48 | + * | |
| 49 | + * Calls to comedi_pci_enable() and comedi_pci_disable() cannot be nested. | |
| 50 | + * | |
| 51 | + * Return: | |
| 52 | + * 0 on success, | |
| 53 | + * -%ENODEV if @dev->hw_dev is %NULL, | |
| 54 | + * -%EBUSY if regions busy, | |
| 55 | + * or some negative error number if failed to enable PCI device. | |
| 56 | + * | |
| 37 | 57 | */ |
| 38 | 58 | int comedi_pci_enable(struct comedi_device *dev) |
| 39 | 59 | { |
| @@ -58,8 +78,13 @@ int comedi_pci_enable(struct comedi_device *dev) · 18 unmodified lines | ||
| 58 | 78 | EXPORT_SYMBOL_GPL(comedi_pci_enable); |
| 59 | 79 | |
| 60 | 80 | /** |
| 61 | − * comedi_pci_disable() - Release the regions and disable the PCI device. | |
| 62 | − * @dev: comedi_device struct | |
| 81 | + * comedi_pci_disable() - Release the regions and disable the PCI device | |
| 82 | + * @dev: COMEDI device. | |
| 83 | + * | |
| 84 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 85 | + * a &struct device embedded in a &struct pci_dev. If the earlier call | |
| 86 | + * to comedi_pci_enable() was successful, release the PCI device's regions | |
| 87 | + * and disable it. Reset @dev->ioenabled back to %false. | |
| 63 | 88 | */ |
| 64 | 89 | void comedi_pci_disable(struct comedi_device *dev) |
| 65 | 90 | { |
| @@ -74,8 +99,18 @@ void comedi_pci_disable(struct comedi_device *dev) · 8 unmodified lines | ||
| 74 | 99 | EXPORT_SYMBOL_GPL(comedi_pci_disable); |
| 75 | 100 | |
| 76 | 101 | /** |
| 77 | − * comedi_pci_detach() - A generic (*detach) function for PCI drivers. | |
| 78 | − * @dev: comedi_device struct | |
| 102 | + * comedi_pci_detach() - A generic "detach" handler for PCI COMEDI drivers | |
| 103 | + * @dev: COMEDI device. | |
| 104 | + * | |
| 105 | + * COMEDI drivers for PCI devices that need no special clean-up of private data | |
| 106 | + * and have no ioremapped regions other than that pointed to by @dev->mmio may | |
| 107 | + * use this function as its "detach" handler called by the COMEDI core when a | |
| 108 | + * COMEDI device is being detached from the low-level driver. It may be also | |
| 109 | + * called from a more specific "detach" handler that does additional clean-up. | |
| 110 | + * | |
| 111 | + * Free the IRQ if @dev->irq is non-zero, iounmap @dev->mmio if it is | |
| 112 | + * non-%NULL, and call comedi_pci_disable() to release the PCI device's regions | |
| 113 | + * and disable it. | |
| 79 | 114 | */ |
| 80 | 115 | void comedi_pci_detach(struct comedi_device *dev) |
| 81 | 116 | { |
| @@ -97,12 +132,19 @@ void comedi_pci_detach(struct comedi_device *dev) · 15 unmodified lines | ||
| 97 | 132 | EXPORT_SYMBOL_GPL(comedi_pci_detach); |
| 98 | 133 | |
| 99 | 134 | /** |
| 100 | − * comedi_pci_auto_config() - Configure/probe a comedi PCI driver. | |
| 101 | − * @pcidev: pci_dev struct | |
| 102 | − * @driver: comedi_driver struct | |
| 103 | − * @context: driver specific data, passed to comedi_auto_config() | |
| 135 | + * comedi_pci_auto_config() - Configure/probe a PCI COMEDI device | |
| 136 | + * @pcidev: PCI device. | |
| 137 | + * @driver: Registered COMEDI driver. | |
| 138 | + * @context: Driver specific data, passed to comedi_auto_config(). | |
| 104 | 139 | * |
| 105 | − * Typically called from the pci_driver (*probe) function. | |
| 140 | + * Typically called from the pci_driver (*probe) function. Auto-configure | |
| 141 | + * a COMEDI device, using the &struct device embedded in *@pcidev as the | |
| 142 | + * hardware device. The @context value gets passed through to @driver's | |
| 143 | + * "auto_attach" handler. The "auto_attach" handler may call | |
| 144 | + * comedi_to_pci_dev() on the passed in COMEDI device to recover @pcidev. | |
| 145 | + * | |
| 146 | + * Return: The result of calling comedi_auto_config() (0 on success, or | |
| 147 | + * a negative error number on failure). | |
| 106 | 148 | */ |
| 107 | 149 | int comedi_pci_auto_config(struct pci_dev *pcidev, |
| 108 | 150 | struct comedi_driver *driver, |
| @@ -113,10 +155,18 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, · 4 unmodified lines | ||
| 113 | 155 | EXPORT_SYMBOL_GPL(comedi_pci_auto_config); |
| 114 | 156 | |
| 115 | 157 | /** |
| 116 | − * comedi_pci_auto_unconfig() - Unconfigure/remove a comedi PCI driver. | |
| 117 | − * @pcidev: pci_dev struct | |
| 158 | + * comedi_pci_auto_unconfig() - Unconfigure/remove a PCI COMEDI device | |
| 159 | + * @pcidev: PCI device. | |
| 160 | + * | |
| 161 | + * Typically called from the pci_driver (*remove) function. Auto-unconfigure | |
| 162 | + * a COMEDI device attached to this PCI device, using a pointer to the | |
| 163 | + * &struct device embedded in *@pcidev as the hardware device. The COMEDI | |
| 164 | + * driver's "detach" handler will be called during unconfiguration of the | |
| 165 | + * COMEDI device. | |
| 118 | 166 | * |
| 119 | − * Typically called from the pci_driver (*remove) function. | |
| 167 | + * Note that the COMEDI device may have already been unconfigured using the | |
| 168 | + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it | |
| 169 | + * again should be ignored. | |
| 120 | 170 | */ |
| 121 | 171 | void comedi_pci_auto_unconfig(struct pci_dev *pcidev) |
| 122 | 172 | { |
| @@ -125,13 +175,15 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev) · 2 unmodified lines | ||
| 125 | 175 | EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); |
| 126 | 176 | |
| 127 | 177 | /** |
| 128 | − * comedi_pci_driver_register() - Register a comedi PCI driver. | |
| 129 | − * @comedi_driver: comedi_driver struct | |
| 130 | − * @pci_driver: pci_driver struct | |
| 178 | + * comedi_pci_driver_register() - Register a PCI COMEDI driver | |
| 179 | + * @comedi_driver: COMEDI driver to be registered. | |
| 180 | + * @pci_driver: PCI driver to be registered. | |
| 181 | + * | |
| 182 | + * This function is called from the module_init() of PCI COMEDI driver modules | |
| 183 | + * to register the COMEDI driver and the PCI driver. Do not call it directly, | |
| 184 | + * use the module_comedi_pci_driver() helper macro instead. | |
| 131 | 185 | * |
| 132 | − * This function is used for the module_init() of comedi PCI drivers. | |
| 133 | − * Do not call it directly, use the module_comedi_pci_driver() helper | |
| 134 | − * macro instead. | |
| 186 | + * Return: 0 on success, or a negative error number on failure. | |
| 135 | 187 | */ |
| 136 | 188 | int comedi_pci_driver_register(struct comedi_driver *comedi_driver, |
| 137 | 189 | struct pci_driver *pci_driver) |
| @@ -153,13 +205,13 @@ int comedi_pci_driver_register(struct comedi_driver *comedi_driver, · 15 unmodified lines | ||
| 153 | 205 | EXPORT_SYMBOL_GPL(comedi_pci_driver_register); |
| 154 | 206 | |
| 155 | 207 | /** |
| 156 | − * comedi_pci_driver_unregister() - Unregister a comedi PCI driver. | |
| 157 | − * @comedi_driver: comedi_driver struct | |
| 158 | − * @pci_driver: pci_driver struct | |
| 208 | + * comedi_pci_driver_unregister() - Unregister a PCI COMEDI driver | |
| 209 | + * @comedi_driver: COMEDI driver to be unregistered. | |
| 210 | + * @pci_driver: PCI driver to be unregistered. | |
| 159 | 211 | * |
| 160 | − * This function is used for the module_exit() of comedi PCI drivers. | |
| 161 | − * Do not call it directly, use the module_comedi_pci_driver() helper | |
| 162 | − * macro instead. | |
| 212 | + * This function is called from the module_exit() of PCI COMEDI driver modules | |
| 213 | + * to unregister the PCI driver and the COMEDI driver. Do not call it | |
| 214 | + * directly, use the module_comedi_pci_driver() helper macro instead. | |
| 163 | 215 | */ |
| 164 | 216 | void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, |
| 165 | 217 | struct pci_driver *pci_driver) |
| @@ -22,8 +22,14 @@ · 21 unmodified lines | ||
| 22 | 22 | #include "comedi_pcmcia.h" |
| 23 | 23 | |
| 24 | 24 | /** |
| 25 | − * comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer. | |
| 26 | − * @dev: comedi_device struct | |
| 25 | + * comedi_to_pcmcia_dev() - Return PCMCIA device attached to COMEDI device | |
| 26 | + * @dev: COMEDI device. | |
| 27 | + * | |
| 28 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 29 | + * a &struct device embedded in a &struct pcmcia_device. | |
| 30 | + * | |
| 31 | + * Return: Attached PCMCIA device if @dev->hw_dev is non-%NULL. | |
| 32 | + * Return %NULL if @dev->hw_dev is %NULL. | |
| 27 | 33 | */ |
| 28 | 34 | struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev) |
| 29 | 35 | { |
| @@ -41,13 +47,35 @@ static int comedi_pcmcia_conf_check(struct pcmcia_device *link, · 11 unmodified lines | ||
| 41 | 47 | } |
| 42 | 48 | |
| 43 | 49 | /** |
| 44 | − * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device. | |
| 45 | − * @dev: comedi_device struct | |
| 46 | − * @conf_check: optional callback to check the pcmcia_device configuration | |
| 50 | + * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device | |
| 51 | + * @dev: COMEDI device. | |
| 52 | + * @conf_check: Optional callback to check each configuration option of the | |
| 53 | + * PCMCIA device and request I/O regions. | |
| 54 | + * | |
| 55 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a a | |
| 56 | + * &struct device embedded in a &struct pcmcia_device. The comedi PCMCIA | |
| 57 | + * driver needs to set the 'config_flags' member in the &struct pcmcia_device, | |
| 58 | + * as appropriate for that driver, before calling this function in order to | |
| 59 | + * allow pcmcia_loop_config() to do its internal autoconfiguration. | |
| 60 | + * | |
| 61 | + * If @conf_check is %NULL it is set to a default function. If is | |
| 62 | + * passed to pcmcia_loop_config() and should return %0 if the configuration | |
| 63 | + * is valid and I/O regions requested successfully, otherwise it should return | |
| 64 | + * a negative error value. The default function returns -%EINVAL if the | |
| 65 | + * 'config_index' member is %0, otherwise it calls pcmcia_request_io() and | |
| 66 | + * returns the result. | |
| 67 | + * | |
| 68 | + * If the above configuration check passes, pcmcia_enable_device() is called | |
| 69 | + * to set up and activate the PCMCIA device. | |
| 47 | 70 | * |
| 48 | − * The comedi PCMCIA driver needs to set the link->config_flags, as | |
| 49 | − * appropriate for that driver, before calling this function in order | |
| 50 | − * to allow pcmcia_loop_config() to do its internal autoconfiguration. | |
| 71 | + * If this function returns an error, comedi_pcmcia_disable() should be called | |
| 72 | + * to release requested resources. | |
| 73 | + * | |
| 74 | + * Return: | |
| 75 | + * 0 on success, | |
| 76 | + * -%ENODEV id @dev->hw_dev is %NULL, | |
| 77 | + * a negative error number from pcmcia_loop_config() if it fails, | |
| 78 | + * or a negative error number from pcmcia_enable_device() if it fails. | |
| 51 | 79 | */ |
| 52 | 80 | int comedi_pcmcia_enable(struct comedi_device *dev, |
| 53 | 81 | int (*conf_check)(struct pcmcia_device *, void *)) |
| @@ -70,8 +98,12 @@ int comedi_pcmcia_enable(struct comedi_device *dev, · 16 unmodified lines | ||
| 70 | 98 | EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); |
| 71 | 99 | |
| 72 | 100 | /** |
| 73 | − * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions. | |
| 74 | − * @dev: comedi_device struct | |
| 101 | + * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions | |
| 102 | + * @dev: COMEDI device. | |
| 103 | + * | |
| 104 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 105 | + * a &struct device embedded in a &struct pcmcia_device. Call | |
| 106 | + * pcmcia_disable_device() to disable and clean up the PCMCIA device. | |
| 75 | 107 | */ |
| 76 | 108 | void comedi_pcmcia_disable(struct comedi_device *dev) |
| 77 | 109 | { |
| @@ -83,11 +115,17 @@ void comedi_pcmcia_disable(struct comedi_device *dev) · 5 unmodified lines | ||
| 83 | 115 | EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); |
| 84 | 116 | |
| 85 | 117 | /** |
| 86 | − * comedi_pcmcia_auto_config() - Configure/probe a comedi PCMCIA driver. | |
| 87 | − * @link: pcmcia_device struct | |
| 88 | − * @driver: comedi_driver struct | |
| 118 | + * comedi_pcmcia_auto_config() - Configure/probe a PCMCIA COMEDI device | |
| 119 | + * @link: PCMCIA device. | |
| 120 | + * @driver: Registered COMEDI driver. | |
| 121 | + * | |
| 122 | + * Typically called from the pcmcia_driver (*probe) function. Auto-configure | |
| 123 | + * a COMEDI device, using a pointer to the &struct device embedded in *@link | |
| 124 | + * as the hardware device. The @driver's "auto_attach" handler may call | |
| 125 | + * comedi_to_pcmcia_dev() on the passed in COMEDI device to recover @link. | |
| 89 | 126 | * |
| 90 | − * Typically called from the pcmcia_driver (*probe) function. | |
| 127 | + * Return: The result of calling comedi_auto_config() (0 on success, or a | |
| 128 | + * negative error number on failure). | |
| 91 | 129 | */ |
| 92 | 130 | int comedi_pcmcia_auto_config(struct pcmcia_device *link, |
| 93 | 131 | struct comedi_driver *driver) |
| @@ -97,10 +135,18 @@ int comedi_pcmcia_auto_config(struct pcmcia_device *link, · 3 unmodified lines | ||
| 97 | 135 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); |
| 98 | 136 | |
| 99 | 137 | /** |
| 100 | − * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a comedi PCMCIA driver. | |
| 101 | − * @link: pcmcia_device struct | |
| 138 | + * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a PCMCIA COMEDI device | |
| 139 | + * @link: PCMCIA device. | |
| 102 | 140 | * |
| 103 | 141 | * Typically called from the pcmcia_driver (*remove) function. |
| 142 | + * Auto-unconfigure a COMEDI device attached to this PCMCIA device, using a | |
| 143 | + * pointer to the &struct device embedded in *@link as the hardware device. | |
| 144 | + * The COMEDI driver's "detach" handler will be called during unconfiguration | |
| 145 | + * of the COMEDI device. | |
| 146 | + * | |
| 147 | + * Note that the COMEDI device may have already been unconfigured using the | |
| 148 | + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it | |
| 149 | + * again should be ignored. | |
| 104 | 150 | */ |
| 105 | 151 | void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) |
| 106 | 152 | { |
| @@ -109,13 +155,15 @@ void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) · 2 unmodified lines | ||
| 109 | 155 | EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); |
| 110 | 156 | |
| 111 | 157 | /** |
| 112 | − * comedi_pcmcia_driver_register() - Register a comedi PCMCIA driver. | |
| 113 | − * @comedi_driver: comedi_driver struct | |
| 114 | − * @pcmcia_driver: pcmcia_driver struct | |
| 158 | + * comedi_pcmcia_driver_register() - Register a PCMCIA COMEDI driver | |
| 159 | + * @comedi_driver: COMEDI driver to be registered. | |
| 160 | + * @pcmcia_driver: PCMCIA driver to be registered. | |
| 161 | + * | |
| 162 | + * This function is used for the module_init() of PCMCIA COMEDI driver modules | |
| 163 | + * to register the COMEDI driver and the PCMCIA driver. Do not call it | |
| 164 | + * directly, use the module_comedi_pcmcia_driver() helper macro instead. | |
| 115 | 165 | * |
| 116 | − * This function is used for the module_init() of comedi USB drivers. | |
| 117 | − * Do not call it directly, use the module_comedi_pcmcia_driver() helper | |
| 118 | − * macro instead. | |
| 166 | + * Return: 0 on success, or a negative error number on failure. | |
| 119 | 167 | */ |
| 120 | 168 | int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, |
| 121 | 169 | struct pcmcia_driver *pcmcia_driver) |
| @@ -137,13 +185,13 @@ int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, · 15 unmodified lines | ||
| 137 | 185 | EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); |
| 138 | 186 | |
| 139 | 187 | /** |
| 140 | − * comedi_pcmcia_driver_unregister() - Unregister a comedi PCMCIA driver. | |
| 141 | − * @comedi_driver: comedi_driver struct | |
| 142 | − * @pcmcia_driver: pcmcia_driver struct | |
| 188 | + * comedi_pcmcia_driver_unregister() - Unregister a PCMCIA COMEDI driver | |
| 189 | + * @comedi_driver: COMEDI driver to be registered. | |
| 190 | + * @pcmcia_driver: PCMCIA driver to be registered. | |
| 143 | 191 | * |
| 144 | − * This function is used for the module_exit() of comedi PCMCIA drivers. | |
| 145 | − * Do not call it directly, use the module_comedi_pcmcia_driver() helper | |
| 146 | − * macro instead. | |
| 192 | + * This function is called from the module_exit() of PCMCIA COMEDI driver | |
| 193 | + * modules to unregister the PCMCIA driver and the COMEDI driver. Do not call | |
| 194 | + * it directly, use the module_comedi_pcmcia_driver() helper macro instead. | |
| 147 | 195 | */ |
| 148 | 196 | void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, |
| 149 | 197 | struct pcmcia_driver *pcmcia_driver) |
| @@ -21,8 +21,14 @@ · 20 unmodified lines | ||
| 21 | 21 | #include "comedi_usb.h" |
| 22 | 22 | |
| 23 | 23 | /** |
| 24 | − * comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer. | |
| 25 | − * @dev: comedi_device struct | |
| 24 | + * comedi_to_usb_interface() - Return USB interface attached to COMEDI device | |
| 25 | + * @dev: COMEDI device. | |
| 26 | + * | |
| 27 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 28 | + * a &struct device embedded in a &struct usb_interface. | |
| 29 | + * | |
| 30 | + * Return: Attached USB interface if @dev->hw_dev is non-%NULL. | |
| 31 | + * Return %NULL if @dev->hw_dev is %NULL. | |
| 26 | 32 | */ |
| 27 | 33 | struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) |
| 28 | 34 | { |
| @@ -31,8 +37,14 @@ struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) · 2 unmodified lines | ||
| 31 | 37 | EXPORT_SYMBOL_GPL(comedi_to_usb_interface); |
| 32 | 38 | |
| 33 | 39 | /** |
| 34 | − * comedi_to_usb_dev() - comedi_device pointer to usb_device pointer. | |
| 35 | − * @dev: comedi_device struct | |
| 40 | + * comedi_to_usb_dev() - Return USB device attached to COMEDI device | |
| 41 | + * @dev: COMEDI device. | |
| 42 | + * | |
| 43 | + * Assuming @dev->hw_dev is non-%NULL, it is assumed to be pointing to a | |
| 44 | + * a &struct device embedded in a &struct usb_interface. | |
| 45 | + * | |
| 46 | + * Return: USB device to which the USB interface belongs if @dev->hw_dev is | |
| 47 | + * non-%NULL. Return %NULL if @dev->hw_dev is %NULL. | |
| 36 | 48 | */ |
| 37 | 49 | struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) |
| 38 | 50 | { |
| @@ -43,12 +55,19 @@ struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) · 4 unmodified lines | ||
| 43 | 55 | EXPORT_SYMBOL_GPL(comedi_to_usb_dev); |
| 44 | 56 | |
| 45 | 57 | /** |
| 46 | − * comedi_usb_auto_config() - Configure/probe a comedi USB driver. | |
| 47 | − * @intf: usb_interface struct | |
| 48 | − * @driver: comedi_driver struct | |
| 49 | − * @context: driver specific data, passed to comedi_auto_config() | |
| 58 | + * comedi_usb_auto_config() - Configure/probe a USB COMEDI driver | |
| 59 | + * @intf: USB interface. | |
| 60 | + * @driver: Registered COMEDI driver. | |
| 61 | + * @context: Driver specific data, passed to comedi_auto_config(). | |
| 50 | 62 | * |
| 51 | − * Typically called from the usb_driver (*probe) function. | |
| 63 | + * Typically called from the usb_driver (*probe) function. Auto-configure a | |
| 64 | + * COMEDI device, using a pointer to the &struct device embedded in *@intf as | |
| 65 | + * the hardware device. The @context value gets passed through to @driver's | |
| 66 | + * "auto_attach" handler. The "auto_attach" handler may call | |
| 67 | + * comedi_to_usb_interface() on the passed in COMEDI device to recover @intf. | |
| 68 | + * | |
| 69 | + * Return: The result of calling comedi_auto_config() (%0 on success, or | |
| 70 | + * a negative error number on failure). | |
| 52 | 71 | */ |
| 53 | 72 | int comedi_usb_auto_config(struct usb_interface *intf, |
| 54 | 73 | struct comedi_driver *driver, |
| @@ -59,10 +78,18 @@ int comedi_usb_auto_config(struct usb_interface *intf, · 4 unmodified lines | ||
| 59 | 78 | EXPORT_SYMBOL_GPL(comedi_usb_auto_config); |
| 60 | 79 | |
| 61 | 80 | /** |
| 62 | − * comedi_pci_auto_unconfig() - Unconfigure/disconnect a comedi USB driver. | |
| 63 | − * @intf: usb_interface struct | |
| 81 | + * comedi_usb_auto_unconfig() - Unconfigure/disconnect a USB COMEDI device | |
| 82 | + * @intf: USB interface. | |
| 64 | 83 | * |
| 65 | 84 | * Typically called from the usb_driver (*disconnect) function. |
| 85 | + * Auto-unconfigure a COMEDI device attached to this USB interface, using a | |
| 86 | + * pointer to the &struct device embedded in *@intf as the hardware device. | |
| 87 | + * The COMEDI driver's "detach" handler will be called during unconfiguration | |
| 88 | + * of the COMEDI device. | |
| 89 | + * | |
| 90 | + * Note that the COMEDI device may have already been unconfigured using the | |
| 91 | + * %COMEDI_DEVCONFIG ioctl, in which case this attempt to unconfigure it | |
| 92 | + * again should be ignored. | |
| 66 | 93 | */ |
| 67 | 94 | void comedi_usb_auto_unconfig(struct usb_interface *intf) |
| 68 | 95 | { |
| @@ -71,13 +98,15 @@ void comedi_usb_auto_unconfig(struct usb_interface *intf) · 2 unmodified lines | ||
| 71 | 98 | EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); |
| 72 | 99 | |
| 73 | 100 | /** |
| 74 | − * comedi_usb_driver_register() - Register a comedi USB driver. | |
| 75 | − * @comedi_driver: comedi_driver struct | |
| 76 | − * @usb_driver: usb_driver struct | |
| 101 | + * comedi_usb_driver_register() - Register a USB COMEDI driver | |
| 102 | + * @comedi_driver: COMEDI driver to be registered. | |
| 103 | + * @usb_driver: USB driver to be registered. | |
| 104 | + * | |
| 105 | + * This function is called from the module_init() of USB COMEDI driver modules | |
| 106 | + * to register the COMEDI driver and the USB driver. Do not call it directly, | |
| 107 | + * use the module_comedi_usb_driver() helper macro instead. | |
| 77 | 108 | * |
| 78 | − * This function is used for the module_init() of comedi USB drivers. | |
| 79 | − * Do not call it directly, use the module_comedi_usb_driver() helper | |
| 80 | − * macro instead. | |
| 109 | + * Return: %0 on success, or a negative error number on failure. | |
| 81 | 110 | */ |
| 82 | 111 | int comedi_usb_driver_register(struct comedi_driver *comedi_driver, |
| 83 | 112 | struct usb_driver *usb_driver) |
| @@ -99,13 +128,13 @@ int comedi_usb_driver_register(struct comedi_driver *comedi_driver, · 15 unmodified lines | ||
| 99 | 128 | EXPORT_SYMBOL_GPL(comedi_usb_driver_register); |
| 100 | 129 | |
| 101 | 130 | /** |
| 102 | − * comedi_usb_driver_unregister() - Unregister a comedi USB driver. | |
| 103 | − * @comedi_driver: comedi_driver struct | |
| 104 | − * @usb_driver: usb_driver struct | |
| 131 | + * comedi_usb_driver_unregister() - Unregister a USB COMEDI driver | |
| 132 | + * @comedi_driver: COMEDI driver to be registered. | |
| 133 | + * @usb_driver: USB driver to be registered. | |
| 105 | 134 | * |
| 106 | − * This function is used for the module_exit() of comedi USB drivers. | |
| 107 | − * Do not call it directly, use the module_comedi_usb_driver() helper | |
| 108 | − * macro instead. | |
| 135 | + * This function is called from the module_exit() of USB COMEDI driver modules | |
| 136 | + * to unregister the USB driver and the COMEDI driver. Do not call it | |
| 137 | + * directly, use the module_comedi_usb_driver() helper macro instead. | |
| 109 | 138 | */ |
| 110 | 139 | void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, |
| 111 | 140 | struct usb_driver *usb_driver) |
| @@ -1,20 +1,20 @@ | ||
| 1 | 1 | /* |
| 2 | − include/linux/comedidev.h | |
| 3 | − header file for kernel-only structures, variables, and constants | |
| 4 | − | |
| 5 | − COMEDI - Linux Control and Measurement Device Interface | |
| 6 | − Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> | |
| 7 | − | |
| 8 | − This program is free software; you can redistribute it and/or modify | |
| 9 | − it under the terms of the GNU General Public License as published by | |
| 10 | − the Free Software Foundation; either version 2 of the License, or | |
| 11 | − (at your option) any later version. | |
| 12 | − | |
| 13 | − This program is distributed in the hope that it will be useful, | |
| 14 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | − GNU General Public License for more details. | |
| 17 | −*/ | |
| 2 | + * comedidev.h | |
| 3 | + * header file for kernel-only structures, variables, and constants | |
| 4 | + * | |
| 5 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 6 | + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License as published by | |
| 10 | + * the Free Software Foundation; either version 2 of the License, or | |
| 11 | + * (at your option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + */ | |
| 18 | 18 | |
| 19 | 19 | #ifndef _COMEDIDEV_H |
| 20 | 20 | #define _COMEDIDEV_H |
| @@ -34,6 +34,131 @@ · 13 unmodified lines | ||
| 34 | 34 | |
| 35 | 35 | #define COMEDI_NUM_BOARD_MINORS 0x30 |
| 36 | 36 | |
| 37 | +/** | |
| 38 | + * struct comedi_subdevice - Working data for a COMEDI subdevice | |
| 39 | + * @device: COMEDI device to which this subdevice belongs. (Initialized by | |
| 40 | + * comedi_alloc_subdevices().) | |
| 41 | + * @index: Index of this subdevice within device's array of subdevices. | |
| 42 | + * (Initialized by comedi_alloc_subdevices().) | |
| 43 | + * @type: Type of subdevice from &enum comedi_subdevice_type. (Initialized by | |
| 44 | + * the low-level driver.) | |
| 45 | + * @n_chan: Number of channels the subdevice supports. (Initialized by the | |
| 46 | + * low-level driver.) | |
| 47 | + * @subdev_flags: Various "SDF" flags indicating aspects of the subdevice to | |
| 48 | + * the COMEDI core and user application. (Initialized by the low-level | |
| 49 | + * driver.) | |
| 50 | + * @len_chanlist: Maximum length of a channel list if the subdevice supports | |
| 51 | + * asynchronous acquisition commands. (Optionally initialized by the | |
| 52 | + * low-level driver, or changed from 0 to 1 during post-configuration.) | |
| 53 | + * @private: Private data pointer which is either set by the low-level driver | |
| 54 | + * itself, or by a call to comedi_alloc_spriv() which allocates storage. | |
| 55 | + * In the latter case, the storage is automatically freed after the | |
| 56 | + * low-level driver's "detach" handler is called for the device. | |
| 57 | + * (Initialized by the low-level driver.) | |
| 58 | + * @async: Pointer to &struct comedi_async id the subdevice supports | |
| 59 | + * asynchronous acquisition commands. (Allocated and initialized during | |
| 60 | + * post-configuration if needed.) | |
| 61 | + * @lock: Pointer to a file object that performed a %COMEDI_LOCK ioctl on the | |
| 62 | + * subdevice. (Initially NULL.) | |
| 63 | + * @busy: Pointer to a file object that is performing an asynchronous | |
| 64 | + * acquisition command on the subdevice. (Initially NULL.) | |
| 65 | + * @runflags: Internal flags for use by COMEDI core, mostly indicating whether | |
| 66 | + * an asynchronous acquisition command is running. | |
| 67 | + * @spin_lock: Generic spin-lock for use by the COMEDI core and the low-level | |
| 68 | + * driver. (Initialized by comedi_alloc_subdevices().) | |
| 69 | + * @io_bits: Bit-mask indicating the channel directions for a DIO subdevice | |
| 70 | + * with no more than 32 channels. A '1' at a bit position indicates the | |
| 71 | + * corresponding channel is configured as an output. (Initialized by the | |
| 72 | + * low-level driver for a DIO subdevice. Forced to all-outputs during | |
| 73 | + * post-configuration for a digital output subdevice.) | |
| 74 | + * @maxdata: If non-zero, this is the maximum raw data value of each channel. | |
| 75 | + * If zero, the maximum data value is channel-specific. (Initialized by | |
| 76 | + * the low-level driver.) | |
| 77 | + * @maxdata_list: If the maximum data value is channel-specific, this points | |
| 78 | + * to an array of maximum data values indexed by channel index. | |
| 79 | + * (Initialized by the low-level driver.) | |
| 80 | + * @range_table: If non-NULL, this points to a COMEDI range table for the | |
| 81 | + * subdevice. If NULL, the range table is channel-specific. (Initialized | |
| 82 | + * by the low-level driver, will be set to an "invalid" range table during | |
| 83 | + * post-configuration if @range_table and @range_table_list are both | |
| 84 | + * NULL.) | |
| 85 | + * @range_table_list: If the COMEDI range table is channel-specific, this | |
| 86 | + * points to an array of pointers to COMEDI range tables indexed by | |
| 87 | + * channel number. (Initialized by the low-level driver.) | |
| 88 | + * @chanlist: Not used. | |
| 89 | + * @insn_read: Optional pointer to a handler for the %INSN_READ instruction. | |
| 90 | + * (Initialized by the low-level driver, or set to a default handler | |
| 91 | + * during post-configuration.) | |
| 92 | + * @insn_write: Optional pointer to a handler for the %INSN_WRITE instruction. | |
| 93 | + * (Initialized by the low-level driver, or set to a default handler | |
| 94 | + * during post-configuration.) | |
| 95 | + * @insn_bits: Optional pointer to a handler for the %INSN_BITS instruction | |
| 96 | + * for a digital input, digital output or digital input/output subdevice. | |
| 97 | + * (Initialized by the low-level driver, or set to a default handler | |
| 98 | + * during post-configuration.) | |
| 99 | + * @insn_config: Optional pointer to a handler for the %INSN_CONFIG | |
| 100 | + * instruction. (Initialized by the low-level driver, or set to a default | |
| 101 | + * handler during post-configuration.) | |
| 102 | + * @do_cmd: If the subdevice supports asynchronous acquisition commands, this | |
| 103 | + * points to a handler to set it up in hardware. (Initialized by the | |
| 104 | + * low-level driver.) | |
| 105 | + * @do_cmdtest: If the subdevice supports asynchronous acquisition commands, | |
| 106 | + * this points to a handler used to check and possibly tweak a prospective | |
| 107 | + * acquisition command without setting it up in hardware. (Initialized by | |
| 108 | + * the low-level driver.) | |
| 109 | + * @poll: If the subdevice supports asynchronous acquisition commands, this | |
| 110 | + * is an optional pointer to a handler for the %COMEDI_POLL ioctl which | |
| 111 | + * instructs the low-level driver to synchronize buffers. (Initialized by | |
| 112 | + * the low-level driver if needed.) | |
| 113 | + * @cancel: If the subdevice supports asynchronous acquisition commands, this | |
| 114 | + * points to a handler used to terminate a running command. (Initialized | |
| 115 | + * by the low-level driver.) | |
| 116 | + * @buf_change: If the subdevice supports asynchronous acquisition commands, | |
| 117 | + * this is an optional pointer to a handler that is called when the data | |
| 118 | + * buffer for handling asynchronous commands is allocated or reallocated. | |
| 119 | + * (Initialized by the low-level driver if needed.) | |
| 120 | + * @munge: If the subdevice supports asynchronous acquisition commands and | |
| 121 | + * uses DMA to transfer data from the hardware to the acquisition buffer, | |
| 122 | + * this points to a function used to "munge" the data values from the | |
| 123 | + * hardware into the format expected by COMEDI. (Initialized by the | |
| 124 | + * low-level driver if needed.) | |
| 125 | + * @async_dma_dir: If the subdevice supports asynchronous acquisition commands | |
| 126 | + * and uses DMA to transfer data from the hardware to the acquisition | |
| 127 | + * buffer, this sets the DMA direction for the buffer. (initialized to | |
| 128 | + * %DMA_NONE by comedi_alloc_subdevices() and changed by the low-level | |
| 129 | + * driver if necessary.) | |
| 130 | + * @state: Handy bit-mask indicating the output states for a DIO or digital | |
| 131 | + * output subdevice with no more than 32 channels. (Initialized by the | |
| 132 | + * low-level driver.) | |
| 133 | + * @class_dev: If the subdevice supports asynchronous acquisition commands, | |
| 134 | + * this points to a sysfs comediX_subdY device where X is the minor device | |
| 135 | + * number of the COMEDI device and Y is the subdevice number. The minor | |
| 136 | + * device number for the sysfs device is allocated dynamically in the | |
| 137 | + * range 48 to 255. This is used to allow the COMEDI device to be opened | |
| 138 | + * with a different default read or write subdevice. (Allocated during | |
| 139 | + * post-configuration if needed.) | |
| 140 | + * @minor: If @class_dev is set, this is its dynamically allocated minor | |
| 141 | + * device number. (Set during post-configuration if necessary.) | |
| 142 | + * @readback: Optional pointer to memory allocated by | |
| 143 | + * comedi_alloc_subdev_readback() used to hold the values written to | |
| 144 | + * analog output channels so they can be read back. The storage is | |
| 145 | + * automatically freed after the low-level driver's "detach" handler is | |
| 146 | + * called for the device. (Initialized by the low-level driver.) | |
| 147 | + * | |
| 148 | + * This is the main control structure for a COMEDI subdevice. If the subdevice | |
| 149 | + * supports asynchronous acquisition commands, additional information is stored | |
| 150 | + * in the &struct comedi_async pointed to by @async. | |
| 151 | + * | |
| 152 | + * Most of the subdevice is initialized by the low-level driver's "attach" or | |
| 153 | + * "auto_attach" handlers but parts of it are initialized by | |
| 154 | + * comedi_alloc_subdevices(), and other parts are initialized during | |
| 155 | + * post-configuration on return from that handler. | |
| 156 | + * | |
| 157 | + * A low-level driver that sets @insn_bits for a digital input, digital output, | |
| 158 | + * or DIO subdevice may leave @insn_read and @insn_write uninitialized, in | |
| 159 | + * which case they will be set to a default handler during post-configuration | |
| 160 | + * that uses @insn_bits to emulate the %INSN_READ and %INSN_WRITE instructions. | |
| 161 | + */ | |
| 37 | 162 | struct comedi_subdevice { |
| 38 | 163 | struct comedi_device *device; |
| 39 | 164 | int index; |
| @@ -49,7 +174,7 @@ struct comedi_subdevice { · 9 unmodified lines | ||
| 49 | 174 | void *lock; |
| 50 | 175 | void *busy; |
| 51 | 176 | unsigned runflags; |
| 52 | − spinlock_t spin_lock; | |
| 177 | + spinlock_t spin_lock; /* generic spin-lock for COMEDI and drivers */ | |
| 53 | 178 | |
| 54 | 179 | unsigned int io_bits; |
| 55 | 180 | |
| @@ -92,11 +217,40 @@ struct comedi_subdevice { · 36 unmodified lines | ||
| 92 | 217 | unsigned int *readback; |
| 93 | 218 | }; |
| 94 | 219 | |
| 220 | +/** | |
| 221 | + * struct comedi_buf_page - Describe a page of a COMEDI buffer | |
| 222 | + * @virt_addr: Kernel address of page. | |
| 223 | + * @dma_addr: DMA address of page if in DMA coherent memory. | |
| 224 | + */ | |
| 95 | 225 | struct comedi_buf_page { |
| 96 | 226 | void *virt_addr; |
| 97 | 227 | dma_addr_t dma_addr; |
| 98 | 228 | }; |
| 99 | 229 | |
| 230 | +/** | |
| 231 | + * struct comedi_buf_map - Describe pages in a COMEDI buffer | |
| 232 | + * @dma_hw_dev: Low-level hardware &struct device pointer copied from the | |
| 233 | + * COMEDI device's hw_dev member. | |
| 234 | + * @page_list: Pointer to array of &struct comedi_buf_page, one for each | |
| 235 | + * page in the buffer. | |
| 236 | + * @n_pages: Number of pages in the buffer. | |
| 237 | + * @dma_dir: DMA direction used to allocate pages of DMA coherent memory, | |
| 238 | + * or %DMA_NONE if pages allocated from regular memory. | |
| 239 | + * @refcount: &struct kref reference counter used to free the buffer. | |
| 240 | + * | |
| 241 | + * A COMEDI data buffer is allocated as individual pages, either in | |
| 242 | + * conventional memory or DMA coherent memory, depending on the attached, | |
| 243 | + * low-level hardware device. (The buffer pages also get mapped into the | |
| 244 | + * kernel's contiguous virtual address space pointed to by the 'prealloc_buf' | |
| 245 | + * member of &struct comedi_async.) | |
| 246 | + * | |
| 247 | + * The buffer is normally freed when the COMEDI device is detached from the | |
| 248 | + * low-level driver (which may happen due to device removal), but if it happens | |
| 249 | + * to be mmapped at the time, the pages cannot be freed until the buffer has | |
| 250 | + * been munmapped. That is what the reference counter is for. (The virtual | |
| 251 | + * address space pointed by 'prealloc_buf' is freed when the COMEDI device is | |
| 252 | + * detached.) | |
| 253 | + */ | |
| 100 | 254 | struct comedi_buf_map { |
| 101 | 255 | struct device *dma_hw_dev; |
| 102 | 256 | struct comedi_buf_page *page_list; |
| @@ -106,61 +260,66 @@ struct comedi_buf_map { · 3 unmodified lines | ||
| 106 | 260 | }; |
| 107 | 261 | |
| 108 | 262 | /** |
| 109 | − * struct comedi_async - control data for asynchronous comedi commands | |
| 110 | − * @prealloc_buf: preallocated buffer | |
| 111 | − * @prealloc_bufsz: buffer size (in bytes) | |
| 112 | − * @buf_map: map of buffer pages | |
| 113 | − * @max_bufsize: maximum buffer size (in bytes) | |
| 114 | − * @buf_write_count: "write completed" count (in bytes, modulo 2**32) | |
| 115 | − * @buf_write_alloc_count: "allocated for writing" count (in bytes, | |
| 116 | − * modulo 2**32) | |
| 117 | − * @buf_read_count: "read completed" count (in bytes, modulo 2**32) | |
| 118 | − * @buf_read_alloc_count: "allocated for reading" count (in bytes, | |
| 119 | − * modulo 2**32) | |
| 120 | − * @buf_write_ptr: buffer position for writer | |
| 121 | − * @buf_read_ptr: buffer position for reader | |
| 122 | − * @cur_chan: current position in chanlist for scan (for those | |
| 123 | − * drivers that use it) | |
| 124 | − * @scans_done: the number of scans completed (COMEDI_CB_EOS) | |
| 125 | − * @scan_progress: amount received or sent for current scan (in bytes) | |
| 126 | − * @munge_chan: current position in chanlist for "munging" | |
| 127 | − * @munge_count: "munge" count (in bytes, modulo 2**32) | |
| 128 | − * @munge_ptr: buffer position for "munging" | |
| 129 | − * @events: bit-vector of events that have occurred | |
| 130 | − * @cmd: details of comedi command in progress | |
| 131 | − * @wait_head: task wait queue for file reader or writer | |
| 132 | − * @cb_mask: bit-vector of events that should wake waiting tasks | |
| 133 | − * @inttrig: software trigger function for command, or NULL | |
| 263 | + * struct comedi_async - Control data for asynchronous COMEDI commands | |
| 264 | + * @prealloc_buf: Kernel virtual address of allocated acquisition buffer. | |
| 265 | + * @prealloc_bufsz: Buffer size (in bytes). | |
| 266 | + * @buf_map: Map of buffer pages. | |
| 267 | + * @max_bufsize: Maximum allowed buffer size (in bytes). | |
| 268 | + * @buf_write_count: "Write completed" count (in bytes, modulo 2**32). | |
| 269 | + * @buf_write_alloc_count: "Allocated for writing" count (in bytes, | |
| 270 | + * modulo 2**32). | |
| 271 | + * @buf_read_count: "Read completed" count (in bytes, modulo 2**32). | |
| 272 | + * @buf_read_alloc_count: "Allocated for reading" count (in bytes, | |
| 273 | + * modulo 2**32). | |
| 274 | + * @buf_write_ptr: Buffer position for writer. | |
| 275 | + * @buf_read_ptr: Buffer position for reader. | |
| 276 | + * @cur_chan: Current position in chanlist for scan (for those drivers that | |
| 277 | + * use it). | |
| 278 | + * @scans_done: The number of scans completed. | |
| 279 | + * @scan_progress: Amount received or sent for current scan (in bytes). | |
| 280 | + * @munge_chan: Current position in chanlist for "munging". | |
| 281 | + * @munge_count: "Munge" count (in bytes, modulo 2**32). | |
| 282 | + * @munge_ptr: Buffer position for "munging". | |
| 283 | + * @events: Bit-vector of events that have occurred. | |
| 284 | + * @cmd: Details of comedi command in progress. | |
| 285 | + * @wait_head: Task wait queue for file reader or writer. | |
| 286 | + * @cb_mask: Bit-vector of events that should wake waiting tasks. | |
| 287 | + * @inttrig: Software trigger function for command, or NULL. | |
| 134 | 288 | * |
| 135 | 289 | * Note about the ..._count and ..._ptr members: |
| 136 | 290 | * |
| 137 | 291 | * Think of the _Count values being integers of unlimited size, indexing |
| 138 | 292 | * into a buffer of infinite length (though only an advancing portion |
| 139 | − * of the buffer of fixed length prealloc_bufsz is accessible at any time). | |
| 140 | − * Then: | |
| 293 | + * of the buffer of fixed length prealloc_bufsz is accessible at any | |
| 294 | + * time). Then: | |
| 141 | 295 | * |
| 142 | 296 | * Buf_Read_Count <= Buf_Read_Alloc_Count <= Munge_Count <= |
| 143 | 297 | * Buf_Write_Count <= Buf_Write_Alloc_Count <= |
| 144 | 298 | * (Buf_Read_Count + prealloc_bufsz) |
| 145 | 299 | * |
| 146 | − * (Those aren't the actual members, apart from prealloc_bufsz.) When | |
| 147 | − * the buffer is reset, those _Count values start at 0 and only increase | |
| 148 | − * in value, maintaining the above inequalities until the next time the | |
| 149 | − * buffer is reset. The buffer is divided into the following regions by | |
| 150 | − * the inequalities: | |
| 300 | + * (Those aren't the actual members, apart from prealloc_bufsz.) When the | |
| 301 | + * buffer is reset, those _Count values start at 0 and only increase in value, | |
| 302 | + * maintaining the above inequalities until the next time the buffer is | |
| 303 | + * reset. The buffer is divided into the following regions by the inequalities: | |
| 151 | 304 | * |
| 152 | 305 | * [0, Buf_Read_Count): |
| 153 | 306 | * old region no longer accessible |
| 307 | + * | |
| 154 | 308 | * [Buf_Read_Count, Buf_Read_Alloc_Count): |
| 155 | 309 | * filled and munged region allocated for reading but not yet read |
| 310 | + * | |
| 156 | 311 | * [Buf_Read_Alloc_Count, Munge_Count): |
| 157 | 312 | * filled and munged region not yet allocated for reading |
| 313 | + * | |
| 158 | 314 | * [Munge_Count, Buf_Write_Count): |
| 159 | 315 | * filled region not yet munged |
| 316 | + * | |
| 160 | 317 | * [Buf_Write_Count, Buf_Write_Alloc_Count): |
| 161 | 318 | * unfilled region allocated for writing but not yet written |
| 319 | + * | |
| 162 | 320 | * [Buf_Write_Alloc_Count, Buf_Read_Count + prealloc_bufsz): |
| 163 | 321 | * unfilled region not yet allocated for writing |
| 322 | + * | |
| 164 | 323 | * [Buf_Read_Count + prealloc_bufsz, infinity): |
| 165 | 324 | * unfilled region not yet accessible |
| 166 | 325 | * |
| @@ -216,43 +375,153 @@ struct comedi_async { · 49 unmodified lines | ||
| 216 | 375 | }; |
| 217 | 376 | |
| 218 | 377 | /** |
| 219 | − * comedi_async callback "events" | |
| 378 | + * enum comedi_cb - &struct comedi_async callback "events" | |
| 220 | 379 | * @COMEDI_CB_EOS: end-of-scan |
| 221 | 380 | * @COMEDI_CB_EOA: end-of-acquisition/output |
| 222 | 381 | * @COMEDI_CB_BLOCK: data has arrived, wakes up read() / write() |
| 223 | 382 | * @COMEDI_CB_EOBUF: DEPRECATED: end of buffer |
| 224 | 383 | * @COMEDI_CB_ERROR: card error during acquisition |
| 225 | 384 | * @COMEDI_CB_OVERFLOW: buffer overflow/underflow |
| 226 | − * | |
| 227 | 385 | * @COMEDI_CB_ERROR_MASK: events that indicate an error has occurred |
| 228 | 386 | * @COMEDI_CB_CANCEL_MASK: events that will cancel an async command |
| 229 | 387 | */ |
| 230 | −#define COMEDI_CB_EOS BIT(0) | |
| 231 | −#define COMEDI_CB_EOA BIT(1) | |
| 232 | −#define COMEDI_CB_BLOCK BIT(2) | |
| 233 | −#define COMEDI_CB_EOBUF BIT(3) | |
| 234 | −#define COMEDI_CB_ERROR BIT(4) | |
| 235 | −#define COMEDI_CB_OVERFLOW BIT(5) | |
| 236 | − | |
| 237 | −#define COMEDI_CB_ERROR_MASK (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW) | |
| 238 | −#define COMEDI_CB_CANCEL_MASK (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK) | |
| 388 | +enum comedi_cb { | |
| 389 | + COMEDI_CB_EOS = BIT(0), | |
| 390 | + COMEDI_CB_EOA = BIT(1), | |
| 391 | + COMEDI_CB_BLOCK = BIT(2), | |
| 392 | + COMEDI_CB_EOBUF = BIT(3), | |
| 393 | + COMEDI_CB_ERROR = BIT(4), | |
| 394 | + COMEDI_CB_OVERFLOW = BIT(5), | |
| 395 | + /* masks */ | |
| 396 | + COMEDI_CB_ERROR_MASK = (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW), | |
| 397 | + COMEDI_CB_CANCEL_MASK = (COMEDI_CB_EOA | COMEDI_CB_ERROR_MASK) | |
| 398 | +}; | |
| 239 | 399 | |
| 400 | +/** | |
| 401 | + * struct comedi_driver - COMEDI driver registration | |
| 402 | + * @driver_name: Name of driver. | |
| 403 | + * @module: Owning module. | |
| 404 | + * @attach: The optional "attach" handler for manually configured COMEDI | |
| 405 | + * devices. | |
| 406 | + * @detach: The "detach" handler for deconfiguring COMEDI devices. | |
| 407 | + * @auto_attach: The optional "auto_attach" handler for automatically | |
| 408 | + * configured COMEDI devices. | |
| 409 | + * @num_names: Optional number of "board names" supported. | |
| 410 | + * @board_name: Optional pointer to a pointer to a board name. The pointer | |
| 411 | + * to a board name is embedded in an element of a driver-defined array | |
| 412 | + * of static, read-only board type information. | |
| 413 | + * @offset: Optional size of each element of the driver-defined array of | |
| 414 | + * static, read-only board type information, i.e. the offset between each | |
| 415 | + * pointer to a board name. | |
| 416 | + * | |
| 417 | + * This is used with comedi_driver_register() and comedi_driver_unregister() to | |
| 418 | + * register and unregister a low-level COMEDI driver with the COMEDI core. | |
| 419 | + * | |
| 420 | + * If @num_names is non-zero, @board_name should be non-NULL, and @offset | |
| 421 | + * should be at least sizeof(*board_name). These are used by the handler for | |
| 422 | + * the %COMEDI_DEVCONFIG ioctl to match a hardware device and its driver by | |
| 423 | + * board name. If @num_names is zero, the %COMEDI_DEVCONFIG ioctl matches a | |
| 424 | + * hardware device and its driver by driver name. This is only useful if the | |
| 425 | + * @attach handler is set. If @num_names is non-zero, the driver's @attach | |
| 426 | + * handler will be called with the COMEDI device structure's board_ptr member | |
| 427 | + * pointing to the matched pointer to a board name within the driver's private | |
| 428 | + * array of static, read-only board type information. | |
| 429 | + */ | |
| 240 | 430 | struct comedi_driver { |
| 241 | − struct comedi_driver *next; | |
| 242 | − | |
| 431 | + /* private: */ | |
| 432 | + struct comedi_driver *next; /* Next in list of COMEDI drivers. */ | |
| 433 | + /* public: */ | |
| 243 | 434 | const char *driver_name; |
| 244 | 435 | struct module *module; |
| 245 | 436 | int (*attach)(struct comedi_device *, struct comedi_devconfig *); |
| 246 | 437 | void (*detach)(struct comedi_device *); |
| 247 | 438 | int (*auto_attach)(struct comedi_device *, unsigned long); |
| 248 | − | |
| 249 | − /* number of elements in board_name and board_id arrays */ | |
| 250 | 439 | unsigned int num_names; |
| 251 | 440 | const char *const *board_name; |
| 252 | − /* offset in bytes from one board name pointer to the next */ | |
| 253 | 441 | int offset; |
| 254 | 442 | }; |
| 255 | 443 | |
| 444 | +/** | |
| 445 | + * struct comedi_device - Working data for a COMEDI device | |
| 446 | + * @use_count: Number of open file objects. | |
| 447 | + * @driver: Low-level COMEDI driver attached to this COMEDI device. | |
| 448 | + * @pacer: Optional pointer to a dynamically allocated acquisition pacer | |
| 449 | + * control. It is freed automatically after the COMEDI device is | |
| 450 | + * detached from the low-level driver. | |
| 451 | + * @private: Optional pointer to private data allocated by the low-level | |
| 452 | + * driver. It is freed automatically after the COMEDI device is | |
| 453 | + * detached from the low-level driver. | |
| 454 | + * @class_dev: Sysfs comediX device. | |
| 455 | + * @minor: Minor device number of COMEDI char device (0-47). | |
| 456 | + * @detach_count: Counter incremented every time the COMEDI device is detached. | |
| 457 | + * Used for checking a previous attachment is still valid. | |
| 458 | + * @hw_dev: Optional pointer to the low-level hardware &struct device. It is | |
| 459 | + * required for automatically configured COMEDI devices and optional for | |
| 460 | + * COMEDI devices configured by the %COMEDI_DEVCONFIG ioctl, although | |
| 461 | + * the bus-specific COMEDI functions only work if it is set correctly. | |
| 462 | + * It is also passed to dma_alloc_coherent() for COMEDI subdevices that | |
| 463 | + * have their 'async_dma_dir' member set to something other than | |
| 464 | + * %DMA_NONE. | |
| 465 | + * @board_name: Pointer to a COMEDI board name or a COMEDI driver name. When | |
| 466 | + * the low-level driver's "attach" handler is called by the handler for | |
| 467 | + * the %COMEDI_DEVCONFIG ioctl, it either points to a matched board name | |
| 468 | + * string if the 'num_names' member of the &struct comedi_driver is | |
| 469 | + * non-zero, otherwise it points to the low-level driver name string. | |
| 470 | + * When the low-lever driver's "auto_attach" handler is called for an | |
| 471 | + * automatically configured COMEDI device, it points to the low-level | |
| 472 | + * driver name string. The low-level driver is free to change it in its | |
| 473 | + * "attach" or "auto_attach" handler if it wishes. | |
| 474 | + * @board_ptr: Optional pointer to private, read-only board type information in | |
| 475 | + * the low-level driver. If the 'num_names' member of the &struct | |
| 476 | + * comedi_driver is non-zero, the handler for the %COMEDI_DEVCONFIG ioctl | |
| 477 | + * will point it to a pointer to a matched board name string within the | |
| 478 | + * driver's private array of static, read-only board type information when | |
| 479 | + * calling the driver's "attach" handler. The low-level driver is free to | |
| 480 | + * change it. | |
| 481 | + * @attached: Flag indicating that the COMEDI device is attached to a low-level | |
| 482 | + * driver. | |
| 483 | + * @ioenabled: Flag used to indicate that a PCI device has been enabled and | |
| 484 | + * its regions requested. | |
| 485 | + * @spinlock: Generic spin-lock for use by the low-level driver. | |
| 486 | + * @mutex: Generic mutex for use by the COMEDI core module. | |
| 487 | + * @attach_lock: &struct rw_semaphore used to guard against the COMEDI device | |
| 488 | + * being detached while an operation is in progress. The down_write() | |
| 489 | + * operation is only allowed while @mutex is held and is used when | |
| 490 | + * changing @attached and @detach_count and calling the low-level driver's | |
| 491 | + * "detach" handler. The down_read() operation is generally used without | |
| 492 | + * holding @mutex. | |
| 493 | + * @refcount: &struct kref reference counter for freeing COMEDI device. | |
| 494 | + * @n_subdevices: Number of COMEDI subdevices allocated by the low-level | |
| 495 | + * driver for this device. | |
| 496 | + * @subdevices: Dynamically allocated array of COMEDI subdevices. | |
| 497 | + * @mmio: Optional pointer to a remapped MMIO region set by the low-level | |
| 498 | + * driver. | |
| 499 | + * @iobase: Optional base of an I/O port region requested by the low-level | |
| 500 | + * driver. | |
| 501 | + * @iolen: Length of I/O port region requested at @iobase. | |
| 502 | + * @irq: Optional IRQ number requested by the low-level driver. | |
| 503 | + * @read_subdev: Optional pointer to a default COMEDI subdevice operated on by | |
| 504 | + * the read() file operation. Set by the low-level driver. | |
| 505 | + * @write_subdev: Optional pointer to a default COMEDI subdevice operated on by | |
| 506 | + * the write() file operation. Set by the low-level driver. | |
| 507 | + * @async_queue: Storage for fasync_helper(). | |
| 508 | + * @open: Optional pointer to a function set by the low-level driver to be | |
| 509 | + * called when @use_count changes from 0 to 1. | |
| 510 | + * @close: Optional pointer to a function set by the low-level driver to be | |
| 511 | + * called when @use_count changed from 1 to 0. | |
| 512 | + * | |
| 513 | + * This is the main control data structure for a COMEDI device (as far as the | |
| 514 | + * COMEDI core is concerned). There are two groups of COMEDI devices - | |
| 515 | + * "legacy" devices that are configured by the handler for the | |
| 516 | + * %COMEDI_DEVCONFIG ioctl, and automatically configured devices resulting | |
| 517 | + * from a call to comedi_auto_config() as a result of a bus driver probe in | |
| 518 | + * a low-level COMEDI driver. The "legacy" COMEDI devices are allocated | |
| 519 | + * during module initialization if the "comedi_num_legacy_minors" module | |
| 520 | + * parameter is non-zero and use minor device numbers from 0 to | |
| 521 | + * comedi_num_legacy_minors minus one. The automatically configured COMEDI | |
| 522 | + * devices are allocated on demand and use minor device numbers from | |
| 523 | + * comedi_num_legacy_minors to 47. | |
| 524 | + */ | |
| 256 | 525 | struct comedi_device { |
| 257 | 526 | int use_count; |
| 258 | 527 | struct comedi_driver *driver; |
| @@ -262,17 +531,14 @@ struct comedi_device { · 3 unmodified lines | ||
| 262 | 531 | struct device *class_dev; |
| 263 | 532 | int minor; |
| 264 | 533 | unsigned int detach_count; |
| 265 | − /* hw_dev is passed to dma_alloc_coherent when allocating async buffers | |
| 266 | − * for subdevices that have async_dma_dir set to something other than | |
| 267 | − * DMA_NONE */ | |
| 268 | 534 | struct device *hw_dev; |
| 269 | 535 | |
| 270 | 536 | const char *board_name; |
| 271 | 537 | const void *board_ptr; |
| 272 | 538 | bool attached:1; |
| 273 | 539 | bool ioenabled:1; |
| 274 | − spinlock_t spinlock; | |
| 275 | − struct mutex mutex; | |
| 540 | + spinlock_t spinlock; /* generic spin-lock for low-level driver */ | |
| 541 | + struct mutex mutex; /* generic mutex for COMEDI core */ | |
| 276 | 542 | struct rw_semaphore attach_lock; |
| 277 | 543 | struct kref refcount; |
| 278 | 544 | |
| @@ -314,12 +580,12 @@ int comedi_check_chanlist(struct comedi_subdevice *s, · 35 unmodified lines | ||
| 314 | 580 | |
| 315 | 581 | /* range stuff */ |
| 316 | 582 | |
| 317 | −#define RANGE(a, b) {(a)*1e6, (b)*1e6, 0} | |
| 318 | −#define RANGE_ext(a, b) {(a)*1e6, (b)*1e6, RF_EXTERNAL} | |
| 319 | −#define RANGE_mA(a, b) {(a)*1e6, (b)*1e6, UNIT_mA} | |
| 320 | −#define RANGE_unitless(a, b) {(a)*1e6, (b)*1e6, 0} | |
| 321 | −#define BIP_RANGE(a) {-(a)*1e6, (a)*1e6, 0} | |
| 322 | −#define UNI_RANGE(a) {0, (a)*1e6, 0} | |
| 583 | +#define RANGE(a, b) {(a) * 1e6, (b) * 1e6, 0} | |
| 584 | +#define RANGE_ext(a, b) {(a) * 1e6, (b) * 1e6, RF_EXTERNAL} | |
| 585 | +#define RANGE_mA(a, b) {(a) * 1e6, (b) * 1e6, UNIT_mA} | |
| 586 | +#define RANGE_unitless(a, b) {(a) * 1e6, (b) * 1e6, 0} | |
| 587 | +#define BIP_RANGE(a) {-(a) * 1e6, (a) * 1e6, 0} | |
| 588 | +#define UNI_RANGE(a) {0, (a) * 1e6, 0} | |
| 323 | 589 | |
| 324 | 590 | extern const struct comedi_lrange range_bipolar10; |
| 325 | 591 | extern const struct comedi_lrange range_bipolar5; |
| @@ -340,29 +606,101 @@ extern const struct comedi_lrange range_unknown; · 14 unmodified lines | ||
| 340 | 606 | #define GCC_ZERO_LENGTH_ARRAY 0 |
| 341 | 607 | #endif |
| 342 | 608 | |
| 609 | +/** | |
| 610 | + * struct comedi_lrange - Describes a COMEDI range table | |
| 611 | + * @length: Number of entries in the range table. | |
| 612 | + * @range: Array of &struct comedi_krange, one for each range. | |
| 613 | + * | |
| 614 | + * Each element of @range[] describes the minimum and maximum physical range | |
| 615 | + * range and the type of units. Typically, the type of unit is %UNIT_volt | |
| 616 | + * (i.e. volts) and the minimum and maximum are in millionths of a volt. | |
| 617 | + * There may also be a flag that indicates the minimum and maximum are merely | |
| 618 | + * scale factors for an unknown, external reference. | |
| 619 | + */ | |
| 343 | 620 | struct comedi_lrange { |
| 344 | 621 | int length; |
| 345 | 622 | struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY]; |
| 346 | 623 | }; |
| 347 | 624 | |
| 625 | +/** | |
| 626 | + * comedi_range_is_bipolar() - Test if subdevice range is bipolar | |
| 627 | + * @s: COMEDI subdevice. | |
| 628 | + * @range: Index of range within a range table. | |
| 629 | + * | |
| 630 | + * Tests whether a range is bipolar by checking whether its minimum value | |
| 631 | + * is negative. | |
| 632 | + * | |
| 633 | + * Assumes @range is valid. Does not work for subdevices using a | |
| 634 | + * channel-specific range table list. | |
| 635 | + * | |
| 636 | + * Return: | |
| 637 | + * %true if the range is bipolar. | |
| 638 | + * %false if the range is unipolar. | |
| 639 | + */ | |
| 348 | 640 | static inline bool comedi_range_is_bipolar(struct comedi_subdevice *s, |
| 349 | 641 | unsigned int range) |
| 350 | 642 | { |
| 351 | 643 | return s->range_table->range[range].min < 0; |
| 352 | 644 | } |
| 353 | 645 | |
| 646 | +/** | |
| 647 | + * comedi_range_is_unipolar() - Test if subdevice range is unipolar | |
| 648 | + * @s: COMEDI subdevice. | |
| 649 | + * @range: Index of range within a range table. | |
| 650 | + * | |
| 651 | + * Tests whether a range is unipolar by checking whether its minimum value | |
| 652 | + * is at least 0. | |
| 653 | + * | |
| 654 | + * Assumes @range is valid. Does not work for subdevices using a | |
| 655 | + * channel-specific range table list. | |
| 656 | + * | |
| 657 | + * Return: | |
| 658 | + * %true if the range is unipolar. | |
| 659 | + * %false if the range is bipolar. | |
| 660 | + */ | |
| 354 | 661 | static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, |
| 355 | 662 | unsigned int range) |
| 356 | 663 | { |
| 357 | 664 | return s->range_table->range[range].min >= 0; |
| 358 | 665 | } |
| 359 | 666 | |
| 667 | +/** | |
| 668 | + * comedi_range_is_external() - Test if subdevice range is external | |
| 669 | + * @s: COMEDI subdevice. | |
| 670 | + * @range: Index of range within a range table. | |
| 671 | + * | |
| 672 | + * Tests whether a range is externally reference by checking whether its | |
| 673 | + * %RF_EXTERNAL flag is set. | |
| 674 | + * | |
| 675 | + * Assumes @range is valid. Does not work for subdevices using a | |
| 676 | + * channel-specific range table list. | |
| 677 | + * | |
| 678 | + * Return: | |
| 679 | + * %true if the range is external. | |
| 680 | + * %false if the range is internal. | |
| 681 | + */ | |
| 360 | 682 | static inline bool comedi_range_is_external(struct comedi_subdevice *s, |
| 361 | 683 | unsigned int range) |
| 362 | 684 | { |
| 363 | 685 | return !!(s->range_table->range[range].flags & RF_EXTERNAL); |
| 364 | 686 | } |
| 365 | 687 | |
| 688 | +/** | |
| 689 | + * comedi_chan_range_is_bipolar() - Test if channel-specific range is bipolar | |
| 690 | + * @s: COMEDI subdevice. | |
| 691 | + * @chan: The channel number. | |
| 692 | + * @range: Index of range within a range table. | |
| 693 | + * | |
| 694 | + * Tests whether a range is bipolar by checking whether its minimum value | |
| 695 | + * is negative. | |
| 696 | + * | |
| 697 | + * Assumes @chan and @range are valid. Only works for subdevices with a | |
| 698 | + * channel-specific range table list. | |
| 699 | + * | |
| 700 | + * Return: | |
| 701 | + * %true if the range is bipolar. | |
| 702 | + * %false if the range is unipolar. | |
| 703 | + */ | |
| 366 | 704 | static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, |
| 367 | 705 | unsigned int chan, |
| 368 | 706 | unsigned int range) |
| @@ -370,6 +708,22 @@ static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, · 1 unmodified line | ||
| 370 | 708 | return s->range_table_list[chan]->range[range].min < 0; |
| 371 | 709 | } |
| 372 | 710 | |
| 711 | +/** | |
| 712 | + * comedi_chan_range_is_unipolar() - Test if channel-specific range is unipolar | |
| 713 | + * @s: COMEDI subdevice. | |
| 714 | + * @chan: The channel number. | |
| 715 | + * @range: Index of range within a range table. | |
| 716 | + * | |
| 717 | + * Tests whether a range is unipolar by checking whether its minimum value | |
| 718 | + * is at least 0. | |
| 719 | + * | |
| 720 | + * Assumes @chan and @range are valid. Only works for subdevices with a | |
| 721 | + * channel-specific range table list. | |
| 722 | + * | |
| 723 | + * Return: | |
| 724 | + * %true if the range is unipolar. | |
| 725 | + * %false if the range is bipolar. | |
| 726 | + */ | |
| 373 | 727 | static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, |
| 374 | 728 | unsigned int chan, |
| 375 | 729 | unsigned int range) |
| @@ -377,6 +731,22 @@ static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, · 1 unmodified line | ||
| 377 | 731 | return s->range_table_list[chan]->range[range].min >= 0; |
| 378 | 732 | } |
| 379 | 733 | |
| 734 | +/** | |
| 735 | + * comedi_chan_range_is_external() - Test if channel-specific range is external | |
| 736 | + * @s: COMEDI subdevice. | |
| 737 | + * @chan: The channel number. | |
| 738 | + * @range: Index of range within a range table. | |
| 739 | + * | |
| 740 | + * Tests whether a range is externally reference by checking whether its | |
| 741 | + * %RF_EXTERNAL flag is set. | |
| 742 | + * | |
| 743 | + * Assumes @chan and @range are valid. Only works for subdevices with a | |
| 744 | + * channel-specific range table list. | |
| 745 | + * | |
| 746 | + * Return: | |
| 747 | + * %true if the range is bipolar. | |
| 748 | + * %false if the range is unipolar. | |
| 749 | + */ | |
| 380 | 750 | static inline bool comedi_chan_range_is_external(struct comedi_subdevice *s, |
| 381 | 751 | unsigned int chan, |
| 382 | 752 | unsigned int range) |
| @@ -384,7 +754,16 @@ static inline bool comedi_chan_range_is_external(struct comedi_subdevice *s, · 1 unmodified line | ||
| 384 | 754 | return !!(s->range_table_list[chan]->range[range].flags & RF_EXTERNAL); |
| 385 | 755 | } |
| 386 | 756 | |
| 387 | −/* munge between offset binary and two's complement values */ | |
| 757 | +/** | |
| 758 | + * comedi_offset_munge() - Convert between offset binary and 2's complement | |
| 759 | + * @s: COMEDI subdevice. | |
| 760 | + * @val: Value to be converted. | |
| 761 | + * | |
| 762 | + * Toggles the highest bit of a sample value to toggle between offset binary | |
| 763 | + * and 2's complement. Assumes that @s->maxdata is a power of 2 minus 1. | |
| 764 | + * | |
| 765 | + * Return: The converted value. | |
| 766 | + */ | |
| 388 | 767 | static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, |
| 389 | 768 | unsigned int val) |
| 390 | 769 | { |
| @@ -392,13 +771,13 @@ static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, · 1 unmodified line | ||
| 392 | 771 | } |
| 393 | 772 | |
| 394 | 773 | /** |
| 395 | − * comedi_bytes_per_sample - determine subdevice sample size | |
| 396 | − * @s: comedi_subdevice struct | |
| 774 | + * comedi_bytes_per_sample() - Determine subdevice sample size | |
| 775 | + * @s: COMEDI subdevice. | |
| 397 | 776 | * |
| 398 | 777 | * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on |
| 399 | − * whether the SDF_LSAMPL subdevice flag is set or not. | |
| 778 | + * whether the %SDF_LSAMPL subdevice flag is set or not. | |
| 400 | 779 | * |
| 401 | − * Returns the subdevice sample size. | |
| 780 | + * Return: The subdevice sample size. | |
| 402 | 781 | */ |
| 403 | 782 | static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s) |
| 404 | 783 | { |
| @@ -406,15 +785,15 @@ static inline unsigned int comedi_bytes_per_sample(struct comedi_subdevice *s) · 1 unmodified line | ||
| 406 | 785 | } |
| 407 | 786 | |
| 408 | 787 | /** |
| 409 | − * comedi_sample_shift - determine log2 of subdevice sample size | |
| 410 | − * @s: comedi_subdevice struct | |
| 788 | + * comedi_sample_shift() - Determine log2 of subdevice sample size | |
| 789 | + * @s: COMEDI subdevice. | |
| 411 | 790 | * |
| 412 | 791 | * The sample size will be 4 (sizeof int) or 2 (sizeof short) depending on |
| 413 | − * whether the SDF_LSAMPL subdevice flag is set or not. The log2 of the | |
| 792 | + * whether the %SDF_LSAMPL subdevice flag is set or not. The log2 of the | |
| 414 | 793 | * sample size will be 2 or 1 and can be used as the right operand of a |
| 415 | 794 | * bit-shift operator to multiply or divide something by the sample size. |
| 416 | 795 | * |
| 417 | − * Returns log2 of the subdevice sample size. | |
| 796 | + * Return: log2 of the subdevice sample size. | |
| 418 | 797 | */ |
| 419 | 798 | static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s) |
| 420 | 799 | { |
| @@ -422,11 +801,11 @@ static inline unsigned int comedi_sample_shift(struct comedi_subdevice *s) · 1 unmodified line | ||
| 422 | 801 | } |
| 423 | 802 | |
| 424 | 803 | /** |
| 425 | − * comedi_bytes_to_samples - converts a number of bytes to a number of samples | |
| 426 | − * @s: comedi_subdevice struct | |
| 427 | − * @nbytes: number of bytes | |
| 804 | + * comedi_bytes_to_samples() - Convert a number of bytes to a number of samples | |
| 805 | + * @s: COMEDI subdevice. | |
| 806 | + * @nbytes: Number of bytes | |
| 428 | 807 | * |
| 429 | − * Returns the number of bytes divided by the subdevice sample size. | |
| 808 | + * Return: The number of bytes divided by the subdevice sample size. | |
| 430 | 809 | */ |
| 431 | 810 | static inline unsigned int comedi_bytes_to_samples(struct comedi_subdevice *s, |
| 432 | 811 | unsigned int nbytes) |
| @@ -435,12 +814,12 @@ static inline unsigned int comedi_bytes_to_samples(struct comedi_subdevice *s, · 2 unmodified lines | ||
| 435 | 814 | } |
| 436 | 815 | |
| 437 | 816 | /** |
| 438 | − * comedi_samples_to_bytes - converts a number of samples to a number of bytes | |
| 439 | − * @s: comedi_subdevice struct | |
| 440 | − * @nsamples: number of samples | |
| 817 | + * comedi_samples_to_bytes() - Convert a number of samples to a number of bytes | |
| 818 | + * @s: COMEDI subdevice. | |
| 819 | + * @nsamples: Number of samples. | |
| 441 | 820 | * |
| 442 | − * Returns the number of samples multiplied by the subdevice sample size. | |
| 443 | − * Does not check for arithmetic overflow. | |
| 821 | + * Return: The number of samples multiplied by the subdevice sample size. | |
| 822 | + * (Does not check for arithmetic overflow.) | |
| 444 | 823 | */ |
| 445 | 824 | static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s, |
| 446 | 825 | unsigned int nsamples) |
| @@ -449,14 +828,18 @@ static inline unsigned int comedi_samples_to_bytes(struct comedi_subdevice *s, · 2 unmodified lines | ||
| 449 | 828 | } |
| 450 | 829 | |
| 451 | 830 | /** |
| 452 | − * comedi_check_trigger_src() - trivially validate a comedi_cmd trigger source | |
| 453 | − * @src: pointer to the trigger source to validate | |
| 454 | − * @flags: bitmask of valid TRIG_* for the trigger | |
| 831 | + * comedi_check_trigger_src() - Trivially validate a comedi_cmd trigger source | |
| 832 | + * @src: Pointer to the trigger source to validate. | |
| 833 | + * @flags: Bitmask of valid %TRIG_* for the trigger. | |
| 455 | 834 | * |
| 456 | 835 | * This is used in "step 1" of the do_cmdtest functions of comedi drivers |
| 457 | − * to vaildate the comedi_cmd triggers. The mask of the @src against the | |
| 836 | + * to validate the comedi_cmd triggers. The mask of the @src against the | |
| 458 | 837 | * @flags allows the userspace comedilib to pass all the comedi_cmd |
| 459 | − * triggers as TRIG_ANY and get back a bitmask of the valid trigger sources. | |
| 838 | + * triggers as %TRIG_ANY and get back a bitmask of the valid trigger sources. | |
| 839 | + * | |
| 840 | + * Return: | |
| 841 | + * 0 if trigger sources in *@src are all supported. | |
| 842 | + * -EINVAL if any trigger source in *@src is unsupported. | |
| 460 | 843 | */ |
| 461 | 844 | static inline int comedi_check_trigger_src(unsigned int *src, |
| 462 | 845 | unsigned int flags) |
| @@ -470,8 +853,12 @@ static inline int comedi_check_trigger_src(unsigned int *src, · 7 unmodified lines | ||
| 470 | 853 | } |
| 471 | 854 | |
| 472 | 855 | /** |
| 473 | − * comedi_check_trigger_is_unique() - make sure a trigger source is unique | |
| 474 | − * @src: the trigger source to check | |
| 856 | + * comedi_check_trigger_is_unique() - Make sure a trigger source is unique | |
| 857 | + * @src: The trigger source to check. | |
| 858 | + * | |
| 859 | + * Return: | |
| 860 | + * 0 if no more than one trigger source is set. | |
| 861 | + * -EINVAL if more than one trigger source is set. | |
| 475 | 862 | */ |
| 476 | 863 | static inline int comedi_check_trigger_is_unique(unsigned int src) |
| 477 | 864 | { |
| @@ -482,9 +869,15 @@ static inline int comedi_check_trigger_is_unique(unsigned int src) · 4 unmodified lines | ||
| 482 | 869 | } |
| 483 | 870 | |
| 484 | 871 | /** |
| 485 | − * comedi_check_trigger_arg_is() - trivially validate a trigger argument | |
| 486 | − * @arg: pointer to the trigger arg to validate | |
| 487 | − * @val: the value the argument should be | |
| 872 | + * comedi_check_trigger_arg_is() - Trivially validate a trigger argument | |
| 873 | + * @arg: Pointer to the trigger arg to validate. | |
| 874 | + * @val: The value the argument should be. | |
| 875 | + * | |
| 876 | + * Forces *@arg to be @val. | |
| 877 | + * | |
| 878 | + * Return: | |
| 879 | + * 0 if *@arg was already @val. | |
| 880 | + * -EINVAL if *@arg differed from @val. | |
| 488 | 881 | */ |
| 489 | 882 | static inline int comedi_check_trigger_arg_is(unsigned int *arg, |
| 490 | 883 | unsigned int val) |
| @@ -497,9 +890,15 @@ static inline int comedi_check_trigger_arg_is(unsigned int *arg, · 6 unmodified lines | ||
| 497 | 890 | } |
| 498 | 891 | |
| 499 | 892 | /** |
| 500 | − * comedi_check_trigger_arg_min() - trivially validate a trigger argument | |
| 501 | − * @arg: pointer to the trigger arg to validate | |
| 502 | − * @val: the minimum value the argument should be | |
| 893 | + * comedi_check_trigger_arg_min() - Trivially validate a trigger argument min | |
| 894 | + * @arg: Pointer to the trigger arg to validate. | |
| 895 | + * @val: The minimum value the argument should be. | |
| 896 | + * | |
| 897 | + * Forces *@arg to be at least @val, setting it to @val if necessary. | |
| 898 | + * | |
| 899 | + * Return: | |
| 900 | + * 0 if *@arg was already at least @val. | |
| 901 | + * -EINVAL if *@arg was less than @val. | |
| 503 | 902 | */ |
| 504 | 903 | static inline int comedi_check_trigger_arg_min(unsigned int *arg, |
| 505 | 904 | unsigned int val) |
| @@ -512,9 +911,15 @@ static inline int comedi_check_trigger_arg_min(unsigned int *arg, · 6 unmodified lines | ||
| 512 | 911 | } |
| 513 | 912 | |
| 514 | 913 | /** |
| 515 | − * comedi_check_trigger_arg_max() - trivially validate a trigger argument | |
| 516 | − * @arg: pointer to the trigger arg to validate | |
| 517 | − * @val: the maximum value the argument should be | |
| 914 | + * comedi_check_trigger_arg_max() - Trivially validate a trigger argument max | |
| 915 | + * @arg: Pointer to the trigger arg to validate. | |
| 916 | + * @val: The maximum value the argument should be. | |
| 917 | + * | |
| 918 | + * Forces *@arg to be no more than @val, setting it to @val if necessary. | |
| 919 | + * | |
| 920 | + * Return: | |
| 921 | + * 0 if*@arg was already no more than @val. | |
| 922 | + * -EINVAL if *@arg was greater than @val. | |
| 518 | 923 | */ |
| 519 | 924 | static inline int comedi_check_trigger_arg_max(unsigned int *arg, |
| 520 | 925 | unsigned int val) |
| @@ -534,6 +939,16 @@ static inline int comedi_check_trigger_arg_max(unsigned int *arg, · 13 unmodified lines | ||
| 534 | 939 | */ |
| 535 | 940 | int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev); |
| 536 | 941 | |
| 942 | +/** | |
| 943 | + * comedi_buf_n_bytes_ready - Determine amount of unread data in buffer | |
| 944 | + * @s: COMEDI subdevice. | |
| 945 | + * | |
| 946 | + * Determines the number of bytes of unread data in the asynchronous | |
| 947 | + * acquisition data buffer for a subdevice. The data in question might not | |
| 948 | + * have been fully "munged" yet. | |
| 949 | + * | |
| 950 | + * Returns: The amount of unread data in bytes. | |
| 951 | + */ | |
| 537 | 952 | static inline unsigned int comedi_buf_n_bytes_ready(struct comedi_subdevice *s) |
| 538 | 953 | { |
| 539 | 954 | return s->async->buf_write_count - s->async->buf_read_count; |
| @@ -1,37 +1,29 @@ | ||
| 1 | 1 | /* |
| 2 | − module/drivers.c | |
| 3 | − functions for manipulating drivers | |
| 4 | − | |
| 5 | − COMEDI - Linux Control and Measurement Device Interface | |
| 6 | − Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> | |
| 7 | − Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 8 | − | |
| 9 | − This program is free software; you can redistribute it and/or modify | |
| 10 | − it under the terms of the GNU General Public License as published by | |
| 11 | − the Free Software Foundation; either version 2 of the License, or | |
| 12 | − (at your option) any later version. | |
| 13 | − | |
| 14 | − This program is distributed in the hope that it will be useful, | |
| 15 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | − GNU General Public License for more details. | |
| 2 | + * module/drivers.c | |
| 3 | + * functions for manipulating drivers | |
| 4 | + * | |
| 5 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 6 | + * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org> | |
| 7 | + * Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 8 | + * | |
| 9 | + * This program is free software; you can redistribute it and/or modify | |
| 10 | + * it under the terms of the GNU General Public License as published by | |
| 11 | + * the Free Software Foundation; either version 2 of the License, or | |
| 12 | + * (at your option) any later version. | |
| 13 | + * | |
| 14 | + * This program is distributed in the hope that it will be useful, | |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | + * GNU General Public License for more details. | |
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | 20 | #include <linux/device.h> |
| 21 | 21 | #include <linux/module.h> |
| 22 | 22 | #include <linux/errno.h> |
| 23 | −#include <linux/kconfig.h> | |
| 24 | 23 | #include <linux/kernel.h> |
| 25 | −#include <linux/sched.h> | |
| 26 | −#include <linux/fcntl.h> | |
| 27 | 24 | #include <linux/ioport.h> |
| 28 | −#include <linux/mm.h> | |
| 29 | 25 | #include <linux/slab.h> |
| 30 | −#include <linux/highmem.h> /* for SuSE brokenness */ | |
| 31 | −#include <linux/vmalloc.h> | |
| 32 | −#include <linux/cdev.h> | |
| 33 | −#include <linux/dma-mapping.h> | |
| 34 | −#include <linux/io.h> | |
| 26 | +#include <linux/dma-direction.h> | |
| 35 | 27 | #include <linux/interrupt.h> |
| 36 | 28 | #include <linux/firmware.h> |
| 37 | 29 | |
| @@ -42,6 +34,28 @@ struct comedi_driver *comedi_drivers; · 4 unmodified lines | ||
| 42 | 34 | /* protects access to comedi_drivers */ |
| 43 | 35 | DEFINE_MUTEX(comedi_drivers_list_lock); |
| 44 | 36 | |
| 37 | +/** | |
| 38 | + * comedi_set_hw_dev() - Set hardware device associated with COMEDI device | |
| 39 | + * @dev: COMEDI device. | |
| 40 | + * @hw_dev: Hardware device. | |
| 41 | + * | |
| 42 | + * For automatically configured COMEDI devices (resulting from a call to | |
| 43 | + * comedi_auto_config() or one of its wrappers from the low-level COMEDI | |
| 44 | + * driver), comedi_set_hw_dev() is called automatically by the COMEDI core | |
| 45 | + * to associate the COMEDI device with the hardware device. It can also be | |
| 46 | + * called directly by "legacy" low-level COMEDI drivers that rely on the | |
| 47 | + * %COMEDI_DEVCONFIG ioctl to configure the hardware as long as the hardware | |
| 48 | + * has a &struct device. | |
| 49 | + * | |
| 50 | + * If @dev->hw_dev is NULL, it gets a reference to @hw_dev and sets | |
| 51 | + * @dev->hw_dev, otherwise, it does nothing. Calling it multiple times | |
| 52 | + * with the same hardware device is not considered an error. If it gets | |
| 53 | + * a reference to the hardware device, it will be automatically 'put' when | |
| 54 | + * the device is detached from COMEDI. | |
| 55 | + * | |
| 56 | + * Returns 0 if @dev->hw_dev was NULL or the same as @hw_dev, otherwise | |
| 57 | + * returns -EEXIST. | |
| 58 | + */ | |
| 45 | 59 | int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev) |
| 46 | 60 | { |
| 47 | 61 | if (hw_dev == dev->hw_dev) |
| @@ -60,9 +74,15 @@ static void comedi_clear_hw_dev(struct comedi_device *dev) · 12 unmodified lines | ||
| 60 | 74 | } |
| 61 | 75 | |
| 62 | 76 | /** |
| 63 | − * comedi_alloc_devpriv() - Allocate memory for the device private data. | |
| 64 | − * @dev: comedi_device struct | |
| 65 | − * @size: size of the memory to allocate | |
| 77 | + * comedi_alloc_devpriv() - Allocate memory for the device private data | |
| 78 | + * @dev: COMEDI device. | |
| 79 | + * @size: Size of the memory to allocate. | |
| 80 | + * | |
| 81 | + * The allocated memory is zero-filled. @dev->private points to it on | |
| 82 | + * return. The memory will be automatically freed when the COMEDI device is | |
| 83 | + * "detached". | |
| 84 | + * | |
| 85 | + * Returns a pointer to the allocated memory, or NULL on failure. | |
| 66 | 86 | */ |
| 67 | 87 | void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) |
| 68 | 88 | { |
| @@ -71,6 +91,18 @@ void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) · 2 unmodified lines | ||
| 71 | 91 | } |
| 72 | 92 | EXPORT_SYMBOL_GPL(comedi_alloc_devpriv); |
| 73 | 93 | |
| 94 | +/** | |
| 95 | + * comedi_alloc_subdevices() - Allocate subdevices for COMEDI device | |
| 96 | + * @dev: COMEDI device. | |
| 97 | + * @num_subdevices: Number of subdevices to allocate. | |
| 98 | + * | |
| 99 | + * Allocates and initializes an array of &struct comedi_subdevice for the | |
| 100 | + * COMEDI device. If successful, sets @dev->subdevices to point to the | |
| 101 | + * first one and @dev->n_subdevices to the number. | |
| 102 | + * | |
| 103 | + * Returns 0 on success, -EINVAL if @num_subdevices is < 1, or -ENOMEM if | |
| 104 | + * failed to allocate the memory. | |
| 105 | + */ | |
| 74 | 106 | int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) |
| 75 | 107 | { |
| 76 | 108 | struct comedi_subdevice *s; |
| @@ -98,8 +130,22 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) · 21 unmodified lines | ||
| 98 | 130 | EXPORT_SYMBOL_GPL(comedi_alloc_subdevices); |
| 99 | 131 | |
| 100 | 132 | /** |
| 101 | − * comedi_alloc_subdev_readback() - Allocate memory for the subdevice readback. | |
| 102 | − * @s: comedi_subdevice struct | |
| 133 | + * comedi_alloc_subdev_readback() - Allocate memory for the subdevice readback | |
| 134 | + * @s: COMEDI subdevice. | |
| 135 | + * | |
| 136 | + * This is called by low-level COMEDI drivers to allocate an array to record | |
| 137 | + * the last values written to a subdevice's analog output channels (at least | |
| 138 | + * by the %INSN_WRITE instruction), to allow them to be read back by an | |
| 139 | + * %INSN_READ instruction. It also provides a default handler for the | |
| 140 | + * %INSN_READ instruction unless one has already been set. | |
| 141 | + * | |
| 142 | + * On success, @s->readback points to the first element of the array, which | |
| 143 | + * is zero-filled. The low-level driver is responsible for updating its | |
| 144 | + * contents. @s->insn_read will be set to comedi_readback_insn_read() | |
| 145 | + * unless it is already non-NULL. | |
| 146 | + * | |
| 147 | + * Returns 0 on success, -EINVAL if the subdevice has no channels, or | |
| 148 | + * -ENOMEM on allocation failure. | |
| 103 | 149 | */ |
| 104 | 150 | int comedi_alloc_subdev_readback(struct comedi_subdevice *s) |
| 105 | 151 | { |
| @@ -182,10 +228,20 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, · 76 unmodified lines | ||
| 182 | 228 | |
| 183 | 229 | /** |
| 184 | 230 | * comedi_readback_insn_read() - A generic (*insn_read) for subdevice readback. |
| 185 | − * @dev: comedi_device struct | |
| 186 | − * @s: comedi_subdevice struct | |
| 187 | − * @insn: comedi_insn struct | |
| 188 | − * @data: pointer to return the readback data | |
| 231 | + * @dev: COMEDI device. | |
| 232 | + * @s: COMEDI subdevice. | |
| 233 | + * @insn: COMEDI instruction. | |
| 234 | + * @data: Pointer to return the readback data. | |
| 235 | + * | |
| 236 | + * Handles the %INSN_READ instruction for subdevices that use the readback | |
| 237 | + * array allocated by comedi_alloc_subdev_readback(). It may be used | |
| 238 | + * directly as the subdevice's handler (@s->insn_read) or called via a | |
| 239 | + * wrapper. | |
| 240 | + * | |
| 241 | + * @insn->n is normally 1, which will read a single value. If higher, the | |
| 242 | + * same element of the readback array will be read multiple times. | |
| 243 | + * | |
| 244 | + * Returns @insn->n on success, or -EINVAL if @s->readback is NULL. | |
| 189 | 245 | */ |
| 190 | 246 | int comedi_readback_insn_read(struct comedi_device *dev, |
| 191 | 247 | struct comedi_subdevice *s, |
| @@ -206,12 +262,21 @@ int comedi_readback_insn_read(struct comedi_device *dev, · 14 unmodified lines | ||
| 206 | 262 | EXPORT_SYMBOL_GPL(comedi_readback_insn_read); |
| 207 | 263 | |
| 208 | 264 | /** |
| 209 | − * comedi_timeout() - busy-wait for a driver condition to occur. | |
| 210 | − * @dev: comedi_device struct | |
| 211 | − * @s: comedi_subdevice struct | |
| 212 | − * @insn: comedi_insn struct | |
| 213 | − * @cb: callback to check for the condition | |
| 214 | − * @context: private context from the driver | |
| 265 | + * comedi_timeout() - Busy-wait for a driver condition to occur | |
| 266 | + * @dev: COMEDI device. | |
| 267 | + * @s: COMEDI subdevice. | |
| 268 | + * @insn: COMEDI instruction. | |
| 269 | + * @cb: Callback to check for the condition. | |
| 270 | + * @context: Private context from the driver. | |
| 271 | + * | |
| 272 | + * Busy-waits for up to a second (%COMEDI_TIMEOUT_MS) for the condition or | |
| 273 | + * some error (other than -EBUSY) to occur. The parameters @dev, @s, @insn, | |
| 274 | + * and @context are passed to the callback function, which returns -EBUSY to | |
| 275 | + * continue waiting or some other value to stop waiting (generally 0 if the | |
| 276 | + * condition occurred, or some error value). | |
| 277 | + * | |
| 278 | + * Returns -ETIMEDOUT if timed out, otherwise the return value from the | |
| 279 | + * callback function. | |
| 215 | 280 | */ |
| 216 | 281 | int comedi_timeout(struct comedi_device *dev, |
| 217 | 282 | struct comedi_subdevice *s, |
| @@ -236,12 +301,30 @@ int comedi_timeout(struct comedi_device *dev, · 18 unmodified lines | ||
| 236 | 301 | EXPORT_SYMBOL_GPL(comedi_timeout); |
| 237 | 302 | |
| 238 | 303 | /** |
| 239 | − * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices. | |
| 240 | − * @dev: comedi_device struct | |
| 241 | − * @s: comedi_subdevice struct | |
| 242 | − * @insn: comedi_insn struct | |
| 243 | − * @data: parameters for the @insn | |
| 244 | − * @mask: io_bits mask for grouped channels | |
| 304 | + * comedi_dio_insn_config() - Boilerplate (*insn_config) for DIO subdevices | |
| 305 | + * @dev: COMEDI device. | |
| 306 | + * @s: COMEDI subdevice. | |
| 307 | + * @insn: COMEDI instruction. | |
| 308 | + * @data: Instruction parameters and return data. | |
| 309 | + * @mask: io_bits mask for grouped channels, or 0 for single channel. | |
| 310 | + * | |
| 311 | + * If @mask is 0, it is replaced with a single-bit mask corresponding to the | |
| 312 | + * channel number specified by @insn->chanspec. Otherwise, @mask | |
| 313 | + * corresponds to a group of channels (which should include the specified | |
| 314 | + * channel) that are always configured together as inputs or outputs. | |
| 315 | + * | |
| 316 | + * Partially handles the %INSN_CONFIG_DIO_INPUT, %INSN_CONFIG_DIO_OUTPUTS, | |
| 317 | + * and %INSN_CONFIG_DIO_QUERY instructions. The first two update | |
| 318 | + * @s->io_bits to record the directions of the masked channels. The last | |
| 319 | + * one sets @data[1] to the current direction of the group of channels | |
| 320 | + * (%COMEDI_INPUT) or %COMEDI_OUTPUT) as recorded in @s->io_bits. | |
| 321 | + * | |
| 322 | + * The caller is responsible for updating the DIO direction in the hardware | |
| 323 | + * registers if this function returns 0. | |
| 324 | + * | |
| 325 | + * Returns 0 for a %INSN_CONFIG_DIO_INPUT or %INSN_CONFIG_DIO_OUTPUT | |
| 326 | + * instruction, @insn->n (> 0) for a %INSN_CONFIG_DIO_QUERY instruction, or | |
| 327 | + * -EINVAL for some other instruction. | |
| 245 | 328 | */ |
| 246 | 329 | int comedi_dio_insn_config(struct comedi_device *dev, |
| 247 | 330 | struct comedi_subdevice *s, |
| @@ -276,9 +359,18 @@ int comedi_dio_insn_config(struct comedi_device *dev, · 28 unmodified lines | ||
| 276 | 359 | EXPORT_SYMBOL_GPL(comedi_dio_insn_config); |
| 277 | 360 | |
| 278 | 361 | /** |
| 279 | − * comedi_dio_update_state() - update the internal state of DIO subdevices. | |
| 280 | − * @s: comedi_subdevice struct | |
| 281 | − * @data: the channel mask and bits to update | |
| 362 | + * comedi_dio_update_state() - Update the internal state of DIO subdevices | |
| 363 | + * @s: COMEDI subdevice. | |
| 364 | + * @data: The channel mask and bits to update. | |
| 365 | + * | |
| 366 | + * Updates @s->state which holds the internal state of the outputs for DIO | |
| 367 | + * or DO subdevices (up to 32 channels). @data[0] contains a bit-mask of | |
| 368 | + * the channels to be updated. @data[1] contains a bit-mask of those | |
| 369 | + * channels to be set to '1'. The caller is responsible for updating the | |
| 370 | + * outputs in hardware according to @s->state. As a minimum, the channels | |
| 371 | + * in the returned bit-mask need to be updated. | |
| 372 | + * | |
| 373 | + * Returns @mask with non-existent channels removed. | |
| 282 | 374 | */ |
| 283 | 375 | unsigned int comedi_dio_update_state(struct comedi_subdevice *s, |
| 284 | 376 | unsigned int *data) |
| @@ -298,17 +390,17 @@ unsigned int comedi_dio_update_state(struct comedi_subdevice *s, · 13 unmodified lines | ||
| 298 | 390 | EXPORT_SYMBOL_GPL(comedi_dio_update_state); |
| 299 | 391 | |
| 300 | 392 | /** |
| 301 | − * comedi_bytes_per_scan - get length of asynchronous command "scan" in bytes | |
| 302 | − * @s: comedi_subdevice struct | |
| 393 | + * comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes | |
| 394 | + * @s: COMEDI subdevice. | |
| 303 | 395 | * |
| 304 | 396 | * Determines the overall scan length according to the subdevice type and the |
| 305 | 397 | * number of channels in the scan. |
| 306 | 398 | * |
| 307 | − * For digital input, output or input/output subdevices, samples for multiple | |
| 308 | − * channels are assumed to be packed into one or more unsigned short or | |
| 309 | − * unsigned int values according to the subdevice's SDF_LSAMPL flag. For other | |
| 310 | − * types of subdevice, samples are assumed to occupy a whole unsigned short or | |
| 311 | − * unsigned int according to the SDF_LSAMPL flag. | |
| 399 | + * For digital input, output or input/output subdevices, samples for | |
| 400 | + * multiple channels are assumed to be packed into one or more unsigned | |
| 401 | + * short or unsigned int values according to the subdevice's %SDF_LSAMPL | |
| 402 | + * flag. For other types of subdevice, samples are assumed to occupy a | |
| 403 | + * whole unsigned short or unsigned int according to the %SDF_LSAMPL flag. | |
| 312 | 404 | * |
| 313 | 405 | * Returns the overall scan length in bytes. |
| 314 | 406 | */ |
| @@ -333,32 +425,12 @@ unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s) · 18 unmodified lines | ||
| 333 | 425 | } |
| 334 | 426 | EXPORT_SYMBOL_GPL(comedi_bytes_per_scan); |
| 335 | 427 | |
| 336 | −/** | |
| 337 | − * comedi_nscans_left - return the number of scans left in the command | |
| 338 | − * @s: comedi_subdevice struct | |
| 339 | − * @nscans: the expected number of scans | |
| 340 | − * | |
| 341 | − * If nscans is 0, the number of scans available in the async buffer will be | |
| 342 | − * used. Otherwise the expected number of scans will be used. | |
| 343 | − * | |
| 344 | − * If the async command has a stop_src of TRIG_COUNT, the nscans will be | |
| 345 | − * checked against the number of scans left in the command. | |
| 346 | − * | |
| 347 | − * The return value will then be either the expected number of scans or the | |
| 348 | − * number of scans remaining in the command. | |
| 349 | − */ | |
| 350 | −unsigned int comedi_nscans_left(struct comedi_subdevice *s, | |
| 351 | − unsigned int nscans) | |
| 428 | +static unsigned int __comedi_nscans_left(struct comedi_subdevice *s, | |
| 429 | + unsigned int nscans) | |
| 352 | 430 | { |
| 353 | 431 | struct comedi_async *async = s->async; |
| 354 | 432 | struct comedi_cmd *cmd = &async->cmd; |
| 355 | 433 | |
| 356 | − if (nscans == 0) { | |
| 357 | − unsigned int nbytes = comedi_buf_read_n_available(s); | |
| 358 | − | |
| 359 | − nscans = nbytes / comedi_bytes_per_scan(s); | |
| 360 | − } | |
| 361 | − | |
| 362 | 434 | if (cmd->stop_src == TRIG_COUNT) { |
| 363 | 435 | unsigned int scans_left = 0; |
| 364 | 436 | |
| @@ -370,15 +442,40 @@ unsigned int comedi_nscans_left(struct comedi_subdevice *s, · 5 unmodified lines | ||
| 370 | 442 | } |
| 371 | 443 | return nscans; |
| 372 | 444 | } |
| 445 | + | |
| 446 | +/** | |
| 447 | + * comedi_nscans_left() - Return the number of scans left in the command | |
| 448 | + * @s: COMEDI subdevice. | |
| 449 | + * @nscans: The expected number of scans or 0 for all available scans. | |
| 450 | + * | |
| 451 | + * If @nscans is 0, it is set to the number of scans available in the | |
| 452 | + * async buffer. | |
| 453 | + * | |
| 454 | + * If the async command has a stop_src of %TRIG_COUNT, the @nscans will be | |
| 455 | + * checked against the number of scans remaining to complete the command. | |
| 456 | + * | |
| 457 | + * The return value will then be either the expected number of scans or the | |
| 458 | + * number of scans remaining to complete the command, whichever is fewer. | |
| 459 | + */ | |
| 460 | +unsigned int comedi_nscans_left(struct comedi_subdevice *s, | |
| 461 | + unsigned int nscans) | |
| 462 | +{ | |
| 463 | + if (nscans == 0) { | |
| 464 | + unsigned int nbytes = comedi_buf_read_n_available(s); | |
| 465 | + | |
| 466 | + nscans = nbytes / comedi_bytes_per_scan(s); | |
| 467 | + } | |
| 468 | + return __comedi_nscans_left(s, nscans); | |
| 469 | +} | |
| 373 | 470 | EXPORT_SYMBOL_GPL(comedi_nscans_left); |
| 374 | 471 | |
| 375 | 472 | /** |
| 376 | − * comedi_nsamples_left - return the number of samples left in the command | |
| 377 | − * @s: comedi_subdevice struct | |
| 378 | − * @nsamples: the expected number of samples | |
| 473 | + * comedi_nsamples_left() - Return the number of samples left in the command | |
| 474 | + * @s: COMEDI subdevice. | |
| 475 | + * @nsamples: The expected number of samples. | |
| 379 | 476 | * |
| 380 | − * Returns the expected number of samples of the number of samples remaining | |
| 381 | − * in the command. | |
| 477 | + * Returns the number of samples remaining to complete the command, or the | |
| 478 | + * specified expected number of samples (@nsamples), whichever is fewer. | |
| 382 | 479 | */ |
| 383 | 480 | unsigned int comedi_nsamples_left(struct comedi_subdevice *s, |
| 384 | 481 | unsigned int nsamples) |
| @@ -387,9 +484,8 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, · 2 unmodified lines | ||
| 387 | 484 | struct comedi_cmd *cmd = &async->cmd; |
| 388 | 485 | |
| 389 | 486 | if (cmd->stop_src == TRIG_COUNT) { |
| 390 | − /* +1 to force comedi_nscans_left() to return the scans left */ | |
| 391 | − unsigned int nscans = (nsamples / cmd->scan_end_arg) + 1; | |
| 392 | − unsigned int scans_left = comedi_nscans_left(s, nscans); | |
| 487 | + unsigned int nscans = nsamples / cmd->scan_end_arg; | |
| 488 | + unsigned int scans_left = __comedi_nscans_left(s, nscans); | |
| 393 | 489 | unsigned int scan_pos = |
| 394 | 490 | comedi_bytes_to_samples(s, async->scan_progress); |
| 395 | 491 | unsigned long long samples_left = 0; |
| @@ -407,14 +503,14 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, · 11 unmodified lines | ||
| 407 | 503 | EXPORT_SYMBOL_GPL(comedi_nsamples_left); |
| 408 | 504 | |
| 409 | 505 | /** |
| 410 | − * comedi_inc_scan_progress - update scan progress in asynchronous command | |
| 411 | − * @s: comedi_subdevice struct | |
| 412 | − * @num_bytes: amount of data in bytes to increment scan progress | |
| 506 | + * comedi_inc_scan_progress() - Update scan progress in asynchronous command | |
| 507 | + * @s: COMEDI subdevice. | |
| 508 | + * @num_bytes: Amount of data in bytes to increment scan progress. | |
| 413 | 509 | * |
| 414 | − * Increments the scan progress by the number of bytes specified by num_bytes. | |
| 510 | + * Increments the scan progress by the number of bytes specified by @num_bytes. | |
| 415 | 511 | * If the scan progress reaches or exceeds the scan length in bytes, reduce |
| 416 | 512 | * it modulo the scan length in bytes and set the "end of scan" asynchronous |
| 417 | − * event flag to be processed later. | |
| 513 | + * event flag (%COMEDI_CB_EOS) to be processed later. | |
| 418 | 514 | */ |
| 419 | 515 | void comedi_inc_scan_progress(struct comedi_subdevice *s, |
| 420 | 516 | unsigned int num_bytes) |
| @@ -445,12 +541,12 @@ void comedi_inc_scan_progress(struct comedi_subdevice *s, · 24 unmodified lines | ||
| 445 | 541 | EXPORT_SYMBOL_GPL(comedi_inc_scan_progress); |
| 446 | 542 | |
| 447 | 543 | /** |
| 448 | − * comedi_handle_events - handle events and possibly stop acquisition | |
| 449 | − * @dev: comedi_device struct | |
| 450 | − * @s: comedi_subdevice struct | |
| 544 | + * comedi_handle_events() - Handle events and possibly stop acquisition | |
| 545 | + * @dev: COMEDI device. | |
| 546 | + * @s: COMEDI subdevice. | |
| 451 | 547 | * |
| 452 | 548 | * Handles outstanding asynchronous acquisition event flags associated |
| 453 | − * with the subdevice. Call the subdevice's "->cancel()" handler if the | |
| 549 | + * with the subdevice. Call the subdevice's @s->cancel() handler if the | |
| 454 | 550 | * "end of acquisition", "error" or "overflow" event flags are set in order |
| 455 | 551 | * to stop the acquisition at the driver level. |
| 456 | 552 | * |
| @@ -685,12 +781,19 @@ static void comedi_report_boards(struct comedi_driver *driv) · 228 unmodified lines | ||
| 685 | 781 | } |
| 686 | 782 | |
| 687 | 783 | /** |
| 688 | − * comedi_load_firmware() - Request and load firmware for a device. | |
| 689 | − * @dev: comedi_device struct | |
| 690 | − * @hw_device: device struct for the comedi_device | |
| 691 | − * @name: the name of the firmware image | |
| 692 | − * @cb: callback to the upload the firmware image | |
| 693 | − * @context: private context from the driver | |
| 784 | + * comedi_load_firmware() - Request and load firmware for a device | |
| 785 | + * @dev: COMEDI device. | |
| 786 | + * @device: Hardware device. | |
| 787 | + * @name: The name of the firmware image. | |
| 788 | + * @cb: Callback to the upload the firmware image. | |
| 789 | + * @context: Private context from the driver. | |
| 790 | + * | |
| 791 | + * Sends a firmware request for the hardware device and waits for it. Calls | |
| 792 | + * the callback function to upload the firmware to the device, them releases | |
| 793 | + * the firmware. | |
| 794 | + * | |
| 795 | + * Returns 0 on success, -EINVAL if @cb is NULL, or a negative error number | |
| 796 | + * from the firmware request or the callback function. | |
| 694 | 797 | */ |
| 695 | 798 | int comedi_load_firmware(struct comedi_device *dev, |
| 696 | 799 | struct device *device, |
| @@ -717,10 +820,16 @@ int comedi_load_firmware(struct comedi_device *dev, · 20 unmodified lines | ||
| 717 | 820 | EXPORT_SYMBOL_GPL(comedi_load_firmware); |
| 718 | 821 | |
| 719 | 822 | /** |
| 720 | − * __comedi_request_region() - Request an I/O reqion for a legacy driver. | |
| 721 | − * @dev: comedi_device struct | |
| 722 | − * @start: base address of the I/O reqion | |
| 723 | − * @len: length of the I/O region | |
| 823 | + * __comedi_request_region() - Request an I/O region for a legacy driver | |
| 824 | + * @dev: COMEDI device. | |
| 825 | + * @start: Base address of the I/O region. | |
| 826 | + * @len: Length of the I/O region. | |
| 827 | + * | |
| 828 | + * Requests the specified I/O port region which must start at a non-zero | |
| 829 | + * address. | |
| 830 | + * | |
| 831 | + * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request | |
| 832 | + * fails. | |
| 724 | 833 | */ |
| 725 | 834 | int __comedi_request_region(struct comedi_device *dev, |
| 726 | 835 | unsigned long start, unsigned long len) |
| @@ -743,10 +852,19 @@ int __comedi_request_region(struct comedi_device *dev, · 16 unmodified lines | ||
| 743 | 852 | EXPORT_SYMBOL_GPL(__comedi_request_region); |
| 744 | 853 | |
| 745 | 854 | /** |
| 746 | − * comedi_request_region() - Request an I/O reqion for a legacy driver. | |
| 747 | − * @dev: comedi_device struct | |
| 748 | − * @start: base address of the I/O reqion | |
| 749 | − * @len: length of the I/O region | |
| 855 | + * comedi_request_region() - Request an I/O region for a legacy driver | |
| 856 | + * @dev: COMEDI device. | |
| 857 | + * @start: Base address of the I/O region. | |
| 858 | + * @len: Length of the I/O region. | |
| 859 | + * | |
| 860 | + * Requests the specified I/O port region which must start at a non-zero | |
| 861 | + * address. | |
| 862 | + * | |
| 863 | + * On success, @dev->iobase is set to the base address of the region and | |
| 864 | + * @dev->iolen is set to its length. | |
| 865 | + * | |
| 866 | + * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request | |
| 867 | + * fails. | |
| 750 | 868 | */ |
| 751 | 869 | int comedi_request_region(struct comedi_device *dev, |
| 752 | 870 | unsigned long start, unsigned long len) |
| @@ -764,8 +882,16 @@ int comedi_request_region(struct comedi_device *dev, · 11 unmodified lines | ||
| 764 | 882 | EXPORT_SYMBOL_GPL(comedi_request_region); |
| 765 | 883 | |
| 766 | 884 | /** |
| 767 | − * comedi_legacy_detach() - A generic (*detach) function for legacy drivers. | |
| 768 | − * @dev: comedi_device struct | |
| 885 | + * comedi_legacy_detach() - A generic (*detach) function for legacy drivers | |
| 886 | + * @dev: COMEDI device. | |
| 887 | + * | |
| 888 | + * This is a simple, generic 'detach' handler for legacy COMEDI devices that | |
| 889 | + * just use a single I/O port region and possibly an IRQ and that don't need | |
| 890 | + * any special clean-up for their private device or subdevice storage. It | |
| 891 | + * can also be called by a driver-specific 'detach' handler. | |
| 892 | + * | |
| 893 | + * If @dev->irq is non-zero, the IRQ will be freed. If @dev->iobase and | |
| 894 | + * @dev->iolen are both non-zero, the I/O port region will be released. | |
| 769 | 895 | */ |
| 770 | 896 | void comedi_legacy_detach(struct comedi_device *dev) |
| 771 | 897 | { |
| @@ -839,6 +965,29 @@ out: · 67 unmodified lines | ||
| 839 | 965 | return ret; |
| 840 | 966 | } |
| 841 | 967 | |
| 968 | +/** | |
| 969 | + * comedi_auto_config() - Create a COMEDI device for a hardware device | |
| 970 | + * @hardware_device: Hardware device. | |
| 971 | + * @driver: COMEDI low-level driver for the hardware device. | |
| 972 | + * @context: Driver context for the auto_attach handler. | |
| 973 | + * | |
| 974 | + * Allocates a new COMEDI device for the hardware device and calls the | |
| 975 | + * low-level driver's 'auto_attach' handler to set-up the hardware and | |
| 976 | + * allocate the COMEDI subdevices. Additional "post-configuration" setting | |
| 977 | + * up is performed on successful return from the 'auto_attach' handler. | |
| 978 | + * If the 'auto_attach' handler fails, the low-level driver's 'detach' | |
| 979 | + * handler will be called as part of the clean-up. | |
| 980 | + * | |
| 981 | + * This is usually called from a wrapper function in a bus-specific COMEDI | |
| 982 | + * module, which in turn is usually called from a bus device 'probe' | |
| 983 | + * function in the low-level driver. | |
| 984 | + * | |
| 985 | + * Returns 0 on success, -EINVAL if the parameters are invalid or the | |
| 986 | + * post-configuration determines the driver has set the COMEDI device up | |
| 987 | + * incorrectly, -ENOMEM if failed to allocate memory, -EBUSY if run out of | |
| 988 | + * COMEDI minor device numbers, or some negative error number returned by | |
| 989 | + * the driver's 'auto_attach' handler. | |
| 990 | + */ | |
| 842 | 991 | int comedi_auto_config(struct device *hardware_device, |
| 843 | 992 | struct comedi_driver *driver, unsigned long context) |
| 844 | 993 | { |
| @@ -896,6 +1045,22 @@ int comedi_auto_config(struct device *hardware_device, · 51 unmodified lines | ||
| 896 | 1045 | } |
| 897 | 1046 | EXPORT_SYMBOL_GPL(comedi_auto_config); |
| 898 | 1047 | |
| 1048 | +/** | |
| 1049 | + * comedi_auto_unconfig() - Unconfigure auto-allocated COMEDI device | |
| 1050 | + * @hardware_device: Hardware device previously passed to | |
| 1051 | + * comedi_auto_config(). | |
| 1052 | + * | |
| 1053 | + * Cleans up and eventually destroys the COMEDI device allocated by | |
| 1054 | + * comedi_auto_config() for the same hardware device. As part of this | |
| 1055 | + * clean-up, the low-level COMEDI driver's 'detach' handler will be called. | |
| 1056 | + * (The COMEDI device itself will persist in an unattached state if it is | |
| 1057 | + * still open, until it is released, and any mmapped buffers will persist | |
| 1058 | + * until they are munmapped.) | |
| 1059 | + * | |
| 1060 | + * This is usually called from a wrapper module in a bus-specific COMEDI | |
| 1061 | + * module, which in turn is usually set as the bus device 'remove' function | |
| 1062 | + * in the low-level COMEDI driver. | |
| 1063 | + */ | |
| 899 | 1064 | void comedi_auto_unconfig(struct device *hardware_device) |
| 900 | 1065 | { |
| 901 | 1066 | if (!hardware_device) |
| @@ -904,6 +1069,17 @@ void comedi_auto_unconfig(struct device *hardware_device) · 2 unmodified lines | ||
| 904 | 1069 | } |
| 905 | 1070 | EXPORT_SYMBOL_GPL(comedi_auto_unconfig); |
| 906 | 1071 | |
| 1072 | +/** | |
| 1073 | + * comedi_driver_register() - Register a low-level COMEDI driver | |
| 1074 | + * @driver: Low-level COMEDI driver. | |
| 1075 | + * | |
| 1076 | + * The low-level COMEDI driver is added to the list of registered COMEDI | |
| 1077 | + * drivers. This is used by the handler for the "/proc/comedi" file and is | |
| 1078 | + * also used by the handler for the %COMEDI_DEVCONFIG ioctl to configure | |
| 1079 | + * "legacy" COMEDI devices (for those low-level drivers that support it). | |
| 1080 | + * | |
| 1081 | + * Returns 0. | |
| 1082 | + */ | |
| 907 | 1083 | int comedi_driver_register(struct comedi_driver *driver) |
| 908 | 1084 | { |
| 909 | 1085 | mutex_lock(&comedi_drivers_list_lock); |
| @@ -915,6 +1091,15 @@ int comedi_driver_register(struct comedi_driver *driver) · 5 unmodified lines | ||
| 915 | 1091 | } |
| 916 | 1092 | EXPORT_SYMBOL_GPL(comedi_driver_register); |
| 917 | 1093 | |
| 1094 | +/** | |
| 1095 | + * comedi_driver_unregister() - Unregister a low-level COMEDI driver | |
| 1096 | + * @driver: Low-level COMEDI driver. | |
| 1097 | + * | |
| 1098 | + * The low-level COMEDI driver is removed from the list of registered COMEDI | |
| 1099 | + * drivers. Detaches any COMEDI devices attached to the driver, which will | |
| 1100 | + * result in the low-level driver's 'detach' handler being called for those | |
| 1101 | + * devices before this function returns. | |
| 1102 | + */ | |
| 918 | 1103 | void comedi_driver_unregister(struct comedi_driver *driver) |
| 919 | 1104 | { |
| 920 | 1105 | struct comedi_driver *prev; |
| @@ -25,13 +25,13 @@ · 24 unmodified lines | ||
| 25 | 25 | #define I8255_DATA_B_REG 0x01 |
| 26 | 26 | #define I8255_DATA_C_REG 0x02 |
| 27 | 27 | #define I8255_CTRL_REG 0x03 |
| 28 | −#define I8255_CTRL_C_LO_IO (1 << 0) | |
| 29 | −#define I8255_CTRL_B_IO (1 << 1) | |
| 30 | −#define I8255_CTRL_B_MODE (1 << 2) | |
| 31 | −#define I8255_CTRL_C_HI_IO (1 << 3) | |
| 32 | −#define I8255_CTRL_A_IO (1 << 4) | |
| 28 | +#define I8255_CTRL_C_LO_IO BIT(0) | |
| 29 | +#define I8255_CTRL_B_IO BIT(1) | |
| 30 | +#define I8255_CTRL_B_MODE BIT(2) | |
| 31 | +#define I8255_CTRL_C_HI_IO BIT(3) | |
| 32 | +#define I8255_CTRL_A_IO BIT(4) | |
| 33 | 33 | #define I8255_CTRL_A_MODE(x) ((x) << 5) |
| 34 | −#define I8255_CTRL_CW (1 << 7) | |
| 34 | +#define I8255_CTRL_CW BIT(7) | |
| 35 | 35 | |
| 36 | 36 | struct comedi_device; |
| 37 | 37 | struct comedi_subdevice; |
| @@ -178,8 +178,8 @@ static const struct pci_8255_boardinfo pci_8255_boards[] = { · 177 unmodified lines | ||
| 178 | 178 | }; |
| 179 | 179 | |
| 180 | 180 | /* ripped from mite.h and mite_setup2() to avoid mite dependency */ |
| 181 | −#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ | |
| 182 | −#define WENAB (1 << 7) /* window enable */ | |
| 181 | +#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ | |
| 182 | +#define WENAB BIT(7) /* window enable */ | |
| 183 | 183 | |
| 184 | 184 | static int pci_8255_mite_init(struct pci_dev *pcidev) |
| 185 | 185 | { |
| @@ -90,7 +90,6 @@ obj-$(CONFIG_COMEDI_CONTEC_PCI_DIO) += contec_pci_dio.o · 89 unmodified lines | ||
| 90 | 90 | obj-$(CONFIG_COMEDI_DAS08_PCI) += das08_pci.o |
| 91 | 91 | obj-$(CONFIG_COMEDI_DT3000) += dt3000.o |
| 92 | 92 | obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o |
| 93 | −obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o | |
| 94 | 93 | obj-$(CONFIG_COMEDI_GSC_HPDI) += gsc_hpdi.o |
| 95 | 94 | obj-$(CONFIG_COMEDI_ICP_MULTI) += icp_multi.o |
| 96 | 95 | obj-$(CONFIG_COMEDI_DAQBOARD2000) += daqboard2000.o |
| @@ -84,9 +84,10 @@ · 83 unmodified lines | ||
| 84 | 84 | #define APCI1032_MODE2_REG 0x08 |
| 85 | 85 | #define APCI1032_STATUS_REG 0x0c |
| 86 | 86 | #define APCI1032_CTRL_REG 0x10 |
| 87 | −#define APCI1032_CTRL_INT_OR (0 << 1) | |
| 88 | −#define APCI1032_CTRL_INT_AND (1 << 1) | |
| 89 | −#define APCI1032_CTRL_INT_ENA (1 << 2) | |
| 87 | +#define APCI1032_CTRL_INT_MODE(x) (((x) & 0x1) << 1) | |
| 88 | +#define APCI1032_CTRL_INT_OR APCI1032_CTRL_INT_MODE(0) | |
| 89 | +#define APCI1032_CTRL_INT_AND APCI1032_CTRL_INT_MODE(1) | |
| 90 | +#define APCI1032_CTRL_INT_ENA BIT(2) | |
| 90 | 91 | |
| 91 | 92 | struct apci1032_private { |
| 92 | 93 | unsigned long amcc_iobase; /* base of AMCC I/O registers */ |
| @@ -34,19 +34,19 @@ · 33 unmodified lines | ||
| 34 | 34 | */ |
| 35 | 35 | #define APCI2032_DO_REG 0x00 |
| 36 | 36 | #define APCI2032_INT_CTRL_REG 0x04 |
| 37 | −#define APCI2032_INT_CTRL_VCC_ENA (1 << 0) | |
| 38 | −#define APCI2032_INT_CTRL_CC_ENA (1 << 1) | |
| 37 | +#define APCI2032_INT_CTRL_VCC_ENA BIT(0) | |
| 38 | +#define APCI2032_INT_CTRL_CC_ENA BIT(1) | |
| 39 | 39 | #define APCI2032_INT_STATUS_REG 0x08 |
| 40 | −#define APCI2032_INT_STATUS_VCC (1 << 0) | |
| 41 | −#define APCI2032_INT_STATUS_CC (1 << 1) | |
| 40 | +#define APCI2032_INT_STATUS_VCC BIT(0) | |
| 41 | +#define APCI2032_INT_STATUS_CC BIT(1) | |
| 42 | 42 | #define APCI2032_STATUS_REG 0x0c |
| 43 | −#define APCI2032_STATUS_IRQ (1 << 0) | |
| 43 | +#define APCI2032_STATUS_IRQ BIT(0) | |
| 44 | 44 | #define APCI2032_WDOG_REG 0x10 |
| 45 | 45 | |
| 46 | 46 | struct apci2032_int_private { |
| 47 | − spinlock_t spinlock; | |
| 48 | − bool active; | |
| 49 | − unsigned char enabled_isns; | |
| 47 | + spinlock_t spinlock; /* protects the following members */ | |
| 48 | + bool active; /* an async command is running */ | |
| 49 | + unsigned char enabled_isns; /* mask of enabled interrupt channels */ | |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | 52 | static int apci2032_do_insn_bits(struct comedi_device *dev, |
| @@ -31,33 +31,33 @@ · 30 unmodified lines | ||
| 31 | 31 | * PCI BAR 0 register map (devpriv->amcc) |
| 32 | 32 | * see amcc_s5933.h for register and bit defines |
| 33 | 33 | */ |
| 34 | −#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 (1 << 29) | |
| 34 | +#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 BIT(29) | |
| 35 | 35 | |
| 36 | 36 | /* |
| 37 | 37 | * PCI BAR 1 register map (dev->iobase) |
| 38 | 38 | */ |
| 39 | 39 | #define APCI3120_AI_FIFO_REG 0x00 |
| 40 | 40 | #define APCI3120_CTRL_REG 0x00 |
| 41 | −#define APCI3120_CTRL_EXT_TRIG (1 << 15) | |
| 42 | −#define APCI3120_CTRL_GATE(x) (1 << (12 + (x))) | |
| 41 | +#define APCI3120_CTRL_EXT_TRIG BIT(15) | |
| 42 | +#define APCI3120_CTRL_GATE(x) BIT(12 + (x)) | |
| 43 | 43 | #define APCI3120_CTRL_PR(x) (((x) & 0xf) << 8) |
| 44 | 44 | #define APCI3120_CTRL_PA(x) (((x) & 0xf) << 0) |
| 45 | 45 | #define APCI3120_AI_SOFTTRIG_REG 0x02 |
| 46 | 46 | #define APCI3120_STATUS_REG 0x02 |
| 47 | −#define APCI3120_STATUS_EOC_INT (1 << 15) | |
| 48 | −#define APCI3120_STATUS_AMCC_INT (1 << 14) | |
| 49 | −#define APCI3120_STATUS_EOS_INT (1 << 13) | |
| 50 | −#define APCI3120_STATUS_TIMER2_INT (1 << 12) | |
| 47 | +#define APCI3120_STATUS_EOC_INT BIT(15) | |
| 48 | +#define APCI3120_STATUS_AMCC_INT BIT(14) | |
| 49 | +#define APCI3120_STATUS_EOS_INT BIT(13) | |
| 50 | +#define APCI3120_STATUS_TIMER2_INT BIT(12) | |
| 51 | 51 | #define APCI3120_STATUS_INT_MASK (0xf << 12) |
| 52 | 52 | #define APCI3120_STATUS_TO_DI_BITS(x) (((x) >> 8) & 0xf) |
| 53 | 53 | #define APCI3120_STATUS_TO_VERSION(x) (((x) >> 4) & 0xf) |
| 54 | −#define APCI3120_STATUS_FIFO_FULL (1 << 2) | |
| 55 | −#define APCI3120_STATUS_FIFO_EMPTY (1 << 1) | |
| 56 | −#define APCI3120_STATUS_DA_READY (1 << 0) | |
| 54 | +#define APCI3120_STATUS_FIFO_FULL BIT(2) | |
| 55 | +#define APCI3120_STATUS_FIFO_EMPTY BIT(1) | |
| 56 | +#define APCI3120_STATUS_DA_READY BIT(0) | |
| 57 | 57 | #define APCI3120_TIMER_REG 0x04 |
| 58 | 58 | #define APCI3120_CHANLIST_REG 0x06 |
| 59 | 59 | #define APCI3120_CHANLIST_INDEX(x) (((x) & 0xf) << 8) |
| 60 | −#define APCI3120_CHANLIST_UNIPOLAR (1 << 7) | |
| 60 | +#define APCI3120_CHANLIST_UNIPOLAR BIT(7) | |
| 61 | 61 | #define APCI3120_CHANLIST_GAIN(x) (((x) & 0x3) << 4) |
| 62 | 62 | #define APCI3120_CHANLIST_MUX(x) (((x) & 0xf) << 0) |
| 63 | 63 | #define APCI3120_AO_REG(x) (0x08 + (((x) / 4) * 2)) |
| @@ -74,19 +74,21 @@ · 10 unmodified lines | ||
| 74 | 74 | #define APCI3120_CTR0_DO_BITS(x) ((x) << 4) |
| 75 | 75 | #define APCI3120_CTR0_TIMER_SEL(x) ((x) << 0) |
| 76 | 76 | #define APCI3120_MODE_REG 0x0e |
| 77 | −#define APCI3120_MODE_TIMER2_CLK_OSC (0 << 6) | |
| 78 | −#define APCI3120_MODE_TIMER2_CLK_OUT1 (1 << 6) | |
| 79 | −#define APCI3120_MODE_TIMER2_CLK_EOC (2 << 6) | |
| 80 | −#define APCI3120_MODE_TIMER2_CLK_EOS (3 << 6) | |
| 81 | −#define APCI3120_MODE_TIMER2_CLK_MASK (3 << 6) | |
| 82 | −#define APCI3120_MODE_TIMER2_AS_TIMER (0 << 4) | |
| 83 | −#define APCI3120_MODE_TIMER2_AS_COUNTER (1 << 4) | |
| 84 | −#define APCI3120_MODE_TIMER2_AS_WDOG (2 << 4) | |
| 85 | −#define APCI3120_MODE_TIMER2_AS_MASK (3 << 4) /* sets AS_TIMER */ | |
| 86 | −#define APCI3120_MODE_SCAN_ENA (1 << 3) | |
| 87 | −#define APCI3120_MODE_TIMER2_IRQ_ENA (1 << 2) | |
| 88 | −#define APCI3120_MODE_EOS_IRQ_ENA (1 << 1) | |
| 89 | −#define APCI3120_MODE_EOC_IRQ_ENA (1 << 0) | |
| 77 | +#define APCI3120_MODE_TIMER2_CLK(x) (((x) & 0x3) << 6) | |
| 78 | +#define APCI3120_MODE_TIMER2_CLK_OSC APCI3120_MODE_TIMER2_CLK(0) | |
| 79 | +#define APCI3120_MODE_TIMER2_CLK_OUT1 APCI3120_MODE_TIMER2_CLK(1) | |
| 80 | +#define APCI3120_MODE_TIMER2_CLK_EOC APCI3120_MODE_TIMER2_CLK(2) | |
| 81 | +#define APCI3120_MODE_TIMER2_CLK_EOS APCI3120_MODE_TIMER2_CLK(3) | |
| 82 | +#define APCI3120_MODE_TIMER2_CLK_MASK APCI3120_MODE_TIMER2_CLK(3) | |
| 83 | +#define APCI3120_MODE_TIMER2_AS(x) (((x) & 0x3) << 4) | |
| 84 | +#define APCI3120_MODE_TIMER2_AS_TIMER APCI3120_MODE_TIMER2_AS(0) | |
| 85 | +#define APCI3120_MODE_TIMER2_AS_COUNTER APCI3120_MODE_TIMER2_AS(1) | |
| 86 | +#define APCI3120_MODE_TIMER2_AS_WDOG APCI3120_MODE_TIMER2_AS(2) | |
| 87 | +#define APCI3120_MODE_TIMER2_AS_MASK APCI3120_MODE_TIMER2_AS(3) | |
| 88 | +#define APCI3120_MODE_SCAN_ENA BIT(3) | |
| 89 | +#define APCI3120_MODE_TIMER2_IRQ_ENA BIT(2) | |
| 90 | +#define APCI3120_MODE_EOS_IRQ_ENA BIT(1) | |
| 91 | +#define APCI3120_MODE_EOC_IRQ_ENA BIT(0) | |
| 90 | 92 | |
| 91 | 93 | /* |
| 92 | 94 | * PCI BAR 2 register map (devpriv->addon) |
| @@ -94,8 +96,8 @@ · 1 unmodified line | ||
| 94 | 96 | #define APCI3120_ADDON_ADDR_REG 0x00 |
| 95 | 97 | #define APCI3120_ADDON_DATA_REG 0x02 |
| 96 | 98 | #define APCI3120_ADDON_CTRL_REG 0x04 |
| 97 | −#define APCI3120_ADDON_CTRL_AMWEN_ENA (1 << 1) | |
| 98 | −#define APCI3120_ADDON_CTRL_A2P_FIFO_ENA (1 << 0) | |
| 99 | +#define APCI3120_ADDON_CTRL_AMWEN_ENA BIT(1) | |
| 100 | +#define APCI3120_ADDON_CTRL_A2P_FIFO_ENA BIT(0) | |
| 99 | 101 | |
| 100 | 102 | /* |
| 101 | 103 | * Board revisions |
| @@ -502,11 +504,6 @@ static irqreturn_t apci3120_interrupt(int irq, void *d) · 400 unmodified lines | ||
| 502 | 504 | if (int_amcc & TARGET_ABORT_INT) |
| 503 | 505 | dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n"); |
| 504 | 506 | |
| 505 | − if ((status & APCI3120_STATUS_EOC_INT) == 0 && | |
| 506 | − (devpriv->mode & APCI3120_MODE_EOC_IRQ_ENA)) { | |
| 507 | − /* nothing to do... EOC mode is not currently used */ | |
| 508 | − } | |
| 509 | − | |
| 510 | 507 | if ((status & APCI3120_STATUS_EOS_INT) && |
| 511 | 508 | (devpriv->mode & APCI3120_MODE_EOS_IRQ_ENA)) { |
| 512 | 509 | unsigned short val; |
| @@ -27,9 +27,9 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | #include "../comedi_pci.h" |
| 29 | 29 | |
| 30 | −#define CONV_UNIT_NS (1 << 0) | |
| 31 | −#define CONV_UNIT_US (1 << 1) | |
| 32 | −#define CONV_UNIT_MS (1 << 2) | |
| 30 | +#define CONV_UNIT_NS BIT(0) | |
| 31 | +#define CONV_UNIT_US BIT(1) | |
| 32 | +#define CONV_UNIT_MS BIT(2) | |
| 33 | 33 | |
| 34 | 34 | static const struct comedi_lrange apci3xxx_ai_range = { |
| 35 | 35 | 8, { |
| @@ -41,7 +41,7 @@ · 40 unmodified lines | ||
| 41 | 41 | */ |
| 42 | 42 | #define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x))) |
| 43 | 43 | #define PCI6208_AO_STATUS 0x00 |
| 44 | −#define PCI6208_AO_STATUS_DATA_SEND (1 << 0) | |
| 44 | +#define PCI6208_AO_STATUS_DATA_SEND BIT(0) | |
| 45 | 45 | #define PCI6208_DIO 0x40 |
| 46 | 46 | #define PCI6208_DIO_DO_MASK (0x0f) |
| 47 | 47 | #define PCI6208_DIO_DO_SHIFT (0) |
| @@ -1,68 +1,52 @@ | ||
| 1 | 1 | /* |
| 2 | − | |
| 3 | −comedi/drivers/adl_pci9111.c | |
| 4 | − | |
| 5 | −Hardware driver for PCI9111 ADLink cards: | |
| 6 | − | |
| 7 | −PCI-9111HR | |
| 8 | − | |
| 9 | −Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> | |
| 10 | − | |
| 11 | −This program is free software; you can redistribute it and/or modify | |
| 12 | −it under the terms of the GNU General Public License as published by | |
| 13 | −the Free Software Foundation; either version 2 of the License, or | |
| 14 | −(at your option) any later version. | |
| 15 | − | |
| 16 | −This program is distributed in the hope that it will be useful, | |
| 17 | −but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 | −MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 19 | −GNU General Public License for more details. | |
| 20 | −*/ | |
| 2 | + * adl_pci9111.c | |
| 3 | + * Hardware driver for PCI9111 ADLink cards: PCI-9111HR | |
| 4 | + * Copyright (C) 2002-2005 Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + */ | |
| 21 | 16 | |
| 22 | 17 | /* |
| 23 | −Driver: adl_pci9111 | |
| 24 | −Description: Adlink PCI-9111HR | |
| 25 | −Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> | |
| 26 | −Devices: [ADLink] PCI-9111HR (adl_pci9111) | |
| 27 | −Status: experimental | |
| 28 | − | |
| 29 | −Supports: | |
| 30 | − | |
| 31 | − - ai_insn read | |
| 32 | − - ao_insn read/write | |
| 33 | − - di_insn read | |
| 34 | − - do_insn read/write | |
| 35 | − - ai_do_cmd mode with the following sources: | |
| 36 | − | |
| 37 | − - start_src TRIG_NOW | |
| 38 | − - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT | |
| 39 | − - convert_src TRIG_TIMER TRIG_EXT | |
| 40 | − - scan_end_src TRIG_COUNT | |
| 41 | − - stop_src TRIG_COUNT TRIG_NONE | |
| 42 | − | |
| 43 | −The scanned channels must be consecutive and start from 0. They must | |
| 44 | −all have the same range and aref. | |
| 45 | − | |
| 46 | −Configuration options: not applicable, uses PCI auto config | |
| 47 | −*/ | |
| 18 | + * Driver: adl_pci9111 | |
| 19 | + * Description: Adlink PCI-9111HR | |
| 20 | + * Devices: [ADLink] PCI-9111HR (adl_pci9111) | |
| 21 | + * Author: Emmanuel Pacaud <emmanuel.pacaud@univ-poitiers.fr> | |
| 22 | + * Status: experimental | |
| 23 | + * | |
| 24 | + * Configuration options: not applicable, uses PCI auto config | |
| 25 | + * | |
| 26 | + * Supports: | |
| 27 | + * - ai_insn read | |
| 28 | + * - ao_insn read/write | |
| 29 | + * - di_insn read | |
| 30 | + * - do_insn read/write | |
| 31 | + * - ai_do_cmd mode with the following sources: | |
| 32 | + * - start_src TRIG_NOW | |
| 33 | + * - scan_begin_src TRIG_FOLLOW TRIG_TIMER TRIG_EXT | |
| 34 | + * - convert_src TRIG_TIMER TRIG_EXT | |
| 35 | + * - scan_end_src TRIG_COUNT | |
| 36 | + * - stop_src TRIG_COUNT TRIG_NONE | |
| 37 | + * | |
| 38 | + * The scanned channels must be consecutive and start from 0. They must | |
| 39 | + * all have the same range and aref. | |
| 40 | + */ | |
| 48 | 41 | |
| 49 | 42 | /* |
| 50 | −CHANGELOG: | |
| 51 | − | |
| 52 | −2005/02/17 Extend AI streaming capabilities. Now, scan_begin_arg can be | |
| 53 | −a multiple of chanlist_len*convert_arg. | |
| 54 | −2002/02/19 Fixed the two's complement conversion in pci9111_(hr_)ai_get_data. | |
| 55 | −2002/02/18 Added external trigger support for analog input. | |
| 56 | − | |
| 57 | −TODO: | |
| 58 | − | |
| 59 | − - Really test implemented functionality. | |
| 60 | − - Add support for the PCI-9111DG with a probe routine to identify | |
| 61 | − the card type (perhaps with the help of the channel number readback | |
| 62 | − of the A/D Data register). | |
| 63 | − - Add external multiplexer support. | |
| 64 | − | |
| 65 | −*/ | |
| 43 | + * TODO: | |
| 44 | + * - Really test implemented functionality. | |
| 45 | + * - Add support for the PCI-9111DG with a probe routine to identify | |
| 46 | + * the card type (perhaps with the help of the channel number readback | |
| 47 | + * of the A/D Data register). | |
| 48 | + * - Add external multiplexer support. | |
| 49 | + */ | |
| 66 | 50 | |
| 67 | 51 | #include <linux/module.h> |
| 68 | 52 | #include <linux/delay.h> |
| @@ -89,23 +73,24 @@ TODO: · 20 unmodified lines | ||
| 89 | 73 | #define PCI9111_EDIO_REG 0x04 |
| 90 | 74 | #define PCI9111_AI_CHANNEL_REG 0x06 |
| 91 | 75 | #define PCI9111_AI_RANGE_STAT_REG 0x08 |
| 92 | −#define PCI9111_AI_STAT_AD_BUSY (1 << 7) | |
| 93 | −#define PCI9111_AI_STAT_FF_FF (1 << 6) | |
| 94 | −#define PCI9111_AI_STAT_FF_HF (1 << 5) | |
| 95 | −#define PCI9111_AI_STAT_FF_EF (1 << 4) | |
| 96 | −#define PCI9111_AI_RANGE_MASK (7 << 0) | |
| 76 | +#define PCI9111_AI_STAT_AD_BUSY BIT(7) | |
| 77 | +#define PCI9111_AI_STAT_FF_FF BIT(6) | |
| 78 | +#define PCI9111_AI_STAT_FF_HF BIT(5) | |
| 79 | +#define PCI9111_AI_STAT_FF_EF BIT(4) | |
| 80 | +#define PCI9111_AI_RANGE(x) (((x) & 0x7) << 0) | |
| 81 | +#define PCI9111_AI_RANGE_MASK PCI9111_AI_RANGE(7) | |
| 97 | 82 | #define PCI9111_AI_TRIG_CTRL_REG 0x0a |
| 98 | −#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5) | |
| 99 | −#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4) | |
| 100 | −#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3) | |
| 101 | −#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2) | |
| 102 | −#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1) | |
| 103 | −#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0) | |
| 83 | +#define PCI9111_AI_TRIG_CTRL_TRGEVENT BIT(5) | |
| 84 | +#define PCI9111_AI_TRIG_CTRL_POTRG BIT(4) | |
| 85 | +#define PCI9111_AI_TRIG_CTRL_PTRG BIT(3) | |
| 86 | +#define PCI9111_AI_TRIG_CTRL_ETIS BIT(2) | |
| 87 | +#define PCI9111_AI_TRIG_CTRL_TPST BIT(1) | |
| 88 | +#define PCI9111_AI_TRIG_CTRL_ASCAN BIT(0) | |
| 104 | 89 | #define PCI9111_INT_CTRL_REG 0x0c |
| 105 | −#define PCI9111_INT_CTRL_ISC2 (1 << 3) | |
| 106 | −#define PCI9111_INT_CTRL_FFEN (1 << 2) | |
| 107 | −#define PCI9111_INT_CTRL_ISC1 (1 << 1) | |
| 108 | −#define PCI9111_INT_CTRL_ISC0 (1 << 0) | |
| 90 | +#define PCI9111_INT_CTRL_ISC2 BIT(3) | |
| 91 | +#define PCI9111_INT_CTRL_FFEN BIT(2) | |
| 92 | +#define PCI9111_INT_CTRL_ISC1 BIT(1) | |
| 93 | +#define PCI9111_INT_CTRL_ISC0 BIT(0) | |
| 109 | 94 | #define PCI9111_SOFT_TRIG_REG 0x0e |
| 110 | 95 | #define PCI9111_8254_BASE_REG 0x40 |
| 111 | 96 | #define PCI9111_INT_CLR_REG 0x48 |
| @@ -139,21 +124,21 @@ struct pci9111_private_data { · 27 unmodified lines | ||
| 139 | 124 | }; |
| 140 | 125 | |
| 141 | 126 | static void plx9050_interrupt_control(unsigned long io_base, |
| 142 | − bool LINTi1_enable, | |
| 143 | − bool LINTi1_active_high, | |
| 144 | − bool LINTi2_enable, | |
| 145 | − bool LINTi2_active_high, | |
| 127 | + bool int1_enable, | |
| 128 | + bool int1_active_high, | |
| 129 | + bool int2_enable, | |
| 130 | + bool int2_active_high, | |
| 146 | 131 | bool interrupt_enable) |
| 147 | 132 | { |
| 148 | 133 | int flags = 0; |
| 149 | 134 | |
| 150 | − if (LINTi1_enable) | |
| 135 | + if (int1_enable) | |
| 151 | 136 | flags |= PLX9052_INTCSR_LI1ENAB; |
| 152 | − if (LINTi1_active_high) | |
| 137 | + if (int1_active_high) | |
| 153 | 138 | flags |= PLX9052_INTCSR_LI1POL; |
| 154 | − if (LINTi2_enable) | |
| 139 | + if (int2_enable) | |
| 155 | 140 | flags |= PLX9052_INTCSR_LI2ENAB; |
| 156 | − if (LINTi2_active_high) | |
| 141 | + if (int2_active_high) | |
| 157 | 142 | flags |= PLX9052_INTCSR_LI2POL; |
| 158 | 143 | |
| 159 | 144 | if (interrupt_enable) |
| @@ -363,6 +348,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, · 203 unmodified lines | ||
| 363 | 348 | struct pci9111_private_data *dev_private = dev->private; |
| 364 | 349 | struct comedi_cmd *cmd = &s->async->cmd; |
| 365 | 350 | unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); |
| 351 | + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); | |
| 366 | 352 | unsigned int trig = 0; |
| 367 | 353 | |
| 368 | 354 | /* Set channel scan limit */ |
| @@ -374,11 +360,8 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, · 5 unmodified lines | ||
| 374 | 360 | |
| 375 | 361 | outb(last_chan, dev->iobase + PCI9111_AI_CHANNEL_REG); |
| 376 | 362 | |
| 377 | − /* Set gain */ | |
| 378 | − /* This is the same gain on every channel */ | |
| 379 | − | |
| 380 | − outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, | |
| 381 | − dev->iobase + PCI9111_AI_RANGE_STAT_REG); | |
| 363 | + /* Set gain - all channels use the same range */ | |
| 364 | + outb(PCI9111_AI_RANGE(range0), dev->iobase + PCI9111_AI_RANGE_STAT_REG); | |
| 382 | 365 | |
| 383 | 366 | /* Set timer pacer */ |
| 384 | 367 | dev_private->scan_delay = 0; |
| @@ -434,14 +417,14 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, · 49 unmodified lines | ||
| 434 | 417 | { |
| 435 | 418 | struct pci9111_private_data *devpriv = dev->private; |
| 436 | 419 | struct comedi_cmd *cmd = &s->async->cmd; |
| 420 | + unsigned short *buf = devpriv->ai_bounce_buffer; | |
| 437 | 421 | unsigned int samples; |
| 438 | 422 | |
| 439 | 423 | samples = comedi_nsamples_left(s, PCI9111_FIFO_HALF_SIZE); |
| 440 | − insw(dev->iobase + PCI9111_AI_FIFO_REG, | |
| 441 | − devpriv->ai_bounce_buffer, samples); | |
| 424 | + insw(dev->iobase + PCI9111_AI_FIFO_REG, buf, samples); | |
| 442 | 425 | |
| 443 | 426 | if (devpriv->scan_delay < 1) { |
| 444 | − comedi_buf_write_samples(s, devpriv->ai_bounce_buffer, samples); | |
| 427 | + comedi_buf_write_samples(s, buf, samples); | |
| 445 | 428 | } else { |
| 446 | 429 | unsigned int pos = 0; |
| 447 | 430 | unsigned int to_read; |
| @@ -454,9 +437,7 @@ static void pci9111_handle_fifo_half_full(struct comedi_device *dev, · 6 unmodified lines | ||
| 454 | 437 | if (to_read > samples - pos) |
| 455 | 438 | to_read = samples - pos; |
| 456 | 439 | |
| 457 | − comedi_buf_write_samples(s, | |
| 458 | − devpriv->ai_bounce_buffer + pos, | |
| 459 | − to_read); | |
| 440 | + comedi_buf_write_samples(s, buf + pos, to_read); | |
| 460 | 441 | } else { |
| 461 | 442 | to_read = devpriv->chunk_num_samples - |
| 462 | 443 | devpriv->chunk_counter; |
| @@ -571,7 +552,7 @@ static int pci9111_ai_insn_read(struct comedi_device *dev, · 108 unmodified lines | ||
| 571 | 552 | |
| 572 | 553 | status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); |
| 573 | 554 | if ((status & PCI9111_AI_RANGE_MASK) != range) { |
| 574 | − outb(range & PCI9111_AI_RANGE_MASK, | |
| 555 | + outb(PCI9111_AI_RANGE(range), | |
| 575 | 556 | dev->iobase + PCI9111_AI_RANGE_STAT_REG); |
| 576 | 557 | } |
| 577 | 558 | |
| @@ -83,12 +83,6 @@ · 82 unmodified lines | ||
| 83 | 83 | #include "amcc_s5933.h" |
| 84 | 84 | #include "comedi_8254.h" |
| 85 | 85 | |
| 86 | −#define IORANGE_9118 64 /* I hope */ | |
| 87 | −#define PCI9118_CHANLEN 255 /* | |
| 88 | − * len of chanlist, some source say 256, | |
| 89 | − * but reality looks like 255 :-( | |
| 90 | − */ | |
| 91 | − | |
| 92 | 86 | /* |
| 93 | 87 | * PCI BAR2 Register map (dev->iobase) |
| 94 | 88 | */ |
| @@ -96,24 +90,24 @@ · 1 unmodified line | ||
| 96 | 90 | #define PCI9118_AI_FIFO_REG 0x10 |
| 97 | 91 | #define PCI9118_AO_REG(x) (0x10 + ((x) * 4)) |
| 98 | 92 | #define PCI9118_AI_STATUS_REG 0x18 |
| 99 | −#define PCI9118_AI_STATUS_NFULL (1 << 8) /* 0=FIFO full (fatal) */ | |
| 100 | −#define PCI9118_AI_STATUS_NHFULL (1 << 7) /* 0=FIFO half full */ | |
| 101 | −#define PCI9118_AI_STATUS_NEPTY (1 << 6) /* 0=FIFO empty */ | |
| 102 | −#define PCI9118_AI_STATUS_ACMP (1 << 5) /* 1=about trigger complete */ | |
| 103 | −#define PCI9118_AI_STATUS_DTH (1 << 4) /* 1=ext. digital trigger */ | |
| 104 | −#define PCI9118_AI_STATUS_BOVER (1 << 3) /* 1=burst overrun (fatal) */ | |
| 105 | −#define PCI9118_AI_STATUS_ADOS (1 << 2) /* 1=A/D over speed (warn) */ | |
| 106 | −#define PCI9118_AI_STATUS_ADOR (1 << 1) /* 1=A/D overrun (fatal) */ | |
| 107 | −#define PCI9118_AI_STATUS_ADRDY (1 << 0) /* 1=A/D ready */ | |
| 93 | +#define PCI9118_AI_STATUS_NFULL BIT(8) /* 0=FIFO full (fatal) */ | |
| 94 | +#define PCI9118_AI_STATUS_NHFULL BIT(7) /* 0=FIFO half full */ | |
| 95 | +#define PCI9118_AI_STATUS_NEPTY BIT(6) /* 0=FIFO empty */ | |
| 96 | +#define PCI9118_AI_STATUS_ACMP BIT(5) /* 1=about trigger complete */ | |
| 97 | +#define PCI9118_AI_STATUS_DTH BIT(4) /* 1=ext. digital trigger */ | |
| 98 | +#define PCI9118_AI_STATUS_BOVER BIT(3) /* 1=burst overrun (fatal) */ | |
| 99 | +#define PCI9118_AI_STATUS_ADOS BIT(2) /* 1=A/D over speed (warn) */ | |
| 100 | +#define PCI9118_AI_STATUS_ADOR BIT(1) /* 1=A/D overrun (fatal) */ | |
| 101 | +#define PCI9118_AI_STATUS_ADRDY BIT(0) /* 1=A/D ready */ | |
| 108 | 102 | #define PCI9118_AI_CTRL_REG 0x18 |
| 109 | −#define PCI9118_AI_CTRL_UNIP (1 << 7) /* 1=unipolar */ | |
| 110 | −#define PCI9118_AI_CTRL_DIFF (1 << 6) /* 1=differential inputs */ | |
| 111 | −#define PCI9118_AI_CTRL_SOFTG (1 << 5) /* 1=8254 software gate */ | |
| 112 | −#define PCI9118_AI_CTRL_EXTG (1 << 4) /* 1=8254 TGIN(pin 46) gate */ | |
| 113 | −#define PCI9118_AI_CTRL_EXTM (1 << 3) /* 1=ext. trigger (pin 44) */ | |
| 114 | −#define PCI9118_AI_CTRL_TMRTR (1 << 2) /* 1=8254 is trigger source */ | |
| 115 | −#define PCI9118_AI_CTRL_INT (1 << 1) /* 1=enable interrupt */ | |
| 116 | −#define PCI9118_AI_CTRL_DMA (1 << 0) /* 1=enable DMA */ | |
| 103 | +#define PCI9118_AI_CTRL_UNIP BIT(7) /* 1=unipolar */ | |
| 104 | +#define PCI9118_AI_CTRL_DIFF BIT(6) /* 1=differential inputs */ | |
| 105 | +#define PCI9118_AI_CTRL_SOFTG BIT(5) /* 1=8254 software gate */ | |
| 106 | +#define PCI9118_AI_CTRL_EXTG BIT(4) /* 1=8254 TGIN(pin 46) gate */ | |
| 107 | +#define PCI9118_AI_CTRL_EXTM BIT(3) /* 1=ext. trigger (pin 44) */ | |
| 108 | +#define PCI9118_AI_CTRL_TMRTR BIT(2) /* 1=8254 is trigger source */ | |
| 109 | +#define PCI9118_AI_CTRL_INT BIT(1) /* 1=enable interrupt */ | |
| 110 | +#define PCI9118_AI_CTRL_DMA BIT(0) /* 1=enable DMA */ | |
| 117 | 111 | #define PCI9118_DIO_REG 0x1c |
| 118 | 112 | #define PCI9118_SOFTTRG_REG 0x20 |
| 119 | 113 | #define PCI9118_AI_CHANLIST_REG 0x24 |
| @@ -122,27 +116,25 @@ · 2 unmodified lines | ||
| 122 | 116 | #define PCI9118_AI_BURST_NUM_REG 0x28 |
| 123 | 117 | #define PCI9118_AI_AUTOSCAN_MODE_REG 0x2c |
| 124 | 118 | #define PCI9118_AI_CFG_REG 0x30 |
| 125 | −#define PCI9118_AI_CFG_PDTRG (1 << 7) /* 1=positive trigger */ | |
| 126 | −#define PCI9118_AI_CFG_PETRG (1 << 6) /* 1=positive ext. trigger */ | |
| 127 | −#define PCI9118_AI_CFG_BSSH (1 << 5) /* 1=with sample & hold */ | |
| 128 | −#define PCI9118_AI_CFG_BM (1 << 4) /* 1=burst mode */ | |
| 129 | −#define PCI9118_AI_CFG_BS (1 << 3) /* 1=burst mode start */ | |
| 130 | −#define PCI9118_AI_CFG_PM (1 << 2) /* 1=post trigger */ | |
| 131 | −#define PCI9118_AI_CFG_AM (1 << 1) /* 1=about trigger */ | |
| 132 | −#define PCI9118_AI_CFG_START (1 << 0) /* 1=trigger start */ | |
| 119 | +#define PCI9118_AI_CFG_PDTRG BIT(7) /* 1=positive trigger */ | |
| 120 | +#define PCI9118_AI_CFG_PETRG BIT(6) /* 1=positive ext. trigger */ | |
| 121 | +#define PCI9118_AI_CFG_BSSH BIT(5) /* 1=with sample & hold */ | |
| 122 | +#define PCI9118_AI_CFG_BM BIT(4) /* 1=burst mode */ | |
| 123 | +#define PCI9118_AI_CFG_BS BIT(3) /* 1=burst mode start */ | |
| 124 | +#define PCI9118_AI_CFG_PM BIT(2) /* 1=post trigger */ | |
| 125 | +#define PCI9118_AI_CFG_AM BIT(1) /* 1=about trigger */ | |
| 126 | +#define PCI9118_AI_CFG_START BIT(0) /* 1=trigger start */ | |
| 133 | 127 | #define PCI9118_FIFO_RESET_REG 0x34 |
| 134 | 128 | #define PCI9118_INT_CTRL_REG 0x38 |
| 135 | −#define PCI9118_INT_CTRL_TIMER (1 << 3) /* timer interrupt */ | |
| 136 | −#define PCI9118_INT_CTRL_ABOUT (1 << 2) /* about trigger complete */ | |
| 137 | −#define PCI9118_INT_CTRL_HFULL (1 << 1) /* A/D FIFO half full */ | |
| 138 | −#define PCI9118_INT_CTRL_DTRG (1 << 0) /* ext. digital trigger */ | |
| 129 | +#define PCI9118_INT_CTRL_TIMER BIT(3) /* timer interrupt */ | |
| 130 | +#define PCI9118_INT_CTRL_ABOUT BIT(2) /* about trigger complete */ | |
| 131 | +#define PCI9118_INT_CTRL_HFULL BIT(1) /* A/D FIFO half full */ | |
| 132 | +#define PCI9118_INT_CTRL_DTRG BIT(0) /* ext. digital trigger */ | |
| 139 | 133 | |
| 140 | 134 | #define START_AI_EXT 0x01 /* start measure on external trigger */ |
| 141 | 135 | #define STOP_AI_EXT 0x02 /* stop measure on external trigger */ |
| 142 | 136 | #define STOP_AI_INT 0x08 /* stop measure on internal trigger */ |
| 143 | 137 | |
| 144 | −#define PCI9118_HALF_FIFO_SZ (1024 / 2) | |
| 145 | − | |
| 146 | 138 | static const struct comedi_lrange pci9118_ai_range = { |
| 147 | 139 | 8, { |
| 148 | 140 | BIP_RANGE(5), |
| @@ -169,11 +161,6 @@ static const struct comedi_lrange pci9118hg_ai_range = { · 20 unmodified lines | ||
| 169 | 161 | } |
| 170 | 162 | }; |
| 171 | 163 | |
| 172 | −#define PCI9118_BIPOLAR_RANGES 4 /* | |
| 173 | − * used for test on mixture | |
| 174 | − * of BIP/UNI ranges | |
| 175 | − */ | |
| 176 | − | |
| 177 | 164 | enum pci9118_boardid { |
| 178 | 165 | BOARD_PCI9118DG, |
| 179 | 166 | BOARD_PCI9118HG, |
| @@ -296,51 +283,44 @@ static void pci9118_ai_reset_fifo(struct comedi_device *dev) · 116 unmodified lines | ||
| 296 | 283 | outl(0, dev->iobase + PCI9118_FIFO_RESET_REG); |
| 297 | 284 | } |
| 298 | 285 | |
| 299 | −static int check_channel_list(struct comedi_device *dev, | |
| 300 | − struct comedi_subdevice *s, int n_chan, | |
| 301 | − unsigned int *chanlist, int frontadd, int backadd) | |
| 286 | +static int pci9118_ai_check_chanlist(struct comedi_device *dev, | |
| 287 | + struct comedi_subdevice *s, | |
| 288 | + struct comedi_cmd *cmd) | |
| 302 | 289 | { |
| 303 | 290 | struct pci9118_private *devpriv = dev->private; |
| 304 | − unsigned int i, differencial = 0, bipolar = 0; | |
| 291 | + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); | |
| 292 | + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); | |
| 293 | + int i; | |
| 305 | 294 | |
| 306 | − /* correct channel and range number check itself comedi/range.c */ | |
| 307 | − if (n_chan < 1) { | |
| 308 | − dev_err(dev->class_dev, "range/channel list is empty!\n"); | |
| 295 | + /* single channel scans are always ok */ | |
| 296 | + if (cmd->chanlist_len == 1) | |
| 309 | 297 | return 0; |
| 310 | − } | |
| 311 | − if ((frontadd + n_chan + backadd) > s->len_chanlist) { | |
| 312 | − dev_err(dev->class_dev, | |
| 313 | − "range/channel list is too long for actual configuration!\n"); | |
| 314 | − return 0; | |
| 315 | − } | |
| 316 | 298 | |
| 317 | − if (CR_AREF(chanlist[0]) == AREF_DIFF) | |
| 318 | − differencial = 1; /* all input must be diff */ | |
| 319 | − if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) | |
| 320 | − bipolar = 1; /* all input must be bipolar */ | |
| 321 | − if (n_chan > 1) | |
| 322 | − for (i = 1; i < n_chan; i++) { /* check S.E/diff */ | |
| 323 | − if ((CR_AREF(chanlist[i]) == AREF_DIFF) != | |
| 324 | − (differencial)) { | |
| 325 | − dev_err(dev->class_dev, | |
| 326 | − "Differential and single ended inputs can't be mixed!\n"); | |
| 327 | − return 0; | |
| 328 | − } | |
| 329 | − if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != | |
| 330 | − (bipolar)) { | |
| 331 | − dev_err(dev->class_dev, | |
| 332 | − "Bipolar and unipolar ranges can't be mixed!\n"); | |
| 333 | − return 0; | |
| 334 | − } | |
| 335 | − if (!devpriv->usemux && differencial && | |
| 336 | − (CR_CHAN(chanlist[i]) >= (s->n_chan / 2))) { | |
| 337 | − dev_err(dev->class_dev, | |
| 338 | − "AREF_DIFF is only available for the first 8 channels!\n"); | |
| 339 | − return 0; | |
| 340 | − } | |
| 299 | + for (i = 1; i < cmd->chanlist_len; i++) { | |
| 300 | + unsigned int chan = CR_CHAN(cmd->chanlist[i]); | |
| 301 | + unsigned int range = CR_RANGE(cmd->chanlist[i]); | |
| 302 | + unsigned int aref = CR_AREF(cmd->chanlist[i]); | |
| 303 | + | |
| 304 | + if (aref != aref0) { | |
| 305 | + dev_err(dev->class_dev, | |
| 306 | + "Differential and single ended inputs can't be mixed!\n"); | |
| 307 | + return -EINVAL; | |
| 308 | + } | |
| 309 | + if (comedi_range_is_bipolar(s, range) != | |
| 310 | + comedi_range_is_bipolar(s, range0)) { | |
| 311 | + dev_err(dev->class_dev, | |
| 312 | + "Bipolar and unipolar ranges can't be mixed!\n"); | |
| 313 | + return -EINVAL; | |
| 341 | 314 | } |
| 315 | + if (!devpriv->usemux && aref == AREF_DIFF && | |
| 316 | + (chan >= (s->n_chan / 2))) { | |
| 317 | + dev_err(dev->class_dev, | |
| 318 | + "AREF_DIFF is only available for the first 8 channels!\n"); | |
| 319 | + return -EINVAL; | |
| 320 | + } | |
| 321 | + } | |
| 342 | 322 | |
| 343 | − return 1; | |
| 323 | + return 0; | |
| 344 | 324 | } |
| 345 | 325 | |
| 346 | 326 | static void pci9118_set_chanlist(struct comedi_device *dev, |
| @@ -406,8 +386,8 @@ static void pci9118_set_chanlist(struct comedi_device *dev, · 59 unmodified lines | ||
| 406 | 386 | /* udelay(100); important delay, or first sample will be crippled */ |
| 407 | 387 | } |
| 408 | 388 | |
| 409 | −static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, | |
| 410 | − unsigned int next_buf) | |
| 389 | +static void pci9118_ai_mode4_switch(struct comedi_device *dev, | |
| 390 | + unsigned int next_buf) | |
| 411 | 391 | { |
| 412 | 392 | struct pci9118_private *devpriv = dev->private; |
| 413 | 393 | struct pci9118_dmabuf *dmabuf = &devpriv->dmabuf[next_buf]; |
| @@ -421,9 +401,9 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev, · 7 unmodified lines | ||
| 421 | 401 | outl(devpriv->ai_cfg, dev->iobase + PCI9118_AI_CFG_REG); |
| 422 | 402 | } |
| 423 | 403 | |
| 424 | −static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev, | |
| 425 | − struct comedi_subdevice *s, | |
| 426 | − unsigned int n_raw_samples) | |
| 404 | +static unsigned int pci9118_ai_samples_ready(struct comedi_device *dev, | |
| 405 | + struct comedi_subdevice *s, | |
| 406 | + unsigned int n_raw_samples) | |
| 427 | 407 | { |
| 428 | 408 | struct pci9118_private *devpriv = dev->private; |
| 429 | 409 | struct comedi_cmd *cmd = &s->async->cmd; |
| @@ -477,7 +457,7 @@ static unsigned int valid_samples_in_act_dma_buf(struct comedi_device *dev, · 47 unmodified lines | ||
| 477 | 457 | return n_samples; |
| 478 | 458 | } |
| 479 | 459 | |
| 480 | −static void move_block_from_dma(struct comedi_device *dev, | |
| 460 | +static void pci9118_ai_dma_xfer(struct comedi_device *dev, | |
| 481 | 461 | struct comedi_subdevice *s, |
| 482 | 462 | unsigned short *dma_buffer, |
| 483 | 463 | unsigned int n_raw_samples) |
| @@ -634,8 +614,8 @@ static void pci9118_ai_munge(struct comedi_device *dev, · 150 unmodified lines | ||
| 634 | 614 | } |
| 635 | 615 | } |
| 636 | 616 | |
| 637 | −static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, | |
| 638 | − struct comedi_subdevice *s) | |
| 617 | +static void pci9118_ai_get_onesample(struct comedi_device *dev, | |
| 618 | + struct comedi_subdevice *s) | |
| 639 | 619 | { |
| 640 | 620 | struct pci9118_private *devpriv = dev->private; |
| 641 | 621 | struct comedi_cmd *cmd = &s->async->cmd; |
| @@ -651,8 +631,8 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, · 9 unmodified lines | ||
| 651 | 631 | } |
| 652 | 632 | } |
| 653 | 633 | |
| 654 | −static void interrupt_pci9118_ai_dma(struct comedi_device *dev, | |
| 655 | − struct comedi_subdevice *s) | |
| 634 | +static void pci9118_ai_get_dma(struct comedi_device *dev, | |
| 635 | + struct comedi_subdevice *s) | |
| 656 | 636 | { |
| 657 | 637 | struct pci9118_private *devpriv = dev->private; |
| 658 | 638 | struct comedi_cmd *cmd = &s->async->cmd; |
| @@ -662,21 +642,19 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, · 3 unmodified lines | ||
| 662 | 642 | bool more_dma; |
| 663 | 643 | |
| 664 | 644 | /* determine whether more DMA buffers to do after this one */ |
| 665 | − n_valid = valid_samples_in_act_dma_buf(dev, s, n_all); | |
| 645 | + n_valid = pci9118_ai_samples_ready(dev, s, n_all); | |
| 666 | 646 | more_dma = n_valid < comedi_nsamples_left(s, n_valid + 1); |
| 667 | 647 | |
| 668 | 648 | /* switch DMA buffers and restart DMA if double buffering */ |
| 669 | 649 | if (more_dma && devpriv->dma_doublebuf) { |
| 670 | 650 | devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; |
| 671 | 651 | pci9118_amcc_setup_dma(dev, devpriv->dma_actbuf); |
| 672 | − if (devpriv->ai_do == 4) { | |
| 673 | − interrupt_pci9118_ai_mode4_switch(dev, | |
| 674 | − devpriv->dma_actbuf); | |
| 675 | − } | |
| 652 | + if (devpriv->ai_do == 4) | |
| 653 | + pci9118_ai_mode4_switch(dev, devpriv->dma_actbuf); | |
| 676 | 654 | } |
| 677 | 655 | |
| 678 | 656 | if (n_all) |
| 679 | − move_block_from_dma(dev, s, dmabuf->virt, n_all); | |
| 657 | + pci9118_ai_dma_xfer(dev, s, dmabuf->virt, n_all); | |
| 680 | 658 | |
| 681 | 659 | if (!devpriv->ai_neverending) { |
| 682 | 660 | if (s->async->scans_done >= cmd->stop_arg) |
| @@ -690,7 +668,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, · 7 unmodified lines | ||
| 690 | 668 | if (more_dma && !devpriv->dma_doublebuf) { |
| 691 | 669 | pci9118_amcc_setup_dma(dev, 0); |
| 692 | 670 | if (devpriv->ai_do == 4) |
| 693 | − interrupt_pci9118_ai_mode4_switch(dev, 0); | |
| 671 | + pci9118_ai_mode4_switch(dev, 0); | |
| 694 | 672 | } |
| 695 | 673 | } |
| 696 | 674 | |
| @@ -779,9 +757,9 @@ static irqreturn_t pci9118_interrupt(int irq, void *d) · 82 unmodified lines | ||
| 779 | 757 | } |
| 780 | 758 | |
| 781 | 759 | if (devpriv->usedma) |
| 782 | − interrupt_pci9118_ai_dma(dev, s); | |
| 760 | + pci9118_ai_get_dma(dev, s); | |
| 783 | 761 | else |
| 784 | − interrupt_pci9118_ai_onesample(dev, s); | |
| 762 | + pci9118_ai_get_onesample(dev, s); | |
| 785 | 763 | |
| 786 | 764 | interrupt_exit: |
| 787 | 765 | comedi_handle_events(dev, s); |
| @@ -816,17 +794,18 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, · 28 unmodified lines | ||
| 816 | 794 | return 1; |
| 817 | 795 | } |
| 818 | 796 | |
| 819 | −static int Compute_and_setup_dma(struct comedi_device *dev, | |
| 820 | − struct comedi_subdevice *s) | |
| 797 | +static int pci9118_ai_setup_dma(struct comedi_device *dev, | |
| 798 | + struct comedi_subdevice *s) | |
| 821 | 799 | { |
| 822 | 800 | struct pci9118_private *devpriv = dev->private; |
| 823 | 801 | struct comedi_cmd *cmd = &s->async->cmd; |
| 824 | 802 | struct pci9118_dmabuf *dmabuf0 = &devpriv->dmabuf[0]; |
| 825 | 803 | struct pci9118_dmabuf *dmabuf1 = &devpriv->dmabuf[1]; |
| 826 | − unsigned int dmalen0, dmalen1, i; | |
| 804 | + unsigned int dmalen0 = dmabuf0->size; | |
| 805 | + unsigned int dmalen1 = dmabuf1->size; | |
| 806 | + unsigned int scan_bytes = devpriv->ai_n_realscanlen * | |
| 807 | + comedi_bytes_per_sample(s); | |
| 827 | 808 | |
| 828 | − dmalen0 = dmabuf0->size; | |
| 829 | − dmalen1 = dmabuf1->size; | |
| 830 | 809 | /* isn't output buff smaller that our DMA buff? */ |
| 831 | 810 | if (dmalen0 > s->async->prealloc_bufsz) { |
| 832 | 811 | /* align to 32bit down */ |
| @@ -839,15 +818,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev, · 6 unmodified lines | ||
| 839 | 818 | |
| 840 | 819 | /* we want wake up every scan? */ |
| 841 | 820 | if (devpriv->ai_flags & CMDF_WAKE_EOS) { |
| 842 | − if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { | |
| 821 | + if (dmalen0 < scan_bytes) { | |
| 843 | 822 | /* uff, too short DMA buffer, disable EOS support! */ |
| 844 | 823 | devpriv->ai_flags &= (~CMDF_WAKE_EOS); |
| 845 | 824 | dev_info(dev->class_dev, |
| 846 | 825 | "WAR: DMA0 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", |
| 847 | − dmalen0, devpriv->ai_n_realscanlen << 1); | |
| 826 | + dmalen0, scan_bytes); | |
| 848 | 827 | } else { |
| 849 | 828 | /* short first DMA buffer to one scan */ |
| 850 | − dmalen0 = devpriv->ai_n_realscanlen << 1; | |
| 829 | + dmalen0 = scan_bytes; | |
| 851 | 830 | if (dmalen0 < 4) { |
| 852 | 831 | dev_info(dev->class_dev, |
| 853 | 832 | "ERR: DMA0 buf len bug? (%d<4)\n", |
| @@ -857,15 +836,15 @@ static int Compute_and_setup_dma(struct comedi_device *dev, · 3 unmodified lines | ||
| 857 | 836 | } |
| 858 | 837 | } |
| 859 | 838 | if (devpriv->ai_flags & CMDF_WAKE_EOS) { |
| 860 | − if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { | |
| 839 | + if (dmalen1 < scan_bytes) { | |
| 861 | 840 | /* uff, too short DMA buffer, disable EOS support! */ |
| 862 | 841 | devpriv->ai_flags &= (~CMDF_WAKE_EOS); |
| 863 | 842 | dev_info(dev->class_dev, |
| 864 | 843 | "WAR: DMA1 buf too short, can't support CMDF_WAKE_EOS (%d<%d)\n", |
| 865 | − dmalen1, devpriv->ai_n_realscanlen << 1); | |
| 844 | + dmalen1, scan_bytes); | |
| 866 | 845 | } else { |
| 867 | 846 | /* short second DMA buffer to one scan */ |
| 868 | − dmalen1 = devpriv->ai_n_realscanlen << 1; | |
| 847 | + dmalen1 = scan_bytes; | |
| 869 | 848 | if (dmalen1 < 4) { |
| 870 | 849 | dev_info(dev->class_dev, |
| 871 | 850 | "ERR: DMA1 buf len bug? (%d<4)\n", |
| @@ -877,45 +856,39 @@ static int Compute_and_setup_dma(struct comedi_device *dev, · 5 unmodified lines | ||
| 877 | 856 | |
| 878 | 857 | /* transfer without CMDF_WAKE_EOS */ |
| 879 | 858 | if (!(devpriv->ai_flags & CMDF_WAKE_EOS)) { |
| 859 | + unsigned int tmp; | |
| 860 | + | |
| 880 | 861 | /* if it's possible then align DMA buffers to length of scan */ |
| 881 | − i = dmalen0; | |
| 882 | − dmalen0 = | |
| 883 | − (dmalen0 / (devpriv->ai_n_realscanlen << 1)) * | |
| 884 | − (devpriv->ai_n_realscanlen << 1); | |
| 862 | + tmp = dmalen0; | |
| 863 | + dmalen0 = (dmalen0 / scan_bytes) * scan_bytes; | |
| 885 | 864 | dmalen0 &= ~3L; |
| 886 | 865 | if (!dmalen0) |
| 887 | − dmalen0 = i; /* uff. very long scan? */ | |
| 888 | − i = dmalen1; | |
| 889 | − dmalen1 = | |
| 890 | − (dmalen1 / (devpriv->ai_n_realscanlen << 1)) * | |
| 891 | − (devpriv->ai_n_realscanlen << 1); | |
| 866 | + dmalen0 = tmp; /* uff. very long scan? */ | |
| 867 | + tmp = dmalen1; | |
| 868 | + dmalen1 = (dmalen1 / scan_bytes) * scan_bytes; | |
| 892 | 869 | dmalen1 &= ~3L; |
| 893 | 870 | if (!dmalen1) |
| 894 | − dmalen1 = i; /* uff. very long scan? */ | |
| 871 | + dmalen1 = tmp; /* uff. very long scan? */ | |
| 895 | 872 | /* |
| 896 | 873 | * if measure isn't neverending then test, if it fits whole |
| 897 | 874 | * into one or two DMA buffers |
| 898 | 875 | */ |
| 899 | 876 | if (!devpriv->ai_neverending) { |
| 877 | + unsigned long long scanlen; | |
| 878 | + | |
| 879 | + scanlen = (unsigned long long)scan_bytes * | |
| 880 | + cmd->stop_arg; | |
| 881 | + | |
| 900 | 882 | /* fits whole measure into one DMA buffer? */ |
| 901 | − if (dmalen0 > | |
| 902 | − ((devpriv->ai_n_realscanlen << 1) * | |
| 903 | − cmd->stop_arg)) { | |
| 904 | − dmalen0 = | |
| 905 | − (devpriv->ai_n_realscanlen << 1) * | |
| 906 | − cmd->stop_arg; | |
| 883 | + if (dmalen0 > scanlen) { | |
| 884 | + dmalen0 = scanlen; | |
| 907 | 885 | dmalen0 &= ~3L; |
| 908 | − } else { /* | |
| 909 | − * fits whole measure into | |
| 910 | − * two DMA buffer? | |
| 911 | − */ | |
| 912 | − if (dmalen1 > | |
| 913 | − ((devpriv->ai_n_realscanlen << 1) * | |
| 914 | − cmd->stop_arg - dmalen0)) | |
| 915 | − dmalen1 = | |
| 916 | − (devpriv->ai_n_realscanlen << 1) * | |
| 917 | − cmd->stop_arg - dmalen0; | |
| 918 | − dmalen1 &= ~3L; | |
| 886 | + } else { | |
| 887 | + /* fits whole measure into two DMA buffer? */ | |
| 888 | + if (dmalen1 > (scanlen - dmalen0)) { | |
| 889 | + dmalen1 = scanlen - dmalen0; | |
| 890 | + dmalen1 &= ~3L; | |
| 891 | + } | |
| 919 | 892 | } |
| 920 | 893 | } |
| 921 | 894 | } |
| @@ -945,6 +918,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) · 23 unmodified lines | ||
| 945 | 918 | struct comedi_8254 *pacer = dev->pacer; |
| 946 | 919 | struct comedi_cmd *cmd = &s->async->cmd; |
| 947 | 920 | unsigned int addchans = 0; |
| 921 | + unsigned int scanlen; | |
| 948 | 922 | |
| 949 | 923 | devpriv->ai12_startstop = 0; |
| 950 | 924 | devpriv->ai_flags = cmd->flags; |
| @@ -1030,19 +1004,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) · 79 unmodified lines | ||
| 1030 | 1004 | } |
| 1031 | 1005 | } |
| 1032 | 1006 | /* well, we now know what must be all added */ |
| 1033 | − devpriv->ai_n_realscanlen = /* | |
| 1034 | − * what we must take from card in real | |
| 1035 | − * to have cmd->scan_end_arg on output? | |
| 1036 | − */ | |
| 1037 | − (devpriv->ai_add_front + cmd->chanlist_len + | |
| 1038 | − devpriv->ai_add_back) * (cmd->scan_end_arg / | |
| 1039 | − cmd->chanlist_len); | |
| 1040 | − | |
| 1041 | − /* check and setup channel list */ | |
| 1042 | − if (!check_channel_list(dev, s, cmd->chanlist_len, | |
| 1043 | − cmd->chanlist, devpriv->ai_add_front, | |
| 1044 | − devpriv->ai_add_back)) | |
| 1007 | + scanlen = devpriv->ai_add_front + cmd->chanlist_len + | |
| 1008 | + devpriv->ai_add_back; | |
| 1009 | + /* | |
| 1010 | + * what we must take from card in real to have cmd->scan_end_arg | |
| 1011 | + * on output? | |
| 1012 | + */ | |
| 1013 | + devpriv->ai_n_realscanlen = scanlen * | |
| 1014 | + (cmd->scan_end_arg / cmd->chanlist_len); | |
| 1015 | + | |
| 1016 | + if (scanlen > s->len_chanlist) { | |
| 1017 | + dev_err(dev->class_dev, | |
| 1018 | + "range/channel list is too long for actual configuration!\n"); | |
| 1045 | 1019 | return -EINVAL; |
| 1020 | + } | |
| 1046 | 1021 | |
| 1047 | 1022 | /* |
| 1048 | 1023 | * Configure analog input and load the chanlist. |
| @@ -1141,7 +1116,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) · 92 unmodified lines | ||
| 1141 | 1116 | devpriv->ai_act_dmapos = 0; |
| 1142 | 1117 | |
| 1143 | 1118 | if (devpriv->usedma) { |
| 1144 | − Compute_and_setup_dma(dev, s); | |
| 1119 | + pci9118_ai_setup_dma(dev, s); | |
| 1145 | 1120 | |
| 1146 | 1121 | outl(0x02000000 | AINT_WRITE_COMPL, |
| 1147 | 1122 | devpriv->iobase_a + AMCC_OP_REG_INTCSR); |
| @@ -1205,9 +1180,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, · 57 unmodified lines | ||
| 1205 | 1180 | if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) |
| 1206 | 1181 | err |= -EINVAL; |
| 1207 | 1182 | |
| 1208 | − if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) | |
| 1209 | − err |= -EINVAL; | |
| 1210 | − | |
| 1211 | 1183 | if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) && |
| 1212 | 1184 | (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) |
| 1213 | 1185 | err |= -EINVAL; |
| @@ -1315,10 +1287,13 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, · 101 unmodified lines | ||
| 1315 | 1287 | if (err) |
| 1316 | 1288 | return 4; |
| 1317 | 1289 | |
| 1290 | + /* Step 5: check channel list if it exists */ | |
| 1291 | + | |
| 1318 | 1292 | if (cmd->chanlist) |
| 1319 | − if (!check_channel_list(dev, s, cmd->chanlist_len, | |
| 1320 | − cmd->chanlist, 0, 0)) | |
| 1321 | − return 5; /* incorrect channels list */ | |
| 1293 | + err |= pci9118_ai_check_chanlist(dev, s, cmd); | |
| 1294 | + | |
| 1295 | + if (err) | |
| 1296 | + return 5; | |
| 1322 | 1297 | |
| 1323 | 1298 | return 0; |
| 1324 | 1299 | } |
| @@ -1608,7 +1583,7 @@ static int pci9118_common_attach(struct comedi_device *dev, · 283 unmodified lines | ||
| 1608 | 1583 | if (dev->irq) { |
| 1609 | 1584 | dev->read_subdev = s; |
| 1610 | 1585 | s->subdev_flags |= SDF_CMD_READ; |
| 1611 | − s->len_chanlist = PCI9118_CHANLEN; | |
| 1586 | + s->len_chanlist = 255; | |
| 1612 | 1587 | s->do_cmdtest = pci9118_ai_cmdtest; |
| 1613 | 1588 | s->do_cmd = pci9118_ai_cmd; |
| 1614 | 1589 | s->cancel = pci9118_ai_cancel; |
| @@ -1,75 +1,59 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/adq12b.c | |
| 3 | − driver for MicroAxial ADQ12-B data acquisition and control card | |
| 4 | − | |
| 5 | − COMEDI - Linux Control and Measurement Device Interface | |
| 6 | − Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
| 7 | − | |
| 8 | − This program is free software; you can redistribute it and/or modify | |
| 9 | − it under the terms of the GNU General Public License as published by | |
| 10 | − the Free Software Foundation; either version 2 of the License, or | |
| 11 | − (at your option) any later version. | |
| 12 | − | |
| 13 | − This program is distributed in the hope that it will be useful, | |
| 14 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | − GNU General Public License for more details. | |
| 17 | −*/ | |
| 18 | −/* | |
| 19 | −Driver: adq12b | |
| 20 | −Description: driver for MicroAxial ADQ12-B data acquisition and control card | |
| 21 | −Devices: [MicroAxial] ADQ12-B (adq12b) | |
| 22 | −Author: jeremy theler <thelerg@ib.cnea.gov.ar> | |
| 23 | −Updated: Thu, 21 Feb 2008 02:56:27 -0300 | |
| 24 | −Status: works | |
| 25 | − | |
| 26 | −Driver for the acquisition card ADQ12-B (without any add-on). | |
| 27 | − | |
| 28 | − - Analog input is subdevice 0 (16 channels single-ended or 8 differential) | |
| 29 | − - Digital input is subdevice 1 (5 channels) | |
| 30 | − - Digital output is subdevice 1 (8 channels) | |
| 31 | − - The PACER is not supported in this version | |
| 32 | − | |
| 33 | −If you do not specify any options, they will default to | |
| 34 | − | |
| 35 | − # comedi_config /dev/comedi0 adq12b 0x300,0,0 | |
| 36 | − | |
| 37 | − option 1: I/O base address. The following table is provided as a help | |
| 38 | − of the hardware jumpers. | |
| 39 | − | |
| 40 | − address jumper JADR | |
| 41 | − 0x300 1 (factory default) | |
| 42 | − 0x320 2 | |
| 43 | − 0x340 3 | |
| 44 | − 0x360 4 | |
| 45 | − 0x380 5 | |
| 46 | − 0x3A0 6 | |
| 47 | − | |
| 48 | − option 2: unipolar/bipolar ADC selection: 0 -> bipolar, 1 -> unipolar | |
| 2 | + * adq12b.c | |
| 3 | + * Driver for MicroAxial ADQ12-B data acquisition and control card | |
| 4 | + * written by jeremy theler <thelerg@ib.cnea.gov.ar> | |
| 5 | + * instituto balseiro | |
| 6 | + * commission nacional de energia atomica | |
| 7 | + * universidad nacional de cuyo | |
| 8 | + * argentina | |
| 9 | + * | |
| 10 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 11 | + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
| 12 | + * | |
| 13 | + * This program is free software; you can redistribute it and/or modify | |
| 14 | + * it under the terms of the GNU General Public License as published by | |
| 15 | + * the Free Software Foundation; either version 2 of the License, or | |
| 16 | + * (at your option) any later version. | |
| 17 | + * | |
| 18 | + * This program is distributed in the hope that it will be useful, | |
| 19 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 20 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 21 | + * GNU General Public License for more details. | |
| 22 | + */ | |
| 49 | 23 | |
| 50 | − selection comedi_config option JUB | |
| 51 | − bipolar 0 2-3 (factory default) | |
| 52 | − unipolar 1 1-2 | |
| 53 | − | |
| 54 | − option 3: single-ended/differential AI selection: 0 -> SE, 1 -> differential | |
| 55 | − | |
| 56 | − selection comedi_config option JCHA JCHB | |
| 57 | − single-ended 0 1-2 1-2 (factory default) | |
| 58 | − differential 1 2-3 2-3 | |
| 59 | − | |
| 60 | − written by jeremy theler <thelerg@ib.cnea.gov.ar> | |
| 61 | − | |
| 62 | − instituto balseiro | |
| 63 | − commission nacional de energia atomica | |
| 64 | − universidad nacional de cuyo | |
| 65 | − argentina | |
| 66 | − | |
| 67 | − 21-feb-2008 | |
| 68 | − + changed supported devices string (missused the [] and ()) | |
| 69 | − | |
| 70 | − 13-oct-2007 | |
| 71 | − + first try | |
| 72 | −*/ | |
| 24 | +/* | |
| 25 | + * Driver: adq12b | |
| 26 | + * Description: Driver for MicroAxial ADQ12-B data acquisition and control card | |
| 27 | + * Devices: [MicroAxial] ADQ12-B (adq12b) | |
| 28 | + * Author: jeremy theler <thelerg@ib.cnea.gov.ar> | |
| 29 | + * Updated: Thu, 21 Feb 2008 02:56:27 -0300 | |
| 30 | + * Status: works | |
| 31 | + * | |
| 32 | + * Configuration options: | |
| 33 | + * [0] - I/O base address (set with hardware jumpers) | |
| 34 | + * address jumper JADR | |
| 35 | + * 0x300 1 (factory default) | |
| 36 | + * 0x320 2 | |
| 37 | + * 0x340 3 | |
| 38 | + * 0x360 4 | |
| 39 | + * 0x380 5 | |
| 40 | + * 0x3A0 6 | |
| 41 | + * [1] - Analog Input unipolar/bipolar selection | |
| 42 | + * selection option JUB | |
| 43 | + * bipolar 0 2-3 (factory default) | |
| 44 | + * unipolar 1 1-2 | |
| 45 | + * [2] - Analog Input single-ended/differential selection | |
| 46 | + * selection option JCHA JCHB | |
| 47 | + * single-ended 0 1-2 1-2 (factory default) | |
| 48 | + * differential 1 2-3 2-3 | |
| 49 | + * | |
| 50 | + * Driver for the acquisition card ADQ12-B (without any add-on). | |
| 51 | + * | |
| 52 | + * - Analog input is subdevice 0 (16 channels single-ended or 8 differential) | |
| 53 | + * - Digital input is subdevice 1 (5 channels) | |
| 54 | + * - Digital output is subdevice 1 (8 channels) | |
| 55 | + * - The PACER is not supported in this version | |
| 56 | + */ | |
| 73 | 57 | |
| 74 | 58 | #include <linux/module.h> |
| 75 | 59 | #include <linux/delay.h> |
| @@ -78,14 +62,14 @@ If you do not specify any options, they will default to · 2 unmodified lines | ||
| 78 | 62 | |
| 79 | 63 | /* address scheme (page 2.17 of the manual) */ |
| 80 | 64 | #define ADQ12B_CTREG 0x00 |
| 81 | −#define ADQ12B_CTREG_MSKP (1 << 7) /* enable pacer interrupt */ | |
| 82 | −#define ADQ12B_CTREG_GTP (1 << 6) /* enable pacer */ | |
| 65 | +#define ADQ12B_CTREG_MSKP BIT(7) /* enable pacer interrupt */ | |
| 66 | +#define ADQ12B_CTREG_GTP BIT(6) /* enable pacer */ | |
| 83 | 67 | #define ADQ12B_CTREG_RANGE(x) ((x) << 4) |
| 84 | 68 | #define ADQ12B_CTREG_CHAN(x) ((x) << 0) |
| 85 | 69 | #define ADQ12B_STINR 0x00 |
| 86 | −#define ADQ12B_STINR_OUT2 (1 << 7) /* timer 2 output state */ | |
| 87 | −#define ADQ12B_STINR_OUTP (1 << 6) /* pacer output state */ | |
| 88 | −#define ADQ12B_STINR_EOC (1 << 5) /* A/D end-of-conversion */ | |
| 70 | +#define ADQ12B_STINR_OUT2 BIT(7) /* timer 2 output state */ | |
| 71 | +#define ADQ12B_STINR_OUTP BIT(6) /* pacer output state */ | |
| 72 | +#define ADQ12B_STINR_EOC BIT(5) /* A/D end-of-conversion */ | |
| 89 | 73 | #define ADQ12B_STINR_IN_MASK (0x1f << 0) |
| 90 | 74 | #define ADQ12B_OUTBR 0x04 |
| 91 | 75 | #define ADQ12B_ADLOW 0x08 |
| @@ -145,7 +129,7 @@ static int adq12b_ai_insn_read(struct comedi_device *dev, · 53 unmodified lines | ||
| 145 | 129 | if (val != devpriv->last_ctreg) { |
| 146 | 130 | outb(val, dev->iobase + ADQ12B_CTREG); |
| 147 | 131 | devpriv->last_ctreg = val; |
| 148 | − udelay(50); /* wait for the mux to settle */ | |
| 132 | + usleep_range(50, 100); /* wait for the mux to settle */ | |
| 149 | 133 | } |
| 150 | 134 | |
| 151 | 135 | val = inb(dev->iobase + ADQ12B_ADLOW); /* trigger A/D */ |
| @@ -1,45 +1,30 @@ | ||
| 1 | 1 | /* |
| 2 | − * comedi/drivers/adv_pci1710.c | |
| 3 | − * | |
| 2 | + * adv_pci1710.c | |
| 3 | + * Comedi driver for Advantech PCI-1710 series boards | |
| 4 | 4 | * Author: Michal Dobes <dobes@tesnet.cz> |
| 5 | 5 | * |
| 6 | 6 | * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn> |
| 7 | 7 | * for testing and information. |
| 8 | + */ | |
| 9 | + | |
| 10 | +/* | |
| 11 | + * Driver: adv_pci1710 | |
| 12 | + * Description: Comedi driver for Advantech PCI-1710 series boards | |
| 13 | + * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711, | |
| 14 | + * PCI-1713, PCI-1720, PCI-1731 | |
| 15 | + * Author: Michal Dobes <dobes@tesnet.cz> | |
| 16 | + * Status: works | |
| 8 | 17 | * |
| 9 | − * hardware driver for Advantech cards: | |
| 10 | − * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731 | |
| 11 | − * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731 | |
| 18 | + * Configuration options: not applicable, uses PCI auto config | |
| 12 | 19 | * |
| 13 | − * Options: | |
| 14 | − * [0] - PCI bus number - if bus number and slot number are 0, | |
| 15 | − * then driver search for first unused card | |
| 16 | − * [1] - PCI slot number | |
| 20 | + * This driver supports AI, AO, DI and DO subdevices. | |
| 21 | + * AI subdevice supports cmd and insn interface, | |
| 22 | + * other subdevices support only insn interface. | |
| 17 | 23 | * |
| 18 | −*/ | |
| 19 | −/* | |
| 20 | −Driver: adv_pci1710 | |
| 21 | −Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, | |
| 22 | − Advantech PCI-1720, PCI-1731 | |
| 23 | −Author: Michal Dobes <dobes@tesnet.cz> | |
| 24 | −Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg), | |
| 25 | − PCI-1711 (adv_pci1710), PCI-1713, PCI-1720, | |
| 26 | − PCI-1731 | |
| 27 | −Status: works | |
| 28 | − | |
| 29 | −This driver supports AI, AO, DI and DO subdevices. | |
| 30 | −AI subdevice supports cmd and insn interface, | |
| 31 | −other subdevices support only insn interface. | |
| 32 | − | |
| 33 | −The PCI-1710 and PCI-1710HG have the same PCI device ID, so the | |
| 34 | −driver cannot distinguish between them, as would be normal for a | |
| 35 | −PCI driver. | |
| 36 | − | |
| 37 | −Configuration options: | |
| 38 | − [0] - PCI bus of device (optional) | |
| 39 | − [1] - PCI slot of device (optional) | |
| 40 | − If bus/slot is not specified, the first available PCI | |
| 41 | − device will be used. | |
| 42 | −*/ | |
| 24 | + * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the | |
| 25 | + * driver cannot distinguish between them, as would be normal for a | |
| 26 | + * PCI driver. | |
| 27 | + */ | |
| 43 | 28 | |
| 44 | 29 | #include <linux/module.h> |
| 45 | 30 | #include <linux/interrupt.h> |
| @@ -49,48 +34,43 @@ Configuration options: · 3 unmodified lines | ||
| 49 | 34 | #include "comedi_8254.h" |
| 50 | 35 | #include "amcc_s5933.h" |
| 51 | 36 | |
| 52 | −#define PCI171x_AD_DATA 0 /* R: A/D data */ | |
| 53 | −#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ | |
| 54 | −#define PCI171x_RANGE 2 /* W: A/D gain/range register */ | |
| 55 | −#define PCI171x_MUX 4 /* W: A/D multiplexor control */ | |
| 56 | −#define PCI171x_STATUS 6 /* R: status register */ | |
| 57 | −#define PCI171x_CONTROL 6 /* W: control register */ | |
| 58 | −#define PCI171x_CLRINT 8 /* W: clear interrupts request */ | |
| 59 | −#define PCI171x_CLRFIFO 9 /* W: clear FIFO */ | |
| 60 | −#define PCI171x_DA1 10 /* W: D/A register */ | |
| 61 | −#define PCI171x_DA2 12 /* W: D/A register */ | |
| 62 | −#define PCI171x_DAREF 14 /* W: D/A reference control */ | |
| 63 | −#define PCI171x_DI 16 /* R: digi inputs */ | |
| 64 | −#define PCI171x_DO 16 /* R: digi inputs */ | |
| 65 | − | |
| 66 | −#define PCI171X_TIMER_BASE 0x18 | |
| 67 | − | |
| 68 | −/* upper bits from status register (PCI171x_STATUS) (lower is same with control | |
| 69 | − * reg) */ | |
| 70 | −#define Status_FE 0x0100 /* 1=FIFO is empty */ | |
| 71 | −#define Status_FH 0x0200 /* 1=FIFO is half full */ | |
| 72 | −#define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ | |
| 73 | −#define Status_IRQ 0x0800 /* 1=IRQ occurred */ | |
| 74 | −/* bits from control register (PCI171x_CONTROL) */ | |
| 75 | −#define Control_CNT0 0x0040 /* 1=CNT0 have external source, | |
| 76 | − * 0=have internal 100kHz source */ | |
| 77 | −#define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */ | |
| 78 | −#define Control_IRQEN 0x0010 /* 1=enable IRQ */ | |
| 79 | −#define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */ | |
| 80 | −#define Control_EXT 0x0004 /* 1=external trigger source */ | |
| 81 | −#define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */ | |
| 82 | −#define Control_SW 0x0001 /* 1=enable software trigger source */ | |
| 83 | − | |
| 84 | −#define PCI1720_DA0 0 /* W: D/A register 0 */ | |
| 85 | −#define PCI1720_DA1 2 /* W: D/A register 1 */ | |
| 86 | −#define PCI1720_DA2 4 /* W: D/A register 2 */ | |
| 87 | −#define PCI1720_DA3 6 /* W: D/A register 3 */ | |
| 88 | −#define PCI1720_RANGE 8 /* R/W: D/A range register */ | |
| 89 | −#define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */ | |
| 90 | −#define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */ | |
| 91 | − | |
| 92 | −/* D/A synchronized control (PCI1720_SYNCONT) */ | |
| 93 | −#define Syncont_SC0 1 /* set synchronous output mode */ | |
| 37 | +/* | |
| 38 | + * PCI BAR2 Register map (dev->iobase) | |
| 39 | + */ | |
| 40 | +#define PCI171X_AD_DATA_REG 0x00 /* R: A/D data */ | |
| 41 | +#define PCI171X_SOFTTRG_REG 0x00 /* W: soft trigger for A/D */ | |
| 42 | +#define PCI171X_RANGE_REG 0x02 /* W: A/D gain/range register */ | |
| 43 | +#define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */ | |
| 44 | +#define PCI171X_STATUS_REG 0x06 /* R: status register */ | |
| 45 | +#define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */ | |
| 46 | +#define PCI171X_STATUS_FF BIT(10) /* 1=FIFO is full, fatal error */ | |
| 47 | +#define PCI171X_STATUS_FH BIT(9) /* 1=FIFO is half full */ | |
| 48 | +#define PCI171X_STATUS_FE BIT(8) /* 1=FIFO is empty */ | |
| 49 | +#define PCI171X_CTRL_REG 0x06 /* W: control register */ | |
| 50 | +#define PCI171X_CTRL_CNT0 BIT(6) /* 1=ext. clk, 0=int. 100kHz clk */ | |
| 51 | +#define PCI171X_CTRL_ONEFH BIT(5) /* 1=on FIFO half full, 0=on sample */ | |
| 52 | +#define PCI171X_CTRL_IRQEN BIT(4) /* 1=enable IRQ */ | |
| 53 | +#define PCI171X_CTRL_GATE BIT(3) /* 1=enable ext. trigger GATE (8254?) */ | |
| 54 | +#define PCI171X_CTRL_EXT BIT(2) /* 1=enable ext. trigger source */ | |
| 55 | +#define PCI171X_CTRL_PACER BIT(1) /* 1=enable int. 8254 trigger source */ | |
| 56 | +#define PCI171X_CTRL_SW BIT(0) /* 1=enable software trigger source */ | |
| 57 | +#define PCI171X_CLRINT_REG 0x08 /* W: clear interrupts request */ | |
| 58 | +#define PCI171X_CLRFIFO_REG 0x09 /* W: clear FIFO */ | |
| 59 | +#define PCI171X_DA_REG(x) (0x0a + ((x) * 2)) /* W: D/A register */ | |
| 60 | +#define PCI171X_DAREF_REG 0x0e /* W: D/A reference control */ | |
| 61 | +#define PCI171X_DI_REG 0x10 /* R: digital inputs */ | |
| 62 | +#define PCI171X_DO_REG 0x10 /* W: digital outputs */ | |
| 63 | +#define PCI171X_TIMER_BASE 0x18 /* R/W: 8254 timer */ | |
| 64 | + | |
| 65 | +/* | |
| 66 | + * PCI-1720 only has analog outputs and has a different | |
| 67 | + * register map (dev->iobase) | |
| 68 | + */ | |
| 69 | +#define PCI1720_DA_REG(x) (0x00 + ((x) * 2)) /* W: D/A registers */ | |
| 70 | +#define PCI1720_RANGE_REG 0x08 /* R/W: D/A range register */ | |
| 71 | +#define PCI1720_SYNC_REG 0x09 /* W: D/A synchronized output */ | |
| 72 | +#define PCI1720_SYNC_CTRL_REG 0x0f /* R/W: D/A synchronized control */ | |
| 73 | +#define PCI1720_SYNC_CTRL_SC0 BIT(0) /* set synchronous output mode */ | |
| 94 | 74 | |
| 95 | 75 | static const struct comedi_lrange range_pci1710_3 = { |
| 96 | 76 | 9, { |
| @@ -244,10 +224,10 @@ static const struct boardtype boardtypes[] = { · 147 unmodified lines | ||
| 244 | 224 | |
| 245 | 225 | struct pci1710_private { |
| 246 | 226 | unsigned int max_samples; |
| 247 | − unsigned int CntrlReg; /* Control register */ | |
| 227 | + unsigned int ctrl; /* control register value */ | |
| 228 | + unsigned int ctrl_ext; /* used to switch from TRIG_EXT to TRIG_xxx */ | |
| 229 | + unsigned int mux_ext; /* used to set the channel interval to scan */ | |
| 248 | 230 | unsigned char ai_et; |
| 249 | − unsigned int ai_et_CntrlReg; | |
| 250 | − unsigned int ai_et_MuxVal; | |
| 251 | 231 | unsigned int act_chanlist[32]; /* list of scanned channel */ |
| 252 | 232 | unsigned char saved_seglen; /* len of the non-repeating chanlist */ |
| 253 | 233 | unsigned char da_ranges; /* copy of D/A outpit range register */ |
| @@ -342,8 +322,8 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev, · 88 unmodified lines | ||
| 342 | 322 | rangeval |= 0x0020; |
| 343 | 323 | |
| 344 | 324 | /* select channel and set range */ |
| 345 | − outw(chan | (chan << 8), dev->iobase + PCI171x_MUX); | |
| 346 | − outw(rangeval, dev->iobase + PCI171x_RANGE); | |
| 325 | + outw(chan | (chan << 8), dev->iobase + PCI171X_MUX_REG); | |
| 326 | + outw(rangeval, dev->iobase + PCI171X_RANGE_REG); | |
| 347 | 327 | |
| 348 | 328 | devpriv->act_chanlist[i] = chan; |
| 349 | 329 | } |
| @@ -351,8 +331,8 @@ static void pci171x_ai_setup_chanlist(struct comedi_device *dev, · 1 unmodified line | ||
| 351 | 331 | devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); |
| 352 | 332 | |
| 353 | 333 | /* select channel interval to scan */ |
| 354 | − devpriv->ai_et_MuxVal = first_chan | (last_chan << 8); | |
| 355 | − outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); | |
| 334 | + devpriv->mux_ext = first_chan | (last_chan << 8); | |
| 335 | + outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG); | |
| 356 | 336 | } |
| 357 | 337 | |
| 358 | 338 | static int pci171x_ai_eoc(struct comedi_device *dev, |
| @@ -362,8 +342,8 @@ static int pci171x_ai_eoc(struct comedi_device *dev, · 3 unmodified lines | ||
| 362 | 342 | { |
| 363 | 343 | unsigned int status; |
| 364 | 344 | |
| 365 | − status = inw(dev->iobase + PCI171x_STATUS); | |
| 366 | − if ((status & Status_FE) == 0) | |
| 345 | + status = inw(dev->iobase + PCI171X_STATUS_REG); | |
| 346 | + if ((status & PCI171X_STATUS_FE) == 0) | |
| 367 | 347 | return 0; |
| 368 | 348 | return -EBUSY; |
| 369 | 349 | } |
| @@ -378,7 +358,7 @@ static int pci171x_ai_read_sample(struct comedi_device *dev, · 8 unmodified lines | ||
| 378 | 358 | unsigned int sample; |
| 379 | 359 | unsigned int chan; |
| 380 | 360 | |
| 381 | − sample = inw(dev->iobase + PCI171x_AD_DATA); | |
| 361 | + sample = inw(dev->iobase + PCI171X_AD_DATA_REG); | |
| 382 | 362 | if (!board->is_pci1713) { |
| 383 | 363 | /* |
| 384 | 364 | * The upper 4 bits of the 16-bit sample are the channel number |
| @@ -406,18 +386,19 @@ static int pci171x_ai_insn_read(struct comedi_device *dev, · 21 unmodified lines | ||
| 406 | 386 | int ret = 0; |
| 407 | 387 | int i; |
| 408 | 388 | |
| 409 | − devpriv->CntrlReg &= Control_CNT0; | |
| 410 | − devpriv->CntrlReg |= Control_SW; /* set software trigger */ | |
| 411 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 412 | − outb(0, dev->iobase + PCI171x_CLRFIFO); | |
| 413 | − outb(0, dev->iobase + PCI171x_CLRINT); | |
| 389 | + devpriv->ctrl &= PCI171X_CTRL_CNT0; | |
| 390 | + devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */ | |
| 391 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 392 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 393 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 414 | 394 | |
| 415 | 395 | pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1); |
| 416 | 396 | |
| 417 | 397 | for (i = 0; i < insn->n; i++) { |
| 418 | 398 | unsigned int val; |
| 419 | 399 | |
| 420 | − outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ | |
| 400 | + /* start conversion */ | |
| 401 | + outw(0, dev->iobase + PCI171X_SOFTTRG_REG); | |
| 421 | 402 | |
| 422 | 403 | ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); |
| 423 | 404 | if (ret) |
| @@ -430,8 +411,8 @@ static int pci171x_ai_insn_read(struct comedi_device *dev, · 6 unmodified lines | ||
| 430 | 411 | data[i] = val; |
| 431 | 412 | } |
| 432 | 413 | |
| 433 | − outb(0, dev->iobase + PCI171x_CLRFIFO); | |
| 434 | − outb(0, dev->iobase + PCI171x_CLRINT); | |
| 414 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 415 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 435 | 416 | |
| 436 | 417 | return ret ? ret : insn->n; |
| 437 | 418 | } |
| @@ -444,17 +425,16 @@ static int pci171x_ao_insn_write(struct comedi_device *dev, · 6 unmodified lines | ||
| 444 | 425 | struct pci1710_private *devpriv = dev->private; |
| 445 | 426 | unsigned int chan = CR_CHAN(insn->chanspec); |
| 446 | 427 | unsigned int range = CR_RANGE(insn->chanspec); |
| 447 | − unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1; | |
| 448 | 428 | unsigned int val = s->readback[chan]; |
| 449 | 429 | int i; |
| 450 | 430 | |
| 451 | 431 | devpriv->da_ranges &= ~(1 << (chan << 1)); |
| 452 | 432 | devpriv->da_ranges |= (range << (chan << 1)); |
| 453 | − outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); | |
| 433 | + outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG); | |
| 454 | 434 | |
| 455 | 435 | for (i = 0; i < insn->n; i++) { |
| 456 | 436 | val = data[i]; |
| 457 | − outw(val, dev->iobase + reg); | |
| 437 | + outw(val, dev->iobase + PCI171X_DA_REG(chan)); | |
| 458 | 438 | } |
| 459 | 439 | |
| 460 | 440 | s->readback[chan] = val; |
| @@ -467,7 +447,7 @@ static int pci171x_di_insn_bits(struct comedi_device *dev, · 6 unmodified lines | ||
| 467 | 447 | struct comedi_insn *insn, |
| 468 | 448 | unsigned int *data) |
| 469 | 449 | { |
| 470 | − data[1] = inw(dev->iobase + PCI171x_DI); | |
| 450 | + data[1] = inw(dev->iobase + PCI171X_DI_REG); | |
| 471 | 451 | |
| 472 | 452 | return insn->n; |
| 473 | 453 | } |
| @@ -478,7 +458,7 @@ static int pci171x_do_insn_bits(struct comedi_device *dev, · 4 unmodified lines | ||
| 478 | 458 | unsigned int *data) |
| 479 | 459 | { |
| 480 | 460 | if (comedi_dio_update_state(s, data)) |
| 481 | − outw(s->state, dev->iobase + PCI171x_DO); | |
| 461 | + outw(s->state, dev->iobase + PCI171X_DO_REG); | |
| 482 | 462 | |
| 483 | 463 | data[1] = s->state; |
| 484 | 464 | |
| @@ -499,15 +479,15 @@ static int pci1720_ao_insn_write(struct comedi_device *dev, · 14 unmodified lines | ||
| 499 | 479 | val = devpriv->da_ranges & (~(0x03 << (chan << 1))); |
| 500 | 480 | val |= (range << (chan << 1)); |
| 501 | 481 | if (val != devpriv->da_ranges) { |
| 502 | − outb(val, dev->iobase + PCI1720_RANGE); | |
| 482 | + outb(val, dev->iobase + PCI1720_RANGE_REG); | |
| 503 | 483 | devpriv->da_ranges = val; |
| 504 | 484 | } |
| 505 | 485 | |
| 506 | 486 | val = s->readback[chan]; |
| 507 | 487 | for (i = 0; i < insn->n; i++) { |
| 508 | 488 | val = data[i]; |
| 509 | − outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); | |
| 510 | − outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ | |
| 489 | + outw(val, dev->iobase + PCI1720_DA_REG(chan)); | |
| 490 | + outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */ | |
| 511 | 491 | } |
| 512 | 492 | |
| 513 | 493 | s->readback[chan] = val; |
| @@ -520,13 +500,13 @@ static int pci171x_ai_cancel(struct comedi_device *dev, · 6 unmodified lines | ||
| 520 | 500 | { |
| 521 | 501 | struct pci1710_private *devpriv = dev->private; |
| 522 | 502 | |
| 523 | − devpriv->CntrlReg &= Control_CNT0; | |
| 524 | − devpriv->CntrlReg |= Control_SW; | |
| 503 | + devpriv->ctrl &= PCI171X_CTRL_CNT0; | |
| 504 | + devpriv->ctrl |= PCI171X_CTRL_SW; | |
| 525 | 505 | /* reset any operations */ |
| 526 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 506 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 527 | 507 | comedi_8254_pacer_enable(dev->pacer, 1, 2, false); |
| 528 | − outb(0, dev->iobase + PCI171x_CLRFIFO); | |
| 529 | − outb(0, dev->iobase + PCI171x_CLRINT); | |
| 508 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 509 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 530 | 510 | |
| 531 | 511 | return 0; |
| 532 | 512 | } |
| @@ -539,22 +519,22 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, · 6 unmodified lines | ||
| 539 | 519 | unsigned int val; |
| 540 | 520 | int ret; |
| 541 | 521 | |
| 542 | − status = inw(dev->iobase + PCI171x_STATUS); | |
| 543 | − if (status & Status_FE) { | |
| 522 | + status = inw(dev->iobase + PCI171X_STATUS_REG); | |
| 523 | + if (status & PCI171X_STATUS_FE) { | |
| 544 | 524 | dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); |
| 545 | 525 | s->async->events |= COMEDI_CB_ERROR; |
| 546 | 526 | return; |
| 547 | 527 | } |
| 548 | − if (status & Status_FF) { | |
| 528 | + if (status & PCI171X_STATUS_FF) { | |
| 549 | 529 | dev_dbg(dev->class_dev, |
| 550 | 530 | "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); |
| 551 | 531 | s->async->events |= COMEDI_CB_ERROR; |
| 552 | 532 | return; |
| 553 | 533 | } |
| 554 | 534 | |
| 555 | − outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ | |
| 535 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 556 | 536 | |
| 557 | − for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { | |
| 537 | + for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) { | |
| 558 | 538 | ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val); |
| 559 | 539 | if (ret) { |
| 560 | 540 | s->async->events |= COMEDI_CB_ERROR; |
| @@ -570,7 +550,7 @@ static void pci1710_handle_every_sample(struct comedi_device *dev, · 9 unmodified lines | ||
| 570 | 550 | } |
| 571 | 551 | } |
| 572 | 552 | |
| 573 | − outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ | |
| 553 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 574 | 554 | } |
| 575 | 555 | |
| 576 | 556 | static void pci1710_handle_fifo(struct comedi_device *dev, |
| @@ -582,13 +562,13 @@ static void pci1710_handle_fifo(struct comedi_device *dev, · 5 unmodified lines | ||
| 582 | 562 | unsigned int status; |
| 583 | 563 | int i; |
| 584 | 564 | |
| 585 | − status = inw(dev->iobase + PCI171x_STATUS); | |
| 586 | − if (!(status & Status_FH)) { | |
| 565 | + status = inw(dev->iobase + PCI171X_STATUS_REG); | |
| 566 | + if (!(status & PCI171X_STATUS_FH)) { | |
| 587 | 567 | dev_dbg(dev->class_dev, "A/D FIFO not half full!\n"); |
| 588 | 568 | async->events |= COMEDI_CB_ERROR; |
| 589 | 569 | return; |
| 590 | 570 | } |
| 591 | − if (status & Status_FF) { | |
| 571 | + if (status & PCI171X_STATUS_FF) { | |
| 592 | 572 | dev_dbg(dev->class_dev, |
| 593 | 573 | "A/D FIFO Full status (Fatal Error!)\n"); |
| 594 | 574 | async->events |= COMEDI_CB_ERROR; |
| @@ -615,7 +595,7 @@ static void pci1710_handle_fifo(struct comedi_device *dev, · 20 unmodified lines | ||
| 615 | 595 | } |
| 616 | 596 | } |
| 617 | 597 | |
| 618 | − outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ | |
| 598 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 619 | 599 | } |
| 620 | 600 | |
| 621 | 601 | static irqreturn_t interrupt_service_pci1710(int irq, void *d) |
| @@ -632,19 +612,20 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) · 10 unmodified lines | ||
| 632 | 612 | cmd = &s->async->cmd; |
| 633 | 613 | |
| 634 | 614 | /* is this interrupt from our board? */ |
| 635 | − if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) | |
| 615 | + if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ)) | |
| 636 | 616 | return IRQ_NONE; /* no, exit */ |
| 637 | 617 | |
| 638 | 618 | if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ |
| 639 | 619 | devpriv->ai_et = 0; |
| 640 | − devpriv->CntrlReg &= Control_CNT0; | |
| 641 | − devpriv->CntrlReg |= Control_SW; /* set software trigger */ | |
| 642 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 643 | − devpriv->CntrlReg = devpriv->ai_et_CntrlReg; | |
| 644 | − outb(0, dev->iobase + PCI171x_CLRFIFO); | |
| 645 | − outb(0, dev->iobase + PCI171x_CLRINT); | |
| 646 | − outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); | |
| 647 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 620 | + devpriv->ctrl &= PCI171X_CTRL_CNT0; | |
| 621 | + devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */ | |
| 622 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 623 | + devpriv->ctrl = devpriv->ctrl_ext; | |
| 624 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 625 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 626 | + /* no sample on this interrupt; reset the channel interval */ | |
| 627 | + outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG); | |
| 628 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 648 | 629 | comedi_8254_pacer_enable(dev->pacer, 1, 2, true); |
| 649 | 630 | return IRQ_HANDLED; |
| 650 | 631 | } |
| @@ -667,33 +648,34 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) · 16 unmodified lines | ||
| 667 | 648 | pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len, |
| 668 | 649 | devpriv->saved_seglen); |
| 669 | 650 | |
| 670 | − outb(0, dev->iobase + PCI171x_CLRFIFO); | |
| 671 | − outb(0, dev->iobase + PCI171x_CLRINT); | |
| 651 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 652 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 672 | 653 | |
| 673 | − devpriv->CntrlReg &= Control_CNT0; | |
| 654 | + devpriv->ctrl &= PCI171X_CTRL_CNT0; | |
| 674 | 655 | if ((cmd->flags & CMDF_WAKE_EOS) == 0) |
| 675 | − devpriv->CntrlReg |= Control_ONEFH; | |
| 656 | + devpriv->ctrl |= PCI171X_CTRL_ONEFH; | |
| 676 | 657 | |
| 677 | 658 | if (cmd->convert_src == TRIG_TIMER) { |
| 678 | 659 | comedi_8254_update_divisors(dev->pacer); |
| 679 | 660 | |
| 680 | − devpriv->CntrlReg |= Control_PACER | Control_IRQEN; | |
| 661 | + devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN; | |
| 681 | 662 | if (cmd->start_src == TRIG_EXT) { |
| 682 | − devpriv->ai_et_CntrlReg = devpriv->CntrlReg; | |
| 683 | − devpriv->CntrlReg &= | |
| 684 | − ~(Control_PACER | Control_ONEFH | Control_GATE); | |
| 685 | − devpriv->CntrlReg |= Control_EXT; | |
| 663 | + devpriv->ctrl_ext = devpriv->ctrl; | |
| 664 | + devpriv->ctrl &= ~(PCI171X_CTRL_PACER | | |
| 665 | + PCI171X_CTRL_ONEFH | | |
| 666 | + PCI171X_CTRL_GATE); | |
| 667 | + devpriv->ctrl |= PCI171X_CTRL_EXT; | |
| 686 | 668 | devpriv->ai_et = 1; |
| 687 | 669 | } else { /* TRIG_NOW */ |
| 688 | 670 | devpriv->ai_et = 0; |
| 689 | 671 | } |
| 690 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 672 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 691 | 673 | |
| 692 | 674 | if (cmd->start_src == TRIG_NOW) |
| 693 | 675 | comedi_8254_pacer_enable(dev->pacer, 1, 2, true); |
| 694 | 676 | } else { /* TRIG_EXT */ |
| 695 | − devpriv->CntrlReg |= Control_EXT | Control_IRQEN; | |
| 696 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 677 | + devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN; | |
| 678 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 697 | 679 | } |
| 698 | 680 | |
| 699 | 681 | return 0; |
| @@ -782,18 +764,18 @@ static int pci171x_insn_counter_config(struct comedi_device *dev, · 82 unmodified lines | ||
| 782 | 764 | case INSN_CONFIG_SET_CLOCK_SRC: |
| 783 | 765 | switch (data[1]) { |
| 784 | 766 | case 0: /* internal */ |
| 785 | − devpriv->ai_et_CntrlReg &= ~Control_CNT0; | |
| 767 | + devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0; | |
| 786 | 768 | break; |
| 787 | 769 | case 1: /* external */ |
| 788 | − devpriv->ai_et_CntrlReg |= Control_CNT0; | |
| 770 | + devpriv->ctrl_ext |= PCI171X_CTRL_CNT0; | |
| 789 | 771 | break; |
| 790 | 772 | default: |
| 791 | 773 | return -EINVAL; |
| 792 | 774 | } |
| 793 | − outw(devpriv->ai_et_CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 775 | + outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG); | |
| 794 | 776 | break; |
| 795 | 777 | case INSN_CONFIG_GET_CLOCK_SRC: |
| 796 | − if (devpriv->ai_et_CntrlReg & Control_CNT0) { | |
| 778 | + if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) { | |
| 797 | 779 | data[1] = 1; |
| 798 | 780 | data[2] = 0; |
| 799 | 781 | } else { |
| @@ -814,21 +796,21 @@ static int pci171x_reset(struct comedi_device *dev) · 14 unmodified lines | ||
| 814 | 796 | struct pci1710_private *devpriv = dev->private; |
| 815 | 797 | |
| 816 | 798 | /* Software trigger, CNT0=external */ |
| 817 | − devpriv->CntrlReg = Control_SW | Control_CNT0; | |
| 799 | + devpriv->ctrl = PCI171X_CTRL_SW | PCI171X_CTRL_CNT0; | |
| 818 | 800 | /* reset any operations */ |
| 819 | − outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); | |
| 820 | − outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ | |
| 821 | − outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ | |
| 801 | + outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG); | |
| 802 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 803 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 822 | 804 | devpriv->da_ranges = 0; |
| 823 | 805 | if (board->has_ao) { |
| 824 | − /* set DACs to 0..5V */ | |
| 825 | − outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); | |
| 826 | − outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */ | |
| 827 | − outw(0, dev->iobase + PCI171x_DA2); | |
| 806 | + /* set DACs to 0..5V and outputs to 0V */ | |
| 807 | + outb(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG); | |
| 808 | + outw(0, dev->iobase + PCI171X_DA_REG(0)); | |
| 809 | + outw(0, dev->iobase + PCI171X_DA_REG(1)); | |
| 828 | 810 | } |
| 829 | − outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */ | |
| 830 | − outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ | |
| 831 | − outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ | |
| 811 | + outw(0, dev->iobase + PCI171X_DO_REG); /* digital outputs to 0 */ | |
| 812 | + outb(0, dev->iobase + PCI171X_CLRFIFO_REG); | |
| 813 | + outb(0, dev->iobase + PCI171X_CLRINT_REG); | |
| 832 | 814 | |
| 833 | 815 | return 0; |
| 834 | 816 | } |
| @@ -837,15 +819,15 @@ static int pci1720_reset(struct comedi_device *dev) · 2 unmodified lines | ||
| 837 | 819 | { |
| 838 | 820 | struct pci1710_private *devpriv = dev->private; |
| 839 | 821 | /* set synchronous output mode */ |
| 840 | − outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); | |
| 822 | + outb(PCI1720_SYNC_CTRL_SC0, dev->iobase + PCI1720_SYNC_CTRL_REG); | |
| 841 | 823 | devpriv->da_ranges = 0xAA; |
| 842 | − /* set all ranges to +/-5V */ | |
| 843 | − outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); | |
| 844 | − outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */ | |
| 845 | − outw(0x0800, dev->iobase + PCI1720_DA1); | |
| 846 | − outw(0x0800, dev->iobase + PCI1720_DA2); | |
| 847 | − outw(0x0800, dev->iobase + PCI1720_DA3); | |
| 848 | − outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ | |
| 824 | + /* set all ranges to +/-5V and outputs to 0V */ | |
| 825 | + outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE_REG); | |
| 826 | + outw(0x0800, dev->iobase + PCI1720_DA_REG(0)); | |
| 827 | + outw(0x0800, dev->iobase + PCI1720_DA_REG(1)); | |
| 828 | + outw(0x0800, dev->iobase + PCI1720_DA_REG(2)); | |
| 829 | + outw(0x0800, dev->iobase + PCI1720_DA_REG(3)); | |
| 830 | + outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */ | |
| 849 | 831 | |
| 850 | 832 | return 0; |
| 851 | 833 | } |
| @@ -51,25 +51,27 @@ · 50 unmodified lines | ||
| 51 | 51 | #define PCI1723_BOARD_ID_REG 0x10 |
| 52 | 52 | #define PCI1723_BOARD_ID_MASK (0xf << 0) |
| 53 | 53 | #define PCI1723_SYNC_CTRL_REG 0x12 |
| 54 | −#define PCI1723_SYNC_CTRL_ASYNC (0 << 0) | |
| 55 | −#define PCI1723_SYNC_CTRL_SYNC (1 << 0) | |
| 54 | +#define PCI1723_SYNC_CTRL(x) (((x) & 0x1) << 0) | |
| 55 | +#define PCI1723_SYNC_CTRL_ASYNC PCI1723_SYNC_CTRL(0) | |
| 56 | +#define PCI1723_SYNC_CTRL_SYNC PCI1723_SYNC_CTRL(1) | |
| 56 | 57 | #define PCI1723_CTRL_REG 0x14 |
| 57 | −#define PCI1723_CTRL_BUSY (1 << 15) | |
| 58 | −#define PCI1723_CTRL_INIT (1 << 14) | |
| 59 | −#define PCI1723_CTRL_SELF (1 << 8) | |
| 58 | +#define PCI1723_CTRL_BUSY BIT(15) | |
| 59 | +#define PCI1723_CTRL_INIT BIT(14) | |
| 60 | +#define PCI1723_CTRL_SELF BIT(8) | |
| 60 | 61 | #define PCI1723_CTRL_IDX(x) (((x) & 0x3) << 6) |
| 61 | 62 | #define PCI1723_CTRL_RANGE(x) (((x) & 0x3) << 4) |
| 62 | −#define PCI1723_CTRL_GAIN (0 << 3) | |
| 63 | −#define PCI1723_CTRL_OFFSET (1 << 3) | |
| 63 | +#define PCI1723_CTRL_SEL(x) (((x) & 0x1) << 3) | |
| 64 | +#define PCI1723_CTRL_GAIN PCI1723_CTRL_SEL(0) | |
| 65 | +#define PCI1723_CTRL_OFFSET PCI1723_CTRL_SEL(1) | |
| 64 | 66 | #define PCI1723_CTRL_CHAN(x) (((x) & 0x7) << 0) |
| 65 | 67 | #define PCI1723_CALIB_CTRL_REG 0x16 |
| 66 | −#define PCI1723_CALIB_CTRL_CS (1 << 2) | |
| 67 | −#define PCI1723_CALIB_CTRL_DAT (1 << 1) | |
| 68 | −#define PCI1723_CALIB_CTRL_CLK (1 << 0) | |
| 68 | +#define PCI1723_CALIB_CTRL_CS BIT(2) | |
| 69 | +#define PCI1723_CALIB_CTRL_DAT BIT(1) | |
| 70 | +#define PCI1723_CALIB_CTRL_CLK BIT(0) | |
| 69 | 71 | #define PCI1723_CALIB_STROBE_REG 0x18 |
| 70 | 72 | #define PCI1723_DIO_CTRL_REG 0x1a |
| 71 | −#define PCI1723_DIO_CTRL_HDIO (1 << 1) | |
| 72 | −#define PCI1723_DIO_CTRL_LDIO (1 << 0) | |
| 73 | +#define PCI1723_DIO_CTRL_HDIO BIT(1) | |
| 74 | +#define PCI1723_DIO_CTRL_LDIO BIT(0) | |
| 73 | 75 | #define PCI1723_DIO_DATA_REG 0x1c |
| 74 | 76 | #define PCI1723_CALIB_DATA_REG 0x1e |
| 75 | 77 | #define PCI1723_SYNC_STROBE_REG 0x20 |
| @@ -77,9 +79,10 @@ · 1 unmodified line | ||
| 77 | 79 | #define PCI1723_RESET_CALIB_STROBE_REG 0x24 |
| 78 | 80 | #define PCI1723_RANGE_STROBE_REG 0x26 |
| 79 | 81 | #define PCI1723_VREF_REG 0x28 |
| 80 | −#define PCI1723_VREF_NEG10V (0 << 0) | |
| 81 | −#define PCI1723_VREF_0V (1 << 0) | |
| 82 | −#define PCI1723_VREF_POS10V (3 << 0) | |
| 82 | +#define PCI1723_VREF(x) (((x) & 0x3) << 0) | |
| 83 | +#define PCI1723_VREF_NEG10V PCI1723_VREF(0) | |
| 84 | +#define PCI1723_VREF_0V PCI1723_VREF(1) | |
| 85 | +#define PCI1723_VREF_POS10V PCI1723_VREF(3) | |
| 83 | 86 | |
| 84 | 87 | static int pci1723_ao_insn_write(struct comedi_device *dev, |
| 85 | 88 | struct comedi_subdevice *s, |
| @@ -54,16 +54,17 @@ · 53 unmodified lines | ||
| 54 | 54 | * PCI bar 2 Register I/O map (dev->iobase) |
| 55 | 55 | */ |
| 56 | 56 | #define PCI1724_DAC_CTRL_REG 0x00 |
| 57 | −#define PCI1724_DAC_CTRL_GX(x) (1 << (20 + ((x) / 8))) | |
| 57 | +#define PCI1724_DAC_CTRL_GX(x) BIT(20 + ((x) / 8)) | |
| 58 | 58 | #define PCI1724_DAC_CTRL_CX(x) (((x) % 8) << 16) |
| 59 | −#define PCI1724_DAC_CTRL_MODE_GAIN (1 << 14) | |
| 60 | −#define PCI1724_DAC_CTRL_MODE_OFFSET (2 << 14) | |
| 61 | −#define PCI1724_DAC_CTRL_MODE_NORMAL (3 << 14) | |
| 62 | −#define PCI1724_DAC_CTRL_MODE_MASK (3 << 14) | |
| 59 | +#define PCI1724_DAC_CTRL_MODE(x) (((x) & 0x3) << 14) | |
| 60 | +#define PCI1724_DAC_CTRL_MODE_GAIN PCI1724_DAC_CTRL_MODE(1) | |
| 61 | +#define PCI1724_DAC_CTRL_MODE_OFFSET PCI1724_DAC_CTRL_MODE(2) | |
| 62 | +#define PCI1724_DAC_CTRL_MODE_NORMAL PCI1724_DAC_CTRL_MODE(3) | |
| 63 | +#define PCI1724_DAC_CTRL_MODE_MASK PCI1724_DAC_CTRL_MODE(3) | |
| 63 | 64 | #define PCI1724_DAC_CTRL_DATA(x) (((x) & 0x3fff) << 0) |
| 64 | 65 | #define PCI1724_SYNC_CTRL_REG 0x04 |
| 65 | −#define PCI1724_SYNC_CTRL_DACSTAT (1 << 1) | |
| 66 | −#define PCI1724_SYNC_CTRL_SYN (1 << 0) | |
| 66 | +#define PCI1724_SYNC_CTRL_DACSTAT BIT(1) | |
| 67 | +#define PCI1724_SYNC_CTRL_SYN BIT(0) | |
| 67 | 68 | #define PCI1724_EEPROM_CTRL_REG 0x08 |
| 68 | 69 | #define PCI1724_SYNC_TRIG_REG 0x0c /* any value works */ |
| 69 | 70 | #define PCI1724_BOARD_ID_REG 0x10 |
| @@ -1,99 +1,107 @@ | ||
| 1 | 1 | /* |
| 2 | − | |
| 3 | − comedi/drivers/aio_aio12_8.c | |
| 4 | − | |
| 5 | − Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board | |
| 6 | − Copyright (C) 2006 C&C Technologies, Inc. | |
| 7 | − | |
| 8 | − This program is free software; you can redistribute it and/or modify | |
| 9 | − it under the terms of the GNU General Public License as published by | |
| 10 | − the Free Software Foundation; either version 2 of the License, or | |
| 11 | − (at your option) any later version. | |
| 12 | − | |
| 13 | − This program is distributed in the hope that it will be useful, | |
| 14 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | − GNU General Public License for more details. | |
| 17 | −*/ | |
| 2 | + * aio_aio12_8.c | |
| 3 | + * Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board | |
| 4 | + * Copyright (C) 2006 C&C Technologies, Inc. | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + */ | |
| 18 | 16 | |
| 19 | 17 | /* |
| 20 | − | |
| 21 | −Driver: aio_aio12_8 | |
| 22 | −Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board | |
| 23 | −Author: Pablo Mejia <pablo.mejia@cctechnol.com> | |
| 24 | −Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8) | |
| 25 | − [Access I/O] PC-104 AI12-8 (aio_ai12_8) | |
| 26 | − [Access I/O] PC-104 AO12-8 (aio_ao12_8) | |
| 27 | −Status: experimental | |
| 28 | − | |
| 29 | −Configuration Options: | |
| 30 | − [0] - I/O port base address | |
| 31 | − | |
| 32 | −Notes: | |
| 33 | − | |
| 34 | − Only synchronous operations are supported. | |
| 35 | − | |
| 36 | −*/ | |
| 18 | + * Driver: aio_aio12_8 | |
| 19 | + * Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board | |
| 20 | + * Author: Pablo Mejia <pablo.mejia@cctechnol.com> | |
| 21 | + * Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8), | |
| 22 | + * [Access I/O] PC-104 AI12-8 (aio_ai12_8), | |
| 23 | + * [Access I/O] PC-104 AO12-4 (aio_ao12_4) | |
| 24 | + * Status: experimental | |
| 25 | + * | |
| 26 | + * Configuration Options: | |
| 27 | + * [0] - I/O port base address | |
| 28 | + * | |
| 29 | + * Notes: | |
| 30 | + * Only synchronous operations are supported. | |
| 31 | + */ | |
| 37 | 32 | |
| 38 | 33 | #include <linux/module.h> |
| 39 | 34 | #include "../comedidev.h" |
| 35 | + | |
| 36 | +#include "comedi_8254.h" | |
| 40 | 37 | #include "8255.h" |
| 41 | 38 | |
| 42 | 39 | /* |
| 43 | 40 | * Register map |
| 44 | 41 | */ |
| 45 | 42 | #define AIO12_8_STATUS_REG 0x00 |
| 46 | −#define AIO12_8_STATUS_ADC_EOC (1 << 7) | |
| 47 | −#define AIO12_8_STATUS_PORT_C_COS (1 << 6) | |
| 48 | −#define AIO12_8_STATUS_IRQ_ENA (1 << 2) | |
| 43 | +#define AIO12_8_STATUS_ADC_EOC BIT(7) | |
| 44 | +#define AIO12_8_STATUS_PORT_C_COS BIT(6) | |
| 45 | +#define AIO12_8_STATUS_IRQ_ENA BIT(2) | |
| 49 | 46 | #define AIO12_8_INTERRUPT_REG 0x01 |
| 50 | −#define AIO12_8_INTERRUPT_ADC (1 << 7) | |
| 51 | −#define AIO12_8_INTERRUPT_COS (1 << 6) | |
| 52 | −#define AIO12_8_INTERRUPT_COUNTER1 (1 << 5) | |
| 53 | −#define AIO12_8_INTERRUPT_PORT_C3 (1 << 4) | |
| 54 | −#define AIO12_8_INTERRUPT_PORT_C0 (1 << 3) | |
| 55 | −#define AIO12_8_INTERRUPT_ENA (1 << 2) | |
| 47 | +#define AIO12_8_INTERRUPT_ADC BIT(7) | |
| 48 | +#define AIO12_8_INTERRUPT_COS BIT(6) | |
| 49 | +#define AIO12_8_INTERRUPT_COUNTER1 BIT(5) | |
| 50 | +#define AIO12_8_INTERRUPT_PORT_C3 BIT(4) | |
| 51 | +#define AIO12_8_INTERRUPT_PORT_C0 BIT(3) | |
| 52 | +#define AIO12_8_INTERRUPT_ENA BIT(2) | |
| 56 | 53 | #define AIO12_8_ADC_REG 0x02 |
| 57 | −#define AIO12_8_ADC_MODE_NORMAL (0 << 6) | |
| 58 | −#define AIO12_8_ADC_MODE_INT_CLK (1 << 6) | |
| 59 | −#define AIO12_8_ADC_MODE_STANDBY (2 << 6) | |
| 60 | −#define AIO12_8_ADC_MODE_POWERDOWN (3 << 6) | |
| 61 | −#define AIO12_8_ADC_ACQ_3USEC (0 << 5) | |
| 62 | −#define AIO12_8_ADC_ACQ_PROGRAM (1 << 5) | |
| 54 | +#define AIO12_8_ADC_MODE(x) (((x) & 0x3) << 6) | |
| 55 | +#define AIO12_8_ADC_MODE_NORMAL AIO12_8_ADC_MODE(0) | |
| 56 | +#define AIO12_8_ADC_MODE_INT_CLK AIO12_8_ADC_MODE(1) | |
| 57 | +#define AIO12_8_ADC_MODE_STANDBY AIO12_8_ADC_MODE(2) | |
| 58 | +#define AIO12_8_ADC_MODE_POWERDOWN AIO12_8_ADC_MODE(3) | |
| 59 | +#define AIO12_8_ADC_ACQ(x) (((x) & 0x1) << 5) | |
| 60 | +#define AIO12_8_ADC_ACQ_3USEC AIO12_8_ADC_ACQ(0) | |
| 61 | +#define AIO12_8_ADC_ACQ_PROGRAM AIO12_8_ADC_ACQ(1) | |
| 63 | 62 | #define AIO12_8_ADC_RANGE(x) ((x) << 3) |
| 64 | 63 | #define AIO12_8_ADC_CHAN(x) ((x) << 0) |
| 65 | 64 | #define AIO12_8_DAC_REG(x) (0x04 + (x) * 2) |
| 66 | 65 | #define AIO12_8_8254_BASE_REG 0x0c |
| 67 | 66 | #define AIO12_8_8255_BASE_REG 0x10 |
| 68 | 67 | #define AIO12_8_DIO_CONTROL_REG 0x14 |
| 69 | −#define AIO12_8_DIO_CONTROL_TST (1 << 0) | |
| 68 | +#define AIO12_8_DIO_CONTROL_TST BIT(0) | |
| 70 | 69 | #define AIO12_8_ADC_TRIGGER_REG 0x15 |
| 71 | 70 | #define AIO12_8_ADC_TRIGGER_RANGE(x) ((x) << 3) |
| 72 | 71 | #define AIO12_8_ADC_TRIGGER_CHAN(x) ((x) << 0) |
| 73 | 72 | #define AIO12_8_TRIGGER_REG 0x16 |
| 74 | −#define AIO12_8_TRIGGER_ADTRIG (1 << 1) | |
| 75 | −#define AIO12_8_TRIGGER_DACTRIG (1 << 0) | |
| 73 | +#define AIO12_8_TRIGGER_ADTRIG BIT(1) | |
| 74 | +#define AIO12_8_TRIGGER_DACTRIG BIT(0) | |
| 76 | 75 | #define AIO12_8_COS_REG 0x17 |
| 77 | 76 | #define AIO12_8_DAC_ENABLE_REG 0x18 |
| 78 | −#define AIO12_8_DAC_ENABLE_REF_ENA (1 << 0) | |
| 77 | +#define AIO12_8_DAC_ENABLE_REF_ENA BIT(0) | |
| 78 | + | |
| 79 | +static const struct comedi_lrange aio_aio12_8_range = { | |
| 80 | + 4, { | |
| 81 | + UNI_RANGE(5), | |
| 82 | + BIP_RANGE(5), | |
| 83 | + UNI_RANGE(10), | |
| 84 | + BIP_RANGE(10) | |
| 85 | + } | |
| 86 | +}; | |
| 79 | 87 | |
| 80 | 88 | struct aio12_8_boardtype { |
| 81 | 89 | const char *name; |
| 82 | − int ai_nchan; | |
| 83 | − int ao_nchan; | |
| 90 | + unsigned int has_ai:1; | |
| 91 | + unsigned int has_ao:1; | |
| 84 | 92 | }; |
| 85 | 93 | |
| 86 | 94 | static const struct aio12_8_boardtype board_types[] = { |
| 87 | 95 | { |
| 88 | 96 | .name = "aio_aio12_8", |
| 89 | − .ai_nchan = 8, | |
| 90 | − .ao_nchan = 4, | |
| 97 | + .has_ai = 1, | |
| 98 | + .has_ao = 1, | |
| 91 | 99 | }, { |
| 92 | 100 | .name = "aio_ai12_8", |
| 93 | − .ai_nchan = 8, | |
| 101 | + .has_ai = 1, | |
| 94 | 102 | }, { |
| 95 | − .name = "aio_ao12_8", | |
| 96 | − .ao_nchan = 4, | |
| 103 | + .name = "aio_ao12_4", | |
| 104 | + .has_ao = 1, | |
| 97 | 105 | }, |
| 98 | 106 | }; |
| 99 | 107 | |
| @@ -112,13 +120,15 @@ static int aio_aio12_8_ai_eoc(struct comedi_device *dev, · 12 unmodified lines | ||
| 112 | 120 | |
| 113 | 121 | static int aio_aio12_8_ai_read(struct comedi_device *dev, |
| 114 | 122 | struct comedi_subdevice *s, |
| 115 | − struct comedi_insn *insn, unsigned int *data) | |
| 123 | + struct comedi_insn *insn, | |
| 124 | + unsigned int *data) | |
| 116 | 125 | { |
| 117 | 126 | unsigned int chan = CR_CHAN(insn->chanspec); |
| 118 | 127 | unsigned int range = CR_RANGE(insn->chanspec); |
| 128 | + unsigned int val; | |
| 119 | 129 | unsigned char control; |
| 120 | 130 | int ret; |
| 121 | − int n; | |
| 131 | + int i; | |
| 122 | 132 | |
| 123 | 133 | /* |
| 124 | 134 | * Setup the control byte for internal 2MHz clock, 3uS conversion, |
| @@ -130,7 +140,7 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, · 5 unmodified lines | ||
| 130 | 140 | /* Read status to clear EOC latch */ |
| 131 | 141 | inb(dev->iobase + AIO12_8_STATUS_REG); |
| 132 | 142 | |
| 133 | − for (n = 0; n < insn->n; n++) { | |
| 143 | + for (i = 0; i < insn->n; i++) { | |
| 134 | 144 | /* Setup and start conversion */ |
| 135 | 145 | outb(control, dev->iobase + AIO12_8_ADC_REG); |
| 136 | 146 | |
| @@ -139,7 +149,13 @@ static int aio_aio12_8_ai_read(struct comedi_device *dev, · 2 unmodified lines | ||
| 139 | 149 | if (ret) |
| 140 | 150 | return ret; |
| 141 | 151 | |
| 142 | − data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; | |
| 152 | + val = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; | |
| 153 | + | |
| 154 | + /* munge bipolar 2's complement data to offset binary */ | |
| 155 | + if (comedi_range_is_bipolar(s, range)) | |
| 156 | + val = comedi_offset_munge(s, val); | |
| 157 | + | |
| 158 | + data[i] = val; | |
| 143 | 159 | } |
| 144 | 160 | |
| 145 | 161 | return insn->n; |
| @@ -166,14 +182,28 @@ static int aio_aio12_8_ao_insn_write(struct comedi_device *dev, · 20 unmodified lines | ||
| 166 | 182 | return insn->n; |
| 167 | 183 | } |
| 168 | 184 | |
| 169 | −static const struct comedi_lrange range_aio_aio12_8 = { | |
| 170 | − 4, { | |
| 171 | − UNI_RANGE(5), | |
| 172 | − BIP_RANGE(5), | |
| 173 | − UNI_RANGE(10), | |
| 174 | − BIP_RANGE(10) | |
| 185 | +static int aio_aio12_8_counter_insn_config(struct comedi_device *dev, | |
| 186 | + struct comedi_subdevice *s, | |
| 187 | + struct comedi_insn *insn, | |
| 188 | + unsigned int *data) | |
| 189 | +{ | |
| 190 | + unsigned int chan = CR_CHAN(insn->chanspec); | |
| 191 | + | |
| 192 | + switch (data[0]) { | |
| 193 | + case INSN_CONFIG_GET_CLOCK_SRC: | |
| 194 | + /* | |
| 195 | + * Channels 0 and 2 have external clock sources. | |
| 196 | + * Channel 1 has a fixed 1 MHz clock source. | |
| 197 | + */ | |
| 198 | + data[0] = 0; | |
| 199 | + data[1] = (chan == 1) ? I8254_OSC_BASE_1MHZ : 0; | |
| 200 | + break; | |
| 201 | + default: | |
| 202 | + return -EINVAL; | |
| 175 | 203 | } |
| 176 | −}; | |
| 204 | + | |
| 205 | + return insn->n; | |
| 206 | +} | |
| 177 | 207 | |
| 178 | 208 | static int aio_aio12_8_attach(struct comedi_device *dev, |
| 179 | 209 | struct comedi_devconfig *it) |
| @@ -186,31 +216,36 @@ static int aio_aio12_8_attach(struct comedi_device *dev, · 6 unmodified lines | ||
| 186 | 216 | if (ret) |
| 187 | 217 | return ret; |
| 188 | 218 | |
| 219 | + dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG, | |
| 220 | + 0, I8254_IO8, 0); | |
| 221 | + if (!dev->pacer) | |
| 222 | + return -ENOMEM; | |
| 223 | + | |
| 189 | 224 | ret = comedi_alloc_subdevices(dev, 4); |
| 190 | 225 | if (ret) |
| 191 | 226 | return ret; |
| 192 | 227 | |
| 228 | + /* Analog Input subdevice */ | |
| 193 | 229 | s = &dev->subdevices[0]; |
| 194 | − if (board->ai_nchan) { | |
| 195 | − /* Analog input subdevice */ | |
| 230 | + if (board->has_ai) { | |
| 196 | 231 | s->type = COMEDI_SUBD_AI; |
| 197 | 232 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; |
| 198 | − s->n_chan = board->ai_nchan; | |
| 233 | + s->n_chan = 8; | |
| 199 | 234 | s->maxdata = 0x0fff; |
| 200 | − s->range_table = &range_aio_aio12_8; | |
| 235 | + s->range_table = &aio_aio12_8_range; | |
| 201 | 236 | s->insn_read = aio_aio12_8_ai_read; |
| 202 | 237 | } else { |
| 203 | 238 | s->type = COMEDI_SUBD_UNUSED; |
| 204 | 239 | } |
| 205 | 240 | |
| 241 | + /* Analog Output subdevice */ | |
| 206 | 242 | s = &dev->subdevices[1]; |
| 207 | − if (board->ao_nchan) { | |
| 208 | − /* Analog output subdevice */ | |
| 243 | + if (board->has_ao) { | |
| 209 | 244 | s->type = COMEDI_SUBD_AO; |
| 210 | − s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; | |
| 245 | + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; | |
| 211 | 246 | s->n_chan = 4; |
| 212 | 247 | s->maxdata = 0x0fff; |
| 213 | − s->range_table = &range_aio_aio12_8; | |
| 248 | + s->range_table = &aio_aio12_8_range; | |
| 214 | 249 | s->insn_write = aio_aio12_8_ao_insn_write; |
| 215 | 250 | |
| 216 | 251 | ret = comedi_alloc_subdev_readback(s); |
| @@ -220,15 +255,17 @@ static int aio_aio12_8_attach(struct comedi_device *dev, · 3 unmodified lines | ||
| 220 | 255 | s->type = COMEDI_SUBD_UNUSED; |
| 221 | 256 | } |
| 222 | 257 | |
| 258 | + /* Digital I/O subdevice (8255) */ | |
| 223 | 259 | s = &dev->subdevices[2]; |
| 224 | − /* 8255 Digital i/o subdevice */ | |
| 225 | 260 | ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG); |
| 226 | 261 | if (ret) |
| 227 | 262 | return ret; |
| 228 | 263 | |
| 264 | + /* Counter subdevice (8254) */ | |
| 229 | 265 | s = &dev->subdevices[3]; |
| 230 | − /* 8254 counter/timer subdevice */ | |
| 231 | − s->type = COMEDI_SUBD_UNUSED; | |
| 266 | + comedi_8254_subdevice_init(s, dev->pacer); | |
| 267 | + | |
| 268 | + dev->pacer->insn_config = aio_aio12_8_counter_insn_config; | |
| 232 | 269 | |
| 233 | 270 | return 0; |
| 234 | 271 | } |
| @@ -245,5 +282,5 @@ static struct comedi_driver aio_aio12_8_driver = { · 10 unmodified lines | ||
| 245 | 282 | module_comedi_driver(aio_aio12_8_driver); |
| 246 | 283 | |
| 247 | 284 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
| 248 | −MODULE_DESCRIPTION("Comedi low-level driver"); | |
| 285 | +MODULE_DESCRIPTION("Comedi driver for Access I/O AIO12-8 Analog I/O Board"); | |
| 249 | 286 | MODULE_LICENSE("GPL"); |
| @@ -2275,7 +2275,7 @@ static int pci230_ai_cancel(struct comedi_device *dev, · 2274 unmodified lines | ||
| 2275 | 2275 | static irqreturn_t pci230_interrupt(int irq, void *d) |
| 2276 | 2276 | { |
| 2277 | 2277 | unsigned char status_int, valid_status_int, temp_ier; |
| 2278 | − struct comedi_device *dev = (struct comedi_device *)d; | |
| 2278 | + struct comedi_device *dev = d; | |
| 2279 | 2279 | struct pci230_private *devpriv = dev->private; |
| 2280 | 2280 | struct comedi_subdevice *s_ao = dev->write_subdev; |
| 2281 | 2281 | struct comedi_subdevice *s_ai = dev->read_subdev; |
| @@ -1,36 +1,37 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/das16cs.c | |
| 3 | − Driver for Computer Boards PC-CARD DAS16/16. | |
| 2 | + * cb_das16_cs.c | |
| 3 | + * Driver for Computer Boards PC-CARD DAS16/16. | |
| 4 | + * | |
| 5 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 6 | + * Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License as published by | |
| 10 | + * the Free Software Foundation; either version 2 of the License, or | |
| 11 | + * (at your option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + * | |
| 18 | + * PCMCIA support code for this driver is adapted from the dummy_cs.c | |
| 19 | + * driver of the Linux PCMCIA Card Services package. | |
| 20 | + * | |
| 21 | + * The initial developer of the original code is David A. Hinds | |
| 22 | + * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |
| 23 | + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |
| 24 | + */ | |
| 4 | 25 | |
| 5 | − COMEDI - Linux Control and Measurement Device Interface | |
| 6 | − Copyright (C) 2000, 2001, 2002 David A. Schleef <ds@schleef.org> | |
| 7 | − | |
| 8 | − This program is free software; you can redistribute it and/or modify | |
| 9 | − it under the terms of the GNU General Public License as published by | |
| 10 | − the Free Software Foundation; either version 2 of the License, or | |
| 11 | − (at your option) any later version. | |
| 12 | − | |
| 13 | − This program is distributed in the hope that it will be useful, | |
| 14 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | − GNU General Public License for more details. | |
| 17 | − | |
| 18 | − PCMCIA support code for this driver is adapted from the dummy_cs.c | |
| 19 | − driver of the Linux PCMCIA Card Services package. | |
| 20 | − | |
| 21 | − The initial developer of the original code is David A. Hinds | |
| 22 | − <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |
| 23 | − are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |
| 24 | − | |
| 25 | −*/ | |
| 26 | 26 | /* |
| 27 | −Driver: cb_das16_cs | |
| 28 | −Description: Computer Boards PC-CARD DAS16/16 | |
| 29 | −Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), PC-CARD DAS16/16-AO | |
| 30 | −Author: ds | |
| 31 | −Updated: Mon, 04 Nov 2002 20:04:21 -0800 | |
| 32 | −Status: experimental | |
| 33 | −*/ | |
| 27 | + * Driver: cb_das16_cs | |
| 28 | + * Description: Computer Boards PC-CARD DAS16/16 | |
| 29 | + * Devices: [ComputerBoards] PC-CARD DAS16/16 (cb_das16_cs), | |
| 30 | + * PC-CARD DAS16/16-AO | |
| 31 | + * Author: ds | |
| 32 | + * Updated: Mon, 04 Nov 2002 20:04:21 -0800 | |
| 33 | + * Status: experimental | |
| 34 | + */ | |
| 34 | 35 | |
| 35 | 36 | #include <linux/module.h> |
| 36 | 37 | #include <linux/interrupt.h> |
| @@ -40,38 +41,86 @@ Status: experimental · 3 unmodified lines | ||
| 40 | 41 | |
| 41 | 42 | #include "comedi_8254.h" |
| 42 | 43 | |
| 43 | −#define DAS16CS_ADC_DATA 0 | |
| 44 | −#define DAS16CS_DIO_MUX 2 | |
| 45 | −#define DAS16CS_MISC1 4 | |
| 46 | −#define DAS16CS_MISC2 6 | |
| 47 | −#define DAS16CS_TIMER_BASE 8 | |
| 48 | −#define DAS16CS_DIO 16 | |
| 44 | +/* | |
| 45 | + * Register I/O map | |
| 46 | + */ | |
| 47 | +#define DAS16CS_AI_DATA_REG 0x00 | |
| 48 | +#define DAS16CS_AI_MUX_REG 0x02 | |
| 49 | +#define DAS16CS_AI_MUX_HI_CHAN(x) (((x) & 0xf) << 4) | |
| 50 | +#define DAS16CS_AI_MUX_LO_CHAN(x) (((x) & 0xf) << 0) | |
| 51 | +#define DAS16CS_AI_MUX_SINGLE_CHAN(x) (DAS16CS_AI_MUX_HI_CHAN(x) | \ | |
| 52 | + DAS16CS_AI_MUX_LO_CHAN(x)) | |
| 53 | +#define DAS16CS_MISC1_REG 0x04 | |
| 54 | +#define DAS16CS_MISC1_INTE BIT(15) /* 1=enable; 0=disable */ | |
| 55 | +#define DAS16CS_MISC1_INT_SRC(x) (((x) & 0x7) << 12) /* interrupt src */ | |
| 56 | +#define DAS16CS_MISC1_INT_SRC_NONE DAS16CS_MISC1_INT_SRC(0) | |
| 57 | +#define DAS16CS_MISC1_INT_SRC_PACER DAS16CS_MISC1_INT_SRC(1) | |
| 58 | +#define DAS16CS_MISC1_INT_SRC_EXT DAS16CS_MISC1_INT_SRC(2) | |
| 59 | +#define DAS16CS_MISC1_INT_SRC_FNE DAS16CS_MISC1_INT_SRC(3) | |
| 60 | +#define DAS16CS_MISC1_INT_SRC_FHF DAS16CS_MISC1_INT_SRC(4) | |
| 61 | +#define DAS16CS_MISC1_INT_SRC_EOS DAS16CS_MISC1_INT_SRC(5) | |
| 62 | +#define DAS16CS_MISC1_INT_SRC_MASK DAS16CS_MISC1_INT_SRC(7) | |
| 63 | +#define DAS16CS_MISC1_OVR BIT(10) /* ro - 1=FIFO overflow */ | |
| 64 | +#define DAS16CS_MISC1_AI_CONV(x) (((x) & 0x3) << 8) /* AI convert src */ | |
| 65 | +#define DAS16CS_MISC1_AI_CONV_SW DAS16CS_MISC1_AI_CONV(0) | |
| 66 | +#define DAS16CS_MISC1_AI_CONV_EXT_NEG DAS16CS_MISC1_AI_CONV(1) | |
| 67 | +#define DAS16CS_MISC1_AI_CONV_EXT_POS DAS16CS_MISC1_AI_CONV(2) | |
| 68 | +#define DAS16CS_MISC1_AI_CONV_PACER DAS16CS_MISC1_AI_CONV(3) | |
| 69 | +#define DAS16CS_MISC1_AI_CONV_MASK DAS16CS_MISC1_AI_CONV(3) | |
| 70 | +#define DAS16CS_MISC1_EOC BIT(7) /* ro - 0=busy; 1=ready */ | |
| 71 | +#define DAS16CS_MISC1_SEDIFF BIT(5) /* 0=diff; 1=se */ | |
| 72 | +#define DAS16CS_MISC1_INTB BIT(4) /* ro - 0=latched; 1=cleared */ | |
| 73 | +#define DAS16CS_MISC1_MA_MASK (0xf << 0) /* ro - current ai mux */ | |
| 74 | +#define DAS16CS_MISC1_DAC1CS BIT(3) /* wo - DAC1 chip select */ | |
| 75 | +#define DAS16CS_MISC1_DACCLK BIT(2) /* wo - Serial DAC clock */ | |
| 76 | +#define DAS16CS_MISC1_DACSD BIT(1) /* wo - Serial DAC data */ | |
| 77 | +#define DAS16CS_MISC1_DAC0CS BIT(0) /* wo - DAC0 chip select */ | |
| 78 | +#define DAS16CS_MISC1_DAC_MASK (0x0f << 0) | |
| 79 | +#define DAS16CS_MISC2_REG 0x06 | |
| 80 | +#define DAS16CS_MISC2_BME BIT(14) /* 1=burst enable; 0=disable */ | |
| 81 | +#define DAS16CS_MISC2_AI_GAIN(x) (((x) & 0xf) << 8) /* AI gain */ | |
| 82 | +#define DAS16CS_MISC2_AI_GAIN_1 DAS16CS_MISC2_AI_GAIN(4) /* +/-10V */ | |
| 83 | +#define DAS16CS_MISC2_AI_GAIN_2 DAS16CS_MISC2_AI_GAIN(0) /* +/-5V */ | |
| 84 | +#define DAS16CS_MISC2_AI_GAIN_4 DAS16CS_MISC2_AI_GAIN(1) /* +/-2.5V */ | |
| 85 | +#define DAS16CS_MISC2_AI_GAIN_8 DAS16CS_MISC2_AI_GAIN(2) /* +-1.25V */ | |
| 86 | +#define DAS16CS_MISC2_AI_GAIN_MASK DAS16CS_MISC2_AI_GAIN(0xf) | |
| 87 | +#define DAS16CS_MISC2_UDIR BIT(7) /* 1=dio7:4 output; 0=input */ | |
| 88 | +#define DAS16CS_MISC2_LDIR BIT(6) /* 1=dio3:0 output; 0=input */ | |
| 89 | +#define DAS16CS_MISC2_TRGPOL BIT(5) /* 1=active lo; 0=hi */ | |
| 90 | +#define DAS16CS_MISC2_TRGSEL BIT(4) /* 1=edge; 0=level */ | |
| 91 | +#define DAS16CS_MISC2_FFNE BIT(3) /* ro - 1=FIFO not empty */ | |
| 92 | +#define DAS16CS_MISC2_TRGCLR BIT(3) /* wo - 1=clr (monstable) */ | |
| 93 | +#define DAS16CS_MISC2_CLK2 BIT(2) /* 1=10 MHz; 0=1 MHz */ | |
| 94 | +#define DAS16CS_MISC2_CTR1 BIT(1) /* 1=int. 100 kHz; 0=ext. clk */ | |
| 95 | +#define DAS16CS_MISC2_TRG0 BIT(0) /* 1=enable; 0=disable */ | |
| 96 | +#define DAS16CS_TIMER_BASE 0x08 | |
| 97 | +#define DAS16CS_DIO_REG 0x10 | |
| 49 | 98 | |
| 50 | 99 | struct das16cs_board { |
| 51 | 100 | const char *name; |
| 52 | 101 | int device_id; |
| 53 | − int n_ao_chans; | |
| 102 | + unsigned int has_ao:1; | |
| 103 | + unsigned int has_4dio:1; | |
| 54 | 104 | }; |
| 55 | 105 | |
| 56 | 106 | static const struct das16cs_board das16cs_boards[] = { |
| 57 | 107 | { |
| 58 | 108 | .name = "PC-CARD DAS16/16-AO", |
| 59 | 109 | .device_id = 0x0039, |
| 60 | − .n_ao_chans = 2, | |
| 110 | + .has_ao = 1, | |
| 111 | + .has_4dio = 1, | |
| 61 | 112 | }, { |
| 62 | 113 | .name = "PCM-DAS16s/16", |
| 63 | 114 | .device_id = 0x4009, |
| 64 | − .n_ao_chans = 0, | |
| 65 | 115 | }, { |
| 66 | 116 | .name = "PC-CARD DAS16/16", |
| 67 | 117 | .device_id = 0x0000, /* unknown */ |
| 68 | − .n_ao_chans = 0, | |
| 69 | 118 | }, |
| 70 | 119 | }; |
| 71 | 120 | |
| 72 | 121 | struct das16cs_private { |
| 73 | − unsigned short status1; | |
| 74 | − unsigned short status2; | |
| 122 | + unsigned short misc1; | |
| 123 | + unsigned short misc2; | |
| 75 | 124 | }; |
| 76 | 125 | |
| 77 | 126 | static const struct comedi_lrange das16cs_ai_range = { |
| @@ -90,15 +139,16 @@ static int das16cs_ai_eoc(struct comedi_device *dev, · 12 unmodified lines | ||
| 90 | 139 | { |
| 91 | 140 | unsigned int status; |
| 92 | 141 | |
| 93 | − status = inw(dev->iobase + DAS16CS_MISC1); | |
| 94 | − if (status & 0x0080) | |
| 142 | + status = inw(dev->iobase + DAS16CS_MISC1_REG); | |
| 143 | + if (status & DAS16CS_MISC1_EOC) | |
| 95 | 144 | return 0; |
| 96 | 145 | return -EBUSY; |
| 97 | 146 | } |
| 98 | 147 | |
| 99 | −static int das16cs_ai_rinsn(struct comedi_device *dev, | |
| 100 | − struct comedi_subdevice *s, | |
| 101 | − struct comedi_insn *insn, unsigned int *data) | |
| 148 | +static int das16cs_ai_insn_read(struct comedi_device *dev, | |
| 149 | + struct comedi_subdevice *s, | |
| 150 | + struct comedi_insn *insn, | |
| 151 | + unsigned int *data) | |
| 102 | 152 | { |
| 103 | 153 | struct das16cs_private *devpriv = dev->private; |
| 104 | 154 | int chan = CR_CHAN(insn->chanspec); |
| @@ -107,37 +157,43 @@ static int das16cs_ai_rinsn(struct comedi_device *dev, · 2 unmodified lines | ||
| 107 | 157 | int ret; |
| 108 | 158 | int i; |
| 109 | 159 | |
| 110 | − outw(chan, dev->iobase + DAS16CS_DIO_MUX); | |
| 160 | + outw(DAS16CS_AI_MUX_SINGLE_CHAN(chan), | |
| 161 | + dev->iobase + DAS16CS_AI_MUX_REG); | |
| 111 | 162 | |
| 112 | − devpriv->status1 &= ~0xf320; | |
| 113 | − devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020; | |
| 114 | − outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); | |
| 163 | + /* disable interrupts, software convert */ | |
| 164 | + devpriv->misc1 &= ~(DAS16CS_MISC1_INTE | DAS16CS_MISC1_INT_SRC_MASK | | |
| 165 | + DAS16CS_MISC1_AI_CONV_MASK); | |
| 166 | + if (aref == AREF_DIFF) | |
| 167 | + devpriv->misc1 &= ~DAS16CS_MISC1_SEDIFF; | |
| 168 | + else | |
| 169 | + devpriv->misc1 |= DAS16CS_MISC1_SEDIFF; | |
| 170 | + outw(devpriv->misc1, dev->iobase + DAS16CS_MISC1_REG); | |
| 115 | 171 | |
| 116 | − devpriv->status2 &= ~0xff00; | |
| 172 | + devpriv->misc2 &= ~(DAS16CS_MISC2_BME | DAS16CS_MISC2_AI_GAIN_MASK); | |
| 117 | 173 | switch (range) { |
| 118 | 174 | case 0: |
| 119 | − devpriv->status2 |= 0x800; | |
| 175 | + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_1; | |
| 120 | 176 | break; |
| 121 | 177 | case 1: |
| 122 | − devpriv->status2 |= 0x000; | |
| 178 | + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_2; | |
| 123 | 179 | break; |
| 124 | 180 | case 2: |
| 125 | − devpriv->status2 |= 0x100; | |
| 181 | + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_4; | |
| 126 | 182 | break; |
| 127 | 183 | case 3: |
| 128 | − devpriv->status2 |= 0x200; | |
| 184 | + devpriv->misc2 |= DAS16CS_MISC2_AI_GAIN_8; | |
| 129 | 185 | break; |
| 130 | 186 | } |
| 131 | − outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); | |
| 187 | + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); | |
| 132 | 188 | |
| 133 | 189 | for (i = 0; i < insn->n; i++) { |
| 134 | − outw(0, dev->iobase + DAS16CS_ADC_DATA); | |
| 190 | + outw(0, dev->iobase + DAS16CS_AI_DATA_REG); | |
| 135 | 191 | |
| 136 | 192 | ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); |
| 137 | 193 | if (ret) |
| 138 | 194 | return ret; |
| 139 | 195 | |
| 140 | − data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); | |
| 196 | + data[i] = inw(dev->iobase + DAS16CS_AI_DATA_REG); | |
| 141 | 197 | } |
| 142 | 198 | |
| 143 | 199 | return i; |
| @@ -151,39 +207,43 @@ static int das16cs_ao_insn_write(struct comedi_device *dev, · 7 unmodified lines | ||
| 151 | 207 | struct das16cs_private *devpriv = dev->private; |
| 152 | 208 | unsigned int chan = CR_CHAN(insn->chanspec); |
| 153 | 209 | unsigned int val = s->readback[chan]; |
| 154 | − unsigned short status1; | |
| 210 | + unsigned short misc1; | |
| 155 | 211 | int bit; |
| 156 | 212 | int i; |
| 157 | 213 | |
| 158 | 214 | for (i = 0; i < insn->n; i++) { |
| 159 | 215 | val = data[i]; |
| 160 | 216 | |
| 161 | − outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); | |
| 217 | + outw(devpriv->misc1, dev->iobase + DAS16CS_MISC1_REG); | |
| 162 | 218 | udelay(1); |
| 163 | 219 | |
| 164 | − status1 = devpriv->status1 & ~0xf; | |
| 220 | + /* raise the DACxCS line for the non-selected channel */ | |
| 221 | + misc1 = devpriv->misc1 & ~DAS16CS_MISC1_DAC_MASK; | |
| 165 | 222 | if (chan) |
| 166 | − status1 |= 0x0001; | |
| 223 | + misc1 |= DAS16CS_MISC1_DAC0CS; | |
| 167 | 224 | else |
| 168 | − status1 |= 0x0008; | |
| 225 | + misc1 |= DAS16CS_MISC1_DAC1CS; | |
| 169 | 226 | |
| 170 | − outw(status1, dev->iobase + DAS16CS_MISC1); | |
| 227 | + outw(misc1, dev->iobase + DAS16CS_MISC1_REG); | |
| 171 | 228 | udelay(1); |
| 172 | 229 | |
| 173 | 230 | for (bit = 15; bit >= 0; bit--) { |
| 174 | − int b = (val >> bit) & 0x1; | |
| 175 | − | |
| 176 | − b <<= 1; | |
| 177 | − outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1); | |
| 231 | + if ((val >> bit) & 0x1) | |
| 232 | + misc1 |= DAS16CS_MISC1_DACSD; | |
| 233 | + else | |
| 234 | + misc1 &= ~DAS16CS_MISC1_DACSD; | |
| 235 | + outw(misc1, dev->iobase + DAS16CS_MISC1_REG); | |
| 178 | 236 | udelay(1); |
| 179 | − outw(status1 | b | 0x0004, dev->iobase + DAS16CS_MISC1); | |
| 237 | + outw(misc1 | DAS16CS_MISC1_DACCLK, | |
| 238 | + dev->iobase + DAS16CS_MISC1_REG); | |
| 180 | 239 | udelay(1); |
| 181 | 240 | } |
| 182 | 241 | /* |
| 183 | 242 | * Make both DAC0CS and DAC1CS high to load |
| 184 | 243 | * the new data and update analog the output |
| 185 | 244 | */ |
| 186 | − outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1); | |
| 245 | + outw(misc1 | DAS16CS_MISC1_DAC0CS | DAS16CS_MISC1_DAC1CS, | |
| 246 | + dev->iobase + DAS16CS_MISC1_REG); | |
| 187 | 247 | } |
| 188 | 248 | s->readback[chan] = val; |
| 189 | 249 | |
| @@ -196,9 +256,9 @@ static int das16cs_dio_insn_bits(struct comedi_device *dev, · 6 unmodified lines | ||
| 196 | 256 | unsigned int *data) |
| 197 | 257 | { |
| 198 | 258 | if (comedi_dio_update_state(s, data)) |
| 199 | − outw(s->state, dev->iobase + DAS16CS_DIO); | |
| 259 | + outw(s->state, dev->iobase + DAS16CS_DIO_REG); | |
| 200 | 260 | |
| 201 | − data[1] = inw(dev->iobase + DAS16CS_DIO); | |
| 261 | + data[1] = inw(dev->iobase + DAS16CS_DIO_REG); | |
| 202 | 262 | |
| 203 | 263 | return insn->n; |
| 204 | 264 | } |
| @@ -222,11 +282,52 @@ static int das16cs_dio_insn_config(struct comedi_device *dev, · 17 unmodified lines | ||
| 222 | 282 | if (ret) |
| 223 | 283 | return ret; |
| 224 | 284 | |
| 225 | − devpriv->status2 &= ~0x00c0; | |
| 226 | − devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0; | |
| 227 | − devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0; | |
| 285 | + if (s->io_bits & 0xf0) | |
| 286 | + devpriv->misc2 |= DAS16CS_MISC2_UDIR; | |
| 287 | + else | |
| 288 | + devpriv->misc2 &= ~DAS16CS_MISC2_UDIR; | |
| 289 | + if (s->io_bits & 0x0f) | |
| 290 | + devpriv->misc2 |= DAS16CS_MISC2_LDIR; | |
| 291 | + else | |
| 292 | + devpriv->misc2 &= ~DAS16CS_MISC2_LDIR; | |
| 293 | + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); | |
| 294 | + | |
| 295 | + return insn->n; | |
| 296 | +} | |
| 297 | + | |
| 298 | +static int das16cs_counter_insn_config(struct comedi_device *dev, | |
| 299 | + struct comedi_subdevice *s, | |
| 300 | + struct comedi_insn *insn, | |
| 301 | + unsigned int *data) | |
| 302 | +{ | |
| 303 | + struct das16cs_private *devpriv = dev->private; | |
| 228 | 304 | |
| 229 | − outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); | |
| 305 | + switch (data[0]) { | |
| 306 | + case INSN_CONFIG_SET_CLOCK_SRC: | |
| 307 | + switch (data[1]) { | |
| 308 | + case 0: /* internal 100 kHz */ | |
| 309 | + devpriv->misc2 |= DAS16CS_MISC2_CTR1; | |
| 310 | + break; | |
| 311 | + case 1: /* external */ | |
| 312 | + devpriv->misc2 &= ~DAS16CS_MISC2_CTR1; | |
| 313 | + break; | |
| 314 | + default: | |
| 315 | + return -EINVAL; | |
| 316 | + } | |
| 317 | + outw(devpriv->misc2, dev->iobase + DAS16CS_MISC2_REG); | |
| 318 | + break; | |
| 319 | + case INSN_CONFIG_GET_CLOCK_SRC: | |
| 320 | + if (devpriv->misc2 & DAS16CS_MISC2_CTR1) { | |
| 321 | + data[1] = 0; | |
| 322 | + data[2] = I8254_OSC_BASE_100KHZ; | |
| 323 | + } else { | |
| 324 | + data[1] = 1; | |
| 325 | + data[2] = 0; /* unknown */ | |
| 326 | + } | |
| 327 | + break; | |
| 328 | + default: | |
| 329 | + return -EINVAL; | |
| 330 | + } | |
| 230 | 331 | |
| 231 | 332 | return insn->n; |
| 232 | 333 | } |
| @@ -278,26 +379,25 @@ static int das16cs_auto_attach(struct comedi_device *dev, · 45 unmodified lines | ||
| 278 | 379 | if (!dev->pacer) |
| 279 | 380 | return -ENOMEM; |
| 280 | 381 | |
| 281 | − ret = comedi_alloc_subdevices(dev, 3); | |
| 382 | + ret = comedi_alloc_subdevices(dev, 4); | |
| 282 | 383 | if (ret) |
| 283 | 384 | return ret; |
| 284 | 385 | |
| 386 | + /* Analog Input subdevice */ | |
| 285 | 387 | s = &dev->subdevices[0]; |
| 286 | − /* analog input subdevice */ | |
| 287 | 388 | s->type = COMEDI_SUBD_AI; |
| 288 | − s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; | |
| 389 | + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; | |
| 289 | 390 | s->n_chan = 16; |
| 290 | 391 | s->maxdata = 0xffff; |
| 291 | 392 | s->range_table = &das16cs_ai_range; |
| 292 | − s->len_chanlist = 16; | |
| 293 | − s->insn_read = das16cs_ai_rinsn; | |
| 393 | + s->insn_read = das16cs_ai_insn_read; | |
| 294 | 394 | |
| 395 | + /* Analog Output subdevice */ | |
| 295 | 396 | s = &dev->subdevices[1]; |
| 296 | − /* analog output subdevice */ | |
| 297 | − if (board->n_ao_chans) { | |
| 397 | + if (board->has_ao) { | |
| 298 | 398 | s->type = COMEDI_SUBD_AO; |
| 299 | 399 | s->subdev_flags = SDF_WRITABLE; |
| 300 | − s->n_chan = board->n_ao_chans; | |
| 400 | + s->n_chan = 2; | |
| 301 | 401 | s->maxdata = 0xffff; |
| 302 | 402 | s->range_table = &range_bipolar10; |
| 303 | 403 | s->insn_write = &das16cs_ao_insn_write; |
| @@ -309,16 +409,26 @@ static int das16cs_auto_attach(struct comedi_device *dev, · 5 unmodified lines | ||
| 309 | 409 | s->type = COMEDI_SUBD_UNUSED; |
| 310 | 410 | } |
| 311 | 411 | |
| 412 | + /* Digital I/O subdevice */ | |
| 312 | 413 | s = &dev->subdevices[2]; |
| 313 | − /* digital i/o subdevice */ | |
| 314 | 414 | s->type = COMEDI_SUBD_DIO; |
| 315 | 415 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; |
| 316 | − s->n_chan = 8; | |
| 416 | + s->n_chan = board->has_4dio ? 4 : 8; | |
| 317 | 417 | s->maxdata = 1; |
| 318 | 418 | s->range_table = &range_digital; |
| 319 | 419 | s->insn_bits = das16cs_dio_insn_bits; |
| 320 | 420 | s->insn_config = das16cs_dio_insn_config; |
| 321 | 421 | |
| 422 | + /* Counter subdevice (8254) */ | |
| 423 | + s = &dev->subdevices[3]; | |
| 424 | + comedi_8254_subdevice_init(s, dev->pacer); | |
| 425 | + | |
| 426 | + dev->pacer->insn_config = das16cs_counter_insn_config; | |
| 427 | + | |
| 428 | + /* counters 1 and 2 are used internally for the pacer */ | |
| 429 | + comedi_8254_set_busy(dev->pacer, 1, true); | |
| 430 | + comedi_8254_set_busy(dev->pacer, 2, true); | |
| 431 | + | |
| 322 | 432 | return 0; |
| 323 | 433 | } |
| 324 | 434 | |
| @@ -1,65 +1,64 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/cb_pcidas.c | |
| 2 | + * cb_pcidas.c | |
| 3 | + * Developed by Ivan Martinez and Frank Mori Hess, with valuable help from | |
| 4 | + * David Schleef and the rest of the Comedi developers comunity. | |
| 5 | + * | |
| 6 | + * Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk> | |
| 7 | + * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 8 | + * | |
| 9 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 10 | + * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> | |
| 11 | + * | |
| 12 | + * This program is free software; you can redistribute it and/or modify | |
| 13 | + * it under the terms of the GNU General Public License as published by | |
| 14 | + * the Free Software Foundation; either version 2 of the License, or | |
| 15 | + * (at your option) any later version. | |
| 16 | + * | |
| 17 | + * This program is distributed in the hope that it will be useful, | |
| 18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 20 | + * GNU General Public License for more details. | |
| 21 | + */ | |
| 3 | 22 | |
| 4 | − Developed by Ivan Martinez and Frank Mori Hess, with valuable help from | |
| 5 | − David Schleef and the rest of the Comedi developers comunity. | |
| 6 | − | |
| 7 | − Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk> | |
| 8 | − Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 9 | − | |
| 10 | − COMEDI - Linux Control and Measurement Device Interface | |
| 11 | − Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> | |
| 12 | − | |
| 13 | − This program is free software; you can redistribute it and/or modify | |
| 14 | − it under the terms of the GNU General Public License as published by | |
| 15 | − the Free Software Foundation; either version 2 of the License, or | |
| 16 | − (at your option) any later version. | |
| 17 | − | |
| 18 | − This program is distributed in the hope that it will be useful, | |
| 19 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 20 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 21 | − GNU General Public License for more details. | |
| 22 | −*/ | |
| 23 | −/* | |
| 24 | −Driver: cb_pcidas | |
| 25 | −Description: MeasurementComputing PCI-DAS series | |
| 26 | − with the AMCC S5933 PCI controller | |
| 27 | −Author: Ivan Martinez <imr@oersted.dtu.dk>, | |
| 28 | − Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 29 | −Updated: 2003-3-11 | |
| 30 | −Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas), | |
| 31 | − PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, | |
| 32 | − PCI-DAS1000, PCI-DAS1001, PCI_DAS1002 | |
| 33 | − | |
| 34 | −Status: | |
| 35 | − There are many reports of the driver being used with most of the | |
| 36 | − supported cards. Despite no detailed log is maintained, it can | |
| 37 | − be said that the driver is quite tested and stable. | |
| 38 | − | |
| 39 | − The boards may be autocalibrated using the comedi_calibrate | |
| 40 | − utility. | |
| 41 | − | |
| 42 | −Configuration options: not applicable, uses PCI auto config | |
| 43 | − | |
| 44 | −For commands, the scanned channels must be consecutive | |
| 45 | −(i.e. 4-5-6-7, 2-3-4,...), and must all have the same | |
| 46 | −range and aref. | |
| 47 | − | |
| 48 | −AI Triggering: | |
| 49 | − For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used. | |
| 50 | − For 1602 series, the start_arg is interpreted as follows: | |
| 51 | − start_arg == 0 => gated trigger (level high) | |
| 52 | − start_arg == CR_INVERT => gated trigger (level low) | |
| 53 | − start_arg == CR_EDGE => Rising edge | |
| 54 | − start_arg == CR_EDGE | CR_INVERT => Falling edge | |
| 55 | − For the other boards the trigger will be done on rising edge | |
| 56 | −*/ | |
| 57 | 23 | /* |
| 24 | + * Driver: cb_pcidas | |
| 25 | + * Description: MeasurementComputing PCI-DAS series | |
| 26 | + * with the AMCC S5933 PCI controller | |
| 27 | + * Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas), | |
| 28 | + * PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, | |
| 29 | + * PCI-DAS1000, PCI-DAS1001, PCI_DAS1002 | |
| 30 | + * Author: Ivan Martinez <imr@oersted.dtu.dk>, | |
| 31 | + * Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 32 | + * Updated: 2003-3-11 | |
| 33 | + * | |
| 34 | + * Status: | |
| 35 | + * There are many reports of the driver being used with most of the | |
| 36 | + * supported cards. Despite no detailed log is maintained, it can | |
| 37 | + * be said that the driver is quite tested and stable. | |
| 38 | + * | |
| 39 | + * The boards may be autocalibrated using the comedi_calibrate | |
| 40 | + * utility. | |
| 41 | + * | |
| 42 | + * Configuration options: not applicable, uses PCI auto config | |
| 43 | + * | |
| 44 | + * For commands, the scanned channels must be consecutive | |
| 45 | + * (i.e. 4-5-6-7, 2-3-4,...), and must all have the same | |
| 46 | + * range and aref. | |
| 47 | + * | |
| 48 | + * AI Triggering: | |
| 49 | + * For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used. | |
| 50 | + * For 1602 series, the start_arg is interpreted as follows: | |
| 51 | + * start_arg == 0 => gated trigger (level high) | |
| 52 | + * start_arg == CR_INVERT => gated trigger (level low) | |
| 53 | + * start_arg == CR_EDGE => Rising edge | |
| 54 | + * start_arg == CR_EDGE | CR_INVERT => Falling edge | |
| 55 | + * For the other boards the trigger will be done on rising edge | |
| 56 | + */ | |
| 58 | 57 | |
| 59 | −TODO: | |
| 60 | − | |
| 61 | −analog triggering on 1602 series | |
| 62 | −*/ | |
| 58 | +/* | |
| 59 | + * TODO: | |
| 60 | + * analog triggering on 1602 series | |
| 61 | + */ | |
| 63 | 62 | |
| 64 | 63 | #include <linux/module.h> |
| 65 | 64 | #include <linux/delay.h> |
| @@ -73,109 +72,107 @@ analog triggering on 1602 series · 7 unmodified lines | ||
| 73 | 72 | |
| 74 | 73 | #define AI_BUFFER_SIZE 1024 /* max ai fifo size */ |
| 75 | 74 | #define AO_BUFFER_SIZE 1024 /* max ao fifo size */ |
| 76 | −#define NUM_CHANNELS_8800 8 | |
| 77 | −#define NUM_CHANNELS_7376 1 | |
| 78 | −#define NUM_CHANNELS_8402 2 | |
| 79 | −#define NUM_CHANNELS_DAC08 1 | |
| 80 | − | |
| 81 | −/* Control/Status registers */ | |
| 82 | −#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */ | |
| 83 | −#define INT_EOS 0x1 /* int end of scan */ | |
| 84 | −#define INT_FHF 0x2 /* int fifo half full */ | |
| 85 | −#define INT_FNE 0x3 /* int fifo not empty */ | |
| 86 | −#define INT_MASK 0x3 /* mask of int select bits */ | |
| 87 | −#define INTE 0x4 /* int enable */ | |
| 88 | −#define DAHFIE 0x8 /* dac half full int enable */ | |
| 89 | −#define EOAIE 0x10 /* end of acq. int enable */ | |
| 90 | −#define DAHFI 0x20 /* dac half full status / clear */ | |
| 91 | −#define EOAI 0x40 /* end of acq. int status / clear */ | |
| 92 | −#define INT 0x80 /* int status / clear */ | |
| 93 | −#define EOBI 0x200 /* end of burst int status */ | |
| 94 | −#define ADHFI 0x400 /* half-full int status */ | |
| 95 | −#define ADNEI 0x800 /* fifo not empty int status (latch) */ | |
| 96 | −#define ADNE 0x1000 /* fifo not empty status (realtime) */ | |
| 97 | −#define DAEMIE 0x1000 /* dac empty int enable */ | |
| 98 | −#define LADFUL 0x2000 /* fifo overflow / clear */ | |
| 99 | −#define DAEMI 0x4000 /* dac fifo empty int status / clear */ | |
| 100 | − | |
| 101 | −#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL reg */ | |
| 102 | −#define BEGIN_SCAN(x) ((x) & 0xf) | |
| 103 | −#define END_SCAN(x) (((x) & 0xf) << 4) | |
| 104 | −#define GAIN_BITS(x) (((x) & 0x3) << 8) | |
| 105 | −#define UNIP 0x800 /* Analog front-end unipolar mode */ | |
| 106 | −#define SE 0x400 /* Inputs in single-ended mode */ | |
| 107 | −#define PACER_MASK 0x3000 /* pacer source bits */ | |
| 108 | −#define PACER_INT 0x1000 /* int. pacer */ | |
| 109 | −#define PACER_EXT_FALL 0x2000 /* ext. falling edge */ | |
| 110 | −#define PACER_EXT_RISE 0x3000 /* ext. rising edge */ | |
| 111 | −#define EOC 0x4000 /* adc not busy */ | |
| 112 | − | |
| 113 | −#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */ | |
| 114 | −#define SW_TRIGGER 0x1 /* software start trigger */ | |
| 115 | −#define EXT_TRIGGER 0x2 /* ext. start trigger */ | |
| 116 | −#define ANALOG_TRIGGER 0x3 /* ext. analog trigger */ | |
| 117 | −#define TRIGGER_MASK 0x3 /* start trigger mask */ | |
| 118 | −#define TGPOL 0x04 /* invert trigger (1602 only) */ | |
| 119 | −#define TGSEL 0x08 /* edge/level trigerred (1602 only) */ | |
| 120 | −#define TGEN 0x10 /* enable external start trigger */ | |
| 121 | −#define BURSTE 0x20 /* burst mode enable */ | |
| 122 | −#define XTRCL 0x80 /* clear external trigger */ | |
| 123 | − | |
| 124 | −#define CALIBRATION_REG 6 /* CALIBRATION register */ | |
| 125 | −#define SELECT_8800_BIT 0x100 /* select 8800 caldac */ | |
| 126 | −#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */ | |
| 127 | −#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */ | |
| 128 | −#define CAL_SRC_BITS(x) (((x) & 0x7) << 11) | |
| 129 | −#define CAL_EN_BIT 0x4000 /* calibration source enable */ | |
| 130 | −#define SERIAL_DATA_IN_BIT 0x8000 /* serial data bit going to caldac */ | |
| 131 | − | |
| 132 | −#define DAC_CSR 0x8 /* dac control and status register */ | |
| 133 | −#define DACEN 0x02 /* dac enable */ | |
| 134 | −#define DAC_MODE_UPDATE_BOTH 0x80 /* update both dacs */ | |
| 135 | − | |
| 136 | −static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range) | |
| 137 | −{ | |
| 138 | − return (range & 0x3) << (8 + 2 * (channel & 0x1)); | |
| 139 | −} | |
| 140 | − | |
| 141 | −static inline unsigned int DAC_RANGE_MASK(unsigned int channel) | |
| 142 | −{ | |
| 143 | − return 0x3 << (8 + 2 * (channel & 0x1)); | |
| 144 | −}; | |
| 145 | − | |
| 146 | −/* bits for 1602 series only */ | |
| 147 | −#define DAC_EMPTY 0x1 /* fifo empty, read, write clear */ | |
| 148 | −#define DAC_START 0x4 /* start/arm fifo operations */ | |
| 149 | −#define DAC_PACER_MASK 0x18 /* bits that set pacer source */ | |
| 150 | −#define DAC_PACER_INT 0x8 /* int. pacing */ | |
| 151 | −#define DAC_PACER_EXT_FALL 0x10 /* ext. pacing, falling edge */ | |
| 152 | −#define DAC_PACER_EXT_RISE 0x18 /* ext. pacing, rising edge */ | |
| 153 | − | |
| 154 | −static inline unsigned int DAC_CHAN_EN(unsigned int channel) | |
| 155 | −{ | |
| 156 | − return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */ | |
| 157 | −}; | |
| 158 | − | |
| 159 | −/* analog input fifo */ | |
| 160 | −#define ADCDATA 0 /* ADC DATA register */ | |
| 161 | −#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */ | |
| 162 | 75 | |
| 163 | −/* pacer, counter, dio registers */ | |
| 164 | −#define ADC8254 0 | |
| 165 | −#define DIO_8255 4 | |
| 166 | −#define DAC8254 8 | |
| 76 | +/* | |
| 77 | + * PCI BAR1 Register map (devpriv->pcibar1) | |
| 78 | + */ | |
| 79 | +#define PCIDAS_CTRL_REG 0x00 /* INTERRUPT / ADC FIFO register */ | |
| 80 | +#define PCIDAS_CTRL_INT(x) (((x) & 0x3) << 0) | |
| 81 | +#define PCIDAS_CTRL_INT_NONE PCIDAS_CTRL_INT(0) /* no int selected */ | |
| 82 | +#define PCIDAS_CTRL_INT_EOS PCIDAS_CTRL_INT(1) /* int on end of scan */ | |
| 83 | +#define PCIDAS_CTRL_INT_FHF PCIDAS_CTRL_INT(2) /* int on fifo half full */ | |
| 84 | +#define PCIDAS_CTRL_INT_FNE PCIDAS_CTRL_INT(3) /* int on fifo not empty */ | |
| 85 | +#define PCIDAS_CTRL_INT_MASK PCIDAS_CTRL_INT(3) /* mask of int select bits */ | |
| 86 | +#define PCIDAS_CTRL_INTE BIT(2) /* int enable */ | |
| 87 | +#define PCIDAS_CTRL_DAHFIE BIT(3) /* dac half full int enable */ | |
| 88 | +#define PCIDAS_CTRL_EOAIE BIT(4) /* end of acq. int enable */ | |
| 89 | +#define PCIDAS_CTRL_DAHFI BIT(5) /* dac half full status / clear */ | |
| 90 | +#define PCIDAS_CTRL_EOAI BIT(6) /* end of acq. int status / clear */ | |
| 91 | +#define PCIDAS_CTRL_INT_CLR BIT(7) /* int status / clear */ | |
| 92 | +#define PCIDAS_CTRL_EOBI BIT(9) /* end of burst int status */ | |
| 93 | +#define PCIDAS_CTRL_ADHFI BIT(10) /* half-full int status */ | |
| 94 | +#define PCIDAS_CTRL_ADNEI BIT(11) /* fifo not empty int status (latch) */ | |
| 95 | +#define PCIDAS_CTRL_ADNE BIT(12) /* fifo not empty status (realtime) */ | |
| 96 | +#define PCIDAS_CTRL_DAEMIE BIT(12) /* dac empty int enable */ | |
| 97 | +#define PCIDAS_CTRL_LADFUL BIT(13) /* fifo overflow / clear */ | |
| 98 | +#define PCIDAS_CTRL_DAEMI BIT(14) /* dac fifo empty int status / clear */ | |
| 99 | + | |
| 100 | +#define PCIDAS_CTRL_AI_INT (PCIDAS_CTRL_EOAI | PCIDAS_CTRL_EOBI | \ | |
| 101 | + PCIDAS_CTRL_ADHFI | PCIDAS_CTRL_ADNEI | \ | |
| 102 | + PCIDAS_CTRL_LADFUL) | |
| 103 | +#define PCIDAS_CTRL_AO_INT (PCIDAS_CTRL_DAHFI | PCIDAS_CTRL_DAEMI) | |
| 104 | + | |
| 105 | +#define PCIDAS_AI_REG 0x02 /* ADC CHANNEL MUX AND CONTROL reg */ | |
| 106 | +#define PCIDAS_AI_FIRST(x) ((x) & 0xf) | |
| 107 | +#define PCIDAS_AI_LAST(x) (((x) & 0xf) << 4) | |
| 108 | +#define PCIDAS_AI_CHAN(x) (PCIDAS_AI_FIRST(x) | PCIDAS_AI_LAST(x)) | |
| 109 | +#define PCIDAS_AI_GAIN(x) (((x) & 0x3) << 8) | |
| 110 | +#define PCIDAS_AI_SE BIT(10) /* Inputs in single-ended mode */ | |
| 111 | +#define PCIDAS_AI_UNIP BIT(11) /* Analog front-end unipolar mode */ | |
| 112 | +#define PCIDAS_AI_PACER(x) (((x) & 0x3) << 12) | |
| 113 | +#define PCIDAS_AI_PACER_SW PCIDAS_AI_PACER(0) /* software pacer */ | |
| 114 | +#define PCIDAS_AI_PACER_INT PCIDAS_AI_PACER(1) /* int. pacer */ | |
| 115 | +#define PCIDAS_AI_PACER_EXTN PCIDAS_AI_PACER(2) /* ext. falling edge */ | |
| 116 | +#define PCIDAS_AI_PACER_EXTP PCIDAS_AI_PACER(3) /* ext. rising edge */ | |
| 117 | +#define PCIDAS_AI_PACER_MASK PCIDAS_AI_PACER(3) /* pacer source bits */ | |
| 118 | +#define PCIDAS_AI_EOC BIT(14) /* adc not busy */ | |
| 119 | + | |
| 120 | +#define PCIDAS_TRIG_REG 0x04 /* TRIGGER CONTROL/STATUS register */ | |
| 121 | +#define PCIDAS_TRIG_SEL(x) (((x) & 0x3) << 0) | |
| 122 | +#define PCIDAS_TRIG_SEL_NONE PCIDAS_TRIG_SEL(0) /* no start trigger */ | |
| 123 | +#define PCIDAS_TRIG_SEL_SW PCIDAS_TRIG_SEL(1) /* software start trigger */ | |
| 124 | +#define PCIDAS_TRIG_SEL_EXT PCIDAS_TRIG_SEL(2) /* ext. start trigger */ | |
| 125 | +#define PCIDAS_TRIG_SEL_ANALOG PCIDAS_TRIG_SEL(3) /* ext. analog trigger */ | |
| 126 | +#define PCIDAS_TRIG_SEL_MASK PCIDAS_TRIG_SEL(3) /* start trigger mask */ | |
| 127 | +#define PCIDAS_TRIG_POL BIT(2) /* invert trigger (1602 only) */ | |
| 128 | +#define PCIDAS_TRIG_MODE BIT(3) /* edge/level trigerred (1602 only) */ | |
| 129 | +#define PCIDAS_TRIG_EN BIT(4) /* enable external start trigger */ | |
| 130 | +#define PCIDAS_TRIG_BURSTE BIT(5) /* burst mode enable */ | |
| 131 | +#define PCIDAS_TRIG_CLR BIT(7) /* clear external trigger */ | |
| 132 | + | |
| 133 | +#define PCIDAS_CALIB_REG 0x06 /* CALIBRATION register */ | |
| 134 | +#define PCIDAS_CALIB_8800_SEL BIT(8) /* select 8800 caldac */ | |
| 135 | +#define PCIDAS_CALIB_TRIM_SEL BIT(9) /* select ad7376 trim pot */ | |
| 136 | +#define PCIDAS_CALIB_DAC08_SEL BIT(10) /* select dac08 caldac */ | |
| 137 | +#define PCIDAS_CALIB_SRC(x) (((x) & 0x7) << 11) | |
| 138 | +#define PCIDAS_CALIB_EN BIT(14) /* calibration source enable */ | |
| 139 | +#define PCIDAS_CALIB_DATA BIT(15) /* serial data bit going to caldac */ | |
| 140 | + | |
| 141 | +#define PCIDAS_AO_REG 0x08 /* dac control and status register */ | |
| 142 | +#define PCIDAS_AO_EMPTY BIT(0) /* fifo empty, write clear (1602) */ | |
| 143 | +#define PCIDAS_AO_DACEN BIT(1) /* dac enable */ | |
| 144 | +#define PCIDAS_AO_START BIT(2) /* start/arm fifo (1602) */ | |
| 145 | +#define PCIDAS_AO_PACER(x) (((x) & 0x3) << 3) /* (1602) */ | |
| 146 | +#define PCIDAS_AO_PACER_SW PCIDAS_AO_PACER(0) /* software pacer */ | |
| 147 | +#define PCIDAS_AO_PACER_INT PCIDAS_AO_PACER(1) /* int. pacer */ | |
| 148 | +#define PCIDAS_AO_PACER_EXTN PCIDAS_AO_PACER(2) /* ext. falling edge */ | |
| 149 | +#define PCIDAS_AO_PACER_EXTP PCIDAS_AO_PACER(3) /* ext. rising edge */ | |
| 150 | +#define PCIDAS_AO_PACER_MASK PCIDAS_AO_PACER(3) /* pacer source bits */ | |
| 151 | +#define PCIDAS_AO_CHAN_EN(c) BIT(5 + ((c) & 0x1)) | |
| 152 | +#define PCIDAS_AO_CHAN_MASK (PCIDAS_AO_CHAN_EN(0) | PCIDAS_AO_CHAN_EN(1)) | |
| 153 | +#define PCIDAS_AO_UPDATE_BOTH BIT(7) /* update both dacs */ | |
| 154 | +#define PCIDAS_AO_RANGE(c, r) (((r) & 0x3) << (8 + 2 * ((c) & 0x1))) | |
| 155 | +#define PCIDAS_AO_RANGE_MASK(c) PCIDAS_AO_RANGE((c), 0x3) | |
| 167 | 156 | |
| 168 | −/* analog output registers for 100x, 1200 series */ | |
| 169 | −static inline unsigned int DAC_DATA_REG(unsigned int channel) | |
| 170 | −{ | |
| 171 | − return 2 * (channel & 0x1); | |
| 172 | −} | |
| 157 | +/* | |
| 158 | + * PCI BAR2 Register map (devpriv->pcibar2) | |
| 159 | + */ | |
| 160 | +#define PCIDAS_AI_DATA_REG 0x00 | |
| 161 | +#define PCIDAS_AI_FIFO_CLR_REG 0x02 | |
| 173 | 162 | |
| 174 | −/* analog output registers for 1602 series*/ | |
| 175 | −#define DACDATA 0 /* DAC DATA register */ | |
| 176 | −#define DACFIFOCLR 2 /* DAC FIFO CLEAR */ | |
| 163 | +/* | |
| 164 | + * PCI BAR3 Register map (dev->iobase) | |
| 165 | + */ | |
| 166 | +#define PCIDAS_AI_8254_BASE 0x00 | |
| 167 | +#define PCIDAS_8255_BASE 0x04 | |
| 168 | +#define PCIDAS_AO_8254_BASE 0x08 | |
| 177 | 169 | |
| 178 | −#define IS_UNIPOLAR 0x4 /* unipolar range mask */ | |
| 170 | +/* | |
| 171 | + * PCI BAR4 Register map (devpriv->pcibar4) | |
| 172 | + */ | |
| 173 | +#define PCIDAS_AO_DATA_REG(x) (0x00 + ((x) * 2)) | |
| 174 | +#define PCIDAS_AO_FIFO_REG 0x00 | |
| 175 | +#define PCIDAS_AO_FIFO_CLR_REG 0x02 | |
| 179 | 176 | |
| 180 | 177 | /* analog input ranges for most boards */ |
| 181 | 178 | static const struct comedi_lrange cb_pcidas_ranges = { |
| @@ -215,11 +212,6 @@ static const struct comedi_lrange cb_pcidas_ao_ranges = { · 33 unmodified lines | ||
| 215 | 212 | } |
| 216 | 213 | }; |
| 217 | 214 | |
| 218 | −enum trimpot_model { | |
| 219 | − AD7376, | |
| 220 | − AD8402, | |
| 221 | −}; | |
| 222 | − | |
| 223 | 215 | enum cb_pcidas_boardid { |
| 224 | 216 | BOARD_PCIDAS1602_16, |
| 225 | 217 | BOARD_PCIDAS1200, |
| @@ -233,132 +225,97 @@ enum cb_pcidas_boardid { · 7 unmodified lines | ||
| 233 | 225 | |
| 234 | 226 | struct cb_pcidas_board { |
| 235 | 227 | const char *name; |
| 236 | − int ai_nchan; /* Inputs in single-ended mode */ | |
| 237 | − int ai_bits; /* analog input resolution */ | |
| 238 | 228 | int ai_speed; /* fastest conversion period in ns */ |
| 239 | − int ao_nchan; /* number of analog out channels */ | |
| 240 | − int has_ao_fifo; /* analog output has fifo */ | |
| 241 | 229 | int ao_scan_speed; /* analog output scan speed for 1602 series */ |
| 242 | 230 | int fifo_size; /* number of samples fifo can hold */ |
| 243 | − const struct comedi_lrange *ranges; | |
| 244 | − enum trimpot_model trimpot; | |
| 245 | − unsigned has_dac08:1; | |
| 246 | − unsigned is_1602:1; | |
| 231 | + unsigned int is_16bit; /* ai/ao is 1=16-bit; 0=12-bit */ | |
| 232 | + unsigned int use_alt_range:1; /* use alternate ai range table */ | |
| 233 | + unsigned int has_ao:1; /* has 2 analog output channels */ | |
| 234 | + unsigned int has_ao_fifo:1; /* analog output has fifo */ | |
| 235 | + unsigned int has_ad8402:1; /* trimpot type 1=AD8402; 0=AD7376 */ | |
| 236 | + unsigned int has_dac08:1; | |
| 237 | + unsigned int is_1602:1; | |
| 247 | 238 | }; |
| 248 | 239 | |
| 249 | 240 | static const struct cb_pcidas_board cb_pcidas_boards[] = { |
| 250 | 241 | [BOARD_PCIDAS1602_16] = { |
| 251 | 242 | .name = "pci-das1602/16", |
| 252 | − .ai_nchan = 16, | |
| 253 | − .ai_bits = 16, | |
| 254 | 243 | .ai_speed = 5000, |
| 255 | − .ao_nchan = 2, | |
| 256 | − .has_ao_fifo = 1, | |
| 257 | 244 | .ao_scan_speed = 10000, |
| 258 | 245 | .fifo_size = 512, |
| 259 | − .ranges = &cb_pcidas_ranges, | |
| 260 | − .trimpot = AD8402, | |
| 246 | + .is_16bit = 1, | |
| 247 | + .has_ao = 1, | |
| 248 | + .has_ao_fifo = 1, | |
| 249 | + .has_ad8402 = 1, | |
| 261 | 250 | .has_dac08 = 1, |
| 262 | 251 | .is_1602 = 1, |
| 263 | 252 | }, |
| 264 | 253 | [BOARD_PCIDAS1200] = { |
| 265 | 254 | .name = "pci-das1200", |
| 266 | − .ai_nchan = 16, | |
| 267 | − .ai_bits = 12, | |
| 268 | 255 | .ai_speed = 3200, |
| 269 | − .ao_nchan = 2, | |
| 270 | 256 | .fifo_size = 1024, |
| 271 | − .ranges = &cb_pcidas_ranges, | |
| 272 | − .trimpot = AD7376, | |
| 257 | + .has_ao = 1, | |
| 273 | 258 | }, |
| 274 | 259 | [BOARD_PCIDAS1602_12] = { |
| 275 | 260 | .name = "pci-das1602/12", |
| 276 | − .ai_nchan = 16, | |
| 277 | − .ai_bits = 12, | |
| 278 | 261 | .ai_speed = 3200, |
| 279 | − .ao_nchan = 2, | |
| 280 | − .has_ao_fifo = 1, | |
| 281 | 262 | .ao_scan_speed = 4000, |
| 282 | 263 | .fifo_size = 1024, |
| 283 | − .ranges = &cb_pcidas_ranges, | |
| 284 | − .trimpot = AD7376, | |
| 264 | + .has_ao = 1, | |
| 265 | + .has_ao_fifo = 1, | |
| 285 | 266 | .is_1602 = 1, |
| 286 | 267 | }, |
| 287 | 268 | [BOARD_PCIDAS1200_JR] = { |
| 288 | 269 | .name = "pci-das1200/jr", |
| 289 | − .ai_nchan = 16, | |
| 290 | − .ai_bits = 12, | |
| 291 | 270 | .ai_speed = 3200, |
| 292 | 271 | .fifo_size = 1024, |
| 293 | − .ranges = &cb_pcidas_ranges, | |
| 294 | − .trimpot = AD7376, | |
| 295 | 272 | }, |
| 296 | 273 | [BOARD_PCIDAS1602_16_JR] = { |
| 297 | 274 | .name = "pci-das1602/16/jr", |
| 298 | − .ai_nchan = 16, | |
| 299 | − .ai_bits = 16, | |
| 300 | 275 | .ai_speed = 5000, |
| 301 | 276 | .fifo_size = 512, |
| 302 | − .ranges = &cb_pcidas_ranges, | |
| 303 | − .trimpot = AD8402, | |
| 277 | + .is_16bit = 1, | |
| 278 | + .has_ad8402 = 1, | |
| 304 | 279 | .has_dac08 = 1, |
| 305 | 280 | .is_1602 = 1, |
| 306 | 281 | }, |
| 307 | 282 | [BOARD_PCIDAS1000] = { |
| 308 | 283 | .name = "pci-das1000", |
| 309 | − .ai_nchan = 16, | |
| 310 | − .ai_bits = 12, | |
| 311 | 284 | .ai_speed = 4000, |
| 312 | 285 | .fifo_size = 1024, |
| 313 | − .ranges = &cb_pcidas_ranges, | |
| 314 | − .trimpot = AD7376, | |
| 315 | 286 | }, |
| 316 | 287 | [BOARD_PCIDAS1001] = { |
| 317 | 288 | .name = "pci-das1001", |
| 318 | − .ai_nchan = 16, | |
| 319 | − .ai_bits = 12, | |
| 320 | 289 | .ai_speed = 6800, |
| 321 | − .ao_nchan = 2, | |
| 322 | 290 | .fifo_size = 1024, |
| 323 | − .ranges = &cb_pcidas_alt_ranges, | |
| 324 | − .trimpot = AD7376, | |
| 291 | + .use_alt_range = 1, | |
| 292 | + .has_ao = 1, | |
| 325 | 293 | }, |
| 326 | 294 | [BOARD_PCIDAS1002] = { |
| 327 | 295 | .name = "pci-das1002", |
| 328 | − .ai_nchan = 16, | |
| 329 | − .ai_bits = 12, | |
| 330 | 296 | .ai_speed = 6800, |
| 331 | − .ao_nchan = 2, | |
| 332 | 297 | .fifo_size = 1024, |
| 333 | − .ranges = &cb_pcidas_ranges, | |
| 334 | − .trimpot = AD7376, | |
| 298 | + .has_ao = 1, | |
| 335 | 299 | }, |
| 336 | 300 | }; |
| 337 | 301 | |
| 338 | 302 | struct cb_pcidas_private { |
| 339 | 303 | struct comedi_8254 *ao_pacer; |
| 340 | 304 | /* base addresses */ |
| 341 | − unsigned long s5933_config; | |
| 342 | − unsigned long control_status; | |
| 343 | − unsigned long adc_fifo; | |
| 344 | − unsigned long ao_registers; | |
| 305 | + unsigned long amcc; /* pcibar0 */ | |
| 306 | + unsigned long pcibar1; | |
| 307 | + unsigned long pcibar2; | |
| 308 | + unsigned long pcibar4; | |
| 345 | 309 | /* bits to write to registers */ |
| 346 | − unsigned int adc_fifo_bits; | |
| 347 | − unsigned int s5933_intcsr_bits; | |
| 348 | − unsigned int ao_control_bits; | |
| 310 | + unsigned int ctrl; | |
| 311 | + unsigned int amcc_intcsr; | |
| 312 | + unsigned int ao_ctrl; | |
| 349 | 313 | /* fifo buffers */ |
| 350 | 314 | unsigned short ai_buffer[AI_BUFFER_SIZE]; |
| 351 | 315 | unsigned short ao_buffer[AO_BUFFER_SIZE]; |
| 352 | − unsigned int calibration_source; | |
| 316 | + unsigned int calib_src; | |
| 353 | 317 | }; |
| 354 | 318 | |
| 355 | −static inline unsigned int cal_enable_bits(struct comedi_device *dev) | |
| 356 | −{ | |
| 357 | − struct cb_pcidas_private *devpriv = dev->private; | |
| 358 | − | |
| 359 | − return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); | |
| 360 | −} | |
| 361 | − | |
| 362 | 319 | static int cb_pcidas_ai_eoc(struct comedi_device *dev, |
| 363 | 320 | struct comedi_subdevice *s, |
| 364 | 321 | struct comedi_insn *insn, |
| @@ -367,15 +324,16 @@ static int cb_pcidas_ai_eoc(struct comedi_device *dev, · 2 unmodified lines | ||
| 367 | 324 | struct cb_pcidas_private *devpriv = dev->private; |
| 368 | 325 | unsigned int status; |
| 369 | 326 | |
| 370 | − status = inw(devpriv->control_status + ADCMUX_CONT); | |
| 371 | − if (status & EOC) | |
| 327 | + status = inw(devpriv->pcibar1 + PCIDAS_AI_REG); | |
| 328 | + if (status & PCIDAS_AI_EOC) | |
| 372 | 329 | return 0; |
| 373 | 330 | return -EBUSY; |
| 374 | 331 | } |
| 375 | 332 | |
| 376 | −static int cb_pcidas_ai_rinsn(struct comedi_device *dev, | |
| 377 | − struct comedi_subdevice *s, | |
| 378 | − struct comedi_insn *insn, unsigned int *data) | |
| 333 | +static int cb_pcidas_ai_insn_read(struct comedi_device *dev, | |
| 334 | + struct comedi_subdevice *s, | |
| 335 | + struct comedi_insn *insn, | |
| 336 | + unsigned int *data) | |
| 379 | 337 | { |
| 380 | 338 | struct cb_pcidas_private *devpriv = dev->private; |
| 381 | 339 | unsigned int chan = CR_CHAN(insn->chanspec); |
| @@ -387,30 +345,30 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, · 5 unmodified lines | ||
| 387 | 345 | |
| 388 | 346 | /* enable calibration input if appropriate */ |
| 389 | 347 | if (insn->chanspec & CR_ALT_SOURCE) { |
| 390 | − outw(cal_enable_bits(dev), | |
| 391 | − devpriv->control_status + CALIBRATION_REG); | |
| 348 | + outw(PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src), | |
| 349 | + devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 392 | 350 | chan = 0; |
| 393 | 351 | } else { |
| 394 | − outw(0, devpriv->control_status + CALIBRATION_REG); | |
| 352 | + outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 395 | 353 | } |
| 396 | 354 | |
| 397 | 355 | /* set mux limits and gain */ |
| 398 | − bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range); | |
| 356 | + bits = PCIDAS_AI_CHAN(chan) | PCIDAS_AI_GAIN(range); | |
| 399 | 357 | /* set unipolar/bipolar */ |
| 400 | − if (range & IS_UNIPOLAR) | |
| 401 | − bits |= UNIP; | |
| 358 | + if (comedi_range_is_unipolar(s, range)) | |
| 359 | + bits |= PCIDAS_AI_UNIP; | |
| 402 | 360 | /* set single-ended/differential */ |
| 403 | 361 | if (aref != AREF_DIFF) |
| 404 | − bits |= SE; | |
| 405 | − outw(bits, devpriv->control_status + ADCMUX_CONT); | |
| 362 | + bits |= PCIDAS_AI_SE; | |
| 363 | + outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG); | |
| 406 | 364 | |
| 407 | 365 | /* clear fifo */ |
| 408 | − outw(0, devpriv->adc_fifo + ADCFIFOCLR); | |
| 366 | + outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG); | |
| 409 | 367 | |
| 410 | 368 | /* convert n samples */ |
| 411 | 369 | for (n = 0; n < insn->n; n++) { |
| 412 | 370 | /* trigger conversion */ |
| 413 | − outw(0, devpriv->adc_fifo + ADCDATA); | |
| 371 | + outw(0, devpriv->pcibar2 + PCIDAS_AI_DATA_REG); | |
| 414 | 372 | |
| 415 | 373 | /* wait for conversion to end */ |
| 416 | 374 | ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); |
| @@ -418,15 +376,17 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, · 1 unmodified line | ||
| 418 | 376 | return ret; |
| 419 | 377 | |
| 420 | 378 | /* read data */ |
| 421 | − data[n] = inw(devpriv->adc_fifo + ADCDATA); | |
| 379 | + data[n] = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG); | |
| 422 | 380 | } |
| 423 | 381 | |
| 424 | 382 | /* return the number of samples read/written */ |
| 425 | 383 | return n; |
| 426 | 384 | } |
| 427 | 385 | |
| 428 | −static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, | |
| 429 | − struct comedi_insn *insn, unsigned int *data) | |
| 386 | +static int cb_pcidas_ai_insn_config(struct comedi_device *dev, | |
| 387 | + struct comedi_subdevice *s, | |
| 388 | + struct comedi_insn *insn, | |
| 389 | + unsigned int *data) | |
| 430 | 390 | { |
| 431 | 391 | struct cb_pcidas_private *devpriv = dev->private; |
| 432 | 392 | int id = data[0]; |
| @@ -440,7 +400,7 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, · 7 unmodified lines | ||
| 440 | 400 | source); |
| 441 | 401 | return -EINVAL; |
| 442 | 402 | } |
| 443 | − devpriv->calibration_source = source; | |
| 403 | + devpriv->calib_src = source; | |
| 444 | 404 | break; |
| 445 | 405 | default: |
| 446 | 406 | return -EINVAL; |
| @@ -449,155 +409,160 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, · 2 unmodified lines | ||
| 449 | 409 | } |
| 450 | 410 | |
| 451 | 411 | /* analog output insn for pcidas-1000 and 1200 series */ |
| 452 | −static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, | |
| 453 | − struct comedi_subdevice *s, | |
| 454 | − struct comedi_insn *insn, | |
| 455 | − unsigned int *data) | |
| 412 | +static int cb_pcidas_ao_nofifo_insn_write(struct comedi_device *dev, | |
| 413 | + struct comedi_subdevice *s, | |
| 414 | + struct comedi_insn *insn, | |
| 415 | + unsigned int *data) | |
| 456 | 416 | { |
| 457 | 417 | struct cb_pcidas_private *devpriv = dev->private; |
| 458 | 418 | unsigned int chan = CR_CHAN(insn->chanspec); |
| 459 | 419 | unsigned int range = CR_RANGE(insn->chanspec); |
| 420 | + unsigned int val = s->readback[chan]; | |
| 460 | 421 | unsigned long flags; |
| 422 | + int i; | |
| 461 | 423 | |
| 462 | 424 | /* set channel and range */ |
| 463 | 425 | spin_lock_irqsave(&dev->spinlock, flags); |
| 464 | − devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH & | |
| 465 | − ~DAC_RANGE_MASK(chan)); | |
| 466 | − devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range)); | |
| 467 | − outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); | |
| 426 | + devpriv->ao_ctrl &= ~(PCIDAS_AO_UPDATE_BOTH | | |
| 427 | + PCIDAS_AO_RANGE_MASK(chan)); | |
| 428 | + devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range); | |
| 429 | + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); | |
| 468 | 430 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 469 | 431 | |
| 470 | − /* remember value for readback */ | |
| 471 | − s->readback[chan] = data[0]; | |
| 432 | + for (i = 0; i < insn->n; i++) { | |
| 433 | + val = data[i]; | |
| 434 | + outw(val, devpriv->pcibar4 + PCIDAS_AO_DATA_REG(chan)); | |
| 435 | + } | |
| 472 | 436 | |
| 473 | − /* send data */ | |
| 474 | − outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan)); | |
| 437 | + s->readback[chan] = val; | |
| 475 | 438 | |
| 476 | 439 | return insn->n; |
| 477 | 440 | } |
| 478 | 441 | |
| 479 | 442 | /* analog output insn for pcidas-1602 series */ |
| 480 | −static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, | |
| 481 | − struct comedi_subdevice *s, | |
| 482 | − struct comedi_insn *insn, unsigned int *data) | |
| 443 | +static int cb_pcidas_ao_fifo_insn_write(struct comedi_device *dev, | |
| 444 | + struct comedi_subdevice *s, | |
| 445 | + struct comedi_insn *insn, | |
| 446 | + unsigned int *data) | |
| 483 | 447 | { |
| 484 | 448 | struct cb_pcidas_private *devpriv = dev->private; |
| 485 | 449 | unsigned int chan = CR_CHAN(insn->chanspec); |
| 486 | 450 | unsigned int range = CR_RANGE(insn->chanspec); |
| 451 | + unsigned int val = s->readback[chan]; | |
| 487 | 452 | unsigned long flags; |
| 453 | + int i; | |
| 488 | 454 | |
| 489 | 455 | /* clear dac fifo */ |
| 490 | − outw(0, devpriv->ao_registers + DACFIFOCLR); | |
| 456 | + outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG); | |
| 491 | 457 | |
| 492 | 458 | /* set channel and range */ |
| 493 | 459 | spin_lock_irqsave(&dev->spinlock, flags); |
| 494 | − devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & | |
| 495 | − ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK); | |
| 496 | − devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) | | |
| 497 | − DAC_CHAN_EN(chan) | DAC_START); | |
| 498 | − outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); | |
| 460 | + devpriv->ao_ctrl &= ~(PCIDAS_AO_CHAN_MASK | PCIDAS_AO_RANGE_MASK(chan) | | |
| 461 | + PCIDAS_AO_PACER_MASK); | |
| 462 | + devpriv->ao_ctrl |= PCIDAS_AO_DACEN | PCIDAS_AO_RANGE(chan, range) | | |
| 463 | + PCIDAS_AO_CHAN_EN(chan) | PCIDAS_AO_START; | |
| 464 | + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); | |
| 499 | 465 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 500 | 466 | |
| 501 | − /* remember value for readback */ | |
| 502 | − s->readback[chan] = data[0]; | |
| 467 | + for (i = 0; i < insn->n; i++) { | |
| 468 | + val = data[i]; | |
| 469 | + outw(val, devpriv->pcibar4 + PCIDAS_AO_FIFO_REG); | |
| 470 | + } | |
| 503 | 471 | |
| 504 | − /* send data */ | |
| 505 | − outw(data[0], devpriv->ao_registers + DACDATA); | |
| 472 | + s->readback[chan] = val; | |
| 506 | 473 | |
| 507 | 474 | return insn->n; |
| 508 | 475 | } |
| 509 | 476 | |
| 510 | −static int wait_for_nvram_ready(unsigned long s5933_base_addr) | |
| 477 | +static int cb_pcidas_eeprom_ready(struct comedi_device *dev, | |
| 478 | + struct comedi_subdevice *s, | |
| 479 | + struct comedi_insn *insn, | |
| 480 | + unsigned long context) | |
| 511 | 481 | { |
| 512 | − static const int timeout = 1000; | |
| 513 | − unsigned int i; | |
| 482 | + struct cb_pcidas_private *devpriv = dev->private; | |
| 483 | + unsigned int status; | |
| 514 | 484 | |
| 515 | − for (i = 0; i < timeout; i++) { | |
| 516 | − if ((inb(s5933_base_addr + | |
| 517 | − AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY) | |
| 518 | − == 0) | |
| 519 | − return 0; | |
| 520 | − udelay(1); | |
| 521 | − } | |
| 522 | − return -1; | |
| 485 | + status = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); | |
| 486 | + if ((status & MCSR_NV_BUSY) == 0) | |
| 487 | + return 0; | |
| 488 | + return -EBUSY; | |
| 523 | 489 | } |
| 524 | 490 | |
| 525 | −static int nvram_read(struct comedi_device *dev, unsigned int address, | |
| 526 | − uint8_t *data) | |
| 491 | +static int cb_pcidas_eeprom_insn_read(struct comedi_device *dev, | |
| 492 | + struct comedi_subdevice *s, | |
| 493 | + struct comedi_insn *insn, | |
| 494 | + unsigned int *data) | |
| 527 | 495 | { |
| 528 | 496 | struct cb_pcidas_private *devpriv = dev->private; |
| 529 | − unsigned long iobase = devpriv->s5933_config; | |
| 530 | − | |
| 531 | − if (wait_for_nvram_ready(iobase) < 0) | |
| 532 | − return -ETIMEDOUT; | |
| 533 | − | |
| 534 | − outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, | |
| 535 | − iobase + AMCC_OP_REG_MCSR_NVCMD); | |
| 536 | − outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); | |
| 537 | − outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, | |
| 538 | − iobase + AMCC_OP_REG_MCSR_NVCMD); | |
| 539 | − outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); | |
| 540 | − outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); | |
| 541 | − | |
| 542 | − if (wait_for_nvram_ready(iobase) < 0) | |
| 543 | − return -ETIMEDOUT; | |
| 544 | − | |
| 545 | − *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); | |
| 546 | − | |
| 547 | − return 0; | |
| 548 | −} | |
| 497 | + unsigned int chan = CR_CHAN(insn->chanspec); | |
| 498 | + int ret; | |
| 499 | + int i; | |
| 549 | 500 | |
| 550 | −static int eeprom_read_insn(struct comedi_device *dev, | |
| 551 | − struct comedi_subdevice *s, | |
| 552 | − struct comedi_insn *insn, unsigned int *data) | |
| 553 | −{ | |
| 554 | − uint8_t nvram_data; | |
| 555 | − int retval; | |
| 501 | + for (i = 0; i < insn->n; i++) { | |
| 502 | + /* make sure eeprom is ready */ | |
| 503 | + ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0); | |
| 504 | + if (ret) | |
| 505 | + return ret; | |
| 556 | 506 | |
| 557 | − retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data); | |
| 558 | − if (retval < 0) | |
| 559 | − return retval; | |
| 507 | + /* set address (chan) and read operation */ | |
| 508 | + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, | |
| 509 | + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); | |
| 510 | + outb(chan & 0xff, devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); | |
| 511 | + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, | |
| 512 | + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); | |
| 513 | + outb((chan >> 8) & 0xff, | |
| 514 | + devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); | |
| 515 | + outb(MCSR_NV_ENABLE | MCSR_NV_READ, | |
| 516 | + devpriv->amcc + AMCC_OP_REG_MCSR_NVCMD); | |
| 517 | + | |
| 518 | + /* wait for data to be returned */ | |
| 519 | + ret = comedi_timeout(dev, s, insn, cb_pcidas_eeprom_ready, 0); | |
| 520 | + if (ret) | |
| 521 | + return ret; | |
| 560 | 522 | |
| 561 | − data[0] = nvram_data; | |
| 523 | + data[i] = inb(devpriv->amcc + AMCC_OP_REG_MCSR_NVDATA); | |
| 524 | + } | |
| 562 | 525 | |
| 563 | − return 1; | |
| 526 | + return insn->n; | |
| 564 | 527 | } |
| 565 | 528 | |
| 566 | −static void write_calibration_bitstream(struct comedi_device *dev, | |
| 567 | − unsigned int register_bits, | |
| 568 | − unsigned int bitstream, | |
| 569 | − unsigned int bitstream_length) | |
| 529 | +static void cb_pcidas_calib_write(struct comedi_device *dev, | |
| 530 | + unsigned int val, unsigned int len, | |
| 531 | + bool trimpot) | |
| 570 | 532 | { |
| 571 | 533 | struct cb_pcidas_private *devpriv = dev->private; |
| 572 | − static const int write_delay = 1; | |
| 534 | + unsigned int calib_bits; | |
| 573 | 535 | unsigned int bit; |
| 574 | 536 | |
| 575 | − for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { | |
| 576 | − if (bitstream & bit) | |
| 577 | − register_bits |= SERIAL_DATA_IN_BIT; | |
| 537 | + calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); | |
| 538 | + if (trimpot) { | |
| 539 | + /* select trimpot */ | |
| 540 | + calib_bits |= PCIDAS_CALIB_TRIM_SEL; | |
| 541 | + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 542 | + } | |
| 543 | + | |
| 544 | + /* write bitstream to calibration device */ | |
| 545 | + for (bit = 1 << (len - 1); bit; bit >>= 1) { | |
| 546 | + if (val & bit) | |
| 547 | + calib_bits |= PCIDAS_CALIB_DATA; | |
| 578 | 548 | else |
| 579 | − register_bits &= ~SERIAL_DATA_IN_BIT; | |
| 580 | − udelay(write_delay); | |
| 581 | − outw(register_bits, devpriv->control_status + CALIBRATION_REG); | |
| 549 | + calib_bits &= ~PCIDAS_CALIB_DATA; | |
| 550 | + udelay(1); | |
| 551 | + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 582 | 552 | } |
| 583 | −} | |
| 553 | + udelay(1); | |
| 584 | 554 | |
| 585 | −static void caldac_8800_write(struct comedi_device *dev, | |
| 586 | − unsigned int chan, uint8_t val) | |
| 587 | −{ | |
| 588 | − struct cb_pcidas_private *devpriv = dev->private; | |
| 589 | − static const int bitstream_length = 11; | |
| 590 | − unsigned int bitstream = ((chan & 0x7) << 8) | val; | |
| 591 | − static const int caldac_8800_udelay = 1; | |
| 592 | − | |
| 593 | − write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, | |
| 594 | − bitstream_length); | |
| 595 | − | |
| 596 | − udelay(caldac_8800_udelay); | |
| 597 | − outw(cal_enable_bits(dev) | SELECT_8800_BIT, | |
| 598 | − devpriv->control_status + CALIBRATION_REG); | |
| 599 | − udelay(caldac_8800_udelay); | |
| 600 | − outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); | |
| 555 | + calib_bits = PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); | |
| 556 | + | |
| 557 | + if (!trimpot) { | |
| 558 | + /* select caldac */ | |
| 559 | + outw(calib_bits | PCIDAS_CALIB_8800_SEL, | |
| 560 | + devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 561 | + udelay(1); | |
| 562 | + } | |
| 563 | + | |
| 564 | + /* latch value to trimpot/caldac */ | |
| 565 | + outw(calib_bits, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 601 | 566 | } |
| 602 | 567 | |
| 603 | 568 | static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, |
| @@ -611,7 +576,9 @@ static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, · 7 unmodified lines | ||
| 611 | 576 | unsigned int val = data[insn->n - 1]; |
| 612 | 577 | |
| 613 | 578 | if (s->readback[chan] != val) { |
| 614 | − caldac_8800_write(dev, chan, val); | |
| 579 | + /* write 11-bit channel/value to caldac */ | |
| 580 | + cb_pcidas_calib_write(dev, (chan << 8) | val, 11, | |
| 581 | + false); | |
| 615 | 582 | s->readback[chan] = val; |
| 616 | 583 | } |
| 617 | 584 | } |
| @@ -619,21 +586,19 @@ static int cb_pcidas_caldac_insn_write(struct comedi_device *dev, · 1 unmodified line | ||
| 619 | 586 | return insn->n; |
| 620 | 587 | } |
| 621 | 588 | |
| 622 | −/* 1602/16 pregain offset */ | |
| 623 | −static void dac08_write(struct comedi_device *dev, unsigned int value) | |
| 589 | +static void cb_pcidas_dac08_write(struct comedi_device *dev, unsigned int val) | |
| 624 | 590 | { |
| 625 | 591 | struct cb_pcidas_private *devpriv = dev->private; |
| 626 | 592 | |
| 627 | − value &= 0xff; | |
| 628 | − value |= cal_enable_bits(dev); | |
| 593 | + val |= PCIDAS_CALIB_EN | PCIDAS_CALIB_SRC(devpriv->calib_src); | |
| 629 | 594 | |
| 630 | 595 | /* latch the new value into the caldac */ |
| 631 | − outw(value, devpriv->control_status + CALIBRATION_REG); | |
| 596 | + outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 632 | 597 | udelay(1); |
| 633 | − outw(value | SELECT_DAC08_BIT, | |
| 634 | − devpriv->control_status + CALIBRATION_REG); | |
| 598 | + outw(val | PCIDAS_CALIB_DAC08_SEL, | |
| 599 | + devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 635 | 600 | udelay(1); |
| 636 | − outw(value, devpriv->control_status + CALIBRATION_REG); | |
| 601 | + outw(val, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 637 | 602 | udelay(1); |
| 638 | 603 | } |
| 639 | 604 | |
| @@ -648,7 +613,7 @@ static int cb_pcidas_dac08_insn_write(struct comedi_device *dev, · 8 unmodified lines | ||
| 648 | 613 | unsigned int val = data[insn->n - 1]; |
| 649 | 614 | |
| 650 | 615 | if (s->readback[chan] != val) { |
| 651 | − dac08_write(dev, val); | |
| 616 | + cb_pcidas_dac08_write(dev, val); | |
| 652 | 617 | s->readback[chan] = val; |
| 653 | 618 | } |
| 654 | 619 | } |
| @@ -656,67 +621,17 @@ static int cb_pcidas_dac08_insn_write(struct comedi_device *dev, · 1 unmodified line | ||
| 656 | 621 | return insn->n; |
| 657 | 622 | } |
| 658 | 623 | |
| 659 | −static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) | |
| 660 | −{ | |
| 661 | − struct cb_pcidas_private *devpriv = dev->private; | |
| 662 | − static const int bitstream_length = 7; | |
| 663 | − unsigned int bitstream = value & 0x7f; | |
| 664 | − unsigned int register_bits; | |
| 665 | − static const int ad7376_udelay = 1; | |
| 666 | − | |
| 667 | − register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; | |
| 668 | − udelay(ad7376_udelay); | |
| 669 | − outw(register_bits, devpriv->control_status + CALIBRATION_REG); | |
| 670 | − | |
| 671 | − write_calibration_bitstream(dev, register_bits, bitstream, | |
| 672 | − bitstream_length); | |
| 673 | − | |
| 674 | − udelay(ad7376_udelay); | |
| 675 | − outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); | |
| 676 | − | |
| 677 | − return 0; | |
| 678 | −} | |
| 679 | − | |
| 680 | −/* For 1602/16 only | |
| 681 | − * ch 0 : adc gain | |
| 682 | − * ch 1 : adc postgain offset */ | |
| 683 | −static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, | |
| 684 | − uint8_t value) | |
| 685 | −{ | |
| 686 | − struct cb_pcidas_private *devpriv = dev->private; | |
| 687 | − static const int bitstream_length = 10; | |
| 688 | − unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); | |
| 689 | − unsigned int register_bits; | |
| 690 | − static const int ad8402_udelay = 1; | |
| 691 | − | |
| 692 | − register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; | |
| 693 | − udelay(ad8402_udelay); | |
| 694 | − outw(register_bits, devpriv->control_status + CALIBRATION_REG); | |
| 695 | − | |
| 696 | − write_calibration_bitstream(dev, register_bits, bitstream, | |
| 697 | − bitstream_length); | |
| 698 | − | |
| 699 | − udelay(ad8402_udelay); | |
| 700 | − outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); | |
| 701 | − | |
| 702 | − return 0; | |
| 703 | −} | |
| 704 | − | |
| 705 | 624 | static void cb_pcidas_trimpot_write(struct comedi_device *dev, |
| 706 | 625 | unsigned int chan, unsigned int val) |
| 707 | 626 | { |
| 708 | 627 | const struct cb_pcidas_board *board = dev->board_ptr; |
| 709 | 628 | |
| 710 | − switch (board->trimpot) { | |
| 711 | − case AD7376: | |
| 712 | − trimpot_7376_write(dev, val); | |
| 713 | − break; | |
| 714 | − case AD8402: | |
| 715 | − trimpot_8402_write(dev, chan, val); | |
| 716 | − break; | |
| 717 | − default: | |
| 718 | − dev_err(dev->class_dev, "driver bug?\n"); | |
| 719 | − break; | |
| 629 | + if (board->has_ad8402) { | |
| 630 | + /* write 10-bit channel/value to AD8402 trimpot */ | |
| 631 | + cb_pcidas_calib_write(dev, (chan << 8) | val, 10, true); | |
| 632 | + } else { | |
| 633 | + /* write 7-bit value to AD7376 trimpot */ | |
| 634 | + cb_pcidas_calib_write(dev, val, 7, true); | |
| 720 | 635 | } |
| 721 | 636 | } |
| 722 | 637 | |
| @@ -883,32 +798,33 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, · 160 unmodified lines | ||
| 883 | 798 | struct cb_pcidas_private *devpriv = dev->private; |
| 884 | 799 | struct comedi_async *async = s->async; |
| 885 | 800 | struct comedi_cmd *cmd = &async->cmd; |
| 801 | + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); | |
| 886 | 802 | unsigned int bits; |
| 887 | 803 | unsigned long flags; |
| 888 | 804 | |
| 889 | − /* make sure CAL_EN_BIT is disabled */ | |
| 890 | − outw(0, devpriv->control_status + CALIBRATION_REG); | |
| 805 | + /* make sure PCIDAS_CALIB_EN is disabled */ | |
| 806 | + outw(0, devpriv->pcibar1 + PCIDAS_CALIB_REG); | |
| 891 | 807 | /* initialize before settings pacer source and count values */ |
| 892 | − outw(0, devpriv->control_status + TRIG_CONTSTAT); | |
| 808 | + outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG); | |
| 893 | 809 | /* clear fifo */ |
| 894 | − outw(0, devpriv->adc_fifo + ADCFIFOCLR); | |
| 810 | + outw(0, devpriv->pcibar2 + PCIDAS_AI_FIFO_CLR_REG); | |
| 895 | 811 | |
| 896 | 812 | /* set mux limits, gain and pacer source */ |
| 897 | − bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) | | |
| 898 | − END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) | | |
| 899 | − GAIN_BITS(CR_RANGE(cmd->chanlist[0])); | |
| 813 | + bits = PCIDAS_AI_FIRST(CR_CHAN(cmd->chanlist[0])) | | |
| 814 | + PCIDAS_AI_LAST(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) | | |
| 815 | + PCIDAS_AI_GAIN(range0); | |
| 900 | 816 | /* set unipolar/bipolar */ |
| 901 | − if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR) | |
| 902 | − bits |= UNIP; | |
| 817 | + if (comedi_range_is_unipolar(s, range0)) | |
| 818 | + bits |= PCIDAS_AI_UNIP; | |
| 903 | 819 | /* set singleended/differential */ |
| 904 | 820 | if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF) |
| 905 | − bits |= SE; | |
| 821 | + bits |= PCIDAS_AI_SE; | |
| 906 | 822 | /* set pacer source */ |
| 907 | 823 | if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT) |
| 908 | − bits |= PACER_EXT_RISE; | |
| 824 | + bits |= PCIDAS_AI_PACER_EXTP; | |
| 909 | 825 | else |
| 910 | − bits |= PACER_INT; | |
| 911 | − outw(bits, devpriv->control_status + ADCMUX_CONT); | |
| 826 | + bits |= PCIDAS_AI_PACER_INT; | |
| 827 | + outw(bits, devpriv->pcibar1 + PCIDAS_AI_REG); | |
| 912 | 828 | |
| 913 | 829 | /* load counters */ |
| 914 | 830 | if (cmd->scan_begin_src == TRIG_TIMER || |
| @@ -919,42 +835,43 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, · 4 unmodified lines | ||
| 919 | 835 | |
| 920 | 836 | /* enable interrupts */ |
| 921 | 837 | spin_lock_irqsave(&dev->spinlock, flags); |
| 922 | − devpriv->adc_fifo_bits |= INTE; | |
| 923 | − devpriv->adc_fifo_bits &= ~INT_MASK; | |
| 838 | + devpriv->ctrl |= PCIDAS_CTRL_INTE; | |
| 839 | + devpriv->ctrl &= ~PCIDAS_CTRL_INT_MASK; | |
| 924 | 840 | if (cmd->flags & CMDF_WAKE_EOS) { |
| 925 | 841 | if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) { |
| 926 | 842 | /* interrupt end of burst */ |
| 927 | − devpriv->adc_fifo_bits |= INT_EOS; | |
| 843 | + devpriv->ctrl |= PCIDAS_CTRL_INT_EOS; | |
| 928 | 844 | } else { |
| 929 | 845 | /* interrupt fifo not empty */ |
| 930 | − devpriv->adc_fifo_bits |= INT_FNE; | |
| 846 | + devpriv->ctrl |= PCIDAS_CTRL_INT_FNE; | |
| 931 | 847 | } |
| 932 | 848 | } else { |
| 933 | 849 | /* interrupt fifo half full */ |
| 934 | − devpriv->adc_fifo_bits |= INT_FHF; | |
| 850 | + devpriv->ctrl |= PCIDAS_CTRL_INT_FHF; | |
| 935 | 851 | } |
| 936 | 852 | |
| 937 | 853 | /* enable (and clear) interrupts */ |
| 938 | − outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL, | |
| 939 | − devpriv->control_status + INT_ADCFIFO); | |
| 854 | + outw(devpriv->ctrl | | |
| 855 | + PCIDAS_CTRL_EOAI | PCIDAS_CTRL_INT_CLR | PCIDAS_CTRL_LADFUL, | |
| 856 | + devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 940 | 857 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 941 | 858 | |
| 942 | 859 | /* set start trigger and burst mode */ |
| 943 | 860 | bits = 0; |
| 944 | 861 | if (cmd->start_src == TRIG_NOW) { |
| 945 | − bits |= SW_TRIGGER; | |
| 862 | + bits |= PCIDAS_TRIG_SEL_SW; | |
| 946 | 863 | } else { /* TRIG_EXT */ |
| 947 | − bits |= EXT_TRIGGER | TGEN | XTRCL; | |
| 864 | + bits |= PCIDAS_TRIG_SEL_EXT | PCIDAS_TRIG_EN | PCIDAS_TRIG_CLR; | |
| 948 | 865 | if (board->is_1602) { |
| 949 | 866 | if (cmd->start_arg & CR_INVERT) |
| 950 | − bits |= TGPOL; | |
| 867 | + bits |= PCIDAS_TRIG_POL; | |
| 951 | 868 | if (cmd->start_arg & CR_EDGE) |
| 952 | − bits |= TGSEL; | |
| 869 | + bits |= PCIDAS_TRIG_MODE; | |
| 953 | 870 | } |
| 954 | 871 | } |
| 955 | 872 | if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) |
| 956 | − bits |= BURSTE; | |
| 957 | − outw(bits, devpriv->control_status + TRIG_CONTSTAT); | |
| 873 | + bits |= PCIDAS_TRIG_BURSTE; | |
| 874 | + outw(bits, devpriv->pcibar1 + PCIDAS_TRIG_REG); | |
| 958 | 875 | |
| 959 | 876 | return 0; |
| 960 | 877 | } |
| @@ -1051,23 +968,21 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, · 90 unmodified lines | ||
| 1051 | 968 | return 0; |
| 1052 | 969 | } |
| 1053 | 970 | |
| 1054 | −/* cancel analog input command */ | |
| 1055 | −static int cb_pcidas_cancel(struct comedi_device *dev, | |
| 1056 | − struct comedi_subdevice *s) | |
| 971 | +static int cb_pcidas_ai_cancel(struct comedi_device *dev, | |
| 972 | + struct comedi_subdevice *s) | |
| 1057 | 973 | { |
| 1058 | 974 | struct cb_pcidas_private *devpriv = dev->private; |
| 1059 | 975 | unsigned long flags; |
| 1060 | 976 | |
| 1061 | 977 | spin_lock_irqsave(&dev->spinlock, flags); |
| 1062 | 978 | /* disable interrupts */ |
| 1063 | − devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; | |
| 1064 | − outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); | |
| 979 | + devpriv->ctrl &= ~(PCIDAS_CTRL_INTE | PCIDAS_CTRL_EOAIE); | |
| 980 | + outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 1065 | 981 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 1066 | 982 | |
| 1067 | 983 | /* disable start trigger source and burst mode */ |
| 1068 | − outw(0, devpriv->control_status + TRIG_CONTSTAT); | |
| 1069 | − /* software pacer source */ | |
| 1070 | − outw(0, devpriv->control_status + ADCMUX_CONT); | |
| 984 | + outw(PCIDAS_TRIG_SEL_NONE, devpriv->pcibar1 + PCIDAS_TRIG_REG); | |
| 985 | + outw(PCIDAS_AI_PACER_SW, devpriv->pcibar1 + PCIDAS_AI_REG); | |
| 1071 | 986 | |
| 1072 | 987 | return 0; |
| 1073 | 988 | } |
| @@ -1083,7 +998,8 @@ static void cb_pcidas_ao_load_fifo(struct comedi_device *dev, · 9 unmodified lines | ||
| 1083 | 998 | nbytes = comedi_buf_read_samples(s, devpriv->ao_buffer, nsamples); |
| 1084 | 999 | |
| 1085 | 1000 | nsamples = comedi_bytes_to_samples(s, nbytes); |
| 1086 | − outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, nsamples); | |
| 1001 | + outsw(devpriv->pcibar4 + PCIDAS_AO_FIFO_REG, | |
| 1002 | + devpriv->ao_buffer, nsamples); | |
| 1087 | 1003 | } |
| 1088 | 1004 | |
| 1089 | 1005 | static int cb_pcidas_ao_inttrig(struct comedi_device *dev, |
| @@ -1103,15 +1019,15 @@ static int cb_pcidas_ao_inttrig(struct comedi_device *dev, · 13 unmodified lines | ||
| 1103 | 1019 | |
| 1104 | 1020 | /* enable dac half-full and empty interrupts */ |
| 1105 | 1021 | spin_lock_irqsave(&dev->spinlock, flags); |
| 1106 | − devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; | |
| 1022 | + devpriv->ctrl |= PCIDAS_CTRL_DAEMIE | PCIDAS_CTRL_DAHFIE; | |
| 1107 | 1023 | |
| 1108 | 1024 | /* enable and clear interrupts */ |
| 1109 | − outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, | |
| 1110 | − devpriv->control_status + INT_ADCFIFO); | |
| 1025 | + outw(devpriv->ctrl | PCIDAS_CTRL_DAEMI | PCIDAS_CTRL_DAHFI, | |
| 1026 | + devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 1111 | 1027 | |
| 1112 | 1028 | /* start dac */ |
| 1113 | − devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; | |
| 1114 | − outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); | |
| 1029 | + devpriv->ao_ctrl |= PCIDAS_AO_START | PCIDAS_AO_DACEN | PCIDAS_AO_EMPTY; | |
| 1030 | + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); | |
| 1115 | 1031 | |
| 1116 | 1032 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 1117 | 1033 | |
| @@ -1132,21 +1048,21 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, · 14 unmodified lines | ||
| 1132 | 1048 | /* set channel limits, gain */ |
| 1133 | 1049 | spin_lock_irqsave(&dev->spinlock, flags); |
| 1134 | 1050 | for (i = 0; i < cmd->chanlist_len; i++) { |
| 1051 | + unsigned int chan = CR_CHAN(cmd->chanlist[i]); | |
| 1052 | + unsigned int range = CR_RANGE(cmd->chanlist[i]); | |
| 1053 | + | |
| 1135 | 1054 | /* enable channel */ |
| 1136 | − devpriv->ao_control_bits |= | |
| 1137 | − DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i])); | |
| 1055 | + devpriv->ao_ctrl |= PCIDAS_AO_CHAN_EN(chan); | |
| 1138 | 1056 | /* set range */ |
| 1139 | − devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]), | |
| 1140 | − CR_RANGE(cmd-> | |
| 1141 | − chanlist[i])); | |
| 1057 | + devpriv->ao_ctrl |= PCIDAS_AO_RANGE(chan, range); | |
| 1142 | 1058 | } |
| 1143 | 1059 | |
| 1144 | 1060 | /* disable analog out before settings pacer source and count values */ |
| 1145 | − outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); | |
| 1061 | + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); | |
| 1146 | 1062 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 1147 | 1063 | |
| 1148 | 1064 | /* clear fifo */ |
| 1149 | − outw(0, devpriv->ao_registers + DACFIFOCLR); | |
| 1065 | + outw(0, devpriv->pcibar4 + PCIDAS_AO_FIFO_CLR_REG); | |
| 1150 | 1066 | |
| 1151 | 1067 | /* load counters */ |
| 1152 | 1068 | if (cmd->scan_begin_src == TRIG_TIMER) { |
| @@ -1158,10 +1074,10 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, · 5 unmodified lines | ||
| 1158 | 1074 | spin_lock_irqsave(&dev->spinlock, flags); |
| 1159 | 1075 | switch (cmd->scan_begin_src) { |
| 1160 | 1076 | case TRIG_TIMER: |
| 1161 | − devpriv->ao_control_bits |= DAC_PACER_INT; | |
| 1077 | + devpriv->ao_ctrl |= PCIDAS_AO_PACER_INT; | |
| 1162 | 1078 | break; |
| 1163 | 1079 | case TRIG_EXT: |
| 1164 | − devpriv->ao_control_bits |= DAC_PACER_EXT_RISE; | |
| 1080 | + devpriv->ao_ctrl |= PCIDAS_AO_PACER_EXTP; | |
| 1165 | 1081 | break; |
| 1166 | 1082 | default: |
| 1167 | 1083 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| @@ -1175,7 +1091,6 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, · 7 unmodified lines | ||
| 1175 | 1091 | return 0; |
| 1176 | 1092 | } |
| 1177 | 1093 | |
| 1178 | −/* cancel analog output command */ | |
| 1179 | 1094 | static int cb_pcidas_ao_cancel(struct comedi_device *dev, |
| 1180 | 1095 | struct comedi_subdevice *s) |
| 1181 | 1096 | { |
| @@ -1184,33 +1099,31 @@ static int cb_pcidas_ao_cancel(struct comedi_device *dev, · 2 unmodified lines | ||
| 1184 | 1099 | |
| 1185 | 1100 | spin_lock_irqsave(&dev->spinlock, flags); |
| 1186 | 1101 | /* disable interrupts */ |
| 1187 | − devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; | |
| 1188 | − outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); | |
| 1102 | + devpriv->ctrl &= ~(PCIDAS_CTRL_DAHFIE | PCIDAS_CTRL_DAEMIE); | |
| 1103 | + outw(devpriv->ctrl, devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 1189 | 1104 | |
| 1190 | 1105 | /* disable output */ |
| 1191 | − devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; | |
| 1192 | − outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); | |
| 1106 | + devpriv->ao_ctrl &= ~(PCIDAS_AO_DACEN | PCIDAS_AO_PACER_MASK); | |
| 1107 | + outw(devpriv->ao_ctrl, devpriv->pcibar1 + PCIDAS_AO_REG); | |
| 1193 | 1108 | spin_unlock_irqrestore(&dev->spinlock, flags); |
| 1194 | 1109 | |
| 1195 | 1110 | return 0; |
| 1196 | 1111 | } |
| 1197 | 1112 | |
| 1198 | −static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) | |
| 1113 | +static unsigned int cb_pcidas_ao_interrupt(struct comedi_device *dev, | |
| 1114 | + unsigned int status) | |
| 1199 | 1115 | { |
| 1200 | 1116 | const struct cb_pcidas_board *board = dev->board_ptr; |
| 1201 | 1117 | struct cb_pcidas_private *devpriv = dev->private; |
| 1202 | 1118 | struct comedi_subdevice *s = dev->write_subdev; |
| 1203 | 1119 | struct comedi_async *async = s->async; |
| 1204 | 1120 | struct comedi_cmd *cmd = &async->cmd; |
| 1205 | − unsigned long flags; | |
| 1121 | + unsigned int irq_clr = 0; | |
| 1206 | 1122 | |
| 1207 | − if (status & DAEMI) { | |
| 1208 | − /* clear dac empty interrupt latch */ | |
| 1209 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1210 | − outw(devpriv->adc_fifo_bits | DAEMI, | |
| 1211 | − devpriv->control_status + INT_ADCFIFO); | |
| 1212 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1213 | − if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { | |
| 1123 | + if (status & PCIDAS_CTRL_DAEMI) { | |
| 1124 | + irq_clr |= PCIDAS_CTRL_DAEMI; | |
| 1125 | + | |
| 1126 | + if (inw(devpriv->pcibar4 + PCIDAS_AO_REG) & PCIDAS_AO_EMPTY) { | |
| 1214 | 1127 | if (cmd->stop_src == TRIG_COUNT && |
| 1215 | 1128 | async->scans_done >= cmd->stop_arg) { |
| 1216 | 1129 | async->events |= COMEDI_CB_EOA; |
| @@ -1219,83 +1132,55 @@ static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) · 2 unmodified lines | ||
| 1219 | 1132 | async->events |= COMEDI_CB_ERROR; |
| 1220 | 1133 | } |
| 1221 | 1134 | } |
| 1222 | − } else if (status & DAHFI) { | |
| 1223 | − cb_pcidas_ao_load_fifo(dev, s, board->fifo_size / 2); | |
| 1135 | + } else if (status & PCIDAS_CTRL_DAHFI) { | |
| 1136 | + irq_clr |= PCIDAS_CTRL_DAHFI; | |
| 1224 | 1137 | |
| 1225 | − /* clear half-full interrupt latch */ | |
| 1226 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1227 | − outw(devpriv->adc_fifo_bits | DAHFI, | |
| 1228 | − devpriv->control_status + INT_ADCFIFO); | |
| 1229 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1138 | + cb_pcidas_ao_load_fifo(dev, s, board->fifo_size / 2); | |
| 1230 | 1139 | } |
| 1231 | 1140 | |
| 1232 | 1141 | comedi_handle_events(dev, s); |
| 1142 | + | |
| 1143 | + return irq_clr; | |
| 1233 | 1144 | } |
| 1234 | 1145 | |
| 1235 | −static irqreturn_t cb_pcidas_interrupt(int irq, void *d) | |
| 1146 | +static unsigned int cb_pcidas_ai_interrupt(struct comedi_device *dev, | |
| 1147 | + unsigned int status) | |
| 1236 | 1148 | { |
| 1237 | − struct comedi_device *dev = (struct comedi_device *)d; | |
| 1238 | 1149 | const struct cb_pcidas_board *board = dev->board_ptr; |
| 1239 | 1150 | struct cb_pcidas_private *devpriv = dev->private; |
| 1240 | 1151 | struct comedi_subdevice *s = dev->read_subdev; |
| 1241 | − struct comedi_async *async; | |
| 1242 | − struct comedi_cmd *cmd; | |
| 1243 | − int status, s5933_status; | |
| 1244 | − int half_fifo = board->fifo_size / 2; | |
| 1245 | − unsigned int num_samples, i; | |
| 1246 | − static const int timeout = 10000; | |
| 1247 | − unsigned long flags; | |
| 1248 | − | |
| 1249 | − if (!dev->attached) | |
| 1250 | − return IRQ_NONE; | |
| 1251 | − | |
| 1252 | − async = s->async; | |
| 1253 | − cmd = &async->cmd; | |
| 1152 | + struct comedi_async *async = s->async; | |
| 1153 | + struct comedi_cmd *cmd = &async->cmd; | |
| 1154 | + unsigned int irq_clr = 0; | |
| 1254 | 1155 | |
| 1255 | − s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); | |
| 1156 | + if (status & PCIDAS_CTRL_ADHFI) { | |
| 1157 | + unsigned int num_samples; | |
| 1256 | 1158 | |
| 1257 | − if ((INTCSR_INTR_ASSERTED & s5933_status) == 0) | |
| 1258 | − return IRQ_NONE; | |
| 1159 | + irq_clr |= PCIDAS_CTRL_INT_CLR; | |
| 1259 | 1160 | |
| 1260 | − /* make sure mailbox 4 is empty */ | |
| 1261 | − inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4); | |
| 1262 | − /* clear interrupt on amcc s5933 */ | |
| 1263 | − outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, | |
| 1264 | − devpriv->s5933_config + AMCC_OP_REG_INTCSR); | |
| 1265 | − | |
| 1266 | − status = inw(devpriv->control_status + INT_ADCFIFO); | |
| 1267 | − | |
| 1268 | − /* check for analog output interrupt */ | |
| 1269 | − if (status & (DAHFI | DAEMI)) | |
| 1270 | − handle_ao_interrupt(dev, status); | |
| 1271 | − /* check for analog input interrupts */ | |
| 1272 | − /* if fifo half-full */ | |
| 1273 | − if (status & ADHFI) { | |
| 1274 | − /* read data */ | |
| 1275 | − num_samples = comedi_nsamples_left(s, half_fifo); | |
| 1276 | − insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer, | |
| 1277 | − num_samples); | |
| 1161 | + /* FIFO is half-full - read data */ | |
| 1162 | + num_samples = comedi_nsamples_left(s, board->fifo_size / 2); | |
| 1163 | + insw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG, | |
| 1164 | + devpriv->ai_buffer, num_samples); | |
| 1278 | 1165 | comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples); |
| 1279 | 1166 | |
| 1280 | 1167 | if (cmd->stop_src == TRIG_COUNT && |
| 1281 | 1168 | async->scans_done >= cmd->stop_arg) |
| 1282 | 1169 | async->events |= COMEDI_CB_EOA; |
| 1170 | + } else if (status & (PCIDAS_CTRL_ADNEI | PCIDAS_CTRL_EOBI)) { | |
| 1171 | + unsigned int i; | |
| 1283 | 1172 | |
| 1284 | − /* clear half-full interrupt latch */ | |
| 1285 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1286 | − outw(devpriv->adc_fifo_bits | INT, | |
| 1287 | − devpriv->control_status + INT_ADCFIFO); | |
| 1288 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1289 | − /* else if fifo not empty */ | |
| 1290 | − } else if (status & (ADNEI | EOBI)) { | |
| 1291 | − for (i = 0; i < timeout; i++) { | |
| 1173 | + irq_clr |= PCIDAS_CTRL_INT_CLR; | |
| 1174 | + | |
| 1175 | + /* FIFO is not empty - read data until empty or timeoout */ | |
| 1176 | + for (i = 0; i < 10000; i++) { | |
| 1292 | 1177 | unsigned short val; |
| 1293 | 1178 | |
| 1294 | 1179 | /* break if fifo is empty */ |
| 1295 | − if ((ADNE & inw(devpriv->control_status + | |
| 1296 | − INT_ADCFIFO)) == 0) | |
| 1180 | + if ((inw(devpriv->pcibar1 + PCIDAS_CTRL_REG) & | |
| 1181 | + PCIDAS_CTRL_ADNE) == 0) | |
| 1297 | 1182 | break; |
| 1298 | − val = inw(devpriv->adc_fifo); | |
| 1183 | + val = inw(devpriv->pcibar2 + PCIDAS_AI_DATA_REG); | |
| 1299 | 1184 | comedi_buf_write_samples(s, &val, 1); |
| 1300 | 1185 | |
| 1301 | 1186 | if (cmd->stop_src == TRIG_COUNT && |
| @@ -1304,33 +1189,67 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) · 2 unmodified lines | ||
| 1304 | 1189 | break; |
| 1305 | 1190 | } |
| 1306 | 1191 | } |
| 1307 | − /* clear not-empty interrupt latch */ | |
| 1308 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1309 | − outw(devpriv->adc_fifo_bits | INT, | |
| 1310 | − devpriv->control_status + INT_ADCFIFO); | |
| 1311 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1312 | − } else if (status & EOAI) { | |
| 1192 | + } else if (status & PCIDAS_CTRL_EOAI) { | |
| 1193 | + irq_clr |= PCIDAS_CTRL_EOAI; | |
| 1194 | + | |
| 1313 | 1195 | dev_err(dev->class_dev, |
| 1314 | 1196 | "bug! encountered end of acquisition interrupt?\n"); |
| 1315 | − /* clear EOA interrupt latch */ | |
| 1316 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1317 | − outw(devpriv->adc_fifo_bits | EOAI, | |
| 1318 | − devpriv->control_status + INT_ADCFIFO); | |
| 1319 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1320 | 1197 | } |
| 1198 | + | |
| 1321 | 1199 | /* check for fifo overflow */ |
| 1322 | − if (status & LADFUL) { | |
| 1200 | + if (status & PCIDAS_CTRL_LADFUL) { | |
| 1201 | + irq_clr |= PCIDAS_CTRL_LADFUL; | |
| 1202 | + | |
| 1323 | 1203 | dev_err(dev->class_dev, "fifo overflow\n"); |
| 1324 | − /* clear overflow interrupt latch */ | |
| 1325 | − spin_lock_irqsave(&dev->spinlock, flags); | |
| 1326 | − outw(devpriv->adc_fifo_bits | LADFUL, | |
| 1327 | − devpriv->control_status + INT_ADCFIFO); | |
| 1328 | − spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1329 | 1204 | async->events |= COMEDI_CB_ERROR; |
| 1330 | 1205 | } |
| 1331 | 1206 | |
| 1332 | 1207 | comedi_handle_events(dev, s); |
| 1333 | 1208 | |
| 1209 | + return irq_clr; | |
| 1210 | +} | |
| 1211 | + | |
| 1212 | +static irqreturn_t cb_pcidas_interrupt(int irq, void *d) | |
| 1213 | +{ | |
| 1214 | + struct comedi_device *dev = d; | |
| 1215 | + struct cb_pcidas_private *devpriv = dev->private; | |
| 1216 | + unsigned int irq_clr = 0; | |
| 1217 | + unsigned int amcc_status; | |
| 1218 | + unsigned int status; | |
| 1219 | + | |
| 1220 | + if (!dev->attached) | |
| 1221 | + return IRQ_NONE; | |
| 1222 | + | |
| 1223 | + amcc_status = inl(devpriv->amcc + AMCC_OP_REG_INTCSR); | |
| 1224 | + | |
| 1225 | + if ((INTCSR_INTR_ASSERTED & amcc_status) == 0) | |
| 1226 | + return IRQ_NONE; | |
| 1227 | + | |
| 1228 | + /* make sure mailbox 4 is empty */ | |
| 1229 | + inl_p(devpriv->amcc + AMCC_OP_REG_IMB4); | |
| 1230 | + /* clear interrupt on amcc s5933 */ | |
| 1231 | + outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS, | |
| 1232 | + devpriv->amcc + AMCC_OP_REG_INTCSR); | |
| 1233 | + | |
| 1234 | + status = inw(devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 1235 | + | |
| 1236 | + /* handle analog output interrupts */ | |
| 1237 | + if (status & PCIDAS_CTRL_AO_INT) | |
| 1238 | + irq_clr |= cb_pcidas_ao_interrupt(dev, status); | |
| 1239 | + | |
| 1240 | + /* handle analog input interrupts */ | |
| 1241 | + if (status & PCIDAS_CTRL_AI_INT) | |
| 1242 | + irq_clr |= cb_pcidas_ai_interrupt(dev, status); | |
| 1243 | + | |
| 1244 | + if (irq_clr) { | |
| 1245 | + unsigned long flags; | |
| 1246 | + | |
| 1247 | + spin_lock_irqsave(&dev->spinlock, flags); | |
| 1248 | + outw(devpriv->ctrl | irq_clr, | |
| 1249 | + devpriv->pcibar1 + PCIDAS_CTRL_REG); | |
| 1250 | + spin_unlock_irqrestore(&dev->spinlock, flags); | |
| 1251 | + } | |
| 1252 | + | |
| 1334 | 1253 | return IRQ_HANDLED; |
| 1335 | 1254 | } |
| 1336 | 1255 | |
| @@ -1359,16 +1278,16 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, · 22 unmodified lines | ||
| 1359 | 1278 | if (ret) |
| 1360 | 1279 | return ret; |
| 1361 | 1280 | |
| 1362 | − devpriv->s5933_config = pci_resource_start(pcidev, 0); | |
| 1363 | − devpriv->control_status = pci_resource_start(pcidev, 1); | |
| 1364 | − devpriv->adc_fifo = pci_resource_start(pcidev, 2); | |
| 1281 | + devpriv->amcc = pci_resource_start(pcidev, 0); | |
| 1282 | + devpriv->pcibar1 = pci_resource_start(pcidev, 1); | |
| 1283 | + devpriv->pcibar2 = pci_resource_start(pcidev, 2); | |
| 1365 | 1284 | dev->iobase = pci_resource_start(pcidev, 3); |
| 1366 | − if (board->ao_nchan) | |
| 1367 | − devpriv->ao_registers = pci_resource_start(pcidev, 4); | |
| 1285 | + if (board->has_ao) | |
| 1286 | + devpriv->pcibar4 = pci_resource_start(pcidev, 4); | |
| 1368 | 1287 | |
| 1369 | 1288 | /* disable and clear interrupts on amcc s5933 */ |
| 1370 | 1289 | outl(INTCSR_INBOX_INTR_STATUS, |
| 1371 | − devpriv->s5933_config + AMCC_OP_REG_INTCSR); | |
| 1290 | + devpriv->amcc + AMCC_OP_REG_INTCSR); | |
| 1372 | 1291 | |
| 1373 | 1292 | ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED, |
| 1374 | 1293 | dev->board_name, dev); |
| @@ -1379,12 +1298,12 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, · 4 unmodified lines | ||
| 1379 | 1298 | } |
| 1380 | 1299 | dev->irq = pcidev->irq; |
| 1381 | 1300 | |
| 1382 | − dev->pacer = comedi_8254_init(dev->iobase + ADC8254, | |
| 1301 | + dev->pacer = comedi_8254_init(dev->iobase + PCIDAS_AI_8254_BASE, | |
| 1383 | 1302 | I8254_OSC_BASE_10MHZ, I8254_IO8, 0); |
| 1384 | 1303 | if (!dev->pacer) |
| 1385 | 1304 | return -ENOMEM; |
| 1386 | 1305 | |
| 1387 | − devpriv->ao_pacer = comedi_8254_init(dev->iobase + DAC8254, | |
| 1306 | + devpriv->ao_pacer = comedi_8254_init(dev->iobase + PCIDAS_AO_8254_BASE, | |
| 1388 | 1307 | I8254_OSC_BASE_10MHZ, |
| 1389 | 1308 | I8254_IO8, 0); |
| 1390 | 1309 | if (!devpriv->ao_pacer) |
| @@ -1394,97 +1313,104 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, · 3 unmodified lines | ||
| 1394 | 1313 | if (ret) |
| 1395 | 1314 | return ret; |
| 1396 | 1315 | |
| 1316 | + /* Analog Input subdevice */ | |
| 1397 | 1317 | s = &dev->subdevices[0]; |
| 1398 | − /* analog input subdevice */ | |
| 1399 | − dev->read_subdev = s; | |
| 1400 | − s->type = COMEDI_SUBD_AI; | |
| 1401 | − s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; | |
| 1402 | − /* WARNING: Number of inputs in differential mode is ignored */ | |
| 1403 | − s->n_chan = board->ai_nchan; | |
| 1404 | − s->len_chanlist = board->ai_nchan; | |
| 1405 | − s->maxdata = (1 << board->ai_bits) - 1; | |
| 1406 | − s->range_table = board->ranges; | |
| 1407 | − s->insn_read = cb_pcidas_ai_rinsn; | |
| 1408 | − s->insn_config = ai_config_insn; | |
| 1409 | − s->do_cmd = cb_pcidas_ai_cmd; | |
| 1410 | − s->do_cmdtest = cb_pcidas_ai_cmdtest; | |
| 1411 | − s->cancel = cb_pcidas_cancel; | |
| 1412 | − | |
| 1413 | − /* analog output subdevice */ | |
| 1318 | + s->type = COMEDI_SUBD_AI; | |
| 1319 | + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; | |
| 1320 | + s->n_chan = 16; | |
| 1321 | + s->maxdata = board->is_16bit ? 0xffff : 0x0fff; | |
| 1322 | + s->range_table = board->use_alt_range ? &cb_pcidas_alt_ranges | |
| 1323 | + : &cb_pcidas_ranges; | |
| 1324 | + s->insn_read = cb_pcidas_ai_insn_read; | |
| 1325 | + s->insn_config = cb_pcidas_ai_insn_config; | |
| 1326 | + if (dev->irq) { | |
| 1327 | + dev->read_subdev = s; | |
| 1328 | + s->subdev_flags |= SDF_CMD_READ; | |
| 1329 | + s->len_chanlist = s->n_chan; | |
| 1330 | + s->do_cmd = cb_pcidas_ai_cmd; | |
| 1331 | + s->do_cmdtest = cb_pcidas_ai_cmdtest; | |
| 1332 | + s->cancel = cb_pcidas_ai_cancel; | |
| 1333 | + } | |
| 1334 | + | |
| 1335 | + /* Analog Output subdevice */ | |
| 1414 | 1336 | s = &dev->subdevices[1]; |
| 1415 | − if (board->ao_nchan) { | |
| 1416 | − s->type = COMEDI_SUBD_AO; | |
| 1417 | − s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; | |
| 1418 | − s->n_chan = board->ao_nchan; | |
| 1419 | − /* | |
| 1420 | − * analog out resolution is the same as | |
| 1421 | − * analog input resolution, so use ai_bits | |
| 1422 | − */ | |
| 1423 | − s->maxdata = (1 << board->ai_bits) - 1; | |
| 1424 | − s->range_table = &cb_pcidas_ao_ranges; | |
| 1425 | − /* default to no fifo (*insn_write) */ | |
| 1426 | − s->insn_write = cb_pcidas_ao_nofifo_winsn; | |
| 1337 | + if (board->has_ao) { | |
| 1338 | + s->type = COMEDI_SUBD_AO; | |
| 1339 | + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; | |
| 1340 | + s->n_chan = 2; | |
| 1341 | + s->maxdata = board->is_16bit ? 0xffff : 0x0fff; | |
| 1342 | + s->range_table = &cb_pcidas_ao_ranges; | |
| 1343 | + s->insn_write = (board->has_ao_fifo) | |
| 1344 | + ? cb_pcidas_ao_fifo_insn_write | |
| 1345 | + : cb_pcidas_ao_nofifo_insn_write; | |
| 1427 | 1346 | |
| 1428 | 1347 | ret = comedi_alloc_subdev_readback(s); |
| 1429 | 1348 | if (ret) |
| 1430 | 1349 | return ret; |
| 1431 | 1350 | |
| 1432 | − if (board->has_ao_fifo) { | |
| 1351 | + if (dev->irq && board->has_ao_fifo) { | |
| 1433 | 1352 | dev->write_subdev = s; |
| 1434 | − s->subdev_flags |= SDF_CMD_WRITE; | |
| 1435 | − /* use fifo (*insn_write) instead */ | |
| 1436 | − s->insn_write = cb_pcidas_ao_fifo_winsn; | |
| 1437 | − s->do_cmdtest = cb_pcidas_ao_cmdtest; | |
| 1438 | − s->do_cmd = cb_pcidas_ao_cmd; | |
| 1439 | − s->cancel = cb_pcidas_ao_cancel; | |
| 1353 | + s->subdev_flags |= SDF_CMD_WRITE; | |
| 1354 | + s->do_cmdtest = cb_pcidas_ao_cmdtest; | |
| 1355 | + s->do_cmd = cb_pcidas_ao_cmd; | |
| 1356 | + s->cancel = cb_pcidas_ao_cancel; | |
| 1440 | 1357 | } |
| 1441 | 1358 | } else { |
| 1442 | − s->type = COMEDI_SUBD_UNUSED; | |
| 1359 | + s->type = COMEDI_SUBD_UNUSED; | |
| 1443 | 1360 | } |
| 1444 | 1361 | |
| 1445 | 1362 | /* 8255 */ |
| 1446 | 1363 | s = &dev->subdevices[2]; |
| 1447 | − ret = subdev_8255_init(dev, s, NULL, DIO_8255); | |
| 1364 | + ret = subdev_8255_init(dev, s, NULL, PCIDAS_8255_BASE); | |
| 1448 | 1365 | if (ret) |
| 1449 | 1366 | return ret; |
| 1450 | 1367 | |
| 1451 | − /* serial EEPROM, */ | |
| 1368 | + /* Memory subdevice - serial EEPROM */ | |
| 1452 | 1369 | s = &dev->subdevices[3]; |
| 1453 | − s->type = COMEDI_SUBD_MEMORY; | |
| 1454 | − s->subdev_flags = SDF_READABLE | SDF_INTERNAL; | |
| 1455 | − s->n_chan = 256; | |
| 1456 | − s->maxdata = 0xff; | |
| 1457 | − s->insn_read = eeprom_read_insn; | |
| 1370 | + s->type = COMEDI_SUBD_MEMORY; | |
| 1371 | + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; | |
| 1372 | + s->n_chan = 256; | |
| 1373 | + s->maxdata = 0xff; | |
| 1374 | + s->insn_read = cb_pcidas_eeprom_insn_read; | |
| 1458 | 1375 | |
| 1459 | − /* 8800 caldac */ | |
| 1376 | + /* Calibration subdevice - 8800 caldac */ | |
| 1460 | 1377 | s = &dev->subdevices[4]; |
| 1461 | − s->type = COMEDI_SUBD_CALIB; | |
| 1462 | − s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; | |
| 1463 | − s->n_chan = NUM_CHANNELS_8800; | |
| 1464 | − s->maxdata = 0xff; | |
| 1465 | − s->insn_write = cb_pcidas_caldac_insn_write; | |
| 1378 | + s->type = COMEDI_SUBD_CALIB; | |
| 1379 | + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; | |
| 1380 | + s->n_chan = 8; | |
| 1381 | + s->maxdata = 0xff; | |
| 1382 | + s->insn_write = cb_pcidas_caldac_insn_write; | |
| 1466 | 1383 | |
| 1467 | 1384 | ret = comedi_alloc_subdev_readback(s); |
| 1468 | 1385 | if (ret) |
| 1469 | 1386 | return ret; |
| 1470 | 1387 | |
| 1471 | 1388 | for (i = 0; i < s->n_chan; i++) { |
| 1472 | − caldac_8800_write(dev, i, s->maxdata / 2); | |
| 1473 | − s->readback[i] = s->maxdata / 2; | |
| 1389 | + unsigned int val = s->maxdata / 2; | |
| 1390 | + | |
| 1391 | + /* write 11-bit channel/value to caldac */ | |
| 1392 | + cb_pcidas_calib_write(dev, (i << 8) | val, 11, false); | |
| 1393 | + s->readback[i] = val; | |
| 1474 | 1394 | } |
| 1475 | 1395 | |
| 1476 | − /* trim potentiometer */ | |
| 1396 | + /* Calibration subdevice - trim potentiometer */ | |
| 1477 | 1397 | s = &dev->subdevices[5]; |
| 1478 | − s->type = COMEDI_SUBD_CALIB; | |
| 1479 | − s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; | |
| 1480 | − if (board->trimpot == AD7376) { | |
| 1481 | − s->n_chan = NUM_CHANNELS_7376; | |
| 1482 | − s->maxdata = 0x7f; | |
| 1398 | + s->type = COMEDI_SUBD_CALIB; | |
| 1399 | + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; | |
| 1400 | + if (board->has_ad8402) { | |
| 1401 | + /* | |
| 1402 | + * pci-das1602/16 have an AD8402 trimpot: | |
| 1403 | + * chan 0 : adc gain | |
| 1404 | + * chan 1 : adc postgain offset | |
| 1405 | + */ | |
| 1406 | + s->n_chan = 2; | |
| 1407 | + s->maxdata = 0xff; | |
| 1483 | 1408 | } else { |
| 1484 | − s->n_chan = NUM_CHANNELS_8402; | |
| 1485 | − s->maxdata = 0xff; | |
| 1409 | + /* all other boards have an AD7376 trimpot */ | |
| 1410 | + s->n_chan = 1; | |
| 1411 | + s->maxdata = 0x7f; | |
| 1486 | 1412 | } |
| 1487 | − s->insn_write = cb_pcidas_trimpot_insn_write; | |
| 1413 | + s->insn_write = cb_pcidas_trimpot_insn_write; | |
| 1488 | 1414 | |
| 1489 | 1415 | ret = comedi_alloc_subdev_readback(s); |
| 1490 | 1416 | if (ret) |
| @@ -1495,36 +1421,35 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev, · 4 unmodified lines | ||
| 1495 | 1421 | s->readback[i] = s->maxdata / 2; |
| 1496 | 1422 | } |
| 1497 | 1423 | |
| 1498 | − /* dac08 caldac */ | |
| 1424 | + /* Calibration subdevice - pci-das1602/16 pregain offset (dac08) */ | |
| 1499 | 1425 | s = &dev->subdevices[6]; |
| 1500 | 1426 | if (board->has_dac08) { |
| 1501 | − s->type = COMEDI_SUBD_CALIB; | |
| 1502 | − s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; | |
| 1503 | − s->n_chan = NUM_CHANNELS_DAC08; | |
| 1504 | − s->maxdata = 0xff; | |
| 1505 | − s->insn_write = cb_pcidas_dac08_insn_write; | |
| 1427 | + s->type = COMEDI_SUBD_CALIB; | |
| 1428 | + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; | |
| 1429 | + s->n_chan = 1; | |
| 1430 | + s->maxdata = 0xff; | |
| 1431 | + s->insn_write = cb_pcidas_dac08_insn_write; | |
| 1506 | 1432 | |
| 1507 | 1433 | ret = comedi_alloc_subdev_readback(s); |
| 1508 | 1434 | if (ret) |
| 1509 | 1435 | return ret; |
| 1510 | 1436 | |
| 1511 | 1437 | for (i = 0; i < s->n_chan; i++) { |
| 1512 | − dac08_write(dev, s->maxdata / 2); | |
| 1438 | + cb_pcidas_dac08_write(dev, s->maxdata / 2); | |
| 1513 | 1439 | s->readback[i] = s->maxdata / 2; |
| 1514 | 1440 | } |
| 1515 | 1441 | } else { |
| 1516 | − s->type = COMEDI_SUBD_UNUSED; | |
| 1442 | + s->type = COMEDI_SUBD_UNUSED; | |
| 1517 | 1443 | } |
| 1518 | 1444 | |
| 1519 | 1445 | /* make sure mailbox 4 is empty */ |
| 1520 | − inl(devpriv->s5933_config + AMCC_OP_REG_IMB4); | |
| 1446 | + inl(devpriv->amcc + AMCC_OP_REG_IMB4); | |
| 1521 | 1447 | /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ |
| 1522 | − devpriv->s5933_intcsr_bits = | |
| 1523 | − INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | | |
| 1524 | − INTCSR_INBOX_FULL_INT; | |
| 1448 | + devpriv->amcc_intcsr = INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | | |
| 1449 | + INTCSR_INBOX_FULL_INT; | |
| 1525 | 1450 | /* clear and enable interrupt on amcc s5933 */ |
| 1526 | − outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, | |
| 1527 | − devpriv->s5933_config + AMCC_OP_REG_INTCSR); | |
| 1451 | + outl(devpriv->amcc_intcsr | INTCSR_INBOX_INTR_STATUS, | |
| 1452 | + devpriv->amcc + AMCC_OP_REG_INTCSR); | |
| 1528 | 1453 | |
| 1529 | 1454 | return 0; |
| 1530 | 1455 | } |
| @@ -1534,9 +1459,9 @@ static void cb_pcidas_detach(struct comedi_device *dev) · 3 unmodified lines | ||
| 1534 | 1459 | struct cb_pcidas_private *devpriv = dev->private; |
| 1535 | 1460 | |
| 1536 | 1461 | if (devpriv) { |
| 1537 | − if (devpriv->s5933_config) | |
| 1462 | + if (devpriv->amcc) | |
| 1538 | 1463 | outl(INTCSR_INBOX_INTR_STATUS, |
| 1539 | − devpriv->s5933_config + AMCC_OP_REG_INTCSR); | |
| 1464 | + devpriv->amcc + AMCC_OP_REG_INTCSR); | |
| 1540 | 1465 | kfree(devpriv->ao_pacer); |
| 1541 | 1466 | } |
| 1542 | 1467 | comedi_pci_detach(dev); |
| @@ -1578,5 +1503,5 @@ static struct pci_driver cb_pcidas_pci_driver = { · 35 unmodified lines | ||
| 1578 | 1503 | module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver); |
| 1579 | 1504 | |
| 1580 | 1505 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
| 1581 | −MODULE_DESCRIPTION("Comedi low-level driver"); | |
| 1506 | +MODULE_DESCRIPTION("Comedi driver for MeasurementComputing PCI-DAS series"); | |
| 1582 | 1507 | MODULE_LICENSE("GPL"); |
| @@ -1,49 +1,49 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/comedi_test.c | |
| 2 | + * comedi/drivers/comedi_test.c | |
| 3 | + * | |
| 4 | + * Generates fake waveform signals that can be read through | |
| 5 | + * the command interface. It does _not_ read from any board; | |
| 6 | + * it just generates deterministic waveforms. | |
| 7 | + * Useful for various testing purposes. | |
| 8 | + * | |
| 9 | + * Copyright (C) 2002 Joachim Wuttke <Joachim.Wuttke@icn.siemens.de> | |
| 10 | + * Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 11 | + * | |
| 12 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 13 | + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
| 14 | + * | |
| 15 | + * This program is free software; you can redistribute it and/or modify | |
| 16 | + * it under the terms of the GNU General Public License as published by | |
| 17 | + * the Free Software Foundation; either version 2 of the License, or | |
| 18 | + * (at your option) any later version. | |
| 19 | + * | |
| 20 | + * This program is distributed in the hope that it will be useful, | |
| 21 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 23 | + * GNU General Public License for more details. | |
| 24 | + */ | |
| 3 | 25 | |
| 4 | − Generates fake waveform signals that can be read through | |
| 5 | − the command interface. It does _not_ read from any board; | |
| 6 | − it just generates deterministic waveforms. | |
| 7 | − Useful for various testing purposes. | |
| 8 | − | |
| 9 | − Copyright (C) 2002 Joachim Wuttke <Joachim.Wuttke@icn.siemens.de> | |
| 10 | − Copyright (C) 2002 Frank Mori Hess <fmhess@users.sourceforge.net> | |
| 11 | − | |
| 12 | − COMEDI - Linux Control and Measurement Device Interface | |
| 13 | − Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
| 14 | − | |
| 15 | − This program is free software; you can redistribute it and/or modify | |
| 16 | − it under the terms of the GNU General Public License as published by | |
| 17 | − the Free Software Foundation; either version 2 of the License, or | |
| 18 | − (at your option) any later version. | |
| 19 | − | |
| 20 | − This program is distributed in the hope that it will be useful, | |
| 21 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 23 | − GNU General Public License for more details. | |
| 24 | −*/ | |
| 25 | 26 | /* |
| 26 | −Driver: comedi_test | |
| 27 | −Description: generates fake waveforms | |
| 28 | −Author: Joachim Wuttke <Joachim.Wuttke@icn.siemens.de>, Frank Mori Hess | |
| 29 | − <fmhess@users.sourceforge.net>, ds | |
| 30 | −Devices: | |
| 31 | −Status: works | |
| 32 | −Updated: Sat, 16 Mar 2002 17:34:48 -0800 | |
| 33 | − | |
| 34 | −This driver is mainly for testing purposes, but can also be used to | |
| 35 | −generate sample waveforms on systems that don't have data acquisition | |
| 36 | −hardware. | |
| 37 | − | |
| 38 | −Configuration options: | |
| 39 | − [0] - Amplitude in microvolts for fake waveforms (default 1 volt) | |
| 40 | − [1] - Period in microseconds for fake waveforms (default 0.1 sec) | |
| 41 | − | |
| 42 | −Generates a sawtooth wave on channel 0, square wave on channel 1, additional | |
| 43 | −waveforms could be added to other channels (currently they return flatline | |
| 44 | −zero volts). | |
| 45 | − | |
| 46 | −*/ | |
| 27 | + * Driver: comedi_test | |
| 28 | + * Description: generates fake waveforms | |
| 29 | + * Author: Joachim Wuttke <Joachim.Wuttke@icn.siemens.de>, Frank Mori Hess | |
| 30 | + * <fmhess@users.sourceforge.net>, ds | |
| 31 | + * Devices: | |
| 32 | + * Status: works | |
| 33 | + * Updated: Sat, 16 Mar 2002 17:34:48 -0800 | |
| 34 | + * | |
| 35 | + * This driver is mainly for testing purposes, but can also be used to | |
| 36 | + * generate sample waveforms on systems that don't have data acquisition | |
| 37 | + * hardware. | |
| 38 | + * | |
| 39 | + * Configuration options: | |
| 40 | + * [0] - Amplitude in microvolts for fake waveforms (default 1 volt) | |
| 41 | + * [1] - Period in microseconds for fake waveforms (default 0.1 sec) | |
| 42 | + * | |
| 43 | + * Generates a sawtooth wave on channel 0, square wave on channel 1, additional | |
| 44 | + * waveforms could be added to other channels (currently they return flatline | |
| 45 | + * zero volts). | |
| 46 | + */ | |
| 47 | 47 | |
| 48 | 48 | #include <linux/module.h> |
| 49 | 49 | #include "../comedidev.h" |
| @@ -52,30 +52,31 @@ zero volts). · 2 unmodified lines | ||
| 52 | 52 | |
| 53 | 53 | #include <linux/timer.h> |
| 54 | 54 | #include <linux/ktime.h> |
| 55 | +#include <linux/jiffies.h> | |
| 55 | 56 | |
| 56 | 57 | #define N_CHANS 8 |
| 57 | 58 | |
| 58 | 59 | enum waveform_state_bits { |
| 59 | − WAVEFORM_AI_RUNNING = 0 | |
| 60 | + WAVEFORM_AI_RUNNING, | |
| 61 | + WAVEFORM_AO_RUNNING | |
| 60 | 62 | }; |
| 61 | 63 | |
| 62 | 64 | /* Data unique to this driver */ |
| 63 | 65 | struct waveform_private { |
| 64 | − struct timer_list timer; | |
| 65 | − ktime_t last; /* time last timer interrupt occurred */ | |
| 66 | − unsigned int uvolt_amplitude; /* waveform amplitude in microvolts */ | |
| 67 | − unsigned long usec_period; /* waveform period in microseconds */ | |
| 68 | − unsigned long usec_current; /* current time (mod waveform period) */ | |
| 69 | − unsigned long usec_remainder; /* usec since last scan */ | |
| 66 | + struct timer_list ai_timer; /* timer for AI commands */ | |
| 67 | + u64 ai_convert_time; /* time of next AI conversion in usec */ | |
| 68 | + unsigned int wf_amplitude; /* waveform amplitude in microvolts */ | |
| 69 | + unsigned int wf_period; /* waveform period in microseconds */ | |
| 70 | + unsigned int wf_current; /* current time in waveform period */ | |
| 70 | 71 | unsigned long state_bits; |
| 71 | − unsigned int scan_period; /* scan period in usec */ | |
| 72 | − unsigned int convert_period; /* conversion period in usec */ | |
| 73 | − unsigned int ao_loopbacks[N_CHANS]; | |
| 72 | + unsigned int ai_scan_period; /* AI scan period in usec */ | |
| 73 | + unsigned int ai_convert_period; /* AI conversion period in usec */ | |
| 74 | + struct timer_list ao_timer; /* timer for AO commands */ | |
| 75 | + u64 ao_last_scan_time; /* time of previous AO scan in usec */ | |
| 76 | + unsigned int ao_scan_period; /* AO scan period in usec */ | |
| 77 | + unsigned short ao_loopbacks[N_CHANS]; | |
| 74 | 78 | }; |
| 75 | 79 | |
| 76 | −/* 1000 nanosec in a microsec */ | |
| 77 | −static const int nano_per_micro = 1000; | |
| 78 | − | |
| 79 | 80 | /* fake analog input ranges */ |
| 80 | 81 | static const struct comedi_lrange waveform_ai_ranges = { |
| 81 | 82 | 2, { |
| @@ -86,7 +87,7 @@ static const struct comedi_lrange waveform_ai_ranges = { · 4 unmodified lines | ||
| 86 | 87 | |
| 87 | 88 | static unsigned short fake_sawtooth(struct comedi_device *dev, |
| 88 | 89 | unsigned int range_index, |
| 89 | − unsigned long current_time) | |
| 90 | + unsigned int current_time) | |
| 90 | 91 | { |
| 91 | 92 | struct waveform_private *devpriv = dev->private; |
| 92 | 93 | struct comedi_subdevice *s = dev->read_subdev; |
| @@ -97,21 +98,28 @@ static unsigned short fake_sawtooth(struct comedi_device *dev, · 4 unmodified lines | ||
| 97 | 98 | u64 binary_amplitude; |
| 98 | 99 | |
| 99 | 100 | binary_amplitude = s->maxdata; |
| 100 | − binary_amplitude *= devpriv->uvolt_amplitude; | |
| 101 | + binary_amplitude *= devpriv->wf_amplitude; | |
| 101 | 102 | do_div(binary_amplitude, krange->max - krange->min); |
| 102 | 103 | |
| 103 | − current_time %= devpriv->usec_period; | |
| 104 | 104 | value = current_time; |
| 105 | 105 | value *= binary_amplitude * 2; |
| 106 | − do_div(value, devpriv->usec_period); | |
| 107 | − value -= binary_amplitude; /* get rid of sawtooth's dc offset */ | |
| 106 | + do_div(value, devpriv->wf_period); | |
| 107 | + value += offset; | |
| 108 | + /* get rid of sawtooth's dc offset and clamp value */ | |
| 109 | + if (value < binary_amplitude) { | |
| 110 | + value = 0; /* negative saturation */ | |
| 111 | + } else { | |
| 112 | + value -= binary_amplitude; | |
| 113 | + if (value > s->maxdata) | |
| 114 | + value = s->maxdata; /* positive saturation */ | |
| 115 | + } | |
| 108 | 116 | |
| 109 | − return offset + value; | |
| 117 | + return value; | |
| 110 | 118 | } |
| 111 | 119 | |
| 112 | 120 | static unsigned short fake_squarewave(struct comedi_device *dev, |
| 113 | 121 | unsigned int range_index, |
| 114 | − unsigned long current_time) | |
| 122 | + unsigned int current_time) | |
| 115 | 123 | { |
| 116 | 124 | struct waveform_private *devpriv = dev->private; |
| 117 | 125 | struct comedi_subdevice *s = dev->read_subdev; |
| @@ -119,21 +127,29 @@ static unsigned short fake_squarewave(struct comedi_device *dev, · 1 unmodified line | ||
| 119 | 127 | u64 value; |
| 120 | 128 | const struct comedi_krange *krange = |
| 121 | 129 | &s->range_table->range[range_index]; |
| 122 | − current_time %= devpriv->usec_period; | |
| 123 | 130 | |
| 124 | 131 | value = s->maxdata; |
| 125 | − value *= devpriv->uvolt_amplitude; | |
| 132 | + value *= devpriv->wf_amplitude; | |
| 126 | 133 | do_div(value, krange->max - krange->min); |
| 127 | 134 | |
| 128 | − if (current_time < devpriv->usec_period / 2) | |
| 129 | − value *= -1; | |
| 135 | + /* get one of two values for square-wave and clamp */ | |
| 136 | + if (current_time < devpriv->wf_period / 2) { | |
| 137 | + if (offset < value) | |
| 138 | + value = 0; /* negative saturation */ | |
| 139 | + else | |
| 140 | + value = offset - value; | |
| 141 | + } else { | |
| 142 | + value += offset; | |
| 143 | + if (value > s->maxdata) | |
| 144 | + value = s->maxdata; /* positive saturation */ | |
| 145 | + } | |
| 130 | 146 | |
| 131 | − return offset + value; | |
| 147 | + return value; | |
| 132 | 148 | } |
| 133 | 149 | |
| 134 | 150 | static unsigned short fake_flatline(struct comedi_device *dev, |
| 135 | 151 | unsigned int range_index, |
| 136 | − unsigned long current_time) | |
| 152 | + unsigned int current_time) | |
| 137 | 153 | { |
| 138 | 154 | return dev->read_subdev->maxdata / 2; |
| 139 | 155 | } |
| @@ -141,7 +157,7 @@ static unsigned short fake_flatline(struct comedi_device *dev, · 1 unmodified line | ||
| 141 | 157 | /* generates a different waveform depending on what channel is read */ |
| 142 | 158 | static unsigned short fake_waveform(struct comedi_device *dev, |
| 143 | 159 | unsigned int channel, unsigned int range, |
| 144 | − unsigned long current_time) | |
| 160 | + unsigned int current_time) | |
| 145 | 161 | { |
| 146 | 162 | enum { |
| 147 | 163 | SAWTOOTH_CHAN, |
| @@ -160,58 +176,62 @@ static unsigned short fake_waveform(struct comedi_device *dev, · 12 unmodified lines | ||
| 160 | 176 | } |
| 161 | 177 | |
| 162 | 178 | /* |
| 163 | − This is the background routine used to generate arbitrary data. | |
| 164 | − It should run in the background; therefore it is scheduled by | |
| 165 | − a timer mechanism. | |
| 166 | −*/ | |
| 167 | −static void waveform_ai_interrupt(unsigned long arg) | |
| 179 | + * This is the background routine used to generate arbitrary data. | |
| 180 | + * It should run in the background; therefore it is scheduled by | |
| 181 | + * a timer mechanism. | |
| 182 | + */ | |
| 183 | +static void waveform_ai_timer(unsigned long arg) | |
| 168 | 184 | { |
| 169 | 185 | struct comedi_device *dev = (struct comedi_device *)arg; |
| 170 | 186 | struct waveform_private *devpriv = dev->private; |
| 171 | 187 | struct comedi_subdevice *s = dev->read_subdev; |
| 172 | 188 | struct comedi_async *async = s->async; |
| 173 | 189 | struct comedi_cmd *cmd = &async->cmd; |
| 174 | − unsigned int i, j; | |
| 175 | − /* all times in microsec */ | |
| 176 | − unsigned long elapsed_time; | |
| 177 | − unsigned int num_scans; | |
| 178 | − ktime_t now; | |
| 190 | + u64 now; | |
| 191 | + unsigned int nsamples; | |
| 192 | + unsigned int time_increment; | |
| 179 | 193 | |
| 180 | 194 | /* check command is still active */ |
| 181 | 195 | if (!test_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits)) |
| 182 | 196 | return; |
| 183 | 197 | |
| 184 | − now = ktime_get(); | |
| 185 | − | |
| 186 | − elapsed_time = ktime_to_us(ktime_sub(now, devpriv->last)); | |
| 187 | − devpriv->last = now; | |
| 188 | − num_scans = | |
| 189 | − (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period; | |
| 190 | − devpriv->usec_remainder = | |
| 191 | − (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; | |
| 192 | − | |
| 193 | − num_scans = comedi_nscans_left(s, num_scans); | |
| 194 | − for (i = 0; i < num_scans; i++) { | |
| 195 | − for (j = 0; j < cmd->chanlist_len; j++) { | |
| 196 | − unsigned short sample; | |
| 197 | − | |
| 198 | − sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), | |
| 199 | − CR_RANGE(cmd->chanlist[j]), | |
| 200 | − devpriv->usec_current + | |
| 201 | − i * devpriv->scan_period + | |
| 202 | − j * devpriv->convert_period); | |
| 203 | − comedi_buf_write_samples(s, &sample, 1); | |
| 198 | + now = ktime_to_us(ktime_get()); | |
| 199 | + nsamples = comedi_nsamples_left(s, UINT_MAX); | |
| 200 | + | |
| 201 | + while (nsamples && devpriv->ai_convert_time < now) { | |
| 202 | + unsigned int chanspec = cmd->chanlist[async->cur_chan]; | |
| 203 | + unsigned short sample; | |
| 204 | + | |
| 205 | + sample = fake_waveform(dev, CR_CHAN(chanspec), | |
| 206 | + CR_RANGE(chanspec), devpriv->wf_current); | |
| 207 | + if (comedi_buf_write_samples(s, &sample, 1) == 0) | |
| 208 | + goto overrun; | |
| 209 | + time_increment = devpriv->ai_convert_period; | |
| 210 | + if (async->scan_progress == 0) { | |
| 211 | + /* done last conversion in scan, so add dead time */ | |
| 212 | + time_increment += devpriv->ai_scan_period - | |
| 213 | + devpriv->ai_convert_period * | |
| 214 | + cmd->scan_end_arg; | |
| 204 | 215 | } |
| 216 | + devpriv->wf_current += time_increment; | |
| 217 | + if (devpriv->wf_current >= devpriv->wf_period) | |
| 218 | + devpriv->wf_current %= devpriv->wf_period; | |
| 219 | + devpriv->ai_convert_time += time_increment; | |
| 220 | + nsamples--; | |
| 205 | 221 | } |
| 206 | 222 | |
| 207 | − devpriv->usec_current += elapsed_time; | |
| 208 | − devpriv->usec_current %= devpriv->usec_period; | |
| 209 | − | |
| 210 | − if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) | |
| 223 | + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { | |
| 211 | 224 | async->events |= COMEDI_CB_EOA; |
| 212 | − else | |
| 213 | − mod_timer(&devpriv->timer, jiffies + 1); | |
| 225 | + } else { | |
| 226 | + if (devpriv->ai_convert_time > now) | |
| 227 | + time_increment = devpriv->ai_convert_time - now; | |
| 228 | + else | |
| 229 | + time_increment = 1; | |
| 230 | + mod_timer(&devpriv->ai_timer, | |
| 231 | + jiffies + usecs_to_jiffies(time_increment)); | |
| 232 | + } | |
| 214 | 233 | |
| 234 | +overrun: | |
| 215 | 235 | comedi_handle_events(dev, s); |
| 216 | 236 | } |
| 217 | 237 | |
| @@ -220,12 +240,13 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, · 2 unmodified lines | ||
| 220 | 240 | struct comedi_cmd *cmd) |
| 221 | 241 | { |
| 222 | 242 | int err = 0; |
| 223 | − unsigned int arg; | |
| 243 | + unsigned int arg, limit; | |
| 224 | 244 | |
| 225 | 245 | /* Step 1 : check if triggers are trivially valid */ |
| 226 | 246 | |
| 227 | 247 | err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); |
| 228 | − err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); | |
| 248 | + err |= comedi_check_trigger_src(&cmd->scan_begin_src, | |
| 249 | + TRIG_FOLLOW | TRIG_TIMER); | |
| 229 | 250 | err |= comedi_check_trigger_src(&cmd->convert_src, |
| 230 | 251 | TRIG_NOW | TRIG_TIMER); |
| 231 | 252 | err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); |
| @@ -241,6 +262,9 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, · 9 unmodified lines | ||
| 241 | 262 | |
| 242 | 263 | /* Step 2b : and mutually compatible */ |
| 243 | 264 | |
| 265 | + if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) | |
| 266 | + err |= -EINVAL; /* scan period would be 0 */ | |
| 267 | + | |
| 244 | 268 | if (err) |
| 245 | 269 | return 2; |
| 246 | 270 | |
| @@ -248,18 +272,20 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, · 1 unmodified line | ||
| 248 | 272 | |
| 249 | 273 | err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); |
| 250 | 274 | |
| 251 | − if (cmd->convert_src == TRIG_NOW) | |
| 275 | + if (cmd->convert_src == TRIG_NOW) { | |
| 252 | 276 | err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); |
| 277 | + } else { /* cmd->convert_src == TRIG_TIMER */ | |
| 278 | + if (cmd->scan_begin_src == TRIG_FOLLOW) { | |
| 279 | + err |= comedi_check_trigger_arg_min(&cmd->convert_arg, | |
| 280 | + NSEC_PER_USEC); | |
| 281 | + } | |
| 282 | + } | |
| 253 | 283 | |
| 254 | − if (cmd->scan_begin_src == TRIG_TIMER) { | |
| 284 | + if (cmd->scan_begin_src == TRIG_FOLLOW) { | |
| 285 | + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); | |
| 286 | + } else { /* cmd->scan_begin_src == TRIG_TIMER */ | |
| 255 | 287 | err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, |
| 256 | − nano_per_micro); | |
| 257 | − if (cmd->convert_src == TRIG_TIMER) { | |
| 258 | − err |= comedi_check_trigger_arg_min(&cmd-> | |
| 259 | − scan_begin_arg, | |
| 260 | − cmd->convert_arg * | |
| 261 | − cmd->chanlist_len); | |
| 262 | − } | |
| 288 | + NSEC_PER_USEC); | |
| 263 | 289 | } |
| 264 | 290 | |
| 265 | 291 | err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); |
| @@ -268,7 +294,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, · 2 unmodified lines | ||
| 268 | 294 | |
| 269 | 295 | if (cmd->stop_src == TRIG_COUNT) |
| 270 | 296 | err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); |
| 271 | − else /* TRIG_NONE */ | |
| 297 | + else /* cmd->stop_src == TRIG_NONE */ | |
| 272 | 298 | err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); |
| 273 | 299 | |
| 274 | 300 | if (err) |
| @@ -276,21 +302,34 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, · 1 unmodified line | ||
| 276 | 302 | |
| 277 | 303 | /* step 4: fix up any arguments */ |
| 278 | 304 | |
| 279 | − if (cmd->scan_begin_src == TRIG_TIMER) { | |
| 280 | − arg = cmd->scan_begin_arg; | |
| 281 | − /* round to nearest microsec */ | |
| 282 | − arg = nano_per_micro * | |
| 283 | − ((arg + (nano_per_micro / 2)) / nano_per_micro); | |
| 284 | − err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); | |
| 285 | − } | |
| 286 | 305 | if (cmd->convert_src == TRIG_TIMER) { |
| 306 | + /* round convert_arg to nearest microsecond */ | |
| 287 | 307 | arg = cmd->convert_arg; |
| 288 | − /* round to nearest microsec */ | |
| 289 | − arg = nano_per_micro * | |
| 290 | − ((arg + (nano_per_micro / 2)) / nano_per_micro); | |
| 308 | + arg = min(arg, | |
| 309 | + rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); | |
| 310 | + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); | |
| 311 | + if (cmd->scan_begin_arg == TRIG_TIMER) { | |
| 312 | + /* limit convert_arg to keep scan_begin_arg in range */ | |
| 313 | + limit = UINT_MAX / cmd->scan_end_arg; | |
| 314 | + limit = rounddown(limit, (unsigned int)NSEC_PER_SEC); | |
| 315 | + arg = min(arg, limit); | |
| 316 | + } | |
| 291 | 317 | err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); |
| 292 | 318 | } |
| 293 | 319 | |
| 320 | + if (cmd->scan_begin_src == TRIG_TIMER) { | |
| 321 | + /* round scan_begin_arg to nearest microsecond */ | |
| 322 | + arg = cmd->scan_begin_arg; | |
| 323 | + arg = min(arg, | |
| 324 | + rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); | |
| 325 | + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); | |
| 326 | + if (cmd->convert_src == TRIG_TIMER) { | |
| 327 | + /* but ensure scan_begin_arg is large enough */ | |
| 328 | + arg = max(arg, cmd->convert_arg * cmd->scan_end_arg); | |
| 329 | + } | |
| 330 | + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); | |
| 331 | + } | |
| 332 | + | |
| 294 | 333 | if (err) |
| 295 | 334 | return 4; |
| 296 | 335 | |
| @@ -302,6 +341,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, · 5 unmodified lines | ||
| 302 | 341 | { |
| 303 | 342 | struct waveform_private *devpriv = dev->private; |
| 304 | 343 | struct comedi_cmd *cmd = &s->async->cmd; |
| 344 | + unsigned int first_convert_time; | |
| 345 | + u64 wf_current; | |
| 305 | 346 | |
| 306 | 347 | if (cmd->flags & CMDF_PRIORITY) { |
| 307 | 348 | dev_err(dev->class_dev, |
| @@ -309,24 +350,48 @@ static int waveform_ai_cmd(struct comedi_device *dev, · 1 unmodified line | ||
| 309 | 350 | return -1; |
| 310 | 351 | } |
| 311 | 352 | |
| 312 | − devpriv->scan_period = cmd->scan_begin_arg / nano_per_micro; | |
| 313 | − | |
| 314 | 353 | if (cmd->convert_src == TRIG_NOW) |
| 315 | − devpriv->convert_period = 0; | |
| 316 | − else /* TRIG_TIMER */ | |
| 317 | − devpriv->convert_period = cmd->convert_arg / nano_per_micro; | |
| 354 | + devpriv->ai_convert_period = 0; | |
| 355 | + else /* cmd->convert_src == TRIG_TIMER */ | |
| 356 | + devpriv->ai_convert_period = cmd->convert_arg / NSEC_PER_USEC; | |
| 357 | + | |
| 358 | + if (cmd->scan_begin_src == TRIG_FOLLOW) { | |
| 359 | + devpriv->ai_scan_period = devpriv->ai_convert_period * | |
| 360 | + cmd->scan_end_arg; | |
| 361 | + } else { /* cmd->scan_begin_src == TRIG_TIMER */ | |
| 362 | + devpriv->ai_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; | |
| 363 | + } | |
| 318 | 364 | |
| 319 | − devpriv->last = ktime_get(); | |
| 320 | − devpriv->usec_current = | |
| 321 | − ((u32)ktime_to_us(devpriv->last)) % devpriv->usec_period; | |
| 322 | − devpriv->usec_remainder = 0; | |
| 365 | + /* | |
| 366 | + * Simulate first conversion to occur at convert period after | |
| 367 | + * conversion timer starts. If scan_begin_src is TRIG_FOLLOW, assume | |
| 368 | + * the conversion timer starts immediately. If scan_begin_src is | |
| 369 | + * TRIG_TIMER, assume the conversion timer starts after the scan | |
| 370 | + * period. | |
| 371 | + */ | |
| 372 | + first_convert_time = devpriv->ai_convert_period; | |
| 373 | + if (cmd->scan_begin_src == TRIG_TIMER) | |
| 374 | + first_convert_time += devpriv->ai_scan_period; | |
| 375 | + devpriv->ai_convert_time = ktime_to_us(ktime_get()) + | |
| 376 | + first_convert_time; | |
| 377 | + | |
| 378 | + /* Determine time within waveform period at time of conversion. */ | |
| 379 | + wf_current = devpriv->ai_convert_time; | |
| 380 | + devpriv->wf_current = do_div(wf_current, devpriv->wf_period); | |
| 381 | + | |
| 382 | + /* | |
| 383 | + * Schedule timer to expire just after first conversion time. | |
| 384 | + * Seem to need an extra jiffy here, otherwise timer expires slightly | |
| 385 | + * early! | |
| 386 | + */ | |
| 387 | + devpriv->ai_timer.expires = | |
| 388 | + jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1; | |
| 323 | 389 | |
| 324 | − devpriv->timer.expires = jiffies + 1; | |
| 325 | 390 | /* mark command as active */ |
| 326 | 391 | smp_mb__before_atomic(); |
| 327 | 392 | set_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits); |
| 328 | 393 | smp_mb__after_atomic(); |
| 329 | − add_timer(&devpriv->timer); | |
| 394 | + add_timer(&devpriv->ai_timer); | |
| 330 | 395 | return 0; |
| 331 | 396 | } |
| 332 | 397 | |
| @@ -339,7 +404,7 @@ static int waveform_ai_cancel(struct comedi_device *dev, · 6 unmodified lines | ||
| 339 | 404 | clear_bit(WAVEFORM_AI_RUNNING, &devpriv->state_bits); |
| 340 | 405 | smp_mb__after_atomic(); |
| 341 | 406 | /* cannot call del_timer_sync() as may be called from timer routine */ |
| 342 | − del_timer(&devpriv->timer); | |
| 407 | + del_timer(&devpriv->ai_timer); | |
| 343 | 408 | return 0; |
| 344 | 409 | } |
| 345 | 410 | |
| @@ -356,6 +421,201 @@ static int waveform_ai_insn_read(struct comedi_device *dev, · 10 unmodified lines | ||
| 356 | 421 | return insn->n; |
| 357 | 422 | } |
| 358 | 423 | |
| 424 | +/* | |
| 425 | + * This is the background routine to handle AO commands, scheduled by | |
| 426 | + * a timer mechanism. | |
| 427 | + */ | |
| 428 | +static void waveform_ao_timer(unsigned long arg) | |
| 429 | +{ | |
| 430 | + struct comedi_device *dev = (struct comedi_device *)arg; | |
| 431 | + struct waveform_private *devpriv = dev->private; | |
| 432 | + struct comedi_subdevice *s = dev->write_subdev; | |
| 433 | + struct comedi_async *async = s->async; | |
| 434 | + struct comedi_cmd *cmd = &async->cmd; | |
| 435 | + u64 now; | |
| 436 | + u64 scans_since; | |
| 437 | + unsigned int scans_avail = 0; | |
| 438 | + | |
| 439 | + /* check command is still active */ | |
| 440 | + if (!test_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits)) | |
| 441 | + return; | |
| 442 | + | |
| 443 | + /* determine number of scan periods since last time */ | |
| 444 | + now = ktime_to_us(ktime_get()); | |
| 445 | + scans_since = now - devpriv->ao_last_scan_time; | |
| 446 | + do_div(scans_since, devpriv->ao_scan_period); | |
| 447 | + if (scans_since) { | |
| 448 | + unsigned int i; | |
| 449 | + | |
| 450 | + /* determine scans in buffer, limit to scans to do this time */ | |
| 451 | + scans_avail = comedi_nscans_left(s, 0); | |
| 452 | + if (scans_avail > scans_since) | |
| 453 | + scans_avail = scans_since; | |
| 454 | + if (scans_avail) { | |
| 455 | + /* skip all but the last scan to save processing time */ | |
| 456 | + if (scans_avail > 1) { | |
| 457 | + unsigned int skip_bytes, nbytes; | |
| 458 | + | |
| 459 | + skip_bytes = | |
| 460 | + comedi_samples_to_bytes(s, cmd->scan_end_arg * | |
| 461 | + (scans_avail - 1)); | |
| 462 | + nbytes = comedi_buf_read_alloc(s, skip_bytes); | |
| 463 | + comedi_buf_read_free(s, nbytes); | |
| 464 | + comedi_inc_scan_progress(s, nbytes); | |
| 465 | + if (nbytes < skip_bytes) { | |
| 466 | + /* unexpected underrun! (cancelled?) */ | |
| 467 | + async->events |= COMEDI_CB_OVERFLOW; | |
| 468 | + goto underrun; | |
| 469 | + } | |
| 470 | + } | |
| 471 | + /* output the last scan */ | |
| 472 | + for (i = 0; i < cmd->scan_end_arg; i++) { | |
| 473 | + unsigned int chan = CR_CHAN(cmd->chanlist[i]); | |
| 474 | + | |
| 475 | + if (comedi_buf_read_samples(s, | |
| 476 | + &devpriv-> | |
| 477 | + ao_loopbacks[chan], | |
| 478 | + 1) == 0) { | |
| 479 | + /* unexpected underrun! (cancelled?) */ | |
| 480 | + async->events |= COMEDI_CB_OVERFLOW; | |
| 481 | + goto underrun; | |
| 482 | + } | |
| 483 | + } | |
| 484 | + /* advance time of last scan */ | |
| 485 | + devpriv->ao_last_scan_time += | |
| 486 | + (u64)scans_avail * devpriv->ao_scan_period; | |
| 487 | + } | |
| 488 | + } | |
| 489 | + if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { | |
| 490 | + async->events |= COMEDI_CB_EOA; | |
| 491 | + } else if (scans_avail < scans_since) { | |
| 492 | + async->events |= COMEDI_CB_OVERFLOW; | |
| 493 | + } else { | |
| 494 | + unsigned int time_inc = devpriv->ao_last_scan_time + | |
| 495 | + devpriv->ao_scan_period - now; | |
| 496 | + | |
| 497 | + mod_timer(&devpriv->ao_timer, | |
| 498 | + jiffies + usecs_to_jiffies(time_inc)); | |
| 499 | + } | |
| 500 | + | |
| 501 | +underrun: | |
| 502 | + comedi_handle_events(dev, s); | |
| 503 | +} | |
| 504 | + | |
| 505 | +static int waveform_ao_inttrig_start(struct comedi_device *dev, | |
| 506 | + struct comedi_subdevice *s, | |
| 507 | + unsigned int trig_num) | |
| 508 | +{ | |
| 509 | + struct waveform_private *devpriv = dev->private; | |
| 510 | + struct comedi_async *async = s->async; | |
| 511 | + struct comedi_cmd *cmd = &async->cmd; | |
| 512 | + | |
| 513 | + if (trig_num != cmd->start_arg) | |
| 514 | + return -EINVAL; | |
| 515 | + | |
| 516 | + async->inttrig = NULL; | |
| 517 | + | |
| 518 | + devpriv->ao_last_scan_time = ktime_to_us(ktime_get()); | |
| 519 | + devpriv->ao_timer.expires = | |
| 520 | + jiffies + usecs_to_jiffies(devpriv->ao_scan_period); | |
| 521 | + | |
| 522 | + /* mark command as active */ | |
| 523 | + smp_mb__before_atomic(); | |
| 524 | + set_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits); | |
| 525 | + smp_mb__after_atomic(); | |
| 526 | + add_timer(&devpriv->ao_timer); | |
| 527 | + | |
| 528 | + return 1; | |
| 529 | +} | |
| 530 | + | |
| 531 | +static int waveform_ao_cmdtest(struct comedi_device *dev, | |
| 532 | + struct comedi_subdevice *s, | |
| 533 | + struct comedi_cmd *cmd) | |
| 534 | +{ | |
| 535 | + int err = 0; | |
| 536 | + unsigned int arg; | |
| 537 | + | |
| 538 | + /* Step 1 : check if triggers are trivially valid */ | |
| 539 | + | |
| 540 | + err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT); | |
| 541 | + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); | |
| 542 | + err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); | |
| 543 | + err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); | |
| 544 | + err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); | |
| 545 | + | |
| 546 | + if (err) | |
| 547 | + return 1; | |
| 548 | + | |
| 549 | + /* Step 2a : make sure trigger sources are unique */ | |
| 550 | + | |
| 551 | + err |= comedi_check_trigger_is_unique(cmd->stop_src); | |
| 552 | + | |
| 553 | + /* Step 2b : and mutually compatible */ | |
| 554 | + | |
| 555 | + if (err) | |
| 556 | + return 2; | |
| 557 | + | |
| 558 | + /* Step 3: check if arguments are trivially valid */ | |
| 559 | + | |
| 560 | + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, | |
| 561 | + NSEC_PER_USEC); | |
| 562 | + err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); | |
| 563 | + err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); | |
| 564 | + err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, | |
| 565 | + cmd->chanlist_len); | |
| 566 | + if (cmd->stop_src == TRIG_COUNT) | |
| 567 | + err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); | |
| 568 | + else /* cmd->stop_src == TRIG_NONE */ | |
| 569 | + err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); | |
| 570 | + | |
| 571 | + if (err) | |
| 572 | + return 3; | |
| 573 | + | |
| 574 | + /* step 4: fix up any arguments */ | |
| 575 | + | |
| 576 | + /* round scan_begin_arg to nearest microsecond */ | |
| 577 | + arg = cmd->scan_begin_arg; | |
| 578 | + arg = min(arg, rounddown(UINT_MAX, (unsigned int)NSEC_PER_USEC)); | |
| 579 | + arg = NSEC_PER_USEC * DIV_ROUND_CLOSEST(arg, NSEC_PER_USEC); | |
| 580 | + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); | |
| 581 | + | |
| 582 | + if (err) | |
| 583 | + return 4; | |
| 584 | + | |
| 585 | + return 0; | |
| 586 | +} | |
| 587 | + | |
| 588 | +static int waveform_ao_cmd(struct comedi_device *dev, | |
| 589 | + struct comedi_subdevice *s) | |
| 590 | +{ | |
| 591 | + struct waveform_private *devpriv = dev->private; | |
| 592 | + struct comedi_cmd *cmd = &s->async->cmd; | |
| 593 | + | |
| 594 | + if (cmd->flags & CMDF_PRIORITY) { | |
| 595 | + dev_err(dev->class_dev, | |
| 596 | + "commands at RT priority not supported in this driver\n"); | |
| 597 | + return -1; | |
| 598 | + } | |
| 599 | + | |
| 600 | + devpriv->ao_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; | |
| 601 | + s->async->inttrig = waveform_ao_inttrig_start; | |
| 602 | + return 0; | |
| 603 | +} | |
| 604 | + | |
| 605 | +static int waveform_ao_cancel(struct comedi_device *dev, | |
| 606 | + struct comedi_subdevice *s) | |
| 607 | +{ | |
| 608 | + struct waveform_private *devpriv = dev->private; | |
| 609 | + | |
| 610 | + s->async->inttrig = NULL; | |
| 611 | + /* mark command as no longer active */ | |
| 612 | + clear_bit(WAVEFORM_AO_RUNNING, &devpriv->state_bits); | |
| 613 | + smp_mb__after_atomic(); | |
| 614 | + /* cannot call del_timer_sync() as may be called from timer routine */ | |
| 615 | + del_timer(&devpriv->ao_timer); | |
| 616 | + return 0; | |
| 617 | +} | |
| 618 | + | |
| 359 | 619 | static int waveform_ao_insn_write(struct comedi_device *dev, |
| 360 | 620 | struct comedi_subdevice *s, |
| 361 | 621 | struct comedi_insn *insn, unsigned int *data) |
| @@ -389,8 +649,8 @@ static int waveform_attach(struct comedi_device *dev, · 27 unmodified lines | ||
| 389 | 649 | if (period <= 0) |
| 390 | 650 | period = 100000; /* 0.1 sec */ |
| 391 | 651 | |
| 392 | − devpriv->uvolt_amplitude = amplitude; | |
| 393 | − devpriv->usec_period = period; | |
| 652 | + devpriv->wf_amplitude = amplitude; | |
| 653 | + devpriv->wf_period = period; | |
| 394 | 654 | |
| 395 | 655 | ret = comedi_alloc_subdevices(dev, 2); |
| 396 | 656 | if (ret) |
| @@ -414,23 +674,28 @@ static int waveform_attach(struct comedi_device *dev, · 17 unmodified lines | ||
| 414 | 674 | dev->write_subdev = s; |
| 415 | 675 | /* analog output subdevice (loopback) */ |
| 416 | 676 | s->type = COMEDI_SUBD_AO; |
| 417 | − s->subdev_flags = SDF_WRITABLE | SDF_GROUND; | |
| 677 | + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; | |
| 418 | 678 | s->n_chan = N_CHANS; |
| 419 | 679 | s->maxdata = 0xffff; |
| 420 | 680 | s->range_table = &waveform_ai_ranges; |
| 681 | + s->len_chanlist = s->n_chan; | |
| 421 | 682 | s->insn_write = waveform_ao_insn_write; |
| 683 | + s->insn_read = waveform_ai_insn_read; /* do same as AI insn_read */ | |
| 684 | + s->do_cmd = waveform_ao_cmd; | |
| 685 | + s->do_cmdtest = waveform_ao_cmdtest; | |
| 686 | + s->cancel = waveform_ao_cancel; | |
| 422 | 687 | |
| 423 | 688 | /* Our default loopback value is just a 0V flatline */ |
| 424 | 689 | for (i = 0; i < s->n_chan; i++) |
| 425 | 690 | devpriv->ao_loopbacks[i] = s->maxdata / 2; |
| 426 | 691 | |
| 427 | − setup_timer(&devpriv->timer, waveform_ai_interrupt, | |
| 428 | − (unsigned long)dev); | |
| 692 | + setup_timer(&devpriv->ai_timer, waveform_ai_timer, (unsigned long)dev); | |
| 693 | + setup_timer(&devpriv->ao_timer, waveform_ao_timer, (unsigned long)dev); | |
| 429 | 694 | |
| 430 | 695 | dev_info(dev->class_dev, |
| 431 | − "%s: %i microvolt, %li microsecond waveform attached\n", | |
| 696 | + "%s: %u microvolt, %u microsecond waveform attached\n", | |
| 432 | 697 | dev->board_name, |
| 433 | − devpriv->uvolt_amplitude, devpriv->usec_period); | |
| 698 | + devpriv->wf_amplitude, devpriv->wf_period); | |
| 434 | 699 | |
| 435 | 700 | return 0; |
| 436 | 701 | } |
| @@ -439,8 +704,10 @@ static void waveform_detach(struct comedi_device *dev) · 2 unmodified lines | ||
| 439 | 704 | { |
| 440 | 705 | struct waveform_private *devpriv = dev->private; |
| 441 | 706 | |
| 442 | − if (devpriv) | |
| 443 | − del_timer_sync(&devpriv->timer); | |
| 707 | + if (devpriv) { | |
| 708 | + del_timer_sync(&devpriv->ai_timer); | |
| 709 | + del_timer_sync(&devpriv->ao_timer); | |
| 710 | + } | |
| 444 | 711 | } |
| 445 | 712 | |
| 446 | 713 | static struct comedi_driver waveform_driver = { |
| @@ -713,12 +713,8 @@ static int daqboard2000_auto_attach(struct comedi_device *dev, · 712 unmodified lines | ||
| 713 | 713 | return result; |
| 714 | 714 | |
| 715 | 715 | s = &dev->subdevices[2]; |
| 716 | − result = subdev_8255_init(dev, s, daqboard2000_8255_cb, | |
| 717 | − dioP2ExpansionIO8Bit); | |
| 718 | − if (result) | |
| 719 | − return result; | |
| 720 | − | |
| 721 | − return 0; | |
| 716 | + return subdev_8255_init(dev, s, daqboard2000_8255_cb, | |
| 717 | + dioP2ExpansionIO8Bit); | |
| 722 | 718 | } |
| 723 | 719 | |
| 724 | 720 | static void daqboard2000_detach(struct comedi_device *dev) |
| @@ -1,52 +1,53 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/dt3000.c | |
| 3 | − Data Translation DT3000 series driver | |
| 4 | − | |
| 5 | − COMEDI - Linux Control and Measurement Device Interface | |
| 6 | − Copyright (C) 1999 David A. Schleef <ds@schleef.org> | |
| 7 | − | |
| 8 | − This program is free software; you can redistribute it and/or modify | |
| 9 | − it under the terms of the GNU General Public License as published by | |
| 10 | − the Free Software Foundation; either version 2 of the License, or | |
| 11 | − (at your option) any later version. | |
| 12 | − | |
| 13 | − This program is distributed in the hope that it will be useful, | |
| 14 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | − GNU General Public License for more details. | |
| 17 | −*/ | |
| 18 | −/* | |
| 19 | −Driver: dt3000 | |
| 20 | −Description: Data Translation DT3000 series | |
| 21 | −Author: ds | |
| 22 | −Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, | |
| 23 | − DT3003-PGL, DT3004, DT3005, DT3004-200 | |
| 24 | −Updated: Mon, 14 Apr 2008 15:41:24 +0100 | |
| 25 | −Status: works | |
| 26 | − | |
| 27 | −Configuration Options: not applicable, uses PCI auto config | |
| 28 | − | |
| 29 | −There is code to support AI commands, but it may not work. | |
| 2 | + * dt3000.c | |
| 3 | + * Data Translation DT3000 series driver | |
| 4 | + * | |
| 5 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 6 | + * Copyright (C) 1999 David A. Schleef <ds@schleef.org> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License as published by | |
| 10 | + * the Free Software Foundation; either version 2 of the License, or | |
| 11 | + * (at your option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + */ | |
| 30 | 18 | |
| 31 | −AO commands are not supported. | |
| 32 | −*/ | |
| 19 | +/* | |
| 20 | + * Driver: dt3000 | |
| 21 | + * Description: Data Translation DT3000 series | |
| 22 | + * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, | |
| 23 | + * DT3003-PGL, DT3004, DT3005, DT3004-200 | |
| 24 | + * Author: ds | |
| 25 | + * Updated: Mon, 14 Apr 2008 15:41:24 +0100 | |
| 26 | + * Status: works | |
| 27 | + * | |
| 28 | + * Configuration Options: not applicable, uses PCI auto config | |
| 29 | + * | |
| 30 | + * There is code to support AI commands, but it may not work. | |
| 31 | + * | |
| 32 | + * AO commands are not supported. | |
| 33 | + */ | |
| 33 | 34 | |
| 34 | 35 | /* |
| 35 | − The DT3000 series is Data Translation's attempt to make a PCI | |
| 36 | − data acquisition board. The design of this series is very nice, | |
| 37 | − since each board has an on-board DSP (Texas Instruments TMS320C52). | |
| 38 | − However, a few details are a little annoying. The boards lack | |
| 39 | − bus-mastering DMA, which eliminates them from serious work. | |
| 40 | − They also are not capable of autocalibration, which is a common | |
| 41 | − feature in modern hardware. The default firmware is pretty bad, | |
| 42 | − making it nearly impossible to write an RT compatible driver. | |
| 43 | − It would make an interesting project to write a decent firmware | |
| 44 | − for these boards. | |
| 45 | − | |
| 46 | − Data Translation originally wanted an NDA for the documentation | |
| 47 | − for the 3k series. However, if you ask nicely, they might send | |
| 48 | − you the docs without one, also. | |
| 49 | −*/ | |
| 36 | + * The DT3000 series is Data Translation's attempt to make a PCI | |
| 37 | + * data acquisition board. The design of this series is very nice, | |
| 38 | + * since each board has an on-board DSP (Texas Instruments TMS320C52). | |
| 39 | + * However, a few details are a little annoying. The boards lack | |
| 40 | + * bus-mastering DMA, which eliminates them from serious work. | |
| 41 | + * They also are not capable of autocalibration, which is a common | |
| 42 | + * feature in modern hardware. The default firmware is pretty bad, | |
| 43 | + * making it nearly impossible to write an RT compatible driver. | |
| 44 | + * It would make an interesting project to write a decent firmware | |
| 45 | + * for these boards. | |
| 46 | + * | |
| 47 | + * Data Translation originally wanted an NDA for the documentation | |
| 48 | + * for the 3k series. However, if you ask nicely, they might send | |
| 49 | + * you the docs without one, also. | |
| 50 | + */ | |
| 50 | 51 | |
| 51 | 52 | #include <linux/module.h> |
| 52 | 53 | #include <linux/delay.h> |
| @@ -54,6 +55,88 @@ AO commands are not supported. · 1 unmodified line | ||
| 54 | 55 | |
| 55 | 56 | #include "../comedi_pci.h" |
| 56 | 57 | |
| 58 | +/* | |
| 59 | + * PCI BAR0 - dual-ported RAM location definitions (dev->mmio) | |
| 60 | + */ | |
| 61 | +#define DPR_DAC_BUFFER (4 * 0x000) | |
| 62 | +#define DPR_ADC_BUFFER (4 * 0x800) | |
| 63 | +#define DPR_COMMAND (4 * 0xfd3) | |
| 64 | +#define DPR_SUBSYS (4 * 0xfd3) | |
| 65 | +#define DPR_SUBSYS_AI 0 | |
| 66 | +#define DPR_SUBSYS_AO 1 | |
| 67 | +#define DPR_SUBSYS_DIN 2 | |
| 68 | +#define DPR_SUBSYS_DOUT 3 | |
| 69 | +#define DPR_SUBSYS_MEM 4 | |
| 70 | +#define DPR_SUBSYS_CT 5 | |
| 71 | +#define DPR_ENCODE (4 * 0xfd4) | |
| 72 | +#define DPR_PARAMS(x) (4 * (0xfd5 + (x))) | |
| 73 | +#define DPR_TICK_REG_LO (4 * 0xff5) | |
| 74 | +#define DPR_TICK_REG_HI (4 * 0xff6) | |
| 75 | +#define DPR_DA_BUF_FRONT (4 * 0xff7) | |
| 76 | +#define DPR_DA_BUF_REAR (4 * 0xff8) | |
| 77 | +#define DPR_AD_BUF_FRONT (4 * 0xff9) | |
| 78 | +#define DPR_AD_BUF_REAR (4 * 0xffa) | |
| 79 | +#define DPR_INT_MASK (4 * 0xffb) | |
| 80 | +#define DPR_INTR_FLAG (4 * 0xffc) | |
| 81 | +#define DPR_INTR_CMDONE BIT(7) | |
| 82 | +#define DPR_INTR_CTDONE BIT(6) | |
| 83 | +#define DPR_INTR_DAHWERR BIT(5) | |
| 84 | +#define DPR_INTR_DASWERR BIT(4) | |
| 85 | +#define DPR_INTR_DAEMPTY BIT(3) | |
| 86 | +#define DPR_INTR_ADHWERR BIT(2) | |
| 87 | +#define DPR_INTR_ADSWERR BIT(1) | |
| 88 | +#define DPR_INTR_ADFULL BIT(0) | |
| 89 | +#define DPR_RESPONSE_MBX (4 * 0xffe) | |
| 90 | +#define DPR_CMD_MBX (4 * 0xfff) | |
| 91 | +#define DPR_CMD_COMPLETION(x) ((x) << 8) | |
| 92 | +#define DPR_CMD_NOTPROCESSED DPR_CMD_COMPLETION(0x00) | |
| 93 | +#define DPR_CMD_NOERROR DPR_CMD_COMPLETION(0x55) | |
| 94 | +#define DPR_CMD_ERROR DPR_CMD_COMPLETION(0xaa) | |
| 95 | +#define DPR_CMD_NOTSUPPORTED DPR_CMD_COMPLETION(0xff) | |
| 96 | +#define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff) | |
| 97 | +#define DPR_CMD(x) ((x) << 0) | |
| 98 | +#define DPR_CMD_GETBRDINFO DPR_CMD(0) | |
| 99 | +#define DPR_CMD_CONFIG DPR_CMD(1) | |
| 100 | +#define DPR_CMD_GETCONFIG DPR_CMD(2) | |
| 101 | +#define DPR_CMD_START DPR_CMD(3) | |
| 102 | +#define DPR_CMD_STOP DPR_CMD(4) | |
| 103 | +#define DPR_CMD_READSINGLE DPR_CMD(5) | |
| 104 | +#define DPR_CMD_WRITESINGLE DPR_CMD(6) | |
| 105 | +#define DPR_CMD_CALCCLOCK DPR_CMD(7) | |
| 106 | +#define DPR_CMD_READEVENTS DPR_CMD(8) | |
| 107 | +#define DPR_CMD_WRITECTCTRL DPR_CMD(16) | |
| 108 | +#define DPR_CMD_READCTCTRL DPR_CMD(17) | |
| 109 | +#define DPR_CMD_WRITECT DPR_CMD(18) | |
| 110 | +#define DPR_CMD_READCT DPR_CMD(19) | |
| 111 | +#define DPR_CMD_WRITEDATA DPR_CMD(32) | |
| 112 | +#define DPR_CMD_READDATA DPR_CMD(33) | |
| 113 | +#define DPR_CMD_WRITEIO DPR_CMD(34) | |
| 114 | +#define DPR_CMD_READIO DPR_CMD(35) | |
| 115 | +#define DPR_CMD_WRITECODE DPR_CMD(36) | |
| 116 | +#define DPR_CMD_READCODE DPR_CMD(37) | |
| 117 | +#define DPR_CMD_EXECUTE DPR_CMD(38) | |
| 118 | +#define DPR_CMD_HALT DPR_CMD(48) | |
| 119 | +#define DPR_CMD_MASK DPR_CMD(0xff) | |
| 120 | + | |
| 121 | +#define DPR_PARAM5_AD_TRIG(x) (((x) & 0x7) << 2) | |
| 122 | +#define DPR_PARAM5_AD_TRIG_INT DPR_PARAM5_AD_TRIG(0) | |
| 123 | +#define DPR_PARAM5_AD_TRIG_EXT DPR_PARAM5_AD_TRIG(1) | |
| 124 | +#define DPR_PARAM5_AD_TRIG_INT_RETRIG DPR_PARAM5_AD_TRIG(2) | |
| 125 | +#define DPR_PARAM5_AD_TRIG_EXT_RETRIG DPR_PARAM5_AD_TRIG(3) | |
| 126 | +#define DPR_PARAM5_AD_TRIG_INT_RETRIG2 DPR_PARAM5_AD_TRIG(4) | |
| 127 | + | |
| 128 | +#define DPR_PARAM6_AD_DIFF BIT(0) | |
| 129 | + | |
| 130 | +#define DPR_AI_FIFO_DEPTH 2003 | |
| 131 | +#define DPR_AO_FIFO_DEPTH 2048 | |
| 132 | + | |
| 133 | +#define DPR_EXTERNAL_CLOCK 1 | |
| 134 | +#define DPR_RISING_EDGE 2 | |
| 135 | + | |
| 136 | +#define DPR_TMODE_MASK 0x1c | |
| 137 | + | |
| 138 | +#define DPR_CMD_TIMEOUT 100 | |
| 139 | + | |
| 57 | 140 | static const struct comedi_lrange range_dt3000_ai = { |
| 58 | 141 | 4, { |
| 59 | 142 | BIP_RANGE(10), |
| @@ -85,184 +168,87 @@ enum dt3k_boardid { · 25 unmodified lines | ||
| 85 | 168 | struct dt3k_boardtype { |
| 86 | 169 | const char *name; |
| 87 | 170 | int adchan; |
| 88 | − int adbits; | |
| 89 | 171 | int ai_speed; |
| 90 | 172 | const struct comedi_lrange *adrange; |
| 91 | − int dachan; | |
| 92 | − int dabits; | |
| 173 | + unsigned int ai_is_16bit:1; | |
| 174 | + unsigned int has_ao:1; | |
| 93 | 175 | }; |
| 94 | 176 | |
| 95 | 177 | static const struct dt3k_boardtype dt3k_boardtypes[] = { |
| 96 | 178 | [BOARD_DT3001] = { |
| 97 | 179 | .name = "dt3001", |
| 98 | 180 | .adchan = 16, |
| 99 | − .adbits = 12, | |
| 100 | 181 | .adrange = &range_dt3000_ai, |
| 101 | 182 | .ai_speed = 3000, |
| 102 | − .dachan = 2, | |
| 103 | − .dabits = 12, | |
| 183 | + .has_ao = 1, | |
| 104 | 184 | }, |
| 105 | 185 | [BOARD_DT3001_PGL] = { |
| 106 | 186 | .name = "dt3001-pgl", |
| 107 | 187 | .adchan = 16, |
| 108 | − .adbits = 12, | |
| 109 | 188 | .adrange = &range_dt3000_ai_pgl, |
| 110 | 189 | .ai_speed = 3000, |
| 111 | − .dachan = 2, | |
| 112 | − .dabits = 12, | |
| 190 | + .has_ao = 1, | |
| 113 | 191 | }, |
| 114 | 192 | [BOARD_DT3002] = { |
| 115 | 193 | .name = "dt3002", |
| 116 | 194 | .adchan = 32, |
| 117 | − .adbits = 12, | |
| 118 | 195 | .adrange = &range_dt3000_ai, |
| 119 | 196 | .ai_speed = 3000, |
| 120 | 197 | }, |
| 121 | 198 | [BOARD_DT3003] = { |
| 122 | 199 | .name = "dt3003", |
| 123 | 200 | .adchan = 64, |
| 124 | − .adbits = 12, | |
| 125 | 201 | .adrange = &range_dt3000_ai, |
| 126 | 202 | .ai_speed = 3000, |
| 127 | − .dachan = 2, | |
| 128 | − .dabits = 12, | |
| 203 | + .has_ao = 1, | |
| 129 | 204 | }, |
| 130 | 205 | [BOARD_DT3003_PGL] = { |
| 131 | 206 | .name = "dt3003-pgl", |
| 132 | 207 | .adchan = 64, |
| 133 | − .adbits = 12, | |
| 134 | 208 | .adrange = &range_dt3000_ai_pgl, |
| 135 | 209 | .ai_speed = 3000, |
| 136 | − .dachan = 2, | |
| 137 | − .dabits = 12, | |
| 210 | + .has_ao = 1, | |
| 138 | 211 | }, |
| 139 | 212 | [BOARD_DT3004] = { |
| 140 | 213 | .name = "dt3004", |
| 141 | 214 | .adchan = 16, |
| 142 | − .adbits = 16, | |
| 143 | 215 | .adrange = &range_dt3000_ai, |
| 144 | 216 | .ai_speed = 10000, |
| 145 | − .dachan = 2, | |
| 146 | − .dabits = 12, | |
| 217 | + .ai_is_16bit = 1, | |
| 218 | + .has_ao = 1, | |
| 147 | 219 | }, |
| 148 | 220 | [BOARD_DT3005] = { |
| 149 | 221 | .name = "dt3005", /* a.k.a. 3004-200 */ |
| 150 | 222 | .adchan = 16, |
| 151 | − .adbits = 16, | |
| 152 | 223 | .adrange = &range_dt3000_ai, |
| 153 | 224 | .ai_speed = 5000, |
| 154 | − .dachan = 2, | |
| 155 | − .dabits = 12, | |
| 225 | + .ai_is_16bit = 1, | |
| 226 | + .has_ao = 1, | |
| 156 | 227 | }, |
| 157 | 228 | }; |
| 158 | 229 | |
| 159 | −/* dual-ported RAM location definitions */ | |
| 160 | − | |
| 161 | −#define DPR_DAC_buffer (4*0x000) | |
| 162 | −#define DPR_ADC_buffer (4*0x800) | |
| 163 | −#define DPR_Command (4*0xfd3) | |
| 164 | −#define DPR_SubSys (4*0xfd3) | |
| 165 | −#define DPR_Encode (4*0xfd4) | |
| 166 | −#define DPR_Params(a) (4*(0xfd5+(a))) | |
| 167 | −#define DPR_Tick_Reg_Lo (4*0xff5) | |
| 168 | −#define DPR_Tick_Reg_Hi (4*0xff6) | |
| 169 | −#define DPR_DA_Buf_Front (4*0xff7) | |
| 170 | −#define DPR_DA_Buf_Rear (4*0xff8) | |
| 171 | −#define DPR_AD_Buf_Front (4*0xff9) | |
| 172 | −#define DPR_AD_Buf_Rear (4*0xffa) | |
| 173 | −#define DPR_Int_Mask (4*0xffb) | |
| 174 | −#define DPR_Intr_Flag (4*0xffc) | |
| 175 | −#define DPR_Response_Mbx (4*0xffe) | |
| 176 | −#define DPR_Command_Mbx (4*0xfff) | |
| 177 | − | |
| 178 | −#define AI_FIFO_DEPTH 2003 | |
| 179 | −#define AO_FIFO_DEPTH 2048 | |
| 180 | − | |
| 181 | −/* command list */ | |
| 182 | − | |
| 183 | −#define CMD_GETBRDINFO 0 | |
| 184 | −#define CMD_CONFIG 1 | |
| 185 | −#define CMD_GETCONFIG 2 | |
| 186 | −#define CMD_START 3 | |
| 187 | −#define CMD_STOP 4 | |
| 188 | −#define CMD_READSINGLE 5 | |
| 189 | −#define CMD_WRITESINGLE 6 | |
| 190 | −#define CMD_CALCCLOCK 7 | |
| 191 | −#define CMD_READEVENTS 8 | |
| 192 | −#define CMD_WRITECTCTRL 16 | |
| 193 | −#define CMD_READCTCTRL 17 | |
| 194 | −#define CMD_WRITECT 18 | |
| 195 | −#define CMD_READCT 19 | |
| 196 | −#define CMD_WRITEDATA 32 | |
| 197 | −#define CMD_READDATA 33 | |
| 198 | −#define CMD_WRITEIO 34 | |
| 199 | −#define CMD_READIO 35 | |
| 200 | −#define CMD_WRITECODE 36 | |
| 201 | −#define CMD_READCODE 37 | |
| 202 | −#define CMD_EXECUTE 38 | |
| 203 | −#define CMD_HALT 48 | |
| 204 | − | |
| 205 | −#define SUBS_AI 0 | |
| 206 | −#define SUBS_AO 1 | |
| 207 | −#define SUBS_DIN 2 | |
| 208 | −#define SUBS_DOUT 3 | |
| 209 | −#define SUBS_MEM 4 | |
| 210 | −#define SUBS_CT 5 | |
| 211 | − | |
| 212 | −/* interrupt flags */ | |
| 213 | −#define DT3000_CMDONE 0x80 | |
| 214 | −#define DT3000_CTDONE 0x40 | |
| 215 | −#define DT3000_DAHWERR 0x20 | |
| 216 | −#define DT3000_DASWERR 0x10 | |
| 217 | −#define DT3000_DAEMPTY 0x08 | |
| 218 | −#define DT3000_ADHWERR 0x04 | |
| 219 | −#define DT3000_ADSWERR 0x02 | |
| 220 | −#define DT3000_ADFULL 0x01 | |
| 221 | − | |
| 222 | −#define DT3000_COMPLETION_MASK 0xff00 | |
| 223 | −#define DT3000_COMMAND_MASK 0x00ff | |
| 224 | −#define DT3000_NOTPROCESSED 0x0000 | |
| 225 | −#define DT3000_NOERROR 0x5500 | |
| 226 | −#define DT3000_ERROR 0xaa00 | |
| 227 | −#define DT3000_NOTSUPPORTED 0xff00 | |
| 228 | − | |
| 229 | −#define DT3000_EXTERNAL_CLOCK 1 | |
| 230 | −#define DT3000_RISING_EDGE 2 | |
| 231 | − | |
| 232 | −#define TMODE_MASK 0x1c | |
| 233 | − | |
| 234 | −#define DT3000_AD_TRIG_INTERNAL (0<<2) | |
| 235 | −#define DT3000_AD_TRIG_EXTERNAL (1<<2) | |
| 236 | −#define DT3000_AD_RETRIG_INTERNAL (2<<2) | |
| 237 | −#define DT3000_AD_RETRIG_EXTERNAL (3<<2) | |
| 238 | −#define DT3000_AD_EXTRETRIG (4<<2) | |
| 239 | − | |
| 240 | −#define DT3000_CHANNEL_MODE_SE 0 | |
| 241 | −#define DT3000_CHANNEL_MODE_DI 1 | |
| 242 | − | |
| 243 | 230 | struct dt3k_private { |
| 244 | 231 | unsigned int lock; |
| 245 | 232 | unsigned int ai_front; |
| 246 | 233 | unsigned int ai_rear; |
| 247 | 234 | }; |
| 248 | 235 | |
| 249 | −#define TIMEOUT 100 | |
| 250 | − | |
| 251 | 236 | static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) |
| 252 | 237 | { |
| 253 | 238 | int i; |
| 254 | 239 | unsigned int status = 0; |
| 255 | 240 | |
| 256 | − writew(cmd, dev->mmio + DPR_Command_Mbx); | |
| 241 | + writew(cmd, dev->mmio + DPR_CMD_MBX); | |
| 257 | 242 | |
| 258 | − for (i = 0; i < TIMEOUT; i++) { | |
| 259 | − status = readw(dev->mmio + DPR_Command_Mbx); | |
| 260 | − if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED) | |
| 243 | + for (i = 0; i < DPR_CMD_TIMEOUT; i++) { | |
| 244 | + status = readw(dev->mmio + DPR_CMD_MBX); | |
| 245 | + status &= DPR_CMD_COMPLETION_MASK; | |
| 246 | + if (status != DPR_CMD_NOTPROCESSED) | |
| 261 | 247 | break; |
| 262 | 248 | udelay(1); |
| 263 | 249 | } |
| 264 | 250 | |
| 265 | − if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR) | |
| 251 | + if (status != DPR_CMD_NOERROR) | |
| 266 | 252 | dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", |
| 267 | 253 | __func__, status); |
| 268 | 254 | } |
| @@ -271,26 +257,26 @@ static unsigned int dt3k_readsingle(struct comedi_device *dev, · 2 unmodified lines | ||
| 271 | 257 | unsigned int subsys, unsigned int chan, |
| 272 | 258 | unsigned int gain) |
| 273 | 259 | { |
| 274 | − writew(subsys, dev->mmio + DPR_SubSys); | |
| 260 | + writew(subsys, dev->mmio + DPR_SUBSYS); | |
| 275 | 261 | |
| 276 | − writew(chan, dev->mmio + DPR_Params(0)); | |
| 277 | − writew(gain, dev->mmio + DPR_Params(1)); | |
| 262 | + writew(chan, dev->mmio + DPR_PARAMS(0)); | |
| 263 | + writew(gain, dev->mmio + DPR_PARAMS(1)); | |
| 278 | 264 | |
| 279 | − dt3k_send_cmd(dev, CMD_READSINGLE); | |
| 265 | + dt3k_send_cmd(dev, DPR_CMD_READSINGLE); | |
| 280 | 266 | |
| 281 | − return readw(dev->mmio + DPR_Params(2)); | |
| 267 | + return readw(dev->mmio + DPR_PARAMS(2)); | |
| 282 | 268 | } |
| 283 | 269 | |
| 284 | 270 | static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, |
| 285 | 271 | unsigned int chan, unsigned int data) |
| 286 | 272 | { |
| 287 | − writew(subsys, dev->mmio + DPR_SubSys); | |
| 273 | + writew(subsys, dev->mmio + DPR_SUBSYS); | |
| 288 | 274 | |
| 289 | − writew(chan, dev->mmio + DPR_Params(0)); | |
| 290 | − writew(0, dev->mmio + DPR_Params(1)); | |
| 291 | − writew(data, dev->mmio + DPR_Params(2)); | |
| 275 | + writew(chan, dev->mmio + DPR_PARAMS(0)); | |
| 276 | + writew(0, dev->mmio + DPR_PARAMS(1)); | |
| 277 | + writew(data, dev->mmio + DPR_PARAMS(2)); | |
| 292 | 278 | |
| 293 | − dt3k_send_cmd(dev, CMD_WRITESINGLE); | |
| 279 | + dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE); | |
| 294 | 280 | } |
| 295 | 281 | |
| 296 | 282 | static void dt3k_ai_empty_fifo(struct comedi_device *dev, |
| @@ -303,32 +289,32 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, · 6 unmodified lines | ||
| 303 | 289 | int i; |
| 304 | 290 | unsigned short data; |
| 305 | 291 | |
| 306 | − front = readw(dev->mmio + DPR_AD_Buf_Front); | |
| 292 | + front = readw(dev->mmio + DPR_AD_BUF_FRONT); | |
| 307 | 293 | count = front - devpriv->ai_front; |
| 308 | 294 | if (count < 0) |
| 309 | − count += AI_FIFO_DEPTH; | |
| 295 | + count += DPR_AI_FIFO_DEPTH; | |
| 310 | 296 | |
| 311 | 297 | rear = devpriv->ai_rear; |
| 312 | 298 | |
| 313 | 299 | for (i = 0; i < count; i++) { |
| 314 | − data = readw(dev->mmio + DPR_ADC_buffer + rear); | |
| 300 | + data = readw(dev->mmio + DPR_ADC_BUFFER + rear); | |
| 315 | 301 | comedi_buf_write_samples(s, &data, 1); |
| 316 | 302 | rear++; |
| 317 | − if (rear >= AI_FIFO_DEPTH) | |
| 303 | + if (rear >= DPR_AI_FIFO_DEPTH) | |
| 318 | 304 | rear = 0; |
| 319 | 305 | } |
| 320 | 306 | |
| 321 | 307 | devpriv->ai_rear = rear; |
| 322 | − writew(rear, dev->mmio + DPR_AD_Buf_Rear); | |
| 308 | + writew(rear, dev->mmio + DPR_AD_BUF_REAR); | |
| 323 | 309 | } |
| 324 | 310 | |
| 325 | 311 | static int dt3k_ai_cancel(struct comedi_device *dev, |
| 326 | 312 | struct comedi_subdevice *s) |
| 327 | 313 | { |
| 328 | − writew(SUBS_AI, dev->mmio + DPR_SubSys); | |
| 329 | − dt3k_send_cmd(dev, CMD_STOP); | |
| 314 | + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); | |
| 315 | + dt3k_send_cmd(dev, DPR_CMD_STOP); | |
| 330 | 316 | |
| 331 | − writew(0, dev->mmio + DPR_Int_Mask); | |
| 317 | + writew(0, dev->mmio + DPR_INT_MASK); | |
| 332 | 318 | |
| 333 | 319 | return 0; |
| 334 | 320 | } |
| @@ -346,12 +332,12 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) · 11 unmodified lines | ||
| 346 | 332 | if (!dev->attached) |
| 347 | 333 | return IRQ_NONE; |
| 348 | 334 | |
| 349 | − status = readw(dev->mmio + DPR_Intr_Flag); | |
| 335 | + status = readw(dev->mmio + DPR_INTR_FLAG); | |
| 350 | 336 | |
| 351 | − if (status & DT3000_ADFULL) | |
| 337 | + if (status & DPR_INTR_ADFULL) | |
| 352 | 338 | dt3k_ai_empty_fifo(dev, s); |
| 353 | 339 | |
| 354 | − if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) | |
| 340 | + if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR)) | |
| 355 | 341 | s->async->events |= COMEDI_CB_ERROR; |
| 356 | 342 | |
| 357 | 343 | debug_n_ints++; |
| @@ -486,46 +472,49 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) · 128 unmodified lines | ||
| 486 | 472 | chan = CR_CHAN(cmd->chanlist[i]); |
| 487 | 473 | range = CR_RANGE(cmd->chanlist[i]); |
| 488 | 474 | |
| 489 | − writew((range << 6) | chan, dev->mmio + DPR_ADC_buffer + i); | |
| 475 | + writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i); | |
| 490 | 476 | } |
| 491 | 477 | aref = CR_AREF(cmd->chanlist[0]); |
| 492 | 478 | |
| 493 | − writew(cmd->scan_end_arg, dev->mmio + DPR_Params(0)); | |
| 479 | + writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0)); | |
| 494 | 480 | |
| 495 | 481 | if (cmd->convert_src == TRIG_TIMER) { |
| 496 | 482 | divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags); |
| 497 | − writew((divider >> 16), dev->mmio + DPR_Params(1)); | |
| 498 | − writew((divider & 0xffff), dev->mmio + DPR_Params(2)); | |
| 483 | + writew((divider >> 16), dev->mmio + DPR_PARAMS(1)); | |
| 484 | + writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2)); | |
| 499 | 485 | } |
| 500 | 486 | |
| 501 | 487 | if (cmd->scan_begin_src == TRIG_TIMER) { |
| 502 | 488 | tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, |
| 503 | 489 | cmd->flags); |
| 504 | − writew((tscandiv >> 16), dev->mmio + DPR_Params(3)); | |
| 505 | − writew((tscandiv & 0xffff), dev->mmio + DPR_Params(4)); | |
| 490 | + writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3)); | |
| 491 | + writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4)); | |
| 506 | 492 | } |
| 507 | 493 | |
| 508 | − writew(DT3000_AD_RETRIG_INTERNAL, dev->mmio + DPR_Params(5)); | |
| 509 | − writew(aref == AREF_DIFF, dev->mmio + DPR_Params(6)); | |
| 494 | + writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5)); | |
| 495 | + writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0, | |
| 496 | + dev->mmio + DPR_PARAMS(6)); | |
| 510 | 497 | |
| 511 | − writew(AI_FIFO_DEPTH / 2, dev->mmio + DPR_Params(7)); | |
| 498 | + writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7)); | |
| 512 | 499 | |
| 513 | − writew(SUBS_AI, dev->mmio + DPR_SubSys); | |
| 514 | − dt3k_send_cmd(dev, CMD_CONFIG); | |
| 500 | + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); | |
| 501 | + dt3k_send_cmd(dev, DPR_CMD_CONFIG); | |
| 515 | 502 | |
| 516 | − writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR, | |
| 517 | − dev->mmio + DPR_Int_Mask); | |
| 503 | + writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR, | |
| 504 | + dev->mmio + DPR_INT_MASK); | |
| 518 | 505 | |
| 519 | 506 | debug_n_ints = 0; |
| 520 | 507 | |
| 521 | − writew(SUBS_AI, dev->mmio + DPR_SubSys); | |
| 522 | − dt3k_send_cmd(dev, CMD_START); | |
| 508 | + writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); | |
| 509 | + dt3k_send_cmd(dev, DPR_CMD_START); | |
| 523 | 510 | |
| 524 | 511 | return 0; |
| 525 | 512 | } |
| 526 | 513 | |
| 527 | −static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, | |
| 528 | − struct comedi_insn *insn, unsigned int *data) | |
| 514 | +static int dt3k_ai_insn_read(struct comedi_device *dev, | |
| 515 | + struct comedi_subdevice *s, | |
| 516 | + struct comedi_insn *insn, | |
| 517 | + unsigned int *data) | |
| 529 | 518 | { |
| 530 | 519 | int i; |
| 531 | 520 | unsigned int chan, gain, aref; |
| @@ -536,7 +525,7 @@ static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, · 4 unmodified lines | ||
| 536 | 525 | aref = CR_AREF(insn->chanspec); |
| 537 | 526 | |
| 538 | 527 | for (i = 0; i < insn->n; i++) |
| 539 | − data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain); | |
| 528 | + data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain); | |
| 540 | 529 | |
| 541 | 530 | return i; |
| 542 | 531 | } |
| @@ -552,7 +541,7 @@ static int dt3k_ao_insn_write(struct comedi_device *dev, · 9 unmodified lines | ||
| 552 | 541 | |
| 553 | 542 | for (i = 0; i < insn->n; i++) { |
| 554 | 543 | val = data[i]; |
| 555 | − dt3k_writesingle(dev, SUBS_AO, chan, val); | |
| 544 | + dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val); | |
| 556 | 545 | } |
| 557 | 546 | s->readback[chan] = val; |
| 558 | 547 | |
| @@ -562,16 +551,13 @@ static int dt3k_ao_insn_write(struct comedi_device *dev, · 3 unmodified lines | ||
| 562 | 551 | static void dt3k_dio_config(struct comedi_device *dev, int bits) |
| 563 | 552 | { |
| 564 | 553 | /* XXX */ |
| 565 | − writew(SUBS_DOUT, dev->mmio + DPR_SubSys); | |
| 554 | + writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS); | |
| 566 | 555 | |
| 567 | − writew(bits, dev->mmio + DPR_Params(0)); | |
| 568 | −#if 0 | |
| 569 | − /* don't know */ | |
| 570 | − writew(0, dev->mmio + DPR_Params(1)); | |
| 571 | − writew(0, dev->mmio + DPR_Params(2)); | |
| 572 | −#endif | |
| 556 | + writew(bits, dev->mmio + DPR_PARAMS(0)); | |
| 573 | 557 | |
| 574 | − dt3k_send_cmd(dev, CMD_CONFIG); | |
| 558 | + /* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */ | |
| 559 | + | |
| 560 | + dt3k_send_cmd(dev, DPR_CMD_CONFIG); | |
| 575 | 561 | } |
| 576 | 562 | |
| 577 | 563 | static int dt3k_dio_insn_config(struct comedi_device *dev, |
| @@ -603,9 +589,9 @@ static int dt3k_dio_insn_bits(struct comedi_device *dev, · 25 unmodified lines | ||
| 603 | 589 | unsigned int *data) |
| 604 | 590 | { |
| 605 | 591 | if (comedi_dio_update_state(s, data)) |
| 606 | − dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); | |
| 592 | + dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state); | |
| 607 | 593 | |
| 608 | − data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); | |
| 594 | + data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0); | |
| 609 | 595 | |
| 610 | 596 | return insn->n; |
| 611 | 597 | } |
| @@ -619,13 +605,13 @@ static int dt3k_mem_insn_read(struct comedi_device *dev, · 7 unmodified lines | ||
| 619 | 605 | int i; |
| 620 | 606 | |
| 621 | 607 | for (i = 0; i < insn->n; i++) { |
| 622 | − writew(SUBS_MEM, dev->mmio + DPR_SubSys); | |
| 623 | − writew(addr, dev->mmio + DPR_Params(0)); | |
| 624 | − writew(1, dev->mmio + DPR_Params(1)); | |
| 608 | + writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS); | |
| 609 | + writew(addr, dev->mmio + DPR_PARAMS(0)); | |
| 610 | + writew(1, dev->mmio + DPR_PARAMS(1)); | |
| 625 | 611 | |
| 626 | − dt3k_send_cmd(dev, CMD_READCODE); | |
| 612 | + dt3k_send_cmd(dev, DPR_CMD_READCODE); | |
| 627 | 613 | |
| 628 | − data[i] = readw(dev->mmio + DPR_Params(2)); | |
| 614 | + data[i] = readw(dev->mmio + DPR_PARAMS(2)); | |
| 629 | 615 | } |
| 630 | 616 | |
| 631 | 617 | return i; |
| @@ -670,14 +656,14 @@ static int dt3000_auto_attach(struct comedi_device *dev, · 38 unmodified lines | ||
| 670 | 656 | if (ret) |
| 671 | 657 | return ret; |
| 672 | 658 | |
| 659 | + /* Analog Input subdevice */ | |
| 673 | 660 | s = &dev->subdevices[0]; |
| 674 | − /* ai subdevice */ | |
| 675 | 661 | s->type = COMEDI_SUBD_AI; |
| 676 | 662 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; |
| 677 | 663 | s->n_chan = board->adchan; |
| 678 | − s->insn_read = dt3k_ai_insn; | |
| 679 | − s->maxdata = (1 << board->adbits) - 1; | |
| 664 | + s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff; | |
| 680 | 665 | s->range_table = &range_dt3000_ai; /* XXX */ |
| 666 | + s->insn_read = dt3k_ai_insn_read; | |
| 681 | 667 | if (dev->irq) { |
| 682 | 668 | dev->read_subdev = s; |
| 683 | 669 | s->subdev_flags |= SDF_CMD_READ; |
| @@ -687,46 +673,42 @@ static int dt3000_auto_attach(struct comedi_device *dev, · 3 unmodified lines | ||
| 687 | 673 | s->cancel = dt3k_ai_cancel; |
| 688 | 674 | } |
| 689 | 675 | |
| 676 | + /* Analog Output subdevice */ | |
| 690 | 677 | s = &dev->subdevices[1]; |
| 691 | − /* ao subsystem */ | |
| 692 | − s->type = COMEDI_SUBD_AO; | |
| 693 | − s->subdev_flags = SDF_WRITABLE; | |
| 694 | − s->n_chan = 2; | |
| 695 | − s->maxdata = (1 << board->dabits) - 1; | |
| 696 | − s->len_chanlist = 1; | |
| 697 | − s->range_table = &range_bipolar10; | |
| 698 | − s->insn_write = dt3k_ao_insn_write; | |
| 699 | − | |
| 700 | − ret = comedi_alloc_subdev_readback(s); | |
| 701 | − if (ret) | |
| 702 | − return ret; | |
| 678 | + if (board->has_ao) { | |
| 679 | + s->type = COMEDI_SUBD_AO; | |
| 680 | + s->subdev_flags = SDF_WRITABLE; | |
| 681 | + s->n_chan = 2; | |
| 682 | + s->maxdata = 0x0fff; | |
| 683 | + s->range_table = &range_bipolar10; | |
| 684 | + s->insn_write = dt3k_ao_insn_write; | |
| 685 | + | |
| 686 | + ret = comedi_alloc_subdev_readback(s); | |
| 687 | + if (ret) | |
| 688 | + return ret; | |
| 689 | + | |
| 690 | + } else { | |
| 691 | + s->type = COMEDI_SUBD_UNUSED; | |
| 692 | + } | |
| 703 | 693 | |
| 694 | + /* Digital I/O subdevice */ | |
| 704 | 695 | s = &dev->subdevices[2]; |
| 705 | − /* dio subsystem */ | |
| 706 | 696 | s->type = COMEDI_SUBD_DIO; |
| 707 | 697 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE; |
| 708 | 698 | s->n_chan = 8; |
| 709 | − s->insn_config = dt3k_dio_insn_config; | |
| 710 | − s->insn_bits = dt3k_dio_insn_bits; | |
| 711 | 699 | s->maxdata = 1; |
| 712 | − s->len_chanlist = 8; | |
| 713 | 700 | s->range_table = &range_digital; |
| 701 | + s->insn_config = dt3k_dio_insn_config; | |
| 702 | + s->insn_bits = dt3k_dio_insn_bits; | |
| 714 | 703 | |
| 704 | + /* Memory subdevice */ | |
| 715 | 705 | s = &dev->subdevices[3]; |
| 716 | − /* mem subsystem */ | |
| 717 | 706 | s->type = COMEDI_SUBD_MEMORY; |
| 718 | 707 | s->subdev_flags = SDF_READABLE; |
| 719 | 708 | s->n_chan = 0x1000; |
| 720 | − s->insn_read = dt3k_mem_insn_read; | |
| 721 | 709 | s->maxdata = 0xff; |
| 722 | − s->len_chanlist = 1; | |
| 723 | 710 | s->range_table = &range_unknown; |
| 724 | − | |
| 725 | −#if 0 | |
| 726 | − s = &dev->subdevices[4]; | |
| 727 | − /* proc subsystem */ | |
| 728 | − s->type = COMEDI_SUBD_PROC; | |
| 729 | −#endif | |
| 711 | + s->insn_read = dt3k_mem_insn_read; | |
| 730 | 712 | |
| 731 | 713 | return 0; |
| 732 | 714 | } |
| @@ -765,5 +747,5 @@ static struct pci_driver dt3000_pci_driver = { · 32 unmodified lines | ||
| 765 | 747 | module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); |
| 766 | 748 | |
| 767 | 749 | MODULE_AUTHOR("Comedi http://www.comedi.org"); |
| 768 | −MODULE_DESCRIPTION("Comedi low-level driver"); | |
| 750 | +MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards"); | |
| 769 | 751 | MODULE_LICENSE("GPL"); |
| @@ -18,17 +18,17 @@ · 17 unmodified lines | ||
| 18 | 18 | */ |
| 19 | 19 | |
| 20 | 20 | /* |
| 21 | −Driver: dt9812 | |
| 22 | −Description: Data Translation DT9812 USB module | |
| 23 | −Author: anders.blomdell@control.lth.se (Anders Blomdell) | |
| 24 | −Status: in development | |
| 25 | −Devices: [Data Translation] DT9812 (dt9812) | |
| 26 | −Updated: Sun Nov 20 20:18:34 EST 2005 | |
| 27 | − | |
| 28 | −This driver works, but bulk transfers not implemented. Might be a starting point | |
| 29 | −for someone else. I found out too late that USB has too high latencies (>1 ms) | |
| 30 | −for my needs. | |
| 31 | −*/ | |
| 21 | + * Driver: dt9812 | |
| 22 | + * Description: Data Translation DT9812 USB module | |
| 23 | + * Devices: [Data Translation] DT9812 (dt9812) | |
| 24 | + * Author: anders.blomdell@control.lth.se (Anders Blomdell) | |
| 25 | + * Status: in development | |
| 26 | + * Updated: Sun Nov 20 20:18:34 EST 2005 | |
| 27 | + * | |
| 28 | + * This driver works, but bulk transfers not implemented. Might be a | |
| 29 | + * starting point for someone else. I found out too late that USB has | |
| 30 | + * too high latencies (>1 ms) for my needs. | |
| 31 | + */ | |
| 32 | 32 | |
| 33 | 33 | /* |
| 34 | 34 | * Nota Bene: |
| @@ -80,7 +80,7 @@ for my needs. · 45 unmodified lines | ||
| 80 | 80 | #define F020_MASK_ADC0CN_AD0INT 0x20 |
| 81 | 81 | #define F020_MASK_ADC0CN_AD0BUSY 0x10 |
| 82 | 82 | |
| 83 | −#define F020_MASK_DACxCN_DACxEN 0x80 | |
| 83 | +#define F020_MASK_DACXCN_DACXEN 0x80 | |
| 84 | 84 | |
| 85 | 85 | enum { |
| 86 | 86 | /* A/D D/A DI DO CT */ |
| @@ -233,7 +233,7 @@ struct dt9812_usb_cmd { · 146 unmodified lines | ||
| 233 | 233 | }; |
| 234 | 234 | |
| 235 | 235 | struct dt9812_private { |
| 236 | − struct semaphore sem; | |
| 236 | + struct mutex mut; | |
| 237 | 237 | struct { |
| 238 | 238 | __u8 addr; |
| 239 | 239 | size_t size; |
| @@ -335,7 +335,7 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) · 95 unmodified lines | ||
| 335 | 335 | u8 value[2]; |
| 336 | 336 | int ret; |
| 337 | 337 | |
| 338 | − down(&devpriv->sem); | |
| 338 | + mutex_lock(&devpriv->mut); | |
| 339 | 339 | ret = dt9812_read_multiple_registers(dev, 2, reg, value); |
| 340 | 340 | if (ret == 0) { |
| 341 | 341 | /* |
| @@ -345,7 +345,7 @@ static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) · 3 unmodified lines | ||
| 345 | 345 | */ |
| 346 | 346 | *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); |
| 347 | 347 | } |
| 348 | − up(&devpriv->sem); | |
| 348 | + mutex_unlock(&devpriv->mut); | |
| 349 | 349 | |
| 350 | 350 | return ret; |
| 351 | 351 | } |
| @@ -357,9 +357,9 @@ static int dt9812_digital_out(struct comedi_device *dev, u8 bits) · 5 unmodified lines | ||
| 357 | 357 | u8 value[1] = { bits }; |
| 358 | 358 | int ret; |
| 359 | 359 | |
| 360 | − down(&devpriv->sem); | |
| 360 | + mutex_lock(&devpriv->mut); | |
| 361 | 361 | ret = dt9812_write_multiple_registers(dev, 1, reg, value); |
| 362 | − up(&devpriv->sem); | |
| 362 | + mutex_unlock(&devpriv->mut); | |
| 363 | 363 | |
| 364 | 364 | return ret; |
| 365 | 365 | } |
| @@ -444,7 +444,7 @@ static int dt9812_analog_in(struct comedi_device *dev, · 78 unmodified lines | ||
| 444 | 444 | u8 val[3]; |
| 445 | 445 | int ret; |
| 446 | 446 | |
| 447 | − down(&devpriv->sem); | |
| 447 | + mutex_lock(&devpriv->mut); | |
| 448 | 448 | |
| 449 | 449 | /* 1 select the gain */ |
| 450 | 450 | dt9812_configure_gain(dev, &rmw[0], gain); |
| @@ -493,7 +493,7 @@ static int dt9812_analog_in(struct comedi_device *dev, · 42 unmodified lines | ||
| 493 | 493 | } |
| 494 | 494 | |
| 495 | 495 | exit: |
| 496 | − up(&devpriv->sem); | |
| 496 | + mutex_unlock(&devpriv->mut); | |
| 497 | 497 | |
| 498 | 498 | return ret; |
| 499 | 499 | } |
| @@ -504,22 +504,21 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) · 4 unmodified lines | ||
| 504 | 504 | struct dt9812_rmw_byte rmw[3]; |
| 505 | 505 | int ret; |
| 506 | 506 | |
| 507 | − down(&devpriv->sem); | |
| 507 | + mutex_lock(&devpriv->mut); | |
| 508 | 508 | |
| 509 | 509 | switch (channel) { |
| 510 | 510 | case 0: |
| 511 | 511 | /* 1. Set DAC mode */ |
| 512 | 512 | rmw[0].address = F020_SFR_DAC0CN; |
| 513 | 513 | rmw[0].and_mask = 0xff; |
| 514 | − rmw[0].or_value = F020_MASK_DACxCN_DACxEN; | |
| 514 | + rmw[0].or_value = F020_MASK_DACXCN_DACXEN; | |
| 515 | 515 | |
| 516 | − /* 2 load low byte of DAC value first */ | |
| 516 | + /* 2. load lsb of DAC value first */ | |
| 517 | 517 | rmw[1].address = F020_SFR_DAC0L; |
| 518 | 518 | rmw[1].and_mask = 0xff; |
| 519 | 519 | rmw[1].or_value = value & 0xff; |
| 520 | 520 | |
| 521 | − /* 3 load high byte of DAC value next to latch the | |
| 522 | − 12-bit value */ | |
| 521 | + /* 3. load msb of DAC value next to latch the 12-bit value */ | |
| 523 | 522 | rmw[2].address = F020_SFR_DAC0H; |
| 524 | 523 | rmw[2].and_mask = 0xff; |
| 525 | 524 | rmw[2].or_value = (value >> 8) & 0xf; |
| @@ -529,15 +528,14 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) · 3 unmodified lines | ||
| 529 | 528 | /* 1. Set DAC mode */ |
| 530 | 529 | rmw[0].address = F020_SFR_DAC1CN; |
| 531 | 530 | rmw[0].and_mask = 0xff; |
| 532 | − rmw[0].or_value = F020_MASK_DACxCN_DACxEN; | |
| 531 | + rmw[0].or_value = F020_MASK_DACXCN_DACXEN; | |
| 533 | 532 | |
| 534 | − /* 2 load low byte of DAC value first */ | |
| 533 | + /* 2. load lsb of DAC value first */ | |
| 535 | 534 | rmw[1].address = F020_SFR_DAC1L; |
| 536 | 535 | rmw[1].and_mask = 0xff; |
| 537 | 536 | rmw[1].or_value = value & 0xff; |
| 538 | 537 | |
| 539 | − /* 3 load high byte of DAC value next to latch the | |
| 540 | − 12-bit value */ | |
| 538 | + /* 3. load msb of DAC value next to latch the 12-bit value */ | |
| 541 | 539 | rmw[2].address = F020_SFR_DAC1H; |
| 542 | 540 | rmw[2].and_mask = 0xff; |
| 543 | 541 | rmw[2].or_value = (value >> 8) & 0xf; |
| @@ -545,7 +543,7 @@ static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) · 1 unmodified line | ||
| 545 | 543 | } |
| 546 | 544 | ret = dt9812_rmw_multiple_registers(dev, 3, rmw); |
| 547 | 545 | |
| 548 | − up(&devpriv->sem); | |
| 546 | + mutex_unlock(&devpriv->mut); | |
| 549 | 547 | |
| 550 | 548 | return ret; |
| 551 | 549 | } |
| @@ -608,9 +606,9 @@ static int dt9812_ao_insn_read(struct comedi_device *dev, · 56 unmodified lines | ||
| 608 | 606 | struct dt9812_private *devpriv = dev->private; |
| 609 | 607 | int ret; |
| 610 | 608 | |
| 611 | − down(&devpriv->sem); | |
| 609 | + mutex_lock(&devpriv->mut); | |
| 612 | 610 | ret = comedi_readback_insn_read(dev, s, insn, data); |
| 613 | − up(&devpriv->sem); | |
| 611 | + mutex_unlock(&devpriv->mut); | |
| 614 | 612 | |
| 615 | 613 | return ret; |
| 616 | 614 | } |
| @@ -774,7 +772,7 @@ static int dt9812_auto_attach(struct comedi_device *dev, · 157 unmodified lines | ||
| 774 | 772 | if (!devpriv) |
| 775 | 773 | return -ENOMEM; |
| 776 | 774 | |
| 777 | − sema_init(&devpriv->sem, 1); | |
| 775 | + mutex_init(&devpriv->mut); | |
| 778 | 776 | usb_set_intfdata(intf, devpriv); |
| 779 | 777 | |
| 780 | 778 | ret = dt9812_find_endpoints(dev); |
| @@ -846,11 +844,11 @@ static void dt9812_detach(struct comedi_device *dev) · 65 unmodified lines | ||
| 846 | 844 | if (!devpriv) |
| 847 | 845 | return; |
| 848 | 846 | |
| 849 | − down(&devpriv->sem); | |
| 847 | + mutex_lock(&devpriv->mut); | |
| 850 | 848 | |
| 851 | 849 | usb_set_intfdata(intf, NULL); |
| 852 | 850 | |
| 853 | − up(&devpriv->sem); | |
| 851 | + mutex_unlock(&devpriv->mut); | |
| 854 | 852 | } |
| 855 | 853 | |
| 856 | 854 | static struct comedi_driver dt9812_driver = { |
| @@ -71,7 +71,7 @@ static int fl512_ai_insn_read(struct comedi_device *dev, · 70 unmodified lines | ||
| 71 | 71 | outb(0, dev->iobase + FL512_AI_START_CONV_REG); |
| 72 | 72 | |
| 73 | 73 | /* XXX should test "done" flag instead of delay */ |
| 74 | − udelay(30); | |
| 74 | + usleep_range(30, 100); | |
| 75 | 75 | |
| 76 | 76 | val = inb(dev->iobase + FL512_AI_LSB_REG); |
| 77 | 77 | val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); |
| @@ -125,7 +125,7 @@ · 124 unmodified lines | ||
| 125 | 125 | |
| 126 | 126 | struct hpdi_private { |
| 127 | 127 | void __iomem *plx9080_mmio; |
| 128 | − uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ | |
| 128 | + u32 *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ | |
| 129 | 129 | /* physical addresses of dma buffers */ |
| 130 | 130 | dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; |
| 131 | 131 | /* |
| @@ -137,7 +137,7 @@ struct hpdi_private { · 5 unmodified lines | ||
| 137 | 137 | dma_addr_t dma_desc_phys_addr; |
| 138 | 138 | unsigned int num_dma_descriptors; |
| 139 | 139 | /* pointer to start of buffers indexed by descriptor */ |
| 140 | − uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; | |
| 140 | + u32 *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; | |
| 141 | 141 | /* index of the dma descriptor that is currently being used */ |
| 142 | 142 | unsigned int dma_desc_index; |
| 143 | 143 | unsigned int tx_fifo_size; |
| @@ -169,7 +169,7 @@ static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) · 25 unmodified lines | ||
| 169 | 169 | for (desc = 0; (next < start || next >= start + devpriv->block_size) && |
| 170 | 170 | desc < devpriv->num_dma_descriptors; desc++) { |
| 171 | 171 | /* transfer data from dma buffer to comedi buffer */ |
| 172 | − size = devpriv->block_size / sizeof(uint32_t); | |
| 172 | + size = devpriv->block_size / sizeof(u32); | |
| 173 | 173 | if (cmd->stop_src == TRIG_COUNT) { |
| 174 | 174 | if (size > devpriv->dio_count) |
| 175 | 175 | size = devpriv->dio_count; |
| @@ -192,10 +192,10 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) · 16 unmodified lines | ||
| 192 | 192 | struct hpdi_private *devpriv = dev->private; |
| 193 | 193 | struct comedi_subdevice *s = dev->read_subdev; |
| 194 | 194 | struct comedi_async *async = s->async; |
| 195 | − uint32_t hpdi_intr_status, hpdi_board_status; | |
| 196 | − uint32_t plx_status; | |
| 197 | − uint32_t plx_bits; | |
| 198 | − uint8_t dma0_status, dma1_status; | |
| 195 | + u32 hpdi_intr_status, hpdi_board_status; | |
| 196 | + u32 plx_status; | |
| 197 | + u32 plx_bits; | |
| 198 | + u8 dma0_status, dma1_status; | |
| 199 | 199 | unsigned long flags; |
| 200 | 200 | |
| 201 | 201 | if (!dev->attached) |
| @@ -290,7 +290,7 @@ static int gsc_hpdi_cmd(struct comedi_device *dev, · 88 unmodified lines | ||
| 290 | 290 | struct comedi_async *async = s->async; |
| 291 | 291 | struct comedi_cmd *cmd = &async->cmd; |
| 292 | 292 | unsigned long flags; |
| 293 | − uint32_t bits; | |
| 293 | + u32 bits; | |
| 294 | 294 | |
| 295 | 295 | if (s->io_bits) |
| 296 | 296 | return -EINVAL; |
| @@ -424,15 +424,15 @@ static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, · 127 unmodified lines | ||
| 424 | 424 | { |
| 425 | 425 | struct hpdi_private *devpriv = dev->private; |
| 426 | 426 | dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; |
| 427 | − uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | | |
| 428 | − PLX_XFER_LOCAL_TO_PCI; | |
| 427 | + u32 next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | | |
| 428 | + PLX_XFER_LOCAL_TO_PCI; | |
| 429 | 429 | unsigned int offset = 0; |
| 430 | 430 | unsigned int idx = 0; |
| 431 | 431 | unsigned int i; |
| 432 | 432 | |
| 433 | 433 | if (len > DMA_BUFFER_SIZE) |
| 434 | 434 | len = DMA_BUFFER_SIZE; |
| 435 | − len -= len % sizeof(uint32_t); | |
| 435 | + len -= len % sizeof(u32); | |
| 436 | 436 | if (len == 0) |
| 437 | 437 | return -EINVAL; |
| 438 | 438 | |
| @@ -445,7 +445,7 @@ static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, · 6 unmodified lines | ||
| 445 | 445 | (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); |
| 446 | 446 | |
| 447 | 447 | devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + |
| 448 | − (offset / sizeof(uint32_t)); | |
| 448 | + (offset / sizeof(u32)); | |
| 449 | 449 | |
| 450 | 450 | offset += len; |
| 451 | 451 | if (len + offset > DMA_BUFFER_SIZE) { |
| @@ -516,7 +516,7 @@ static void gsc_hpdi_free_dma(struct comedi_device *dev) · 64 unmodified lines | ||
| 516 | 516 | static int gsc_hpdi_init(struct comedi_device *dev) |
| 517 | 517 | { |
| 518 | 518 | struct hpdi_private *devpriv = dev->private; |
| 519 | − uint32_t plx_intcsr_bits; | |
| 519 | + u32 plx_intcsr_bits; | |
| 520 | 520 | |
| 521 | 521 | /* wait 10usec after reset before accessing fifos */ |
| 522 | 522 | writel(BOARD_RESET_BIT, dev->mmio + BOARD_CONTROL_REG); |
| @@ -546,7 +546,7 @@ static int gsc_hpdi_init(struct comedi_device *dev) · 23 unmodified lines | ||
| 546 | 546 | static void gsc_hpdi_init_plx9080(struct comedi_device *dev) |
| 547 | 547 | { |
| 548 | 548 | struct hpdi_private *devpriv = dev->private; |
| 549 | − uint32_t bits; | |
| 549 | + u32 bits; | |
| 550 | 550 | void __iomem *plx_iobase = devpriv->plx9080_mmio; |
| 551 | 551 | |
| 552 | 552 | #ifdef __BIG_ENDIAN |
| @@ -1,94 +1,89 @@ | ||
| 1 | 1 | /* |
| 2 | − comedi/drivers/icp_multi.c | |
| 3 | − | |
| 4 | − COMEDI - Linux Control and Measurement Device Interface | |
| 5 | − Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org> | |
| 6 | − | |
| 7 | − This program is free software; you can redistribute it and/or modify | |
| 8 | − it under the terms of the GNU General Public License as published by | |
| 9 | − the Free Software Foundation; either version 2 of the License, or | |
| 10 | − (at your option) any later version. | |
| 11 | − | |
| 12 | − This program is distributed in the hope that it will be useful, | |
| 13 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 | − GNU General Public License for more details. | |
| 16 | −*/ | |
| 2 | + * icp_multi.c | |
| 3 | + * Comedi driver for Inova ICP_MULTI board | |
| 4 | + * | |
| 5 | + * COMEDI - Linux Control and Measurement Device Interface | |
| 6 | + * Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License as published by | |
| 10 | + * the Free Software Foundation; either version 2 of the License, or | |
| 11 | + * (at your option) any later version. | |
| 12 | + * | |
| 13 | + * This program is distributed in the hope that it will be useful, | |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 | + * GNU General Public License for more details. | |
| 17 | + */ | |
| 17 | 18 | |
| 18 | 19 | /* |
| 19 | −Driver: icp_multi | |
| 20 | −Description: Inova ICP_MULTI | |
| 21 | −Author: Anne Smorthit <anne.smorthit@sfwte.ch> | |
| 22 | −Devices: [Inova] ICP_MULTI (icp_multi) | |
| 23 | −Status: works | |
| 24 | − | |
| 25 | −The driver works for analog input and output and digital input and output. | |
| 26 | −It does not work with interrupts or with the counters. Currently no support | |
| 27 | −for DMA. | |
| 28 | − | |
| 29 | −It has 16 single-ended or 8 differential Analogue Input channels with 12-bit | |
| 30 | −resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. Input | |
| 31 | −ranges can be individually programmed for each channel. Voltage or current | |
| 32 | −measurement is selected by jumper. | |
| 33 | − | |
| 34 | −There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V | |
| 35 | − | |
| 36 | −16 x Digital Inputs, 24V | |
| 37 | − | |
| 38 | −8 x Digital Outputs, 24V, 1A | |
| 39 | − | |
| 40 | −4 x 16-bit counters | |
| 41 | − | |
| 42 | −Configuration options: not applicable, uses PCI auto config | |
| 43 | −*/ | |
| 20 | + * Driver: icp_multi | |
| 21 | + * Description: Inova ICP_MULTI | |
| 22 | + * Devices: [Inova] ICP_MULTI (icp_multi) | |
| 23 | + * Author: Anne Smorthit <anne.smorthit@sfwte.ch> | |
| 24 | + * Status: works | |
| 25 | + * | |
| 26 | + * Configuration options: not applicable, uses PCI auto config | |
| 27 | + * | |
| 28 | + * The driver works for analog input and output and digital input and | |
| 29 | + * output. It does not work with interrupts or with the counters. Currently | |
| 30 | + * no support for DMA. | |
| 31 | + * | |
| 32 | + * It has 16 single-ended or 8 differential Analogue Input channels with | |
| 33 | + * 12-bit resolution. Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA. | |
| 34 | + * Input ranges can be individually programmed for each channel. Voltage or | |
| 35 | + * current measurement is selected by jumper. | |
| 36 | + * | |
| 37 | + * There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V | |
| 38 | + * | |
| 39 | + * 16 x Digital Inputs, 24V | |
| 40 | + * | |
| 41 | + * 8 x Digital Outputs, 24V, 1A | |
| 42 | + * | |
| 43 | + * 4 x 16-bit counters - not implemented | |
| 44 | + */ | |
| 44 | 45 | |
| 45 | 46 | #include <linux/module.h> |
| 46 | 47 | #include <linux/delay.h> |
| 47 | −#include <linux/interrupt.h> | |
| 48 | 48 | |
| 49 | 49 | #include "../comedi_pci.h" |
| 50 | 50 | |
| 51 | −#define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ | |
| 51 | +#define ICP_MULTI_ADC_CSR 0x00 /* R/W: ADC command/status register */ | |
| 52 | +#define ICP_MULTI_ADC_CSR_ST BIT(0) /* Start ADC */ | |
| 53 | +#define ICP_MULTI_ADC_CSR_BSY BIT(0) /* ADC busy */ | |
| 54 | +#define ICP_MULTI_ADC_CSR_BI BIT(4) /* Bipolar input range */ | |
| 55 | +#define ICP_MULTI_ADC_CSR_RA BIT(5) /* Input range 0 = 5V, 1 = 10V */ | |
| 56 | +#define ICP_MULTI_ADC_CSR_DI BIT(6) /* Input mode 1 = differential */ | |
| 57 | +#define ICP_MULTI_ADC_CSR_DI_CHAN(x) (((x) & 0x7) << 9) | |
| 58 | +#define ICP_MULTI_ADC_CSR_SE_CHAN(x) (((x) & 0xf) << 8) | |
| 52 | 59 | #define ICP_MULTI_AI 2 /* R: Analogue input data */ |
| 53 | −#define ICP_MULTI_DAC_CSR 4 /* R/W: DAC command/status register */ | |
| 60 | +#define ICP_MULTI_DAC_CSR 0x04 /* R/W: DAC command/status register */ | |
| 61 | +#define ICP_MULTI_DAC_CSR_ST BIT(0) /* Start DAC */ | |
| 62 | +#define ICP_MULTI_DAC_CSR_BSY BIT(0) /* DAC busy */ | |
| 63 | +#define ICP_MULTI_DAC_CSR_BI BIT(4) /* Bipolar output range */ | |
| 64 | +#define ICP_MULTI_DAC_CSR_RA BIT(5) /* Output range 0 = 5V, 1 = 10V */ | |
| 65 | +#define ICP_MULTI_DAC_CSR_CHAN(x) (((x) & 0x3) << 8) | |
| 54 | 66 | #define ICP_MULTI_AO 6 /* R/W: Analogue output data */ |
| 55 | 67 | #define ICP_MULTI_DI 8 /* R/W: Digital inputs */ |
| 56 | 68 | #define ICP_MULTI_DO 0x0A /* R/W: Digital outputs */ |
| 57 | −#define ICP_MULTI_INT_EN 0x0C /* R/W: Interrupt enable register */ | |
| 58 | −#define ICP_MULTI_INT_STAT 0x0E /* R/W: Interrupt status register */ | |
| 69 | +#define ICP_MULTI_INT_EN 0x0c /* R/W: Interrupt enable register */ | |
| 70 | +#define ICP_MULTI_INT_STAT 0x0e /* R/W: Interrupt status register */ | |
| 71 | +#define ICP_MULTI_INT_ADC_RDY BIT(0) /* A/D conversion ready interrupt */ | |
| 72 | +#define ICP_MULTI_INT_DAC_RDY BIT(1) /* D/A conversion ready interrupt */ | |
| 73 | +#define ICP_MULTI_INT_DOUT_ERR BIT(2) /* Digital output error interrupt */ | |
| 74 | +#define ICP_MULTI_INT_DIN_STAT BIT(3) /* Digital input status change int. */ | |
| 75 | +#define ICP_MULTI_INT_CIE0 BIT(4) /* Counter 0 overrun interrupt */ | |
| 76 | +#define ICP_MULTI_INT_CIE1 BIT(5) /* Counter 1 overrun interrupt */ | |
| 77 | +#define ICP_MULTI_INT_CIE2 BIT(6) /* Counter 2 overrun interrupt */ | |
| 78 | +#define ICP_MULTI_INT_CIE3 BIT(7) /* Counter 3 overrun interrupt */ | |
| 79 | +#define ICP_MULTI_INT_MASK 0xff /* All interrupts */ | |
551 more lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 481 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
This diff is large: its 501 lines aren’t shown here.
This diff is large: its 470 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 440 lines aren’t shown here.
This diff is large: its 179 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 172 lines aren’t shown here.
This diff is large: its 922 lines aren’t shown here.
This diff is large: its 673 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 779 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 507 lines aren’t shown here.
This diff is large: its 499 lines aren’t shown here.
This diff is large: its 549 lines aren’t shown here.
This diff is large: its 461 lines aren’t shown here.
This diff is large: its 140 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 1779 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 206 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 447 lines aren’t shown here.
This diff is large: its 355 lines aren’t shown here.
This diff is large: its 1122 lines aren’t shown here.
This diff is large: its 638 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 266 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 122 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 307 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 364 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 593 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 513 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 1395 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 312 lines aren’t shown here.
This diff is large: its 302 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 356 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 839 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
Binary file not shown.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 770 lines aren’t shown here.
This diff is large: its 2069 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 790 lines aren’t shown here.
This diff is large: its 1059 lines aren’t shown here.
This diff is large: its 1587 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 151 lines aren’t shown here.
Binary file not shown.
This diff is large: its 367 lines aren’t shown here.
This diff is large: its 179 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 220 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 184 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 403 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 499 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 304 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 399 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 135 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 1261 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 1497 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 189 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 330 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 202 lines aren’t shown here.
This diff is large: its 306 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 327 lines aren’t shown here.
This diff is large: its 403 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 276 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 477 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 388 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 469 lines aren’t shown here.
This diff is large: its 340 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 235 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 313 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 404 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 677 lines aren’t shown here.
This diff is large: its 543 lines aren’t shown here.
This diff is large: its 427 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 391 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 183 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 843 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 334 lines aren’t shown here.
This diff is large: its 662 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 384 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 105 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 182 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 154 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 561 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 169 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 422 lines aren’t shown here.
This diff is large: its 254 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 1055 lines aren’t shown here.
This diff is large: its 903 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 595 lines aren’t shown here.
This diff is large: its 642 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 661 lines aren’t shown here.
This diff is large: its 622 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 805 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 198 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 219 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 710 lines aren’t shown here.
This diff is large: its 1171 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 288 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 185 lines aren’t shown here.
This diff is large: its 878 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 251 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 898 lines aren’t shown here.
This diff is large: its 323 lines aren’t shown here.
This diff is large: its 463 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 830 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 270 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 512 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 200 lines aren’t shown here.
This diff is large: its 174 lines aren’t shown here.
This diff is large: its 268 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 134 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 408 lines aren’t shown here.
This diff is large: its 603 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 274 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 416 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 76 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 470 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 127 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 289 lines aren’t shown here.
This diff is large: its 138 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 272 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 262 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 204 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 253 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 190 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 538 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 381 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 570 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 1080 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 817 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 718 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 226 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 318 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 3958 lines aren’t shown here.
This diff is large: its 41 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 562 lines aren’t shown here.
This diff is large: its 179 lines aren’t shown here.
This diff is large: its 230 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 678 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 504 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 295 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 480 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 514 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 315 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 444 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 529 lines aren’t shown here.
This diff is large: its 496 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 111 lines aren’t shown here.
This diff is large: its 126 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 271 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 113 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 258 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 572 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 914 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 108 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 444 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 494 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 1242 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 716 lines aren’t shown here.
This diff is large: its 175 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 854 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 225 lines aren’t shown here.
This diff is large: its 1275 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 1947 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 10482 lines aren’t shown here.
This diff is large: its 1108 lines aren’t shown here.
This diff is large: its 373 lines aren’t shown here.
This diff is large: its 2591 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 114 lines aren’t shown here.
This diff is large: its 222 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 261 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 502 lines aren’t shown here.
This diff is large: its 798 lines aren’t shown here.
This diff is large: its 3041 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 233 lines aren’t shown here.
This diff is large: its 2085 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 378 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 1670 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 1333 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 373 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 264 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.