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

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

Pull staging driver tree update from Greg Kroah-Hartman:
 "Here's the big staging driver tree update for 3.10-rc1

  This update contains loads of comedi driver cleanups and fixes in
  here, iio updates, android driver changes, and other various staging
  driver cleanups.

  Thanks to some drivers being removed, and the comedi driver cleanups,
  we have removed more code than we added:

   627 files changed, 65145 insertions(+), 76321 deletions(-)

  which is always nice to see.

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

* tag 'staging-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (940 commits)
  staging: comedi: ni_labpc: fix legacy driver build
  staging: comedi: das800: cleanup the cio-das802/16 fifo comments
  staging: comedi: das800: rename CamelCase vars in das800_ai_do_cmd()
  staging: comedi: das800: tidy up the private data
  staging: comedi: das800: tidy up das800_interrupt()
  staging: comedi: das800: tidy up das800_ai_insn_read()
  staging: comedi: das800: tidy up das800_di_insn_bits()
  staging: comedi: das800: tidy up das800_do_insn_bits()
  staging: comedi: das800: remove extra divisor calculation call
  staging: comedi: das800: rename {enable,disable}_das800
  staging: comedi: das800: tidy up subdevice init
  staging: comedi: das800: allow attaching without interrupt support
  staging: comedi: das800: interrupts are required for async command support
  staging: comedi: das800: tidy up das800_ai_do_cmdtest()
  staging: comedi: das800: remove 'volatile' on private data variables
  staging: comedi: das800: cleanup the boardinfo
  staging: comedi: das800: cleanup range table declarations
  staging: comedi: das800: introduce das800_ind_{write, read}()
  staging: comedi: das800: remove forward declarations
  staging: comedi: das800: move das800_set_frequency()
  ...
