mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
Staging driver patches for 3.17-rc1
Here's the big pull request for the staging driver tree for 3.17-rc1. Lots of things in here, over 2000 patches, but the best part is this: 1480 files changed, 39070 insertions(+), 254659 deletions(-) Thanks to the great work of Kristina Martšenko, 14 different staging drivers have been removed from the tree as they were obsolete and no one was willing to work on cleaning them up. Other than the driver removals, loads of cleanups are in here (comedi, lustre, etc.) as well as the usual IIO driver updates and additions. All of this has been in the linux-next tree for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlPf1wYACgkQMUfUDdst+ykrNwCgswPkRSAPQ3C8WvLhzUYRZZ/L AqEAoJP0Q8Fz8unXjlSMcx7pgcqUaJ8G =mrTQ -----END PGP SIGNATURE----- Merge tag 'staging-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging Pull staging driver updates from Greg KH: "Here's the big pull request for the staging driver tree for 3.17-rc1. Lots of things in here, over 2000 patches, but the best part is this: 1480 files changed, 39070 insertions(+), 254659 deletions(-) Thanks to the great work of Kristina Martšenko, 14 different staging drivers have been removed from the tree as they were obsolete and no one was willing to work on cleaning them up. Other than the driver removals, loads of cleanups are in here (comedi, lustre, etc.) as well as the usual IIO driver updates and additions. All of this has been in the linux-next tree for a while" * tag 'staging-3.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (2199 commits) staging: comedi: addi_apci_1564: remove diagnostic interrupt support code staging: comedi: addi_apci_1564: add subdevice to check diagnostic status staging: wlan-ng: coding style problem fix staging: wlan-ng: fixing coding style problems staging: comedi: ii_pci20kc: request and ioremap memory staging: lustre: bitwise vs logical typo staging: dgnc: Remove unneeded dgnc_trace.c and dgnc_trace.h staging: dgnc: rephrase comment staging: comedi: ni_tio: remove some dead code staging: rtl8723au: Fix static symbol sparse warning staging: rtl8723au: usb_dvobj_init(): Remove unused variable 'pdev_desc' staging: rtl8723au: Do not duplicate kernel provided USB macros staging: rtl8723au: Remove never set struct pwrctrl_priv.bHWPowerdown staging: rtl8723au: Remove two never set variables staging: rtl8723au: RSSI_test is never set staging:r8190: coding style: Fixed checkpatch reported Error staging:r8180: coding style: Fixed too long lines staging:r8180: coding style: Fixed commenting style staging: lustre: ptlrpc: lproc_ptlrpc.c - fix dereferenceing user space buffer staging: lustre: ldlm: ldlm_resource.c - fix dereferenceing user space buffer ...
This commit is contained in:
commit
53ee983378
@ -260,6 +260,10 @@ What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
|
||||
KernelVersion: 2.6.35
|
||||
@ -447,6 +451,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
|
||||
@ -492,6 +504,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
|
||||
What: /sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
|
||||
@ -538,6 +558,14 @@ What: /sys/.../events/in_magn_y_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_magn_y_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_magn_z_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_magn_z_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_true_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_true_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value
|
||||
What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value
|
||||
What: /sys/.../events/in_voltageY_raw_thresh_rising_value
|
||||
@ -588,6 +616,18 @@ What: /sys/.../events/in_magn_y_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_either_hysteresis
|
||||
@ -635,6 +675,14 @@ What: /sys/.../events/in_magn_y_raw_roc_rising_value
|
||||
What: /sys/.../events/in_magn_y_raw_roc_falling_value
|
||||
What: /sys/.../events/in_magn_z_raw_roc_rising_value
|
||||
What: /sys/.../events/in_magn_z_raw_roc_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_raw_roc_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_raw_roc_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_true_raw_roc_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_true_raw_roc_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_falling_value
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_rising_value
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_falling_value
|
||||
What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value
|
||||
What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value
|
||||
What: /sys/.../events/in_voltageY_raw_roc_rising_value
|
||||
@ -690,6 +738,22 @@ What: /sys/.../events/in_magn_z_thresh_rising_period
|
||||
What: /sys/.../events/in_magn_z_thresh_falling_period
|
||||
What: /sys/.../events/in_magn_z_roc_rising_period
|
||||
What: /sys/.../events/in_magn_z_roc_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_thresh_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_thresh_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_roc_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_roc_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_true_thresh_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_true_thresh_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_true_roc_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_true_roc_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_period
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_roc_rising_period
|
||||
What: /sys/.../events/in_rot_from_north_true_tilt_comp_roc_falling_period
|
||||
What: /sys/.../events/in_voltageY_supply_thresh_rising_period
|
||||
What: /sys/.../events/in_voltageY_supply_thresh_falling_period
|
||||
What: /sys/.../events/in_voltageY_supply_roc_rising_period
|
||||
@ -787,6 +851,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en
|
||||
@ -853,6 +921,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
|
||||
@ -895,6 +967,19 @@ Description:
|
||||
on-chip EEPROM. After power-up or chip reset the device will
|
||||
automatically load the saved configuration.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_proximity_raw
|
||||
What: /sys/.../iio:deviceX/in_proximity_input
|
||||
What: /sys/.../iio:deviceX/in_proximityY_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Proximity measurement indicating that some
|
||||
object is near the sensor, usually be observing
|
||||
reflectivity of infrared or ultrasound emitted.
|
||||
Often these sensors are unit less and as such conversion
|
||||
to SI units is not possible. Where it is, the units should
|
||||
be meters.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_input
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_raw
|
||||
What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw
|
||||
@ -933,3 +1018,13 @@ Description:
|
||||
x y z w. Here x, y, and z component represents the axis about
|
||||
which a rotation will occur and w component represents the
|
||||
amount of rotation.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_raw
|
||||
KernelVersion: 3.15
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw value of rotation from true/magnetic north measured with
|
||||
or without compensation from tilt sensors.
|
||||
|
@ -14,14 +14,21 @@ Required properties:
|
||||
for exynos4412/5250 controllers.
|
||||
Must be "samsung,exynos-adc-v2" for
|
||||
future controllers.
|
||||
Must be "samsung,exynos3250-adc" for
|
||||
controllers compatible with ADC of Exynos3250.
|
||||
- reg: Contains ADC register address range (base address and
|
||||
length) and the address of the phy enable register.
|
||||
- interrupts: Contains the interrupt information for the timer. The
|
||||
format is being dependent on which interrupt controller
|
||||
the Samsung device uses.
|
||||
- #io-channel-cells = <1>; As ADC has multiple outputs
|
||||
- clocks From common clock binding: handle to adc clock.
|
||||
- clock-names From common clock binding: Shall be "adc".
|
||||
- clocks From common clock bindings: handles to clocks specified
|
||||
in "clock-names" property, in the same order.
|
||||
- clock-names From common clock bindings: list of clock input names
|
||||
used by ADC block:
|
||||
- "adc" : ADC bus clock
|
||||
- "sclk" : ADC special clock (only for Exynos3250 and
|
||||
compatible ADC block)
|
||||
- vdd-supply VDD input supply.
|
||||
|
||||
Note: child nodes can be added for auto probing from device tree.
|
||||
@ -41,6 +48,20 @@ adc: adc@12D10000 {
|
||||
vdd-supply = <&buck5_reg>;
|
||||
};
|
||||
|
||||
Example: adding device info in dtsi file for Exynos3250 with additional sclk
|
||||
|
||||
adc: adc@126C0000 {
|
||||
compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
|
||||
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
|
||||
interrupts = <0 137 0>;
|
||||
#io-channel-cells = <1>;
|
||||
io-channel-ranges;
|
||||
|
||||
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
|
||||
clock-names = "adc", "sclk";
|
||||
|
||||
vdd-supply = <&buck5_reg>;
|
||||
};
|
||||
|
||||
Example: Adding child nodes in dts file
|
||||
|
||||
|
@ -50,6 +50,7 @@ epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
|
||||
fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
|
||||
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
|
||||
fsl,mma8452 MMA8452Q: 3-axis 12-bit / 8-bit Digital Accelerometer
|
||||
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
|
||||
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
|
||||
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
|
||||
|
22
Documentation/devicetree/bindings/iio/adc/max1027-adc.txt
Normal file
22
Documentation/devicetree/bindings/iio/adc/max1027-adc.txt
Normal file
@ -0,0 +1,22 @@
|
||||
* Maxim 1027/1029/1031 Analog to Digital Converter (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "maxim,max1027" or "maxim,max1029" or "maxim,max1031"
|
||||
- reg: SPI chip select number for the device
|
||||
- interrupt-parent: phandle to the parent interrupt controller
|
||||
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
- interrupts: IRQ line for the ADC
|
||||
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "maxim,max1027";
|
||||
reg = <0>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <15 IRQ_TYPE_EDGE_RISING>;
|
||||
spi-max-frequency = <1000000>;
|
||||
};
|
@ -3,6 +3,10 @@
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "honeywell,hmc5843"
|
||||
Other models which are supported with driver are:
|
||||
"honeywell,hmc5883"
|
||||
"honeywell,hmc5883l"
|
||||
"honeywell,hmc5983"
|
||||
- reg : the I2C address of the magnetometer - typically 0x1e
|
||||
|
||||
Optional properties:
|
||||
|
54
Documentation/devicetree/bindings/iio/st-sensors.txt
Normal file
54
Documentation/devicetree/bindings/iio/st-sensors.txt
Normal file
@ -0,0 +1,54 @@
|
||||
STMicroelectronics MEMS sensors
|
||||
|
||||
The STMicroelectronics sensor devices are pretty straight-forward I2C or
|
||||
SPI devices, all sharing the same device tree descriptions no matter what
|
||||
type of sensor it is.
|
||||
|
||||
Required properties:
|
||||
- compatible: see the list of valid compatible strings below
|
||||
- reg: the I2C or SPI address the device will respond to
|
||||
|
||||
Optional properties:
|
||||
- vdd-supply: an optional regulator that needs to be on to provide VDD
|
||||
power to the sensor.
|
||||
- vddio-supply: an optional regulator that needs to be on to provide the
|
||||
VDD IO power to the sensor.
|
||||
- st,drdy-int-pin: the pin on the package that will be used to signal
|
||||
"data ready" (valid values: 1 or 2). This property is not configurable
|
||||
on all sensors.
|
||||
|
||||
Sensors may also have applicable pin control settings, those use the
|
||||
standard bindings from pinctrl/pinctrl-bindings.txt.
|
||||
|
||||
Valid compatible strings:
|
||||
|
||||
Accelerometers:
|
||||
- st,lsm303dlh-accel
|
||||
- st,lsm303dlhc-accel
|
||||
- st,lis3dh-accel
|
||||
- st,lsm330d-accel
|
||||
- st,lsm330dl-accel
|
||||
- st,lsm330dlc-accel
|
||||
- st,lis331dlh-accel
|
||||
- st,lsm303dl-accel
|
||||
- st,lsm303dlm-accel
|
||||
- st,lsm330-accel
|
||||
|
||||
Gyroscopes:
|
||||
- st,l3g4200d-gyro
|
||||
- st,lsm330d-gyro
|
||||
- st,lsm330dl-gyro
|
||||
- st,lsm330dlc-gyro
|
||||
- st,l3gd20-gyro
|
||||
- st,l3g4is-gyro
|
||||
- st,lsm330-gyro
|
||||
|
||||
Magnetometers:
|
||||
- st,lsm303dlhc-magn
|
||||
- st,lsm303dlm-magn
|
||||
- st,lis3mdl-magn
|
||||
|
||||
Pressure sensors:
|
||||
- st,lps001wp-press
|
||||
- st,lps25h-press
|
||||
- st,lps331ap-press
|
@ -1422,10 +1422,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
ip= [IP_PNP]
|
||||
See Documentation/filesystems/nfs/nfsroot.txt.
|
||||
|
||||
ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards
|
||||
See comment before ip2_setup() in
|
||||
drivers/char/ip2/ip2base.c.
|
||||
|
||||
irqfixup [HW]
|
||||
When an interrupt is not handled search all handlers
|
||||
for it. Intended to get systems with badly broken
|
||||
|
67
MAINTAINERS
67
MAINTAINERS
@ -1796,6 +1796,13 @@ W: http://bcache.evilpiepirate.org
|
||||
S: Maintained:
|
||||
F: drivers/md/bcache/
|
||||
|
||||
BECEEM BCS200/BCS220-3/BCSM250 WIMAX SUPPORT
|
||||
M: Kevin McKinney <klmckinney1@gmail.com>
|
||||
M: Matthias Beyer <mail@beyermatthias.de>
|
||||
L: devel@driverdev.osuosl.org
|
||||
S: Maintained
|
||||
F: drivers/staging/bcm*
|
||||
|
||||
BEFS FILE SYSTEM
|
||||
S: Orphan
|
||||
F: Documentation/filesystems/befs.txt
|
||||
@ -2859,6 +2866,7 @@ F: drivers/staging/dgnc/
|
||||
DIGI EPCA PCI PRODUCTS
|
||||
M: Lidza Louina <lidza.louina@gmail.com>
|
||||
M: Mark Hounschell <markh@compro.net>
|
||||
M: Daeseok Youn <daeseok.youn@gmail.com>
|
||||
L: driverdev-devel@linuxdriverproject.org
|
||||
S: Maintained
|
||||
F: drivers/staging/dgap/
|
||||
@ -5075,13 +5083,6 @@ S: Maintained
|
||||
F: Documentation/hwmon/k8temp
|
||||
F: drivers/hwmon/k8temp.c
|
||||
|
||||
KTAP
|
||||
M: Jovi Zhangwei <jovi.zhangwei@gmail.com>
|
||||
W: http://www.ktap.org
|
||||
L: ktap@freelists.org
|
||||
S: Maintained
|
||||
F: drivers/staging/ktap/
|
||||
|
||||
KCONFIG
|
||||
M: "Yann E. MORIN" <yann.morin.1998@free.fr>
|
||||
L: linux-kbuild@vger.kernel.org
|
||||
@ -8569,37 +8570,12 @@ L: devel@driverdev.osuosl.org
|
||||
S: Supported
|
||||
F: drivers/staging/
|
||||
|
||||
STAGING - AGERE HERMES II and II.5 WIRELESS DRIVERS
|
||||
M: Henk de Groot <pe1dnn@amsat.org>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/wlags49_h2/
|
||||
F: drivers/staging/wlags49_h25/
|
||||
|
||||
STAGING - ASUS OLED
|
||||
M: Jakub Schmidtke <sjakub@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/asus_oled/
|
||||
|
||||
STAGING - COMEDI
|
||||
M: Ian Abbott <abbotti@mev.co.uk>
|
||||
M: H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/comedi/
|
||||
|
||||
STAGING - CRYSTAL HD VIDEO DECODER
|
||||
M: Naren Sankar <nsankar@broadcom.com>
|
||||
M: Jarod Wilson <jarod@wilsonet.com>
|
||||
M: Scott Davilla <davilla@4pi.com>
|
||||
M: Manu Abraham <abraham.manu@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/crystalhd/
|
||||
|
||||
STAGING - ECHO CANCELLER
|
||||
M: Steve Underwood <steveu@coppice.org>
|
||||
M: David Rowe <david@rowetel.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/echo/
|
||||
|
||||
STAGING - ET131X NETWORK DRIVER
|
||||
M: Mark Einon <mark.einon@gmail.com>
|
||||
S: Odd Fixes
|
||||
@ -8610,11 +8586,6 @@ M: Marek Belisko <marek.belisko@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/ft1000/
|
||||
|
||||
STAGING - FRONTIER TRANZPORT AND ALPHATRACK
|
||||
M: David Täht <d@teklibre.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/frontier/
|
||||
|
||||
STAGING - GO7007 MPEG CODEC
|
||||
M: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
S: Maintained
|
||||
@ -8671,11 +8642,6 @@ L: linux-wireless@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/rtl8723au/
|
||||
|
||||
STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER
|
||||
M: Teddy Wang <teddy.wang@siliconmotion.com.cn>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/sm7xxfb/
|
||||
|
||||
STAGING - SLICOSS
|
||||
M: Lior Dotan <liodot@gmail.com>
|
||||
M: Christopher Harrer <charrer@alacritech.com>
|
||||
@ -8692,31 +8658,16 @@ M: William Hubbs <w.d.hubbs@gmail.com>
|
||||
M: Chris Brannon <chris@the-brannons.com>
|
||||
M: Kirk Reiser <kirk@reisers.ca>
|
||||
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
L: speakup@braille.uwo.ca
|
||||
L: speakup@linux-speakup.org
|
||||
W: http://www.linux-speakup.org/
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/speakup/
|
||||
|
||||
STAGING - TI DSP BRIDGE DRIVERS
|
||||
M: Omar Ramirez Luna <omar.ramirez@copitl.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/tidspbridge/
|
||||
|
||||
STAGING - USB ENE SM/MS CARD READER DRIVER
|
||||
M: Al Cho <acho@novell.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/keucr/
|
||||
|
||||
STAGING - VIA VT665X DRIVERS
|
||||
M: Forest Bond <forest@alittletooquiet.net>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/vt665?/
|
||||
|
||||
STAGING - WINBOND IS89C35 WLAN USB DRIVER
|
||||
M: Pavel Machek <pavel@ucw.cz>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/winbond/
|
||||
|
||||
STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER
|
||||
M: Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
S: Odd Fixes
|
||||
|
@ -261,10 +261,11 @@
|
||||
};
|
||||
|
||||
adc: adc@126C0000 {
|
||||
compatible = "samsung,exynos-adc-v3";
|
||||
compatible = "samsung,exynos3250-adc",
|
||||
"samsung,exynos-adc-v2";
|
||||
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
|
||||
interrupts = <0 137 0>;
|
||||
clock-names = "adc", "sclk_tsadc";
|
||||
clock-names = "adc", "sclk";
|
||||
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
|
||||
#io-channel-cells = <1>;
|
||||
io-channel-ranges;
|
||||
|
@ -232,10 +232,6 @@ obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
|
||||
iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o
|
||||
obj-y += $(iommu-m) $(iommu-y)
|
||||
|
||||
ifneq ($(CONFIG_TIDSPBRIDGE),)
|
||||
obj-y += dsp.o
|
||||
endif
|
||||
|
||||
# OMAP2420 MSDI controller integration support ("MMC")
|
||||
obj-$(CONFIG_SOC_OMAP2420) += msdi.o
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_data/dsp-omap.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "omap-secure.h"
|
||||
@ -30,7 +29,6 @@ int __weak omap_secure_ram_reserve_memblock(void)
|
||||
|
||||
void __init omap_reserve(void)
|
||||
{
|
||||
omap_dsp_reserve_sdram_memblock();
|
||||
omap_secure_ram_reserve_memblock();
|
||||
omap_barrier_reserve_memblock();
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* TI's OMAP DSP platform device registration
|
||||
*
|
||||
* Copyright (C) 2005-2006 Texas Instruments, Inc.
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
*
|
||||
* Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* XXX The function pointers to the PRM/CM functions are incorrect and
|
||||
* should be removed. No device driver should be changing PRM/CM bits
|
||||
* directly; that's a layering violation -- those bits are the responsibility
|
||||
* of the OMAP PM core code.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/memblock.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "cm2xxx_3xxx.h"
|
||||
#include "prm2xxx_3xxx.h"
|
||||
#ifdef CONFIG_TIDSPBRIDGE_DVFS
|
||||
#include "omap-pm.h"
|
||||
#endif
|
||||
#include "soc.h"
|
||||
|
||||
#include <linux/platform_data/dsp-omap.h>
|
||||
|
||||
static struct platform_device *omap_dsp_pdev;
|
||||
|
||||
static struct omap_dsp_platform_data omap_dsp_pdata __initdata = {
|
||||
#ifdef CONFIG_TIDSPBRIDGE_DVFS
|
||||
.dsp_set_min_opp = omap_pm_dsp_set_min_opp,
|
||||
.dsp_get_opp = omap_pm_dsp_get_opp,
|
||||
.cpu_set_freq = omap_pm_cpu_set_freq,
|
||||
.cpu_get_freq = omap_pm_cpu_get_freq,
|
||||
#endif
|
||||
.dsp_prm_read = omap2_prm_read_mod_reg,
|
||||
.dsp_prm_write = omap2_prm_write_mod_reg,
|
||||
.dsp_prm_rmw_bits = omap2_prm_rmw_mod_reg_bits,
|
||||
.dsp_cm_read = omap2_cm_read_mod_reg,
|
||||
.dsp_cm_write = omap2_cm_write_mod_reg,
|
||||
.dsp_cm_rmw_bits = omap2_cm_rmw_mod_reg_bits,
|
||||
|
||||
.set_bootaddr = omap_ctrl_write_dsp_boot_addr,
|
||||
.set_bootmode = omap_ctrl_write_dsp_boot_mode,
|
||||
};
|
||||
|
||||
static phys_addr_t omap_dsp_phys_mempool_base;
|
||||
|
||||
void __init omap_dsp_reserve_sdram_memblock(void)
|
||||
{
|
||||
phys_addr_t size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
|
||||
phys_addr_t paddr;
|
||||
|
||||
if (!cpu_is_omap34xx())
|
||||
return;
|
||||
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
paddr = arm_memblock_steal(size, SZ_1M);
|
||||
if (!paddr) {
|
||||
pr_err("%s: failed to reserve %llx bytes\n",
|
||||
__func__, (unsigned long long)size);
|
||||
return;
|
||||
}
|
||||
|
||||
omap_dsp_phys_mempool_base = paddr;
|
||||
}
|
||||
|
||||
static phys_addr_t omap_dsp_get_mempool_base(void)
|
||||
{
|
||||
return omap_dsp_phys_mempool_base;
|
||||
}
|
||||
|
||||
static int __init omap_dsp_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int err = -ENOMEM;
|
||||
struct omap_dsp_platform_data *pdata = &omap_dsp_pdata;
|
||||
|
||||
if (!cpu_is_omap34xx())
|
||||
return 0;
|
||||
|
||||
pdata->phys_mempool_base = omap_dsp_get_mempool_base();
|
||||
|
||||
if (pdata->phys_mempool_base) {
|
||||
pdata->phys_mempool_size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
|
||||
pr_info("%s: %llx bytes @ %llx\n", __func__,
|
||||
(unsigned long long)pdata->phys_mempool_size,
|
||||
(unsigned long long)pdata->phys_mempool_base);
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc("omap-dsp", -1);
|
||||
if (!pdev)
|
||||
goto err_out;
|
||||
|
||||
err = platform_device_add_data(pdev, pdata, sizeof(*pdata));
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
omap_dsp_pdev = pdev;
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
platform_device_put(pdev);
|
||||
return err;
|
||||
}
|
||||
module_init(omap_dsp_init);
|
||||
|
||||
static void __exit omap_dsp_exit(void)
|
||||
{
|
||||
if (!cpu_is_omap34xx())
|
||||
return;
|
||||
|
||||
platform_device_unregister(omap_dsp_pdev);
|
||||
}
|
||||
module_exit(omap_dsp_exit);
|
||||
|
||||
MODULE_AUTHOR("Hiroshi DOYU");
|
||||
MODULE_DESCRIPTION("TI's OMAP DSP platform device registration");
|
||||
MODULE_LICENSE("GPL");
|
@ -317,10 +317,14 @@ static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
|
||||
for (index = 0; index < num_ports; index++) {
|
||||
int ipd_port = cvmx_helper_get_ipd_port(interface, index);
|
||||
__cvmx_helper_sgmii_hardware_init_one_time(interface, index);
|
||||
__cvmx_helper_sgmii_link_set(ipd_port,
|
||||
__cvmx_helper_sgmii_link_get
|
||||
(ipd_port));
|
||||
|
||||
/* Linux kernel driver will call ....link_set with the
|
||||
* proper link state. In the simulator there is no
|
||||
* link state polling and hence it is set from
|
||||
* here.
|
||||
*/
|
||||
if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
|
||||
__cvmx_helper_sgmii_link_set(ipd_port,
|
||||
__cvmx_helper_sgmii_link_get(ipd_port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -124,7 +124,6 @@ CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_DS1307=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_OCTEON_ETHERNET=y
|
||||
# CONFIG_NET_VENDOR_SILICOM is not set
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
|
@ -241,7 +241,6 @@ CONFIG_UIO_AEC=m
|
||||
CONFIG_UIO_SERCOS3=m
|
||||
CONFIG_UIO_PCI_GENERIC=m
|
||||
CONFIG_STAGING=y
|
||||
# CONFIG_NET_VENDOR_SILICOM is not set
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT2_FS_XATTR=y
|
||||
CONFIG_EXT2_FS_SECURITY=y
|
||||
|
@ -192,7 +192,6 @@ CONFIG_RTC_DRV_DS3232=y
|
||||
CONFIG_RTC_DRV_CMOS=y
|
||||
CONFIG_UIO=y
|
||||
CONFIG_STAGING=y
|
||||
# CONFIG_NET_VENDOR_SILICOM is not set
|
||||
CONFIG_CLK_PPC_CORENET=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_NTFS_FS=y
|
||||
|
@ -816,6 +816,61 @@ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kstrdup);
|
||||
|
||||
/**
|
||||
* devm_kvasprintf - Allocate resource managed space
|
||||
* for the formatted string.
|
||||
* @dev: Device to allocate memory for
|
||||
* @gfp: the GFP mask used in the devm_kmalloc() call when
|
||||
* allocating memory
|
||||
* @fmt: the formatted string to duplicate
|
||||
* @ap: the list of tokens to be placed in the formatted string
|
||||
* RETURNS:
|
||||
* Pointer to allocated string on success, NULL on failure.
|
||||
*/
|
||||
char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
unsigned int len;
|
||||
char *p;
|
||||
va_list aq;
|
||||
|
||||
va_copy(aq, ap);
|
||||
len = vsnprintf(NULL, 0, fmt, aq);
|
||||
va_end(aq);
|
||||
|
||||
p = devm_kmalloc(dev, len+1, gfp);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
vsnprintf(p, len+1, fmt, ap);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_kvasprintf);
|
||||
|
||||
/**
|
||||
* devm_kasprintf - Allocate resource managed space
|
||||
* and copy an existing formatted string into that
|
||||
* @dev: Device to allocate memory for
|
||||
* @gfp: the GFP mask used in the devm_kmalloc() call when
|
||||
* allocating memory
|
||||
* @fmt: the string to duplicate
|
||||
* RETURNS:
|
||||
* Pointer to allocated string on success, NULL on failure.
|
||||
*/
|
||||
char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *p;
|
||||
|
||||
va_start(ap, fmt);
|
||||
p = devm_kvasprintf(dev, gfp, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_kasprintf);
|
||||
|
||||
/**
|
||||
* devm_kfree - Resource-managed kfree
|
||||
* @dev: Device this memory belongs to
|
||||
|
@ -77,4 +77,16 @@ config MMA8452
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
||||
config KXCJK1013
|
||||
tristate "Kionix 3-Axis Accelerometer Driver"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build a driver for the Kionix KXCJK-1013
|
||||
triaxial acceleration sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called kxcjk-1013.
|
||||
|
||||
endmenu
|
||||
|
@ -5,6 +5,7 @@
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_BMA180) += bma180.o
|
||||
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
|
||||
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
|
||||
obj-$(CONFIG_KXSD9) += kxsd9.o
|
||||
obj-$(CONFIG_MMA8452) += mma8452.o
|
||||
|
||||
|
764
drivers/iio/accel/kxcjk-1013.c
Normal file
764
drivers/iio/accel/kxcjk-1013.c
Normal file
@ -0,0 +1,764 @@
|
||||
/*
|
||||
* KXCJK-1013 3-axis accelerometer driver
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/accel/kxcjk_1013.h>
|
||||
|
||||
#define KXCJK1013_DRV_NAME "kxcjk1013"
|
||||
#define KXCJK1013_IRQ_NAME "kxcjk1013_event"
|
||||
|
||||
#define KXCJK1013_REG_XOUT_L 0x06
|
||||
/*
|
||||
* From low byte X axis register, all the other addresses of Y and Z can be
|
||||
* obtained by just applying axis offset. The following axis defines are just
|
||||
* provide clarity, but not used.
|
||||
*/
|
||||
#define KXCJK1013_REG_XOUT_H 0x07
|
||||
#define KXCJK1013_REG_YOUT_L 0x08
|
||||
#define KXCJK1013_REG_YOUT_H 0x09
|
||||
#define KXCJK1013_REG_ZOUT_L 0x0A
|
||||
#define KXCJK1013_REG_ZOUT_H 0x0B
|
||||
|
||||
#define KXCJK1013_REG_DCST_RESP 0x0C
|
||||
#define KXCJK1013_REG_WHO_AM_I 0x0F
|
||||
#define KXCJK1013_REG_INT_SRC1 0x16
|
||||
#define KXCJK1013_REG_INT_SRC2 0x17
|
||||
#define KXCJK1013_REG_STATUS_REG 0x18
|
||||
#define KXCJK1013_REG_INT_REL 0x1A
|
||||
#define KXCJK1013_REG_CTRL1 0x1B
|
||||
#define KXCJK1013_REG_CTRL2 0x1D
|
||||
#define KXCJK1013_REG_INT_CTRL1 0x1E
|
||||
#define KXCJK1013_REG_INT_CTRL2 0x1F
|
||||
#define KXCJK1013_REG_DATA_CTRL 0x21
|
||||
#define KXCJK1013_REG_WAKE_TIMER 0x29
|
||||
#define KXCJK1013_REG_SELF_TEST 0x3A
|
||||
#define KXCJK1013_REG_WAKE_THRES 0x6A
|
||||
|
||||
#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_GSEL1 BIT(4)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_GSEL0 BIT(3)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_WUFE BIT(1)
|
||||
#define KXCJK1013_REG_INT_REG1_BIT_IEA BIT(4)
|
||||
#define KXCJK1013_REG_INT_REG1_BIT_IEN BIT(5)
|
||||
|
||||
#define KXCJK1013_DATA_MASK_12_BIT 0x0FFF
|
||||
#define KXCJK1013_MAX_STARTUP_TIME_US 100000
|
||||
|
||||
struct kxcjk1013_data {
|
||||
struct i2c_client *client;
|
||||
struct iio_trigger *trig;
|
||||
bool trig_mode;
|
||||
struct mutex mutex;
|
||||
s16 buffer[8];
|
||||
int power_state;
|
||||
u8 odr_bits;
|
||||
bool active_high_intr;
|
||||
};
|
||||
|
||||
enum kxcjk1013_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
enum kxcjk1013_mode {
|
||||
STANDBY,
|
||||
OPERATION,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int val;
|
||||
int val2;
|
||||
int odr_bits;
|
||||
} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09},
|
||||
{3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0},
|
||||
{25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03},
|
||||
{200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06},
|
||||
{1600, 0, 0x07} };
|
||||
|
||||
/* Refer to section 4 of the specification */
|
||||
static const struct {
|
||||
int odr_bits;
|
||||
int usec;
|
||||
} odr_start_up_times[] = { {0x08, 100000}, {0x09, 100000}, {0x0A, 100000},
|
||||
{0x0B, 100000}, { 0, 80000}, {0x01, 41000},
|
||||
{0x02, 21000}, {0x03, 11000}, {0x04, 6400},
|
||||
{0x05, 3900}, {0x06, 2700}, {0x07, 2100} };
|
||||
|
||||
static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
|
||||
enum kxcjk1013_mode mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mode == STANDBY)
|
||||
ret &= ~KXCJK1013_REG_CTRL1_BIT_PC1;
|
||||
else
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_PC1;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_WHO_AM_I);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading who_am_i\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&data->client->dev, "KXCJK1013 Chip Id %x\n", ret);
|
||||
|
||||
ret = kxcjk1013_set_mode(data, STANDBY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setting range to 4G */
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_GSEL0;
|
||||
ret &= ~KXCJK1013_REG_CTRL1_BIT_GSEL1;
|
||||
|
||||
/* Set 12 bit mode */
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_RES;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1,
|
||||
ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_data_ctrl\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->odr_bits = ret;
|
||||
|
||||
/* Set up INT polarity */
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data->active_high_intr)
|
||||
ret |= KXCJK1013_REG_INT_REG1_BIT_IEA;
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEA;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
||||
ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data,
|
||||
bool status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* This is requirement by spec to change state to STANDBY */
|
||||
ret = kxcjk1013_set_mode(data, STANDBY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status)
|
||||
ret |= KXCJK1013_REG_INT_REG1_BIT_IEN;
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
||||
ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (status)
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_DRDY;
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxcjk1013_convert_freq_to_bit(int val, int val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) {
|
||||
if (samp_freq_table[i].val == val &&
|
||||
samp_freq_table[i].val2 == val2) {
|
||||
return samp_freq_table[i].odr_bits;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
|
||||
{
|
||||
int ret;
|
||||
int odr_bits;
|
||||
|
||||
odr_bits = kxcjk1013_convert_freq_to_bit(val, val2);
|
||||
if (odr_bits < 0)
|
||||
return odr_bits;
|
||||
|
||||
/* To change ODR, the chip must be set to STANDBY as per spec */
|
||||
ret = kxcjk1013_set_mode(data, STANDBY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL,
|
||||
odr_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing data_ctrl\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->odr_bits = odr_bits;
|
||||
|
||||
/* Check, if the ODR is changed after data enable */
|
||||
if (data->power_state) {
|
||||
/* Set the state back to operation */
|
||||
ret = kxcjk1013_set_mode(data, OPERATION);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) {
|
||||
if (samp_freq_table[i].odr_bits == data->odr_bits) {
|
||||
*val = samp_freq_table[i].val;
|
||||
*val2 = samp_freq_table[i].val2;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis)
|
||||
{
|
||||
u8 reg = KXCJK1013_REG_XOUT_L + axis * 2;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to read accel_%c registers\n", 'x' + axis);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) {
|
||||
if (odr_start_up_times[i].odr_bits == data->odr_bits)
|
||||
return odr_start_up_times[i].usec;
|
||||
}
|
||||
|
||||
return KXCJK1013_MAX_STARTUP_TIME_US;
|
||||
}
|
||||
|
||||
static int kxcjk1013_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&data->mutex);
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
ret = -EBUSY;
|
||||
else {
|
||||
int sleep_val;
|
||||
|
||||
ret = kxcjk1013_set_mode(data, OPERATION);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
++data->power_state;
|
||||
sleep_val = kxcjk1013_get_startup_times(data);
|
||||
if (sleep_val < 20000)
|
||||
usleep_range(sleep_val, 20000);
|
||||
else
|
||||
msleep_interruptible(sleep_val/1000);
|
||||
ret = kxcjk1013_get_acc_reg(data, chan->scan_index);
|
||||
if (--data->power_state == 0)
|
||||
kxcjk1013_set_mode(data, STANDBY);
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = sign_extend32(ret >> 4, 11);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = 19163; /* range +-4g (4/2047*9.806650) */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
mutex_lock(&data->mutex);
|
||||
ret = kxcjk1013_get_odr(data, val, val2);
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kxcjk1013_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
mutex_lock(&data->mutex);
|
||||
ret = kxcjk1013_set_odr(data, val, val2);
|
||||
mutex_unlock(&data->mutex);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->trig != trig)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600");
|
||||
|
||||
static struct attribute *kxcjk1013_attributes[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group kxcjk1013_attrs_group = {
|
||||
.attrs = kxcjk1013_attributes,
|
||||
};
|
||||
|
||||
#define KXCJK1013_CHANNEL(_axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##_axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = AXIS_##_axis, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec kxcjk1013_channels[] = {
|
||||
KXCJK1013_CHANNEL(X),
|
||||
KXCJK1013_CHANNEL(Y),
|
||||
KXCJK1013_CHANNEL(Z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static const struct iio_info kxcjk1013_info = {
|
||||
.attrs = &kxcjk1013_attrs_group,
|
||||
.read_raw = kxcjk1013_read_raw,
|
||||
.write_raw = kxcjk1013_write_raw,
|
||||
.validate_trigger = kxcjk1013_validate_trigger,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->buffer->scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = kxcjk1013_get_acc_reg(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[i++] = ret;
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
pf->timestamp);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int kxcjk1013_trig_try_reen(struct iio_trigger *trig)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (state) {
|
||||
kxcjk1013_chip_setup_interrupt(data, true);
|
||||
kxcjk1013_set_mode(data, OPERATION);
|
||||
++data->power_state;
|
||||
} else {
|
||||
if (--data->power_state) {
|
||||
mutex_unlock(&data->mutex);
|
||||
return 0;
|
||||
}
|
||||
kxcjk1013_chip_setup_interrupt(data, false);
|
||||
kxcjk1013_set_mode(data, STANDBY);
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
|
||||
.set_trigger_state = kxcjk1013_data_rdy_trigger_set_state,
|
||||
.try_reenable = kxcjk1013_trig_try_reen,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client,
|
||||
struct kxcjk1013_data *data)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
int ret;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
if (!ACPI_HANDLE(dev))
|
||||
return -ENODEV;
|
||||
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
/* data ready gpio interrupt pin */
|
||||
gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "acpi gpio get index failed\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ret = gpiod_direction_input(gpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gpiod_to_irq(gpio);
|
||||
|
||||
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxcjk1013_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct kxcjk1013_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
struct iio_trigger *trig = NULL;
|
||||
struct kxcjk_1013_platform_data *pdata;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (pdata)
|
||||
data->active_high_intr = pdata->active_high_intr;
|
||||
else
|
||||
data->active_high_intr = true; /* default polarity */
|
||||
|
||||
ret = kxcjk1013_chip_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = kxcjk1013_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels);
|
||||
indio_dev->name = KXCJK1013_DRV_NAME;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &kxcjk1013_info;
|
||||
|
||||
if (client->irq < 0)
|
||||
client->irq = kxcjk1013_acpi_gpio_probe(client, data);
|
||||
|
||||
if (client->irq >= 0) {
|
||||
trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (!trig)
|
||||
return -ENOMEM;
|
||||
|
||||
data->trig_mode = true;
|
||||
|
||||
ret = devm_request_irq(&client->dev, client->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
IRQF_TRIGGER_RISING,
|
||||
KXCJK1013_IRQ_NAME,
|
||||
trig);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to request IRQ\n");
|
||||
goto err_trigger_free;
|
||||
}
|
||||
|
||||
trig->dev.parent = &client->dev;
|
||||
trig->ops = &kxcjk1013_trigger_ops;
|
||||
iio_trigger_set_drvdata(trig, indio_dev);
|
||||
data->trig = trig;
|
||||
indio_dev->trig = trig;
|
||||
iio_trigger_get(indio_dev->trig);
|
||||
|
||||
ret = iio_trigger_register(trig);
|
||||
if (ret)
|
||||
goto err_trigger_free;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
kxcjk1013_trigger_handler,
|
||||
NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"iio triggered buffer setup failed\n");
|
||||
goto err_trigger_unregister;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_iio_device_register(&client->dev, indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "unable to register iio device\n");
|
||||
goto err_buffer_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_buffer_cleanup:
|
||||
if (data->trig_mode)
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_trigger_unregister:
|
||||
if (data->trig_mode)
|
||||
iio_trigger_unregister(trig);
|
||||
err_trigger_free:
|
||||
if (data->trig_mode)
|
||||
iio_trigger_free(trig);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kxcjk1013_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (data->trig_mode) {
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
iio_trigger_unregister(data->trig);
|
||||
iio_trigger_free(data->trig);
|
||||
}
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
kxcjk1013_set_mode(data, STANDBY);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int kxcjk1013_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
kxcjk1013_set_mode(data, STANDBY);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kxcjk1013_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (data->power_state)
|
||||
kxcjk1013_set_mode(data, OPERATION);
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend, kxcjk1013_resume);
|
||||
#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops)
|
||||
#else
|
||||
#define KXCJK1013_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static const struct acpi_device_id kx_acpi_match[] = {
|
||||
{"KXCJ1013", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
|
||||
|
||||
static const struct i2c_device_id kxcjk1013_id[] = {
|
||||
{"kxcjk1013", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
|
||||
|
||||
static struct i2c_driver kxcjk1013_driver = {
|
||||
.driver = {
|
||||
.name = KXCJK1013_DRV_NAME,
|
||||
.acpi_match_table = ACPI_PTR(kx_acpi_match),
|
||||
.pm = KXCJK1013_PM_OPS,
|
||||
},
|
||||
.probe = kxcjk1013_probe,
|
||||
.remove = kxcjk1013_remove,
|
||||
.id_table = kxcjk1013_id,
|
||||
};
|
||||
module_i2c_driver(kxcjk1013_driver);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("KXCJK1013 accelerometer driver");
|
@ -429,9 +429,15 @@ static const struct i2c_device_id mma8452_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma8452_id);
|
||||
|
||||
static const struct of_device_id mma8452_dt_ids[] = {
|
||||
{ .compatible = "fsl,mma8452" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_driver mma8452_driver = {
|
||||
.driver = {
|
||||
.name = "mma8452",
|
||||
.of_match_table = of_match_ptr(mma8452_dt_ids),
|
||||
.pm = MMA8452_PM_OPS,
|
||||
},
|
||||
.probe = mma8452_probe,
|
||||
|
@ -393,6 +393,9 @@ static int st_accel_read_raw(struct iio_dev *indio_dev,
|
||||
*val = 0;
|
||||
*val2 = adata->current_fullscale->gain;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = adata->odr;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -410,6 +413,13 @@ static int st_accel_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
err = st_sensors_set_odr(indio_dev, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return err;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -417,14 +427,12 @@ static int st_accel_write_raw(struct iio_dev *indio_dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
|
||||
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
|
||||
static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
|
||||
|
||||
static struct attribute *st_accel_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,55 @@
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_accel.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st_accel_of_match[] = {
|
||||
{
|
||||
.compatible = "st,lsm303dlh-accel",
|
||||
.data = LSM303DLH_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303dlhc-accel",
|
||||
.data = LSM303DLHC_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis3dh-accel",
|
||||
.data = LIS3DH_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330d-accel",
|
||||
.data = LSM330D_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330dl-accel",
|
||||
.data = LSM330DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330dlc-accel",
|
||||
.data = LSM330DLC_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis331dlh-accel",
|
||||
.data = LIS331DLH_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303dl-accel",
|
||||
.data = LSM303DL_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303dlm-accel",
|
||||
.data = LSM303DLM_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330-accel",
|
||||
.data = LSM330_ACCEL_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_accel_of_match);
|
||||
#else
|
||||
#define st_accel_of_match NULL
|
||||
#endif
|
||||
|
||||
static int st_accel_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -31,6 +80,7 @@ static int st_accel_i2c_probe(struct i2c_client *client,
|
||||
|
||||
adata = iio_priv(indio_dev);
|
||||
adata->dev = &client->dev;
|
||||
st_sensors_of_i2c_probe(client, st_accel_of_match);
|
||||
|
||||
st_sensors_i2c_configure(indio_dev, client, adata);
|
||||
|
||||
@ -67,6 +117,7 @@ static struct i2c_driver st_accel_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-accel-i2c",
|
||||
.of_match_table = of_match_ptr(st_accel_of_match),
|
||||
},
|
||||
.probe = st_accel_i2c_probe,
|
||||
.remove = st_accel_i2c_remove,
|
||||
|
@ -20,6 +20,16 @@ config AD7266
|
||||
Say yes here to build support for Analog Devices AD7265 and AD7266
|
||||
ADCs.
|
||||
|
||||
config AD7291
|
||||
tristate "Analog Devices AD7291 ADC driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7291
|
||||
8 Channel ADC with temperature sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ad7291.
|
||||
|
||||
config AD7298
|
||||
tristate "Analog Devices AD7298 ADC driver"
|
||||
depends on SPI
|
||||
@ -131,6 +141,15 @@ config LP8788_ADC
|
||||
help
|
||||
Say yes here to build support for TI LP8788 ADC.
|
||||
|
||||
config MAX1027
|
||||
tristate "Maxim max1027 ADC driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Maxim SPI ADC models
|
||||
max1027, max1029 and max1031.
|
||||
|
||||
config MAX1363
|
||||
tristate "Maxim max1363 ADC driver"
|
||||
depends on I2C
|
||||
|
@ -5,6 +5,7 @@
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
|
||||
obj-$(CONFIG_AD7266) += ad7266.o
|
||||
obj-$(CONFIG_AD7291) += ad7291.o
|
||||
obj-$(CONFIG_AD7298) += ad7298.o
|
||||
obj-$(CONFIG_AD7923) += ad7923.o
|
||||
obj-$(CONFIG_AD7476) += ad7476.o
|
||||
@ -15,6 +16,7 @@ obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
obj-$(CONFIG_MCP320X) += mcp320x.o
|
||||
obj-$(CONFIG_MCP3422) += mcp3422.o
|
||||
|
@ -6,22 +6,22 @@
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
#include "ad7291.h"
|
||||
#include <linux/platform_data/ad7291.h>
|
||||
|
||||
/*
|
||||
* Simplified handling
|
||||
@ -31,7 +31,6 @@
|
||||
* is in the read mask.
|
||||
*
|
||||
* The noise-delayed bit as per datasheet suggestion is always enabled.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -47,33 +46,38 @@
|
||||
#define AD7291_VOLTAGE_ALERT_STATUS 0x1F
|
||||
#define AD7291_T_ALERT_STATUS 0x20
|
||||
|
||||
#define AD7291_BITS 12
|
||||
#define AD7291_VOLTAGE_LIMIT_COUNT 8
|
||||
|
||||
|
||||
/*
|
||||
* AD7291 command
|
||||
*/
|
||||
#define AD7291_AUTOCYCLE (1 << 0)
|
||||
#define AD7291_RESET (1 << 1)
|
||||
#define AD7291_ALERT_CLEAR (1 << 2)
|
||||
#define AD7291_ALERT_POLARITY (1 << 3)
|
||||
#define AD7291_EXT_REF (1 << 4)
|
||||
#define AD7291_NOISE_DELAY (1 << 5)
|
||||
#define AD7291_T_SENSE_MASK (1 << 7)
|
||||
#define AD7291_VOLTAGE_MASK 0xFF00
|
||||
#define AD7291_VOLTAGE_OFFSET 0x8
|
||||
#define AD7291_AUTOCYCLE BIT(0)
|
||||
#define AD7291_RESET BIT(1)
|
||||
#define AD7291_ALERT_CLEAR BIT(2)
|
||||
#define AD7291_ALERT_POLARITY BIT(3)
|
||||
#define AD7291_EXT_REF BIT(4)
|
||||
#define AD7291_NOISE_DELAY BIT(5)
|
||||
#define AD7291_T_SENSE_MASK BIT(7)
|
||||
#define AD7291_VOLTAGE_MASK GENMASK(15, 8)
|
||||
#define AD7291_VOLTAGE_OFFSET 8
|
||||
|
||||
/*
|
||||
* AD7291 value masks
|
||||
*/
|
||||
#define AD7291_CHANNEL_MASK 0xF000
|
||||
#define AD7291_BITS 12
|
||||
#define AD7291_VALUE_MASK 0xFFF
|
||||
#define AD7291_T_VALUE_SIGN 0x400
|
||||
#define AD7291_T_VALUE_FLOAT_OFFSET 2
|
||||
#define AD7291_T_VALUE_FLOAT_MASK 0x2
|
||||
#define AD7291_VALUE_MASK GENMASK(11, 0)
|
||||
|
||||
/*
|
||||
* AD7291 alert register bits
|
||||
*/
|
||||
#define AD7291_T_LOW BIT(0)
|
||||
#define AD7291_T_HIGH BIT(1)
|
||||
#define AD7291_T_AVG_LOW BIT(2)
|
||||
#define AD7291_T_AVG_HIGH BIT(3)
|
||||
#define AD7291_V_LOW(x) BIT((x) * 2)
|
||||
#define AD7291_V_HIGH(x) BIT((x) * 2 + 1)
|
||||
|
||||
#define AD7291_BITS 12
|
||||
|
||||
struct ad7291_chip_info {
|
||||
struct i2c_client *client;
|
||||
@ -129,14 +133,14 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
|
||||
ad7291_i2c_write(chip, AD7291_COMMAND, command);
|
||||
|
||||
/* For now treat t_sense and t_sense_average the same */
|
||||
if ((t_status & (1 << 0)) || (t_status & (1 << 2)))
|
||||
if ((t_status & AD7291_T_LOW) || (t_status & AD7291_T_AVG_LOW))
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
timestamp);
|
||||
if ((t_status & (1 << 1)) || (t_status & (1 << 3)))
|
||||
if ((t_status & AD7291_T_HIGH) || (t_status & AD7291_T_AVG_HIGH))
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_TEMP,
|
||||
0,
|
||||
@ -144,18 +148,18 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
|
||||
IIO_EV_DIR_RISING),
|
||||
timestamp);
|
||||
|
||||
for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT*2; i += 2) {
|
||||
if (v_status & (1 << i))
|
||||
for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
|
||||
if (v_status & AD7291_V_LOW(i))
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
|
||||
i/2,
|
||||
i,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
timestamp);
|
||||
if (v_status & (1 << (i + 1)))
|
||||
if (v_status & AD7291_V_HIGH(i))
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
|
||||
i/2,
|
||||
i,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
timestamp);
|
||||
@ -165,7 +169,8 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
|
||||
}
|
||||
|
||||
static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
|
||||
enum iio_event_direction dir, enum iio_event_info info)
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info)
|
||||
{
|
||||
unsigned int offset;
|
||||
|
||||
@ -174,7 +179,7 @@ static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
|
||||
offset = chan->channel;
|
||||
break;
|
||||
case IIO_TEMP:
|
||||
offset = 8;
|
||||
offset = AD7291_VOLTAGE_OFFSET;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@ -182,14 +187,14 @@ static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
return AD7291_DATA_HIGH(offset);
|
||||
else
|
||||
return AD7291_DATA_LOW(offset);
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
return AD7291_DATA_HIGH(offset);
|
||||
else
|
||||
return AD7291_DATA_LOW(offset);
|
||||
case IIO_EV_INFO_HYSTERESIS:
|
||||
return AD7291_HYST(offset);
|
||||
return AD7291_HYST(offset);
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -206,7 +211,7 @@ static int ad7291_read_event_value(struct iio_dev *indio_dev,
|
||||
u16 uval;
|
||||
|
||||
ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info),
|
||||
&uval);
|
||||
&uval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -237,7 +242,7 @@ static int ad7291_write_event_value(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info),
|
||||
val);
|
||||
val);
|
||||
}
|
||||
|
||||
static int ad7291_read_event_config(struct iio_dev *indio_dev,
|
||||
@ -246,15 +251,14 @@ static int ad7291_read_event_config(struct iio_dev *indio_dev,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
/* To be enabled the channel must simply be on. If any are enabled
|
||||
we are in continuous sampling mode */
|
||||
/*
|
||||
* To be enabled the channel must simply be on. If any are enabled
|
||||
* we are in continuous sampling mode
|
||||
*/
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (chip->c_mask & (1 << (15 - chan->channel)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return !!(chip->c_mask & BIT(15 - chan->channel));
|
||||
case IIO_TEMP:
|
||||
/* always on */
|
||||
return 1;
|
||||
@ -336,7 +340,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
/* Enable this channel alone */
|
||||
regval = chip->command & (~AD7291_VOLTAGE_MASK);
|
||||
regval |= 1 << (15 - chan->channel);
|
||||
regval |= BIT(15 - chan->channel);
|
||||
ret = ad7291_i2c_write(chip, AD7291_COMMAND, regval);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&chip->state_lock);
|
||||
@ -344,7 +348,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
/* Read voltage */
|
||||
ret = i2c_smbus_read_word_swapped(chip->client,
|
||||
AD7291_VOLTAGE);
|
||||
AD7291_VOLTAGE);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&chip->state_lock);
|
||||
return ret;
|
||||
@ -355,7 +359,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_TEMP:
|
||||
/* Assumes tsense bit of command register always set */
|
||||
ret = i2c_smbus_read_word_swapped(chip->client,
|
||||
AD7291_T_SENSE);
|
||||
AD7291_T_SENSE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(ret, 11);
|
||||
@ -365,7 +369,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
case IIO_CHAN_INFO_AVERAGE_RAW:
|
||||
ret = i2c_smbus_read_word_swapped(chip->client,
|
||||
AD7291_T_AVERAGE);
|
||||
AD7291_T_AVERAGE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = sign_extend32(ret, 11);
|
||||
@ -375,6 +379,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_VOLTAGE:
|
||||
if (chip->reg) {
|
||||
int vref;
|
||||
|
||||
vref = regulator_get_voltage(chip->reg);
|
||||
if (vref < 0)
|
||||
return vref;
|
||||
@ -460,7 +465,7 @@ static const struct iio_info ad7291_info = {
|
||||
};
|
||||
|
||||
static int ad7291_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ad7291_platform_data *pdata = client->dev.platform_data;
|
||||
struct ad7291_chip_info *chip;
|
@ -16,6 +16,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -25,23 +26,19 @@
|
||||
|
||||
#include <linux/platform_data/ad7298.h>
|
||||
|
||||
#define AD7298_WRITE (1 << 15) /* write to the control register */
|
||||
#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */
|
||||
#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */
|
||||
#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */
|
||||
#define AD7298_EXTREF (1 << 2) /* external reference enable */
|
||||
#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
|
||||
#define AD7298_PDD (1 << 0) /* partial power down enable */
|
||||
#define AD7298_WRITE BIT(15) /* write to the control register */
|
||||
#define AD7298_REPEAT BIT(14) /* repeated conversion enable */
|
||||
#define AD7298_CH(x) BIT(13 - (x)) /* channel select */
|
||||
#define AD7298_TSENSE BIT(5) /* temperature conversion enable */
|
||||
#define AD7298_EXTREF BIT(2) /* external reference enable */
|
||||
#define AD7298_TAVG BIT(1) /* temperature sensor averaging enable */
|
||||
#define AD7298_PDD BIT(0) /* partial power down enable */
|
||||
|
||||
#define AD7298_MAX_CHAN 8
|
||||
#define AD7298_BITS 12
|
||||
#define AD7298_STORAGE_BITS 16
|
||||
#define AD7298_INTREF_mV 2500
|
||||
|
||||
#define AD7298_CH_TEMP 9
|
||||
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
struct ad7298_state {
|
||||
struct spi_device *spi;
|
||||
struct regulator *reg;
|
||||
@ -257,7 +254,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
if (chan->address != AD7298_CH_TEMP)
|
||||
*val = ret & RES_MASK(AD7298_BITS);
|
||||
*val = ret & GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -21,8 +22,6 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
struct ad7476_state;
|
||||
|
||||
struct ad7476_chip_info {
|
||||
@ -117,7 +116,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> st->chip_info->channel[0].scan_type.shift) &
|
||||
RES_MASK(st->chip_info->channel[0].scan_type.realbits);
|
||||
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (!st->chip_info->int_vref_uv) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -25,14 +26,14 @@
|
||||
|
||||
#include <linux/platform_data/ad7887.h>
|
||||
|
||||
#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */
|
||||
#define AD7887_DUAL (1 << 4) /* dual-channel mode */
|
||||
#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */
|
||||
#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */
|
||||
#define AD7887_PM_MODE1 (0) /* CS based shutdown */
|
||||
#define AD7887_PM_MODE2 (1) /* full on */
|
||||
#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */
|
||||
#define AD7887_PM_MODE4 (3) /* standby mode */
|
||||
#define AD7887_REF_DIS BIT(5) /* on-chip reference disable */
|
||||
#define AD7887_DUAL BIT(4) /* dual-channel mode */
|
||||
#define AD7887_CH_AIN1 BIT(3) /* convert on channel 1, DUAL=1 */
|
||||
#define AD7887_CH_AIN0 0 /* convert on channel 0, DUAL=0,1 */
|
||||
#define AD7887_PM_MODE1 0 /* CS based shutdown */
|
||||
#define AD7887_PM_MODE2 1 /* full on */
|
||||
#define AD7887_PM_MODE3 2 /* auto shutdown after conversion */
|
||||
#define AD7887_PM_MODE4 3 /* standby mode */
|
||||
|
||||
enum ad7887_channels {
|
||||
AD7887_CH0,
|
||||
@ -40,8 +41,6 @@ enum ad7887_channels {
|
||||
AD7887_CH1,
|
||||
};
|
||||
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
|
||||
/**
|
||||
* struct ad7887_chip_info - chip specifc information
|
||||
* @int_vref_mv: the internal reference voltage
|
||||
@ -167,7 +166,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret >> chan->scan_type.shift;
|
||||
*val &= RES_MASK(chan->scan_type.realbits);
|
||||
*val &= GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->reg) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -41,7 +42,7 @@
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AD799X_CHANNEL_SHIFT 4
|
||||
#define AD799X_STORAGEBITS 16
|
||||
|
||||
/*
|
||||
* AD7991, AD7995 and AD7999 defines
|
||||
*/
|
||||
@ -55,10 +56,10 @@
|
||||
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines
|
||||
*/
|
||||
|
||||
#define AD7998_FLTR 0x08
|
||||
#define AD7998_ALERT_EN 0x04
|
||||
#define AD7998_BUSY_ALERT 0x02
|
||||
#define AD7998_BUSY_ALERT_POL 0x01
|
||||
#define AD7998_FLTR BIT(3)
|
||||
#define AD7998_ALERT_EN BIT(2)
|
||||
#define AD7998_BUSY_ALERT BIT(1)
|
||||
#define AD7998_BUSY_ALERT_POL BIT(0)
|
||||
|
||||
#define AD7998_CONV_RES_REG 0x0
|
||||
#define AD7998_ALERT_STAT_REG 0x1
|
||||
@ -69,7 +70,7 @@
|
||||
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
|
||||
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
|
||||
|
||||
#define AD7998_CYC_MASK 0x7
|
||||
#define AD7998_CYC_MASK GENMASK(2, 0)
|
||||
#define AD7998_CYC_DIS 0x0
|
||||
#define AD7998_CYC_TCONF_32 0x1
|
||||
#define AD7998_CYC_TCONF_64 0x2
|
||||
@ -85,10 +86,8 @@
|
||||
* AD7997 and AD7997 defines
|
||||
*/
|
||||
|
||||
#define AD7997_8_READ_SINGLE 0x80
|
||||
#define AD7997_8_READ_SEQUENCE 0x70
|
||||
/* TODO: move this into a common header */
|
||||
#define RES_MASK(bits) ((1 << (bits)) - 1)
|
||||
#define AD7997_8_READ_SINGLE BIT(7)
|
||||
#define AD7997_8_READ_SEQUENCE (BIT(6) | BIT(5) | BIT(4))
|
||||
|
||||
enum {
|
||||
ad7991,
|
||||
@ -102,23 +101,32 @@ enum {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad799x_chip_info - chip specific information
|
||||
* struct ad799x_chip_config - chip specific information
|
||||
* @channel: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @monitor_mode: whether the chip supports monitor interrupts
|
||||
* @default_config: device default configuration
|
||||
* @event_attrs: pointer to the monitor event attribute group
|
||||
* @info: pointer to iio_info struct
|
||||
*/
|
||||
struct ad799x_chip_info {
|
||||
struct iio_chan_spec channel[9];
|
||||
int num_channels;
|
||||
struct ad799x_chip_config {
|
||||
const struct iio_chan_spec channel[9];
|
||||
u16 default_config;
|
||||
const struct iio_info *info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad799x_chip_info - chip specific information
|
||||
* @num_channels: number of channels
|
||||
* @noirq_config: device configuration w/o IRQ
|
||||
* @irq_config: device configuration w/IRQ
|
||||
*/
|
||||
struct ad799x_chip_info {
|
||||
int num_channels;
|
||||
const struct ad799x_chip_config noirq_config;
|
||||
const struct ad799x_chip_config irq_config;
|
||||
};
|
||||
|
||||
struct ad799x_state {
|
||||
struct i2c_client *client;
|
||||
const struct ad799x_chip_info *chip_info;
|
||||
const struct ad799x_chip_config *chip_config;
|
||||
struct regulator *reg;
|
||||
struct regulator *vref;
|
||||
unsigned id;
|
||||
@ -128,6 +136,30 @@ struct ad799x_state {
|
||||
unsigned int transfer_size;
|
||||
};
|
||||
|
||||
static int ad799x_write_config(struct ad799x_state *st, u16 val)
|
||||
{
|
||||
switch (st->id) {
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
|
||||
val);
|
||||
default:
|
||||
return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
|
||||
val);
|
||||
}
|
||||
}
|
||||
|
||||
static int ad799x_read_config(struct ad799x_state *st)
|
||||
{
|
||||
switch (st->id) {
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
|
||||
default:
|
||||
return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
|
||||
*
|
||||
@ -176,66 +208,7 @@ out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* ad799x register access by I2C
|
||||
*/
|
||||
static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data)
|
||||
{
|
||||
struct i2c_client *client = st->client;
|
||||
int ret = 0;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(client, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "I2C read error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*data = (u16)ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data)
|
||||
{
|
||||
struct i2c_client *client = st->client;
|
||||
int ret = 0;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "I2C read error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*data = (u8)ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data)
|
||||
{
|
||||
struct i2c_client *client = st->client;
|
||||
int ret = 0;
|
||||
|
||||
ret = i2c_smbus_write_word_swapped(client, reg, data);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "I2C write error\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data)
|
||||
{
|
||||
struct i2c_client *client = st->client;
|
||||
int ret = 0;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, reg, data);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "I2C write error\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
|
||||
static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
|
||||
const unsigned long *scan_mask)
|
||||
{
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
@ -248,33 +221,33 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
|
||||
st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7992:
|
||||
case ad7993:
|
||||
case ad7994:
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
return ad799x_i2c_write16(st, AD7998_CONF_REG,
|
||||
st->config | (*scan_mask << AD799X_CHANNEL_SHIFT));
|
||||
st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT);
|
||||
st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT);
|
||||
return ad799x_write_config(st, st->config);
|
||||
default:
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
|
||||
{
|
||||
u16 rxbuf;
|
||||
u8 cmd;
|
||||
int ret;
|
||||
|
||||
switch (st->id) {
|
||||
case ad7991:
|
||||
case ad7995:
|
||||
case ad7999:
|
||||
cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT);
|
||||
cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT);
|
||||
break;
|
||||
case ad7992:
|
||||
case ad7993:
|
||||
case ad7994:
|
||||
cmd = (1 << ch) << AD799X_CHANNEL_SHIFT;
|
||||
cmd = BIT(ch) << AD799X_CHANNEL_SHIFT;
|
||||
break;
|
||||
case ad7997:
|
||||
case ad7998:
|
||||
@ -284,11 +257,7 @@ static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ad799x_i2c_read16(st, cmd, &rxbuf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return rxbuf;
|
||||
return i2c_smbus_read_word_swapped(st->client, cmd);
|
||||
}
|
||||
|
||||
static int ad799x_read_raw(struct iio_dev *indio_dev,
|
||||
@ -312,7 +281,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> chan->scan_type.shift) &
|
||||
RES_MASK(chan->scan_type.realbits);
|
||||
GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regulator_get_voltage(st->vref);
|
||||
@ -333,6 +302,7 @@ static const unsigned int ad7998_frequencies[] = {
|
||||
[AD7998_CYC_TCONF_1024] = 488,
|
||||
[AD7998_CYC_TCONF_2048] = 244,
|
||||
};
|
||||
|
||||
static ssize_t ad799x_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -340,15 +310,11 @@ static ssize_t ad799x_read_frequency(struct device *dev,
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
|
||||
int ret;
|
||||
u8 val;
|
||||
ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val);
|
||||
if (ret)
|
||||
int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val &= AD7998_CYC_MASK;
|
||||
|
||||
return sprintf(buf, "%u\n", ad7998_frequencies[val]);
|
||||
return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]);
|
||||
}
|
||||
|
||||
static ssize_t ad799x_write_frequency(struct device *dev,
|
||||
@ -361,18 +327,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
|
||||
|
||||
long val;
|
||||
int ret, i;
|
||||
u8 t;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t);
|
||||
if (ret)
|
||||
ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
|
||||
if (ret < 0)
|
||||
goto error_ret_mutex;
|
||||
/* Wipe the bits clean */
|
||||
t &= ~AD7998_CYC_MASK;
|
||||
ret &= ~AD7998_CYC_MASK;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++)
|
||||
if (val == ad7998_frequencies[i])
|
||||
@ -381,13 +346,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
|
||||
ret = -EINVAL;
|
||||
goto error_ret_mutex;
|
||||
}
|
||||
t |= i;
|
||||
ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
|
||||
ret | i);
|
||||
if (ret < 0)
|
||||
goto error_ret_mutex;
|
||||
ret = len;
|
||||
|
||||
error_ret_mutex:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad799x_read_event_config(struct iio_dev *indio_dev,
|
||||
@ -395,7 +364,48 @@ static int ad799x_read_event_config(struct iio_dev *indio_dev,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
return 1;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (!(st->config & AD7998_ALERT_EN))
|
||||
return 0;
|
||||
|
||||
if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad799x_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
ret = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (state)
|
||||
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
|
||||
else
|
||||
st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT);
|
||||
|
||||
if (st->config >> AD799X_CHANNEL_SHIFT)
|
||||
st->config |= AD7998_ALERT_EN;
|
||||
else
|
||||
st->config &= ~AD7998_ALERT_EN;
|
||||
|
||||
ret = ad799x_write_config(st, st->config);
|
||||
|
||||
done:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
|
||||
@ -427,11 +437,12 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
|
||||
int ret;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (val < 0 || val > RES_MASK(chan->scan_type.realbits))
|
||||
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info),
|
||||
ret = i2c_smbus_write_word_swapped(st->client,
|
||||
ad799x_threshold_reg(chan, dir, info),
|
||||
val << chan->scan_type.shift);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
@ -447,16 +458,15 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
|
||||
{
|
||||
int ret;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
u16 valin;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info),
|
||||
&valin);
|
||||
ret = i2c_smbus_read_word_swapped(st->client,
|
||||
ad799x_threshold_reg(chan, dir, info));
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (valin >> chan->scan_type.shift) &
|
||||
RES_MASK(chan->scan_type.realbits);
|
||||
*val = (ret >> chan->scan_type.shift) &
|
||||
GENMASK(chan->scan_type.realbits - 1 , 0);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
@ -465,20 +475,18 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct ad799x_state *st = iio_priv(private);
|
||||
u8 status;
|
||||
int i, ret;
|
||||
|
||||
ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status);
|
||||
if (ret)
|
||||
ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
if (!status)
|
||||
if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
|
||||
AD7998_ALERT_STAT_CLEAR) < 0)
|
||||
goto done;
|
||||
|
||||
ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (status & (1 << i))
|
||||
if (ret & BIT(i))
|
||||
iio_push_event(indio_dev,
|
||||
i & 0x1 ?
|
||||
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
|
||||
@ -517,14 +525,21 @@ static const struct iio_info ad7991_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7993_4_7_8_info = {
|
||||
static const struct iio_info ad7993_4_7_8_noirq_info = {
|
||||
.read_raw = &ad799x_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
.update_scan_mode = ad799x_update_scan_mode,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7993_4_7_8_irq_info = {
|
||||
.read_raw = &ad799x_read_raw,
|
||||
.event_attrs = &ad799x_event_attrs_group,
|
||||
.read_event_config = &ad799x_read_event_config,
|
||||
.write_event_config = &ad799x_write_event_config,
|
||||
.read_event_value = &ad799x_read_event_value,
|
||||
.write_event_value = &ad799x_write_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
.update_scan_mode = ad7997_8_update_scan_mode,
|
||||
.update_scan_mode = ad799x_update_scan_mode,
|
||||
};
|
||||
|
||||
static const struct iio_event_spec ad799x_events[] = {
|
||||
@ -572,103 +587,175 @@ static const struct iio_event_spec ad799x_events[] = {
|
||||
|
||||
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
||||
[ad7991] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
AD799X_CHANNEL(2, 12),
|
||||
AD799X_CHANNEL(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
.info = &ad7991_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
AD799X_CHANNEL(2, 12),
|
||||
AD799X_CHANNEL(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.info = &ad7991_info,
|
||||
},
|
||||
},
|
||||
[ad7995] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10),
|
||||
AD799X_CHANNEL(1, 10),
|
||||
AD799X_CHANNEL(2, 10),
|
||||
AD799X_CHANNEL(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
.info = &ad7991_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10),
|
||||
AD799X_CHANNEL(1, 10),
|
||||
AD799X_CHANNEL(2, 10),
|
||||
AD799X_CHANNEL(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.info = &ad7991_info,
|
||||
},
|
||||
},
|
||||
[ad7999] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 8),
|
||||
AD799X_CHANNEL(1, 8),
|
||||
AD799X_CHANNEL(2, 8),
|
||||
AD799X_CHANNEL(3, 8),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
.info = &ad7991_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 8),
|
||||
AD799X_CHANNEL(1, 8),
|
||||
AD799X_CHANNEL(2, 8),
|
||||
AD799X_CHANNEL(3, 8),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.info = &ad7991_info,
|
||||
},
|
||||
},
|
||||
[ad7992] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
},
|
||||
.num_channels = 3,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
},
|
||||
.info = &ad7993_4_7_8_noirq_info,
|
||||
},
|
||||
.irq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
},
|
||||
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
|
||||
.info = &ad7993_4_7_8_irq_info,
|
||||
},
|
||||
},
|
||||
[ad7993] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10),
|
||||
AD799X_CHANNEL(1, 10),
|
||||
AD799X_CHANNEL(2, 10),
|
||||
AD799X_CHANNEL(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.info = &ad7993_4_7_8_noirq_info,
|
||||
},
|
||||
.irq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
|
||||
.info = &ad7993_4_7_8_irq_info,
|
||||
},
|
||||
},
|
||||
[ad7994] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
AD799X_CHANNEL(2, 12),
|
||||
AD799X_CHANNEL(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.info = &ad7993_4_7_8_noirq_info,
|
||||
},
|
||||
.irq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
|
||||
.info = &ad7993_4_7_8_irq_info,
|
||||
},
|
||||
},
|
||||
[ad7997] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
AD799X_CHANNEL(4, 10),
|
||||
AD799X_CHANNEL(5, 10),
|
||||
AD799X_CHANNEL(6, 10),
|
||||
AD799X_CHANNEL(7, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.num_channels = 9,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10),
|
||||
AD799X_CHANNEL(1, 10),
|
||||
AD799X_CHANNEL(2, 10),
|
||||
AD799X_CHANNEL(3, 10),
|
||||
AD799X_CHANNEL(4, 10),
|
||||
AD799X_CHANNEL(5, 10),
|
||||
AD799X_CHANNEL(6, 10),
|
||||
AD799X_CHANNEL(7, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.info = &ad7993_4_7_8_noirq_info,
|
||||
},
|
||||
.irq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
AD799X_CHANNEL(4, 10),
|
||||
AD799X_CHANNEL(5, 10),
|
||||
AD799X_CHANNEL(6, 10),
|
||||
AD799X_CHANNEL(7, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
|
||||
.info = &ad7993_4_7_8_irq_info,
|
||||
},
|
||||
},
|
||||
[ad7998] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
AD799X_CHANNEL(4, 12),
|
||||
AD799X_CHANNEL(5, 12),
|
||||
AD799X_CHANNEL(6, 12),
|
||||
AD799X_CHANNEL(7, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.num_channels = 9,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
.noirq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
AD799X_CHANNEL(2, 12),
|
||||
AD799X_CHANNEL(3, 12),
|
||||
AD799X_CHANNEL(4, 12),
|
||||
AD799X_CHANNEL(5, 12),
|
||||
AD799X_CHANNEL(6, 12),
|
||||
AD799X_CHANNEL(7, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.info = &ad7993_4_7_8_noirq_info,
|
||||
},
|
||||
.irq_config = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
AD799X_CHANNEL(4, 12),
|
||||
AD799X_CHANNEL(5, 12),
|
||||
AD799X_CHANNEL(6, 12),
|
||||
AD799X_CHANNEL(7, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
|
||||
.info = &ad7993_4_7_8_irq_info,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -678,6 +765,8 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
int ret;
|
||||
struct ad799x_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
const struct ad799x_chip_info *chip_info =
|
||||
&ad799x_chip_info_tbl[id->driver_data];
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
|
||||
if (indio_dev == NULL)
|
||||
@ -688,8 +777,10 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
st->id = id->driver_data;
|
||||
st->chip_info = &ad799x_chip_info_tbl[st->id];
|
||||
st->config = st->chip_info->default_config;
|
||||
if (client->irq > 0 && chip_info->irq_config.info)
|
||||
st->chip_config = &chip_info->irq_config;
|
||||
else
|
||||
st->chip_config = &chip_info->noirq_config;
|
||||
|
||||
/* TODO: Add pdata options for filtering and bit delay */
|
||||
|
||||
@ -712,11 +803,19 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->info = st->chip_info->info;
|
||||
indio_dev->info = st->chip_config->info;
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->chip_info->channel;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
indio_dev->channels = st->chip_config->channel;
|
||||
indio_dev->num_channels = chip_info->num_channels;
|
||||
|
||||
ret = ad799x_write_config(st, st->chip_config->default_config);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
ret = ad799x_read_config(st);
|
||||
if (ret < 0)
|
||||
goto error_disable_reg;
|
||||
st->config = ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
&ad799x_trigger_handler, NULL);
|
||||
|
@ -410,7 +410,7 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
|
||||
complete(&sigma_delta->completion);
|
||||
disable_irq_nosync(irq);
|
||||
sigma_delta->irq_dis = true;
|
||||
iio_trigger_poll(sigma_delta->trig, iio_get_time_ns());
|
||||
iio_trigger_poll(sigma_delta->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
|
||||
|
||||
if (iio_buffer_enabled(idev)) {
|
||||
disable_irq_nosync(irq);
|
||||
iio_trigger_poll(idev->trig, iio_get_time_ns());
|
||||
iio_trigger_poll(idev->trig);
|
||||
} else {
|
||||
st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
|
||||
st->done = true;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
@ -39,11 +40,6 @@
|
||||
#include <linux/iio/machine.h>
|
||||
#include <linux/iio/driver.h>
|
||||
|
||||
enum adc_version {
|
||||
ADC_V1,
|
||||
ADC_V2
|
||||
};
|
||||
|
||||
/* EXYNOS4412/5250 ADC_V1 registers definitions */
|
||||
#define ADC_V1_CON(x) ((x) + 0x00)
|
||||
#define ADC_V1_DLY(x) ((x) + 0x08)
|
||||
@ -75,8 +71,9 @@ enum adc_version {
|
||||
#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
|
||||
#define ADC_V2_CON2_ACH_MASK 0xF
|
||||
|
||||
#define MAX_ADC_V2_CHANNELS 10
|
||||
#define MAX_ADC_V1_CHANNELS 8
|
||||
#define MAX_ADC_V2_CHANNELS 10
|
||||
#define MAX_ADC_V1_CHANNELS 8
|
||||
#define MAX_EXYNOS3250_ADC_CHANNELS 2
|
||||
|
||||
/* Bit definitions common for ADC_V1 and ADC_V2 */
|
||||
#define ADC_CON_EN_START (1u << 0)
|
||||
@ -85,9 +82,12 @@ enum adc_version {
|
||||
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
|
||||
|
||||
struct exynos_adc {
|
||||
struct exynos_adc_data *data;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
void __iomem *enable_reg;
|
||||
struct clk *clk;
|
||||
struct clk *sclk;
|
||||
unsigned int irq;
|
||||
struct regulator *vdd;
|
||||
|
||||
@ -97,43 +97,213 @@ struct exynos_adc {
|
||||
unsigned int version;
|
||||
};
|
||||
|
||||
struct exynos_adc_data {
|
||||
int num_channels;
|
||||
bool needs_sclk;
|
||||
|
||||
void (*init_hw)(struct exynos_adc *info);
|
||||
void (*exit_hw)(struct exynos_adc *info);
|
||||
void (*clear_irq)(struct exynos_adc *info);
|
||||
void (*start_conv)(struct exynos_adc *info, unsigned long addr);
|
||||
};
|
||||
|
||||
static void exynos_adc_unprepare_clk(struct exynos_adc *info)
|
||||
{
|
||||
if (info->data->needs_sclk)
|
||||
clk_unprepare(info->sclk);
|
||||
clk_unprepare(info->clk);
|
||||
}
|
||||
|
||||
static int exynos_adc_prepare_clk(struct exynos_adc *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare(info->clk);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (info->data->needs_sclk) {
|
||||
ret = clk_prepare(info->sclk);
|
||||
if (ret) {
|
||||
clk_unprepare(info->clk);
|
||||
dev_err(info->dev,
|
||||
"failed preparing sclk_adc clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_adc_disable_clk(struct exynos_adc *info)
|
||||
{
|
||||
if (info->data->needs_sclk)
|
||||
clk_disable(info->sclk);
|
||||
clk_disable(info->clk);
|
||||
}
|
||||
|
||||
static int exynos_adc_enable_clk(struct exynos_adc *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(info->clk);
|
||||
if (ret) {
|
||||
dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (info->data->needs_sclk) {
|
||||
ret = clk_enable(info->sclk);
|
||||
if (ret) {
|
||||
clk_disable(info->clk);
|
||||
dev_err(info->dev,
|
||||
"failed enabling sclk_adc clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_adc_v1_init_hw(struct exynos_adc *info)
|
||||
{
|
||||
u32 con1;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
|
||||
/* set default prescaler values and Enable prescaler */
|
||||
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
|
||||
|
||||
/* Enable 12-bit ADC resolution */
|
||||
con1 |= ADC_V1_CON_RES;
|
||||
writel(con1, ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
|
||||
{
|
||||
u32 con;
|
||||
|
||||
writel(0, info->enable_reg);
|
||||
|
||||
con = readl(ADC_V1_CON(info->regs));
|
||||
con |= ADC_V1_CON_STANDBY;
|
||||
writel(con, ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
|
||||
{
|
||||
writel(1, ADC_V1_INTCLR(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v1_start_conv(struct exynos_adc *info,
|
||||
unsigned long addr)
|
||||
{
|
||||
u32 con1;
|
||||
|
||||
writel(addr, ADC_V1_MUX(info->regs));
|
||||
|
||||
con1 = readl(ADC_V1_CON(info->regs));
|
||||
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
static const struct exynos_adc_data exynos_adc_v1_data = {
|
||||
.num_channels = MAX_ADC_V1_CHANNELS,
|
||||
|
||||
.init_hw = exynos_adc_v1_init_hw,
|
||||
.exit_hw = exynos_adc_v1_exit_hw,
|
||||
.clear_irq = exynos_adc_v1_clear_irq,
|
||||
.start_conv = exynos_adc_v1_start_conv,
|
||||
};
|
||||
|
||||
static void exynos_adc_v2_init_hw(struct exynos_adc *info)
|
||||
{
|
||||
u32 con1, con2;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
|
||||
con1 = ADC_V2_CON1_SOFT_RESET;
|
||||
writel(con1, ADC_V2_CON1(info->regs));
|
||||
|
||||
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
|
||||
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(1, ADC_V2_INT_EN(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
|
||||
{
|
||||
u32 con;
|
||||
|
||||
writel(0, info->enable_reg);
|
||||
|
||||
con = readl(ADC_V2_CON1(info->regs));
|
||||
con &= ~ADC_CON_EN_START;
|
||||
writel(con, ADC_V2_CON1(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
|
||||
{
|
||||
writel(1, ADC_V2_INT_ST(info->regs));
|
||||
}
|
||||
|
||||
static void exynos_adc_v2_start_conv(struct exynos_adc *info,
|
||||
unsigned long addr)
|
||||
{
|
||||
u32 con1, con2;
|
||||
|
||||
con2 = readl(ADC_V2_CON2(info->regs));
|
||||
con2 &= ~ADC_V2_CON2_ACH_MASK;
|
||||
con2 |= ADC_V2_CON2_ACH_SEL(addr);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
con1 = readl(ADC_V2_CON1(info->regs));
|
||||
writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
|
||||
}
|
||||
|
||||
static const struct exynos_adc_data exynos_adc_v2_data = {
|
||||
.num_channels = MAX_ADC_V2_CHANNELS,
|
||||
|
||||
.init_hw = exynos_adc_v2_init_hw,
|
||||
.exit_hw = exynos_adc_v2_exit_hw,
|
||||
.clear_irq = exynos_adc_v2_clear_irq,
|
||||
.start_conv = exynos_adc_v2_start_conv,
|
||||
};
|
||||
|
||||
static const struct exynos_adc_data exynos3250_adc_data = {
|
||||
.num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
|
||||
.needs_sclk = true,
|
||||
|
||||
.init_hw = exynos_adc_v2_init_hw,
|
||||
.exit_hw = exynos_adc_v2_exit_hw,
|
||||
.clear_irq = exynos_adc_v2_clear_irq,
|
||||
.start_conv = exynos_adc_v2_start_conv,
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos_adc_match[] = {
|
||||
{ .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 },
|
||||
{ .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 },
|
||||
{
|
||||
.compatible = "samsung,exynos-adc-v1",
|
||||
.data = &exynos_adc_v1_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos-adc-v2",
|
||||
.data = &exynos_adc_v2_data,
|
||||
}, {
|
||||
.compatible = "samsung,exynos3250-adc",
|
||||
.data = &exynos3250_adc_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_adc_match);
|
||||
|
||||
static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
|
||||
static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(exynos_adc_match, pdev->dev.of_node);
|
||||
return (unsigned int)match->data;
|
||||
}
|
||||
|
||||
static void exynos_adc_hw_init(struct exynos_adc *info)
|
||||
{
|
||||
u32 con1, con2;
|
||||
|
||||
if (info->version == ADC_V2) {
|
||||
con1 = ADC_V2_CON1_SOFT_RESET;
|
||||
writel(con1, ADC_V2_CON1(info->regs));
|
||||
|
||||
con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
|
||||
ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
/* Enable interrupts */
|
||||
writel(1, ADC_V2_INT_EN(info->regs));
|
||||
} else {
|
||||
/* set default prescaler values and Enable prescaler */
|
||||
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
|
||||
|
||||
/* Enable 12-bit ADC resolution */
|
||||
con1 |= ADC_V1_CON_RES;
|
||||
writel(con1, ADC_V1_CON(info->regs));
|
||||
}
|
||||
return (struct exynos_adc_data *)match->data;
|
||||
}
|
||||
|
||||
static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct exynos_adc *info = iio_priv(indio_dev);
|
||||
unsigned long timeout;
|
||||
u32 con1, con2;
|
||||
int ret;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
|
||||
reinit_completion(&info->completion);
|
||||
|
||||
/* Select the channel to be used and Trigger conversion */
|
||||
if (info->version == ADC_V2) {
|
||||
con2 = readl(ADC_V2_CON2(info->regs));
|
||||
con2 &= ~ADC_V2_CON2_ACH_MASK;
|
||||
con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
|
||||
writel(con2, ADC_V2_CON2(info->regs));
|
||||
|
||||
con1 = readl(ADC_V2_CON1(info->regs));
|
||||
writel(con1 | ADC_CON_EN_START,
|
||||
ADC_V2_CON1(info->regs));
|
||||
} else {
|
||||
writel(chan->address, ADC_V1_MUX(info->regs));
|
||||
|
||||
con1 = readl(ADC_V1_CON(info->regs));
|
||||
writel(con1 | ADC_CON_EN_START,
|
||||
ADC_V1_CON(info->regs));
|
||||
}
|
||||
if (info->data->start_conv)
|
||||
info->data->start_conv(info, chan->address);
|
||||
|
||||
timeout = wait_for_completion_timeout
|
||||
(&info->completion, EXYNOS_ADC_TIMEOUT);
|
||||
if (timeout == 0) {
|
||||
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
|
||||
exynos_adc_hw_init(info);
|
||||
if (info->data->init_hw)
|
||||
info->data->init_hw(info);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
*val = info->value;
|
||||
@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
|
||||
struct exynos_adc *info = (struct exynos_adc *)dev_id;
|
||||
|
||||
/* Read value */
|
||||
info->value = readl(ADC_V1_DATX(info->regs)) &
|
||||
ADC_DATX_MASK;
|
||||
info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
|
||||
|
||||
/* clear irq */
|
||||
if (info->version == ADC_V2)
|
||||
writel(1, ADC_V2_INT_ST(info->regs));
|
||||
else
|
||||
writel(1, ADC_V1_INTCLR(info->regs));
|
||||
if (info->data->clear_irq)
|
||||
info->data->clear_irq(info);
|
||||
|
||||
complete(&info->completion);
|
||||
|
||||
@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
|
||||
info->data = exynos_adc_get_data(pdev);
|
||||
if (!info->data) {
|
||||
dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
info->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(info->regs))
|
||||
@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
info->irq = irq;
|
||||
info->dev = &pdev->dev;
|
||||
|
||||
init_completion(&info->completion);
|
||||
|
||||
@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
|
||||
if (info->data->needs_sclk) {
|
||||
info->sclk = devm_clk_get(&pdev->dev, "sclk");
|
||||
if (IS_ERR(info->sclk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed getting sclk clock, err = %ld\n",
|
||||
PTR_ERR(info->sclk));
|
||||
return PTR_ERR(info->sclk);
|
||||
}
|
||||
}
|
||||
|
||||
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
|
||||
if (IS_ERR(info->vdd)) {
|
||||
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
|
||||
@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
ret = exynos_adc_prepare_clk(info);
|
||||
if (ret)
|
||||
goto err_disable_reg;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
|
||||
info->version = exynos_adc_get_version(pdev);
|
||||
ret = exynos_adc_enable_clk(info);
|
||||
if (ret)
|
||||
goto err_unprepare_clk;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
indio_dev->info = &exynos_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = exynos_adc_iio_channels;
|
||||
|
||||
if (info->version == ADC_V1)
|
||||
indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
|
||||
else
|
||||
indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
|
||||
indio_dev->num_channels = info->data->num_channels;
|
||||
|
||||
ret = request_irq(info->irq, exynos_adc_isr,
|
||||
0, dev_name(&pdev->dev), info);
|
||||
@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_irq;
|
||||
|
||||
exynos_adc_hw_init(info);
|
||||
if (info->data->init_hw)
|
||||
info->data->init_hw(info);
|
||||
|
||||
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
|
||||
if (ret < 0) {
|
||||
@ -366,8 +534,11 @@ err_of_populate:
|
||||
err_irq:
|
||||
free_irq(info->irq, info);
|
||||
err_disable_clk:
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
if (info->data->exit_hw)
|
||||
info->data->exit_hw(info);
|
||||
exynos_adc_disable_clk(info);
|
||||
err_unprepare_clk:
|
||||
exynos_adc_unprepare_clk(info);
|
||||
err_disable_reg:
|
||||
regulator_disable(info->vdd);
|
||||
return ret;
|
||||
@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev)
|
||||
exynos_adc_remove_devices);
|
||||
iio_device_unregister(indio_dev);
|
||||
free_irq(info->irq, info);
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
if (info->data->exit_hw)
|
||||
info->data->exit_hw(info);
|
||||
exynos_adc_disable_clk(info);
|
||||
exynos_adc_unprepare_clk(info);
|
||||
regulator_disable(info->vdd);
|
||||
|
||||
return 0;
|
||||
@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct exynos_adc *info = iio_priv(indio_dev);
|
||||
u32 con;
|
||||
|
||||
if (info->version == ADC_V2) {
|
||||
con = readl(ADC_V2_CON1(info->regs));
|
||||
con &= ~ADC_CON_EN_START;
|
||||
writel(con, ADC_V2_CON1(info->regs));
|
||||
} else {
|
||||
con = readl(ADC_V1_CON(info->regs));
|
||||
con |= ADC_V1_CON_STANDBY;
|
||||
writel(con, ADC_V1_CON(info->regs));
|
||||
}
|
||||
|
||||
writel(0, info->enable_reg);
|
||||
clk_disable_unprepare(info->clk);
|
||||
if (info->data->exit_hw)
|
||||
info->data->exit_hw(info);
|
||||
exynos_adc_disable_clk(info);
|
||||
regulator_disable(info->vdd);
|
||||
|
||||
return 0;
|
||||
@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
ret = exynos_adc_enable_clk(info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(1, info->enable_reg);
|
||||
exynos_adc_hw_init(info);
|
||||
if (info->data->init_hw)
|
||||
info->data->init_hw(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
521
drivers/iio/adc/max1027.c
Normal file
521
drivers/iio/adc/max1027.c
Normal file
@ -0,0 +1,521 @@
|
||||
/*
|
||||
* iio/adc/max1027.c
|
||||
* Copyright (C) 2014 Philippe Reynes
|
||||
*
|
||||
* based on linux/drivers/iio/ad7923.c
|
||||
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
|
||||
* Copyright 2012 CS Systemes d'Information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* max1027.c
|
||||
*
|
||||
* Partial support for max1027 and similar chips.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define MAX1027_CONV_REG BIT(7)
|
||||
#define MAX1027_SETUP_REG BIT(6)
|
||||
#define MAX1027_AVG_REG BIT(5)
|
||||
#define MAX1027_RST_REG BIT(4)
|
||||
|
||||
/* conversion register */
|
||||
#define MAX1027_TEMP BIT(0)
|
||||
#define MAX1027_SCAN_0_N (0x00 << 1)
|
||||
#define MAX1027_SCAN_N_M (0x01 << 1)
|
||||
#define MAX1027_SCAN_N (0x02 << 1)
|
||||
#define MAX1027_NOSCAN (0x03 << 1)
|
||||
#define MAX1027_CHAN(n) ((n) << 3)
|
||||
|
||||
/* setup register */
|
||||
#define MAX1027_UNIPOLAR 0x02
|
||||
#define MAX1027_BIPOLAR 0x03
|
||||
#define MAX1027_REF_MODE0 (0x00 << 2)
|
||||
#define MAX1027_REF_MODE1 (0x01 << 2)
|
||||
#define MAX1027_REF_MODE2 (0x02 << 2)
|
||||
#define MAX1027_REF_MODE3 (0x03 << 2)
|
||||
#define MAX1027_CKS_MODE0 (0x00 << 4)
|
||||
#define MAX1027_CKS_MODE1 (0x01 << 4)
|
||||
#define MAX1027_CKS_MODE2 (0x02 << 4)
|
||||
#define MAX1027_CKS_MODE3 (0x03 << 4)
|
||||
|
||||
/* averaging register */
|
||||
#define MAX1027_NSCAN_4 0x00
|
||||
#define MAX1027_NSCAN_8 0x01
|
||||
#define MAX1027_NSCAN_12 0x02
|
||||
#define MAX1027_NSCAN_16 0x03
|
||||
#define MAX1027_NAVG_4 (0x00 << 2)
|
||||
#define MAX1027_NAVG_8 (0x01 << 2)
|
||||
#define MAX1027_NAVG_16 (0x02 << 2)
|
||||
#define MAX1027_NAVG_32 (0x03 << 2)
|
||||
#define MAX1027_AVG_EN BIT(4)
|
||||
|
||||
enum max1027_id {
|
||||
max1027,
|
||||
max1029,
|
||||
max1031,
|
||||
};
|
||||
|
||||
static const struct spi_device_id max1027_id[] = {
|
||||
{"max1027", max1027},
|
||||
{"max1029", max1029},
|
||||
{"max1031", max1031},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max1027_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id max1027_adc_dt_ids[] = {
|
||||
{ .compatible = "maxim,max1027" },
|
||||
{ .compatible = "maxim,max1029" },
|
||||
{ .compatible = "maxim,max1031" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
|
||||
#endif
|
||||
|
||||
#define MAX1027_V_CHAN(index) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = index + 1, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 10, \
|
||||
.storagebits = 16, \
|
||||
.shift = 2, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define MAX1027_T_CHAN \
|
||||
{ \
|
||||
.type = IIO_TEMP, \
|
||||
.channel = 0, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec max1027_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1029_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7),
|
||||
MAX1027_V_CHAN(8),
|
||||
MAX1027_V_CHAN(9),
|
||||
MAX1027_V_CHAN(10),
|
||||
MAX1027_V_CHAN(11)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max1031_channels[] = {
|
||||
MAX1027_T_CHAN,
|
||||
MAX1027_V_CHAN(0),
|
||||
MAX1027_V_CHAN(1),
|
||||
MAX1027_V_CHAN(2),
|
||||
MAX1027_V_CHAN(3),
|
||||
MAX1027_V_CHAN(4),
|
||||
MAX1027_V_CHAN(5),
|
||||
MAX1027_V_CHAN(6),
|
||||
MAX1027_V_CHAN(7),
|
||||
MAX1027_V_CHAN(8),
|
||||
MAX1027_V_CHAN(9),
|
||||
MAX1027_V_CHAN(10),
|
||||
MAX1027_V_CHAN(11),
|
||||
MAX1027_V_CHAN(12),
|
||||
MAX1027_V_CHAN(13),
|
||||
MAX1027_V_CHAN(14),
|
||||
MAX1027_V_CHAN(15)
|
||||
};
|
||||
|
||||
static const unsigned long max1027_available_scan_masks[] = {
|
||||
0x000001ff,
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
static const unsigned long max1029_available_scan_masks[] = {
|
||||
0x00001fff,
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
static const unsigned long max1031_available_scan_masks[] = {
|
||||
0x0001ffff,
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
struct max1027_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
const unsigned long *available_scan_masks;
|
||||
};
|
||||
|
||||
static const struct max1027_chip_info max1027_chip_info_tbl[] = {
|
||||
[max1027] = {
|
||||
.channels = max1027_channels,
|
||||
.num_channels = ARRAY_SIZE(max1027_channels),
|
||||
.available_scan_masks = max1027_available_scan_masks,
|
||||
},
|
||||
[max1029] = {
|
||||
.channels = max1029_channels,
|
||||
.num_channels = ARRAY_SIZE(max1029_channels),
|
||||
.available_scan_masks = max1029_available_scan_masks,
|
||||
},
|
||||
[max1031] = {
|
||||
.channels = max1031_channels,
|
||||
.num_channels = ARRAY_SIZE(max1031_channels),
|
||||
.available_scan_masks = max1031_available_scan_masks,
|
||||
},
|
||||
};
|
||||
|
||||
struct max1027_state {
|
||||
const struct max1027_chip_info *info;
|
||||
struct spi_device *spi;
|
||||
struct iio_trigger *trig;
|
||||
__be16 *buffer;
|
||||
struct mutex lock;
|
||||
|
||||
u8 reg ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static int max1027_read_single_value(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val)
|
||||
{
|
||||
int ret;
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
dev_warn(&indio_dev->dev, "trigger mode already enabled");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Start acquisition on conversion register write */
|
||||
st->reg = MAX1027_SETUP_REG | MAX1027_REF_MODE2 | MAX1027_CKS_MODE2;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"Failed to configure setup register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure conversion register with the requested chan */
|
||||
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) |
|
||||
MAX1027_NOSCAN | !!(chan->type == IIO_TEMP);
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"Failed to configure conversion register\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* For an unknown reason, when we use the mode "10" (write
|
||||
* conversion register), the interrupt doesn't occur every time.
|
||||
* So we just wait 1 ms.
|
||||
*/
|
||||
mdelay(1);
|
||||
|
||||
/* Read result */
|
||||
ret = spi_read(st->spi, st->buffer, (chan->type == IIO_TEMP) ? 4 : 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = be16_to_cpu(st->buffer[0]);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int max1027_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
int ret = 0;
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = max1027_read_single_value(indio_dev, chan, val);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = 1;
|
||||
*val2 = 8;
|
||||
ret = IIO_VAL_FRACTIONAL;
|
||||
break;
|
||||
case IIO_VOLTAGE:
|
||||
*val = 2500;
|
||||
*val2 = 10;
|
||||
ret = IIO_VAL_FRACTIONAL_LOG2;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned reg, unsigned writeval,
|
||||
unsigned *readval)
|
||||
{
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
u8 *val = (u8 *)st->buffer;
|
||||
|
||||
if (readval != NULL)
|
||||
return -EINVAL;
|
||||
|
||||
*val = (u8)writeval;
|
||||
return spi_write(st->spi, val, 1);
|
||||
}
|
||||
|
||||
static int max1027_validate_trigger(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig)
|
||||
{
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->trig != trig)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (state) {
|
||||
/* Start acquisition on cnvst */
|
||||
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE0 |
|
||||
MAX1027_REF_MODE2;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Scan from 0 to max */
|
||||
st->reg = MAX1027_CONV_REG | MAX1027_CHAN(0) |
|
||||
MAX1027_SCAN_N_M | MAX1027_TEMP;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
/* Start acquisition on conversion register write */
|
||||
st->reg = MAX1027_SETUP_REG | MAX1027_CKS_MODE2 |
|
||||
MAX1027_REF_MODE2;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max1027_validate_device(struct iio_trigger *trig,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
|
||||
|
||||
if (indio != indio_dev)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t max1027_trigger_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_poll_func *pf = (struct iio_poll_func *)private;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
|
||||
pr_debug("%s(irq=%d, private=0x%p)\n", __func__, irq, private);
|
||||
|
||||
/* fill buffer with all channel */
|
||||
spi_read(st->spi, st->buffer, indio_dev->masklength * 2);
|
||||
|
||||
iio_push_to_buffers(indio_dev, st->buffer);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops max1027_trigger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.validate_device = &max1027_validate_device,
|
||||
.set_trigger_state = &max1027_set_trigger_state,
|
||||
};
|
||||
|
||||
static const struct iio_info max1027_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &max1027_read_raw,
|
||||
.validate_trigger = &max1027_validate_trigger,
|
||||
.debugfs_reg_access = &max1027_debugfs_reg_access,
|
||||
};
|
||||
|
||||
static int max1027_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct iio_dev *indio_dev;
|
||||
struct max1027_state *st;
|
||||
|
||||
pr_debug("%s: probe(spi = 0x%p)\n", __func__, spi);
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (indio_dev == NULL) {
|
||||
pr_err("Can't allocate iio device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->spi = spi;
|
||||
st->info = &max1027_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &max1027_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->info->channels;
|
||||
indio_dev->num_channels = st->info->num_channels;
|
||||
indio_dev->available_scan_masks = st->info->available_scan_masks;
|
||||
|
||||
st->buffer = devm_kmalloc(&indio_dev->dev,
|
||||
indio_dev->num_channels * 2,
|
||||
GFP_KERNEL);
|
||||
if (st->buffer == NULL) {
|
||||
dev_err(&indio_dev->dev, "Can't allocate bufffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
|
||||
&max1027_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
|
||||
indio_dev->name);
|
||||
if (st->trig == NULL) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
|
||||
goto fail_trigger_alloc;
|
||||
}
|
||||
|
||||
st->trig->ops = &max1027_trigger_ops;
|
||||
st->trig->dev.parent = &spi->dev;
|
||||
iio_trigger_set_drvdata(st->trig, indio_dev);
|
||||
iio_trigger_register(st->trig);
|
||||
|
||||
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
NULL,
|
||||
IRQF_TRIGGER_FALLING,
|
||||
spi->dev.driver->name, st->trig);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
|
||||
goto fail_dev_register;
|
||||
}
|
||||
|
||||
/* Disable averaging */
|
||||
st->reg = MAX1027_AVG_REG;
|
||||
ret = spi_write(st->spi, &st->reg, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to configure averaging register\n");
|
||||
goto fail_dev_register;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed to register iio device\n");
|
||||
goto fail_dev_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_dev_register:
|
||||
fail_trigger_alloc:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max1027_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
|
||||
pr_debug("%s: remove(spi = 0x%p)\n", __func__, spi);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver max1027_driver = {
|
||||
.driver = {
|
||||
.name = "max1027",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = max1027_probe,
|
||||
.remove = max1027_remove,
|
||||
.id_table = max1027_id,
|
||||
};
|
||||
module_spi_driver(max1027_driver);
|
||||
|
||||
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
|
||||
MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -486,7 +486,7 @@ static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid)
|
||||
return IRQ_NONE;
|
||||
|
||||
if ((status & XADC_AXI_INT_EOS) && xadc->trigger)
|
||||
iio_trigger_poll(xadc->trigger, 0);
|
||||
iio_trigger_poll(xadc->trigger);
|
||||
|
||||
if (status & XADC_AXI_INT_ALARM_MASK) {
|
||||
/*
|
||||
|
@ -31,17 +31,11 @@ static const struct iio_chan_spec *xadc_event_to_channel(
|
||||
static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
|
||||
{
|
||||
const struct iio_chan_spec *chan;
|
||||
unsigned int offset;
|
||||
|
||||
/* Temperature threshold error, we don't handle this yet */
|
||||
if (event == 0)
|
||||
return;
|
||||
|
||||
if (event < 4)
|
||||
offset = event;
|
||||
else
|
||||
offset = event + 4;
|
||||
|
||||
chan = xadc_event_to_channel(indio_dev, event);
|
||||
|
||||
if (chan->type == IIO_TEMP) {
|
||||
|
@ -26,12 +26,12 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
struct {
|
||||
static struct {
|
||||
u32 usage_id;
|
||||
int unit; /* 0 for default others from HID sensor spec */
|
||||
int scale_val0; /* scale, whole number */
|
||||
int scale_val1; /* scale, fraction in micros */
|
||||
} static unit_conversion[] = {
|
||||
} unit_conversion[] = {
|
||||
{HID_USAGE_SENSOR_ACCEL_3D, 0, 9, 806650},
|
||||
{HID_USAGE_SENSOR_ACCEL_3D,
|
||||
HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
|
||||
@ -343,6 +343,7 @@ int hid_sensor_format_scale(u32 usage_id,
|
||||
}
|
||||
EXPORT_SYMBOL(hid_sensor_format_scale);
|
||||
|
||||
static
|
||||
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
struct hid_sensor_common *st)
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
||||
|
||||
@ -265,14 +265,47 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
|
||||
struct st_sensors_platform_data *defdata)
|
||||
{
|
||||
struct st_sensors_platform_data *pdata;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 val;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
|
||||
pdata->drdy_int_pin = (u8) val;
|
||||
else
|
||||
pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 1;
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
|
||||
struct st_sensors_platform_data *defdata)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
||||
struct st_sensors_platform_data *pdata)
|
||||
{
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
struct st_sensors_platform_data *of_pdata;
|
||||
int err = 0;
|
||||
|
||||
mutex_init(&sdata->tb.buf_lock);
|
||||
|
||||
/* If OF/DT pdata exists, it will take precedence of anything else */
|
||||
of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
|
||||
if (of_pdata)
|
||||
pdata = of_pdata;
|
||||
|
||||
if (pdata)
|
||||
err = st_sensors_set_drdy_int_pin(indio_dev, pdata);
|
||||
|
||||
@ -463,35 +496,6 @@ read_wai_error:
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_check_device_support);
|
||||
|
||||
ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
return sprintf(buf, "%d\n", adata->odr);
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
|
||||
|
||||
ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
int err;
|
||||
unsigned int odr;
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
|
||||
err = kstrtoint(buf, 10, &odr);
|
||||
if (err < 0)
|
||||
goto conversion_error;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
err = st_sensors_set_odr(indio_dev, odr);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
conversion_error:
|
||||
return err < 0 ? err : size;
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
|
||||
|
||||
ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
|
||||
@ -76,6 +77,35 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_i2c_configure);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* st_sensors_of_i2c_probe() - device tree probe for ST I2C sensors
|
||||
* @client: the I2C client device for the sensor
|
||||
* @match: the OF match table for the device, containing compatible strings
|
||||
* but also a .data field with the corresponding internal kernel name
|
||||
* used by this sensor.
|
||||
*
|
||||
* In effect this function matches a compatible string to an internal kernel
|
||||
* name for a certain sensor device, so that the rest of the autodetection can
|
||||
* rely on that name from this point on. I2C client devices will be renamed
|
||||
* to match the internal kernel convention.
|
||||
*/
|
||||
void st_sensors_of_i2c_probe(struct i2c_client *client,
|
||||
const struct of_device_id *match)
|
||||
{
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(match, &client->dev);
|
||||
if (!of_id)
|
||||
return;
|
||||
|
||||
/* The name from the OF match takes precedence if present */
|
||||
strncpy(client->name, of_id->data, sizeof(client->name));
|
||||
client->name[sizeof(client->name) - 1] = '\0';
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_of_i2c_probe);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
|
||||
MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -163,4 +163,14 @@ config MCP4725
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mcp4725.
|
||||
|
||||
config MCP4922
|
||||
tristate "MCP4902, MCP4912, MCP4922 DAC driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build the driver for the Microchip MCP4902
|
||||
MCP4912, and MCP4922 DAC devices.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mcp4922.
|
||||
|
||||
endmenu
|
||||
|
@ -18,3 +18,4 @@ obj-$(CONFIG_AD5686) += ad5686.o
|
||||
obj-$(CONFIG_AD7303) += ad7303.o
|
||||
obj-$(CONFIG_MAX517) += max517.o
|
||||
obj-$(CONFIG_MCP4725) += mcp4725.o
|
||||
obj-$(CONFIG_MCP4922) += mcp4922.o
|
||||
|
@ -15,17 +15,16 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/dac/ad5504.h>
|
||||
|
||||
#define AD5505_BITS 12
|
||||
#define AD5504_RES_MASK ((1 << (AD5505_BITS)) - 1)
|
||||
|
||||
#define AD5504_CMD_READ (1 << 15)
|
||||
#define AD5504_CMD_WRITE (0 << 15)
|
||||
#define AD5504_RES_MASK GENMASK(11, 0)
|
||||
#define AD5504_CMD_READ BIT(15)
|
||||
#define AD5504_CMD_WRITE 0
|
||||
#define AD5504_ADDR(addr) ((addr) << 12)
|
||||
|
||||
/* Registers */
|
||||
@ -42,7 +41,7 @@
|
||||
|
||||
/**
|
||||
* struct ad5446_state - driver instance specific data
|
||||
* @us: spi_device
|
||||
* @spi: spi_device
|
||||
* @reg: supply regulator
|
||||
* @vref_mv: actual reference voltage used
|
||||
* @pwr_down_mask power down mask
|
||||
@ -126,7 +125,6 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
|
||||
long mask)
|
||||
{
|
||||
struct ad5504_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
@ -135,10 +133,8 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
return ad5504_spi_write(st, chan->address, val);
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const char * const ad5504_powerdown_modes[] = {
|
||||
|
@ -67,7 +67,6 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
|
||||
long mask)
|
||||
{
|
||||
struct ad5624r_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
@ -79,10 +78,8 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
|
||||
chan->address, val,
|
||||
chan->scan_type.shift);
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const char * const ad5624r_powerdown_modes[] = {
|
||||
|
@ -313,7 +313,7 @@ static int ad5686_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad5686_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret, regdone = 0, voltage_uv = 0;
|
||||
int ret, voltage_uv = 0;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (indio_dev == NULL)
|
||||
@ -355,7 +355,6 @@ static int ad5686_probe(struct spi_device *spi)
|
||||
indio_dev->channels = st->chip_info->channel;
|
||||
indio_dev->num_channels = AD5686_DAC_CHANNELS;
|
||||
|
||||
regdone = 1;
|
||||
ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
|
||||
!!voltage_uv, 0);
|
||||
if (ret)
|
||||
|
@ -16,17 +16,16 @@
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/dac/ad5791.h>
|
||||
|
||||
#define AD5791_RES_MASK(x) ((1 << (x)) - 1)
|
||||
#define AD5791_DAC_MASK AD5791_RES_MASK(20)
|
||||
#define AD5791_DAC_MSB (1 << 19)
|
||||
#define AD5791_DAC_MASK GENMASK(19, 0)
|
||||
|
||||
#define AD5791_CMD_READ (1 << 23)
|
||||
#define AD5791_CMD_WRITE (0 << 23)
|
||||
#define AD5791_CMD_READ BIT(23)
|
||||
#define AD5791_CMD_WRITE 0
|
||||
#define AD5791_ADDR(addr) ((addr) << 20)
|
||||
|
||||
/* Registers */
|
||||
@ -37,11 +36,11 @@
|
||||
#define AD5791_ADDR_SW_CTRL 4
|
||||
|
||||
/* Control Register */
|
||||
#define AD5791_CTRL_RBUF (1 << 1)
|
||||
#define AD5791_CTRL_OPGND (1 << 2)
|
||||
#define AD5791_CTRL_DACTRI (1 << 3)
|
||||
#define AD5791_CTRL_BIN2SC (1 << 4)
|
||||
#define AD5791_CTRL_SDODIS (1 << 5)
|
||||
#define AD5791_CTRL_RBUF BIT(1)
|
||||
#define AD5791_CTRL_OPGND BIT(2)
|
||||
#define AD5791_CTRL_DACTRI BIT(3)
|
||||
#define AD5791_CTRL_BIN2SC BIT(4)
|
||||
#define AD5791_CTRL_SDODIS BIT(5)
|
||||
#define AD5761_CTRL_LINCOMP(x) ((x) << 6)
|
||||
|
||||
#define AD5791_LINCOMP_0_10 0
|
||||
@ -54,9 +53,9 @@
|
||||
#define AD5780_LINCOMP_10_20 12
|
||||
|
||||
/* Software Control Register */
|
||||
#define AD5791_SWCTRL_LDAC (1 << 0)
|
||||
#define AD5791_SWCTRL_CLR (1 << 1)
|
||||
#define AD5791_SWCTRL_RESET (1 << 2)
|
||||
#define AD5791_SWCTRL_LDAC BIT(0)
|
||||
#define AD5791_SWCTRL_CLR BIT(1)
|
||||
#define AD5791_SWCTRL_RESET BIT(2)
|
||||
|
||||
#define AD5791_DAC_PWRDN_6K 0
|
||||
#define AD5791_DAC_PWRDN_3STATE 1
|
||||
@ -72,7 +71,7 @@ struct ad5791_chip_info {
|
||||
|
||||
/**
|
||||
* struct ad5791_state - driver instance specific data
|
||||
* @us: spi_device
|
||||
* @spi: spi_device
|
||||
* @reg_vdd: positive supply regulator
|
||||
* @reg_vss: negative supply regulator
|
||||
* @chip_info: chip model specific constants
|
||||
@ -328,7 +327,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
val &= AD5791_RES_MASK(chan->scan_type.realbits);
|
||||
val &= GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
val <<= chan->scan_type.shift;
|
||||
|
||||
return ad5791_spi_write(st, chan->address, val);
|
||||
|
216
drivers/iio/dac/mcp4922.c
Normal file
216
drivers/iio/dac/mcp4922.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* mcp4922.c
|
||||
*
|
||||
* Driver for Microchip Digital to Analog Converters.
|
||||
* Supports MCP4902, MCP4912, and MCP4922.
|
||||
*
|
||||
* Copyright (c) 2014 EMAC Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define MCP4922_NUM_CHANNELS 2
|
||||
|
||||
enum mcp4922_supported_device_ids {
|
||||
ID_MCP4902,
|
||||
ID_MCP4912,
|
||||
ID_MCP4922,
|
||||
};
|
||||
|
||||
struct mcp4922_state {
|
||||
struct spi_device *spi;
|
||||
unsigned int value[MCP4922_NUM_CHANNELS];
|
||||
unsigned int vref_mv;
|
||||
struct regulator *vref_reg;
|
||||
u8 mosi[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#define MCP4922_CHAN(chan, bits) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = (bits), \
|
||||
.storagebits = 16, \
|
||||
.shift = 12 - (bits), \
|
||||
}, \
|
||||
}
|
||||
|
||||
static int mcp4922_spi_write(struct mcp4922_state *state, u8 addr, u32 val)
|
||||
{
|
||||
state->mosi[1] = val & 0xff;
|
||||
state->mosi[0] = (addr == 0) ? 0x00 : 0x80;
|
||||
state->mosi[0] |= 0x30 | ((val >> 8) & 0x0f);
|
||||
|
||||
return spi_write(state->spi, state->mosi, 2);
|
||||
}
|
||||
|
||||
static int mcp4922_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct mcp4922_state *state = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = state->value[chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = state->vref_mv;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp4922_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct mcp4922_state *state = iio_priv(indio_dev);
|
||||
|
||||
if (val2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val > GENMASK(chan->scan_type.realbits-1, 0))
|
||||
return -EINVAL;
|
||||
val <<= chan->scan_type.shift;
|
||||
state->value[chan->channel] = val;
|
||||
return mcp4922_spi_write(state, chan->channel, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mcp4922_channels[3][MCP4922_NUM_CHANNELS] = {
|
||||
[ID_MCP4902] = { MCP4922_CHAN(0, 8), MCP4922_CHAN(1, 8) },
|
||||
[ID_MCP4912] = { MCP4922_CHAN(0, 10), MCP4922_CHAN(1, 10) },
|
||||
[ID_MCP4922] = { MCP4922_CHAN(0, 12), MCP4922_CHAN(1, 12) },
|
||||
};
|
||||
|
||||
static const struct iio_info mcp4922_info = {
|
||||
.read_raw = &mcp4922_read_raw,
|
||||
.write_raw = &mcp4922_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mcp4922_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct mcp4922_state *state;
|
||||
const struct spi_device_id *id;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
state = iio_priv(indio_dev);
|
||||
state->spi = spi;
|
||||
state->vref_reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(state->vref_reg)) {
|
||||
dev_err(&spi->dev, "Vref regulator not specified\n");
|
||||
return PTR_ERR(state->vref_reg);
|
||||
}
|
||||
|
||||
ret = regulator_enable(state->vref_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable vref regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(state->vref_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read vref regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
state->vref_mv = ret / 1000;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
id = spi_get_device_id(spi);
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &mcp4922_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = mcp4922_channels[id->driver_data];
|
||||
indio_dev->num_channels = MCP4922_NUM_CHANNELS;
|
||||
indio_dev->name = id->name;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to register iio device: %d\n",
|
||||
ret);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_reg:
|
||||
regulator_disable(state->vref_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mcp4922_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct mcp4922_state *state;
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
state = iio_priv(indio_dev);
|
||||
regulator_disable(state->vref_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id mcp4922_id[] = {
|
||||
{"mcp4902", ID_MCP4902},
|
||||
{"mcp4912", ID_MCP4912},
|
||||
{"mcp4922", ID_MCP4922},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mcp4922_id);
|
||||
|
||||
static struct spi_driver mcp4922_driver = {
|
||||
.driver = {
|
||||
.name = "mcp4922",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mcp4922_probe,
|
||||
.remove = mcp4922_remove,
|
||||
.id_table = mcp4922_id,
|
||||
};
|
||||
module_spi_driver(mcp4922_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
|
||||
MODULE_DESCRIPTION("Microchip MCP4902, MCP4912, MCP4922 DAC");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -101,65 +101,6 @@
|
||||
#define ADIS16260_SCAN_TEMP 3
|
||||
#define ADIS16260_SCAN_ANGL 4
|
||||
|
||||
static ssize_t adis16260_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
int ret, len = 0;
|
||||
u16 t;
|
||||
int sps;
|
||||
ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi_get_device_id(adis->spi)->driver_data) /* If an adis16251 */
|
||||
sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 8 : 256;
|
||||
else
|
||||
sps = (t & ADIS16260_SMPL_PRD_TIME_BASE) ? 66 : 2048;
|
||||
sps /= (t & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
|
||||
len = sprintf(buf, "%d\n", sps);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t adis16260_write_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
u8 t;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (spi_get_device_id(adis->spi)->driver_data)
|
||||
t = 256 / val;
|
||||
else
|
||||
t = 2048 / val;
|
||||
|
||||
if (t > ADIS16260_SMPL_PRD_DIV_MASK)
|
||||
t = ADIS16260_SMPL_PRD_DIV_MASK;
|
||||
else if (t > 0)
|
||||
t--;
|
||||
|
||||
if (t >= 0x0A)
|
||||
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
|
||||
else
|
||||
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
|
||||
ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
/* Power down the device */
|
||||
static int adis16260_stop_device(struct iio_dev *indio_dev)
|
||||
{
|
||||
@ -174,18 +115,19 @@ static int adis16260_stop_device(struct iio_dev *indio_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
adis16260_read_frequency,
|
||||
adis16260_write_frequency);
|
||||
|
||||
static const struct iio_chan_spec adis16260_channels[] = {
|
||||
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE), 14),
|
||||
ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14),
|
||||
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12),
|
||||
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12),
|
||||
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, 12),
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE),
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
|
||||
ADIS_INCLI_CHAN(X, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
|
||||
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(5),
|
||||
};
|
||||
|
||||
@ -258,6 +200,20 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
*val = val16;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = adis_read_reg_16(adis, ADIS16260_SMPL_PRD, &val16);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi_get_device_id(adis->spi)->driver_data)
|
||||
/* If an adis16251 */
|
||||
*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?
|
||||
8 : 256;
|
||||
else
|
||||
*val = (val16 & ADIS16260_SMPL_PRD_TIME_BASE) ?
|
||||
66 : 2048;
|
||||
*val /= (val16 & ADIS16260_SMPL_PRD_DIV_MASK) + 1;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -269,7 +225,9 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
|
||||
long mask)
|
||||
{
|
||||
struct adis *adis = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 addr;
|
||||
u8 t;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
@ -284,21 +242,31 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
addr = adis16260_addresses[chan->scan_index][1];
|
||||
return adis_write_reg_16(adis, addr, val);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (spi_get_device_id(adis->spi)->driver_data)
|
||||
t = 256 / val;
|
||||
else
|
||||
t = 2048 / val;
|
||||
|
||||
if (t > ADIS16260_SMPL_PRD_DIV_MASK)
|
||||
t = ADIS16260_SMPL_PRD_DIV_MASK;
|
||||
else if (t > 0)
|
||||
t--;
|
||||
|
||||
if (t >= 0x0A)
|
||||
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
|
||||
else
|
||||
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
|
||||
ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct attribute *adis16260_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adis16260_attribute_group = {
|
||||
.attrs = adis16260_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info adis16260_info = {
|
||||
.attrs = &adis16260_attribute_group,
|
||||
.read_raw = &adis16260_read_raw,
|
||||
.write_raw = &adis16260_write_raw,
|
||||
.update_scan_mode = adis_update_scan_mode,
|
||||
|
@ -90,6 +90,7 @@ static int itg3200_read_raw(struct iio_dev *indio_dev,
|
||||
{
|
||||
int ret = 0;
|
||||
u8 reg;
|
||||
u8 regval;
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
@ -107,65 +108,60 @@ static int itg3200_read_raw(struct iio_dev *indio_dev,
|
||||
/* Only the temperature channel has an offset */
|
||||
*val = 23000;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = (regval & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
|
||||
|
||||
ret = itg3200_read_reg_8(indio_dev,
|
||||
ITG3200_REG_SAMPLE_RATE_DIV,
|
||||
®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val /= regval + 1;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t itg3200_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static int itg3200_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
int ret, sps;
|
||||
u8 val;
|
||||
|
||||
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sps = (val & ITG3200_DLPF_CFG_MASK) ? 1000 : 8000;
|
||||
|
||||
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sps /= val + 1;
|
||||
|
||||
return sprintf(buf, "%d\n", sps);
|
||||
}
|
||||
|
||||
static ssize_t itg3200_write_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
unsigned val;
|
||||
int ret;
|
||||
u8 t;
|
||||
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val == 0 || val2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
|
||||
if (ret)
|
||||
goto err_ret;
|
||||
ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_DLPF, &t);
|
||||
if (ret) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
|
||||
|
||||
if (val == 0) {
|
||||
ret = -EINVAL;
|
||||
goto err_ret;
|
||||
ret = itg3200_write_reg_8(indio_dev,
|
||||
ITG3200_REG_SAMPLE_RATE_DIV,
|
||||
t);
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
t = ((t & ITG3200_DLPF_CFG_MASK) ? 1000u : 8000u) / val - 1;
|
||||
|
||||
ret = itg3200_write_reg_8(indio_dev, ITG3200_REG_SAMPLE_RATE_DIV, t);
|
||||
|
||||
err_ret:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -255,6 +251,7 @@ err_ret:
|
||||
.channel2 = IIO_MOD_ ## _mod, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
|
||||
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
|
||||
.scan_type = ITG3200_ST, \
|
||||
@ -267,6 +264,7 @@ static const struct iio_chan_spec itg3200_channels[] = {
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.address = ITG3200_REG_TEMP_OUT_H,
|
||||
.scan_index = ITG3200_SCAN_TEMP,
|
||||
.scan_type = ITG3200_ST,
|
||||
@ -277,22 +275,9 @@ static const struct iio_chan_spec itg3200_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(ITG3200_SCAN_ELEMENTS),
|
||||
};
|
||||
|
||||
/* IIO device attributes */
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, itg3200_read_frequency,
|
||||
itg3200_write_frequency);
|
||||
|
||||
static struct attribute *itg3200_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group itg3200_attribute_group = {
|
||||
.attrs = itg3200_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info itg3200_info = {
|
||||
.attrs = &itg3200_attribute_group,
|
||||
.read_raw = &itg3200_read_raw,
|
||||
.write_raw = &itg3200_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -245,6 +245,9 @@ static int st_gyro_read_raw(struct iio_dev *indio_dev,
|
||||
*val = 0;
|
||||
*val2 = gdata->current_fullscale->gain;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = gdata->odr;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -262,6 +265,13 @@ static int st_gyro_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
err = st_sensors_set_odr(indio_dev, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return err;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
@ -269,14 +279,12 @@ static int st_gyro_write_raw(struct iio_dev *indio_dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
|
||||
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
|
||||
static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_anglvel_scale_available);
|
||||
|
||||
static struct attribute *st_gyro_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,43 @@
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_gyro.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st_gyro_of_match[] = {
|
||||
{
|
||||
.compatible = "st,l3g4200d-gyro",
|
||||
.data = L3G4200D_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330d-gyro",
|
||||
.data = LSM330D_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330dl-gyro",
|
||||
.data = LSM330DL_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330dlc-gyro",
|
||||
.data = LSM330DLC_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,l3gd20-gyro",
|
||||
.data = L3GD20_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,l3g4is-gyro",
|
||||
.data = L3G4IS_GYRO_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm330-gyro",
|
||||
.data = LSM330_GYRO_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
|
||||
#else
|
||||
#define st_gyro_of_match NULL
|
||||
#endif
|
||||
|
||||
static int st_gyro_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -31,6 +68,7 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
|
||||
|
||||
gdata = iio_priv(indio_dev);
|
||||
gdata->dev = &client->dev;
|
||||
st_sensors_of_i2c_probe(client, st_gyro_of_match);
|
||||
|
||||
st_sensors_i2c_configure(indio_dev, client, gdata);
|
||||
|
||||
@ -65,6 +103,7 @@ static struct i2c_driver st_gyro_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-gyro-i2c",
|
||||
.of_match_table = of_match_ptr(st_gyro_of_match),
|
||||
},
|
||||
.probe = st_gyro_i2c_probe,
|
||||
.remove = st_gyro_i2c_remove,
|
||||
|
@ -18,7 +18,7 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
struct adis *adis = &st->adis;
|
||||
uint16_t *tx, *rx;
|
||||
uint16_t *tx;
|
||||
|
||||
if (st->variant->flags & ADIS16400_NO_BURST)
|
||||
return adis_update_scan_mode(indio_dev, scan_mask);
|
||||
@ -35,7 +35,6 @@ int adis16400_update_scan_mode(struct iio_dev *indio_dev,
|
||||
if (!adis->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
rx = adis->buffer;
|
||||
tx = adis->buffer + indio_dev->scan_bytes;
|
||||
|
||||
tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
|
||||
|
@ -214,21 +214,6 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
|
||||
return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
|
||||
}
|
||||
|
||||
static ssize_t adis16400_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = st->variant->get_freq(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d.%.3d\n", ret / 1000, ret % 1000);
|
||||
}
|
||||
|
||||
static const unsigned adis16400_3db_divisors[] = {
|
||||
[0] = 2, /* Special case */
|
||||
[1] = 6,
|
||||
@ -260,30 +245,6 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t adis16400_write_frequency(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis16400_state *st = iio_priv(indio_dev);
|
||||
int i, f, val;
|
||||
int ret;
|
||||
|
||||
ret = iio_str_to_fixpoint(buf, 100, &i, &f);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = i * 1000 + f;
|
||||
|
||||
if (val <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
st->variant->set_freq(st, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Power down the device */
|
||||
static int adis16400_stop_device(struct iio_dev *indio_dev)
|
||||
{
|
||||
@ -350,10 +311,6 @@ err_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
adis16400_read_frequency,
|
||||
adis16400_write_frequency);
|
||||
|
||||
static const uint8_t adis16400_addresses[] = {
|
||||
[ADIS16400_SCAN_GYRO_X] = ADIS16400_XGYRO_OFF,
|
||||
[ADIS16400_SCAN_GYRO_Y] = ADIS16400_YGYRO_OFF,
|
||||
@ -394,6 +351,16 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
|
||||
val * 1000 + val2 / 1000);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
sps = val * 1000 + val2 / 1000;
|
||||
|
||||
if (sps <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = st->variant->set_freq(st, sps);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -474,6 +441,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = st->variant->get_freq(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret / 1000;
|
||||
*val2 = (ret % 1000) * 1000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -486,6 +460,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
.extend_name = name, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = (si), \
|
||||
.scan_type = { \
|
||||
@ -511,6 +486,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = addr, \
|
||||
.scan_index = ADIS16400_SCAN_GYRO_ ## mod, \
|
||||
.scan_type = { \
|
||||
@ -530,6 +506,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = ADIS16400_SCAN_ACC_ ## mod, \
|
||||
.scan_type = { \
|
||||
@ -548,6 +525,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = ADIS16400_SCAN_MAGN_ ## mod, \
|
||||
.scan_type = { \
|
||||
@ -573,6 +551,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type = \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = ADIS16350_SCAN_TEMP_ ## mod, \
|
||||
.scan_type = { \
|
||||
@ -591,6 +570,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = ADIS16350_SCAN_TEMP_X, \
|
||||
.scan_type = { \
|
||||
@ -608,6 +588,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
|
||||
.channel2 = IIO_MOD_ ## mod, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (addr), \
|
||||
.scan_index = ADIS16300_SCAN_INCLI_ ## mod, \
|
||||
.scan_type = { \
|
||||
@ -649,6 +630,7 @@ static const struct iio_chan_spec adis16448_channels[] = {
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.address = ADIS16448_BARO_OUT,
|
||||
.scan_index = ADIS16400_SCAN_BARO,
|
||||
.scan_type = {
|
||||
@ -704,15 +686,6 @@ static const struct iio_chan_spec adis16334_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
|
||||
};
|
||||
|
||||
static struct attribute *adis16400_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adis16400_attribute_group = {
|
||||
.attrs = adis16400_attributes,
|
||||
};
|
||||
|
||||
static struct adis16400_chip_info adis16400_chips[] = {
|
||||
[ADIS16300] = {
|
||||
.channels = adis16300_channels,
|
||||
@ -813,7 +786,6 @@ static const struct iio_info adis16400_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &adis16400_read_raw,
|
||||
.write_raw = &adis16400_write_raw,
|
||||
.attrs = &adis16400_attribute_group,
|
||||
.update_scan_mode = adis16400_update_scan_mode,
|
||||
.debugfs_reg_access = adis_debugfs_reg_access,
|
||||
};
|
||||
|
@ -257,11 +257,16 @@ static int adis16480_debugfs_init(struct iio_dev *indio_dev)
|
||||
|
||||
#endif
|
||||
|
||||
static int adis16480_set_freq(struct adis16480 *st, unsigned int freq)
|
||||
static int adis16480_set_freq(struct iio_dev *indio_dev, int val, int val2)
|
||||
{
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
unsigned int t;
|
||||
|
||||
t = 2460000 / freq;
|
||||
t = val * 1000 + val2 / 1000;
|
||||
if (t <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
t = 2460000 / t;
|
||||
if (t > 2048)
|
||||
t = 2048;
|
||||
|
||||
@ -271,65 +276,24 @@ static int adis16480_set_freq(struct adis16480 *st, unsigned int freq)
|
||||
return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
|
||||
}
|
||||
|
||||
static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq)
|
||||
static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
|
||||
{
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
uint16_t t;
|
||||
int ret;
|
||||
unsigned freq;
|
||||
|
||||
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*freq = 2460000 / (t + 1);
|
||||
freq = 2460000 / (t + 1);
|
||||
*val = freq / 1000;
|
||||
*val2 = (freq % 1000) * 1000;
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
static ssize_t adis16480_read_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
unsigned int freq;
|
||||
int ret;
|
||||
|
||||
ret = adis16480_get_freq(st, &freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000);
|
||||
}
|
||||
|
||||
static ssize_t adis16480_write_frequency(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis16480 *st = iio_priv(indio_dev);
|
||||
int freq_int, freq_fract;
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = freq_int * 1000 + freq_fract;
|
||||
|
||||
if (val <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = adis16480_set_freq(st, val);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
adis16480_read_frequency,
|
||||
adis16480_write_frequency);
|
||||
|
||||
enum {
|
||||
ADIS16480_SCAN_GYRO_X,
|
||||
ADIS16480_SCAN_GYRO_Y,
|
||||
@ -571,6 +535,8 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
|
||||
return adis16480_get_calibscale(indio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
return adis16480_get_filter_freq(indio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return adis16480_get_freq(indio_dev, val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -586,6 +552,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
|
||||
return adis16480_set_calibscale(indio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
return adis16480_set_filter_freq(indio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return adis16480_set_freq(indio_dev, val, val2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -600,6 +569,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | \
|
||||
_info_sep, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = (_address), \
|
||||
.scan_index = (_si), \
|
||||
.scan_type = { \
|
||||
@ -638,6 +608,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = ADIS16480_REG_BAROM_OUT, \
|
||||
.scan_index = ADIS16480_SCAN_BARO, \
|
||||
.scan_type = { \
|
||||
@ -655,6 +626,7 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = ADIS16480_REG_TEMP_OUT, \
|
||||
.scan_index = ADIS16480_SCAN_TEMP, \
|
||||
.scan_type = { \
|
||||
@ -717,17 +689,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct attribute *adis16480_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adis16480_attribute_group = {
|
||||
.attrs = adis16480_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info adis16480_info = {
|
||||
.attrs = &adis16480_attribute_group,
|
||||
.read_raw = &adis16480_read_raw,
|
||||
.write_raw = &adis16480_write_raw,
|
||||
.update_scan_mode = adis_update_scan_mode,
|
||||
|
@ -39,10 +39,7 @@ static bool iio_buffer_is_active(struct iio_buffer *buf)
|
||||
|
||||
static bool iio_buffer_data_available(struct iio_buffer *buf)
|
||||
{
|
||||
if (buf->access->data_available)
|
||||
return buf->access->data_available(buf);
|
||||
|
||||
return buf->stufftoread;
|
||||
return buf->access->data_available(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,6 +87,10 @@ static const char * const iio_modifier_names[] = {
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
[IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
|
||||
[IIO_MOD_NORTH_TRUE] = "from_north_true",
|
||||
[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
|
||||
[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
|
||||
};
|
||||
|
||||
/* relies on pairs of these shared then separate */
|
||||
|
@ -209,6 +209,7 @@ static const char * const iio_ev_info_text[] = {
|
||||
[IIO_EV_INFO_ENABLE] = "en",
|
||||
[IIO_EV_INFO_VALUE] = "value",
|
||||
[IIO_EV_INFO_HYSTERESIS] = "hysteresis",
|
||||
[IIO_EV_INFO_PERIOD] = "period",
|
||||
};
|
||||
|
||||
static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
|
||||
|
@ -114,7 +114,7 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name,
|
||||
return trig;
|
||||
}
|
||||
|
||||
void iio_trigger_poll(struct iio_trigger *trig, s64 time)
|
||||
void iio_trigger_poll(struct iio_trigger *trig)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -133,12 +133,12 @@ EXPORT_SYMBOL(iio_trigger_poll);
|
||||
|
||||
irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private)
|
||||
{
|
||||
iio_trigger_poll(private, iio_get_time_ns());
|
||||
iio_trigger_poll(private);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
|
||||
|
||||
void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
|
||||
void iio_trigger_poll_chained(struct iio_trigger *trig)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -161,7 +161,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig)
|
||||
trig->ops->try_reenable)
|
||||
if (trig->ops->try_reenable(trig))
|
||||
/* Missed an interrupt so launch new poll now */
|
||||
iio_trigger_poll(trig, 0);
|
||||
iio_trigger_poll(trig);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_trigger_notify_done);
|
||||
|
||||
|
@ -62,6 +62,18 @@ config GP2AP020A00F
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gp2ap020a00f.
|
||||
|
||||
config ISL29125
|
||||
tristate "Intersil ISL29125 digital color light sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build a driver for the Intersil ISL29125
|
||||
RGB light sensor for I2C.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called isl29125.
|
||||
|
||||
config HID_SENSOR_ALS
|
||||
depends on HID_SENSOR_HUB
|
||||
select IIO_BUFFER
|
||||
@ -116,6 +128,18 @@ config LTR501
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ltr501.
|
||||
|
||||
config TCS3414
|
||||
tristate "TAOS TCS3414 digital color sensor"
|
||||
depends on I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for the TAOS TCS3414
|
||||
family of digital color sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tcs3414.
|
||||
|
||||
config TCS3472
|
||||
tristate "TAOS TCS3472 color light-to-digital converter"
|
||||
depends on I2C
|
||||
|
@ -10,9 +10,11 @@ obj-$(CONFIG_CM36651) += cm36651.o
|
||||
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
|
||||
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
|
||||
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
|
||||
obj-$(CONFIG_ISL29125) += isl29125.o
|
||||
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
|
||||
obj-$(CONFIG_LTR501) += ltr501.o
|
||||
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
|
||||
obj-$(CONFIG_TCS3414) += tcs3414.o
|
||||
obj-$(CONFIG_TCS3472) += tcs3472.o
|
||||
obj-$(CONFIG_TSL4531) += tsl4531.o
|
||||
obj-$(CONFIG_VCNL4000) += vcnl4000.o
|
||||
|
@ -331,7 +331,7 @@ static int cm32181_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_iio_device_register(&client->dev, indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"%s: regist device failed\n",
|
||||
@ -342,14 +342,6 @@ static int cm32181_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cm32181_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cm32181_id[] = {
|
||||
{ "cm32181", 0 },
|
||||
{ }
|
||||
@ -370,7 +362,6 @@ static struct i2c_driver cm32181_driver = {
|
||||
},
|
||||
.id_table = cm32181_id,
|
||||
.probe = cm32181_probe,
|
||||
.remove = cm32181_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(cm32181_driver);
|
||||
|
@ -827,7 +827,7 @@ static void gp2ap020a00f_iio_trigger_work(struct irq_work *work)
|
||||
struct gp2ap020a00f_data *data =
|
||||
container_of(work, struct gp2ap020a00f_data, work);
|
||||
|
||||
iio_trigger_poll(data->trig, 0);
|
||||
iio_trigger_poll(data->trig);
|
||||
}
|
||||
|
||||
static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
|
||||
|
347
drivers/iio/light/isl29125.c
Normal file
347
drivers/iio/light/isl29125.c
Normal file
@ -0,0 +1,347 @@
|
||||
/*
|
||||
* isl29125.c - Support for Intersil ISL29125 RGB light sensor
|
||||
*
|
||||
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* RGB light sensor with 16-bit channels for red, green, blue);
|
||||
* 7-bit I2C slave address 0x44
|
||||
*
|
||||
* TODO: interrupt support, IR compensation, thresholds, 12bit
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define ISL29125_DRV_NAME "isl29125"
|
||||
|
||||
#define ISL29125_DEVICE_ID 0x00
|
||||
#define ISL29125_CONF1 0x01
|
||||
#define ISL29125_CONF2 0x02
|
||||
#define ISL29125_CONF3 0x03
|
||||
#define ISL29125_STATUS 0x08
|
||||
#define ISL29125_GREEN_DATA 0x09
|
||||
#define ISL29125_RED_DATA 0x0b
|
||||
#define ISL29125_BLUE_DATA 0x0d
|
||||
|
||||
#define ISL29125_ID 0x7d
|
||||
|
||||
#define ISL29125_MODE_MASK GENMASK(2, 0)
|
||||
#define ISL29125_MODE_PD 0x0
|
||||
#define ISL29125_MODE_G 0x1
|
||||
#define ISL29125_MODE_R 0x2
|
||||
#define ISL29125_MODE_B 0x3
|
||||
#define ISL29125_MODE_RGB 0x5
|
||||
|
||||
#define ISL29125_MODE_RANGE BIT(3)
|
||||
|
||||
#define ISL29125_STATUS_CONV BIT(1)
|
||||
|
||||
struct isl29125_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u8 conf1;
|
||||
u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */
|
||||
};
|
||||
|
||||
#define ISL29125_CHANNEL(_color, _si) { \
|
||||
.type = IIO_INTENSITY, \
|
||||
.modified = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.channel2 = IIO_MOD_LIGHT_##_color, \
|
||||
.scan_index = _si, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec isl29125_channels[] = {
|
||||
ISL29125_CHANNEL(GREEN, 0),
|
||||
ISL29125_CHANNEL(RED, 1),
|
||||
ISL29125_CHANNEL(BLUE, 2),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static const struct {
|
||||
u8 mode, data;
|
||||
} isl29125_regs[] = {
|
||||
{ISL29125_MODE_G, ISL29125_GREEN_DATA},
|
||||
{ISL29125_MODE_R, ISL29125_RED_DATA},
|
||||
{ISL29125_MODE_B, ISL29125_BLUE_DATA},
|
||||
};
|
||||
|
||||
static int isl29125_read_data(struct isl29125_data *data, int si)
|
||||
{
|
||||
int tries = 5;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1 | isl29125_regs[si].mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
msleep(101);
|
||||
|
||||
while (tries--) {
|
||||
ret = i2c_smbus_read_byte_data(data->client, ISL29125_STATUS);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
if (ret & ISL29125_STATUS_CONV)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
if (tries < 0) {
|
||||
dev_err(&data->client->dev, "data not ready\n");
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_word_data(data->client, isl29125_regs[si].data);
|
||||
|
||||
fail:
|
||||
i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isl29125_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
mutex_lock(&data->lock);
|
||||
ret = isl29125_read_data(data, chan->scan_index);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
if (data->conf1 & ISL29125_MODE_RANGE)
|
||||
*val2 = 152590; /* 10k lux full range */
|
||||
else
|
||||
*val2 = 5722; /* 375 lux full range */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int isl29125_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
if (val2 == 152590)
|
||||
data->conf1 |= ISL29125_MODE_RANGE;
|
||||
else if (val2 == 5722)
|
||||
data->conf1 &= ~ISL29125_MODE_RANGE;
|
||||
else
|
||||
return -EINVAL;
|
||||
return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t isl29125_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct isl29125_data *data = iio_priv(indio_dev);
|
||||
int i, j = 0;
|
||||
|
||||
for_each_set_bit(i, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
int ret = i2c_smbus_read_word_data(data->client,
|
||||
isl29125_regs[i].data);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
data->buffer[j++] = ret;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info isl29125_info = {
|
||||
.read_raw = isl29125_read_raw,
|
||||
.write_raw = isl29125_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int isl29125_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(indio_dev);
|
||||
|
||||
data->conf1 |= ISL29125_MODE_RGB;
|
||||
return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1);
|
||||
}
|
||||
|
||||
static int isl29125_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = iio_triggered_buffer_predisable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->conf1 &= ~ISL29125_MODE_MASK;
|
||||
data->conf1 |= ISL29125_MODE_PD;
|
||||
return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = {
|
||||
.preenable = isl29125_buffer_preenable,
|
||||
.postenable = &iio_triggered_buffer_postenable,
|
||||
.predisable = isl29125_buffer_predisable,
|
||||
};
|
||||
|
||||
static int isl29125_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct isl29125_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &isl29125_info;
|
||||
indio_dev->name = ISL29125_DRV_NAME;
|
||||
indio_dev->channels = isl29125_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(isl29125_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, ISL29125_DEVICE_ID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != ISL29125_ID)
|
||||
return -ENODEV;
|
||||
|
||||
data->conf1 = ISL29125_MODE_PD | ISL29125_MODE_RANGE;
|
||||
ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, ISL29125_STATUS, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
isl29125_trigger_handler, &isl29125_buffer_setup_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isl29125_powerdown(struct isl29125_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
(data->conf1 & ~ISL29125_MODE_MASK) | ISL29125_MODE_PD);
|
||||
}
|
||||
|
||||
static int isl29125_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
isl29125_powerdown(iio_priv(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int isl29125_suspend(struct device *dev)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
return isl29125_powerdown(data);
|
||||
}
|
||||
|
||||
static int isl29125_resume(struct device *dev)
|
||||
{
|
||||
struct isl29125_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
|
||||
data->conf1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume);
|
||||
|
||||
static const struct i2c_device_id isl29125_id[] = {
|
||||
{ "isl29125", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, isl29125_id);
|
||||
|
||||
static struct i2c_driver isl29125_driver = {
|
||||
.driver = {
|
||||
.name = ISL29125_DRV_NAME,
|
||||
.pm = &isl29125_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = isl29125_probe,
|
||||
.remove = isl29125_remove,
|
||||
.id_table = isl29125_id,
|
||||
};
|
||||
module_i2c_driver(isl29125_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("ISL29125 RGB light sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
405
drivers/iio/light/tcs3414.c
Normal file
405
drivers/iio/light/tcs3414.c
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* tcs3414.c - Support for TAOS TCS3414 digital color sensor
|
||||
*
|
||||
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* Digital color sensor with 16-bit channels for red, green, blue, clear);
|
||||
* 7-bit I2C slave address 0x39 (TCS3414) or 0x29, 0x49, 0x59 (TCS3413,
|
||||
* TCS3415, TCS3416, resp.)
|
||||
*
|
||||
* TODO: sync, interrupt support, thresholds, prescaler
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define TCS3414_DRV_NAME "tcs3414"
|
||||
|
||||
#define TCS3414_COMMAND BIT(7)
|
||||
#define TCS3414_COMMAND_WORD (TCS3414_COMMAND | BIT(5))
|
||||
|
||||
#define TCS3414_CONTROL (TCS3414_COMMAND | 0x00)
|
||||
#define TCS3414_TIMING (TCS3414_COMMAND | 0x01)
|
||||
#define TCS3414_ID (TCS3414_COMMAND | 0x04)
|
||||
#define TCS3414_GAIN (TCS3414_COMMAND | 0x07)
|
||||
#define TCS3414_DATA_GREEN (TCS3414_COMMAND_WORD | 0x10)
|
||||
#define TCS3414_DATA_RED (TCS3414_COMMAND_WORD | 0x12)
|
||||
#define TCS3414_DATA_BLUE (TCS3414_COMMAND_WORD | 0x14)
|
||||
#define TCS3414_DATA_CLEAR (TCS3414_COMMAND_WORD | 0x16)
|
||||
|
||||
#define TCS3414_CONTROL_ADC_VALID BIT(4)
|
||||
#define TCS3414_CONTROL_ADC_EN BIT(1)
|
||||
#define TCS3414_CONTROL_POWER BIT(0)
|
||||
|
||||
#define TCS3414_INTEG_MASK GENMASK(1, 0)
|
||||
#define TCS3414_INTEG_12MS 0x0
|
||||
#define TCS3414_INTEG_100MS 0x1
|
||||
#define TCS3414_INTEG_400MS 0x2
|
||||
|
||||
#define TCS3414_GAIN_MASK GENMASK(5, 4)
|
||||
#define TCS3414_GAIN_SHIFT 4
|
||||
|
||||
struct tcs3414_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u8 control;
|
||||
u8 gain;
|
||||
u8 timing;
|
||||
u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */
|
||||
};
|
||||
|
||||
#define TCS3414_CHANNEL(_color, _si, _addr) { \
|
||||
.type = IIO_INTENSITY, \
|
||||
.modified = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_INT_TIME), \
|
||||
.channel2 = IIO_MOD_LIGHT_##_color, \
|
||||
.address = _addr, \
|
||||
.scan_index = _si, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/* scale factors: 1/gain */
|
||||
static const int tcs3414_scales[][2] = {
|
||||
{1, 0}, {0, 250000}, {0, 62500}, {0, 15625}
|
||||
};
|
||||
|
||||
/* integration time in ms */
|
||||
static const int tcs3414_times[] = { 12, 100, 400 };
|
||||
|
||||
static const struct iio_chan_spec tcs3414_channels[] = {
|
||||
TCS3414_CHANNEL(GREEN, 0, TCS3414_DATA_GREEN),
|
||||
TCS3414_CHANNEL(RED, 1, TCS3414_DATA_RED),
|
||||
TCS3414_CHANNEL(BLUE, 2, TCS3414_DATA_BLUE),
|
||||
TCS3414_CHANNEL(CLEAR, 3, TCS3414_DATA_CLEAR),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static int tcs3414_req_data(struct tcs3414_data *data)
|
||||
{
|
||||
int tries = 25;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control | TCS3414_CONTROL_ADC_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
while (tries--) {
|
||||
ret = i2c_smbus_read_byte_data(data->client, TCS3414_CONTROL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret & TCS3414_CONTROL_ADC_VALID)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tries < 0) {
|
||||
dev_err(&data->client->dev, "data not ready\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tcs3414_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(indio_dev);
|
||||
int i, ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
return -EBUSY;
|
||||
mutex_lock(&data->lock);
|
||||
ret = tcs3414_req_data(data);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
ret = i2c_smbus_read_word_data(data->client, chan->address);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
|
||||
*val = tcs3414_scales[i][0];
|
||||
*val2 = tcs3414_scales[i][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
*val = 0;
|
||||
*val2 = tcs3414_times[data->timing & TCS3414_INTEG_MASK] * 1000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int tcs3414_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(indio_dev);
|
||||
int i;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
for (i = 0; i < ARRAY_SIZE(tcs3414_scales); i++) {
|
||||
if (val == tcs3414_scales[i][0] &&
|
||||
val2 == tcs3414_scales[i][1]) {
|
||||
data->gain &= ~TCS3414_GAIN_MASK;
|
||||
data->gain |= i << TCS3414_GAIN_SHIFT;
|
||||
return i2c_smbus_write_byte_data(
|
||||
data->client, TCS3414_GAIN,
|
||||
data->gain);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(tcs3414_times); i++) {
|
||||
if (val == tcs3414_times[i] * 1000) {
|
||||
data->timing &= ~TCS3414_INTEG_MASK;
|
||||
data->timing |= i;
|
||||
return i2c_smbus_write_byte_data(
|
||||
data->client, TCS3414_TIMING,
|
||||
data->timing);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t tcs3414_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct tcs3414_data *data = iio_priv(indio_dev);
|
||||
int i, j = 0;
|
||||
|
||||
for_each_set_bit(i, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
int ret = i2c_smbus_read_word_data(data->client,
|
||||
TCS3414_DATA_GREEN + 2*i);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
data->buffer[j++] = ret;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR(scale_available, "1 0.25 0.0625 0.015625");
|
||||
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.012 0.1 0.4");
|
||||
|
||||
static struct attribute *tcs3414_attributes[] = {
|
||||
&iio_const_attr_scale_available.dev_attr.attr,
|
||||
&iio_const_attr_integration_time_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tcs3414_attribute_group = {
|
||||
.attrs = tcs3414_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info tcs3414_info = {
|
||||
.read_raw = tcs3414_read_raw,
|
||||
.write_raw = tcs3414_write_raw,
|
||||
.attrs = &tcs3414_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int tcs3414_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(indio_dev);
|
||||
|
||||
data->control |= TCS3414_CONTROL_ADC_EN;
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control);
|
||||
}
|
||||
|
||||
static int tcs3414_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = iio_triggered_buffer_predisable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->control &= ~TCS3414_CONTROL_ADC_EN;
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = {
|
||||
.preenable = tcs3414_buffer_preenable,
|
||||
.postenable = &iio_triggered_buffer_postenable,
|
||||
.predisable = tcs3414_buffer_predisable,
|
||||
};
|
||||
|
||||
static int tcs3414_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tcs3414_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &tcs3414_info;
|
||||
indio_dev->name = TCS3414_DRV_NAME;
|
||||
indio_dev->channels = tcs3414_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(tcs3414_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, TCS3414_ID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (ret & 0xf0) {
|
||||
case 0x00:
|
||||
dev_info(&client->dev, "TCS3404 found\n");
|
||||
break;
|
||||
case 0x10:
|
||||
dev_info(&client->dev, "TCS3413/14/15/16 found\n");
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->control = TCS3414_CONTROL_POWER;
|
||||
ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->timing = TCS3414_INTEG_12MS; /* free running */
|
||||
ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING,
|
||||
data->timing);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, TCS3414_GAIN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->gain = ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
tcs3414_trigger_handler, &tcs3414_buffer_setup_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcs3414_powerdown(struct tcs3414_data *data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control & ~(TCS3414_CONTROL_POWER |
|
||||
TCS3414_CONTROL_ADC_EN));
|
||||
}
|
||||
|
||||
static int tcs3414_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
tcs3414_powerdown(iio_priv(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tcs3414_suspend(struct device *dev)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
return tcs3414_powerdown(data);
|
||||
}
|
||||
|
||||
static int tcs3414_resume(struct device *dev)
|
||||
{
|
||||
struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
|
||||
data->control);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume);
|
||||
|
||||
static const struct i2c_device_id tcs3414_id[] = {
|
||||
{ "tcs3414", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tcs3414_id);
|
||||
|
||||
static struct i2c_driver tcs3414_driver = {
|
||||
.driver = {
|
||||
.name = TCS3414_DRV_NAME,
|
||||
.pm = &tcs3414_pm_ops,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tcs3414_probe,
|
||||
.remove = tcs3414_remove,
|
||||
.id_table = tcs3414_id,
|
||||
};
|
||||
module_i2c_driver(tcs3414_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("TCS3414 digital color sensors driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -17,6 +17,16 @@ config AK8975
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak8975.
|
||||
|
||||
config AK09911
|
||||
tristate "Asahi Kasei AK09911 3-axis Compass"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Asahi Kasei AK09911 3-Axis
|
||||
Magnetometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called ak09911.
|
||||
|
||||
config MAG3110
|
||||
tristate "Freescale MAG3110 3-Axis Magnetometer"
|
||||
depends on I2C
|
||||
|
@ -3,6 +3,7 @@
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AK09911) += ak09911.o
|
||||
obj-$(CONFIG_AK8975) += ak8975.o
|
||||
obj-$(CONFIG_MAG3110) += mag3110.o
|
||||
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
|
||||
|
326
drivers/iio/magnetometer/ak09911.c
Normal file
326
drivers/iio/magnetometer/ak09911.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* AK09911 3-axis compass driver
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
#define AK09911_REG_WIA1 0x00
|
||||
#define AK09911_REG_WIA2 0x01
|
||||
#define AK09911_WIA1_VALUE 0x48
|
||||
#define AK09911_WIA2_VALUE 0x05
|
||||
|
||||
#define AK09911_REG_ST1 0x10
|
||||
#define AK09911_REG_HXL 0x11
|
||||
#define AK09911_REG_HXH 0x12
|
||||
#define AK09911_REG_HYL 0x13
|
||||
#define AK09911_REG_HYH 0x14
|
||||
#define AK09911_REG_HZL 0x15
|
||||
#define AK09911_REG_HZH 0x16
|
||||
|
||||
#define AK09911_REG_ASAX 0x60
|
||||
#define AK09911_REG_ASAY 0x61
|
||||
#define AK09911_REG_ASAZ 0x62
|
||||
|
||||
#define AK09911_REG_CNTL1 0x30
|
||||
#define AK09911_REG_CNTL2 0x31
|
||||
#define AK09911_REG_CNTL3 0x32
|
||||
|
||||
#define AK09911_MODE_SNG_MEASURE 0x01
|
||||
#define AK09911_MODE_SELF_TEST 0x10
|
||||
#define AK09911_MODE_FUSE_ACCESS 0x1F
|
||||
#define AK09911_MODE_POWERDOWN 0x00
|
||||
#define AK09911_RESET_DATA 0x01
|
||||
|
||||
#define AK09911_REG_CNTL1 0x30
|
||||
#define AK09911_REG_CNTL2 0x31
|
||||
#define AK09911_REG_CNTL3 0x32
|
||||
|
||||
#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256)
|
||||
|
||||
#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500
|
||||
#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
|
||||
|
||||
struct ak09911_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
u8 asa[3];
|
||||
long raw_to_gauss[3];
|
||||
};
|
||||
|
||||
static const int ak09911_index_to_reg[] = {
|
||||
AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
|
||||
};
|
||||
|
||||
static int ak09911_set_mode(struct i2c_client *client, u8 mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (mode) {
|
||||
case AK09911_MODE_SNG_MEASURE:
|
||||
case AK09911_MODE_SELF_TEST:
|
||||
case AK09911_MODE_FUSE_ACCESS:
|
||||
case AK09911_MODE_POWERDOWN:
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
AK09911_REG_CNTL2, mode);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "set_mode error\n");
|
||||
return ret;
|
||||
}
|
||||
/* After mode change wait atleast 100us */
|
||||
usleep_range(100, 500);
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev,
|
||||
"%s: Unknown mode(%d).", __func__, mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get Sensitivity Adjustment value */
|
||||
static int ak09911_get_asa(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak09911_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Get asa data and store in the device data. */
|
||||
ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
|
||||
3, data->asa);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Not able to read asa data\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
|
||||
data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
|
||||
data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak09911_verify_chip_id(struct i2c_client *client)
|
||||
{
|
||||
u8 wia_val[2];
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
|
||||
2, wia_val);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error reading WIA\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
|
||||
|
||||
if (wia_val[0] != AK09911_WIA1_VALUE ||
|
||||
wia_val[1] != AK09911_WIA2_VALUE) {
|
||||
dev_err(&client->dev, "Device ak09911 not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wait_conversion_complete_polled(struct ak09911_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
u8 read_status;
|
||||
u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
|
||||
int ret;
|
||||
|
||||
/* Wait for the conversion to complete. */
|
||||
while (timeout_ms) {
|
||||
msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
|
||||
ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error in reading ST1\n");
|
||||
return ret;
|
||||
}
|
||||
read_status = ret & 0x01;
|
||||
if (read_status)
|
||||
break;
|
||||
timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
|
||||
}
|
||||
if (!timeout_ms) {
|
||||
dev_err(&client->dev, "Conversion timeout happened\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return read_status;
|
||||
}
|
||||
|
||||
static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
||||
{
|
||||
struct ak09911_data *data = iio_priv(indio_dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
|
||||
if (ret < 0)
|
||||
goto fn_exit;
|
||||
|
||||
ret = wait_conversion_complete_polled(data);
|
||||
if (ret < 0)
|
||||
goto fn_exit;
|
||||
|
||||
/* Read data */
|
||||
ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Read axis data fails\n");
|
||||
goto fn_exit;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
/* Clamp to valid range. */
|
||||
*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
fn_exit:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ak09911_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct ak09911_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return ak09911_read_axis(indio_dev, chan->address, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = data->raw_to_gauss[chan->address];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#define AK09911_CHANNEL(axis, index) \
|
||||
{ \
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.address = index, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ak09911_channels[] = {
|
||||
AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
|
||||
};
|
||||
|
||||
static const struct iio_info ak09911_info = {
|
||||
.read_raw = &ak09911_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id ak_acpi_match[] = {
|
||||
{"AK009911", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
|
||||
|
||||
static int ak09911_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ak09911_data *data;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
ret = ak09911_verify_chip_id(client);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "AK00911 not detected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
ret = ak09911_get_asa(client);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id)
|
||||
name = id->name;
|
||||
else if (ACPI_HANDLE(&client->dev))
|
||||
name = dev_name(&client->dev);
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = ak09911_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
|
||||
indio_dev->info = &ak09911_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->name = name;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak09911_id[] = {
|
||||
{"ak09911", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ak09911_id);
|
||||
|
||||
static struct i2c_driver ak09911_driver = {
|
||||
.driver = {
|
||||
.name = "ak09911",
|
||||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
.probe = ak09911_probe,
|
||||
.id_table = ak09911_id,
|
||||
};
|
||||
module_i2c_driver(ak09911_driver);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("AK09911 Compass driver");
|
@ -165,7 +165,7 @@ static int ak8975_setup_irq(struct ak8975_data *data)
|
||||
else
|
||||
irq = gpio_to_irq(data->eoc_gpio);
|
||||
|
||||
rc = request_irq(irq, ak8975_irq_handler,
|
||||
rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
dev_name(&client->dev), data);
|
||||
if (rc < 0) {
|
||||
@ -513,21 +513,21 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
/* We may not have a GPIO based IRQ to scan, that is fine, we will
|
||||
poll if so */
|
||||
if (gpio_is_valid(eoc_gpio)) {
|
||||
err = gpio_request_one(eoc_gpio, GPIOF_IN, "ak_8975");
|
||||
err = devm_gpio_request_one(&client->dev, eoc_gpio,
|
||||
GPIOF_IN, "ak_8975");
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev,
|
||||
"failed to request GPIO %d, error %d\n",
|
||||
eoc_gpio, err);
|
||||
goto exit;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register with IIO */
|
||||
indio_dev = iio_device_alloc(sizeof(*data));
|
||||
if (indio_dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit_gpio;
|
||||
}
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
@ -542,17 +542,16 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
name = (char *) id->name;
|
||||
} else if (ACPI_HANDLE(&client->dev))
|
||||
name = ak8975_match_acpi_device(&client->dev, &data->chipset);
|
||||
else {
|
||||
err = -ENOSYS;
|
||||
goto exit_free_iio;
|
||||
}
|
||||
else
|
||||
return -ENOSYS;
|
||||
|
||||
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
|
||||
|
||||
/* Perform some basic start-of-day setup of the device. */
|
||||
err = ak8975_setup(client);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "AK8975 initialization fails\n");
|
||||
goto exit_free_iio;
|
||||
return err;
|
||||
}
|
||||
|
||||
data->client = client;
|
||||
@ -564,37 +563,9 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
indio_dev->info = &ak8975_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->name = name;
|
||||
err = iio_device_register(indio_dev);
|
||||
err = devm_iio_device_register(&client->dev, indio_dev);
|
||||
if (err < 0)
|
||||
goto exit_free_iio;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_iio:
|
||||
iio_device_free(indio_dev);
|
||||
if (data->eoc_irq)
|
||||
free_irq(data->eoc_irq, data);
|
||||
exit_gpio:
|
||||
if (gpio_is_valid(eoc_gpio))
|
||||
gpio_free(eoc_gpio);
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ak8975_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
if (data->eoc_irq)
|
||||
free_irq(data->eoc_irq, data);
|
||||
|
||||
if (gpio_is_valid(data->eoc_gpio))
|
||||
gpio_free(data->eoc_gpio);
|
||||
|
||||
iio_device_free(indio_dev);
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -621,7 +592,6 @@ static struct i2c_driver ak8975_driver = {
|
||||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
.probe = ak8975_probe,
|
||||
.remove = ak8975_remove,
|
||||
.id_table = ak8975_id,
|
||||
};
|
||||
module_i2c_driver(ak8975_driver);
|
||||
|
@ -35,6 +35,10 @@ enum magn_3d_channel {
|
||||
CHANNEL_SCAN_INDEX_X,
|
||||
CHANNEL_SCAN_INDEX_Y,
|
||||
CHANNEL_SCAN_INDEX_Z,
|
||||
CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP,
|
||||
CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
|
||||
CHANNEL_SCAN_INDEX_NORTH_MAGN,
|
||||
CHANNEL_SCAN_INDEX_NORTH_TRUE,
|
||||
MAGN_3D_CHANNEL_MAX,
|
||||
};
|
||||
|
||||
@ -42,7 +46,12 @@ struct magn_3d_state {
|
||||
struct hid_sensor_hub_callbacks callbacks;
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
|
||||
u32 magn_val[MAGN_3D_CHANNEL_MAX];
|
||||
|
||||
/* dynamically sized array to hold sensor values */
|
||||
u32 *iio_vals;
|
||||
/* array of pointers to sensor value */
|
||||
u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
|
||||
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
@ -52,7 +61,11 @@ struct magn_3d_state {
|
||||
static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS,
|
||||
HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
|
||||
HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH,
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_NORTH,
|
||||
HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
|
||||
};
|
||||
|
||||
/* Channel definitions */
|
||||
@ -66,7 +79,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
.scan_index = CHANNEL_SCAN_INDEX_X,
|
||||
}, {
|
||||
.type = IIO_MAGN,
|
||||
.modified = 1,
|
||||
@ -76,7 +88,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
.scan_index = CHANNEL_SCAN_INDEX_Y,
|
||||
}, {
|
||||
.type = IIO_MAGN,
|
||||
.modified = 1,
|
||||
@ -86,7 +97,42 @@ static const struct iio_chan_spec magn_3d_channels[] = {
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
.scan_index = CHANNEL_SCAN_INDEX_Z,
|
||||
}, {
|
||||
.type = IIO_ROT,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
}, {
|
||||
.type = IIO_ROT,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
}, {
|
||||
.type = IIO_ROT,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_NORTH_MAGN,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
}, {
|
||||
.type = IIO_ROT,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_NORTH_TRUE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
}
|
||||
};
|
||||
|
||||
@ -126,8 +172,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
report_id =
|
||||
magn_state->magn[chan->scan_index].report_id;
|
||||
address = magn_3d_addresses[chan->scan_index];
|
||||
magn_state->magn[chan->address].report_id;
|
||||
address = magn_3d_addresses[chan->address];
|
||||
if (report_id >= 0)
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
magn_state->common_attributes.hsdev,
|
||||
@ -218,8 +264,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
|
||||
if (atomic_read(&magn_state->common_attributes.data_ready))
|
||||
hid_sensor_push_data(indio_dev,
|
||||
magn_state->magn_val,
|
||||
sizeof(magn_state->magn_val));
|
||||
magn_state->iio_vals,
|
||||
sizeof(magn_state->iio_vals));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -233,52 +279,126 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(priv);
|
||||
struct magn_3d_state *magn_state = iio_priv(indio_dev);
|
||||
int offset;
|
||||
int ret = -EINVAL;
|
||||
int ret = 0;
|
||||
u32 *iio_val = NULL;
|
||||
|
||||
switch (usage_id) {
|
||||
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
|
||||
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
|
||||
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
|
||||
offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS;
|
||||
magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] =
|
||||
*(u32 *)raw_data;
|
||||
ret = 0;
|
||||
offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS)
|
||||
+ CHANNEL_SCAN_INDEX_X;
|
||||
break;
|
||||
case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
|
||||
case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
|
||||
case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
|
||||
case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
|
||||
offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH)
|
||||
+ CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iio_val = magn_state->magn_val_addr[offset];
|
||||
|
||||
if (iio_val != NULL)
|
||||
*iio_val = *((u32 *)raw_data);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse report which is specific to an usage id*/
|
||||
static int magn_3d_parse_report(struct platform_device *pdev,
|
||||
struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_chan_spec *channels,
|
||||
struct iio_chan_spec **channels,
|
||||
int *chan_count,
|
||||
unsigned usage_id,
|
||||
struct magn_3d_state *st)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int attr_count = 0;
|
||||
struct iio_chan_spec *_channels;
|
||||
|
||||
for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
|
||||
ret = sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_INPUT_REPORT,
|
||||
usage_id,
|
||||
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i,
|
||||
&st->magn[CHANNEL_SCAN_INDEX_X + i]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
magn_3d_adjust_channel_bit_mask(channels,
|
||||
CHANNEL_SCAN_INDEX_X + i,
|
||||
st->magn[CHANNEL_SCAN_INDEX_X + i].size);
|
||||
/* Scan for each usage attribute supported */
|
||||
for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
|
||||
int status;
|
||||
u32 address = magn_3d_addresses[i];
|
||||
|
||||
/* Check if usage attribute exists in the sensor hub device */
|
||||
status = sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_INPUT_REPORT,
|
||||
usage_id,
|
||||
address,
|
||||
&(st->magn[i]));
|
||||
if (!status)
|
||||
attr_count++;
|
||||
}
|
||||
dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
|
||||
|
||||
if (attr_count <= 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to find any supported usage attributes in report\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
|
||||
attr_count);
|
||||
dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
|
||||
st->magn[0].index,
|
||||
st->magn[0].report_id,
|
||||
st->magn[1].index, st->magn[1].report_id,
|
||||
st->magn[2].index, st->magn[2].report_id);
|
||||
|
||||
/* Setup IIO channel array */
|
||||
_channels = devm_kcalloc(&pdev->dev, attr_count,
|
||||
sizeof(struct iio_chan_spec),
|
||||
GFP_KERNEL);
|
||||
if (!_channels) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to allocate space for iio channels\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
|
||||
sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!st->iio_vals) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to allocate space for iio values array\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0, *chan_count = 0;
|
||||
i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
|
||||
i++){
|
||||
if (st->magn[i].index >= 0) {
|
||||
/* Setup IIO channel struct */
|
||||
(_channels[*chan_count]) = magn_3d_channels[i];
|
||||
(_channels[*chan_count]).scan_index = *chan_count;
|
||||
(_channels[*chan_count]).address = i;
|
||||
|
||||
/* Set magn_val_addr to iio value address */
|
||||
st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
|
||||
magn_3d_adjust_channel_bit_mask(_channels,
|
||||
*chan_count,
|
||||
st->magn[i].size);
|
||||
(*chan_count)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*chan_count <= 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to find any magnetic channels setup\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*channels = _channels;
|
||||
|
||||
dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
|
||||
*chan_count);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_COMPASS_3D,
|
||||
&st->magn[CHANNEL_SCAN_INDEX_X],
|
||||
@ -296,7 +416,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
|
||||
st->common_attributes.sensitivity.report_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function to initialize the processing for usage id */
|
||||
@ -308,6 +428,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
|
||||
struct magn_3d_state *magn_state;
|
||||
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
|
||||
struct iio_chan_spec *channels;
|
||||
int chan_count = 0;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct magn_3d_state));
|
||||
@ -328,22 +449,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
|
||||
GFP_KERNEL);
|
||||
if (!channels) {
|
||||
dev_err(&pdev->dev, "failed to duplicate channels\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = magn_3d_parse_report(pdev, hsdev, channels,
|
||||
ret = magn_3d_parse_report(pdev, hsdev,
|
||||
&channels, &chan_count,
|
||||
HID_USAGE_SENSOR_COMPASS_3D, magn_state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to setup attributes\n");
|
||||
goto error_free_dev_mem;
|
||||
dev_err(&pdev->dev, "failed to parse report\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->channels = channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels);
|
||||
indio_dev->num_channels = chan_count;
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &magn_3d_info;
|
||||
indio_dev->name = name;
|
||||
@ -353,7 +468,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
|
||||
goto error_free_dev_mem;
|
||||
return ret;
|
||||
}
|
||||
atomic_set(&magn_state->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
@ -387,8 +502,6 @@ error_remove_trigger:
|
||||
hid_sensor_remove_trigger(&magn_state->common_attributes);
|
||||
error_unreg_buffer_funcs:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
error_free_dev_mem:
|
||||
kfree(indio_dev->channels);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -403,7 +516,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
|
||||
iio_device_unregister(indio_dev);
|
||||
hid_sensor_remove_trigger(&magn_state->common_attributes);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
kfree(indio_dev->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -299,6 +299,9 @@ static int st_magn_read_raw(struct iio_dev *indio_dev,
|
||||
else
|
||||
*val2 = mdata->current_fullscale->gain;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = mdata->odr;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -316,6 +319,13 @@ static int st_magn_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
err = st_sensors_set_odr(indio_dev, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return err;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
@ -323,14 +333,12 @@ static int st_magn_write_raw(struct iio_dev *indio_dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
|
||||
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
|
||||
static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_magn_scale_available);
|
||||
|
||||
static struct attribute *st_magn_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_in_magn_scale_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -18,6 +18,27 @@
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_magn.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st_magn_of_match[] = {
|
||||
{
|
||||
.compatible = "st,lsm303dlhc-magn",
|
||||
.data = LSM303DLHC_MAGN_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lsm303dlm-magn",
|
||||
.data = LSM303DLM_MAGN_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis3mdl-magn",
|
||||
.data = LIS3MDL_MAGN_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_magn_of_match);
|
||||
#else
|
||||
#define st_magn_of_match NULL
|
||||
#endif
|
||||
|
||||
static int st_magn_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -31,6 +52,7 @@ static int st_magn_i2c_probe(struct i2c_client *client,
|
||||
|
||||
mdata = iio_priv(indio_dev);
|
||||
mdata->dev = &client->dev;
|
||||
st_sensors_of_i2c_probe(client, st_magn_of_match);
|
||||
|
||||
st_sensors_i2c_configure(indio_dev, client, mdata);
|
||||
|
||||
@ -61,6 +83,7 @@ static struct i2c_driver st_magn_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-magn-i2c",
|
||||
.of_match_table = of_match_ptr(st_magn_of_match),
|
||||
},
|
||||
.probe = st_magn_i2c_probe,
|
||||
.remove = st_magn_i2c_remove,
|
||||
|
@ -70,4 +70,14 @@ config IIO_ST_PRESS_SPI
|
||||
depends on IIO_ST_PRESS
|
||||
depends on IIO_ST_SENSORS_SPI
|
||||
|
||||
config T5403
|
||||
tristate "EPCOS T5403 digital barometric pressure sensor driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the EPCOS T5403 pressure sensor
|
||||
connected via I2C.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called t5403.
|
||||
|
||||
endmenu
|
||||
|
@ -9,6 +9,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
|
||||
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
|
||||
st_pressure-y := st_pressure_core.o
|
||||
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
|
||||
obj-$(CONFIG_T5403) += t5403.o
|
||||
|
||||
obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
|
||||
|
@ -307,6 +307,27 @@ static const struct st_sensors st_press_sensors[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int st_press_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *ch,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
err = st_sensors_set_odr(indio_dev, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return err;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int st_press_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *ch, int *val,
|
||||
int *val2, long mask)
|
||||
@ -349,6 +370,9 @@ static int st_press_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = pdata->odr;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -357,12 +381,10 @@ read_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
|
||||
static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
|
||||
|
||||
static struct attribute *st_press_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -374,6 +396,7 @@ static const struct iio_info press_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &st_press_attribute_group,
|
||||
.read_raw = &st_press_read_raw,
|
||||
.write_raw = &st_press_write_raw,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IIO_TRIGGER
|
||||
|
@ -18,6 +18,27 @@
|
||||
#include <linux/iio/common/st_sensors_i2c.h>
|
||||
#include "st_pressure.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id st_press_of_match[] = {
|
||||
{
|
||||
.compatible = "st,lps001wp-press",
|
||||
.data = LPS001WP_PRESS_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lps25h-press",
|
||||
.data = LPS25H_PRESS_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lps331ap-press",
|
||||
.data = LPS331AP_PRESS_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_press_of_match);
|
||||
#else
|
||||
#define st_press_of_match NULL
|
||||
#endif
|
||||
|
||||
static int st_press_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -31,6 +52,7 @@ static int st_press_i2c_probe(struct i2c_client *client,
|
||||
|
||||
pdata = iio_priv(indio_dev);
|
||||
pdata->dev = &client->dev;
|
||||
st_sensors_of_i2c_probe(client, st_press_of_match);
|
||||
|
||||
st_sensors_i2c_configure(indio_dev, client, pdata);
|
||||
|
||||
@ -60,6 +82,7 @@ static struct i2c_driver st_press_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st-press-i2c",
|
||||
.of_match_table = of_match_ptr(st_press_of_match),
|
||||
},
|
||||
.probe = st_press_i2c_probe,
|
||||
.remove = st_press_i2c_remove,
|
||||
|
275
drivers/iio/pressure/t5403.c
Normal file
275
drivers/iio/pressure/t5403.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* t5403.c - Support for EPCOS T5403 pressure/temperature sensor
|
||||
*
|
||||
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* (7-bit I2C slave address 0x77)
|
||||
*
|
||||
* TODO: end-of-conversion irq
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define T5403_DATA 0xf5 /* data, LSB first, 16 bit */
|
||||
#define T5403_CALIB_DATA 0x8e /* 10 calibration coeff., LSB first, 16 bit */
|
||||
#define T5403_SLAVE_ADDR 0x88 /* I2C slave address, 0x77 */
|
||||
#define T5403_COMMAND 0xf1
|
||||
|
||||
/* command bits */
|
||||
#define T5403_MODE_SHIFT 3 /* conversion time: 2, 8, 16, 66 ms */
|
||||
#define T5403_PT BIT(1) /* 0 .. pressure, 1 .. temperature measurement */
|
||||
#define T5403_SCO BIT(0) /* start conversion */
|
||||
|
||||
#define T5403_MODE_LOW 0
|
||||
#define T5403_MODE_STANDARD 1
|
||||
#define T5403_MODE_HIGH 2
|
||||
#define T5403_MODE_ULTRA_HIGH 3
|
||||
|
||||
#define T5403_I2C_MASK (~BIT(7))
|
||||
#define T5403_I2C_ADDR 0x77
|
||||
|
||||
static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66};
|
||||
|
||||
struct t5403_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
int mode;
|
||||
__le16 c[10];
|
||||
};
|
||||
|
||||
#define T5403_C_U16(i) le16_to_cpu(data->c[(i) - 1])
|
||||
#define T5403_C(i) sign_extend32(T5403_C_U16(i), 15)
|
||||
|
||||
static int t5403_read(struct t5403_data *data, bool pressure)
|
||||
{
|
||||
int wait_time = 3; /* wakeup time in ms */
|
||||
|
||||
int ret = i2c_smbus_write_byte_data(data->client, T5403_COMMAND,
|
||||
(pressure ? (data->mode << T5403_MODE_SHIFT) : T5403_PT) |
|
||||
T5403_SCO);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
wait_time += pressure ? t5403_pressure_conv_ms[data->mode] : 2;
|
||||
|
||||
msleep(wait_time);
|
||||
|
||||
return i2c_smbus_read_word_data(data->client, T5403_DATA);
|
||||
}
|
||||
|
||||
static int t5403_comp_pressure(struct t5403_data *data, int *val, int *val2)
|
||||
{
|
||||
int ret;
|
||||
s16 t_r;
|
||||
u16 p_r;
|
||||
s32 S, O, X;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = t5403_read(data, false);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
t_r = ret;
|
||||
|
||||
ret = t5403_read(data, true);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
p_r = ret;
|
||||
|
||||
/* see EPCOS application note */
|
||||
S = T5403_C_U16(3) + (s32) T5403_C_U16(4) * t_r / 0x20000 +
|
||||
T5403_C(5) * t_r / 0x8000 * t_r / 0x80000 +
|
||||
T5403_C(9) * t_r / 0x8000 * t_r / 0x8000 * t_r / 0x10000;
|
||||
|
||||
O = T5403_C(6) * 0x4000 + T5403_C(7) * t_r / 8 +
|
||||
T5403_C(8) * t_r / 0x8000 * t_r / 16 +
|
||||
T5403_C(9) * t_r / 0x8000 * t_r / 0x10000 * t_r;
|
||||
|
||||
X = (S * p_r + O) / 0x4000;
|
||||
|
||||
X += ((X - 75000) * (X - 75000) / 0x10000 - 9537) *
|
||||
T5403_C(10) / 0x10000;
|
||||
|
||||
*val = X / 1000;
|
||||
*val2 = (X % 1000) * 1000;
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int t5403_comp_temp(struct t5403_data *data, int *val)
|
||||
{
|
||||
int ret;
|
||||
s16 t_r;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = t5403_read(data, false);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
t_r = ret;
|
||||
|
||||
/* see EPCOS application note */
|
||||
*val = ((s32) T5403_C_U16(1) * t_r / 0x100 +
|
||||
(s32) T5403_C_U16(2) * 0x40) * 1000 / 0x10000;
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int t5403_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct t5403_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
switch (chan->type) {
|
||||
case IIO_PRESSURE:
|
||||
ret = t5403_comp_pressure(data, val, val2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_TEMP:
|
||||
ret = t5403_comp_temp(data, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
*val = 0;
|
||||
*val2 = t5403_pressure_conv_ms[data->mode] * 1000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int t5403_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct t5403_data *data = iio_priv(indio_dev);
|
||||
int i;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(t5403_pressure_conv_ms); i++)
|
||||
if (val2 == t5403_pressure_conv_ms[i] * 1000) {
|
||||
mutex_lock(&data->lock);
|
||||
data->mode = i;
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec t5403_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_INT_TIME),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066");
|
||||
|
||||
static struct attribute *t5403_attributes[] = {
|
||||
&iio_const_attr_integration_time_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group t5403_attribute_group = {
|
||||
.attrs = t5403_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info t5403_info = {
|
||||
.read_raw = &t5403_read_raw,
|
||||
.write_raw = &t5403_write_raw,
|
||||
.attrs = &t5403_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int t5403_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct t5403_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if ((ret & T5403_I2C_MASK) != T5403_I2C_ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
indio_dev->info = &t5403_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = t5403_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(t5403_channels);
|
||||
|
||||
data->mode = T5403_MODE_STANDARD;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client, T5403_CALIB_DATA,
|
||||
sizeof(data->c), (u8 *) data->c);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id t5403_id[] = {
|
||||
{ "t5403", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, t5403_id);
|
||||
|
||||
static struct i2c_driver t5403_driver = {
|
||||
.driver = {
|
||||
.name = "t5403",
|
||||
},
|
||||
.probe = t5403_probe,
|
||||
.id_table = t5403_id,
|
||||
};
|
||||
module_i2c_driver(t5403_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
|
||||
MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -232,7 +232,7 @@ static void as3935_event_work(struct work_struct *work)
|
||||
|
||||
switch (val) {
|
||||
case AS3935_EVENT_INT:
|
||||
iio_trigger_poll(st->trig, iio_get_time_ns());
|
||||
iio_trigger_poll(st->trig);
|
||||
break;
|
||||
case AS3935_NOISE_INT:
|
||||
dev_warn(&st->spi->dev, "noise level is too high");
|
||||
|
@ -24,8 +24,7 @@ struct iio_interrupt_trigger_info {
|
||||
|
||||
static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private)
|
||||
{
|
||||
/* Timestamp not currently provided */
|
||||
iio_trigger_poll(private, 0);
|
||||
iio_trigger_poll(private);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ static void iio_sysfs_trigger_work(struct irq_work *work)
|
||||
struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,
|
||||
work);
|
||||
|
||||
iio_trigger_poll(trig->trig, 0);
|
||||
iio_trigger_poll(trig->trig);
|
||||
}
|
||||
|
||||
static ssize_t iio_sysfs_trigger_poll(struct device *dev,
|
||||
|
@ -30,8 +30,6 @@ source "drivers/staging/slicoss/Kconfig"
|
||||
|
||||
source "drivers/staging/usbip/Kconfig"
|
||||
|
||||
source "drivers/staging/winbond/Kconfig"
|
||||
|
||||
source "drivers/staging/wlan-ng/Kconfig"
|
||||
|
||||
source "drivers/staging/comedi/Kconfig"
|
||||
@ -56,41 +54,21 @@ source "drivers/staging/rtl8821ae/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5208/Kconfig"
|
||||
|
||||
source "drivers/staging/frontier/Kconfig"
|
||||
|
||||
source "drivers/staging/phison/Kconfig"
|
||||
|
||||
source "drivers/staging/line6/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon-usb/Kconfig"
|
||||
|
||||
source "drivers/staging/serqt_usb2/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6655/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6656/Kconfig"
|
||||
|
||||
source "drivers/staging/sep/Kconfig"
|
||||
|
||||
source "drivers/staging/iio/Kconfig"
|
||||
|
||||
source "drivers/staging/wlags49_h2/Kconfig"
|
||||
|
||||
source "drivers/staging/wlags49_h25/Kconfig"
|
||||
|
||||
source "drivers/staging/crystalhd/Kconfig"
|
||||
|
||||
source "drivers/staging/cxt1e1/Kconfig"
|
||||
|
||||
source "drivers/staging/xgifb/Kconfig"
|
||||
|
||||
source "drivers/staging/tidspbridge/Kconfig"
|
||||
|
||||
source "drivers/staging/quickstart/Kconfig"
|
||||
|
||||
source "drivers/staging/keucr/Kconfig"
|
||||
source "drivers/staging/emxx_udc/Kconfig"
|
||||
|
||||
source "drivers/staging/bcm/Kconfig"
|
||||
|
||||
@ -108,20 +86,16 @@ source "drivers/staging/media/Kconfig"
|
||||
|
||||
source "drivers/staging/android/Kconfig"
|
||||
|
||||
source "drivers/staging/board/Kconfig"
|
||||
|
||||
source "drivers/staging/ozwpan/Kconfig"
|
||||
|
||||
source "drivers/staging/gdm72xx/Kconfig"
|
||||
|
||||
source "drivers/staging/gdm724x/Kconfig"
|
||||
|
||||
source "drivers/staging/silicom/Kconfig"
|
||||
|
||||
source "drivers/staging/ced1401/Kconfig"
|
||||
|
||||
source "drivers/staging/imx-drm/Kconfig"
|
||||
|
||||
source "drivers/staging/dgrp/Kconfig"
|
||||
|
||||
source "drivers/staging/fwserial/Kconfig"
|
||||
|
||||
source "drivers/staging/goldfish/Kconfig"
|
||||
|
@ -7,7 +7,6 @@ obj-y += media/
|
||||
obj-$(CONFIG_ET131X) += et131x/
|
||||
obj-$(CONFIG_SLICOSS) += slicoss/
|
||||
obj-$(CONFIG_USBIP_CORE) += usbip/
|
||||
obj-$(CONFIG_W35UND) += winbond/
|
||||
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
|
||||
obj-$(CONFIG_COMEDI) += comedi/
|
||||
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
|
||||
@ -20,26 +19,16 @@ obj-$(CONFIG_R8192EE) += rtl8192ee/
|
||||
obj-$(CONFIG_R8723AU) += rtl8723au/
|
||||
obj-$(CONFIG_R8821AE) += rtl8821ae/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_TRANZPORT) += frontier/
|
||||
obj-$(CONFIG_IDE_PHISON) += phison/
|
||||
obj-$(CONFIG_LINE6_USB) += line6/
|
||||
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
|
||||
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_OCTEON_USB) += octeon-usb/
|
||||
obj-$(CONFIG_VT6655) += vt6655/
|
||||
obj-$(CONFIG_VT6656) += vt6656/
|
||||
obj-$(CONFIG_VME_BUS) += vme/
|
||||
obj-$(CONFIG_DX_SEP) += sep/
|
||||
obj-$(CONFIG_IIO) += iio/
|
||||
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
|
||||
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
|
||||
obj-$(CONFIG_CRYSTALHD) += crystalhd/
|
||||
obj-$(CONFIG_CXT1E1) += cxt1e1/
|
||||
obj-$(CONFIG_FB_XGI) += xgifb/
|
||||
obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/
|
||||
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/
|
||||
obj-$(CONFIG_USB_ENESTORAGE) += keucr/
|
||||
obj-$(CONFIG_USB_EMXX) += emxx_udc/
|
||||
obj-$(CONFIG_BCM_WIMAX) += bcm/
|
||||
obj-$(CONFIG_FT1000) += ft1000/
|
||||
obj-$(CONFIG_SPEAKUP) += speakup/
|
||||
@ -47,13 +36,11 @@ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
|
||||
obj-$(CONFIG_MFD_NVEC) += nvec/
|
||||
obj-$(CONFIG_ANDROID) += android/
|
||||
obj-$(CONFIG_STAGING_BOARD) += board/
|
||||
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
|
||||
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
|
||||
obj-$(CONFIG_LTE_GDM724X) += gdm724x/
|
||||
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
|
||||
obj-$(CONFIG_CED1401) += ced1401/
|
||||
obj-$(CONFIG_DRM_IMX) += imx-drm/
|
||||
obj-$(CONFIG_DGRP) += dgrp/
|
||||
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
|
||||
obj-$(CONFIG_GOLDFISH) += goldfish/
|
||||
obj-$(CONFIG_LUSTRE_FS) += lustre/
|
||||
|
@ -76,7 +76,7 @@ config ANDROID_LOW_MEMORY_KILLER
|
||||
Registers processes to be killed when memory is low
|
||||
|
||||
config ANDROID_INTF_ALARM_DEV
|
||||
bool "Android alarm driver"
|
||||
tristate "Android alarm driver"
|
||||
depends on RTC_CLASS
|
||||
default n
|
||||
---help---
|
||||
|
@ -443,4 +443,4 @@ static void __exit alarm_dev_exit(void)
|
||||
|
||||
module_init(alarm_dev_init);
|
||||
module_exit(alarm_dev_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -454,9 +454,8 @@ static size_t binder_buffer_size(struct binder_proc *proc,
|
||||
{
|
||||
if (list_is_last(&buffer->entry, &proc->buffers))
|
||||
return proc->buffer + proc->buffer_size - (void *)buffer->data;
|
||||
else
|
||||
return (size_t)list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry) - (size_t)buffer->data;
|
||||
return (size_t)list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry) - (size_t)buffer->data;
|
||||
}
|
||||
|
||||
static void binder_insert_free_buffer(struct binder_proc *proc,
|
||||
@ -1186,6 +1185,7 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
uint32_t error_code)
|
||||
{
|
||||
struct binder_thread *target_thread;
|
||||
struct binder_transaction *next;
|
||||
|
||||
BUG_ON(t->flags & TF_ONE_WAY);
|
||||
while (1) {
|
||||
@ -1213,24 +1213,23 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
target_thread->return_error);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
struct binder_transaction *next = t->from_parent;
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"send failed reply for transaction %d, target dead\n",
|
||||
t->debug_id);
|
||||
|
||||
binder_pop_transaction(target_thread, t);
|
||||
if (next == NULL) {
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread at root\n");
|
||||
return;
|
||||
}
|
||||
t = next;
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread -- retry %d\n",
|
||||
t->debug_id);
|
||||
}
|
||||
next = t->from_parent;
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"send failed reply for transaction %d, target dead\n",
|
||||
t->debug_id);
|
||||
|
||||
binder_pop_transaction(target_thread, t);
|
||||
if (next == NULL) {
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread at root\n");
|
||||
return;
|
||||
}
|
||||
t = next;
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread -- retry %d\n",
|
||||
t->debug_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2594,6 +2593,106 @@ static unsigned int binder_poll(struct file *filp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_ioctl_write_read(struct file *filp,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
struct binder_thread *thread)
|
||||
{
|
||||
int ret = 0;
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
unsigned int size = _IOC_SIZE(cmd);
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
struct binder_write_read bwr;
|
||||
|
||||
if (size != sizeof(struct binder_write_read)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_size, (u64)bwr.write_buffer,
|
||||
(u64)bwr.read_size, (u64)bwr.read_buffer);
|
||||
|
||||
if (bwr.write_size > 0) {
|
||||
ret = binder_thread_write(proc, thread,
|
||||
bwr.write_buffer,
|
||||
bwr.write_size,
|
||||
&bwr.write_consumed);
|
||||
trace_binder_write_done(ret);
|
||||
if (ret < 0) {
|
||||
bwr.read_consumed = 0;
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (bwr.read_size > 0) {
|
||||
ret = binder_thread_read(proc, thread, bwr.read_buffer,
|
||||
bwr.read_size,
|
||||
&bwr.read_consumed,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
trace_binder_read_done(ret);
|
||||
if (!list_empty(&proc->todo))
|
||||
wake_up_interruptible(&proc->wait);
|
||||
if (ret < 0) {
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_consumed, (u64)bwr.write_size,
|
||||
(u64)bwr.read_consumed, (u64)bwr.read_size);
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int binder_ioctl_set_ctx_mgr(struct file *filp)
|
||||
{
|
||||
int ret = 0;
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
kuid_t curr_euid = current_euid();
|
||||
|
||||
if (binder_context_mgr_node != NULL) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (uid_valid(binder_context_mgr_uid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, curr_euid),
|
||||
from_kuid(&init_user_ns,
|
||||
binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
binder_context_mgr_uid = curr_euid;
|
||||
}
|
||||
binder_context_mgr_node = binder_new_node(proc, 0, 0);
|
||||
if (binder_context_mgr_node == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
binder_context_mgr_node->local_weak_refs++;
|
||||
binder_context_mgr_node->local_strong_refs++;
|
||||
binder_context_mgr_node->has_strong_ref = 1;
|
||||
binder_context_mgr_node->has_weak_ref = 1;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
@ -2601,9 +2700,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
struct binder_thread *thread;
|
||||
unsigned int size = _IOC_SIZE(cmd);
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
kuid_t curr_euid = current_euid();
|
||||
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
|
||||
proc->pid, current->pid, cmd, arg);*/
|
||||
|
||||
trace_binder_ioctl(cmd, arg);
|
||||
|
||||
@ -2619,61 +2718,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case BINDER_WRITE_READ: {
|
||||
struct binder_write_read bwr;
|
||||
|
||||
if (size != sizeof(struct binder_write_read)) {
|
||||
ret = -EINVAL;
|
||||
case BINDER_WRITE_READ:
|
||||
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_size, (u64)bwr.write_buffer,
|
||||
(u64)bwr.read_size, (u64)bwr.read_buffer);
|
||||
|
||||
if (bwr.write_size > 0) {
|
||||
ret = binder_thread_write(proc, thread,
|
||||
bwr.write_buffer,
|
||||
bwr.write_size,
|
||||
&bwr.write_consumed);
|
||||
trace_binder_write_done(ret);
|
||||
if (ret < 0) {
|
||||
bwr.read_consumed = 0;
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (bwr.read_size > 0) {
|
||||
ret = binder_thread_read(proc, thread, bwr.read_buffer,
|
||||
bwr.read_size,
|
||||
&bwr.read_consumed,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
trace_binder_read_done(ret);
|
||||
if (!list_empty(&proc->todo))
|
||||
wake_up_interruptible(&proc->wait);
|
||||
if (ret < 0) {
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_consumed, (u64)bwr.write_size,
|
||||
(u64)bwr.read_consumed, (u64)bwr.read_size);
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BINDER_SET_MAX_THREADS:
|
||||
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
|
||||
ret = -EINVAL;
|
||||
@ -2681,31 +2730,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
case BINDER_SET_CONTEXT_MGR:
|
||||
if (binder_context_mgr_node != NULL) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
|
||||
ret = -EBUSY;
|
||||
ret = binder_ioctl_set_ctx_mgr(filp);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
if (uid_valid(binder_context_mgr_uid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, curr_euid),
|
||||
from_kuid(&init_user_ns, binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
binder_context_mgr_uid = curr_euid;
|
||||
}
|
||||
binder_context_mgr_node = binder_new_node(proc, 0, 0);
|
||||
if (binder_context_mgr_node == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
binder_context_mgr_node->local_weak_refs++;
|
||||
binder_context_mgr_node->local_strong_refs++;
|
||||
binder_context_mgr_node->has_strong_ref = 1;
|
||||
binder_context_mgr_node->has_weak_ref = 1;
|
||||
break;
|
||||
case BINDER_THREAD_EXIT:
|
||||
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
|
||||
@ -2769,9 +2796,15 @@ static void binder_vma_close(struct vm_area_struct *vma)
|
||||
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
|
||||
}
|
||||
|
||||
static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct binder_vm_ops = {
|
||||
.open = binder_vma_open,
|
||||
.close = binder_vma_close,
|
||||
.fault = binder_vm_fault,
|
||||
};
|
||||
|
||||
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
|
@ -1,6 +1,6 @@
|
||||
menuconfig ION
|
||||
bool "Ion Memory Manager"
|
||||
depends on HAVE_MEMBLOCK
|
||||
depends on HAVE_MEMBLOCK && HAS_DMA && MMU
|
||||
select GENERIC_ALLOCATOR
|
||||
select DMA_SHARED_BUFFER
|
||||
---help---
|
||||
|
@ -84,7 +84,6 @@ void ion_reserve(struct ion_platform_data *data);
|
||||
/**
|
||||
* ion_client_create() - allocate a client and returns it
|
||||
* @dev: the global ion device
|
||||
* @heap_type_mask: mask of heaps this client can allocate from
|
||||
* @name: used for debugging
|
||||
*/
|
||||
struct ion_client *ion_client_create(struct ion_device *dev,
|
||||
|
@ -106,7 +106,7 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
|
||||
|
||||
if (ion_buffer_cached(buffer))
|
||||
dma_sync_sg_for_device(NULL, table->sgl, table->nents,
|
||||
DMA_BIDIRECTIONAL);
|
||||
DMA_BIDIRECTIONAL);
|
||||
|
||||
for_each_sg(table->sgl, sg, table->nents, i) {
|
||||
gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
|
||||
|
@ -76,10 +76,8 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
|
||||
return -EINVAL;
|
||||
|
||||
info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(dev, "Can't allocate buffer info\n");
|
||||
if (!info)
|
||||
return ION_CMA_ALLOCATE_FAILED;
|
||||
}
|
||||
|
||||
info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle),
|
||||
GFP_HIGHUSER | __GFP_ZERO);
|
||||
@ -90,10 +88,8 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
|
||||
}
|
||||
|
||||
info->table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
if (!info->table) {
|
||||
dev_err(dev, "Fail to allocate sg table\n");
|
||||
if (!info->table)
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
if (ion_cma_get_sgtable
|
||||
(dev, info->table, info->cpu_addr, info->handle, len))
|
||||
@ -155,7 +151,6 @@ static struct sg_table *ion_cma_heap_map_dma(struct ion_heap *heap,
|
||||
static void ion_cma_heap_unmap_dma(struct ion_heap *heap,
|
||||
struct ion_buffer *buffer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer,
|
||||
|
@ -49,13 +49,7 @@ static inline unsigned int order_to_size(int order)
|
||||
|
||||
struct ion_system_heap {
|
||||
struct ion_heap heap;
|
||||
struct ion_page_pool **pools;
|
||||
};
|
||||
|
||||
struct page_info {
|
||||
struct page *page;
|
||||
unsigned int order;
|
||||
struct list_head list;
|
||||
struct ion_page_pool *pools[0];
|
||||
};
|
||||
|
||||
static struct page *alloc_buffer_page(struct ion_system_heap *heap,
|
||||
@ -84,9 +78,9 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
|
||||
}
|
||||
|
||||
static void free_buffer_page(struct ion_system_heap *heap,
|
||||
struct ion_buffer *buffer, struct page *page,
|
||||
unsigned int order)
|
||||
struct ion_buffer *buffer, struct page *page)
|
||||
{
|
||||
unsigned int order = compound_order(page);
|
||||
bool cached = ion_buffer_cached(buffer);
|
||||
|
||||
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
|
||||
@ -99,19 +93,14 @@ static void free_buffer_page(struct ion_system_heap *heap,
|
||||
}
|
||||
|
||||
|
||||
static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
|
||||
struct ion_buffer *buffer,
|
||||
unsigned long size,
|
||||
unsigned int max_order)
|
||||
static struct page *alloc_largest_available(struct ion_system_heap *heap,
|
||||
struct ion_buffer *buffer,
|
||||
unsigned long size,
|
||||
unsigned int max_order)
|
||||
{
|
||||
struct page *page;
|
||||
struct page_info *info;
|
||||
int i;
|
||||
|
||||
info = kmalloc(sizeof(struct page_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
if (size < order_to_size(orders[i]))
|
||||
continue;
|
||||
@ -122,11 +111,8 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
|
||||
if (!page)
|
||||
continue;
|
||||
|
||||
info->page = page;
|
||||
info->order = orders[i];
|
||||
return info;
|
||||
return page;
|
||||
}
|
||||
kfree(info);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -142,7 +128,7 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
struct sg_table *table;
|
||||
struct scatterlist *sg;
|
||||
struct list_head pages;
|
||||
struct page_info *info, *tmp_info;
|
||||
struct page *page, *tmp_page;
|
||||
int i = 0;
|
||||
unsigned long size_remaining = PAGE_ALIGN(size);
|
||||
unsigned int max_order = orders[0];
|
||||
@ -155,13 +141,13 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
|
||||
INIT_LIST_HEAD(&pages);
|
||||
while (size_remaining > 0) {
|
||||
info = alloc_largest_available(sys_heap, buffer, size_remaining,
|
||||
page = alloc_largest_available(sys_heap, buffer, size_remaining,
|
||||
max_order);
|
||||
if (!info)
|
||||
if (!page)
|
||||
goto free_pages;
|
||||
list_add_tail(&info->list, &pages);
|
||||
size_remaining -= PAGE_SIZE << info->order;
|
||||
max_order = info->order;
|
||||
list_add_tail(&page->lru, &pages);
|
||||
size_remaining -= PAGE_SIZE << compound_order(page);
|
||||
max_order = compound_order(page);
|
||||
i++;
|
||||
}
|
||||
table = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
|
||||
@ -172,12 +158,10 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
goto free_table;
|
||||
|
||||
sg = table->sgl;
|
||||
list_for_each_entry_safe(info, tmp_info, &pages, list) {
|
||||
struct page *page = info->page;
|
||||
sg_set_page(sg, page, PAGE_SIZE << info->order, 0);
|
||||
list_for_each_entry_safe(page, tmp_page, &pages, lru) {
|
||||
sg_set_page(sg, page, PAGE_SIZE << compound_order(page), 0);
|
||||
sg = sg_next(sg);
|
||||
list_del(&info->list);
|
||||
kfree(info);
|
||||
list_del(&page->lru);
|
||||
}
|
||||
|
||||
buffer->priv_virt = table;
|
||||
@ -186,10 +170,8 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
|
||||
free_table:
|
||||
kfree(table);
|
||||
free_pages:
|
||||
list_for_each_entry_safe(info, tmp_info, &pages, list) {
|
||||
free_buffer_page(sys_heap, buffer, info->page, info->order);
|
||||
kfree(info);
|
||||
}
|
||||
list_for_each_entry_safe(page, tmp_page, &pages, lru)
|
||||
free_buffer_page(sys_heap, buffer, page);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -209,8 +191,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer)
|
||||
ion_heap_buffer_zero(buffer);
|
||||
|
||||
for_each_sg(table->sgl, sg, table->nents, i)
|
||||
free_buffer_page(sys_heap, buffer, sg_page(sg),
|
||||
get_order(sg->length));
|
||||
free_buffer_page(sys_heap, buffer, sg_page(sg));
|
||||
sg_free_table(table);
|
||||
kfree(table);
|
||||
}
|
||||
@ -283,16 +264,15 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
|
||||
struct ion_system_heap *heap;
|
||||
int i;
|
||||
|
||||
heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
|
||||
heap = kzalloc(sizeof(struct ion_system_heap) +
|
||||
sizeof(struct ion_page_pool *) * num_orders,
|
||||
GFP_KERNEL);
|
||||
if (!heap)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
heap->heap.ops = &system_heap_ops;
|
||||
heap->heap.type = ION_HEAP_TYPE_SYSTEM;
|
||||
heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
|
||||
heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
|
||||
GFP_KERNEL);
|
||||
if (!heap->pools)
|
||||
goto free_heap;
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool;
|
||||
gfp_t gfp_flags = low_order_gfp_flags;
|
||||
@ -311,8 +291,6 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
|
||||
destroy_pools:
|
||||
while (i--)
|
||||
ion_page_pool_destroy(heap->pools[i]);
|
||||
kfree(heap->pools);
|
||||
free_heap:
|
||||
kfree(heap);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@ -326,7 +304,6 @@ void ion_system_heap_destroy(struct ion_heap *heap)
|
||||
|
||||
for (i = 0; i < num_orders; i++)
|
||||
ion_page_pool_destroy(sys_heap->pools[i]);
|
||||
kfree(sys_heap->pools);
|
||||
kfree(sys_heap);
|
||||
}
|
||||
|
||||
|
@ -110,8 +110,8 @@ static inline struct logger_log *file_get_log(struct file *file)
|
||||
struct logger_reader *reader = file->private_data;
|
||||
|
||||
return reader->log;
|
||||
} else
|
||||
return file->private_data;
|
||||
}
|
||||
return file->private_data;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -159,8 +159,7 @@ static size_t get_user_hdr_len(int ver)
|
||||
{
|
||||
if (ver < 2)
|
||||
return sizeof(struct user_logger_entry_compat);
|
||||
else
|
||||
return sizeof(struct logger_entry);
|
||||
return sizeof(struct logger_entry);
|
||||
}
|
||||
|
||||
static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
|
||||
|
@ -555,8 +555,7 @@ static unsigned int sync_fence_poll(struct file *file, poll_table *wait)
|
||||
return POLLIN;
|
||||
else if (status < 0)
|
||||
return POLLERR;
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg)
|
||||
|
@ -45,16 +45,17 @@ static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)
|
||||
|
||||
static int gpio_get_time(struct timed_output_dev *dev)
|
||||
{
|
||||
struct timed_gpio_data *data =
|
||||
container_of(dev, struct timed_gpio_data, dev);
|
||||
struct timed_gpio_data *data;
|
||||
struct timeval t;
|
||||
|
||||
if (hrtimer_active(&data->timer)) {
|
||||
ktime_t r = hrtimer_get_remaining(&data->timer);
|
||||
struct timeval t = ktime_to_timeval(r);
|
||||
data = container_of(dev, struct timed_gpio_data, dev);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
} else
|
||||
if (!hrtimer_active(&data->timer))
|
||||
return 0;
|
||||
|
||||
t = ktime_to_timeval(hrtimer_get_remaining(&data->timer));
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
}
|
||||
|
||||
static void gpio_enable(struct timed_output_dev *dev, int value)
|
||||
|
@ -41,8 +41,10 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct timed_output_dev *tdev = dev_get_drvdata(dev);
|
||||
int value;
|
||||
int rc;
|
||||
|
||||
if (sscanf(buf, "%d", &value) != 1)
|
||||
rc = kstrtoint(buf, 0, &value);
|
||||
if (rc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
tdev->enable(tdev, value);
|
||||
|
@ -1648,7 +1648,7 @@ static int bcm_char_ioctl_flash2x_section_read(void __user *argp,
|
||||
|
||||
ReadOffset = sFlash2xRead.offset;
|
||||
OutPutBuff = IoBuffer.OutputBuffer;
|
||||
pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);
|
||||
pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
|
||||
|
||||
if (pReadBuff == NULL) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
|
@ -972,6 +972,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
|
||||
pstAddIndication->sfAuthorizedSet.bValid = 1;
|
||||
for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) {
|
||||
struct bcm_convergence_types *psfCSType = NULL;
|
||||
|
||||
psfCSType = &pstAddIndication->sfAuthorizedSet.cConvergenceSLTypes[nIndex];
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "psfCSType = %p", psfCSType);
|
||||
@ -1418,7 +1419,7 @@ static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter,
|
||||
ulAddrSFParamSet = ntohl(ulAddrSFParamSet);
|
||||
|
||||
/* Read out the SF Param Set At the indicated Location */
|
||||
if (rdm(Adapter, ulAddrSFParamSet,(PUCHAR)pucDestBuffer, nBytesToRead) < 0)
|
||||
if (rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0)
|
||||
return STATUS_FAILURE;
|
||||
|
||||
return 1;
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
/* DDR INIT-133Mhz */
|
||||
#define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting133MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting133MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0F000800, 0x00007212},
|
||||
{0x0f000820, 0x07F13FFF},
|
||||
{0x0f000810, 0x00000F95},
|
||||
@ -65,7 +66,8 @@ static struct bcm_ddr_setting asT3_DDRSetting133MHz[] = { /* DPLL Clock Setting
|
||||
};
|
||||
/* 80Mhz */
|
||||
#define T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 10 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting80MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting80MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000820, 0x07f1ffff},
|
||||
{0x0f000860, 0x00000000},
|
||||
@ -117,7 +119,8 @@ static struct bcm_ddr_setting asT3_DDRSetting80MHz[] = { /* DPLL Clock Setting
|
||||
};
|
||||
/* 100Mhz */
|
||||
#define T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 13 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting100MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3_DDRSetting100MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0F000800, 0x00007008},
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000820, 0x07F13E3F},
|
||||
@ -189,7 +192,8 @@ static struct bcm_ddr_setting asDPLL_266MHZ[] = {
|
||||
};
|
||||
|
||||
#define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting133MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting133MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000810, 0x00000F95},
|
||||
@ -247,7 +251,8 @@ static struct bcm_ddr_setting asT3B_DDRSetting133MHz[] = { /* DPLL Clock Settin
|
||||
};
|
||||
|
||||
#define T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting80MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting80MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000820, 0x07F13FFF},
|
||||
{0x0f000840, 0x0FFF1F00},
|
||||
@ -301,7 +306,8 @@ static struct bcm_ddr_setting asT3B_DDRSetting80MHz[] = { /* DPLL Clock Setting
|
||||
|
||||
/* 100Mhz */
|
||||
#define T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 9 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting100MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3B_DDRSetting100MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00000F95},
|
||||
{0x0f000820, 0x07F1369B},
|
||||
{0x0f000840, 0x0FFF0800},
|
||||
@ -356,7 +362,8 @@ static struct bcm_ddr_setting asT3B_DDRSetting100MHz[] = { /* DPLL Clock Settin
|
||||
|
||||
|
||||
#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 9 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting133MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting133MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000820, 0x03F1365B},
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000880, 0x000003DD},
|
||||
@ -416,7 +423,8 @@ static struct bcm_ddr_setting asT3LP_DDRSetting133MHz[] = { /* DPLL Clock Setti
|
||||
};
|
||||
|
||||
#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 11 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting100MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting100MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000820, 0x03F1369B},
|
||||
{0x0f000840, 0x0fff0000},
|
||||
@ -476,7 +484,8 @@ static struct bcm_ddr_setting asT3LP_DDRSetting100MHz[] = { /* DPLL Clock Setti
|
||||
};
|
||||
|
||||
#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting80MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LP_DDRSetting80MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000820, 0x07F13FFF},
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000860, 0x00000000},
|
||||
@ -536,7 +545,8 @@ static struct bcm_ddr_setting asT3LP_DDRSetting80MHz[] = { /* DPLL Clock Settin
|
||||
/* T3 LP-B (UMA-B) */
|
||||
|
||||
#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ 7 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000820, 0x03F137DB},
|
||||
{0x0f000810, 0x01842795},
|
||||
{0x0f000860, 0x00000000},
|
||||
@ -544,7 +554,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[] = { /* DPLL Clock Sett
|
||||
{0x0f000840, 0x0FFF0400},
|
||||
{0x0F00a044, 0x1fffffff},
|
||||
{0x0F00a040, 0x1f000000},
|
||||
{0x0f003050, 0x00000021}, /* this is flash/eeprom clock divisor which set the flash clock to 20 MHz */
|
||||
{0x0f003050, 0x00000021}, /* this is flash/eeprom clock divisor which
|
||||
* set the flash clock to 20 MHz */
|
||||
{0x0F00a084, 0x1Cffffff}, /* Now dump from her in internal memory */
|
||||
{0x0F00a080, 0x1C000000},
|
||||
{0x0F00A000, 0x00000016},
|
||||
@ -593,7 +604,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[] = { /* DPLL Clock Sett
|
||||
|
||||
|
||||
#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 7 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000820, 0x03F1365B},
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000880, 0x000003DD},
|
||||
@ -602,7 +614,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[] = { /* DPLL Clock Sett
|
||||
{0x0f000860, 0x00000000},
|
||||
{0x0F00a044, 0x1fffffff},
|
||||
{0x0F00a040, 0x1f000000},
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which
|
||||
* set the flash clock to 20 MHz */
|
||||
{0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */
|
||||
{0x0F00a080, 0x1C000000},
|
||||
{0x0F00A000, 0x00000016},
|
||||
@ -654,7 +667,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[] = { /* DPLL Clock Sett
|
||||
};
|
||||
|
||||
#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 8 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000820, 0x03F1369B},
|
||||
{0x0f000840, 0x0fff0000},
|
||||
@ -664,7 +678,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[] = { /* DPLL Clock Sett
|
||||
{0x0f000840, 0x0FFF0000},
|
||||
{0x0F00a044, 0x1fffffff},
|
||||
{0x0F00a040, 0x1f000000},
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which
|
||||
* set the flash clock to 20 MHz */
|
||||
{0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */
|
||||
{0x0F00a080, 0x1C000000},
|
||||
/* Memcontroller Default values */
|
||||
@ -715,7 +730,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[] = { /* DPLL Clock Sett
|
||||
};
|
||||
|
||||
#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 7 /* index for 0x0F007000 */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting80MHz[] = { /* DPLL Clock Setting */
|
||||
static struct bcm_ddr_setting asT3LPB_DDRSetting80MHz[] = {
|
||||
/* DPLL Clock Setting */
|
||||
{0x0f000820, 0x07F13FFF},
|
||||
{0x0f000810, 0x00002F95},
|
||||
{0x0f000860, 0x00000000},
|
||||
@ -723,7 +739,8 @@ static struct bcm_ddr_setting asT3LPB_DDRSetting80MHz[] = { /* DPLL Clock Setti
|
||||
{0x0f000840, 0x0FFF1F00},
|
||||
{0x0F00a044, 0x1fffffff},
|
||||
{0x0F00a040, 0x1f000000},
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */
|
||||
{0x0f003050, 0x00000021}, /* flash/eeprom clock divisor
|
||||
* which set the flash clock to 20 MHz */
|
||||
{0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */
|
||||
{0x0F00a080, 0x1C000000},
|
||||
{0x0F00A000, 0x00000016},
|
||||
@ -776,7 +793,7 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
struct bcm_ddr_setting *psDDRSetting = NULL;
|
||||
ULONG RegCount = 0;
|
||||
UINT value = 0;
|
||||
UINT uiResetValue = 0;
|
||||
UINT uiResetValue = 0;
|
||||
UINT uiClockSetting = 0;
|
||||
int retval = STATUS_SUCCESS;
|
||||
|
||||
@ -785,18 +802,18 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
switch (Adapter->DDRSetting) {
|
||||
case DDR_80_MHZ:
|
||||
psDDRSetting = asT3LP_DDRSetting80MHz;
|
||||
RegCount = (sizeof(asT3LP_DDRSetting80MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3LP_DDRSetting80MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_100_MHZ:
|
||||
psDDRSetting = asT3LP_DDRSetting100MHz;
|
||||
RegCount = (sizeof(asT3LP_DDRSetting100MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3LP_DDRSetting100MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_133_MHZ:
|
||||
psDDRSetting = asT3LP_DDRSetting133MHz;
|
||||
RegCount = (sizeof(asT3LP_DDRSetting133MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3LP_DDRSetting133MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
if (Adapter->bMipsConfig == MIPS_200_MHZ)
|
||||
uiClockSetting = 0x03F13652;
|
||||
else
|
||||
@ -818,15 +835,21 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
if ((Adapter->chip_id != BCS220_2) &&
|
||||
(Adapter->chip_id != BCS220_2BC) &&
|
||||
(Adapter->chip_id != BCS220_3)) {
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000830, &uiResetValue,
|
||||
sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__, __LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue |= 0x44;
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000830, &uiResetValue,
|
||||
sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__, __LINE__);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@ -836,18 +859,18 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
|
||||
case DDR_80_MHZ:
|
||||
psDDRSetting = asT3LPB_DDRSetting80MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting80MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting80MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_100_MHZ:
|
||||
psDDRSetting = asT3LPB_DDRSetting100MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting100MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting100MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_133_MHZ:
|
||||
psDDRSetting = asT3LPB_DDRSetting133MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
|
||||
if (Adapter->bMipsConfig == MIPS_200_MHZ)
|
||||
uiClockSetting = 0x03F13652;
|
||||
@ -857,7 +880,8 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
|
||||
case DDR_160_MHZ:
|
||||
psDDRSetting = asT3LPB_DDRSetting160MHz;
|
||||
RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(struct bcm_ddr_setting);
|
||||
RegCount = sizeof(asT3LPB_DDRSetting160MHz) /
|
||||
sizeof(struct bcm_ddr_setting);
|
||||
|
||||
if (Adapter->bMipsConfig == MIPS_200_MHZ)
|
||||
uiClockSetting = 0x03F137D2;
|
||||
@ -871,22 +895,23 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
case 0xbece0121:
|
||||
case 0xbece0130:
|
||||
case 0xbece0300:
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
|
||||
"DDR Setting: %x\n", Adapter->DDRSetting);
|
||||
switch (Adapter->DDRSetting) {
|
||||
case DDR_80_MHZ:
|
||||
psDDRSetting = asT3_DDRSetting80MHz;
|
||||
RegCount = (sizeof(asT3_DDRSetting80MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3_DDRSetting80MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_100_MHZ:
|
||||
psDDRSetting = asT3_DDRSetting100MHz;
|
||||
RegCount = (sizeof(asT3_DDRSetting100MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3_DDRSetting100MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_133_MHZ:
|
||||
psDDRSetting = asT3_DDRSetting133MHz;
|
||||
RegCount = (sizeof(asT3_DDRSetting133MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3_DDRSetting133MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -896,26 +921,27 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
switch (Adapter->DDRSetting) {
|
||||
case DDR_80_MHZ:
|
||||
psDDRSetting = asT3B_DDRSetting80MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting80MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting80MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_100_MHZ:
|
||||
psDDRSetting = asT3B_DDRSetting100MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting100MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting100MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
break;
|
||||
case DDR_133_MHZ:
|
||||
|
||||
if (Adapter->bDPLLConfig == PLL_266_MHZ) { /* 266Mhz PLL selected. */
|
||||
/* 266Mhz PLL selected. */
|
||||
if (Adapter->bDPLLConfig == PLL_266_MHZ) {
|
||||
memcpy(asT3B_DDRSetting133MHz, asDPLL_266MHZ,
|
||||
sizeof(asDPLL_266MHZ));
|
||||
sizeof(asDPLL_266MHZ));
|
||||
psDDRSetting = asT3B_DDRSetting133MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
} else {
|
||||
psDDRSetting = asT3B_DDRSetting133MHz;
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz)/
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
RegCount = (sizeof(asT3B_DDRSetting133MHz) /
|
||||
sizeof(struct bcm_ddr_setting));
|
||||
if (Adapter->bMipsConfig == MIPS_200_MHZ)
|
||||
uiClockSetting = 0x07F13652;
|
||||
else
|
||||
@ -933,15 +959,19 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
}
|
||||
|
||||
value = 0;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Register Count is =%lu\n", RegCount);
|
||||
while (RegCount && !retval) {
|
||||
if (uiClockSetting && psDDRSetting->ulRegAddress == MIPS_CLOCK_REG)
|
||||
if (uiClockSetting
|
||||
&& psDDRSetting->ulRegAddress == MIPS_CLOCK_REG)
|
||||
value = uiClockSetting;
|
||||
else
|
||||
value = psDDRSetting->ulRegValue;
|
||||
retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value));
|
||||
retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value,
|
||||
sizeof(value));
|
||||
if (STATUS_SUCCESS != retval) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"%s:%d\n", __func__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -957,27 +987,47 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
(Adapter->chip_id != BCS220_3)) {
|
||||
/* drive MDDR to half in case of UMA-B: */
|
||||
uiResetValue = 0x01010001;
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007018,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x00040020;
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007094, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007094,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x01020101;
|
||||
retval = wrmalt(Adapter, (UINT)0x0F00701c, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0F00701c,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x01010000;
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0F007018,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@ -986,74 +1036,135 @@ int ddr_init(struct bcm_mini_adapter *Adapter)
|
||||
/* DC/DC standby change...
|
||||
* This is to be done only for Hybrid PMU mode.
|
||||
* with the current h/w there is no way to detect this.
|
||||
* and since we dont have internal PMU lets do it under UMA-B chip id.
|
||||
* we will change this when we will have internal PMU.
|
||||
* and since we dont have internal PMU lets do it under
|
||||
* UMA-B chip id. we will change this when we will have
|
||||
* internal PMU.
|
||||
*/
|
||||
if (Adapter->PmuMode == HYBRID_MODE_7C) {
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x1322a8;
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d1c,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x132296;
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d14,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
} else if (Adapter->PmuMode == HYBRID_MODE_6) {
|
||||
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x6003229a;
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d14,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = rdmalt(Adapter, (UINT)0x0f000c00,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
uiResetValue = 0x1322a8;
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue));
|
||||
retval = wrmalt(Adapter, (UINT)0x0f000d1c,
|
||||
&uiResetValue, sizeof(uiResetValue));
|
||||
if (retval < 0) {
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, CMHOST, RDM,
|
||||
DBG_LVL_ALL,
|
||||
"%s:%d RDM failed\n",
|
||||
__func__,
|
||||
__LINE__);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
@ -1067,8 +1178,9 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
struct bcm_ddr_setting *psDDRSetting = NULL;
|
||||
ULONG RegCount = 0;
|
||||
unsigned long ul_ddr_setting_load_addr = DDR_DUMP_INTERNAL_DEVICE_MEMORY;
|
||||
UINT value = 0;
|
||||
unsigned long ul_ddr_setting_load_addr =
|
||||
DDR_DUMP_INTERNAL_DEVICE_MEMORY;
|
||||
UINT value = 0;
|
||||
int retval = STATUS_SUCCESS;
|
||||
bool bOverrideSelfRefresh = false;
|
||||
|
||||
@ -1191,18 +1303,22 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
|
||||
}
|
||||
/* total number of Register that has to be dumped */
|
||||
value = RegCount;
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value,
|
||||
sizeof(value));
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"%s:%d\n", __func__, __LINE__);
|
||||
|
||||
return retval;
|
||||
}
|
||||
ul_ddr_setting_load_addr += sizeof(ULONG);
|
||||
/* signature */
|
||||
value = (0x1d1e0dd0);
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value,
|
||||
sizeof(value));
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"%s:%d\n", __func__, __LINE__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1211,29 +1327,29 @@ int download_ddr_settings(struct bcm_mini_adapter *Adapter)
|
||||
|
||||
while (RegCount && !retval) {
|
||||
value = psDDRSetting->ulRegAddress;
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value));
|
||||
retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value,
|
||||
sizeof(value));
|
||||
ul_ddr_setting_load_addr += sizeof(ULONG);
|
||||
if (!retval) {
|
||||
if (bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018)) {
|
||||
if (bOverrideSelfRefresh
|
||||
&& (psDDRSetting->ulRegAddress
|
||||
== 0x0F007018))
|
||||
value = (psDDRSetting->ulRegValue | (1<<8));
|
||||
if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr,
|
||||
&value, sizeof(value))) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
value = psDDRSetting->ulRegValue;
|
||||
else
|
||||
value = psDDRSetting->ulRegValue;
|
||||
|
||||
if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr ,
|
||||
&value, sizeof(value))) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__);
|
||||
break;
|
||||
}
|
||||
if (STATUS_SUCCESS != wrmalt(Adapter,
|
||||
ul_ddr_setting_load_addr,
|
||||
&value,
|
||||
sizeof(value))) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
"%s:%d\n", __func__, __LINE__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ul_ddr_setting_load_addr += sizeof(ULONG);
|
||||
RegCount--;
|
||||
psDDRSetting++;
|
||||
}
|
||||
return retval;
|
||||
return retval;
|
||||
}
|
||||
|
@ -11,7 +11,8 @@
|
||||
* Enqueue the control packet for Application.
|
||||
* @return None
|
||||
*/
|
||||
static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk_buff *skb)
|
||||
static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct bcm_tarang_data *pTarang = NULL;
|
||||
bool HighPriorityMessage = false;
|
||||
@ -22,7 +23,7 @@ static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk
|
||||
|
||||
if (netif_msg_pktdata(Adapter))
|
||||
print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE,
|
||||
16, 1, skb->data, skb->len, 0);
|
||||
16, 1, skb->data, skb->len, 0);
|
||||
|
||||
switch (usStatus) {
|
||||
case CM_RESPONSES: /* 0xA0 */
|
||||
@ -106,30 +107,32 @@ static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk
|
||||
* the sum of all types of dropped pkt by that
|
||||
* tarang only.
|
||||
*/
|
||||
struct bcm_mibs_dropped_cntrl_msg *msg =
|
||||
&pTarang->stDroppedAppCntrlMsgs;
|
||||
switch (*(PUSHORT)skb->data) {
|
||||
case CM_RESPONSES:
|
||||
pTarang->stDroppedAppCntrlMsgs.cm_responses++;
|
||||
msg->cm_responses++;
|
||||
break;
|
||||
case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP:
|
||||
pTarang->stDroppedAppCntrlMsgs.cm_control_newdsx_multiclassifier_resp++;
|
||||
msg->cm_control_newdsx_multiclassifier_resp++;
|
||||
break;
|
||||
case LINK_CONTROL_RESP:
|
||||
pTarang->stDroppedAppCntrlMsgs.link_control_resp++;
|
||||
msg->link_control_resp++;
|
||||
break;
|
||||
case STATUS_RSP:
|
||||
pTarang->stDroppedAppCntrlMsgs.status_rsp++;
|
||||
msg->status_rsp++;
|
||||
break;
|
||||
case STATS_POINTER_RESP:
|
||||
pTarang->stDroppedAppCntrlMsgs.stats_pointer_resp++;
|
||||
msg->stats_pointer_resp++;
|
||||
break;
|
||||
case IDLE_MODE_STATUS:
|
||||
pTarang->stDroppedAppCntrlMsgs.idle_mode_status++;
|
||||
msg->idle_mode_status++;
|
||||
break;
|
||||
case AUTH_SS_HOST_MSG:
|
||||
pTarang->stDroppedAppCntrlMsgs.auth_ss_host_msg++;
|
||||
msg->auth_ss_host_msg++;
|
||||
break;
|
||||
default:
|
||||
pTarang->stDroppedAppCntrlMsgs.low_priority_message++;
|
||||
msg->low_priority_message++;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -216,6 +219,7 @@ INT flushAllAppQ(void)
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
struct bcm_tarang_data *pTarang = NULL;
|
||||
struct sk_buff *PacketToDrop = NULL;
|
||||
|
||||
for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) {
|
||||
while (pTarang->RxAppControlHead != NULL) {
|
||||
PacketToDrop = pTarang->RxAppControlHead;
|
||||
|
@ -11,7 +11,7 @@ static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
|
||||
{
|
||||
UCHAR *pucRetHeaderPtr = NULL;
|
||||
UCHAR *pucPayloadPtr = NULL;
|
||||
USHORT usNextHeaderOffset = 0 ;
|
||||
USHORT usNextHeaderOffset = 0;
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
|
||||
if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
|
||||
@ -34,94 +34,89 @@ static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
|
||||
|
||||
switch (*pucNextHeader) {
|
||||
case IPV6HDR_TYPE_HOPBYHOP:
|
||||
{
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nIPv6 HopByHop Header");
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_options_hdr);
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nIPv6 HopByHop Header");
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_options_hdr);
|
||||
break;
|
||||
|
||||
case IPV6HDR_TYPE_ROUTING:
|
||||
{
|
||||
struct bcm_ipv6_routing_hdr *pstIpv6RoutingHeader;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nIPv6 Routing Header");
|
||||
pstIpv6RoutingHeader = (struct bcm_ipv6_routing_hdr *)pucPayloadPtr;
|
||||
pstIpv6RoutingHeader =
|
||||
(struct bcm_ipv6_routing_hdr *)pucPayloadPtr;
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_routing_hdr);
|
||||
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES;
|
||||
|
||||
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses *
|
||||
IPV6_ADDRESS_SIZEINBYTES;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPV6HDR_TYPE_FRAGMENTATION:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Fragmentation Header");
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_fragment_hdr);
|
||||
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Fragmentation Header");
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_fragment_hdr);
|
||||
break;
|
||||
|
||||
case IPV6HDR_TYPE_DESTOPTS:
|
||||
{
|
||||
struct bcm_ipv6_dest_options_hdr *pstIpv6DestOptsHdr = (struct bcm_ipv6_dest_options_hdr *)pucPayloadPtr;
|
||||
struct bcm_ipv6_dest_options_hdr *pstIpv6DestOptsHdr =
|
||||
(struct bcm_ipv6_dest_options_hdr *)pucPayloadPtr;
|
||||
int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 DestOpts Header Header");
|
||||
usNextHeaderOffset += sizeof(struct bcm_ipv6_dest_options_hdr);
|
||||
usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
|
||||
|
||||
usNextHeaderOffset += nTotalOptions *
|
||||
IPV6_DESTOPTS_HDR_OPTIONSIZE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case IPV6HDR_TYPE_AUTHENTICATION:
|
||||
{
|
||||
struct bcm_ipv6_authentication_hdr *pstIpv6AuthHdr = (struct bcm_ipv6_authentication_hdr *)pucPayloadPtr;
|
||||
struct bcm_ipv6_authentication_hdr *pstIpv6AuthHdr =
|
||||
(struct bcm_ipv6_authentication_hdr *)pucPayloadPtr;
|
||||
int nHdrLen = pstIpv6AuthHdr->ucLength;
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Authentication Header");
|
||||
usNextHeaderOffset += nHdrLen * 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Encrypted Security Payload Header");
|
||||
*bParseDone = TRUE;
|
||||
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Encrypted Security Payload Header");
|
||||
*bParseDone = TRUE;
|
||||
break;
|
||||
|
||||
case IPV6_ICMP_HDR_TYPE:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nICMP Header");
|
||||
*bParseDone = TRUE;
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nICMP Header");
|
||||
*bParseDone = TRUE;
|
||||
break;
|
||||
|
||||
case TCP_HEADER_TYPE:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nTCP Header");
|
||||
*bParseDone = TRUE;
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nTCP Header");
|
||||
*bParseDone = TRUE;
|
||||
break;
|
||||
|
||||
case UDP_HEADER_TYPE:
|
||||
{
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nUDP Header");
|
||||
*bParseDone = TRUE;
|
||||
}
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nUDP Header");
|
||||
*bParseDone = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
*bParseDone = TRUE;
|
||||
|
||||
}
|
||||
*bParseDone = TRUE;
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (*bParseDone == false) {
|
||||
@ -156,7 +151,9 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
|
||||
ucHeaderType = ucNextHeader;
|
||||
while (!bDone) {
|
||||
pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,
|
||||
&ucHeaderType, &bDone, &usPayloadLength);
|
||||
&ucHeaderType,
|
||||
&bDone,
|
||||
&usPayloadLength);
|
||||
if (bDone) {
|
||||
if ((ucHeaderType == TCP_HEADER_TYPE) ||
|
||||
(ucHeaderType == UDP_HEADER_TYPE)) {
|
||||
@ -177,11 +174,12 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
|
||||
|
||||
|
||||
/*
|
||||
* Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver contorl structure
|
||||
* Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver control
|
||||
* structure
|
||||
* Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
|
||||
*/
|
||||
USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
struct bcm_classifier_rule *pstClassifierRule)
|
||||
struct bcm_classifier_rule *pstClassifierRule)
|
||||
{
|
||||
USHORT ushDestPort = 0;
|
||||
USHORT ushSrcPort = 0;
|
||||
@ -200,11 +198,12 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
* Try to get the next higher layer protocol
|
||||
* and the Ports Nos if TCP or UDP
|
||||
*/
|
||||
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(struct bcm_ipv6_hdr)),
|
||||
&ushSrcPort,
|
||||
&ushDestPort,
|
||||
pstIpv6Header->usPayloadLength,
|
||||
pstIpv6Header->ucNextHeader);
|
||||
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader +
|
||||
sizeof(struct bcm_ipv6_hdr)),
|
||||
&ushSrcPort,
|
||||
&ushDestPort,
|
||||
pstIpv6Header->usPayloadLength,
|
||||
pstIpv6Header->ucNextHeader);
|
||||
|
||||
do {
|
||||
if (pstClassifierRule->ucDirection == 0) {
|
||||
@ -224,12 +223,12 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
}
|
||||
|
||||
bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule,
|
||||
pstIpv6Header);
|
||||
pstIpv6Header);
|
||||
if (!bClassificationSucceed)
|
||||
break;
|
||||
|
||||
bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule,
|
||||
pstIpv6Header);
|
||||
pstIpv6Header);
|
||||
if (!bClassificationSucceed)
|
||||
break;
|
||||
|
||||
@ -239,7 +238,7 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
* Chain of IPv6 prot headers
|
||||
*/
|
||||
bClassificationSucceed = MatchProtocol(pstClassifierRule,
|
||||
ucNextProtocolAboveIP);
|
||||
ucNextProtocolAboveIP);
|
||||
if (!bClassificationSucceed)
|
||||
break;
|
||||
|
||||
@ -253,7 +252,7 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",
|
||||
ntohs(ushSrcPort));
|
||||
bClassificationSucceed = MatchSrcPort(pstClassifierRule,
|
||||
ntohs(ushSrcPort));
|
||||
ntohs(ushSrcPort));
|
||||
if (!bClassificationSucceed)
|
||||
break;
|
||||
|
||||
@ -262,26 +261,27 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
|
||||
/* Match Dest Port */
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Destination Port:%x\n",
|
||||
ntohs(ushDestPort));
|
||||
bClassificationSucceed = MatchDestPort(pstClassifierRule,
|
||||
ntohs(ushDestPort));
|
||||
ntohs(ushDestPort));
|
||||
if (!bClassificationSucceed)
|
||||
break;
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
|
||||
DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
|
||||
DBG_LVL_ALL,
|
||||
"\nIPv6 Dest Port Matched");
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (bClassificationSucceed == TRUE) {
|
||||
INT iMatchedSFQueueIndex = 0;
|
||||
iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
|
||||
if (iMatchedSFQueueIndex >= NO_OF_QUEUES) {
|
||||
|
||||
iMatchedSFQueueIndex = SearchSfid(Adapter,
|
||||
pstClassifierRule->ulSFID);
|
||||
if ((iMatchedSFQueueIndex >= NO_OF_QUEUES) ||
|
||||
(Adapter->PackInfo[iMatchedSFQueueIndex].bActive == false))
|
||||
bClassificationSucceed = false;
|
||||
} else {
|
||||
if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == false)
|
||||
bClassificationSucceed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bClassificationSucceed;
|
||||
@ -289,18 +289,21 @@ USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader,
|
||||
|
||||
|
||||
static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
|
||||
struct bcm_ipv6_hdr *pstIpv6Header)
|
||||
struct bcm_ipv6_hdr *pstIpv6Header)
|
||||
{
|
||||
UINT uiLoopIndex = 0;
|
||||
UINT uiIpv6AddIndex = 0;
|
||||
UINT uiIpv6AddrNoLongWords = 4;
|
||||
ULONG aulSrcIP[4];
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
union u_ip_address *src_addr = &pstClassifierRule->stSrcIpAddress;
|
||||
|
||||
/*
|
||||
* This is the no. of Src Addresses ie Range of IP Addresses contained
|
||||
* in the classifier rule for which we need to match
|
||||
*/
|
||||
UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength;
|
||||
UINT uiCountIPSrcAddresses =
|
||||
(UINT)pstClassifierRule->ucIPSourceAddressLength;
|
||||
|
||||
|
||||
if (uiCountIPSrcAddresses == 0)
|
||||
@ -308,23 +311,31 @@ static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
|
||||
|
||||
|
||||
/* First Convert the Ip Address in the packet to Host Endian order */
|
||||
for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
|
||||
aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
|
||||
for (uiIpv6AddIndex = 0;
|
||||
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
|
||||
uiIpv6AddIndex++)
|
||||
aulSrcIP[uiIpv6AddIndex] =
|
||||
ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
|
||||
|
||||
for (uiLoopIndex = 0; uiLoopIndex < uiCountIPSrcAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
|
||||
for (uiLoopIndex = 0;
|
||||
uiLoopIndex < uiCountIPSrcAddresses;
|
||||
uiLoopIndex += uiIpv6AddrNoLongWords) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Src Ipv6 Address In Received Packet :\n ");
|
||||
DumpIpv6Address(aulSrcIP);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Src Ipv6 Mask In Classifier Rule:\n");
|
||||
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]);
|
||||
DumpIpv6Address(&src_addr->ulIpv6Mask[uiLoopIndex]);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Src Ipv6 Address In Classifier Rule :\n");
|
||||
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]);
|
||||
DumpIpv6Address(&src_addr->ulIpv6Addr[uiLoopIndex]);
|
||||
|
||||
for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
|
||||
if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
|
||||
!= pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
|
||||
for (uiIpv6AddIndex = 0;
|
||||
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
|
||||
uiIpv6AddIndex++) {
|
||||
if ((src_addr->ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] &
|
||||
aulSrcIP[uiIpv6AddIndex]) !=
|
||||
src_addr->ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
|
||||
/*
|
||||
* Match failed for current Ipv6 Address
|
||||
* Try next Ipv6 Address
|
||||
@ -345,43 +356,53 @@ static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
|
||||
}
|
||||
|
||||
static bool MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule,
|
||||
struct bcm_ipv6_hdr *pstIpv6Header)
|
||||
struct bcm_ipv6_hdr *pstIpv6Header)
|
||||
{
|
||||
UINT uiLoopIndex = 0;
|
||||
UINT uiIpv6AddIndex = 0;
|
||||
UINT uiIpv6AddrNoLongWords = 4;
|
||||
ULONG aulDestIP[4];
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
union u_ip_address *dest_addr = &pstClassifierRule->stDestIpAddress;
|
||||
|
||||
/*
|
||||
* This is the no. of Destination Addresses
|
||||
* ie Range of IP Addresses contained in the classifier rule
|
||||
* for which we need to match
|
||||
*/
|
||||
UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength;
|
||||
|
||||
UINT uiCountIPDestinationAddresses =
|
||||
(UINT)pstClassifierRule->ucIPDestinationAddressLength;
|
||||
|
||||
if (uiCountIPDestinationAddresses == 0)
|
||||
return TRUE;
|
||||
|
||||
|
||||
/* First Convert the Ip Address in the packet to Host Endian order */
|
||||
for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
|
||||
aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
|
||||
for (uiIpv6AddIndex = 0;
|
||||
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
|
||||
uiIpv6AddIndex++)
|
||||
aulDestIP[uiIpv6AddIndex] =
|
||||
ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
|
||||
|
||||
for (uiLoopIndex = 0; uiLoopIndex < uiCountIPDestinationAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
|
||||
for (uiLoopIndex = 0;
|
||||
uiLoopIndex < uiCountIPDestinationAddresses;
|
||||
uiLoopIndex += uiIpv6AddrNoLongWords) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Destination Ipv6 Address In Received Packet :\n ");
|
||||
DumpIpv6Address(aulDestIP);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Destination Ipv6 Mask In Classifier Rule :\n");
|
||||
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]);
|
||||
DumpIpv6Address(&dest_addr->ulIpv6Mask[uiLoopIndex]);
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"\n Destination Ipv6 Address In Classifier Rule :\n");
|
||||
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]);
|
||||
DumpIpv6Address(&dest_addr->ulIpv6Addr[uiLoopIndex]);
|
||||
|
||||
for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
|
||||
if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
|
||||
!= pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
|
||||
for (uiIpv6AddIndex = 0;
|
||||
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
|
||||
uiIpv6AddIndex++) {
|
||||
if ((dest_addr->ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] &
|
||||
aulDestIP[uiIpv6AddIndex]) !=
|
||||
dest_addr->ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
|
||||
/*
|
||||
* Match failed for current Ipv6 Address.
|
||||
* Try next Ipv6 Address
|
||||
@ -407,7 +428,10 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
|
||||
UINT uiIpv6AddrNoLongWords = 4;
|
||||
UINT uiIpv6AddIndex = 0;
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
|
||||
|
||||
for (uiIpv6AddIndex = 0;
|
||||
uiIpv6AddIndex < uiIpv6AddrNoLongWords;
|
||||
uiIpv6AddIndex++) {
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
":%lx", puIpv6Address[uiIpv6AddIndex]);
|
||||
}
|
||||
@ -419,6 +443,7 @@ static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header)
|
||||
UCHAR ucVersion;
|
||||
UCHAR ucPrio;
|
||||
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
|
||||
|
||||
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
|
||||
"----Ipv6 Header---");
|
||||
ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
|
||||
|
@ -244,6 +244,7 @@ static INT buffDnld(struct bcm_mini_adapter *Adapter,
|
||||
{
|
||||
unsigned int len = 0;
|
||||
int retval = STATUS_SUCCESS;
|
||||
|
||||
len = u32FirmwareLength;
|
||||
|
||||
while (u32FirmwareLength) {
|
||||
|
@ -28,28 +28,28 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *Adapter);
|
||||
static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter)
|
||||
{
|
||||
int i = 0;
|
||||
struct bcm_mini_adapter *ps_ad = psIntfAdapter->psAdapter;
|
||||
|
||||
/* Wake up the wait_queue... */
|
||||
if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running &
|
||||
if (ps_ad->LEDInfo.led_thread_running &
|
||||
BCM_LED_THREAD_RUNNING_ACTIVELY) {
|
||||
psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;
|
||||
wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);
|
||||
ps_ad->DriverState = DRIVER_HALT;
|
||||
wake_up(&ps_ad->LEDInfo.notify_led_event);
|
||||
}
|
||||
reset_card_proc(psIntfAdapter->psAdapter);
|
||||
reset_card_proc(ps_ad);
|
||||
|
||||
/*
|
||||
* worst case time taken by the RDM/WRM will be 5 sec. will check after
|
||||
* every 100 ms to accertain the device is not being accessed. After
|
||||
* this No RDM/WRM should be made.
|
||||
*/
|
||||
while (psIntfAdapter->psAdapter->DeviceAccess) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Device is being accessed.\n");
|
||||
while (ps_ad->DeviceAccess) {
|
||||
BCM_DEBUG_PRINT(ps_ad, DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL, "Device is being accessed.\n");
|
||||
msleep(100);
|
||||
}
|
||||
/* Free interrupt URB */
|
||||
/* psIntfAdapter->psAdapter->device_removed = TRUE; */
|
||||
/* ps_ad->device_removed = TRUE; */
|
||||
usb_free_urb(psIntfAdapter->psInterruptUrb);
|
||||
|
||||
/* Free transmit URBs */
|
||||
@ -67,10 +67,11 @@ static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter)
|
||||
psIntfAdapter->asUsbRcb[i].urb = NULL;
|
||||
}
|
||||
}
|
||||
AdapterFree(psIntfAdapter->psAdapter);
|
||||
AdapterFree(ps_ad);
|
||||
}
|
||||
|
||||
static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter)
|
||||
static void ConfigureEndPointTypesThroughEEPROM(
|
||||
struct bcm_mini_adapter *Adapter)
|
||||
{
|
||||
u32 ulReg;
|
||||
int bytes;
|
||||
@ -129,7 +130,10 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter
|
||||
ulReg &= 0x0101FFFF;
|
||||
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
|
||||
|
||||
/* Update length field if required. Also make the string NULL terminated. */
|
||||
/*
|
||||
* Update length field if required.
|
||||
* Also make the string NULL terminated.
|
||||
*/
|
||||
|
||||
ReadBeceemEEPROM(Adapter, 0xA8, &ulReg);
|
||||
if ((ulReg&0x00FF0000)>>16 > 0x30) {
|
||||
@ -147,7 +151,8 @@ static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter
|
||||
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
|
||||
}
|
||||
|
||||
static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
static int usbbcm_device_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
int retval;
|
||||
@ -338,16 +343,16 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter)
|
||||
{
|
||||
int value = 0;
|
||||
UINT status = STATUS_SUCCESS;
|
||||
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
|
||||
|
||||
status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
|
||||
status = InitCardAndDownloadFirmware(psAd);
|
||||
if (status != STATUS_SUCCESS) {
|
||||
pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
|
||||
return status;
|
||||
}
|
||||
if (psIntfAdapter->psAdapter->fw_download_done) {
|
||||
if (psAd->fw_download_done) {
|
||||
if (StartInterruptUrb(psIntfAdapter)) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Cannot send interrupt in URB\n");
|
||||
}
|
||||
@ -356,17 +361,15 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter)
|
||||
* now register the cntrl interface. after downloading the f/w
|
||||
* waiting for 5 sec to get the mailbox interrupt.
|
||||
*/
|
||||
psIntfAdapter->psAdapter->waiting_to_fw_download_done = false;
|
||||
value = wait_event_timeout(
|
||||
psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
|
||||
psIntfAdapter->psAdapter->waiting_to_fw_download_done,
|
||||
5 * HZ);
|
||||
psAd->waiting_to_fw_download_done = false;
|
||||
value = wait_event_timeout(psAd->ioctl_fw_dnld_wait_queue,
|
||||
psAd->waiting_to_fw_download_done,
|
||||
5 * HZ);
|
||||
|
||||
if (value == 0)
|
||||
pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
|
||||
|
||||
if (register_control_device_interface(
|
||||
psIntfAdapter->psAdapter) < 0) {
|
||||
if (register_control_device_interface(psAd) < 0) {
|
||||
pr_err(DRV_NAME ": Register Control Device failed.\n");
|
||||
return -EIO;
|
||||
}
|
||||
@ -374,6 +377,110 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int select_alternate_setting_for_highspeed_modem(
|
||||
struct bcm_interface_adapter *psIntfAdapter,
|
||||
struct usb_endpoint_descriptor **endpoint,
|
||||
const struct usb_host_interface *iface_desc,
|
||||
int *usedIntOutForBulkTransfer)
|
||||
{
|
||||
int retval = 0;
|
||||
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
|
||||
|
||||
/* selecting alternate setting one as a default setting
|
||||
* for High Speed modem. */
|
||||
if (psIntfAdapter->bHighSpeedDevice)
|
||||
retval = usb_set_interface(psIntfAdapter->udev,
|
||||
DEFAULT_SETTING_0,
|
||||
ALTERNATE_SETTING_1);
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
|
||||
"BCM16 is applicable on this dongle\n");
|
||||
if (retval || !psIntfAdapter->bHighSpeedDevice) {
|
||||
*usedIntOutForBulkTransfer = EP2;
|
||||
*endpoint = &iface_desc->endpoint[EP2].desc;
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
|
||||
/*
|
||||
* If Modem is high speed device EP2 should be
|
||||
* INT OUT End point
|
||||
*
|
||||
* If Mode is FS then EP2 should be bulk end
|
||||
* point
|
||||
*/
|
||||
if ((psIntfAdapter->bHighSpeedDevice &&
|
||||
!usb_endpoint_is_int_out(*endpoint)) ||
|
||||
(!psIntfAdapter->bHighSpeedDevice &&
|
||||
!usb_endpoint_is_bulk_out(*endpoint))) {
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Configuring the EEPROM\n");
|
||||
/* change the EP2, EP4 to INT OUT end point */
|
||||
ConfigureEndPointTypesThroughEEPROM(
|
||||
psAd);
|
||||
|
||||
/*
|
||||
* It resets the device and if any thing
|
||||
* gets changed in USB descriptor it
|
||||
* will show fail and re-enumerate the
|
||||
* device
|
||||
*/
|
||||
retval = usb_reset_device(psIntfAdapter->udev);
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"reset failed. Re-enumerating the device.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
if (!psIntfAdapter->bHighSpeedDevice &&
|
||||
usb_endpoint_is_bulk_out(*endpoint)) {
|
||||
/*
|
||||
* Once BULK is selected in FS mode.
|
||||
* Revert it back to INT.
|
||||
* Else USB_IF will fail.
|
||||
*/
|
||||
UINT _uiData = ntohl(EP2_CFG_INT);
|
||||
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Reverting Bulk to INT as it is in Full Speed mode.\n");
|
||||
BeceemEEPROMBulkWrite(psAd, (PUCHAR) & _uiData, 0x136,
|
||||
4, TRUE);
|
||||
}
|
||||
} else {
|
||||
*usedIntOutForBulkTransfer = EP4;
|
||||
*endpoint = &iface_desc->endpoint[EP4].desc;
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Choosing AltSetting as a default setting.\n");
|
||||
if (!usb_endpoint_is_int_out(*endpoint)) {
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Dongle does not have BCM16 Fix.\n");
|
||||
/*
|
||||
* change the EP2, EP4 to INT OUT end point and use EP4
|
||||
* in altsetting
|
||||
*/
|
||||
ConfigureEndPointTypesThroughEEPROM(psAd);
|
||||
|
||||
/*
|
||||
* It resets the device and if any thing
|
||||
* gets changed in USB descriptor it
|
||||
* will show fail and re-enumerate the
|
||||
* device
|
||||
*/
|
||||
retval = usb_reset_device(psIntfAdapter->udev);
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"reset failed. Re-enumerating the device.\n");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
|
||||
{
|
||||
struct usb_host_interface *iface_desc;
|
||||
@ -385,6 +492,7 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
|
||||
bool bBcm16 = false;
|
||||
UINT uiData = 0;
|
||||
int bytes;
|
||||
struct bcm_mini_adapter *psAd = psIntfAdapter->psAdapter;
|
||||
|
||||
/* Store the usb dev into interface adapter */
|
||||
psIntfAdapter->udev =
|
||||
@ -392,141 +500,43 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
|
||||
|
||||
psIntfAdapter->bHighSpeedDevice =
|
||||
(psIntfAdapter->udev->speed == USB_SPEED_HIGH);
|
||||
psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
|
||||
psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
|
||||
psAd->interface_rdm = BcmRDM;
|
||||
psAd->interface_wrm = BcmWRM;
|
||||
|
||||
bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,
|
||||
(u32 *) &(psIntfAdapter->psAdapter->chip_id),
|
||||
sizeof(u32));
|
||||
bytes = rdmalt(psAd, CHIP_ID_REG, (u32 *) &(psAd->chip_id),
|
||||
sizeof(u32));
|
||||
if (bytes < 0) {
|
||||
retval = bytes;
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
|
||||
"CHIP ID Read Failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
|
||||
psIntfAdapter->psAdapter->chip_id &= ~0xF0;
|
||||
if (0xbece3200 == (psAd->chip_id & ~(0xF0)))
|
||||
psAd->chip_id &= ~0xF0;
|
||||
|
||||
dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
|
||||
psIntfAdapter->psAdapter->chip_id);
|
||||
psAd->chip_id);
|
||||
|
||||
iface_desc = psIntfAdapter->interface->cur_altsetting;
|
||||
|
||||
if (psIntfAdapter->psAdapter->chip_id == T3B) {
|
||||
if (psAd->chip_id == T3B) {
|
||||
/* T3B device will have EEPROM, check if EEPROM is proper and
|
||||
* BCM16 can be done or not. */
|
||||
BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
|
||||
BeceemEEPROMBulkRead(psAd, &uiData, 0x0, 4);
|
||||
if (uiData == BECM)
|
||||
bBcm16 = TRUE;
|
||||
|
||||
dev_info(&psIntfAdapter->udev->dev,
|
||||
"number of alternate setting %d\n",
|
||||
psIntfAdapter->interface->num_altsetting);
|
||||
"number of alternate setting %d\n",
|
||||
psIntfAdapter->interface->num_altsetting);
|
||||
|
||||
if (bBcm16 == TRUE) {
|
||||
/* selecting alternate setting one as a default setting
|
||||
* for High Speed modem. */
|
||||
if (psIntfAdapter->bHighSpeedDevice)
|
||||
retval = usb_set_interface(psIntfAdapter->udev,
|
||||
DEFAULT_SETTING_0,
|
||||
ALTERNATE_SETTING_1);
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"BCM16 is applicable on this dongle\n");
|
||||
if (retval || !psIntfAdapter->bHighSpeedDevice) {
|
||||
usedIntOutForBulkTransfer = EP2;
|
||||
endpoint = &iface_desc->endpoint[EP2].desc;
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
|
||||
/*
|
||||
* If Modem is high speed device EP2 should be
|
||||
* INT OUT End point
|
||||
*
|
||||
* If Mode is FS then EP2 should be bulk end
|
||||
* point
|
||||
*/
|
||||
if ((psIntfAdapter->bHighSpeedDevice &&
|
||||
!usb_endpoint_is_int_out(endpoint)) ||
|
||||
(!psIntfAdapter->bHighSpeedDevice &&
|
||||
!usb_endpoint_is_bulk_out(endpoint))) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Configuring the EEPROM\n");
|
||||
/* change the EP2, EP4 to INT OUT end point */
|
||||
ConfigureEndPointTypesThroughEEPROM(
|
||||
psIntfAdapter->psAdapter);
|
||||
|
||||
/*
|
||||
* It resets the device and if any thing
|
||||
* gets changed in USB descriptor it
|
||||
* will show fail and re-enumerate the
|
||||
* device
|
||||
*/
|
||||
retval = usb_reset_device(
|
||||
psIntfAdapter->udev);
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"reset failed. Re-enumerating the device.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
if (!psIntfAdapter->bHighSpeedDevice &&
|
||||
usb_endpoint_is_bulk_out(endpoint)) {
|
||||
/* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
|
||||
UINT _uiData = ntohl(EP2_CFG_INT);
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Reverting Bulk to INT as it is in Full Speed mode.\n");
|
||||
BeceemEEPROMBulkWrite(
|
||||
psIntfAdapter->psAdapter,
|
||||
(PUCHAR) & _uiData,
|
||||
0x136, 4, TRUE);
|
||||
}
|
||||
} else {
|
||||
usedIntOutForBulkTransfer = EP4;
|
||||
endpoint = &iface_desc->endpoint[EP4].desc;
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT, DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"Choosing AltSetting as a default setting.\n");
|
||||
if (!usb_endpoint_is_int_out(endpoint)) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY, DBG_LVL_ALL,
|
||||
"Dongle does not have BCM16 Fix.\n");
|
||||
/* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
|
||||
ConfigureEndPointTypesThroughEEPROM(
|
||||
psIntfAdapter->psAdapter);
|
||||
|
||||
/*
|
||||
* It resets the device and if any thing
|
||||
* gets changed in USB descriptor it
|
||||
* will show fail and re-enumerate the
|
||||
* device
|
||||
*/
|
||||
retval = usb_reset_device(
|
||||
psIntfAdapter->udev);
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,
|
||||
DBG_TYPE_INITEXIT,
|
||||
DRV_ENTRY,
|
||||
DBG_LVL_ALL,
|
||||
"reset failed. Re-enumerating the device.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
retval = select_alternate_setting_for_highspeed_modem(
|
||||
psIntfAdapter, &endpoint, iface_desc,
|
||||
&usedIntOutForBulkTransfer);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,9 +582,12 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
|
||||
if (!psIntfAdapter->sIntrOut.int_out_endpointAddr &&
|
||||
usb_endpoint_is_int_out(endpoint)) {
|
||||
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
|
||||
(psIntfAdapter->psAdapter->chip_id == T3B) &&
|
||||
(psAd->chip_id == T3B) &&
|
||||
(value == usedIntOutForBulkTransfer)) {
|
||||
/* use first intout end point as a bulk out end point */
|
||||
/*
|
||||
* use first intout end point as a bulk out end
|
||||
* point
|
||||
*/
|
||||
buffer_size =
|
||||
le16_to_cpu(endpoint->wMaxPacketSize);
|
||||
psIntfAdapter->sBulkOut.bulk_out_size =
|
||||
@ -606,15 +619,14 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter)
|
||||
|
||||
usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
|
||||
|
||||
psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
|
||||
psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
|
||||
InterfaceFileReadbackFromChip;
|
||||
psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
|
||||
psAd->bcm_file_download = InterfaceFileDownload;
|
||||
psAd->bcm_file_readback_from_chip = InterfaceFileReadbackFromChip;
|
||||
psAd->interface_transmit = InterfaceTransmitPacket;
|
||||
|
||||
retval = CreateInterruptUrb(psIntfAdapter);
|
||||
|
||||
if (retval) {
|
||||
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
|
||||
BCM_DEBUG_PRINT(psAd, DBG_TYPE_PRINTK, 0, 0,
|
||||
"Cannot create interrupt urb\n");
|
||||
return retval;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user