...@@ -14,9 +14,19 @@ Required properties: ...@@ -14,9 +14,19 @@ Required properties:
- atmel,adc-status-register: Offset of the Interrupt Status Register - atmel,adc-status-register: Offset of the Interrupt Status Register
- atmel,adc-trigger-register: Offset of the Trigger Register - atmel,adc-trigger-register: Offset of the Trigger Register
- atmel,adc-vref: Reference voltage in millivolts for the conversions - atmel,adc-vref: Reference voltage in millivolts for the conversions
- atmel,adc-res: List of resolution in bits supported by the ADC. List size
must be two at least.
- atmel,adc-res-names: Contains one identifier string for each resolution
in atmel,adc-res property. "lowres" and "highres"
identifiers are required.
Optional properties: Optional properties:
- atmel,adc-use-external: Boolean to enable of external triggers - atmel,adc-use-external: Boolean to enable of external triggers
- atmel,adc-use-res: String corresponding to an identifier from
atmel,adc-res-names property. If not specified, the highest
resolution will be used.
- atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
- atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
Optional trigger Nodes: Optional trigger Nodes:
- Required properties: - Required properties:
...@@ -40,6 +50,9 @@ adc0: adc@fffb0000 { ...@@ -40,6 +50,9 @@ adc0: adc@fffb0000 {
atmel,adc-trigger-register = <0x08>; atmel,adc-trigger-register = <0x08>;
atmel,adc-use-external; atmel,adc-use-external;
atmel,adc-vref = <3300>; atmel,adc-vref = <3300>;
atmel,adc-res = <8 10>;
atmel,adc-res-names = "lowres", "highres";
atmel,adc-use-res = "lowres";
trigger@0 { trigger@0 {
trigger-name = "external-rising"; trigger-name = "external-rising";
......
Samsung Exynos Analog to Digital Converter bindings
The devicetree bindings are for the new ADC driver written for
Exynos4 and upward SoCs from Samsung.
New driver handles the following
1. Supports ADC IF found on EXYNOS4412/EXYNOS5250
and future SoCs from Samsung
2. Add ADC driver under iio/adc framework
3. Also adds the Documentation for device tree bindings
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
for exynos4412/5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
- 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".
- vdd-supply VDD input supply.
Note: child nodes can be added for auto probing from device tree.
Example: adding device info in dtsi file
adc: adc@12D10000 {
compatible = "samsung,exynos-adc-v1";
reg = <0x12D10000 0x100>, <0x10040718 0x4>;
interrupts = <0 106 0>;
#io-channel-cells = <1>;
io-channel-ranges;
clocks = <&clock 303>;
clock-names = "adc";
vdd-supply = <&buck5_reg>;
};
Example: Adding child nodes in dts file
adc@12D10000 {
/* NTC thermistor is a hwmon device */
ncp15wb473@0 {
compatible = "ntc,ncp15wb473";
pullup-uV = <1800000>;
pullup-ohm = <47000>;
pulldown-ohm = <0>;
io-channels = <&adc 4>;
};
};
Note: Does not apply to ADC driver under arch/arm/plat-samsung/
Note: The child node can be added under the adc node or separately.
This binding is derived from clock bindings, and based on suggestions
from Lars-Peter Clausen [1].
Sources of IIO channels can be represented by any node in the device
tree. Those nodes are designated as IIO providers. IIO consumer
nodes use a phandle and IIO specifier pair to connect IIO provider
outputs to IIO inputs. Similar to the gpio specifiers, an IIO
specifier is an array of one or more cells identifying the IIO
output on a device. The length of an IIO specifier is defined by the
value of a #io-channel-cells property in the IIO provider node.
[1] http://marc.info/?l=linux-iio&m=135902119507483&w=2
==IIO providers==
Required properties:
#io-channel-cells: Number of cells in an IIO specifier; Typically 0 for nodes
with a single IIO output and 1 for nodes with multiple
IIO outputs.
Example for a simple configuration with no trigger:
adc: voltage-sensor@35 {
compatible = "maxim,max1139";
reg = <0x35>;
#io-channel-cells = <1>;
};
Example for a configuration with trigger:
adc@35 {
compatible = "some-vendor,some-adc";
reg = <0x35>;
adc1: iio-device@0 {
#io-channel-cells = <1>;
/* other properties */
};
adc2: iio-device@1 {
#io-channel-cells = <1>;
/* other properties */
};
};
==IIO consumers==
Required properties:
io-channels: List of phandle and IIO specifier pairs, one pair
for each IIO input to the device. Note: if the
IIO provider specifies '0' for #io-channel-cells,
then only the phandle portion of the pair will appear.
Optional properties:
io-channel-names:
List of IIO input name strings sorted in the same
order as the io-channels property. Consumers drivers
will use io-channel-names to match IIO input names
with IIO specifiers.
io-channel-ranges:
Empty property indicating that child nodes can inherit named
IIO channels from this node. Useful for bus nodes to provide
and IIO channel to their children.
For example:
device {
io-channels = <&adc 1>, <&ref 0>;
io-channel-names = "vcc", "vdd";
};
This represents a device with two IIO inputs, named "vcc" and "vdd".
The vcc channel is connected to output 1 of the &adc device, and the
vdd channel is connected to output 0 of the &ref device.
==Example==
adc: max1139@35 {
compatible = "maxim,max1139";
reg = <0x35>;
#io-channel-cells = <1>;
};
...
iio_hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 0>, <&adc 1>, <&adc 2>,
<&adc 3>, <&adc 4>, <&adc 5>,
<&adc 6>, <&adc 7>, <&adc 8>,
<&adc 9>;
};
some_consumer {
compatible = "some-consumer";
io-channels = <&adc 10>, <&adc 11>;
io-channel-names = "adc1", "adc2";
};
Platform DesignWare HS OTG USB 2.0 controller
-----------------------------------------------------
Required properties:
- compatible : "snps,dwc2"
- reg : Should contain 1 register range (address and length)
- interrupts : Should contain 1 interrupt
Example:
usb@101c0000 {
compatible = "ralink,rt3050-usb, snps,dwc2";
reg = <0x101c0000 40000>;
interrupts = <18>;
};
...@@ -26,7 +26,7 @@ Required properties: ...@@ -26,7 +26,7 @@ Required properties:
- crtc: the crtc this display is connected to, see below - crtc: the crtc this display is connected to, see below
Optional properties: Optional properties:
- interface_pix_fmt: How this display is connected to the - interface_pix_fmt: How this display is connected to the
crtc. Currently supported types: "rgb24", "rgb565" crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
- edid: verbatim EDID data block describing attached display. - edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data - ddc: phandle describing the i2c bus handling the display data
channel channel
......
...@@ -2459,6 +2459,12 @@ M: Matthew Garrett <mjg59@srcf.ucam.org> ...@@ -2459,6 +2459,12 @@ M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained S: Maintained
F: drivers/platform/x86/dell-wmi.c F: drivers/platform/x86/dell-wmi.c
DESIGNWARE USB2 DRD IP DRIVER
M: Paul Zimmerman <paulz@synopsys.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/staging/dwc2/
DESIGNWARE USB3 DRD IP DRIVER DESIGNWARE USB3 DRD IP DRIVER
M: Felipe Balbi <balbi@ti.com> M: Felipe Balbi <balbi@ti.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
...@@ -7933,6 +7939,12 @@ T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git ...@@ -7933,6 +7939,12 @@ T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
S: Maintained S: Maintained
F: drivers/platform/x86/thinkpad_acpi.c F: drivers/platform/x86/thinkpad_acpi.c
TI BANDGAP AND THERMAL DRIVER
M: Eduardo Valentin <eduardo.valentin@ti.com>
L: linux-pm@vger.kernel.org
S: Maintained
F: drivers/staging/omap-thermal/
TI FLASH MEDIA INTERFACE DRIVER TI FLASH MEDIA INTERFACE DRIVER
M: Alex Dubov <oakad@yahoo.com> M: Alex Dubov <oakad@yahoo.com>
S: Maintained S: Maintained
......
...@@ -519,6 +519,15 @@ config SENSORS_IBMPEX ...@@ -519,6 +519,15 @@ config SENSORS_IBMPEX
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called ibmpex. will be called ibmpex.
config SENSORS_IIO_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on IIO
help
This is a platform driver that in combination with a suitable
map allows IIO devices to provide basic hwmon functionality
for those channels specified in the map. This map can be provided
either via platform data or the device tree bindings.
config SENSORS_IT87 config SENSORS_IT87
tristate "ITE IT87xx and compatibles" tristate "ITE IT87xx and compatibles"
depends on !PPC depends on !PPC
......
...@@ -67,6 +67,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o ...@@ -67,6 +67,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
obj-$(CONFIG_SENSORS_INA209) += ina209.o obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_IT87) += it87.o
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/of.h>
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/iio/consumer.h> #include <linux/iio/consumer.h>
#include <linux/iio/types.h> #include <linux/iio/types.h>
...@@ -58,7 +59,12 @@ static ssize_t iio_hwmon_read_val(struct device *dev, ...@@ -58,7 +59,12 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
static ssize_t show_name(struct device *dev, struct device_attribute *attr, static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "iio_hwmon\n"); const char *name = "iio_hwmon";
if (dev->of_node && dev->of_node->name)
name = dev->of_node->name;
return sprintf(buf, "%s\n", name);
} }
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
......
...@@ -60,28 +60,28 @@ static const struct iio_chan_spec accel_3d_channels[] = { ...@@ -60,28 +60,28 @@ static const struct iio_chan_spec accel_3d_channels[] = {
.type = IIO_ACCEL, .type = IIO_ACCEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_X, .channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X, .scan_index = CHANNEL_SCAN_INDEX_X,
}, { }, {
.type = IIO_ACCEL, .type = IIO_ACCEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Y, .channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y, .scan_index = CHANNEL_SCAN_INDEX_Y,
}, { }, {
.type = IIO_ACCEL, .type = IIO_ACCEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} }
}; };
......
...@@ -177,8 +177,8 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev, ...@@ -177,8 +177,8 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
.type = IIO_ACCEL, \ .type = IIO_ACCEL, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_##axis, \ .channel2 = IIO_MOD_##axis, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = KXSD9_REG_##axis, \ .address = KXSD9_REG_##axis, \
} }
...@@ -186,7 +186,7 @@ static const struct iio_chan_spec kxsd9_channels[] = { ...@@ -186,7 +186,7 @@ static const struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z), KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
{ {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.indexed = 1, .indexed = 1,
.address = KXSD9_REG_AUX, .address = KXSD9_REG_AUX,
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
int st_accel_trig_set_state(struct iio_trigger *trig, bool state) int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
{ {
struct iio_dev *indio_dev = trig->private_data; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state); return st_sensors_set_dataready_irq(indio_dev, state);
} }
......
...@@ -30,6 +30,18 @@ config AD7298 ...@@ -30,6 +30,18 @@ config AD7298
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad7298. module will be called ad7298.
config AD7923
tristate "Analog Devices AD7923 and similar ADCs driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices
AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
To compile this driver as a module, choose M here: the
module will be called ad7923.
config AD7791 config AD7791
tristate "Analog Devices AD7791 ADC driver" tristate "Analog Devices AD7791 ADC driver"
depends on SPI depends on SPI
...@@ -91,6 +103,14 @@ config AT91_ADC ...@@ -91,6 +103,14 @@ config AT91_ADC
help help
Say yes here to build support for Atmel AT91 ADC. Say yes here to build support for Atmel AT91 ADC.
config EXYNOS_ADC
bool "Exynos ADC driver support"
depends on OF
help
Core support for the ADC block found in the Samsung EXYNOS series
of SoCs for drivers such as the touchscreen and hwmon to use to share
this resource.
config LP8788_ADC config LP8788_ADC
bool "LP8788 ADC driver" bool "LP8788 ADC driver"
depends on MFD_LP8788 depends on MFD_LP8788
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
......
...@@ -201,9 +201,9 @@ static int ad7266_read_raw(struct iio_dev *indio_dev, ...@@ -201,9 +201,9 @@ static int ad7266_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \ .indexed = 1, \
.channel = (_chan), \ .channel = (_chan), \
.address = (_chan), \ .address = (_chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
| IIO_CHAN_INFO_SCALE_SHARED_BIT \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \ .scan_index = (_chan), \
.scan_type = { \ .scan_type = { \
.sign = (_sign), \ .sign = (_sign), \
...@@ -249,9 +249,9 @@ static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's'); ...@@ -249,9 +249,9 @@ static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's');
.channel = (_chan) * 2, \ .channel = (_chan) * 2, \
.channel2 = (_chan) * 2 + 1, \ .channel2 = (_chan) * 2 + 1, \
.address = (_chan), \ .address = (_chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
| IIO_CHAN_INFO_SCALE_SHARED_BIT \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \ .scan_index = (_chan), \
.scan_type = { \ .scan_type = { \
.sign = _sign, \ .sign = _sign, \
......
...@@ -63,8 +63,8 @@ struct ad7298_state { ...@@ -63,8 +63,8 @@ struct ad7298_state {
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = index, \ .channel = index, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \ .address = index, \
.scan_index = index, \ .scan_index = index, \
.scan_type = { \ .scan_type = { \
...@@ -80,9 +80,9 @@ static const struct iio_chan_spec ad7298_channels[] = { ...@@ -80,9 +80,9 @@ static const struct iio_chan_spec ad7298_channels[] = {
.type = IIO_TEMP, .type = IIO_TEMP,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, BIT(IIO_CHAN_INFO_OFFSET),
.address = AD7298_CH_TEMP, .address = AD7298_CH_TEMP,
.scan_index = -1, .scan_index = -1,
.scan_type = { .scan_type = {
......
...@@ -140,12 +140,12 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, ...@@ -140,12 +140,12 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
#define _AD7476_CHAN(bits, _shift, _info_mask) \ #define _AD7476_CHAN(bits, _shift, _info_mask_sep) \
{ \ { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.info_mask = _info_mask | \ .info_mask_separate = _info_mask_sep, \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
.realbits = (bits), \ .realbits = (bits), \
...@@ -156,9 +156,9 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, ...@@ -156,9 +156,9 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
} }
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \ #define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT) BIT(IIO_CHAN_INFO_RAW))
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ #define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
IIO_CHAN_INFO_RAW_SEPARATE_BIT) BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0) #define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
......
...@@ -207,8 +207,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { ...@@ -207,8 +207,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.indexed = 1, .indexed = 1,
.channel = 1, .channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
IIO_CHAN_INFO_SCALE_SHARED_BIT, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1, .address = 1,
.scan_index = 1, .scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0), .scan_type = IIO_ST('u', 12, 16, 0),
...@@ -217,8 +217,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { ...@@ -217,8 +217,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
IIO_CHAN_INFO_SCALE_SHARED_BIT, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0, .address = 0,
.scan_index = 0, .scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0), .scan_type = IIO_ST('u', 12, 16, 0),
......
/*
* AD7904/AD7914/AD7923/AD7924 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
*
* Licensed under the GPL-2.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define AD7923_WRITE_CR (1 << 11) /* write control register */
#define AD7923_RANGE (1 << 1) /* range to REFin */
#define AD7923_CODING (1 << 0) /* coding is straight binary */
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
#define AD7923_CHANNEL_0 (0) /* analog input 0 */
#define AD7923_CHANNEL_1 (1) /* analog input 1 */
#define AD7923_CHANNEL_2 (2) /* analog input 2 */
#define AD7923_CHANNEL_3 (3) /* analog input 3 */
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
#define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */
#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \
+ ((sequence & 2) << 9))
/* write sequence fonction */
/* left shift for CR : bit 11 transmit in first */
#define AD7923_SHIFT_REGISTER 4
/* val = value, dec = left shift, bits = number of bits of the mask */
#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1))
struct ad7923_state {
struct spi_device *spi;
struct spi_transfer ring_xfer[5];
struct spi_transfer scan_single_xfer[2];
struct spi_message ring_msg;
struct spi_message scan_single_msg;
struct regulator *reg;
unsigned int settings;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
__be16 rx_buf[4] ____cacheline_aligned;
__be16 tx_buf[4];
};
struct ad7923_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
enum ad7923_id {
AD7904,
AD7914,
AD7924,
};
#define AD7923_V_CHAN(index, bits) \
{ \
.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), \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
#define DECLARE_AD7923_CHANNELS(name, bits) \
const struct iio_chan_spec name ## _channels[] = { \
AD7923_V_CHAN(0, bits), \
AD7923_V_CHAN(1, bits), \
AD7923_V_CHAN(2, bits), \
AD7923_V_CHAN(3, bits), \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
static DECLARE_AD7923_CHANNELS(ad7904, 8);
static DECLARE_AD7923_CHANNELS(ad7914, 10);
static DECLARE_AD7923_CHANNELS(ad7924, 12);
static const struct ad7923_chip_info ad7923_chip_info[] = {
[AD7904] = {
.channels = ad7904_channels,
.num_channels = ARRAY_SIZE(ad7904_channels),
},
[AD7914] = {
.channels = ad7914_channels,
.num_channels = ARRAY_SIZE(ad7914_channels),
},
[AD7924] = {
.channels = ad7924_channels,
.num_channels = ARRAY_SIZE(ad7924_channels),
},
};
/**
* ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/
static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask)
{
struct ad7923_state *st = iio_priv(indio_dev);
int i, cmd, len;
len = 0;
for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[len++] = cpu_to_be16(cmd);
}
/* build spi ring message */
st->ring_xfer[0].tx_buf = &st->tx_buf[0];
st->ring_xfer[0].len = len;
st->ring_xfer[0].cs_change = 1;
spi_message_init(&st->ring_msg);
spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
for (i = 0; i < len; i++) {
st->ring_xfer[i + 1].rx_buf = &st->rx_buf[i];
st->ring_xfer[i + 1].len = 2;
st->ring_xfer[i + 1].cs_change = 1;
spi_message_add_tail(&st->ring_xfer[i + 1], &st->ring_msg);
}
/* make sure last transfer cs_change is not set */
st->ring_xfer[i + 1].cs_change = 0;
return 0;
}
/**
* ad7923_trigger_handler() bh of trigger launched polling to ring buffer
*
* Currently there is no option in this driver to disable the saving of
* timestamps within the ring.
**/
static irqreturn_t ad7923_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7923_state *st = iio_priv(indio_dev);
s64 time_ns = 0;
int b_sent;
b_sent = spi_sync(st->spi, &st->ring_msg);
if (b_sent)
goto done;
if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
{
int ret, cmd;
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(ch) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
cmd <<= AD7923_SHIFT_REGISTER;
st->tx_buf[0] = cpu_to_be16(cmd);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
return be16_to_cpu(st->rx_buf[0]);
}
static int ad7923_get_range(struct ad7923_state *st)
{
int vref;
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
vref /= 1000;
if (!(st->settings & AD7923_RANGE))
vref *= 2;
return vref;
}
static int ad7923_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret;
struct ad7923_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7923_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
if (chan->address == EXTRACT(ret, 12, 4))
*val = EXTRACT(ret, 0, 12);
else
return -EIO;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = ad7923_get_range(st);
if (ret < 0)
return ret;
*val = ret;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info ad7923_info = {
.read_raw = &ad7923_read_raw,
.update_scan_mode = ad7923_update_scan_mode,
.driver_module = THIS_MODULE,
};
static int ad7923_probe(struct spi_device *spi)
{
struct ad7923_state *st;
struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
const struct ad7923_chip_info *info;
int ret;
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->settings = AD7923_CODING | AD7923_RANGE |
AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS);
info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data];
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->channels;
indio_dev->num_channels = info->num_channels;
indio_dev->info = &ad7923_info;
/* Setup default message */
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[1].len = 2;
spi_message_init(&st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
st->reg = regulator_get(&spi->dev, "refin");
if (IS_ERR(st->reg)) {
ret = PTR_ERR(st->reg);
goto error_free;
}
ret = regulator_enable(st->reg);
if (ret)
goto error_put_reg;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7923_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_ring;
return 0;
error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
error_put_reg:
regulator_put(st->reg);
error_free:
iio_device_free(indio_dev);
return ret;
}
static int ad7923_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7923_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
regulator_put(st->reg);
iio_device_free(indio_dev);
return 0;
}
static const struct spi_device_id ad7923_id[] = {
{"ad7904", AD7904},
{"ad7914", AD7914},
{"ad7923", AD7924},
{"ad7924", AD7924},
{}
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
static struct spi_driver ad7923_driver = {
.driver = {
.name = "ad7923",
.owner = THIS_MODULE,
},
.probe = ad7923_probe,
.remove = ad7923_remove,
.id_table = ad7923_id,
};
module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_LICENSE("GPL v2");
...@@ -470,7 +470,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev) ...@@ -470,7 +470,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
disable_irq_nosync(sigma_delta->spi->irq); disable_irq_nosync(sigma_delta->spi->irq);
} }
sigma_delta->trig->dev.parent = &sigma_delta->spi->dev; sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
sigma_delta->trig->private_data = sigma_delta; iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
ret = iio_trigger_register(sigma_delta->trig); ret = iio_trigger_register(sigma_delta->trig);
if (ret) if (ret)
......
...@@ -52,11 +52,15 @@ struct at91_adc_state { ...@@ -52,11 +52,15 @@ struct at91_adc_state {
void __iomem *reg_base; void __iomem *reg_base;
struct at91_adc_reg_desc *registers; struct at91_adc_reg_desc *registers;
u8 startup_time; u8 startup_time;
u8 sample_hold_time;
bool sleep_mode;
struct iio_trigger **trig; struct iio_trigger **trig;
struct at91_adc_trigger *trigger_list; struct at91_adc_trigger *trigger_list;
u32 trigger_number; u32 trigger_number;
bool use_external; bool use_external;
u32 vref_mv; u32 vref_mv;
u32 res; /* resolution used for convertions */
bool low_res; /* the resolution corresponds to the lowest one */
wait_queue_head_t wq_data_avail; wait_queue_head_t wq_data_avail;
}; };
...@@ -138,10 +142,10 @@ static int at91_adc_channel_init(struct iio_dev *idev) ...@@ -138,10 +142,10 @@ static int at91_adc_channel_init(struct iio_dev *idev)
chan->channel = bit; chan->channel = bit;
chan->scan_index = idx; chan->scan_index = idx;
chan->scan_type.sign = 'u'; chan->scan_type.sign = 'u';
chan->scan_type.realbits = 10; chan->scan_type.realbits = st->res;
chan->scan_type.storagebits = 16; chan->scan_type.storagebits = 16;
chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
IIO_CHAN_INFO_RAW_SEPARATE_BIT; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
idx++; idx++;
} }
timestamp = chan_array + idx; timestamp = chan_array + idx;
...@@ -188,7 +192,7 @@ static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev, ...@@ -188,7 +192,7 @@ static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{ {
struct iio_dev *idev = trig->private_data; struct iio_dev *idev = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(idev); struct at91_adc_state *st = iio_priv(idev);
struct iio_buffer *buffer = idev->buffer; struct iio_buffer *buffer = idev->buffer;
struct at91_adc_reg_desc *reg = st->registers; struct at91_adc_reg_desc *reg = st->registers;
...@@ -254,7 +258,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev, ...@@ -254,7 +258,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
return NULL; return NULL;
trig->dev.parent = idev->dev.parent; trig->dev.parent = idev->dev.parent;
trig->private_data = idev; iio_trigger_set_drvdata(trig, idev);
trig->ops = &at91_adc_trigger_ops; trig->ops = &at91_adc_trigger_ops;
ret = iio_trigger_register(trig); ret = iio_trigger_register(trig);
...@@ -372,6 +376,59 @@ static int at91_adc_read_raw(struct iio_dev *idev, ...@@ -372,6 +376,59 @@ static int at91_adc_read_raw(struct iio_dev *idev,
return -EINVAL; return -EINVAL;
} }
static int at91_adc_of_get_resolution(struct at91_adc_state *st,
struct platform_device *pdev)
{
struct iio_dev *idev = iio_priv_to_dev(st);
struct device_node *np = pdev->dev.of_node;
int count, i, ret = 0;
char *res_name, *s;
u32 *resolutions;
count = of_property_count_strings(np, "atmel,adc-res-names");
if (count < 2) {
dev_err(&idev->dev, "You must specified at least two resolution names for "
"adc-res-names property in the DT\n");
return count;
}
resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
if (!resolutions)
return -ENOMEM;
if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) {
dev_err(&idev->dev, "Missing adc-res property in the DT.\n");
ret = -ENODEV;
goto ret;
}
if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name))
res_name = "highres";
for (i = 0; i < count; i++) {
if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s))
continue;
if (strcmp(res_name, s))
continue;
st->res = resolutions[i];
if (!strcmp(res_name, "lowres"))
st->low_res = true;
else
st->low_res = false;
dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
goto ret;
}
dev_err(&idev->dev, "There is no resolution for %s\n", res_name);
ret:
kfree(resolutions);
return ret;
}
static int at91_adc_probe_dt(struct at91_adc_state *st, static int at91_adc_probe_dt(struct at91_adc_state *st,
struct platform_device *pdev) struct platform_device *pdev)
{ {
...@@ -400,6 +457,8 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, ...@@ -400,6 +457,8 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
} }
st->num_channels = prop; st->num_channels = prop;
st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) { if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n"); dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
ret = -EINVAL; ret = -EINVAL;
...@@ -407,6 +466,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, ...@@ -407,6 +466,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
} }
st->startup_time = prop; st->startup_time = prop;
prop = 0;
of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop);
st->sample_hold_time = prop;
if (of_property_read_u32(node, "atmel,adc-vref", &prop)) { if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
dev_err(&idev->dev, "Missing adc-vref property in the DT.\n"); dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
...@@ -415,6 +477,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st, ...@@ -415,6 +477,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
} }
st->vref_mv = prop; st->vref_mv = prop;
ret = at91_adc_of_get_resolution(st, pdev);
if (ret)
goto error_ret;
st->registers = devm_kzalloc(&idev->dev, st->registers = devm_kzalloc(&idev->dev,
sizeof(struct at91_adc_reg_desc), sizeof(struct at91_adc_reg_desc),
GFP_KERNEL); GFP_KERNEL);
...@@ -516,11 +582,12 @@ static const struct iio_info at91_adc_info = { ...@@ -516,11 +582,12 @@ static const struct iio_info at91_adc_info = {
static int at91_adc_probe(struct platform_device *pdev) static int at91_adc_probe(struct platform_device *pdev)
{ {
unsigned int prsc, mstrclk, ticks, adc_clk; unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
int ret; int ret;
struct iio_dev *idev; struct iio_dev *idev;
struct at91_adc_state *st; struct at91_adc_state *st;
struct resource *res; struct resource *res;
u32 reg;
idev = iio_device_alloc(sizeof(struct at91_adc_state)); idev = iio_device_alloc(sizeof(struct at91_adc_state));
if (idev == NULL) { if (idev == NULL) {
...@@ -628,9 +695,22 @@ static int at91_adc_probe(struct platform_device *pdev) ...@@ -628,9 +695,22 @@ static int at91_adc_probe(struct platform_device *pdev)
*/ */
ticks = round_up((st->startup_time * adc_clk / ticks = round_up((st->startup_time * adc_clk /
1000000) - 1, 8) / 8; 1000000) - 1, 8) / 8;
at91_adc_writel(st, AT91_ADC_MR, /*
(AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) | * a minimal Sample and Hold Time is necessary for the ADC to guarantee
(AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP)); * the best converted final value between two channels selection
* The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
*/
shtim = round_up((st->sample_hold_time * adc_clk /
1000000) - 1, 1);
reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
if (st->low_res)
reg |= AT91_ADC_LOWRES;
if (st->sleep_mode)
reg |= AT91_ADC_SLEEP;
reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM;
at91_adc_writel(st, AT91_ADC_MR, reg);
/* Setup the ADC channels available on the board */ /* Setup the ADC channels available on the board */
ret = at91_adc_channel_init(idev); ret = at91_adc_channel_init(idev);
......
/*
* exynos_adc.c - Support for ADC in EXYNOS SoCs
*
* 8 ~ 10 channel, 10/12-bit ADC
*
* Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/iio/iio.h>
#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)
#define ADC_V1_DATX(x) ((x) + 0x0C)
#define ADC_V1_INTCLR(x) ((x) + 0x18)
#define ADC_V1_MUX(x) ((x) + 0x1c)
/* Future ADC_V2 registers definitions */
#define ADC_V2_CON1(x) ((x) + 0x00)
#define ADC_V2_CON2(x) ((x) + 0x04)
#define ADC_V2_STAT(x) ((x) + 0x08)
#define ADC_V2_INT_EN(x) ((x) + 0x10)
#define ADC_V2_INT_ST(x) ((x) + 0x14)
#define ADC_V2_VER(x) ((x) + 0x20)
/* Bit definitions for ADC_V1 */
#define ADC_V1_CON_RES (1u << 16)
#define ADC_V1_CON_PRSCEN (1u << 14)
#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
#define ADC_V1_CON_STANDBY (1u << 2)
/* Bit definitions for ADC_V2 */
#define ADC_V2_CON1_SOFT_RESET (1u << 2)
#define ADC_V2_CON2_OSEL (1u << 10)
#define ADC_V2_CON2_ESEL (1u << 9)
#define ADC_V2_CON2_HIGHF (1u << 8)
#define ADC_V2_CON2_C_TIME(x) (((x) & 7) << 4)
#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
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
#define ADC_DATX_MASK 0xFFF
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(1000))
struct exynos_adc {
void __iomem *regs;
void __iomem *enable_reg;
struct clk *clk;
unsigned int irq;
struct regulator *vdd;
struct completion completion;
u32 value;
unsigned int version;
};
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 },
{},
};
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static inline unsigned int exynos_adc_get_version(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 int exynos_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout;
u32 con1, con2;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
/* 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));
}
timeout = wait_for_completion_interruptible_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT);
*val = info->value;
mutex_unlock(&indio_dev->mlock);
if (timeout == 0)
return -ETIMEDOUT;
return IIO_VAL_INT;
}
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;
/* clear irq */
if (info->version == ADC_V2)
writel(1, ADC_V2_INT_ST(info->regs));
else
writel(1, ADC_V1_INTCLR(info->regs));
complete(&info->completion);
return IRQ_HANDLED;
}
static int exynos_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct exynos_adc *info = iio_priv(indio_dev);
if (readval == NULL)
return -EINVAL;
*readval = readl(info->regs + reg);
return 0;
}
static const struct iio_info exynos_adc_iio_info = {
.read_raw = &exynos_read_raw,
.debugfs_reg_access = &exynos_adc_reg_access,
.driver_module = THIS_MODULE,
};
#define ADC_CHANNEL(_index, _id) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.address = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.datasheet_name = _id, \
}
static const struct iio_chan_spec exynos_adc_iio_channels[] = {
ADC_CHANNEL(0, "adc0"),
ADC_CHANNEL(1, "adc1"),
ADC_CHANNEL(2, "adc2"),
ADC_CHANNEL(3, "adc3"),
ADC_CHANNEL(4, "adc4"),
ADC_CHANNEL(5, "adc5"),
ADC_CHANNEL(6, "adc6"),
ADC_CHANNEL(7, "adc7"),
ADC_CHANNEL(8, "adc8"),
ADC_CHANNEL(9, "adc9"),
};
static int exynos_adc_remove_devices(struct device *dev, void *c)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
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));
}
}
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
struct resource *mem;
int ret = -ENODEV;
int irq;
if (!np)
return ret;
indio_dev = iio_device_alloc(sizeof(struct exynos_adc));
if (!indio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
info = iio_priv(indio_dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_request_and_ioremap(&pdev->dev, mem);
if (!info->regs) {
ret = -ENOMEM;
goto err_iio;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
info->enable_reg = devm_request_and_ioremap(&pdev->dev, mem);
if (!info->enable_reg) {
ret = -ENOMEM;
goto err_iio;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
ret = irq;
goto err_iio;
}
info->irq = irq;
init_completion(&info->completion);
ret = request_irq(info->irq, exynos_adc_isr,
0, dev_name(&pdev->dev), info);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
info->irq);
goto err_iio;
}
writel(1, info->enable_reg);
info->clk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
PTR_ERR(info->clk));
ret = PTR_ERR(info->clk);
goto err_irq;
}
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) {
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
PTR_ERR(info->vdd));
ret = PTR_ERR(info->vdd);
goto err_irq;
}
info->version = exynos_adc_get_version(pdev);
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
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;
ret = iio_device_register(indio_dev);
if (ret)
goto err_irq;
ret = regulator_enable(info->vdd);
if (ret)
goto err_iio_dev;
clk_prepare_enable(info->clk);
exynos_adc_hw_init(info);
ret = of_platform_populate(np, exynos_adc_match, NULL, &pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed adding child nodes\n");
goto err_of_populate;
}
return 0;
err_of_populate:
device_for_each_child(&pdev->dev, NULL,
exynos_adc_remove_devices);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
err_iio_dev:
iio_device_unregister(indio_dev);
err_irq:
free_irq(info->irq, info);
err_iio:
iio_device_free(indio_dev);
return ret;
}
static int exynos_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
device_for_each_child(&pdev->dev, NULL,
exynos_adc_remove_devices);
regulator_disable(info->vdd);
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
iio_device_unregister(indio_dev);
free_irq(info->irq, info);
iio_device_free(indio_dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int exynos_adc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_adc *info = platform_get_drvdata(pdev);
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));
}
clk_disable_unprepare(info->clk);
writel(0, info->enable_reg);
regulator_disable(info->vdd);
return 0;
}
static int exynos_adc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct exynos_adc *info = platform_get_drvdata(pdev);
int ret;
ret = regulator_enable(info->vdd);
if (ret)
return ret;
writel(1, info->enable_reg);
clk_prepare_enable(info->clk);
exynos_adc_hw_init(info);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops,
exynos_adc_suspend,
exynos_adc_resume);
static struct platform_driver exynos_adc_driver = {
.probe = exynos_adc_probe,
.remove = exynos_adc_remove,
.driver = {
.name = "exynos-adc",
.owner = THIS_MODULE,
.of_match_table = exynos_adc_match,
.pm = &exynos_adc_pm_ops,
},
};
module_platform_driver(exynos_adc_driver);
MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>");
MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver");
MODULE_LICENSE("GPL v2");
...@@ -132,8 +132,8 @@ static const struct iio_info lp8788_adc_info = { ...@@ -132,8 +132,8 @@ static const struct iio_info lp8788_adc_info = {
.type = _type, \ .type = _type, \
.indexed = 1, \ .indexed = 1, \
.channel = LPADC_##_id, \ .channel = LPADC_##_id, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = #_id, \ .datasheet_name = #_id, \
} }
......
...@@ -427,15 +427,15 @@ static const enum max1363_modes max1363_mode_list[] = { ...@@ -427,15 +427,15 @@ static const enum max1363_modes max1363_mode_list[] = {
#define MAX1363_EV_M \ #define MAX1363_EV_M \
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
| IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT)
#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \ #define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
{ \ { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = num, \ .channel = num, \
.address = addr, \ .address = addr, \
.info_mask = MAX1363_INFO_MASK, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "AIN"#num, \ .datasheet_name = "AIN"#num, \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
...@@ -456,7 +456,8 @@ static const enum max1363_modes max1363_mode_list[] = { ...@@ -456,7 +456,8 @@ static const enum max1363_modes max1363_mode_list[] = {
.channel = num, \ .channel = num, \
.channel2 = num2, \ .channel2 = num2, \
.address = addr, \ .address = addr, \
.info_mask = MAX1363_INFO_MASK, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "AIN"#num"-AIN"#num2, \ .datasheet_name = "AIN"#num"-AIN"#num2, \
.scan_type = { \ .scan_type = { \
.sign = 's', \ .sign = 's', \
......
...@@ -55,8 +55,8 @@ static int adc081c_read_raw(struct iio_dev *iio, ...@@ -55,8 +55,8 @@ static int adc081c_read_raw(struct iio_dev *iio,
static const struct iio_chan_spec adc081c_channel = { static const struct iio_chan_spec adc081c_channel = {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
IIO_CHAN_INFO_RAW_SEPARATE_BIT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}; };
static const struct iio_info adc081c_info = { static const struct iio_info adc081c_info = {
......
...@@ -89,7 +89,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels) ...@@ -89,7 +89,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
chan->type = IIO_VOLTAGE; chan->type = IIO_VOLTAGE;
chan->indexed = 1; chan->indexed = 1;
chan->channel = i; chan->channel = i;
chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
} }
indio_dev->channels = chan_array; indio_dev->channels = chan_array;
......
...@@ -41,7 +41,7 @@ struct vprbrd_adc { ...@@ -41,7 +41,7 @@ struct vprbrd_adc {
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = _index, \ .channel = _index, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \ .scan_index = _index, \
.scan_type = { \ .scan_type = { \
.sign = 'u', \ .sign = 'u', \
......
...@@ -125,7 +125,7 @@ static const struct iio_info ad8366_info = { ...@@ -125,7 +125,7 @@ static const struct iio_info ad8366_info = {
.output = 1, \ .output = 1, \
.indexed = 1, \ .indexed = 1, \
.channel = _channel, \ .channel = _channel, \
.info_mask = IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT,\ .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
} }
static const struct iio_chan_spec ad8366_channels[] = { static const struct iio_chan_spec ad8366_channels[] = {
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
struct hid_sensor_common *st = trig->private_data; struct hid_sensor_common *st = iio_trigger_get_drvdata(trig);
int state_val; int state_val;
state_val = state ? 1 : 0; state_val = state ? 1 : 0;
...@@ -76,7 +76,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, ...@@ -76,7 +76,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
} }
trig->dev.parent = indio_dev->dev.parent; trig->dev.parent = indio_dev->dev.parent;
trig->private_data = attrb; iio_trigger_set_drvdata(trig, attrb);
trig->ops = &hid_sensor_trigger_ops; trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig); ret = iio_trigger_register(trig);
......
...@@ -29,7 +29,6 @@ static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev) ...@@ -29,7 +29,6 @@ static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit) struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
{ {
struct spi_message msg;
int err; int err;
struct spi_transfer xfers[] = { struct spi_transfer xfers[] = {
...@@ -51,10 +50,7 @@ static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb, ...@@ -51,10 +50,7 @@ static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
else else
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ; tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
spi_message_init(&msg); err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers));
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
err = spi_sync(to_spi_device(dev), &msg);
if (err) if (err)
goto acc_spi_read_error; goto acc_spi_read_error;
...@@ -83,7 +79,6 @@ static int st_sensors_spi_read_multiple_byte( ...@@ -83,7 +79,6 @@ static int st_sensors_spi_read_multiple_byte(
static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data) struct device *dev, u8 reg_addr, u8 data)
{ {
struct spi_message msg;
int err; int err;
struct spi_transfer xfers = { struct spi_transfer xfers = {
...@@ -96,9 +91,7 @@ static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb, ...@@ -96,9 +91,7 @@ static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
tb->tx_buf[0] = reg_addr; tb->tx_buf[0] = reg_addr;
tb->tx_buf[1] = data; tb->tx_buf[1] = data;
spi_message_init(&msg); err = spi_sync_transfer(to_spi_device(dev), &xfers, 1);
spi_message_add_tail(&xfers, &msg);
err = spi_sync(to_spi_device(dev), &msg);
mutex_unlock(&tb->buf_lock); mutex_unlock(&tb->buf_lock);
return err; return err;
......
...@@ -40,7 +40,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, ...@@ -40,7 +40,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
if (err) if (err)
goto request_irq_error; goto request_irq_error;
sdata->trig->private_data = indio_dev; iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops; sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev; sdata->trig->dev.parent = sdata->dev;
......
...@@ -296,8 +296,8 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { ...@@ -296,8 +296,8 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = (chan), \ .channel = (chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = addr, \ .address = addr, \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \ .scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \
.ext_info = ad5064_ext_info, \ .ext_info = ad5064_ext_info, \
......
...@@ -102,11 +102,11 @@ enum ad5360_type { ...@@ -102,11 +102,11 @@ enum ad5360_type {
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_OFFSET) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \ .scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \
} }
......
...@@ -257,10 +257,10 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = { ...@@ -257,10 +257,10 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)), \ .scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)), \
.ext_info = ad5380_ext_info, \ .ext_info = ad5380_ext_info, \
} }
......
...@@ -86,11 +86,11 @@ static const struct iio_chan_spec ad5421_channels[] = { ...@@ -86,11 +86,11 @@ static const struct iio_chan_spec ad5421_channels[] = {
.indexed = 1, .indexed = 1,
.output = 1, .output = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_CALIBSCALE) |
IIO_CHAN_INFO_OFFSET_SHARED_BIT | BIT(IIO_CHAN_INFO_CALIBBIAS),
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, BIT(IIO_CHAN_INFO_OFFSET),
.scan_type = IIO_ST('u', 16, 16, 0), .scan_type = IIO_ST('u', 16, 16, 0),
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
......
...@@ -143,8 +143,8 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { ...@@ -143,8 +143,8 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = 0, \ .channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', (bits), (storage), (shift)), \ .scan_type = IIO_ST('u', (bits), (storage), (shift)), \
.ext_info = (ext), \ .ext_info = (ext), \
} }
......
...@@ -206,8 +206,8 @@ static const struct iio_info ad5449_info = { ...@@ -206,8 +206,8 @@ static const struct iio_info ad5449_info = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = (chan), \ .channel = (chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = (chan), \ .address = (chan), \
.scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \ .scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \
} }
......
...@@ -259,8 +259,8 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { ...@@ -259,8 +259,8 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = (_chan), \ .channel = (_chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = AD5504_ADDR_DAC(_chan), \ .address = AD5504_ADDR_DAC(_chan), \
.scan_type = IIO_ST('u', 12, 16, 0), \ .scan_type = IIO_ST('u', 12, 16, 0), \
.ext_info = ad5504_ext_info, \ .ext_info = ad5504_ext_info, \
......
...@@ -174,8 +174,8 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = { ...@@ -174,8 +174,8 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = (_chan), \ .channel = (_chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (_chan), \ .address = (_chan), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
.ext_info = ad5624r_ext_info, \ .ext_info = ad5624r_ext_info, \
......
...@@ -276,9 +276,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { ...@@ -276,9 +276,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = chan, \ .channel = chan, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
.address = AD5686_ADDR_DAC(chan), \ .address = AD5686_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', bits, 16, shift), \ .scan_type = IIO_ST('u', bits, 16, shift), \
.ext_info = ad5686_ext_info, \ .ext_info = ad5686_ext_info, \
} }
......
...@@ -393,11 +393,11 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { ...@@ -393,11 +393,11 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
#define AD5755_CHANNEL(_bits) { \ #define AD5755_CHANNEL(_bits) { \
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_OFFSET) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
.ext_info = ad5755_ext_info, \ .ext_info = ad5755_ext_info, \
} }
......
...@@ -78,11 +78,11 @@ enum ad5764_type { ...@@ -78,11 +78,11 @@ enum ad5764_type {
.output = 1, \ .output = 1, \
.channel = (_chan), \ .channel = (_chan), \
.address = (_chan), \ .address = (_chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_OFFSET_SHARED_BIT | \ BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)) \ .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)) \
} }
......
...@@ -302,9 +302,9 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { ...@@ -302,9 +302,9 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
.indexed = 1, \ .indexed = 1, \
.address = AD5791_ADDR_DAC0, \ .address = AD5791_ADDR_DAC0, \
.channel = 0, \ .channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = IIO_ST('u', bits, 24, shift), \ .scan_type = IIO_ST('u', bits, 24, shift), \
.ext_info = ad5791_ext_info, \ .ext_info = ad5791_ext_info, \
} }
......
...@@ -146,8 +146,8 @@ static const struct iio_info max517_info = { ...@@ -146,8 +146,8 @@ static const struct iio_info max517_info = {
.indexed = 1, \ .indexed = 1, \
.output = 1, \ .output = 1, \
.channel = (chan), \ .channel = (chan), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', 8, 8, 0), \ .scan_type = IIO_ST('u', 8, 8, 0), \
} }
......
...@@ -69,8 +69,8 @@ static const struct iio_chan_spec mcp4725_channel = { ...@@ -69,8 +69,8 @@ static const struct iio_chan_spec mcp4725_channel = {
.indexed = 1, .indexed = 1,
.output = 1, .output = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
IIO_CHAN_INFO_SCALE_SHARED_BIT, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_type = IIO_ST('u', 12, 16, 0), .scan_type = IIO_ST('u', 12, 16, 0),
}; };
......
...@@ -920,10 +920,10 @@ static int ad9523_setup(struct iio_dev *indio_dev) ...@@ -920,10 +920,10 @@ static int ad9523_setup(struct iio_dev *indio_dev)
st->ad9523_channels[i].channel = chan->channel_num; st->ad9523_channels[i].channel = chan->channel_num;
st->ad9523_channels[i].extend_name = st->ad9523_channels[i].extend_name =
chan->extended_name; chan->extended_name;
st->ad9523_channels[i].info_mask = st->ad9523_channels[i].info_mask_separate =
IIO_CHAN_INFO_RAW_SEPARATE_BIT | BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_PHASE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_PHASE) |
IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT; BIT(IIO_CHAN_INFO_FREQUENCY);
} }
} }
......
...@@ -136,32 +136,32 @@ static const struct iio_chan_spec adis16080_channels[] = { ...@@ -136,32 +136,32 @@ static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16080_DIN_GYRO, .address = ADIS16080_DIN_GYRO,
}, { }, {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN1, .address = ADIS16080_DIN_AIN1,
}, { }, {
.type = IIO_VOLTAGE, .type = IIO_VOLTAGE,
.indexed = 1, .indexed = 1,
.channel = 1, .channel = 1,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN2, .address = ADIS16080_DIN_AIN2,
}, { }, {
.type = IIO_TEMP, .type = IIO_TEMP,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_TEMP, .address = ADIS16080_DIN_TEMP,
} }
}; };
......
...@@ -357,10 +357,11 @@ static const struct iio_chan_spec adis16136_channels[] = { ...@@ -357,10 +357,11 @@ static const struct iio_chan_spec adis16136_channels[] = {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_X, .channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | BIT(IIO_CHAN_INFO_CALIBBIAS) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16136_REG_GYRO_OUT2, .address = ADIS16136_REG_GYRO_OUT2,
.scan_index = ADIS16136_SCAN_GYRO, .scan_index = ADIS16136_SCAN_GYRO,
.scan_type = { .scan_type = {
...@@ -373,8 +374,8 @@ static const struct iio_chan_spec adis16136_channels[] = { ...@@ -373,8 +374,8 @@ static const struct iio_chan_spec adis16136_channels[] = {
.type = IIO_TEMP, .type = IIO_TEMP,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16136_REG_TEMP_OUT, .address = ADIS16136_REG_TEMP_OUT,
.scan_index = ADIS16136_SCAN_TEMP, .scan_index = ADIS16136_SCAN_TEMP,
.scan_type = { .scan_type = {
......
...@@ -383,16 +383,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = { ...@@ -383,16 +383,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | BIT(IIO_CHAN_INFO_CALIBBIAS) |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT | BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
}, { }, {
.type = IIO_TEMP, .type = IIO_TEMP,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
} }
}, },
[ID_ADXRS453] = { [ID_ADXRS453] = {
...@@ -400,15 +400,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = { ...@@ -400,15 +400,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT, BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW),
}, { }, {
.type = IIO_TEMP, .type = IIO_TEMP,
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
} }
}, },
}; };
......
...@@ -60,28 +60,28 @@ static const struct iio_chan_spec gyro_3d_channels[] = { ...@@ -60,28 +60,28 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_X, .channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X, .scan_index = CHANNEL_SCAN_INDEX_X,
}, { }, {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Y, .channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y, .scan_index = CHANNEL_SCAN_INDEX_Y,
}, { }, {
.type = IIO_ANGL_VEL, .type = IIO_ANGL_VEL,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} }
}; };
......
...@@ -81,7 +81,7 @@ void itg3200_buffer_unconfigure(struct iio_dev *indio_dev) ...@@ -81,7 +81,7 @@ void itg3200_buffer_unconfigure(struct iio_dev *indio_dev)
static int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig, static int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
struct iio_dev *indio_dev = trig->private_data; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
int ret; int ret;
u8 msc; u8 msc;
...@@ -129,7 +129,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev) ...@@ -129,7 +129,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
st->trig->dev.parent = &st->i2c->dev; st->trig->dev.parent = &st->i2c->dev;
st->trig->ops = &itg3200_trigger_ops; st->trig->ops = &itg3200_trigger_ops;
st->trig->private_data = indio_dev; iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig); ret = iio_trigger_register(st->trig);
if (ret) if (ret)
goto error_free_irq; goto error_free_irq;
......
...@@ -248,12 +248,6 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) ...@@ -248,12 +248,6 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
return ret; return ret;
} }
#define ITG3200_TEMP_INFO_MASK (IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#define ITG3200_GYRO_INFO_MASK (IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_RAW_SEPARATE_BIT)
#define ITG3200_ST \ #define ITG3200_ST \
{ .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE } { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
...@@ -261,7 +255,8 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) ...@@ -261,7 +255,8 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
.type = IIO_ANGL_VEL, \ .type = IIO_ANGL_VEL, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## _mod, \ .channel2 = IIO_MOD_ ## _mod, \
.info_mask = ITG3200_GYRO_INFO_MASK, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
.scan_type = ITG3200_ST, \ .scan_type = ITG3200_ST, \
...@@ -271,7 +266,9 @@ static const struct iio_chan_spec itg3200_channels[] = { ...@@ -271,7 +266,9 @@ static const struct iio_chan_spec itg3200_channels[] = {
{ {
.type = IIO_TEMP, .type = IIO_TEMP,
.channel2 = IIO_NO_MOD, .channel2 = IIO_NO_MOD,
.info_mask = ITG3200_TEMP_INFO_MASK, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
.address = ITG3200_REG_TEMP_OUT_H, .address = ITG3200_REG_TEMP_OUT_H,
.scan_index = ITG3200_SCAN_TEMP, .scan_index = ITG3200_SCAN_TEMP,
.scan_type = ITG3200_ST, .scan_type = ITG3200_ST,
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
int st_gyro_trig_set_state(struct iio_trigger *trig, bool state) int st_gyro_trig_set_state(struct iio_trigger *trig, bool state)
{ {
struct iio_dev *indio_dev = trig->private_data; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state); return st_sensors_set_dataready_irq(indio_dev, state);
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
struct iio_chan_spec; struct iio_chan_spec;
struct iio_dev; struct iio_dev;
extern struct device_type iio_device_type;
int __iio_add_chan_devattr(const char *postfix, int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
......
...@@ -484,8 +484,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -484,8 +484,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \ .indexed = 1, \
.channel = 0, \ .channel = 0, \
.extend_name = name, \ .extend_name = name, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \ .address = (addr), \
.scan_index = (si), \ .scan_index = (si), \
.scan_type = { \ .scan_type = { \
...@@ -507,10 +507,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -507,10 +507,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_ANGL_VEL, \ .type = IIO_ANGL_VEL, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## mod, \ .channel2 = IIO_MOD_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = addr, \ .address = addr, \
.scan_index = ADIS16400_SCAN_GYRO_ ## mod, \ .scan_index = ADIS16400_SCAN_GYRO_ ## mod, \
.scan_type = { \ .scan_type = { \
...@@ -526,10 +526,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -526,10 +526,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_ACCEL, \ .type = IIO_ACCEL, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## mod, \ .channel2 = IIO_MOD_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \ .address = (addr), \
.scan_index = ADIS16400_SCAN_ACC_ ## mod, \ .scan_index = ADIS16400_SCAN_ACC_ ## mod, \
.scan_type = { \ .scan_type = { \
...@@ -545,9 +545,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -545,9 +545,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \ .type = IIO_MAGN, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## mod, \ .channel2 = IIO_MOD_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \ .address = (addr), \
.scan_index = ADIS16400_SCAN_MAGN_ ## mod, \ .scan_index = ADIS16400_SCAN_MAGN_ ## mod, \
.scan_type = { \ .scan_type = { \
...@@ -568,10 +568,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -568,10 +568,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \ .indexed = 1, \
.channel = 0, \ .channel = 0, \
.extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \ .extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_OFFSET) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_SCALE), \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \ .info_mask_shared_by_type = \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \ .address = (addr), \
.scan_index = ADIS16350_SCAN_TEMP_ ## mod, \ .scan_index = ADIS16350_SCAN_TEMP_ ## mod, \
.scan_type = { \ .scan_type = { \
...@@ -587,9 +588,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -587,9 +588,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_TEMP, \ .type = IIO_TEMP, \
.indexed = 1, \ .indexed = 1, \
.channel = 0, \ .channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_OFFSET) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \ .address = (addr), \
.scan_index = ADIS16350_SCAN_TEMP_X, \ .scan_index = ADIS16350_SCAN_TEMP_X, \
.scan_type = { \ .scan_type = { \
...@@ -605,8 +606,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -605,8 +606,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_INCLI, \ .type = IIO_INCLI, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## mod, \ .channel2 = IIO_MOD_ ## mod, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \ .address = (addr), \
.scan_index = ADIS16300_SCAN_INCLI_ ## mod, \ .scan_index = ADIS16300_SCAN_INCLI_ ## mod, \
.scan_type = { \ .scan_type = { \
...@@ -646,8 +647,8 @@ static const struct iio_chan_spec adis16448_channels[] = { ...@@ -646,8 +647,8 @@ static const struct iio_chan_spec adis16448_channels[] = {
ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16), ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16),
{ {
.type = IIO_PRESSURE, .type = IIO_PRESSURE,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
IIO_CHAN_INFO_SCALE_SHARED_BIT, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16448_BARO_OUT, .address = ADIS16448_BARO_OUT,
.scan_index = ADIS16400_SCAN_BARO, .scan_index = ADIS16400_SCAN_BARO,
.scan_type = IIO_ST('s', 16, 16, 0), .scan_type = IIO_ST('s', 16, 16, 0),
......
...@@ -591,15 +591,15 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, ...@@ -591,15 +591,15 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
} }
} }
#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info, _bits) \ #define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \
{ \ { \
.type = (_type), \ .type = (_type), \
.modified = 1, \ .modified = 1, \
.channel2 = (_mod), \ .channel2 = (_mod), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
IIO_CHAN_INFO_SCALE_SHARED_BIT | \ _info_sep, \
_info, \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (_address), \ .address = (_address), \
.scan_index = (_si), \ .scan_index = (_si), \
.scan_type = { \ .scan_type = { \
...@@ -613,21 +613,21 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, ...@@ -613,21 +613,21 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
#define ADIS16480_GYRO_CHANNEL(_mod) \ #define ADIS16480_GYRO_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \ ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \ ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_CALIBSCALE), \
32) 32)
#define ADIS16480_ACCEL_CHANNEL(_mod) \ #define ADIS16480_ACCEL_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \ ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \ ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_CALIBSCALE), \
32) 32)
#define ADIS16480_MAGN_CHANNEL(_mod) \ #define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \ ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \ ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
16) 16)
#define ADIS16480_PRESSURE_CHANNEL() \ #define ADIS16480_PRESSURE_CHANNEL() \
...@@ -635,9 +635,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, ...@@ -635,9 +635,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
.type = IIO_PRESSURE, \ .type = IIO_PRESSURE, \
.indexed = 1, \ .indexed = 1, \
.channel = 0, \ .channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = ADIS16480_REG_BAROM_OUT, \ .address = ADIS16480_REG_BAROM_OUT, \
.scan_index = ADIS16480_SCAN_BARO, \ .scan_index = ADIS16480_SCAN_BARO, \
.scan_type = { \ .scan_type = { \
...@@ -652,9 +652,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev, ...@@ -652,9 +652,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
.type = IIO_TEMP, \ .type = IIO_TEMP, \
.indexed = 1, \ .indexed = 1, \
.channel = 0, \ .channel = 0, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ BIT(IIO_CHAN_INFO_SCALE) | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_OFFSET), \
.address = ADIS16480_REG_TEMP_OUT, \ .address = ADIS16480_REG_TEMP_OUT, \
.scan_index = ADIS16480_SCAN_TEMP, \ .scan_index = ADIS16480_SCAN_TEMP, \
.scan_type = { \ .scan_type = { \
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig, static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
struct adis *adis = trig->private_data; struct adis *adis = iio_trigger_get_drvdata(trig);
return adis_enable_irq(adis, state); return adis_enable_irq(adis, state);
} }
...@@ -57,7 +57,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) ...@@ -57,7 +57,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
adis->trig->dev.parent = &adis->spi->dev; adis->trig->dev.parent = &adis->spi->dev;
adis->trig->ops = &adis_trigger_ops; adis->trig->ops = &adis_trigger_ops;
adis->trig->private_data = adis; iio_trigger_set_drvdata(adis->trig, adis);
ret = iio_trigger_register(adis->trig); ret = iio_trigger_register(adis->trig);
indio_dev->trig = adis->trig; indio_dev->trig = adis->trig;
......
...@@ -544,8 +544,8 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev, ...@@ -544,8 +544,8 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
.type = _type, \ .type = _type, \
.modified = 1, \ .modified = 1, \
.channel2 = _channel2, \ .channel2 = _channel2, \
.info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
| IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \ .scan_index = _index, \
.scan_type = { \ .scan_type = { \
.sign = 's', \ .sign = 's', \
...@@ -564,9 +564,9 @@ static const struct iio_chan_spec inv_mpu_channels[] = { ...@@ -564,9 +564,9 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
*/ */
{ {
.type = IIO_TEMP, .type = IIO_TEMP,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | BIT(IIO_CHAN_INFO_OFFSET)
| IIO_CHAN_INFO_SCALE_SEPARATE_BIT, | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1, .scan_index = -1,
}, },
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
......
...@@ -105,9 +105,8 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) ...@@ -105,9 +105,8 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
s64 timestamp; s64 timestamp;
timestamp = iio_get_time_ns(); timestamp = iio_get_time_ns();
spin_lock(&st->time_stamp_lock); kfifo_in_spinlocked(&st->timestamps, &timestamp, 1,
kfifo_in(&st->timestamps, &timestamp, 1); &st->time_stamp_lock);
spin_unlock(&st->time_stamp_lock);
return IRQ_WAKE_THREAD; return IRQ_WAKE_THREAD;
} }
......
...@@ -103,7 +103,7 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) ...@@ -103,7 +103,7 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
return inv_mpu6050_set_enable(trig->private_data, state); return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state);
} }
static const struct iio_trigger_ops inv_mpu_trigger_ops = { static const struct iio_trigger_ops inv_mpu_trigger_ops = {
...@@ -130,8 +130,8 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ...@@ -130,8 +130,8 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
if (ret) if (ret)
goto error_free_trig; goto error_free_trig;
st->trig->dev.parent = &st->client->dev; st->trig->dev.parent = &st->client->dev;
st->trig->private_data = indio_dev;
st->trig->ops = &inv_mpu_trigger_ops; st->trig->ops = &inv_mpu_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig); ret = iio_trigger_register(st->trig);
if (ret) if (ret)
goto error_free_irq; goto error_free_irq;
......
...@@ -691,21 +691,34 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, ...@@ -691,21 +691,34 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
if (chan->channel < 0) if (chan->channel < 0)
return 0; return 0;
for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) { for_each_set_bit(i, &chan->info_mask_separate, sizeof(long)*8) {
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2], ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
chan, chan,
&iio_read_channel_info, &iio_read_channel_info,
&iio_write_channel_info, &iio_write_channel_info,
i/2, i,
!(i%2), 0,
&indio_dev->dev, &indio_dev->dev,
&indio_dev->channel_attr_list); &indio_dev->channel_attr_list);
if (ret == -EBUSY && (i%2 == 0)) { if (ret < 0)
goto error_ret;
attrcount++;
}
for_each_set_bit(i, &chan->info_mask_shared_by_type, sizeof(long)*8) {
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
chan,
&iio_read_channel_info,
&iio_write_channel_info,
i,
1,
&indio_dev->dev,
&indio_dev->channel_attr_list);
if (ret == -EBUSY) {
ret = 0; ret = 0;
continue; continue;
} } else if (ret < 0) {
if (ret < 0)
goto error_ret; goto error_ret;
}
attrcount++; attrcount++;
} }
...@@ -847,7 +860,7 @@ static void iio_dev_release(struct device *device) ...@@ -847,7 +860,7 @@ static void iio_dev_release(struct device *device)
kfree(indio_dev); kfree(indio_dev);
} }
static struct device_type iio_dev_type = { struct device_type iio_device_type = {
.name = "iio_device", .name = "iio_device",
.release = iio_dev_release, .release = iio_dev_release,
}; };
...@@ -869,7 +882,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv) ...@@ -869,7 +882,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
if (dev) { if (dev) {
dev->dev.groups = dev->groups; dev->dev.groups = dev->groups;
dev->dev.type = &iio_dev_type; dev->dev.type = &iio_device_type;
dev->dev.bus = &iio_bus_type; dev->dev.bus = &iio_bus_type;
device_initialize(&dev->dev); device_initialize(&dev->dev);
dev_set_drvdata(&dev->dev, (void *)dev); dev_set_drvdata(&dev->dev, (void *)dev);
...@@ -960,6 +973,10 @@ int iio_device_register(struct iio_dev *indio_dev) ...@@ -960,6 +973,10 @@ int iio_device_register(struct iio_dev *indio_dev)
{ {
int ret; int ret;
/* If the calling driver did not initialize of_node, do it here */
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
/* configure elements for the chrdev */ /* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
......
...@@ -46,10 +46,11 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) ...@@ -46,10 +46,11 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
{ {
struct iio_event_interface *ev_int = indio_dev->event_interface; struct iio_event_interface *ev_int = indio_dev->event_interface;
struct iio_event_data ev; struct iio_event_data ev;
unsigned long flags;
int copied; int copied;
/* Does anyone care? */ /* Does anyone care? */
spin_lock(&ev_int->wait.lock); spin_lock_irqsave(&ev_int->wait.lock, flags);
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
ev.id = ev_code; ev.id = ev_code;
...@@ -59,7 +60,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) ...@@ -59,7 +60,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
if (copied != 0) if (copied != 0)
wake_up_locked_poll(&ev_int->wait, POLLIN); wake_up_locked_poll(&ev_int->wait, POLLIN);
} }
spin_unlock(&ev_int->wait.lock); spin_unlock_irqrestore(&ev_int->wait.lock, flags);
return 0; return 0;
} }
...@@ -76,10 +77,10 @@ static unsigned int iio_event_poll(struct file *filep, ...@@ -76,10 +77,10 @@ static unsigned int iio_event_poll(struct file *filep,
poll_wait(filep, &ev_int->wait, wait); poll_wait(filep, &ev_int->wait, wait);
spin_lock(&ev_int->wait.lock); spin_lock_irq(&ev_int->wait.lock);
if (!kfifo_is_empty(&ev_int->det_events)) if (!kfifo_is_empty(&ev_int->det_events))
events = POLLIN | POLLRDNORM; events = POLLIN | POLLRDNORM;
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
return events; return events;
} }
...@@ -96,14 +97,14 @@ static ssize_t iio_event_chrdev_read(struct file *filep, ...@@ -96,14 +97,14 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
if (count < sizeof(struct iio_event_data)) if (count < sizeof(struct iio_event_data))
return -EINVAL; return -EINVAL;
spin_lock(&ev_int->wait.lock); spin_lock_irq(&ev_int->wait.lock);
if (kfifo_is_empty(&ev_int->det_events)) { if (kfifo_is_empty(&ev_int->det_events)) {
if (filep->f_flags & O_NONBLOCK) { if (filep->f_flags & O_NONBLOCK) {
ret = -EAGAIN; ret = -EAGAIN;
goto error_unlock; goto error_unlock;
} }
/* Blocking on device; waiting for something to be there */ /* Blocking on device; waiting for something to be there */
ret = wait_event_interruptible_locked(ev_int->wait, ret = wait_event_interruptible_locked_irq(ev_int->wait,
!kfifo_is_empty(&ev_int->det_events)); !kfifo_is_empty(&ev_int->det_events));
if (ret) if (ret)
goto error_unlock; goto error_unlock;
...@@ -113,7 +114,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep, ...@@ -113,7 +114,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied); ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
error_unlock: error_unlock:
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
return ret ? ret : copied; return ret ? ret : copied;
} }
...@@ -122,7 +123,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep) ...@@ -122,7 +123,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
{ {
struct iio_event_interface *ev_int = filep->private_data; struct iio_event_interface *ev_int = filep->private_data;
spin_lock(&ev_int->wait.lock); spin_lock_irq(&ev_int->wait.lock);
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
/* /*
* In order to maintain a clean state for reopening, * In order to maintain a clean state for reopening,
...@@ -130,7 +131,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep) ...@@ -130,7 +131,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
* any new __iio_push_event calls running. * any new __iio_push_event calls running.
*/ */
kfifo_reset_out(&ev_int->det_events); kfifo_reset_out(&ev_int->det_events);
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
return 0; return 0;
} }
...@@ -151,18 +152,18 @@ int iio_event_getfd(struct iio_dev *indio_dev) ...@@ -151,18 +152,18 @@ int iio_event_getfd(struct iio_dev *indio_dev)
if (ev_int == NULL) if (ev_int == NULL)
return -ENODEV; return -ENODEV;
spin_lock(&ev_int->wait.lock); spin_lock_irq(&ev_int->wait.lock);
if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
return -EBUSY; return -EBUSY;
} }
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
fd = anon_inode_getfd("iio:event", fd = anon_inode_getfd("iio:event",
&iio_event_chrdev_fileops, ev_int, O_RDONLY); &iio_event_chrdev_fileops, ev_int, O_RDONLY);
if (fd < 0) { if (fd < 0) {
spin_lock(&ev_int->wait.lock); spin_lock_irq(&ev_int->wait.lock);
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); __clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
spin_unlock(&ev_int->wait.lock); spin_unlock_irq(&ev_int->wait.lock);
} }
return fd; return fd;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include "iio_core.h" #include "iio_core.h"
...@@ -92,6 +93,164 @@ static const struct iio_chan_spec ...@@ -92,6 +93,164 @@ static const struct iio_chan_spec
return chan; return chan;
} }
#ifdef CONFIG_OF
static int iio_dev_node_match(struct device *dev, void *data)
{
return dev->of_node == data && dev->type == &iio_device_type;
}
static int __of_iio_channel_get(struct iio_channel *channel,
struct device_node *np, int index)
{
struct device *idev;
struct iio_dev *indio_dev;
int err;
struct of_phandle_args iiospec;
err = of_parse_phandle_with_args(np, "io-channels",
"#io-channel-cells",
index, &iiospec);
if (err)
return err;
idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
iio_dev_node_match);
of_node_put(iiospec.np);
if (idev == NULL)
return -EPROBE_DEFER;
indio_dev = dev_to_iio_dev(idev);
channel->indio_dev = indio_dev;
index = iiospec.args_count ? iiospec.args[0] : 0;
if (index >= indio_dev->num_channels) {
return -EINVAL;
goto err_put;
}
channel->channel = &indio_dev->channels[index];
return 0;
err_put:
iio_device_put(indio_dev);
return err;
}
static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
{
struct iio_channel *channel;
int err;
if (index < 0)
return ERR_PTR(-EINVAL);
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (channel == NULL)
return ERR_PTR(-ENOMEM);
err = __of_iio_channel_get(channel, np, index);
if (err)
goto err_free_channel;
return channel;
err_free_channel:
kfree(channel);
return ERR_PTR(err);
}
static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
const char *name)
{
struct iio_channel *chan = NULL;
/* Walk up the tree of devices looking for a matching iio channel */
while (np) {
int index = 0;
/*
* For named iio channels, first look up the name in the
* "io-channel-names" property. If it cannot be found, the
* index will be an error code, and of_iio_channel_get()
* will fail.
*/
if (name)
index = of_property_match_string(np, "io-channel-names",
name);
chan = of_iio_channel_get(np, index);
if (!IS_ERR(chan))
break;
else if (name && index >= 0) {
pr_err("ERROR: could not get IIO channel %s:%s(%i)\n",
np->full_name, name ? name : "", index);
return chan;
}
/*
* No matching IIO channel found on this node.
* If the parent node has a "io-channel-ranges" property,
* then we can try one of its channels.
*/
np = np->parent;
if (np && !of_get_property(np, "io-channel-ranges", NULL))
break;
}
return chan;
}
static struct iio_channel *of_iio_channel_get_all(struct device *dev)
{
struct iio_channel *chans;
int i, mapind, nummaps = 0;
int ret;
do {
ret = of_parse_phandle_with_args(dev->of_node,
"io-channels",
"#io-channel-cells",
nummaps, NULL);
if (ret < 0)
break;
} while (++nummaps);
if (nummaps == 0) /* no error, return NULL to search map table */
return NULL;
/* NULL terminated array to save passing size */
chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
if (chans == NULL)
return ERR_PTR(-ENOMEM);
/* Search for OF matches */
for (mapind = 0; mapind < nummaps; mapind++) {
ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
mapind);
if (ret)
goto error_free_chans;
}
return chans;
error_free_chans:
for (i = 0; i < mapind; i++)
iio_device_put(chans[i].indio_dev);
kfree(chans);
return ERR_PTR(ret);
}
#else /* CONFIG_OF */
static inline struct iio_channel *
of_iio_channel_get_by_name(struct device_node *np, const char *name)
{
return NULL;
}
static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
{
return NULL;
}
#endif /* CONFIG_OF */
static struct iio_channel *iio_channel_get_sys(const char *name, static struct iio_channel *iio_channel_get_sys(const char *name,
const char *channel_name) const char *channel_name)
...@@ -150,7 +309,14 @@ struct iio_channel *iio_channel_get(struct device *dev, ...@@ -150,7 +309,14 @@ struct iio_channel *iio_channel_get(struct device *dev,
const char *channel_name) const char *channel_name)
{ {
const char *name = dev ? dev_name(dev) : NULL; const char *name = dev ? dev_name(dev) : NULL;
struct iio_channel *channel;
if (dev) {
channel = of_iio_channel_get_by_name(dev->of_node,
channel_name);
if (channel != NULL)
return channel;
}
return iio_channel_get_sys(name, channel_name); return iio_channel_get_sys(name, channel_name);
} }
EXPORT_SYMBOL_GPL(iio_channel_get); EXPORT_SYMBOL_GPL(iio_channel_get);
...@@ -173,6 +339,11 @@ struct iio_channel *iio_channel_get_all(struct device *dev) ...@@ -173,6 +339,11 @@ struct iio_channel *iio_channel_get_all(struct device *dev)
if (dev == NULL) if (dev == NULL)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
chans = of_iio_channel_get_all(dev);
if (chans)
return chans;
name = dev_name(dev); name = dev_name(dev);
mutex_lock(&iio_map_list_lock); mutex_lock(&iio_map_list_lock);
......
...@@ -207,8 +207,8 @@ static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = { ...@@ -207,8 +207,8 @@ static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = {
.type = IIO_INTENSITY, \ .type = IIO_INTENSITY, \
.modified = 1, \ .modified = 1, \
.address = (IDX_##_color), \ .address = (IDX_##_color), \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.channel2 = (IIO_MOD_LIGHT_##_color), \ .channel2 = (IIO_MOD_LIGHT_##_color), \
.scan_index = (_scan_idx), \ .scan_index = (_scan_idx), \
.scan_type = IIO_ST('u', 10, 16, 0), \ .scan_type = IIO_ST('u', 10, 16, 0), \
......
...@@ -49,10 +49,10 @@ static const struct iio_chan_spec als_channels[] = { ...@@ -49,10 +49,10 @@ static const struct iio_chan_spec als_channels[] = {
.type = IIO_INTENSITY, .type = IIO_INTENSITY,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH, .channel2 = IIO_MOD_LIGHT_BOTH,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM, .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
} }
}; };
......
...@@ -231,7 +231,7 @@ static int lm3533_als_read_raw(struct iio_dev *indio_dev, ...@@ -231,7 +231,7 @@ static int lm3533_als_read_raw(struct iio_dev *indio_dev,
.channel = _channel, \ .channel = _channel, \
.indexed = true, \ .indexed = true, \
.output = true, \ .output = true, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
} }
static const struct iio_chan_spec lm3533_als_channels[] = { static const struct iio_chan_spec lm3533_als_channels[] = {
...@@ -239,8 +239,8 @@ static const struct iio_chan_spec lm3533_als_channels[] = { ...@@ -239,8 +239,8 @@ static const struct iio_chan_spec lm3533_als_channels[] = {
.type = IIO_LIGHT, .type = IIO_LIGHT,
.channel = 0, .channel = 0,
.indexed = true, .indexed = true,
.info_mask = (IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
IIO_CHAN_INFO_RAW_SEPARATE_BIT), BIT(IIO_CHAN_INFO_RAW),
}, },
CHANNEL_CURRENT(0), CHANNEL_CURRENT(0),
CHANNEL_CURRENT(1), CHANNEL_CURRENT(1),
......
...@@ -530,14 +530,14 @@ static const struct iio_chan_spec tsl2563_channels[] = { ...@@ -530,14 +530,14 @@ static const struct iio_chan_spec tsl2563_channels[] = {
{ {
.type = IIO_LIGHT, .type = IIO_LIGHT,
.indexed = 1, .indexed = 1,
.info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.channel = 0, .channel = 0,
}, { }, {
.type = IIO_INTENSITY, .type = IIO_INTENSITY,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH, .channel2 = IIO_MOD_LIGHT_BOTH,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_CALIBSCALE),
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH, .event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) | IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_BIT(IIO_EV_TYPE_THRESH,
...@@ -546,8 +546,8 @@ static const struct iio_chan_spec tsl2563_channels[] = { ...@@ -546,8 +546,8 @@ static const struct iio_chan_spec tsl2563_channels[] = {
.type = IIO_INTENSITY, .type = IIO_INTENSITY,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_LIGHT_IR, .channel2 = IIO_MOD_LIGHT_IR,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_CALIBSCALE),
} }
}; };
......
...@@ -93,11 +93,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, ...@@ -93,11 +93,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
static const struct iio_chan_spec vcnl4000_channels[] = { static const struct iio_chan_spec vcnl4000_channels[] = {
{ {
.type = IIO_LIGHT, .type = IIO_LIGHT,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, BIT(IIO_CHAN_INFO_SCALE),
}, { }, {
.type = IIO_PROXIMITY, .type = IIO_PROXIMITY,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
} }
}; };
......
...@@ -3,6 +3,17 @@ ...@@ -3,6 +3,17 @@
# #
menu "Magnetometer sensors" menu "Magnetometer sensors"
config AK8975
tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
depends on I2C
depends on GPIOLIB
help
Say yes here to build support for Asahi Kasei AK8975 3-Axis
Magnetometer.
To compile this driver as a module, choose M here: the module
will be called ak8975.
config HID_SENSOR_MAGNETOMETER_3D config HID_SENSOR_MAGNETOMETER_3D
depends on HID_SENSOR_HUB depends on HID_SENSOR_HUB
select IIO_BUFFER select IIO_BUFFER
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Makefile for industrial I/O Magnetometer sensor drivers # Makefile for industrial I/O Magnetometer sensor drivers
# #
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
......
...@@ -94,7 +94,6 @@ struct ak8975_data { ...@@ -94,7 +94,6 @@ struct ak8975_data {
long raw_to_gauss[3]; long raw_to_gauss[3];
u8 reg_cache[AK8975_MAX_REGS]; u8 reg_cache[AK8975_MAX_REGS];
int eoc_gpio; int eoc_gpio;
int eoc_irq;
}; };
static const int ak8975_index_to_reg[] = { static const int ak8975_index_to_reg[] = {
...@@ -123,36 +122,6 @@ static int ak8975_write_data(struct i2c_client *client, ...@@ -123,36 +122,6 @@ static int ak8975_write_data(struct i2c_client *client,
return 0; return 0;
} }
/*
* Helper function to read a contiguous set of the I2C device's registers.
*/
static int ak8975_read_data(struct i2c_client *client,
u8 reg, u8 length, u8 *buffer)
{
int ret;
struct i2c_msg msg[2] = {
{
.addr = client->addr,
.flags = I2C_M_NOSTART,
.len = 1,
.buf = &reg,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = buffer,
}
};
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0) {
dev_err(&client->dev, "Read from device fails\n");
return ret;
}
return 0;
}
/* /*
* Perform some start-of-day setup, including reading the asa calibration * Perform some start-of-day setup, including reading the asa calibration
* values and caching them. * values and caching them.
...@@ -165,11 +134,12 @@ static int ak8975_setup(struct i2c_client *client) ...@@ -165,11 +134,12 @@ static int ak8975_setup(struct i2c_client *client)
int ret; int ret;
/* Confirm that the device we're talking to is really an AK8975. */ /* Confirm that the device we're talking to is really an AK8975. */
ret = ak8975_read_data(client, AK8975_REG_WIA, 1, &device_id); ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n"); dev_err(&client->dev, "Error reading WIA\n");
return ret; return ret;
} }
device_id = ret;
if (device_id != AK8975_DEVICE_ID) { if (device_id != AK8975_DEVICE_ID) {
dev_err(&client->dev, "Device ak8975 not found\n"); dev_err(&client->dev, "Device ak8975 not found\n");
return -ENODEV; return -ENODEV;
...@@ -187,7 +157,8 @@ static int ak8975_setup(struct i2c_client *client) ...@@ -187,7 +157,8 @@ static int ak8975_setup(struct i2c_client *client)
} }
/* Get asa data and store in the device data. */ /* Get asa data and store in the device data. */
ret = ak8975_read_data(client, AK8975_REG_ASAX, 3, data->asa); ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
3, data->asa);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n"); dev_err(&client->dev, "Not able to read asa data\n");
return ret; return ret;
...@@ -249,7 +220,6 @@ static int ak8975_setup(struct i2c_client *client) ...@@ -249,7 +220,6 @@ static int ak8975_setup(struct i2c_client *client)
static int wait_conversion_complete_gpio(struct ak8975_data *data) static int wait_conversion_complete_gpio(struct ak8975_data *data)
{ {
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
u8 read_status;
u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT; u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
int ret; int ret;
...@@ -265,12 +235,11 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data) ...@@ -265,12 +235,11 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
return -EINVAL; return -EINVAL;
} }
ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status); ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
if (ret < 0) { if (ret < 0)
dev_err(&client->dev, "Error in reading ST1\n"); dev_err(&client->dev, "Error in reading ST1\n");
return ret;
} return ret;
return read_status;
} }
static int wait_conversion_complete_polled(struct ak8975_data *data) static int wait_conversion_complete_polled(struct ak8975_data *data)
...@@ -283,11 +252,12 @@ static int wait_conversion_complete_polled(struct ak8975_data *data) ...@@ -283,11 +252,12 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
/* Wait for the conversion to complete. */ /* Wait for the conversion to complete. */
while (timeout_ms) { while (timeout_ms) {
msleep(AK8975_CONVERSION_DONE_POLL_TIME); msleep(AK8975_CONVERSION_DONE_POLL_TIME);
ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status); ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Error in reading ST1\n"); dev_err(&client->dev, "Error in reading ST1\n");
return ret; return ret;
} }
read_status = ret;
if (read_status) if (read_status)
break; break;
timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME; timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
...@@ -308,7 +278,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) ...@@ -308,7 +278,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
u16 meas_reg; u16 meas_reg;
s16 raw; s16 raw;
u8 read_status;
int ret; int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
...@@ -332,18 +301,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) ...@@ -332,18 +301,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
if (ret < 0) if (ret < 0)
goto exit; goto exit;
read_status = ret; if (ret & AK8975_REG_ST1_DRDY_MASK) {
ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
if (read_status & AK8975_REG_ST1_DRDY_MASK) {
ret = ak8975_read_data(client, AK8975_REG_ST2, 1, &read_status);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Error in reading ST2\n"); dev_err(&client->dev, "Error in reading ST2\n");
goto exit; goto exit;
} }
if (read_status & (AK8975_REG_ST2_DERR_MASK | if (ret & (AK8975_REG_ST2_DERR_MASK |
AK8975_REG_ST2_HOFL_MASK)) { AK8975_REG_ST2_HOFL_MASK)) {
dev_err(&client->dev, "ST2 status error 0x%x\n", dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
read_status);
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
...@@ -351,12 +317,12 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) ...@@ -351,12 +317,12 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
/* Read the flux value from the appropriate register /* Read the flux value from the appropriate register
(the register is specified in the iio device attributes). */ (the register is specified in the iio device attributes). */
ret = ak8975_read_data(client, ak8975_index_to_reg[index], ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
2, (u8 *)&meas_reg);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "Read axis data fails\n"); dev_err(&client->dev, "Read axis data fails\n");
goto exit; goto exit;
} }
meas_reg = ret;
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -395,8 +361,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, ...@@ -395,8 +361,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \ .type = IIO_MAGN, \
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_##axis, \ .channel2 = IIO_MOD_##axis, \
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \ .address = index, \
} }
...@@ -452,7 +418,6 @@ static int ak8975_probe(struct i2c_client *client, ...@@ -452,7 +418,6 @@ static int ak8975_probe(struct i2c_client *client,
data->client = client; data->client = client;
mutex_init(&data->lock); mutex_init(&data->lock);
data->eoc_irq = client->irq;
data->eoc_gpio = eoc_gpio; data->eoc_gpio = eoc_gpio;
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
indio_dev->channels = ak8975_channels; indio_dev->channels = ak8975_channels;
......
...@@ -60,28 +60,28 @@ static const struct iio_chan_spec magn_3d_channels[] = { ...@@ -60,28 +60,28 @@ static const struct iio_chan_spec magn_3d_channels[] = {
.type = IIO_MAGN, .type = IIO_MAGN,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_X, .channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X, .scan_index = CHANNEL_SCAN_INDEX_X,
}, { }, {
.type = IIO_MAGN, .type = IIO_MAGN,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Y, .channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y, .scan_index = CHANNEL_SCAN_INDEX_Y,
}, { }, {
.type = IIO_MAGN, .type = IIO_MAGN,
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_Z, .channel2 = IIO_MOD_Z,
.info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
IIO_CHAN_INFO_SCALE_SHARED_BIT | BIT(IIO_CHAN_INFO_SCALE) |
IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} }
}; };
......
...@@ -110,19 +110,15 @@ source "drivers/staging/nvec/Kconfig" ...@@ -110,19 +110,15 @@ source "drivers/staging/nvec/Kconfig"
source "drivers/staging/media/Kconfig" source "drivers/staging/media/Kconfig"
source "drivers/staging/net/Kconfig"
source "drivers/staging/android/Kconfig" source "drivers/staging/android/Kconfig"
source "drivers/staging/ozwpan/Kconfig" source "drivers/staging/ozwpan/Kconfig"
source "drivers/staging/ccg/Kconfig"
source "drivers/staging/gdm72xx/Kconfig" source "drivers/staging/gdm72xx/Kconfig"
source "drivers/staging/csr/Kconfig" source "drivers/staging/csr/Kconfig"
source "drivers/staging/omap-thermal/Kconfig" source "drivers/staging/ti-soc-thermal/Kconfig"
source "drivers/staging/silicom/Kconfig" source "drivers/staging/silicom/Kconfig"
...@@ -140,4 +136,8 @@ source "drivers/staging/zcache/Kconfig" ...@@ -140,4 +136,8 @@ source "drivers/staging/zcache/Kconfig"
source "drivers/staging/goldfish/Kconfig" source "drivers/staging/goldfish/Kconfig"
source "drivers/staging/netlogic/Kconfig"
source "drivers/staging/dwc2/Kconfig"
endif # STAGING endif # STAGING
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
obj-$(CONFIG_STAGING) += staging.o obj-$(CONFIG_STAGING) += staging.o
obj-y += media/ obj-y += media/
obj-y += net/
obj-$(CONFIG_ET131X) += et131x/ obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_USBIP_CORE) += usbip/ obj-$(CONFIG_USBIP_CORE) += usbip/
...@@ -23,6 +22,7 @@ obj-$(CONFIG_RTS5139) += rts5139/ ...@@ -23,6 +22,7 @@ obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/ obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6655) += vt6655/
...@@ -50,10 +50,9 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ ...@@ -50,10 +50,9 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/ obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
obj-$(CONFIG_USB_G_CCG) += ccg/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/ obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_CSR_WIFI) += csr/ obj-$(CONFIG_CSR_WIFI) += csr/
obj-$(CONFIG_OMAP_BANDGAP) += omap-thermal/ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/ obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/ obj-$(CONFIG_DRM_IMX) += imx-drm/
...@@ -62,3 +61,4 @@ obj-$(CONFIG_SB105X) += sb105x/ ...@@ -62,3 +61,4 @@ obj-$(CONFIG_SB105X) += sb105x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_USB_DWC2) += dwc2/
...@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC ...@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC
config ASHMEM config ASHMEM
bool "Enable the Anonymous Shared Memory Subsystem" bool "Enable the Anonymous Shared Memory Subsystem"
default n default n
depends on SHMEM || TINY_SHMEM depends on SHMEM
---help--- ---help---
The ashmem subsystem is a new shared memory allocator, similar to The ashmem subsystem is a new shared memory allocator, similar to
POSIX SHM but with different behavior and sporting a simpler POSIX SHM but with different behavior and sporting a simpler
...@@ -72,6 +72,33 @@ config ANDROID_INTF_ALARM_DEV ...@@ -72,6 +72,33 @@ config ANDROID_INTF_ALARM_DEV
elapsed realtime, and a non-wakeup alarm on the monotonic clock. elapsed realtime, and a non-wakeup alarm on the monotonic clock.
Also exports the alarm interface to user-space. Also exports the alarm interface to user-space.
config SYNC
bool "Synchronization framework"
default n
select ANON_INODES
help
This option enables the framework for synchronization between multiple
drivers. Sync implementations can take advantage of hardware
synchronization built into devices like GPUs.
config SW_SYNC
bool "Software synchronization objects"
default n
depends on SYNC
help
A sync object driver that uses a 32bit counter to coordinate
syncrhronization. Useful when there is no hardware primitive backing
the synchronization.
config SW_SYNC_USER
bool "Userspace API for SW_SYNC"
default n
depends on SW_SYNC
help
Provides a user space API to the sw sync object.
*WARNING* improper use of this can result in deadlocking kernel
drivers from userspace.
endif # if ANDROID endif # if ANDROID
endmenu endmenu
...@@ -7,3 +7,5 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o ...@@ -7,3 +7,5 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
obj-$(CONFIG_SYNC) += sync.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o
...@@ -414,20 +414,29 @@ static int set_prot_mask(struct ashmem_area *asma, unsigned long prot) ...@@ -414,20 +414,29 @@ static int set_prot_mask(struct ashmem_area *asma, unsigned long prot)
static int set_name(struct ashmem_area *asma, void __user *name) static int set_name(struct ashmem_area *asma, void __user *name)
{ {
int ret = 0; int ret = 0;
char local_name[ASHMEM_NAME_LEN];
mutex_lock(&ashmem_mutex); /*
* Holding the ashmem_mutex while doing a copy_from_user might cause
* an data abort which would try to access mmap_sem. If another
* thread has invoked ashmem_mmap then it will be holding the
* semaphore and will be waiting for ashmem_mutex, there by leading to
* deadlock. We'll release the mutex and take the name to a local
* variable that does not need protection and later copy the local
* variable to the structure member with lock held.
*/
if (copy_from_user(local_name, name, ASHMEM_NAME_LEN))
return -EFAULT;
mutex_lock(&ashmem_mutex);
/* cannot change an existing mapping's name */ /* cannot change an existing mapping's name */
if (unlikely(asma->file)) { if (unlikely(asma->file)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
memcpy(asma->name + ASHMEM_NAME_PREFIX_LEN,
if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name, ASHMEM_NAME_LEN);
name, ASHMEM_NAME_LEN)))
ret = -EFAULT;
asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0'; asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0';
out: out:
mutex_unlock(&ashmem_mutex); mutex_unlock(&ashmem_mutex);
...@@ -437,26 +446,36 @@ static int set_name(struct ashmem_area *asma, void __user *name) ...@@ -437,26 +446,36 @@ static int set_name(struct ashmem_area *asma, void __user *name)
static int get_name(struct ashmem_area *asma, void __user *name) static int get_name(struct ashmem_area *asma, void __user *name)
{ {
int ret = 0; int ret = 0;
size_t len;
/*
* Have a local variable to which we'll copy the content
* from asma with the lock held. Later we can copy this to the user
* space safely without holding any locks. So even if we proceed to
* wait for mmap_sem, it won't lead to deadlock.
*/
char local_name[ASHMEM_NAME_LEN];
mutex_lock(&ashmem_mutex); mutex_lock(&ashmem_mutex);
if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') { if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {
size_t len;
/* /*
* Copying only `len', instead of ASHMEM_NAME_LEN, bytes * Copying only `len', instead of ASHMEM_NAME_LEN, bytes
* prevents us from revealing one user's stack to another. * prevents us from revealing one user's stack to another.
*/ */
len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1; len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1;
if (unlikely(copy_to_user(name, memcpy(local_name, asma->name + ASHMEM_NAME_PREFIX_LEN, len);
asma->name + ASHMEM_NAME_PREFIX_LEN, len)))
ret = -EFAULT;
} else { } else {
if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF, len = sizeof(ASHMEM_NAME_DEF);
sizeof(ASHMEM_NAME_DEF)))) memcpy(local_name, ASHMEM_NAME_DEF, len);
ret = -EFAULT;
} }
mutex_unlock(&ashmem_mutex); mutex_unlock(&ashmem_mutex);
/*
* Now we are just copying from the stack variable to userland
* No lock held
*/
if (unlikely(copy_to_user(name, local_name, len)))
ret = -EFAULT;
return ret; return ret;
} }
...@@ -683,6 +702,23 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -683,6 +702,23 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ret; return ret;
} }
/* support of 32bit userspace on 64bit platforms */
#ifdef CONFIG_COMPAT
static long compat_ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case COMPAT_ASHMEM_SET_SIZE:
cmd = ASHMEM_SET_SIZE;
break;
case COMPAT_ASHMEM_SET_PROT_MASK:
cmd = ASHMEM_SET_PROT_MASK;
break;
}
return ashmem_ioctl(file, cmd, arg);
}
#endif
static const struct file_operations ashmem_fops = { static const struct file_operations ashmem_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = ashmem_open, .open = ashmem_open,
...@@ -691,7 +727,9 @@ static const struct file_operations ashmem_fops = { ...@@ -691,7 +727,9 @@ static const struct file_operations ashmem_fops = {
.llseek = ashmem_llseek, .llseek = ashmem_llseek,
.mmap = ashmem_mmap, .mmap = ashmem_mmap,
.unlocked_ioctl = ashmem_ioctl, .unlocked_ioctl = ashmem_ioctl,
.compat_ioctl = ashmem_ioctl, #ifdef CONFIG_COMPAT
.compat_ioctl = compat_ashmem_ioctl,
#endif
}; };
static struct miscdevice ashmem_misc = { static struct miscdevice ashmem_misc = {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/compat.h>
#define ASHMEM_NAME_LEN 256 #define ASHMEM_NAME_LEN 256
...@@ -45,4 +46,10 @@ struct ashmem_pin { ...@@ -45,4 +46,10 @@ struct ashmem_pin {
#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9) #define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10) #define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
/* support of 32bit userspace on 64bit platforms */
#ifdef CONFIG_COMPAT
#define COMPAT_ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, compat_size_t)
#define COMPAT_ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned int)
#endif
#endif /* _LINUX_ASHMEM_H */ #endif /* _LINUX_ASHMEM_H */
...@@ -2878,82 +2878,109 @@ static int binder_release(struct inode *nodp, struct file *filp) ...@@ -2878,82 +2878,109 @@ static int binder_release(struct inode *nodp, struct file *filp)
return 0; return 0;
} }
static int binder_node_release(struct binder_node *node, int refs)
{
struct binder_ref *ref;
int death = 0;
list_del_init(&node->work.entry);
binder_release_work(&node->async_todo);
if (hlist_empty(&node->refs)) {
kfree(node);
binder_stats_deleted(BINDER_STAT_NODE);
return refs;
}
node->proc = NULL;
node->local_strong_refs = 0;
node->local_weak_refs = 0;
hlist_add_head(&node->dead_node, &binder_dead_nodes);
hlist_for_each_entry(ref, &node->refs, node_entry) {
refs++;
if (!ref->death)
goto out;
death++;
if (list_empty(&ref->death->work.entry)) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
list_add_tail(&ref->death->work.entry,
&ref->proc->todo);
wake_up_interruptible(&ref->proc->wait);
} else
BUG();
}
out:
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"node %d now dead, refs %d, death %d\n",
node->debug_id, refs, death);
return refs;
}
static void binder_deferred_release(struct binder_proc *proc) static void binder_deferred_release(struct binder_proc *proc)
{ {
struct binder_transaction *t; struct binder_transaction *t;
struct rb_node *n; struct rb_node *n;
int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count; int threads, nodes, incoming_refs, outgoing_refs, buffers,
active_transactions, page_count;
BUG_ON(proc->vma); BUG_ON(proc->vma);
BUG_ON(proc->files); BUG_ON(proc->files);
hlist_del(&proc->proc_node); hlist_del(&proc->proc_node);
if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) { if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER, binder_debug(BINDER_DEBUG_DEAD_BINDER,
"binder_release: %d context_mgr_node gone\n", "%s: %d context_mgr_node gone\n",
proc->pid); __func__, proc->pid);
binder_context_mgr_node = NULL; binder_context_mgr_node = NULL;
} }
threads = 0; threads = 0;
active_transactions = 0; active_transactions = 0;
while ((n = rb_first(&proc->threads))) { while ((n = rb_first(&proc->threads))) {
struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); struct binder_thread *thread;
thread = rb_entry(n, struct binder_thread, rb_node);
threads++; threads++;
active_transactions += binder_free_thread(proc, thread); active_transactions += binder_free_thread(proc, thread);
} }
nodes = 0; nodes = 0;
incoming_refs = 0; incoming_refs = 0;
while ((n = rb_first(&proc->nodes))) { while ((n = rb_first(&proc->nodes))) {
struct binder_node *node = rb_entry(n, struct binder_node, rb_node); struct binder_node *node;
node = rb_entry(n, struct binder_node, rb_node);
nodes++; nodes++;
rb_erase(&node->rb_node, &proc->nodes); rb_erase(&node->rb_node, &proc->nodes);
list_del_init(&node->work.entry); incoming_refs = binder_node_release(node, incoming_refs);
binder_release_work(&node->async_todo);
if (hlist_empty(&node->refs)) {
kfree(node);
binder_stats_deleted(BINDER_STAT_NODE);
} else {
struct binder_ref *ref;
int death = 0;
node->proc = NULL;
node->local_strong_refs = 0;
node->local_weak_refs = 0;
hlist_add_head(&node->dead_node, &binder_dead_nodes);
hlist_for_each_entry(ref, &node->refs, node_entry) {
incoming_refs++;
if (ref->death) {
death++;
if (list_empty(&ref->death->work.entry)) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
list_add_tail(&ref->death->work.entry, &ref->proc->todo);
wake_up_interruptible(&ref->proc->wait);
} else
BUG();
}
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"node %d now dead, refs %d, death %d\n",
node->debug_id, incoming_refs, death);
}
} }
outgoing_refs = 0; outgoing_refs = 0;
while ((n = rb_first(&proc->refs_by_desc))) { while ((n = rb_first(&proc->refs_by_desc))) {
struct binder_ref *ref = rb_entry(n, struct binder_ref, struct binder_ref *ref;
rb_node_desc);
ref = rb_entry(n, struct binder_ref, rb_node_desc);
outgoing_refs++; outgoing_refs++;
binder_delete_ref(ref); binder_delete_ref(ref);
} }
binder_release_work(&proc->todo); binder_release_work(&proc->todo);
binder_release_work(&proc->delivered_death); binder_release_work(&proc->delivered_death);
buffers = 0;
buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) { while ((n = rb_first(&proc->allocated_buffers))) {
struct binder_buffer *buffer = rb_entry(n, struct binder_buffer, struct binder_buffer *buffer;
rb_node);
buffer = rb_entry(n, struct binder_buffer, rb_node);
t = buffer->transaction; t = buffer->transaction;
if (t) { if (t) {
t->buffer = NULL; t->buffer = NULL;
...@@ -2962,6 +2989,7 @@ static void binder_deferred_release(struct binder_proc *proc) ...@@ -2962,6 +2989,7 @@ static void binder_deferred_release(struct binder_proc *proc)
proc->pid, t->debug_id); proc->pid, t->debug_id);
/*BUG();*/ /*BUG();*/
} }
binder_free_buf(proc, buffer); binder_free_buf(proc, buffer);
buffers++; buffers++;
} }
...@@ -2971,18 +2999,20 @@ static void binder_deferred_release(struct binder_proc *proc) ...@@ -2971,18 +2999,20 @@ static void binder_deferred_release(struct binder_proc *proc)
page_count = 0; page_count = 0;
if (proc->pages) { if (proc->pages) {
int i; int i;
for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
if (proc->pages[i]) { void *page_addr;
void *page_addr = proc->buffer + i * PAGE_SIZE;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC, if (!proc->pages[i])
"binder_release: %d: page %d at %p not freed\n", continue;
proc->pid, i,
page_addr); page_addr = proc->buffer + i * PAGE_SIZE;
unmap_kernel_range((unsigned long)page_addr, binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
PAGE_SIZE); "%s: %d: page %d at %p not freed\n",
__free_page(proc->pages[i]); __func__, proc->pid, i, page_addr);
page_count++; unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
} __free_page(proc->pages[i]);
page_count++;
} }
kfree(proc->pages); kfree(proc->pages);
vfree(proc->buffer); vfree(proc->buffer);
...@@ -2991,9 +3021,9 @@ static void binder_deferred_release(struct binder_proc *proc) ...@@ -2991,9 +3021,9 @@ static void binder_deferred_release(struct binder_proc *proc)
put_task_struct(proc->tsk); put_task_struct(proc->tsk);
binder_debug(BINDER_DEBUG_OPEN_CLOSE, binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"binder_release: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
proc->pid, threads, nodes, incoming_refs, outgoing_refs, __func__, proc->pid, threads, nodes, incoming_refs,
active_transactions, buffers, page_count); outgoing_refs, active_transactions, buffers, page_count);
kfree(proc); kfree(proc);
} }
......
...@@ -85,11 +85,11 @@ struct binder_version { ...@@ -85,11 +85,11 @@ struct binder_version {
#define BINDER_CURRENT_PROTOCOL_VERSION 7 #define BINDER_CURRENT_PROTOCOL_VERSION 7
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t) #define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int) #define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int) #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, int) #define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/* /*
......
...@@ -68,6 +68,8 @@ static LIST_HEAD(log_list); ...@@ -68,6 +68,8 @@ static LIST_HEAD(log_list);
* @log: The associated log * @log: The associated log
* @list: The associated entry in @logger_log's list * @list: The associated entry in @logger_log's list
* @r_off: The current read head offset. * @r_off: The current read head offset.
* @r_all: Reader can read all entries
* @r_ver: Reader ABI version
* *
* This object lives from open to release, so we don't need additional * This object lives from open to release, so we don't need additional
* reference counting. The structure is protected by log->mutex. * reference counting. The structure is protected by log->mutex.
...@@ -76,6 +78,8 @@ struct logger_reader { ...@@ -76,6 +78,8 @@ struct logger_reader {
struct logger_log *log; struct logger_log *log;
struct list_head list; struct list_head list;
size_t r_off; size_t r_off;
bool r_all;
int r_ver;
}; };
/* logger_offset - returns index 'n' into the log via (optimized) modulus */ /* logger_offset - returns index 'n' into the log via (optimized) modulus */
...@@ -109,8 +113,29 @@ static inline struct logger_log *file_get_log(struct file *file) ...@@ -109,8 +113,29 @@ static inline struct logger_log *file_get_log(struct file *file)
} }
/* /*
* get_entry_len - Grabs the length of the payload of the next entry starting * get_entry_header - returns a pointer to the logger_entry header within
* from 'off'. * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
* be provided. Typically the return value will be a pointer within
* 'logger->buf'. However, a pointer to 'scratch' may be returned if
* the log entry spans the end and beginning of the circular buffer.
*/
static struct logger_entry *get_entry_header(struct logger_log *log,
size_t off, struct logger_entry *scratch)
{
size_t len = min(sizeof(struct logger_entry), log->size - off);
if (len != sizeof(struct logger_entry)) {
memcpy(((void *) scratch), log->buffer + off, len);
memcpy(((void *) scratch) + len, log->buffer,
sizeof(struct logger_entry) - len);
return scratch;
}
return (struct logger_entry *) (log->buffer + off);
}
/*
* get_entry_msg_len - Grabs the length of the message of the entry
* starting from from 'off'.
* *
* An entry length is 2 bytes (16 bits) in host endian order. * An entry length is 2 bytes (16 bits) in host endian order.
* In the log, the length does not include the size of the log entry structure. * In the log, the length does not include the size of the log entry structure.
...@@ -118,20 +143,45 @@ static inline struct logger_log *file_get_log(struct file *file) ...@@ -118,20 +143,45 @@ static inline struct logger_log *file_get_log(struct file *file)
* *
* Caller needs to hold log->mutex. * Caller needs to hold log->mutex.
*/ */
static __u32 get_entry_len(struct logger_log *log, size_t off) static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
{ {
__u16 val; struct logger_entry scratch;
struct logger_entry *entry;
/* copy 2 bytes from buffer, in memcpy order, */ entry = get_entry_header(log, off, &scratch);
/* handling possible wrap at end of buffer */ return entry->len;
}
((__u8 *)&val)[0] = log->buffer[off]; static size_t get_user_hdr_len(int ver)
if (likely(off+1 < log->size)) {
((__u8 *)&val)[1] = log->buffer[off+1]; if (ver < 2)
return sizeof(struct user_logger_entry_compat);
else else
((__u8 *)&val)[1] = log->buffer[0]; return sizeof(struct logger_entry);
}
return sizeof(struct logger_entry) + val; static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
char __user *buf)
{
void *hdr;
size_t hdr_len;
struct user_logger_entry_compat v1;
if (ver < 2) {
v1.len = entry->len;
v1.__pad = 0;
v1.pid = entry->pid;
v1.tid = entry->tid;
v1.sec = entry->sec;
v1.nsec = entry->nsec;
hdr = &v1;
hdr_len = sizeof(struct user_logger_entry_compat);
} else {
hdr = entry;
hdr_len = sizeof(struct logger_entry);
}
return copy_to_user(buf, hdr, hdr_len);
} }
/* /*
...@@ -145,15 +195,31 @@ static ssize_t do_read_log_to_user(struct logger_log *log, ...@@ -145,15 +195,31 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
char __user *buf, char __user *buf,
size_t count) size_t count)
{ {
struct logger_entry scratch;
struct logger_entry *entry;
size_t len; size_t len;
size_t msg_start;
/* /*
* We read from the log in two disjoint operations. First, we read from * First, copy the header to userspace, using the version of
* the current read head offset up to 'count' bytes or to the end of * the header requested
*/
entry = get_entry_header(log, reader->r_off, &scratch);
if (copy_header_to_user(reader->r_ver, entry, buf))
return -EFAULT;
count -= get_user_hdr_len(reader->r_ver);
buf += get_user_hdr_len(reader->r_ver);
msg_start = logger_offset(log,
reader->r_off + sizeof(struct logger_entry));
/*
* We read from the msg in two disjoint operations. First, we read from
* the current msg head offset up to 'count' bytes or to the end of
* the log, whichever comes first. * the log, whichever comes first.
*/ */
len = min(count, log->size - reader->r_off); len = min(count, log->size - msg_start);
if (copy_to_user(buf, log->buffer + reader->r_off, len)) if (copy_to_user(buf, log->buffer + msg_start, len))
return -EFAULT; return -EFAULT;
/* /*
...@@ -164,9 +230,34 @@ static ssize_t do_read_log_to_user(struct logger_log *log, ...@@ -164,9 +230,34 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
if (copy_to_user(buf + len, log->buffer, count - len)) if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT; return -EFAULT;
reader->r_off = logger_offset(log, reader->r_off + count); reader->r_off = logger_offset(log, reader->r_off +
sizeof(struct logger_entry) + count);
return count; return count + get_user_hdr_len(reader->r_ver);
}
/*
* get_next_entry_by_uid - Starting at 'off', returns an offset into
* 'log->buffer' which contains the first entry readable by 'euid'
*/
static size_t get_next_entry_by_uid(struct logger_log *log,
size_t off, uid_t euid)
{
while (off != log->w_off) {
struct logger_entry *entry;
struct logger_entry scratch;
size_t next_len;
entry = get_entry_header(log, off, &scratch);
if (entry->euid == euid)
return off;
next_len = sizeof(struct logger_entry) + entry->len;
off = logger_offset(log, off + next_len);
}
return off;
} }
/* /*
...@@ -178,7 +269,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log, ...@@ -178,7 +269,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
* - If there are no log entries to read, blocks until log is written to * - If there are no log entries to read, blocks until log is written to
* - Atomically reads exactly one log entry * - Atomically reads exactly one log entry
* *
* Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read * Will set errno to EINVAL if read
* buffer is insufficient to hold next entry. * buffer is insufficient to hold next entry.
*/ */
static ssize_t logger_read(struct file *file, char __user *buf, static ssize_t logger_read(struct file *file, char __user *buf,
...@@ -219,6 +310,10 @@ static ssize_t logger_read(struct file *file, char __user *buf, ...@@ -219,6 +310,10 @@ static ssize_t logger_read(struct file *file, char __user *buf,
mutex_lock(&log->mutex); mutex_lock(&log->mutex);
if (!reader->r_all)
reader->r_off = get_next_entry_by_uid(log,
reader->r_off, current_euid());
/* is there still something to read or did we race? */ /* is there still something to read or did we race? */
if (unlikely(log->w_off == reader->r_off)) { if (unlikely(log->w_off == reader->r_off)) {
mutex_unlock(&log->mutex); mutex_unlock(&log->mutex);
...@@ -226,7 +321,8 @@ static ssize_t logger_read(struct file *file, char __user *buf, ...@@ -226,7 +321,8 @@ static ssize_t logger_read(struct file *file, char __user *buf,
} }
/* get the size of the next entry */ /* get the size of the next entry */
ret = get_entry_len(log, reader->r_off); ret = get_user_hdr_len(reader->r_ver) +
get_entry_msg_len(log, reader->r_off);
if (count < ret) { if (count < ret) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
...@@ -252,7 +348,8 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len) ...@@ -252,7 +348,8 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
size_t count = 0; size_t count = 0;
do { do {
size_t nr = get_entry_len(log, off); size_t nr = sizeof(struct logger_entry) +
get_entry_msg_len(log, off);
off = logger_offset(log, off + nr); off = logger_offset(log, off + nr);
count += nr; count += nr;
} while (count < len); } while (count < len);
...@@ -382,7 +479,9 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -382,7 +479,9 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
header.tid = current->pid; header.tid = current->pid;
header.sec = now.tv_sec; header.sec = now.tv_sec;
header.nsec = now.tv_nsec; header.nsec = now.tv_nsec;
header.euid = current_euid();
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
header.hdr_size = sizeof(struct logger_entry);
/* null writes succeed, return zero */ /* null writes succeed, return zero */
if (unlikely(!header.len)) if (unlikely(!header.len))
...@@ -463,6 +562,10 @@ static int logger_open(struct inode *inode, struct file *file) ...@@ -463,6 +562,10 @@ static int logger_open(struct inode *inode, struct file *file)
return -ENOMEM; return -ENOMEM;
reader->log = log; reader->log = log;
reader->r_ver = 1;
reader->r_all = in_egroup_p(inode->i_gid) ||
capable(CAP_SYSLOG);
INIT_LIST_HEAD(&reader->list); INIT_LIST_HEAD(&reader->list);
mutex_lock(&log->mutex); mutex_lock(&log->mutex);
...@@ -522,6 +625,10 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) ...@@ -522,6 +625,10 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
poll_wait(file, &log->wq, wait); poll_wait(file, &log->wq, wait);
mutex_lock(&log->mutex); mutex_lock(&log->mutex);
if (!reader->r_all)
reader->r_off = get_next_entry_by_uid(log,
reader->r_off, current_euid());
if (log->w_off != reader->r_off) if (log->w_off != reader->r_off)
ret |= POLLIN | POLLRDNORM; ret |= POLLIN | POLLRDNORM;
mutex_unlock(&log->mutex); mutex_unlock(&log->mutex);
...@@ -529,11 +636,25 @@ static unsigned int logger_poll(struct file *file, poll_table *wait) ...@@ -529,11 +636,25 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
return ret; return ret;
} }
static long logger_set_version(struct logger_reader *reader, void __user *arg)
{
int version;
if (copy_from_user(&version, arg, sizeof(int)))
return -EFAULT;
if ((version < 1) || (version > 2))
return -EINVAL;
reader->r_ver = version;
return 0;
}
static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct logger_log *log = file_get_log(file); struct logger_log *log = file_get_log(file);
struct logger_reader *reader; struct logger_reader *reader;
long ret = -ENOTTY; long ret = -EINVAL;
void __user *argp = (void __user *) arg;
mutex_lock(&log->mutex); mutex_lock(&log->mutex);
...@@ -558,8 +679,14 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -558,8 +679,14 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
} }
reader = file->private_data; reader = file->private_data;
if (!reader->r_all)
reader->r_off = get_next_entry_by_uid(log,
reader->r_off, current_euid());
if (log->w_off != reader->r_off) if (log->w_off != reader->r_off)
ret = get_entry_len(log, reader->r_off); ret = get_user_hdr_len(reader->r_ver) +
get_entry_msg_len(log, reader->r_off);
else else
ret = 0; ret = 0;
break; break;
...@@ -568,11 +695,32 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -568,11 +695,32 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EBADF; ret = -EBADF;
break; break;
} }
if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
capable(CAP_SYSLOG))) {
ret = -EPERM;
break;
}
list_for_each_entry(reader, &log->readers, list) list_for_each_entry(reader, &log->readers, list)
reader->r_off = log->w_off; reader->r_off = log->w_off;
log->head = log->w_off; log->head = log->w_off;
ret = 0; ret = 0;
break; break;
case LOGGER_GET_VERSION:
if (!(file->f_mode & FMODE_READ)) {
ret = -EBADF;
break;
}
reader = file->private_data;
ret = reader->r_ver;
break;
case LOGGER_SET_VERSION:
if (!(file->f_mode & FMODE_READ)) {
ret = -EBADF;
break;
}
reader = file->private_data;
ret = logger_set_version(reader, argp);
break;
} }
mutex_unlock(&log->mutex); mutex_unlock(&log->mutex);
...@@ -592,8 +740,8 @@ static const struct file_operations logger_fops = { ...@@ -592,8 +740,8 @@ static const struct file_operations logger_fops = {
}; };
/* /*
* Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, * Log size must must be a power of two, and greater than
* and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN. * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
*/ */
static int __init create_log(char *log_name, int size) static int __init create_log(char *log_name, int size)
{ {
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
/** /**
* struct logger_entry - defines a single entry that is given to a logger * struct user_logger_entry_compat - defines a single entry that is given to a logger
* @len: The length of the payload * @len: The length of the payload
* @__pad: Two bytes of padding that appear to be required * @__pad: Two bytes of padding that appear to be required
* @pid: The generating process' process ID * @pid: The generating process' process ID
...@@ -29,8 +29,12 @@ ...@@ -29,8 +29,12 @@
* @sec: The number of seconds that have elapsed since the Epoch * @sec: The number of seconds that have elapsed since the Epoch
* @nsec: The number of nanoseconds that have elapsed since @sec * @nsec: The number of nanoseconds that have elapsed since @sec
* @msg: The message that is to be logged * @msg: The message that is to be logged
*
* The userspace structure for version 1 of the logger_entry ABI.
* This structure is returned to userspace unless the caller requests
* an upgrade to a newer ABI version.
*/ */
struct logger_entry { struct user_logger_entry_compat {
__u16 len; __u16 len;
__u16 __pad; __u16 __pad;
__s32 pid; __s32 pid;
...@@ -40,14 +44,38 @@ struct logger_entry { ...@@ -40,14 +44,38 @@ struct logger_entry {
char msg[0]; char msg[0];
}; };
/**
* struct logger_entry - defines a single entry that is given to a logger
* @len: The length of the payload
* @hdr_size: sizeof(struct logger_entry_v2)
* @pid: The generating process' process ID
* @tid: The generating process' thread ID
* @sec: The number of seconds that have elapsed since the Epoch
* @nsec: The number of nanoseconds that have elapsed since @sec
* @euid: Effective UID of logger
* @msg: The message that is to be logged
*
* The structure for version 2 of the logger_entry ABI.
* This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
* is called with version >= 2
*/
struct logger_entry {
__u16 len;
__u16 hdr_size;
__s32 pid;
__s32 tid;
__s32 sec;
__s32 nsec;
uid_t euid;
char msg[0];
};
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */ #define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
#define LOGGER_LOG_MAIN "log_main" /* everything else */ #define LOGGER_LOG_MAIN "log_main" /* everything else */
#define LOGGER_ENTRY_MAX_LEN (4*1024) #define LOGGER_ENTRY_MAX_PAYLOAD 4076
#define LOGGER_ENTRY_MAX_PAYLOAD \
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
#define __LOGGERIO 0xAE #define __LOGGERIO 0xAE
...@@ -55,5 +83,7 @@ struct logger_entry { ...@@ -55,5 +83,7 @@ struct logger_entry {
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
#endif /* _LINUX_LOGGER_H */ #endif /* _LINUX_LOGGER_H */
...@@ -30,16 +30,19 @@ ...@@ -30,16 +30,19 @@
* *
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/swap.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/notifier.h> #include <linux/notifier.h>
static uint32_t lowmem_debug_level = 2; static uint32_t lowmem_debug_level = 1;
static short lowmem_adj[6] = { static short lowmem_adj[6] = {
0, 0,
1, 1,
...@@ -60,7 +63,7 @@ static unsigned long lowmem_deathpending_timeout; ...@@ -60,7 +63,7 @@ static unsigned long lowmem_deathpending_timeout;
#define lowmem_print(level, x...) \ #define lowmem_print(level, x...) \
do { \ do { \
if (lowmem_debug_level >= (level)) \ if (lowmem_debug_level >= (level)) \
printk(x); \ pr_info(x); \
} while (0) } while (0)
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
...@@ -74,7 +77,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) ...@@ -74,7 +77,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
int selected_tasksize = 0; int selected_tasksize = 0;
short selected_oom_score_adj; short selected_oom_score_adj;
int array_size = ARRAY_SIZE(lowmem_adj); int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES); int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
int other_file = global_page_state(NR_FILE_PAGES) - int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM); global_page_state(NR_SHMEM);
......
/*
* drivers/base/sw_sync.c
*
* Copyright (C) 2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/kernel.h>
#include <linux/export.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include "sw_sync.h"
static int sw_sync_cmp(u32 a, u32 b)
{
if (a == b)
return 0;
return ((s32)a - (s32)b) < 0 ? -1 : 1;
}
struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value)
{
struct sw_sync_pt *pt;
pt = (struct sw_sync_pt *)
sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt));
pt->value = value;
return (struct sync_pt *)pt;
}
EXPORT_SYMBOL(sw_sync_pt_create);
static struct sync_pt *sw_sync_pt_dup(struct sync_pt *sync_pt)
{
struct sw_sync_pt *pt = (struct sw_sync_pt *) sync_pt;
struct sw_sync_timeline *obj =
(struct sw_sync_timeline *)sync_pt->parent;
return (struct sync_pt *) sw_sync_pt_create(obj, pt->value);
}
static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt)
{
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
struct sw_sync_timeline *obj =
(struct sw_sync_timeline *)sync_pt->parent;
return sw_sync_cmp(obj->value, pt->value) >= 0;
}
static int sw_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
{
struct sw_sync_pt *pt_a = (struct sw_sync_pt *)a;
struct sw_sync_pt *pt_b = (struct sw_sync_pt *)b;
return sw_sync_cmp(pt_a->value, pt_b->value);
}
static int sw_sync_fill_driver_data(struct sync_pt *sync_pt,
void *data, int size)
{
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
if (size < sizeof(pt->value))
return -ENOMEM;
memcpy(data, &pt->value, sizeof(pt->value));
return sizeof(pt->value);
}
static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline,
char *str, int size)
{
struct sw_sync_timeline *timeline =
(struct sw_sync_timeline *)sync_timeline;
snprintf(str, size, "%d", timeline->value);
}
static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
char *str, int size)
{
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
snprintf(str, size, "%d", pt->value);
}
static struct sync_timeline_ops sw_sync_timeline_ops = {
.driver_name = "sw_sync",
.dup = sw_sync_pt_dup,
.has_signaled = sw_sync_pt_has_signaled,
.compare = sw_sync_pt_compare,
.fill_driver_data = sw_sync_fill_driver_data,
.timeline_value_str = sw_sync_timeline_value_str,
.pt_value_str = sw_sync_pt_value_str,
};
struct sw_sync_timeline *sw_sync_timeline_create(const char *name)
{
struct sw_sync_timeline *obj = (struct sw_sync_timeline *)
sync_timeline_create(&sw_sync_timeline_ops,
sizeof(struct sw_sync_timeline),
name);
return obj;
}
EXPORT_SYMBOL(sw_sync_timeline_create);
void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
{
obj->value += inc;
sync_timeline_signal(&obj->obj);
}
EXPORT_SYMBOL(sw_sync_timeline_inc);
#ifdef CONFIG_SW_SYNC_USER
/* *WARNING*
*
* improper use of this can result in deadlocking kernel drivers from userspace.
*/
/* opening sw_sync create a new sync obj */
static int sw_sync_open(struct inode *inode, struct file *file)
{
struct sw_sync_timeline *obj;
char task_comm[TASK_COMM_LEN];
get_task_comm(task_comm, current);
obj = sw_sync_timeline_create(task_comm);
if (obj == NULL)
return -ENOMEM;
file->private_data = obj;
return 0;
}
static int sw_sync_release(struct inode *inode, struct file *file)
{
struct sw_sync_timeline *obj = file->private_data;
sync_timeline_destroy(&obj->obj);
return 0;
}
static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj, unsigned long arg)
{
int fd = get_unused_fd();
int err;
struct sync_pt *pt;
struct sync_fence *fence;
struct sw_sync_create_fence_data data;
if (fd < 0)
return fd;
if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
err = -EFAULT;
goto err;
}
pt = sw_sync_pt_create(obj, data.value);
if (pt == NULL) {
err = -ENOMEM;
goto err;
}
data.name[sizeof(data.name) - 1] = '\0';
fence = sync_fence_create(data.name, pt);
if (fence == NULL) {
sync_pt_free(pt);
err = -ENOMEM;
goto err;
}
data.fence = fd;
if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
sync_fence_put(fence);
err = -EFAULT;
goto err;
}
sync_fence_install(fence, fd);
return 0;
err:
put_unused_fd(fd);
return err;
}
static long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg)
{
u32 value;
if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
return -EFAULT;
sw_sync_timeline_inc(obj, value);
return 0;
}
static long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct sw_sync_timeline *obj = file->private_data;
switch (cmd) {
case SW_SYNC_IOC_CREATE_FENCE:
return sw_sync_ioctl_create_fence(obj, arg);
case SW_SYNC_IOC_INC:
return sw_sync_ioctl_inc(obj, arg);
default:
return -ENOTTY;
}
}
static const struct file_operations sw_sync_fops = {
.owner = THIS_MODULE,
.open = sw_sync_open,
.release = sw_sync_release,
.unlocked_ioctl = sw_sync_ioctl,
.compat_ioctl = sw_sync_ioctl,
};
static struct miscdevice sw_sync_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sw_sync",
.fops = &sw_sync_fops,
};
static int __init sw_sync_device_init(void)
{
return misc_register(&sw_sync_dev);
}
static void __exit sw_sync_device_remove(void)
{
misc_deregister(&sw_sync_dev);
}
module_init(sw_sync_device_init);
module_exit(sw_sync_device_remove);
#endif /* CONFIG_SW_SYNC_USER */
/*
* include/linux/sw_sync.h
*
* Copyright (C) 2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_SW_SYNC_H
#define _LINUX_SW_SYNC_H
#include <linux/types.h>
#ifdef __KERNEL__
#include "sync.h"
struct sw_sync_timeline {
struct sync_timeline obj;
u32 value;
};
struct sw_sync_pt {
struct sync_pt pt;
u32 value;
};
struct sw_sync_timeline *sw_sync_timeline_create(const char *name);
void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc);
struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value);
#endif /* __KERNEL __ */
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
__s32 fence; /* fd of new fence */
};
#define SW_SYNC_IOC_MAGIC 'W'
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
#endif /* _LINUX_SW_SYNC_H */
此差异已折叠。
/*
* include/linux/sync.h
*
* Copyright (C) 2012 Google, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_SYNC_H
#define _LINUX_SYNC_H
#include <linux/types.h>
#ifdef __KERNEL__
#include <linux/kref.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
struct sync_timeline;
struct sync_pt;
struct sync_fence;
/**
* struct sync_timeline_ops - sync object implementation ops
* @driver_name: name of the implentation
* @dup: duplicate a sync_pt
* @has_signaled: returns:
* 1 if pt has signaled
* 0 if pt has not signaled
* <0 on error
* @compare: returns:
* 1 if b will signal before a
* 0 if a and b will signal at the same time
* -1 if a will signabl before b
* @free_pt: called before sync_pt is freed
* @release_obj: called before sync_timeline is freed
* @print_obj: deprecated
* @print_pt: deprecated
* @fill_driver_data: write implmentation specific driver data to data.
* should return an error if there is not enough room
* as specified by size. This information is returned
* to userspace by SYNC_IOC_FENCE_INFO.
* @timeline_value_str: fill str with the value of the sync_timeline's counter
* @pt_value_str: fill str with the value of the sync_pt
*/
struct sync_timeline_ops {
const char *driver_name;
/* required */
struct sync_pt *(*dup)(struct sync_pt *pt);
/* required */
int (*has_signaled)(struct sync_pt *pt);
/* required */
int (*compare)(struct sync_pt *a, struct sync_pt *b);
/* optional */
void (*free_pt)(struct sync_pt *sync_pt);
/* optional */
void (*release_obj)(struct sync_timeline *sync_timeline);
/* deprecated */
void (*print_obj)(struct seq_file *s,
struct sync_timeline *sync_timeline);
/* deprecated */
void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt);
/* optional */
int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
/* optional */
void (*timeline_value_str)(struct sync_timeline *timeline, char *str,
int size);
/* optional */
void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
};
/**
* struct sync_timeline - sync object
* @kref: reference count on fence.
* @ops: ops that define the implementaiton of the sync_timeline
* @name: name of the sync_timeline. Useful for debugging
* @destoryed: set when sync_timeline is destroyed
* @child_list_head: list of children sync_pts for this sync_timeline
* @child_list_lock: lock protecting @child_list_head, destroyed, and
* sync_pt.status
* @active_list_head: list of active (unsignaled/errored) sync_pts
* @sync_timeline_list: membership in global sync_timeline_list
*/
struct sync_timeline {
struct kref kref;
const struct sync_timeline_ops *ops;
char name[32];
/* protected by child_list_lock */
bool destroyed;
struct list_head child_list_head;
spinlock_t child_list_lock;
struct list_head active_list_head;
spinlock_t active_list_lock;
struct list_head sync_timeline_list;
};
/**
* struct sync_pt - sync point
* @parent: sync_timeline to which this sync_pt belongs
* @child_list: membership in sync_timeline.child_list_head
* @active_list: membership in sync_timeline.active_list_head
* @signaled_list: membership in temorary signaled_list on stack
* @fence: sync_fence to which the sync_pt belongs
* @pt_list: membership in sync_fence.pt_list_head
* @status: 1: signaled, 0:active, <0: error
* @timestamp: time which sync_pt status transitioned from active to
* singaled or error.
*/
struct sync_pt {
struct sync_timeline *parent;
struct list_head child_list;
struct list_head active_list;
struct list_head signaled_list;
struct sync_fence *fence;
struct list_head pt_list;
/* protected by parent->active_list_lock */
int status;
ktime_t timestamp;
};
/**
* struct sync_fence - sync fence
* @file: file representing this fence
* @kref: referenace count on fence.
* @name: name of sync_fence. Useful for debugging
* @pt_list_head: list of sync_pts in ths fence. immutable once fence
* is created
* @waiter_list_head: list of asynchronous waiters on this fence
* @waiter_list_lock: lock protecting @waiter_list_head and @status
* @status: 1: signaled, 0:active, <0: error
*
* @wq: wait queue for fence signaling
* @sync_fence_list: membership in global fence list
*/
struct sync_fence {
struct file *file;
struct kref kref;
char name[32];
/* this list is immutable once the fence is created */
struct list_head pt_list_head;
struct list_head waiter_list_head;
spinlock_t waiter_list_lock; /* also protects status */
int status;
wait_queue_head_t wq;
struct list_head sync_fence_list;
};
struct sync_fence_waiter;
typedef void (*sync_callback_t)(struct sync_fence *fence,
struct sync_fence_waiter *waiter);
/**
* struct sync_fence_waiter - metadata for asynchronous waiter on a fence
* @waiter_list: membership in sync_fence.waiter_list_head
* @callback: function pointer to call when fence signals
* @callback_data: pointer to pass to @callback
*/
struct sync_fence_waiter {
struct list_head waiter_list;
sync_callback_t callback;
};
static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter,
sync_callback_t callback)
{
waiter->callback = callback;
}
/*
* API for sync_timeline implementers
*/
/**
* sync_timeline_create() - creates a sync object
* @ops: specifies the implemention ops for the object
* @size: size to allocate for this obj
* @name: sync_timeline name
*
* Creates a new sync_timeline which will use the implemetation specified by
* @ops. @size bytes will be allocated allowing for implemntation specific
* data to be kept after the generic sync_timeline stuct.
*/
struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
int size, const char *name);
/**
* sync_timeline_destory() - destorys a sync object
* @obj: sync_timeline to destroy
*
* A sync implemntation should call this when the @obj is going away
* (i.e. module unload.) @obj won't actually be freed until all its childern
* sync_pts are freed.
*/
void sync_timeline_destroy(struct sync_timeline *obj);
/**
* sync_timeline_signal() - signal a status change on a sync_timeline
* @obj: sync_timeline to signal
*
* A sync implemntation should call this any time one of it's sync_pts
* has signaled or has an error condition.
*/
void sync_timeline_signal(struct sync_timeline *obj);
/**
* sync_pt_create() - creates a sync pt
* @parent: sync_pt's parent sync_timeline
* @size: size to allocate for this pt
*
* Creates a new sync_pt as a chiled of @parent. @size bytes will be
* allocated allowing for implemntation specific data to be kept after
* the generic sync_timeline struct.
*/
struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size);
/**
* sync_pt_free() - frees a sync pt
* @pt: sync_pt to free
*
* This should only be called on sync_pts which have been created but
* not added to a fence.
*/
void sync_pt_free(struct sync_pt *pt);
/**
* sync_fence_create() - creates a sync fence
* @name: name of fence to create
* @pt: sync_pt to add to the fence
*
* Creates a fence containg @pt. Once this is called, the fence takes
* ownership of @pt.
*/
struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt);
/*
* API for sync_fence consumers
*/
/**
* sync_fence_merge() - merge two fences
* @name: name of new fence
* @a: fence a
* @b: fence b
*
* Creates a new fence which contains copies of all the sync_pts in both
* @a and @b. @a and @b remain valid, independent fences.
*/
struct sync_fence *sync_fence_merge(const char *name,
struct sync_fence *a, struct sync_fence *b);
/**
* sync_fence_fdget() - get a fence from an fd
* @fd: fd referencing a fence
*
* Ensures @fd references a valid fence, increments the refcount of the backing
* file, and returns the fence.
*/
struct sync_fence *sync_fence_fdget(int fd);
/**
* sync_fence_put() - puts a refernnce of a sync fence
* @fence: fence to put
*
* Puts a reference on @fence. If this is the last reference, the fence and
* all it's sync_pts will be freed
*/
void sync_fence_put(struct sync_fence *fence);
/**
* sync_fence_install() - installs a fence into a file descriptor
* @fence: fence to instal
* @fd: file descriptor in which to install the fence
*
* Installs @fence into @fd. @fd's should be acquired through get_unused_fd().
*/
void sync_fence_install(struct sync_fence *fence, int fd);
/**
* sync_fence_wait_async() - registers and async wait on the fence
* @fence: fence to wait on
* @waiter: waiter callback struck
*
* Returns 1 if @fence has already signaled.
*
* Registers a callback to be called when @fence signals or has an error.
* @waiter should be initialized with sync_fence_waiter_init().
*/
int sync_fence_wait_async(struct sync_fence *fence,
struct sync_fence_waiter *waiter);
/**
* sync_fence_cancel_async() - cancels an async wait
* @fence: fence to wait on
* @waiter: waiter callback struck
*
* returns 0 if waiter was removed from fence's async waiter list.
* returns -ENOENT if waiter was not found on fence's async waiter list.
*
* Cancels a previously registered async wait. Will fail gracefully if
* @waiter was never registered or if @fence has already signaled @waiter.
*/
int sync_fence_cancel_async(struct sync_fence *fence,
struct sync_fence_waiter *waiter);
/**
* sync_fence_wait() - wait on fence
* @fence: fence to wait on
* @tiemout: timeout in ms
*
* Wait for @fence to be signaled or have an error. Waits indefinitely
* if @timeout < 0
*/
int sync_fence_wait(struct sync_fence *fence, long timeout);
#endif /* __KERNEL__ */
/**
* struct sync_merge_data - data passed to merge ioctl
* @fd2: file descriptor of second fence
* @name: name of new fence
* @fence: returns the fd of the new fence to userspace
*/
struct sync_merge_data {
__s32 fd2; /* fd of second fence */
char name[32]; /* name of new fence */
__s32 fence; /* fd on newly created fence */
};
/**
* struct sync_pt_info - detailed sync_pt information
* @len: length of sync_pt_info including any driver_data
* @obj_name: name of parent sync_timeline
* @driver_name: name of driver implmenting the parent
* @status: status of the sync_pt 0:active 1:signaled <0:error
* @timestamp_ns: timestamp of status change in nanoseconds
* @driver_data: any driver dependant data
*/
struct sync_pt_info {
__u32 len;
char obj_name[32];
char driver_name[32];
__s32 status;
__u64 timestamp_ns;
__u8 driver_data[0];
};
/**
* struct sync_fence_info_data - data returned from fence info ioctl
* @len: ioctl caller writes the size of the buffer its passing in.
* ioctl returns length of sync_fence_data reutnred to userspace
* including pt_info.
* @name: name of fence
* @status: status of fence. 1: signaled 0:active <0:error
* @pt_info: a sync_pt_info struct for every sync_pt in the fence
*/
struct sync_fence_info_data {
__u32 len;
char name[32];
__s32 status;
__u8 pt_info[0];
};
#define SYNC_IOC_MAGIC '>'
/**
* DOC: SYNC_IOC_WAIT - wait for a fence to signal
*
* pass timeout in milliseconds. Waits indefinitely timeout < 0.
*/
#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
/**
* DOC: SYNC_IOC_MERGE - merge two fences
*
* Takes a struct sync_merge_data. Creates a new fence containing copies of
* the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
* new fence's fd in sync_merge_data.fence
*/
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
/**
* DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
*
* Takes a struct sync_fence_info_data with extra space allocated for pt_info.
* Caller should write the size of the buffer into len. On return, len is
* updated to reflect the total size of the sync_fence_info_data including
* pt_info.
*
* pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
* To itterate over the sync_pt_infos, use the sync_pt_info.len field.
*/
#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
struct sync_fence_info_data)
#endif /* _LINUX_SYNC_H */
#undef TRACE_SYSTEM
#define TRACE_INCLUDE_PATH ../../drivers/staging/android/trace
#define TRACE_SYSTEM sync
#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SYNC_H
#include "../sync.h"
#include <linux/tracepoint.h>
TRACE_EVENT(sync_timeline,
TP_PROTO(struct sync_timeline *timeline),
TP_ARGS(timeline),
TP_STRUCT__entry(
__string(name, timeline->name)
__array(char, value, 32)
),
TP_fast_assign(
__assign_str(name, timeline->name);
if (timeline->ops->timeline_value_str) {
timeline->ops->timeline_value_str(timeline,
__entry->value,
sizeof(__entry->value));
} else {
__entry->value[0] = '\0';
}
),
TP_printk("name=%s value=%s", __get_str(name), __entry->value)
);
TRACE_EVENT(sync_wait,
TP_PROTO(struct sync_fence *fence, int begin),
TP_ARGS(fence, begin),
TP_STRUCT__entry(
__string(name, fence->name)
__field(s32, status)
__field(u32, begin)
),
TP_fast_assign(
__assign_str(name, fence->name);
__entry->status = fence->status;
__entry->begin = begin;
),
TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end",
__get_str(name), __entry->status)
);
TRACE_EVENT(sync_pt,
TP_PROTO(struct sync_pt *pt),
TP_ARGS(pt),
TP_STRUCT__entry(
__string(timeline, pt->parent->name)
__array(char, value, 32)
),
TP_fast_assign(
__assign_str(timeline, pt->parent->name);
if (pt->parent->ops->pt_value_str) {
pt->parent->ops->pt_value_str(pt, __entry->value,
sizeof(__entry->value));
} else {
__entry->value[0] = '\0';
}
),
TP_printk("name=%s value=%s", __get_str(timeline), __entry->value)
);
#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */
/* This part must be outside protection */
#include <trace/define_trace.h>
...@@ -1148,8 +1148,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) ...@@ -1148,8 +1148,8 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 || if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
((ULONG)pBulkBuffer->Register & 0x3)) { ((ULONG)pBulkBuffer->Register & 0x3)) {
kfree(pvBuffer);
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register); BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register);
kfree(pvBuffer);
Status = -EINVAL; Status = -EINVAL;
break; break;
} }
......
...@@ -205,30 +205,6 @@ static int bcm_download_config_file(struct bcm_mini_adapter *Adapter, struct bcm ...@@ -205,30 +205,6 @@ static int bcm_download_config_file(struct bcm_mini_adapter *Adapter, struct bcm
return retval; return retval;
} }
static int bcm_compare_buff_contents(unsigned char *readbackbuff, unsigned char *buff, unsigned int len)
{
int retval = STATUS_SUCCESS;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
if ((len-sizeof(unsigned int)) < 4) {
if (memcmp(readbackbuff , buff, len))
retval = -EINVAL;
} else {
len -= 4;
while (len) {
if (*(unsigned int *)&readbackbuff[len] != *(unsigned int *)&buff[len]) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Firmware Download is not proper");
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Val from Binary %x, Val From Read Back %x ", *(unsigned int *)&buff[len], *(unsigned int*)&readbackbuff[len]);
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "len =%x!!!", len);
retval = -EINVAL;
break;
}
len -= 4;
}
}
return retval;
}
int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo) int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo)
{ {
int retval = STATUS_SUCCESS; int retval = STATUS_SUCCESS;
...@@ -321,9 +297,11 @@ static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter, PUCHAR mappedbuffer, ...@@ -321,9 +297,11 @@ static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter, PUCHAR mappedbuffer,
break; break;
} }
retval = bcm_compare_buff_contents(readbackbuff, mappedbuffer, len); if (memcmp(readbackbuff, mappedbuffer, len) != 0) {
if (STATUS_SUCCESS != retval) pr_err("%s() failed. The firmware doesn't match what was written",
break; __func__);
retval = -EIO;
}
u32StartingAddress += len; u32StartingAddress += len;
u32FirmwareLength -= len; u32FirmwareLength -= len;
......
此差异已折叠。
...@@ -2228,20 +2228,20 @@ int BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter) ...@@ -2228,20 +2228,20 @@ int BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter)
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL"); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL");
return -EINVAL; return -EINVAL;
} }
psAdapter->psFlashCSInfo = (struct bcm_flash_cs_info *)kzalloc(sizeof(struct bcm_flash_cs_info), GFP_KERNEL); psAdapter->psFlashCSInfo = kzalloc(sizeof(struct bcm_flash_cs_info), GFP_KERNEL);
if (psAdapter->psFlashCSInfo == NULL) { if (psAdapter->psFlashCSInfo == NULL) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 1.x"); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 1.x");
return -ENOMEM; return -ENOMEM;
} }
psAdapter->psFlash2xCSInfo = (struct bcm_flash2x_cs_info *)kzalloc(sizeof(struct bcm_flash2x_cs_info), GFP_KERNEL); psAdapter->psFlash2xCSInfo = kzalloc(sizeof(struct bcm_flash2x_cs_info), GFP_KERNEL);
if (!psAdapter->psFlash2xCSInfo) { if (!psAdapter->psFlash2xCSInfo) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 2.x"); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 2.x");
kfree(psAdapter->psFlashCSInfo); kfree(psAdapter->psFlashCSInfo);
return -ENOMEM; return -ENOMEM;
} }
psAdapter->psFlash2xVendorInfo = (struct bcm_flash2x_vendor_info *)kzalloc(sizeof(struct bcm_flash2x_vendor_info), GFP_KERNEL); psAdapter->psFlash2xVendorInfo = kzalloc(sizeof(struct bcm_flash2x_vendor_info), GFP_KERNEL);
if (!psAdapter->psFlash2xVendorInfo) { if (!psAdapter->psFlash2xVendorInfo) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate Vendor Info Memory for Flash 2.x"); BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate Vendor Info Memory for Flash 2.x");
kfree(psAdapter->psFlashCSInfo); kfree(psAdapter->psFlashCSInfo);
...@@ -4074,7 +4074,7 @@ int BcmCopySection(struct bcm_mini_adapter *Adapter, ...@@ -4074,7 +4074,7 @@ int BcmCopySection(struct bcm_mini_adapter *Adapter,
else else
BuffSize = numOfBytes; BuffSize = numOfBytes;
pBuff = (PCHAR)kzalloc(BuffSize, GFP_KERNEL); pBuff = kzalloc(BuffSize, GFP_KERNEL);
if (!pBuff) { if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed.. "); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed.. ");
return -ENOMEM; return -ENOMEM;
...@@ -4154,7 +4154,7 @@ int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned ...@@ -4154,7 +4154,7 @@ int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned
} }
/* If Header is present overwrite passed buffer with this */ /* If Header is present overwrite passed buffer with this */
if (bHasHeader && (Adapter->bHeaderChangeAllowed == FALSE)) { if (bHasHeader && (Adapter->bHeaderChangeAllowed == FALSE)) {
pTempBuff = (PUCHAR)kzalloc(HeaderSizeToProtect, GFP_KERNEL); pTempBuff = kzalloc(HeaderSizeToProtect, GFP_KERNEL);
if (!pTempBuff) { if (!pTempBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed");
return -ENOMEM; return -ENOMEM;
...@@ -4563,7 +4563,7 @@ static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect ...@@ -4563,7 +4563,7 @@ static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect
} }
} }
pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL); pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL);
if (!pBuff) { if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
return -ENOMEM; return -ENOMEM;
...@@ -4622,7 +4622,7 @@ static int CorruptISOSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect ...@@ -4622,7 +4622,7 @@ static int CorruptISOSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect
return SECTOR_IS_NOT_WRITABLE; return SECTOR_IS_NOT_WRITABLE;
} }
pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL); pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL);
if (!pBuff) { if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
return -ENOMEM; return -ENOMEM;
......
if USB_GADGET
config USB_G_CCG
tristate "Configurable Composite Gadget (STAGING)"
depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM && TTY
help
The Configurable Composite Gadget supports multiple USB
functions: acm, mass storage, rndis and FunctionFS.
Each function can be configured and enabled/disabled
dynamically from userspace through a sysfs interface.
In order to compile this (either as a module or built-in),
"USB Gadget Drivers" and anything under it must not be
selected compiled-in in
Device Drivers->USB Support->USB Gadget Support.
However, you can say "M" there, if you do, the
Configurable Composite Gadget can be compiled "M" only
or not at all.
BIG FAT NOTE: DON'T RELY ON THIS USERINTERFACE HERE! AS PART
OF THE REWORK DONE HERE WILL BE A NEW USER INTERFACE WITHOUT ANY
COMPATIBILITY TO THIS SYSFS INTERFACE HERE. BE AWARE OF THIS
BEFORE SELECTING THIS.
endif # USB_GADGET
g_ccg-y := ccg.o
obj-$(CONFIG_USB_G_CCG) += g_ccg.o
TODO:
- change configuration interface from sysfs to configfs
Please send patches to Greg Kroah-Hartmann <gregkh@linuxfoundation.org>,
Andrzej Pietrasiewicz <andrzej.p@samsung.com>, and
Cc: Mike Lockwood <lockwood@android.com>
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* usb/gadget/config.c -- simplify building config descriptors
*
* Copyright (C) 2003 David Brownell
*
* 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.
*/
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
/**
* usb_descriptor_fillbuf - fill buffer with descriptors
* @buf: Buffer to be filled
* @buflen: Size of buf
* @src: Array of descriptor pointers, terminated by null pointer.
*
* Copies descriptors into the buffer, returning the length or a
* negative error code if they can't all be copied. Useful when
* assembling descriptors for an associated set of interfaces used
* as part of configuring a composite device; or in other cases where
* sets of descriptors need to be marshaled.
*/
int
usb_descriptor_fillbuf(void *buf, unsigned buflen,
const struct usb_descriptor_header **src)
{
u8 *dest = buf;
if (!src)
return -EINVAL;
/* fill buffer from src[] until null descriptor ptr */
for (; NULL != *src; src++) {
unsigned len = (*src)->bLength;
if (len > buflen)
return -EINVAL;
memcpy(dest, *src, len);
buflen -= len;
dest += len;
}
return dest - (u8 *)buf;
}
/**
* usb_gadget_config_buf - builts a complete configuration descriptor
* @config: Header for the descriptor, including characteristics such
* as power requirements and number of interfaces.
* @desc: Null-terminated vector of pointers to the descriptors (interface,
* endpoint, etc) defining all functions in this device configuration.
* @buf: Buffer for the resulting configuration descriptor.
* @length: Length of buffer. If this is not big enough to hold the
* entire configuration descriptor, an error code will be returned.
*
* This copies descriptors into the response buffer, building a descriptor
* for that configuration. It returns the buffer length or a negative
* status code. The config.wTotalLength field is set to match the length
* of the result, but other descriptor fields (including power usage and
* interface count) must be set by the caller.
*
* Gadget drivers could use this when constructing a config descriptor
* in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
* resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
*/
int usb_gadget_config_buf(
const struct usb_config_descriptor *config,
void *buf,
unsigned length,
const struct usb_descriptor_header **desc
)
{
struct usb_config_descriptor *cp = buf;
int len;
/* config descriptor first */
if (length < USB_DT_CONFIG_SIZE || !desc)
return -EINVAL;
*cp = *config;
/* then interface/endpoint/class/vendor/... */
len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
length - USB_DT_CONFIG_SIZE, desc);
if (len < 0)
return len;
len += USB_DT_CONFIG_SIZE;
if (len > 0xffff)
return -EINVAL;
/* patch up the config descriptor */
cp->bLength = USB_DT_CONFIG_SIZE;
cp->bDescriptorType = USB_DT_CONFIG;
cp->wTotalLength = cpu_to_le16(len);
cp->bmAttributes |= USB_CONFIG_ATT_ONE;
return len;
}
/**
* usb_copy_descriptors - copy a vector of USB descriptors
* @src: null-terminated vector to copy
* Context: initialization code, which may sleep
*
* This makes a copy of a vector of USB descriptors. Its primary use
* is to support usb_function objects which can have multiple copies,
* each needing different descriptors. Functions may have static
* tables of descriptors, which are used as templates and customized
* with identifiers (for interfaces, strings, endpoints, and more)
* as needed by a given function instance.
*/
struct usb_descriptor_header **
usb_copy_descriptors(struct usb_descriptor_header **src)
{
struct usb_descriptor_header **tmp;
unsigned bytes;
unsigned n_desc;
void *mem;
struct usb_descriptor_header **ret;
/* count descriptors and their sizes; then add vector size */
for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
bytes += (*tmp)->bLength;
bytes += (n_desc + 1) * sizeof(*tmp);
mem = kmalloc(bytes, GFP_KERNEL);
if (!mem)
return NULL;
/* fill in pointers starting at "tmp",
* to descriptors copied starting at "mem";
* and return "ret"
*/
tmp = mem;
ret = mem;
mem += (n_desc + 1) * sizeof(*tmp);
while (*src) {
memcpy(mem, *src, (*src)->bLength);
*tmp = mem;
tmp++;
mem += (*src)->bLength;
src++;
}
*tmp = NULL;
return ret;
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册