-* AKM 8963C Compass sensor
+* AKM 8963/8975/09911 compass sensor
+
+nvi_ (NVI = NVidia/Invensense) drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+The nvi_ak89xx compass sensor driver supports the AK8963, AK8975, and
+AK09911 devices as stand-alone or behind an Invensense MPU.
Required properties:
-- compatible: must be "ak,ak89xx"
+- compatible: Device or generic name.
+ Supported device names:
+ - ak,ak89xx
+ - ak,ak8963
+ - ak,ak8975
+ - ak,ak09911
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "ak,ak8963";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, ak89xx, (Example: compatible = "ak,ak89xx";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
- reg: i2c address of the device. It should be 0x0C or 0x0D.
+ Note: the AKM09911 also supports I2C addresses 0x0E and 0x0F.
Optional properties:
-- magnetic_field_disable: Setting this property to <1> will disable this
- driver: The driver will unload after this property is
- detected.
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+- magnetic_field_disable: Setting this property to <1> will disable the device
+ and unload the driver.
+- vdd-supply: regulator supply for the chip
+- vid-supply: regulator supply for the chip
+ Note: These are required if the driver is to control the regulators.
- magnetic_field_matrix: Orientation matrix for this device.
+- nvi_config: This configures the device's I2C connection.
+ The string options are: auto
+ mpu
+ host
+ auto = the driver will auto detect the connection.
+ mpu = the device is connected to an Invensense auxilary bus.
+ host = the device is connected to the host AP.
+ If this property is not defined, auto will be used.
Example:
-
- ak8963c@0d {
+ ak89xx@0d {
compatible = "ak,ak89xx";
reg = <0x0d>;
magnetic_field_matrix = [ff 00 00 00 ff 00 00 00 01];
-* Bosch BMP-280 pressure sensor
+* Bosch BMP 180/280 pressure sensor
+
+nvi_ (NVI = NVidia/Invensense) drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+The nvi_bmpX80 pressure sensor driver supports the BMP180 and BMP280 devices
+as stand-alone or behind an Invensense MPU.
+If the part is known and is populated, then it can be specified in the DT:
+Example: bmp280@77.
+By specifying a device this way, the driver will assume this specific device
+is populated during system boot and will not verify its existence. If, however,
+the device is unknown or may not be populated, then the label, ak89xx,
+(e.g. bmpX80@77), must be used. This tells the driver to find which device is
+used. If the device is not found, the driver will unload itself. This also
+requires that regulators be setup correctly for the probe function.
Required properties:
-- compatible: must be "bmp,bmpX80"
+- compatible: Device or generic name.
+ Supported names:
+ - bmp,bmpX80
+ - bmp,bmp180
+ - bmp,bmp280
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "bmp,bmp280";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, bmpX80, (Example: compatible = "bmp,bmpX80";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
- reg: i2c address of the device. It should be 0x76 or 0x77.
Optional properties:
-- pressure_disable: Setting this property to <1> will disable this driver:
- The driver will unload after this property is detected.
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+- pressure_disable: Setting this property to <1> will disable the device and
+ unload the driver.
+- vdd-supply: regulator supply for the chip
+- vddio-supply: regulator supply for the chip
+ Note: These are required if the driver is to control the regulators.
- nvi_config: This configures the device's I2C connection.
The string options are: auto
mpu
If this property is not defined, auto will be used.
Example:
-
- bmp280@77 {
+ bmpX80@77 {
compatible = "bmp,bmpX80";
reg = <0x77>;
};
* Capella CM3217 ambient light sensor
+nvs_ drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+
Required properties:
- compatible: must be "capella,cm3217"
- reg: i2c address of the device. It should be 0x10.
-- vdd-supply: regulator supply for the chip
Optional properties:
-- light_disable: Setting this property to <1> will disable this driver:
- The driver will unload after this property is detected.
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+ This device's POR comes up in an operational mode and will draw power.
+ If it is desired to unload the driver leaving the device in a low power
+ sleep state, then use the individual sensor disable mechanism below.
+- light_disable: Setting this property to <1> will disable the device and
+ unload the driver.
+- vdd-supply: regulator supply for the chip
+ Note: This is required if the driver is to control the regulator.
Example:
cm3217@10 {
--- /dev/null
+* Capella CM3218/CM32180/CM32181 ambient light sensor
+
+nvs_ drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+The nvs_cm3218 ALS sensor driver supports the CM3218, CM32180, and CM32181
+devices.
+
+Required properties:
+- compatible: Device or generic name.
+ Supported device names:
+ - capella,cm3218x
+ - capella,cm3218
+ - capella,cm32180
+ - capella,cm32181
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "capella,cm32181";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, cm3218x, (Example: compatible = "capella,cm3218x";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
+- reg: i2c address of the device. It should be 0x10 or 0x48.
+
+Optional properties:
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+ This device's POR comes up in an operational mode and will draw power.
+ If it is desired to unload the driver leaving the device in a low power
+ sleep state, then use the individual sensor disable mechanism below.
+- light_disable: Setting this property to <1> will disable the device and
+ unload the driver.
+- vdd-supply: regulator supply for the chip
+ Note: This is required if the driver is to control the regulator.
+- interrupt-parent: GPIO number
+- interrupts: GPIO macro
+ Note: The driver will operate in poll mode if an interrupt is not specified.
+
+Example:
+ cm3218x@48 {
+ compatible = "capella,cm3218x";
+ reg = <0x10>;
+ vdd-supply = <&palmas_smps9>;
+ };
+
-* Invensense ICM-20628 Gyro/Accelerometer sensor
+* Invensense ICM-20628 and MPUxxxx Gyro/Accelerometer(/compass) sensors
+
+This driver uses the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+The nvi sensor driver supports the ICM, MPU6xxx and MPU9xxx devices.
Required properties:
-- compatible: must be "invensense,mpu6xxx"
+- compatible: Device or generic name.
+ Supported device names:
+ - invensense,mpu6xxx
+ - invensense,mpu6050
+ - invensense,mpu6500
+ - invensense,mpu6515
+ - invensense,mpu9150
+ - invensense,mpu9250
+ - invensense,mpu9350
+ - invensense,icm20628
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "invensense,icm20628";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, mpu6xxx, (Example: compatible = "invensense,mpu6xxx";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
- reg: i2c address of the device. It should be 0x68 or 0x69.
- interrupt-parent: GPIO number
- interrupts: GPIO macro
Optional properties:
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
- accelerometer_disable: Setting this property to <1> will disable the
accelerometer.
- gyroscope_disable: Setting this property to <1> will disable the gyroscope.
accelerometer_disable = <1>;
gyroscope_disable = <1>;
gyro_temp_disable = <1>;
-
+- vdd-supply: regulator supply for the chip
+- vlogic-supply: regulator supply for the chip
+ Note: These are required if the driver is to control the regulators.
- accelerometer_matrix: Orientation matrix for this device.
- gyroscope_matrix: Orientation matrix for this device.
Example:
-
icm20628@69 {
compatible = "invensense,mpu6xxx";
reg = <0x69>;
* IQS2x3 proximity sensor
+nvs_ drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
The nvs_iqs2x3 proximity sensor driver supports the IQS253 and IQS263 devices.
These two parts are not register compatible and therefore should be specified
in the device tree. Example: iqs263@44. By specifying a device this way, the
This also requires that regulators be setup correctly for the probe function.
Required properties:
-- compatible: must be "azoteq,iqs2x3"
+- compatible: Device or generic name.
+ Supported device names:
+ - azoteq,iqs2x3
+ - azoteq,iqs253
+ - azoteq,iqs263
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "azoteq,iqs263";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, iqs2x3, (Example: compatible = "azoteq,iqs2x3";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
- reg: i2c address of the device. It is one of 0x44-0x47.
-- gpio_rdy: gpio to be used for the I2C handshake with the sensor.
+- gpio_rdy: GPIO to be used for the I2C handshake with the sensor.
+ Note: the gpio_rdy GPIO will be used as an interrupt also.
The IQS devices have a very versatile register set. So much so that the entire
register set values can be different among platforms. Because of this, the way
The entry for this example if the register is, say, 0x56, would be:
02, 56, 12, 34, 1E, FF
-Note that the IQS has a funky register set in that each register has its own
-register length. The reason LENGTH is still used is that maybe only the first
-few bytes of a register are to be written. For example, a register that is 20
-bytes long can get by with defining, say 4 for LENGTH, and only the first 4
-bytes will be written.
+The IQS has a funky register set in that each register has its own register
+length. The reason LENGTH is still used is that maybe only the first few bytes
+of a register are to be written. For example, a register that is 20 bytes long
+can get by with defining, say 4 for LENGTH, and only the first 4 bytes will be
+written.
The DT labeling mechanism is based on the part number and the command to be
-accomplished. Currently there are only two commands: initialization and enable.
-For each label, a "_?" is appended where ? is a decimal number starting at 0.
-Note that driver will put the entries in the sequence defined by ? and not by
-the order defined in the DT.
+accomplished. Currently there are four commands: initialization, enable,
+disable, and event. For each label, a "_?" is appended where ? is a decimal
+number starting at 0. Note the driver will put the entries in the sequence
+defined by ? and not by the order defined in the DT.
An example for initialization of the IQS263 part in the DT is as follows:
263init_0 = [05 09 40 03 00 01 03 FF FF FF FF FF]; // 5 bytes to reg 9
263init_1 = [01 0D 09 FF]; // 1 byte written to register 0x0D
263en_touch_0 = [01 09 10 18]; // 1 byte written to register 0x09
263en_touch_1 = [FF 00]; // write flush. See description below.
263en_touch_2 = [01 09 08 18]; // 1 byte written to register 0x09
+Here are the possible disable command labels:
+ 263dis_prox_?
+ 263dis_touch_?
+ 253dis_prox_?
+ 253dis_touch_?
+The disable commands do not need to write to the registers to put the device to
+sleep. When the driver sees that all the sensors are disabled it will handle
+the global sleep.
+The event command allows any necessary action whenever the device receives an
+event:
+ 263event_?
+ 253event_?
+If partial ATI is enabled, the driver will automatically handle the reseeding.
Due to the IQS device's design for communicating with the device, each entry,
which represents an I2C transaction, is actually stacked so that the entire
execute the I2C transactions thus far and if a millisecond delay is to also be
done, then the following byte contains the number of milliseconds to wait,
otherwise the following byte's value is 0.
+The FF does NOT need to be entered at the end of a byte stream command. The
+driver's byte stream parsing engine will automatically execute the I2C
+transactions.
+It is strongly recommended to not use the flush write within an event command
+byte stream.
FYI, internally to the driver, the byte stream terminates when LENGTH is 0.
This is handled automatically by the driver's DT parsing, but is an FYI so that
-0 is never used for LENGTH. Also note that the driver's DT parsing engine has
-error checking and will exit with an error of "ERR: NOMEM @ %s" where %s will
-be the DT label where things went south. The error can be due to truly out of
-buffer memory to non-existent register or incorrect register length.
-Once the driver has loaded, a debug feature that will dump the parsed byte
-stream can be done by doing the following at the device's sysfs directory in an
-adb terminal prompt:
+0 is never used for LENGTH.
+The driver's DT parsing engine has error checking and will exit with an error
+of "ERR: NOMEM @ %s" where %s will be the DT label where things went south.
+The error can be due to truly out of buffer memory to non-existent register or
+incorrect register length. Once the driver has loaded, a debug feature that
+will dump the parsed byte stream can be done by doing the following at the
+device's sysfs directory in an adb terminal prompt:
$echo 10 > nvs
$cat nvs
The results will be something like:
- IQS driver v. 4
+ IQS driver v. 6
os_options=0
stream_mode=0
watchdog_timeout_ms=30000
flush write and mdelay=0
len=1 reg=9 data/mask=8/18
IQS253 initialization:
+Also, a register dump can be done:
+$echo 4 > nvs
+$cat nvs
+During the tuning process, a debug feature can write a byte to a register:
+$echo 0xXXYYZZ1D > nvs
+where XX = the register
+ YY = the register offset
+ ZZ = the byte value
+Other driver debug commands:
+$echo 0x??1C > nvs
+writes ?? to the gpio_sar GPIO.
+$echo 0x??1B > nvs
+writes ?? to the gpio_rdy GPIO.
+$echo 0x1A > nvs
+switches the gpio_rdy GPIO to input.
-Note that in the case the part populated could be either IQS253 or IQS263, both
-the 253 and 263 commands can be defined in the DT. The driver will use the one
+In the case the part populated could be either IQS253 or IQS263, both the 253
+and 263 commands can be defined in the DT. The driver will use the one
according to the part identified.
Optional properties:
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+ This device's POR comes up in an operational mode and will draw power.
+ If it is desired to unload the driver leaving the device in a low power
+ sleep state, then use the individual sensor disable mechanism below.
- SAR_proximity_disable: Setting this property to <1> will disable the
SAR proximity.
- touch_proximity_disable: Setting this property to <1> will disable the
must be disabled:
SAR_proximity_disable = <1>;
touch_proximity_disable = <1>;
-- gpio_sar: gpio to be used for sending proximity event for SAR sensor.
+- vddhi-supply: regulator supply for the chip
+ Note: This is required if the driver is to control the regulator.
+- gpio_sar: GPIO to be used for sending proximity event for SAR sensor.
Note: The gpio_sar define is not required if the following is true:
- The device's PO pin is wired to the device requiring the SAR event.
- The assert level is high.
os_options is > 0, the OS will be tricked into thinking is has control.
In other words, when os_options is 0 (the default), the device will
always be enabled.
-- stream_mode: The device always triggers an interrupt on every read.
+- stream_mode: The device triggers an interrupt on every device data cycle.
Note: As mentioned above, the IQS devices have an, um, interesting mechanism
for communication where there is a small window of time where the
device will respond to I2C commands (the reason for I2C transaction
stacking). When stream mode is disabled, the driver uses a combination
of disabling/enabling the interrupt, which also doubles in forcing the
- communication window, and reading the device's status and data. The
- mechanism allows the device to not interrupt the AP unless an event has
- occured, thereby saving power. However, depending on how the device is
- configured by the DT commands, it may be desirable to disable this
- feature and stream the data instead.
+ communication window, and reading the device's status and data via
+ stream and event modes. The mechanism allows the device to not
+ interrupt the AP unless an event has occured, thereby saving power.
+ However, depending on how the device is configured by the DT commands,
+ it may be desirable to disable this feature and continually stream the
+ data instead.
- watchdog_timeout_ms: When streaming mode is disabled, a watchdog can
periodically stream the data to confirm the device's
status.
gpio_rdy = <&gpio TEGRA_GPIO(A, 1) GPIO_ACTIVE_LOW>;
gpio_sar = <&gpio TEGRA_GPIO(V, 5) GPIO_ACTIVE_LOW>;
sar_assert_polarity = <0>;
- SAR_proximity_no_suspend = <1>;
- touch_proximity_no_suspend = <1>;
os_options = <0>;
263init_0 = [05 09 40 03 00 01 03 FF FF FF FF FF];
263init_1 = [01 0D 09 FF];
* Soltech JSA-1127 ambient light sensor
+nvs_ drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+
Required properties:
- compatible: must be "solteamopto,jsa1127"
-- reg: i2c address of the device. It should be 0x39.
+- reg: i2c address of the device. It can be 0x29, 0x39 or 0x44.
Optional properties:
-- light_disable: Setting this property to <1> will disable this driver:
- The driver will unload after this property is detected.
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
+- light_disable: Setting this property to <1> will disable the device and
+ unload the driver.
+- vdd-supply: regulator supply for the chip
+ Note: This is required if the driver is to control the regulator.
Format: light_mode_settingname
Where: 'light' refers to the light sensor classification
'mode' refers to data collection mode:
-* LTR659 proximity sensor
+* LTR 558/659 ALS/proximity sensor
+
+nvs_ drivers use the NVidia Sensor (NVS) framework.
+See the nvs.txt documentation for NVS DT capabilities.
+The nvs_ltr659 ALS/proximity sensor driver supports the LTR558 and LTR659
+devices.
+If the part is known and is populated, then it can be specified in the DT:
+Example: ltr659@23.
+By specifying a device this way, the driver will assume this specific device
+is populated during system boot and will not verify its existence. If, however,
+the device is unknown or may not be populated, then the label, ltrX5X,
+(e.g. ltrX5X@23), must be used. This tells the driver to find which device is
+used. If the device is not found, the driver will unload itself. This also
+requires that regulators be setup correctly for the probe function.
Required properties:
-- compatible: must be "liteon,ltrX5X"
+- compatible: Device or generic name.
+ Supported device names:
+ - liteon,ltrX5X
+ - liteon,ltr558als
+ - liteon,ltr659ps
+ Note: If the part is known and is populated, then it can be specified:
+ Example: compatible = "liteon,ltr659ps";
+ When specifying a device this way, the driver will assume this specific
+ device is populated during system boot and will not verify its
+ existence. If, however, the device is unknown or may not be populated,
+ then the label, ltrX5X, (Example: compatible = "liteon,ltrX5X";),
+ must be used. This tells the driver to find which device is used. If
+ the device is not found, the driver will unload itself. This requires
+ regulators to be setup correctly for the probe function.
- reg: i2c address of the device. It is 0x23.
-- vdd-supply: regulator supply for chip
-- vled-supply: regulator supply for led anode.
Optional properties:
+- status: set to "ok" or "okay" for normal operation. Set to anything else
+ to unload the driver without ever communicating with the device.
+ Note: The "anything else" above is typically "disabled".
+ Since the driver will unload without communicating with the device, the
+ device will be left in its POR state.
- light_disable: Setting this property to <1> will disable the light sensor.
- proximity_disable: Setting this property to <1> will disable the proximity
sensor.
entire device so that the driver unloads, all sensors must be disabled:
light_disable = <1>;
proximity_disable = <1>;
+- vdd-supply: regulator supply for chip
+- vled-supply: regulator supply for led anode.
+ Note: These are required if the driver is to control the regulators.
Example:
t += sprintf(buf + t, "snsr_id=%d\n", st->cfg->snsr_id);
t += sprintf(buf + t, "timestamp_sz=%d\n", st->cfg->timestamp_sz);
t += sprintf(buf + t, "snsr_data_n=%d\n", st->cfg->snsr_data_n);
- t += sprintf(buf + t, "no_suspend=%x\n", st->cfg->no_suspend);
t += sprintf(buf + t, "kbuf_sz=%d\n", st->cfg->kbuf_sz);
t += sprintf(buf + t, "ch_n=%u\n", st->cfg->ch_n);
t += sprintf(buf + t, "ch_sz=%d\n", st->cfg->ch_sz);
mutex_lock(&indio_dev->mlock);
st->suspend = true;
- if (!st->cfg->no_suspend) {
+ if (!(st->cfg->flags & SENSOR_FLAG_WAKE_UP)) {
ret = st->fn_dev->enable(st->client, st->cfg->snsr_id, -1);
if (ret > 0)
ret = st->fn_dev->enable(st->client,
return (u32)x2;
dividend = (x2 - x1) * (y3 - y1);
- do_div(dividend, divisor);
+ if (dividend < 0) {
+ dividend = abs64(dividend);
+ do_div(dividend, divisor);
+ dividend = 0 - dividend;
+ } else {
+ do_div(dividend, divisor);
+ }
dividend += y1;
if (dividend < 0)
dividend = 0;
nl->cfg->cal_hi);
}
/* report lux */
- nl->handler(nl->nvs_data, &nl->lux, nl->timestamp_report);
+ nl->handler(nl->nvs_st, &nl->lux, nl->timestamp_report);
if ((nl->thresholds_valid) && !nl->report) {
/* calculate low threshold */
calc = (s64)nl->hw;
int ret_t = -EINVAL;
if (nl->cfg)
- nl->cfg->flags = SENSOR_FLAG_ON_CHANGE_MODE;
+ nl->cfg->flags |= SENSOR_FLAG_ON_CHANGE_MODE;
if (np == NULL)
return -EINVAL;
int lenp;
int ret;
- if (np == NULL || cfg == NULL)
+ if (np == NULL)
+ return -EINVAL;
+
+ if (!of_device_is_available(np))
+ return -ENODEV;
+
+ if (cfg == NULL)
return -EINVAL;
if (dev_name == NULL)
dev_name = cfg->name;
+ ret = sprintf(str, "%s_disable", dev_name);
+ if (ret > 0) {
+ ret = of_property_read_u32(np, str, (u32 *)&i);
+ if (!ret) {
+ if (i)
+ cfg->snsr_id = -1;
+ }
+ }
ret = sprintf(str, "%s_float_significance", dev_name);
if (ret > 0) {
if (!(of_property_read_string((struct device_node *)np,
}
}
}
- ret = sprintf(str, "%s_no_suspend", dev_name);
- if (ret > 0) {
- ret = of_property_read_u32(np, str, (u32 *)&i);
- if (!ret) {
- if (i)
- cfg->no_suspend = true;
- else
- cfg->no_suspend = false;
- }
- }
- ret = sprintf(str, "%s_disable", dev_name);
+ ret = sprintf(str, "%s_flags", dev_name);
if (ret > 0) {
ret = of_property_read_u32(np, str, (u32 *)&i);
if (!ret) {
- if (i)
- cfg->snsr_id = -1;
+ cfg->flags &= SENSOR_FLAG_NO_CFG_MASK;
+ i &= ~SENSOR_FLAG_NO_CFG_MASK;
+ cfg->flags |= i;
}
}
ret = sprintf(str, "%s_kbuffer_size", dev_name);
ret = sprintf(str, "%s_fifo_reserved_event_count", dev_name);
if (ret > 0)
of_property_read_u32(np, str, (u32 *)&cfg->fifo_max_evnt_cnt);
- ret = sprintf(str, "%s_flags", dev_name);
- if (ret > 0)
- of_property_read_u32(np, str, (u32 *)&cfg->flags);
ret = sprintf(str, "%s_matrix", dev_name);
if (ret > 0) {
charp = of_get_property(np, str, &lenp);
}
dividend = (x2 - x1) * (y3 - y1);
- do_div(dividend, divisor);
+ if (dividend < 0) {
+ dividend = abs64(dividend);
+ do_div(dividend, divisor);
+ dividend = 0 - dividend;
+ } else {
+ do_div(dividend, divisor);
+ }
dividend += y1;
if (dividend < 0)
dividend = 0;
if (np->report && report_delay_min) {
np->report--;
np->timestamp_report = np->timestamp;
- np->handler(np->nvs_data, &np->proximity,
+ np->handler(np->nvs_st, &np->proximity,
np->timestamp_report);
ret = RET_HW_UPDATE;
}
if (np->report && report_delay_min) {
np->report--;
np->timestamp_report = np->timestamp;
- np->handler(np->nvs_data, &np->proximity,
+ np->handler(np->nvs_st, &np->proximity,
np->timestamp_report);
ret = RET_HW_UPDATE;
}
np->cfg->cal_hi);
}
/* report proximity */
- np->handler(np->nvs_data, &np->proximity,
+ np->handler(np->nvs_st, &np->proximity,
np->timestamp_report);
if ((np->thresholds_valid) && !np->report) {
/* calculate low threshold */
int ret;
if (np->cfg)
- np->cfg->flags = SENSOR_FLAG_ON_CHANGE_MODE;
+ np->cfg->flags |= SENSOR_FLAG_ON_CHANGE_MODE;
if (dn == NULL)
return -EINVAL;
#include "nvi.h"
-#define NVI_DRIVER_VERSION (208)
+#define NVI_DRIVER_VERSION (209)
#define NVI_NAME "mpu6xxx"
#define NVI_NAME_MPU6050 "MPU6050"
#define NVI_NAME_MPU6500 "MPU6500"
{
struct i2c_msg msg;
- msg.addr = addr;
- msg.flags = 0;
- msg.len = len;
- msg.buf = buf;
- if (i2c_transfer(st->i2c->adapter, &msg, 1) != 1) {
- nvi_err(st);
- return -EIO;
+ if (addr) {
+ msg.addr = addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = buf;
+ if (i2c_transfer(st->i2c->adapter, &msg, 1) != 1) {
+ nvi_err(st);
+ return -EIO;
+ }
}
return 0;
{
struct i2c_msg msg[2];
- msg[0].addr = addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = ®
- msg[1].addr = addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = len;
- msg[1].buf = buf;
- if (i2c_transfer(st->i2c->adapter, msg, 2) != 2) {
- nvi_err(st);
- return -EIO;
+ if (addr) {
+ msg[0].addr = addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = ®
+ msg[1].addr = addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = buf;
+ if (i2c_transfer(st->i2c->adapter, msg, 2) != 2) {
+ nvi_err(st);
+ return -EIO;
+ }
}
return 0;
struct nvi_state *st = (struct nvi_state *)dev_id;
struct aux_port *ap;
u16 fifo_count = 0;
- u16 fifo_sample_size;
+ u16 fifo_sample_size = 0;
u16 fifo_rd_n;
u16 fifo_align;
s64 ts;
static int nvi_of_dt(struct nvi_state *st, struct device_node *dn)
{
u32 tmp;
+ unsigned int i;
+ int ret;
+
+ /* common NVS parameters */
+ for (i = 0; i < DEV_N; i++) {
+ ret = nvs_of_dt(dn, &st->cfg[i], NULL);
+ if (ret == -ENODEV)
+ /* the entire device has been disabled */
+ return -ENODEV;
+ }
/* device specific parameters */
if (!of_property_read_u32(dn, "invensense,standby_en", &tmp)) {
nvi_init_config(st);
if (client->dev.of_node) {
ret = nvi_of_dt(st, client->dev.of_node);
- if (ret)
+ if (ret) {
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n",
+ __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n",
+ __func__);
+ ret = -ENODEV;
+ }
goto nvi_probe_err;
+ }
} else {
pdata = (struct mpu_platform_data *)
dev_get_platdata(&client->dev);
n = 0;
for (i = 0; i < DEV_N; i++) {
- /* populate any overrides */
- ret = nvs_of_dt(client->dev.of_node, &st->cfg[i], NULL);
- if (ret == -ENODEV)
- /* the entire device has been disabled */
- goto nvi_probe_err;
-
ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev,
&nvi_fn_dev, &st->cfg[i]);
if (!ret) {
{ "mpu9250", 0 },
{ "mpu9150", 0 },
{ "mpu9350", 0 },
+ { "icm20628", 0 },
{}
};
{ .compatible = "invensense,mpu9150", },
{ .compatible = "invensense,mpu9250", },
{ .compatible = "invensense,mpu9350", },
+ { .compatible = "invensense,icm20628", },
{}
};
-/* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+/* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
struct cm_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data;
+ void *nvs_st;
struct sensor_cfg cfg;
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(cm_vregs)];
unsigned int sts; /* debug flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
- bool iio_ts_en; /* use IIO timestamps */
bool hw_change; /* HW changed so drop first sample */
u8 cmd1; /* store for register dump */
u8 cmd2; /* store for register dump */
};
-static s64 cm_get_time_ns(struct cm_state *st)
+static s64 cm_get_time_ns(void)
{
struct timespec ts;
- if (st->iio_ts_en)
- return iio_get_time_ns();
-
ktime_get_ts(&ts);
return timespec_to_ns(&ts);
}
if (ret)
return ret;
- ts = cm_get_time_ns(st);
+ ts = cm_get_time_ns();
if (st->sts & NVS_STS_SPEW_DATA)
dev_info(&st->i2c->dev,
"poll light hw %hu %lld diff=%d %lldns index=%u\n",
static void cm_read(struct cm_state *st)
{
- st->nvs->nvs_mutex_lock(st->nvs_data);
+ st->nvs->nvs_mutex_lock(st->nvs_st);
if (st->enabled) {
cm_rd(st);
schedule_delayed_work(&st->dw,
msecs_to_jiffies(st->light.poll_delay_ms));
}
- st->nvs->nvs_mutex_unlock(st->nvs_data);
+ st->nvs->nvs_mutex_unlock(st->nvs_st);
}
static void cm_work(struct work_struct *ws)
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->suspend(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->suspend(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
return ret;
struct cm_state *st = i2c_get_clientdata(client);
int ret = 0;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->resume(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->resume(st->nvs_st);
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
struct cm_state *st = i2c_get_clientdata(client);
st->sts |= NVS_STS_SHUTDOWN;
- if (st->nvs && st->nvs_data)
- st->nvs->shutdown(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->shutdown(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
}
if (st != NULL) {
cm_shutdown(client);
- if (st->nvs && st->nvs_data)
- st->nvs->remove(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->remove(st->nvs_st);
if (st->dw.wq)
destroy_workqueue(st->dw.wq);
cm_pm_exit(st);
static struct sensor_cfg cm_cfg_dflt = {
.name = NVS_LIGHT_STRING,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = CM_NAME,
.vendor = CM_VENDOR,
.version = CM_LIGHT_VERSION,
},
.delay_us_min = CM_POLL_DLY_MS_MIN * 1000,
.delay_us_max = CM_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = CM_LIGHT_SCALE_IVAL,
.fval = CM_LIGHT_SCALE_MICRO,
static int cm_of_dt(struct cm_state *st, struct device_node *dn)
{
unsigned int i;
+ int ret;
/* default NVS programmable parameters */
memcpy(&st->cfg, &cm_cfg_dflt, sizeof(st->cfg));
st->light.hw_mask = 0xFFFF;
st->light.nld_tbl = cm_nld_tbl;
/* device tree parameters */
- if (dn)
- /* common NVS IIO programmable parameters */
- st->iio_ts_en = of_property_read_bool(dn, "iio_timestamps");
- /* common NVS parameters */
- nvs_of_dt(dn, &st->cfg, NULL);
- /* this device supports these programmable parameters */
+ ret = nvs_of_dt(dn, &st->cfg, NULL);
+ if (ret == -ENODEV)
+ return -ENODEV;
+
if (nvs_light_of_dt(&st->light, dn, NULL)) {
st->light.nld_i_lo = 0;
st->light.nld_i_hi = ARRAY_SIZE(cm_nld_tbl) - 1;
st->i2c = client;
ret = cm_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto cm_probe_exit;
}
goto cm_probe_exit;
}
- ret = st->nvs->probe(&st->nvs_data, st, &client->dev,
+ st->light.handler = st->nvs->handler;
+ ret = st->nvs->probe(&st->nvs_st, st, &client->dev,
&cm_fn_dev, &st->cfg);
if (ret) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto cm_probe_exit;
}
- st->light.nvs_data = st->nvs_data;
- st->light.handler = st->nvs->handler;
+ st->light.nvs_st = st->nvs_st;
INIT_DELAYED_WORK(&st->dw, cm_work);
dev_info(&client->dev, "%s done\n", __func__);
return 0;
#define CM_LIGHT_VERSION (1)
#define CM_LIGHT_SCALE_IVAL (0)
#define CM_LIGHT_SCALE_MICRO (10000)
-#define CM_LIGHT_THRESHOLD_LO (100)
-#define CM_LIGHT_THRESHOLD_HI (100)
+#define CM_LIGHT_THRESHOLD_LO (10)
+#define CM_LIGHT_THRESHOLD_HI (10)
#define CM_POLL_DLY_MS_MAX (4000)
/* HW registers */
#define CM_REG_CFG (0x00)
};
static struct nvs_light_dynamic cm3218_nld_tbl[] = {
- { {0, 3570}, {233, 959950}, {0, 130000}, 1000, 0x00C0 },
- { {0, 7140}, {467, 919900}, {0, 130000}, 500, 0x0080 },
- { {0, 14280}, {935, 839800}, {0, 130000}, 250, 0x0040 },
- { {0, 28560}, {1871, 679600}, {0, 130000}, 125, 0x0000 }
+ { {0, 3571}, {234, 25485}, {0, 130000}, 1000, 0x08C0 },
+ { {0, 7140}, {467, 919900}, {0, 130000}, 500, 0x0880 },
+ { {0, 14280}, {935, 839800}, {0, 130000}, 250, 0x0840 },
+ { {0, 28570}, {1872, 334950}, {0, 130000}, 125, 0x0800 }
};
static struct nvs_light_dynamic cm32180_nld_tbl[] = {
- { {0, 890}, {58, 326150}, {0, 130000}, 1000, 0x00C0 },
- { {0, 1780}, {116, 652300}, {0, 130000}, 500, 0x0080 },
- { {0, 3560}, {233, 304600}, {0, 130000}, 250, 0x0040 },
- { {0, 7120}, {466, 609200}, {0, 130000}, 125, 0x0000 }
+ { {0, 3571}, {234, 25485}, {0, 130000}, 1000, 0x08C0 },
+ { {0, 7140}, {467, 919900}, {0, 130000}, 500, 0x0880 },
+ { {0, 14280}, {935, 839800}, {0, 130000}, 250, 0x0840 },
+ { {0, 28570}, {1872, 334950}, {0, 130000}, 125, 0x0800 }
};
static struct nvs_light_dynamic cm32181_nld_tbl[] = {
struct cm_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data;
+ void *nvs_st;
struct sensor_cfg cfg;
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(cm_vregs)];
unsigned int sts; /* debug flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
- bool iio_ts_en; /* use IIO timestamps */
bool hw_change; /* HW changed so drop first sample */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
};
-static s64 cm_get_time_ns(struct cm_state *st)
+static s64 cm_get_time_ns(void)
{
struct timespec ts;
- if (st->iio_ts_en)
- return iio_get_time_ns();
-
ktime_get_ts(&ts);
return timespec_to_ns(&ts);
}
return 0;
}
- ts = cm_get_time_ns(st);
+ ts = cm_get_time_ns();
if (st->sts & NVS_STS_SPEW_DATA)
dev_info(&st->i2c->dev,
"poll light hw %hu %lld diff=%d %lldns index=%u\n",
{
int ret;
- st->nvs->nvs_mutex_lock(st->nvs_data);
+ st->nvs->nvs_mutex_lock(st->nvs_st);
if (st->enabled) {
ret = cm_rd(st);
if (ret < RET_HW_UPDATE)
schedule_delayed_work(&st->dw,
msecs_to_jiffies(st->light.poll_delay_ms));
}
- st->nvs->nvs_mutex_unlock(st->nvs_data);
+ st->nvs->nvs_mutex_unlock(st->nvs_st);
}
static void cm_work(struct work_struct *ws)
t = sprintf(buf, "registers:\n");
for (i = 0; i <= CM_REG_ALS_IF; i++) {
ret = cm_i2c_rd(st, i, &val);
- if (!ret)
+ if (ret)
+ t += sprintf(buf + t, "%#2x=ERR: %d\n", i, ret);
+ else
t += sprintf(buf + t, "%#2x=%#4x\n", i, val);
}
return t;
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->suspend(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->suspend(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
return ret;
struct cm_state *st = i2c_get_clientdata(client);
int ret = 0;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->resume(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->resume(st->nvs_st);
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
struct cm_state *st = i2c_get_clientdata(client);
st->sts |= NVS_STS_SHUTDOWN;
- if (st->nvs && st->nvs_data)
- st->nvs->shutdown(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->shutdown(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
}
if (st != NULL) {
cm_shutdown(client);
- if (st->nvs && st->nvs_data)
- st->nvs->remove(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->remove(st->nvs_st);
if (st->dw.wq)
destroy_workqueue(st->dw.wq);
cm_pm_exit(st);
static struct sensor_cfg cm_cfg_dflt = {
.name = NVS_LIGHT_STRING,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = CM_NAME,
.vendor = CM_VENDOR,
.version = CM_LIGHT_VERSION,
.delay_us_max = CM_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = CM_LIGHT_SCALE_IVAL,
.fval = CM_LIGHT_SCALE_MICRO,
{
u16 als_sm;
u16 als_pers;
+ int ret;
/* default device specific parameters */
als_sm = CM_ALS_SM_DFLT;
st->light.nld_tbl = st->nld_tbl;
/* device tree parameters */
if (dn) {
- /* common NVS IIO programmable parameters */
- st->iio_ts_en = of_property_read_bool(dn, "iio_timestamps");
+ /* common NVS parameters */
+ ret = nvs_of_dt(dn, &st->cfg, NULL);
+ if (ret == -ENODEV)
+ return -ENODEV;
+
/* device specific parameters */
of_property_read_u16(dn, "als_sm", &als_sm);
of_property_read_u16(dn, "als_pers", &als_pers);
of_property_read_u16(dn, "als_psm", &st->als_psm);
of_property_read_u32(dn, "Rset", &st->r_set);
}
- /* common NVS parameters */
- nvs_of_dt(dn, &st->cfg, NULL);
+
/* this device supports these programmable parameters */
if (nvs_light_of_dt(&st->light, dn, NULL)) {
st->light.nld_i_lo = 0;
st->i2c = client;
ret = cm_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto cm_probe_exit;
}
goto cm_probe_exit;
}
- ret = st->nvs->probe(&st->nvs_data, st, &client->dev,
+ st->light.handler = st->nvs->handler;
+ ret = st->nvs->probe(&st->nvs_st, st, &client->dev,
&cm_fn_dev, &st->cfg);
if (ret) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto cm_probe_exit;
}
- st->light.nvs_data = st->nvs_data;
- st->light.handler = st->nvs->handler;
+ st->light.nvs_st = st->nvs_st;
INIT_DELAYED_WORK(&st->dw, cm_work);
if (client->irq) {
ret = request_threaded_irq(client->irq, NULL, cm_irq_thread,
-/* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+/* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
struct isl_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data[ISL_DEV_N];
+ void *nvs_st[ISL_DEV_N];
struct sensor_cfg cfg[ISL_DEV_N];
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(isl_vregs)];
struct nvs_light light;
struct nvs_proximity prox;
- unsigned int dev[ISL_DEV_N];
- unsigned int snsr_n; /* number of sensors */
unsigned int sts; /* status flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
- bool iio_ts_en; /* use IIO timestamps */
bool irq_dis; /* interrupt host disable flag */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
};
-static s64 isl_get_time_ns(struct isl_state *st)
+static s64 isl_get_time_ns(void)
{
struct timespec ts;
- if (st->iio_ts_en)
- return iio_get_time_ns();
-
ktime_get_ts(&ts);
return timespec_to_ns(&ts);
}
st->errs--;
}
+static void isl_mutex_lock(struct isl_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_lock(st->nvs_st[i]);
+ }
+ }
+}
+
+static void isl_mutex_unlock(struct isl_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_unlock(st->nvs_st[i]);
+ }
+ }
+}
+
static int isl_i2c_read(struct isl_state *st, u8 reg, u16 len, u8 *val)
{
struct i2c_msg msg[2];
s64 ts;
int ret = 0;
- ts = isl_get_time_ns(st);
+ ts = isl_get_time_ns();
if (st->enabled & (1 << ISL_DEV_PROX))
ret |= isl_rd_prox(st, ts);
if (st->enabled & (1 << ISL_DEV_LIGHT))
static void isl_read(struct isl_state *st)
{
- unsigned int i;
int ret;
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_lock(st->nvs_data[i]);
+ isl_mutex_lock(st);
if (st->enabled) {
ret = isl_rd(st);
if (ret < 1)
schedule_delayed_work(&st->dw,
msecs_to_jiffies(isl_polldelay(st)));
}
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_unlock(st->nvs_data[i]);
+ isl_mutex_unlock(st);
}
static void isl_work(struct work_struct *ws)
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->suspend(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->suspend(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
unsigned int i;
int ret = 0;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->resume(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->resume(st->nvs_st[i]);
+ }
}
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
unsigned int i;
st->sts |= NVS_STS_SHUTDOWN;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- st->nvs->shutdown(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->shutdown(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
if (st != NULL) {
isl_shutdown(client);
if (st->nvs) {
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs_data[i])
- st->nvs->remove(st->nvs_data[i]);
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->remove(st->nvs_st[i]);
}
}
if (st->dw.wq)
{
.name = NVS_LIGHT_STRING,
.snsr_id = ISL_DEV_LIGHT,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = ISL_NAME,
.vendor = ISL_VENDOR,
.version = ISL_LIGHT_VERSION,
},
.delay_us_min = ISL_POLL_DLY_MS_MIN * 1000,
.delay_us_max = ISL_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = ISL_LIGHT_SCALE_IVAL,
.fval = ISL_LIGHT_SCALE_MICRO,
{
.name = NVS_PROXIMITY_STRING,
.snsr_id = ISL_DEV_PROX,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_proximity),
- .ch_inf = &iio_chan_spec_nvs_proximity,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = ISL_NAME,
.vendor = ISL_VENDOR,
.version = ISL_PROX_VERSION,
},
.delay_us_min = ISL_POLL_DLY_MS_MIN * 1000,
.delay_us_max = ISL_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE |
+ SENSOR_FLAG_WAKE_UP,
.scale = {
.ival = ISL_PROX_SCALE_IVAL,
.fval = ISL_PROX_SCALE_MICRO,
static int isl_of_dt(struct isl_state *st, struct device_node *dn)
{
unsigned int i;
+ int ret;
for (i = 0; i < ISL_DEV_N; i++)
- memcpy(&st->cfg[i], &isl_cfg_dflt[i],
- sizeof(struct sensor_cfg));
+ memcpy(&st->cfg[i], &isl_cfg_dflt[i], sizeof(st->cfg[0]));
+ st->light.cfg = &st->cfg[ISL_DEV_LIGHT];
st->light.hw_mask = 0x0FFF;
st->light.nld_tbl = isl_nld_tbl;
+ st->prox.cfg = &st->cfg[ISL_DEV_PROX];
st->prox.hw_mask = 0x00FF;
/* default device specific parameters */
st->reg_cfg = ISL_CFG_DFLT;
st->reg_int = ISL_INT_DFLT;
/* device tree parameters */
if (dn) {
- /* common NVS programmable parameters */
- st->iio_ts_en = of_property_read_bool(dn, "iio_timestamps");
+ /* common NVS parameters */
+ for (i = 0; i < ISL_DEV_N; i++) {
+ ret = nvs_of_dt(dn, &st->cfg[i], NULL);
+ if (ret == -ENODEV)
+ /* the entire device has been disabled */
+ return -ENODEV;
+ }
+
/* device specific parameters */
of_property_read_u8(dn, "configure_reg", &st->reg_cfg);
of_property_read_u8(dn, "interrupt_reg", &st->reg_int);
}
- /* common NVS parameters */
- for (i = 0; i < ISL_DEV_N; i++)
- nvs_of_dt(dn, &st->cfg[i], NULL);
/* this device supports these programmable parameters */
if (nvs_light_of_dt(&st->light, dn, NULL)) {
st->light.nld_i_lo = 0;
st->i2c = client;
ret = isl_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto isl_probe_exit;
}
goto isl_probe_exit;
}
+ st->light.handler = st->nvs->handler;
+ st->prox.handler = st->nvs->handler;
n = 0;
for (i = 0; i < ISL_DEV_N; i++) {
- ret = st->nvs->probe(&st->nvs_data[n], st, &client->dev,
+ ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev,
&isl_fn_dev, &st->cfg[i]);
- if (!ret) {
- st->dev[n] = st->cfg[i].snsr_id;
- if (st->dev[n] == ISL_DEV_LIGHT) {
- st->light.cfg = &st->cfg[i];
- st->light.nvs_data = st->nvs_data[n];
- st->light.handler = st->nvs->handler;
- } else if (st->dev[n] == ISL_DEV_PROX) {
- st->prox.cfg = &st->cfg[i];
- st->prox.nvs_data = st->nvs_data[n];
- st->prox.handler = st->nvs->handler;
- }
+ if (!ret)
n++;
- }
}
if (!n) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto isl_probe_exit;
}
- st->snsr_n = n;
+ st->light.nvs_st = st->nvs_st[ISL_DEV_LIGHT];
+ st->prox.nvs_st = st->nvs_st[ISL_DEV_PROX];
INIT_DELAYED_WORK(&st->dw, isl_work);
if (client->irq) {
irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
- irqflags |= IRQF_NO_SUSPEND; /* for proximity */
+ for (i = 0; i < ISL_DEV_N; i++) {
+ if (st->cfg[i].snsr_id >= 0) {
+ if (st->cfg[i].flags & SENSOR_FLAG_WAKE_UP)
+ irqflags |= IRQF_NO_SUSPEND;
+ }
+ }
ret = request_threaded_irq(client->irq, NULL, isl_irq_thread,
irqflags, ISL_NAME, st);
if (ret) {
-/* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+/* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
struct jsa_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data;
+ void *nvs_st;
struct sensor_cfg cfg;
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(jsa_vregs)];
unsigned int ms;
int ret;
- st->nvs->nvs_mutex_lock(st->nvs_data);
+ st->nvs->nvs_mutex_lock(st->nvs_st);
if (st->enabled) {
if (st->hw_it) {
jsa_rd(st);
"%s schedule_delayed_work=%ums\n",
__func__, ms);
}
- st->nvs->nvs_mutex_unlock(st->nvs_data);
+ st->nvs->nvs_mutex_unlock(st->nvs_st);
}
static void jsa_work(struct work_struct *ws)
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->suspend(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->suspend(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
return ret;
struct jsa_state *st = i2c_get_clientdata(client);
int ret = 0;
- if (st->nvs && st->nvs_data)
- ret = st->nvs->resume(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ ret = st->nvs->resume(st->nvs_st);
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
struct jsa_state *st = i2c_get_clientdata(client);
st->sts |= NVS_STS_SHUTDOWN;
- if (st->nvs && st->nvs_data)
- st->nvs->shutdown(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->shutdown(st->nvs_st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
}
if (st != NULL) {
jsa_shutdown(client);
- if (st->nvs && st->nvs_data)
- st->nvs->remove(st->nvs_data);
+ if (st->nvs && st->nvs_st)
+ st->nvs->remove(st->nvs_st);
if (st->dw.wq)
destroy_workqueue(st->dw.wq);
jsa_pm_exit(st);
static struct sensor_cfg jsa_cfg_dflt = {
.name = NVS_LIGHT_STRING,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = JSA_NAME,
.vendor = JSA_VENDOR,
.version = JSA_LIGHT_VERSION,
.fval = JSA_LIGHT_MILLIAMP_FVAL,
},
.delay_us_max = JSA_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = JSA_LIGHT_SCALE_IVAL,
.fval = JSA_LIGHT_SCALE_MICRO,
st->light.nld_tbl = jsa_nld_tbl;
/* device tree parameters */
/* common NVS parameters */
- nvs_of_dt(dn, &st->cfg, NULL);
+ ret = nvs_of_dt(dn, &st->cfg, NULL);
+ if (ret == -ENODEV)
+ return -ENODEV;
+
/* this device supports these programmable parameters */
ret = nvs_light_of_dt(&st->light, dn, NULL);
if (ret) {
st->i2c = client;
ret = jsa_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto jsa_probe_exit;
}
goto jsa_probe_exit;
}
- ret = st->nvs->probe(&st->nvs_data, st, &client->dev,
+ st->light.handler = st->nvs->handler;
+ ret = st->nvs->probe(&st->nvs_st, st, &client->dev,
&jsa_fn_dev, &st->cfg);
if (ret) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto jsa_probe_exit;
}
- st->light.nvs_data = st->nvs_data;
- st->light.handler = st->nvs->handler;
+ st->light.nvs_st = st->nvs_st;
INIT_DELAYED_WORK(&st->dw, jsa_work);
dev_info(&client->dev, "%s done\n", __func__);
return 0;
-/* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+/* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
struct ltr_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data[LTR_DEV_N];
+ void *nvs_st[LTR_DEV_N];
struct sensor_cfg cfg[LTR_DEV_N];
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(ltr_vregs)];
struct nvs_light light;
struct nvs_proximity prox;
- unsigned int dev[LTR_DEV_N];
- unsigned int snsr_n; /* number of sensors */
unsigned int sts; /* status flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
- bool iio_ts_en; /* use IIO timestamps */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
u8 ps_contr; /* PS_CONTR register default */
u8 rc_interrupt; /* cache of INTERRUPT */
};
-static s64 ltr_get_time_ns(struct ltr_state *st)
+static s64 ltr_get_time_ns(void)
{
struct timespec ts;
- if (st->iio_ts_en)
- return iio_get_time_ns();
-
ktime_get_ts(&ts);
return timespec_to_ns(&ts);
}
st->errs--;
}
+static void ltr_mutex_lock(struct ltr_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_lock(st->nvs_st[i]);
+ }
+ }
+}
+
+static void ltr_mutex_unlock(struct ltr_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_unlock(st->nvs_st[i]);
+ }
+ }
+}
+
static int ltr_i2c_read(struct ltr_state *st, u8 reg, u16 len, u8 *val)
{
struct i2c_msg msg[2];
return ret;
if (sts & LTR_REG_STATUS_DATA_MASK) {
- ts = ltr_get_time_ns(st);
+ ts = ltr_get_time_ns();
if (st->enabled & (1 << LTR_DEV_PROX))
ret |= ltr_rd_prox(st, ts);
if (st->enabled & (1 << LTR_DEV_LIGHT))
static void ltr_read(struct ltr_state *st)
{
- unsigned int i;
int ret;
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_lock(st->nvs_data[i]);
+ ltr_mutex_lock(st);
if (st->enabled) {
ret = ltr_rd(st);
if (ret < 1)
schedule_delayed_work(&st->dw,
msecs_to_jiffies(ltr_polldelay(st)));
}
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_unlock(st->nvs_data[i]);
+ ltr_mutex_unlock(st);
}
static void ltr_work(struct work_struct *ws)
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->suspend(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->suspend(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
unsigned int i;
int ret = 0;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->resume(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->resume(st->nvs_st[i]);
+ }
}
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
unsigned int i;
st->sts |= NVS_STS_SHUTDOWN;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- st->nvs->shutdown(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->shutdown(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
if (st != NULL) {
ltr_shutdown(client);
if (st->nvs) {
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs_data[i])
- st->nvs->remove(st->nvs_data[i]);
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->remove(st->nvs_st[i]);
}
}
if (st->dw.wq)
{
.name = NVS_LIGHT_STRING,
.snsr_id = LTR_DEV_LIGHT,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = LTR_NAME,
.vendor = LTR_VENDOR,
.version = LTR_LIGHT_VERSION,
},
.delay_us_min = LTR_POLL_DLY_MS_MIN * 1000,
.delay_us_max = LTR_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = LTR_LIGHT_SCALE_IVAL,
.fval = LTR_LIGHT_SCALE_MICRO,
{
.name = NVS_PROXIMITY_STRING,
.snsr_id = LTR_DEV_PROX,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_proximity),
- .ch_inf = &iio_chan_spec_nvs_proximity,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = LTR_NAME,
.vendor = LTR_VENDOR,
.version = LTR_PROX_VERSION,
},
.delay_us_min = LTR_POLL_DLY_MS_MIN * 1000,
.delay_us_max = LTR_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE |
+ SENSOR_FLAG_WAKE_UP,
.scale = {
.ival = LTR_PROX_SCALE_IVAL,
.fval = LTR_PROX_SCALE_MICRO,
static int ltr_of_dt(struct ltr_state *st, struct device_node *dn)
{
unsigned int i;
+ int ret;
for (i = 0; i < LTR_DEV_N; i++)
- memcpy(&st->cfg[i], <r_cfg_dflt[i],
- sizeof(struct sensor_cfg));
+ memcpy(&st->cfg[i], <r_cfg_dflt[i], sizeof(st->cfg[0]));
+ st->light.cfg = &st->cfg[LTR_DEV_LIGHT];
+ st->light.hw_mask = 0xFFFF;
+ st->light.nld_tbl = ltr_nld_tbl;
+ st->prox.cfg = &st->cfg[LTR_DEV_PROX];
+ st->prox.hw_mask = 0xFFFF;
/* default device specific parameters */
st->ps_contr = LTR_REG_PS_CONTR_DFLT;
st->ps_led = LTR_REG_PS_LED_DFLT;
st->interrupt_persist = LTR_REG_INTERRUPT_PERSIST_DFLT;
/* device tree parameters */
if (dn) {
- /* common NVS programmable parameters */
- st->iio_ts_en = of_property_read_bool(dn, "iio_timestamps");
+ /* common NVS parameters */
+ for (i = 0; i < LTR_DEV_N; i++) {
+ ret = nvs_of_dt(dn, &st->cfg[i], NULL);
+ if (ret == -ENODEV)
+ /* the entire device has been disabled */
+ return -ENODEV;
+ }
+
/* device specific parameters */
of_property_read_u8(dn, "register_ps_contr", &st->ps_contr);
st->ps_contr &= LTR_REG_PS_CONTR_POR_MASK;
of_property_read_u8(dn, "register_interrupt_persist",
&st->interrupt_persist);
}
- /* common NVS parameters */
- for (i = 0; i < LTR_DEV_N; i++)
- nvs_of_dt(dn, &st->cfg[i], NULL);
/* this device supports these programmable parameters */
if (nvs_light_of_dt(&st->light, dn, NULL)) {
st->light.nld_i_lo = 0;
st->i2c = client;
ret = ltr_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto ltr_probe_exit;
}
goto ltr_probe_exit;
}
+ st->light.handler = st->nvs->handler;
+ st->prox.handler = st->nvs->handler;
n = 0;
for (i = 0; i < LTR_DEV_N; i++) {
- if (st->dev_id == LTR_DEVID_659PS) {
- if (st->cfg[i].snsr_id == LTR_DEV_LIGHT)
- continue;
- }
-
- ret = st->nvs->probe(&st->nvs_data[n], st, &client->dev,
+ ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev,
<r_fn_dev, &st->cfg[i]);
- if (!ret) {
- st->dev[n] = st->cfg[i].snsr_id;
- if (st->dev[n] == LTR_DEV_LIGHT) {
- st->light.cfg = &st->cfg[i];
- st->light.nvs_data = st->nvs_data[n];
- st->light.handler = st->nvs->handler;
- st->light.hw_mask = 0xFFFF;
- st->light.nld_tbl = ltr_nld_tbl;
- } else if (st->dev[n] == LTR_DEV_PROX) {
- st->prox.cfg = &st->cfg[i];
- st->prox.nvs_data = st->nvs_data[n];
- st->prox.handler = st->nvs->handler;
- st->prox.hw_mask = 0xFFFF;
- }
+ if (!ret)
n++;
- }
}
if (!n) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto ltr_probe_exit;
}
- st->snsr_n = n;
+ st->light.nvs_st = st->nvs_st[LTR_DEV_LIGHT];
+ st->prox.nvs_st = st->nvs_st[LTR_DEV_PROX];
INIT_DELAYED_WORK(&st->dw, ltr_work);
if (client->irq) {
- /* IRQF_NO_SUSPEND for proximity */
- irqflags = IRQF_NO_SUSPEND | IRQF_ONESHOT;
+ irqflags = IRQF_ONESHOT;
if (st->interrupt & LTR_REG_INTERRUPT_POLARITY)
irqflags |= IRQF_TRIGGER_RISING;
else
irqflags |= IRQF_TRIGGER_FALLING;
+ for (i = 0; i < LTR_DEV_N; i++) {
+ if (st->cfg[i].snsr_id >= 0) {
+ if (st->cfg[i].flags & SENSOR_FLAG_WAKE_UP)
+ irqflags |= IRQF_NO_SUSPEND;
+ }
+ }
ret = request_threaded_irq(client->irq, NULL, ltr_irq_thread,
irqflags, LTR_NAME, st);
if (ret) {
-/* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+/* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
struct mx_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
- void *nvs_data[MX_DEV_N];
+ void *nvs_st[MX_DEV_N];
struct sensor_cfg cfg[MX_DEV_N];
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(mx_vregs)];
struct nvs_light light;
struct nvs_proximity prox;
- unsigned int dev[MX_DEV_N];
- unsigned int snsr_n; /* number of sensors */
unsigned int sts; /* status flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
- bool iio_ts_en; /* use IIO timestamps */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
u8 amb_cfg; /* ambient configuration register */
};
-static s64 mx_get_time_ns(struct mx_state *st)
+static s64 mx_get_time_ns(void)
{
struct timespec ts;
- if (st->iio_ts_en)
- return iio_get_time_ns();
-
ktime_get_ts(&ts);
return timespec_to_ns(&ts);
}
st->errs--;
}
+static void mx_mutex_lock(struct mx_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_lock(st->nvs_st[i]);
+ }
+ }
+}
+
+static void mx_mutex_unlock(struct mx_state *st)
+{
+ unsigned int i;
+
+ if (st->nvs) {
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->nvs_mutex_unlock(st->nvs_st[i]);
+ }
+ }
+}
+
static int mx_i2c_read(struct mx_state *st, u8 reg, u16 len, u8 *val)
{
struct i2c_msg msg[2];
return RET_POLL_NEXT;
}
- ts = mx_get_time_ns(st);
+ ts = mx_get_time_ns();
if (st->enabled & (1 << MX_DEV_PROX))
ret |= mx_rd_prox(st, ts);
if (st->enabled & (1 << MX_DEV_LIGHT))
static void mx_read(struct mx_state *st)
{
- unsigned int i;
int ret;
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_lock(st->nvs_data[i]);
+ mx_mutex_lock(st);
if (st->enabled) {
ret = mx_rd(st);
if (ret < 1)
schedule_delayed_work(&st->dw,
msecs_to_jiffies(mx_polldelay(st)));
}
- for (i = 0; i < st->snsr_n; i++)
- st->nvs->nvs_mutex_unlock(st->nvs_data[i]);
+ mx_mutex_unlock(st);
}
static void mx_work(struct work_struct *ws)
int ret = 0;
st->sts |= NVS_STS_SUSPEND;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->suspend(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->suspend(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
unsigned int i;
int ret = 0;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- ret |= st->nvs->resume(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ ret |= st->nvs->resume(st->nvs_st[i]);
+ }
}
st->sts &= ~NVS_STS_SUSPEND;
if (st->sts & NVS_STS_SPEW_MSG)
unsigned int i;
st->sts |= NVS_STS_SHUTDOWN;
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs && st->nvs_data[i])
- st->nvs->shutdown(st->nvs_data[i]);
+ if (st->nvs) {
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->shutdown(st->nvs_st[i]);
+ }
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
if (st != NULL) {
mx_shutdown(client);
if (st->nvs) {
- for (i = 0; i < st->snsr_n; i++) {
- if (st->nvs_data[i])
- st->nvs->remove(st->nvs_data[i]);
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->nvs_st[i])
+ st->nvs->remove(st->nvs_st[i]);
}
}
if (st->dw.wq)
{
.name = NVS_LIGHT_STRING,
.snsr_id = MX_DEV_LIGHT,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_light),
- .ch_inf = &iio_chan_spec_nvs_light,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = MX_NAME,
.vendor = MX_VENDOR,
.version = MX_LIGHT_VERSION,
},
.delay_us_min = MX_POLL_DLY_MS_MIN * 1000,
.delay_us_max = MX_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE,
.scale = {
.ival = MX_LIGHT_SCALE_IVAL,
.fval = MX_LIGHT_SCALE_MICRO,
},
{
.name = NVS_PROXIMITY_STRING,
- .snsr_id = MX_DEV_PROX,
- .ch_n = ARRAY_SIZE(iio_chan_spec_nvs_proximity),
- .ch_inf = &iio_chan_spec_nvs_proximity,
+ .ch_n = 1,
+ .ch_sz = 4,
.part = MX_NAME,
.vendor = MX_VENDOR,
.version = MX_PROX_VERSION,
},
.delay_us_min = MX_POLL_DLY_MS_MIN * 1000,
.delay_us_max = MX_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE |
+ SENSOR_FLAG_WAKE_UP,
.scale = {
.ival = MX_PROX_SCALE_IVAL,
.fval = MX_PROX_SCALE_MICRO,
static int mx_of_dt(struct mx_state *st, struct device_node *dn)
{
unsigned int i;
+ int ret;
for (i = 0; i < MX_DEV_N; i++)
- memcpy(&st->cfg[i], &mx_cfg_dflt[i],
- sizeof(struct sensor_cfg));
+ memcpy(&st->cfg[i], &mx_cfg_dflt[i], sizeof(st->cfg[0]));
+ st->light.cfg = &st->cfg[MX_DEV_LIGHT];
+ st->prox.cfg = &st->cfg[MX_DEV_PROX];
/* default device specific parameters */
st->amb_cfg = MX_AMB_CFG_DFLT;
st->prx_cfg = MX_PRX_CFG_DFLT;
/* device tree parameters */
if (dn) {
- /* common NVS programmable parameters */
- st->iio_ts_en = of_property_read_bool(dn, "iio_timestamps");
+ /* common NVS parameters */
+ for (i = 0; i < MX_DEV_N; i++) {
+ ret = nvs_of_dt(dn, &st->cfg[i], NULL);
+ if (ret == -ENODEV)
+ /* the entire device has been disabled */
+ return -ENODEV;
+ }
+
/* device specific parameters */
of_property_read_u8(dn, "ambient_cfg_reg", &st->amb_cfg);
of_property_read_u8(dn, "proximity_cfg_reg", &st->prx_cfg);
of_property_read_u8(dn, "threshold_persist_reg", &st->thr_cfg);
}
- /* common NVS parameters */
- for (i = 0; i < MX_DEV_N; i++)
- nvs_of_dt(dn, &st->cfg[i], NULL);
/* this device supports these programmable parameters */
if (nvs_light_of_dt(&st->light, dn, NULL)) {
st->light.nld_i_lo = 0;
st->i2c = client;
ret = mx_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
- ret = -ENODEV;
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto mx_probe_exit;
}
goto mx_probe_exit;
}
+ st->light.handler = st->nvs->handler;
+ st->prox.handler = st->nvs->handler;
n = 0;
for (i = 0; i < MX_DEV_N; i++) {
if (st->dev_id != MX_DEVID_MAX44005) {
- if (st->cfg[i].snsr_id == MX_DEV_PROX)
+ if (st->cfg[i].snsr_id == MX_DEV_PROX) {
+ st->cfg[i].snsr_id = -1;
continue;
+ }
}
- ret = st->nvs->probe(&st->nvs_data[n], st, &client->dev,
+ ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev,
&mx_fn_dev, &st->cfg[i]);
- if (!ret) {
- st->dev[n] = st->cfg[i].snsr_id;
- if (st->dev[n] == MX_DEV_LIGHT) {
- st->light.cfg = &st->cfg[i];
- st->light.nvs_data = st->nvs_data[n];
- st->light.handler = st->nvs->handler;
- } else if (st->dev[n] == MX_DEV_PROX) {
- st->prox.cfg = &st->cfg[i];
- st->prox.nvs_data = st->nvs_data[n];
- st->prox.handler = st->nvs->handler;
- }
+ if (!ret)
n++;
- }
}
if (!n) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
goto mx_probe_exit;
}
- st->snsr_n = n;
+ st->light.nvs_st = st->nvs_st[MX_DEV_LIGHT];
+ st->prox.nvs_st = st->nvs_st[MX_DEV_PROX];
INIT_DELAYED_WORK(&st->dw, mx_work);
if (client->irq) {
irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
- if (st->dev_id == MX_DEVID_MAX44005)
- irqflags |= IRQF_NO_SUSPEND; /* for proximity */
+ for (i = 0; i < MX_DEV_N; i++) {
+ if (st->cfg[i].snsr_id >= 0) {
+ if (st->cfg[i].flags & SENSOR_FLAG_WAKE_UP)
+ irqflags |= IRQF_NO_SUSPEND;
+ }
+ }
ret = request_threaded_irq(client->irq, NULL, mx_irq_thread,
irqflags, MX_NAME, st);
if (ret) {
{
char const *pchar;
u8 cfg;
+ int ret;
+
+ ret = nvs_of_dt(dn, &st->cfg, NULL);
+ if (ret == -ENODEV)
+ return -ENODEV;
/* this device supports these programmable parameters */
if (!(of_property_read_string(dn, "nvi_config", &pchar))) {
st->cfg.matrix[8] = 1;
if (client->dev.of_node) {
ret = akm_of_dt(st, client->dev.of_node);
- if (ret)
+ if (ret) {
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n",
+ __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n",
+ __func__);
+ ret = -ENODEV;
+ }
goto akm_probe_err;
+ }
#if AKM_NVI_MPU_SUPPORT
} else {
pd = (struct mpu_platform_data *)
akm_init_hw(st);
akm_pm(st, false);
- ret = nvs_of_dt(client->dev.of_node, &st->cfg, NULL);
- if (ret)
- dev_info(&client->dev, "%s nvs_of_dt ERR\n", __func__);
akm_fn_dev.errs = &st->errs;
akm_fn_dev.sts = &st->sts;
st->nvs = nvs_iio();
{
char const *pchar;
u8 cfg;
+ unsigned int i;
+ int ret;
- /* this device supports these programmable parameters */
- if (!(of_property_read_string(dn, "nvi_config", &pchar))) {
- for (cfg = 0; cfg < ARRAY_SIZE(bmp_configs); cfg++) {
- if (!strcasecmp(pchar, bmp_configs[cfg])) {
- st->nvi_config = cfg;
- break;
+ if (dn) {
+ for (i = 0; i < BMP_DEV_N; i++) {
+ ret = nvs_of_dt(dn, &st->cfg[i], NULL);
+ if (ret == -ENODEV)
+ return -ENODEV;
+ }
+
+ /* this device supports these programmable parameters */
+ if (!(of_property_read_string(dn, "nvi_config", &pchar))) {
+ for (cfg = 0; cfg < ARRAY_SIZE(bmp_configs); cfg++) {
+ if (!strcasecmp(pchar, bmp_configs[cfg])) {
+ st->nvi_config = cfg;
+ break;
+ }
}
}
}
i2c_set_clientdata(client, st);
st->i2c = client;
- if (client->dev.of_node) {
- ret = bmp_of_dt(st, client->dev.of_node);
- if (ret)
- goto bmp_probe_err;
+ ret = bmp_of_dt(st, client->dev.of_node);
+ if (ret) {
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
+ goto bmp_probe_err;
}
bmp_pm_init(st);
menu "Proximity sensors"
config NVS_IQS2X3
- tristate "Maxim MAX4400X ALS/Proximity"
+ tristate "Azoteq IQS253/IQS263 SAR proximity"
select NVS_IIO
select NVS_PROXIMITY
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
depends on I2C
help
- Say Y here for Azoteq IQS253 and IQS263 proximity support.
+ Say Y here for Azoteq IQS253 and IQS263 SAR proximity support.
The driver uses the NVS (NVidia Sensor) IIO and proximity
framework.
#include <linux/nvs_proximity.h>
-#define IQS_DRIVER_VERSION (4)
+#define IQS_DRIVER_VERSION (6)
#define IQS_VENDOR "Azoteq"
#define IQS_NAME "iqs2x3"
#define IQS_NAME_IQS253 "iqs253"
};
#define IQS_DT_INIT_N (128) /* max DT init bytes */
-#define IQS_DT_EN_N (64) /* max DT enable bytes */
+#define IQS_DT_ABLE_N (64) /* max DT en/dis-able bytes */
+#define IQS_DT_EVNT_N (32) /* max DT en/dis-able bytes */
#define IQS263_MSG_N (14)
#define IQS253_MSG_N (9)
unsigned char *wr_reseed;
unsigned char dt_init263[IQS_DT_INIT_N];
unsigned char dt_init253[IQS_DT_INIT_N];
- unsigned char dt_en_prx263[IQS_DT_EN_N];
- unsigned char dt_en_tch263[IQS_DT_EN_N];
- unsigned char dt_en_prx253[IQS_DT_EN_N];
- unsigned char dt_en_tch253[IQS_DT_EN_N];
+ unsigned char dt_en_prx263[IQS_DT_ABLE_N];
+ unsigned char dt_en_tch263[IQS_DT_ABLE_N];
+ unsigned char dt_en_prx253[IQS_DT_ABLE_N];
+ unsigned char dt_en_tch253[IQS_DT_ABLE_N];
+ unsigned char dt_dis_prx263[IQS_DT_ABLE_N];
+ unsigned char dt_dis_tch263[IQS_DT_ABLE_N];
+ unsigned char dt_dis_prx253[IQS_DT_ABLE_N];
+ unsigned char dt_dis_tch253[IQS_DT_ABLE_N];
+ unsigned char dt_evnt263[IQS_DT_EVNT_N];
+ unsigned char dt_evnt253[IQS_DT_EVNT_N];
u8 rc[IQS_BI_N]; /* register cache */
};
int ret;
ret = iqs_wr(st, wr);
- if (!ret)
+ if (st->msg_n && !ret)
ret = iqs_i2c(st);
return ret;
}
st->op_i = st->op_read_n; /* force new read cycle */
}
+static int iqs_init(struct iqs_state *st)
+{
+ unsigned char *wr = st->dt_init263;
+ int ret = 0;
+
+ if (st->dev_id == IQS_DEVID_IQS253)
+ wr = st->dt_init253;
+ if (st->hal_tbl_n)
+ /* only if HAL initialized */
+ ret = iqs_write(st, wr);
+ return ret;
+}
+
static int iqs_en(struct iqs_state *st, int snsr_id)
{
unsigned char *wr;
return -EINVAL;
}
+ /* if sensor enabled */
ret = iqs_write(st, wr);
if (!ret)
ret = nvs_proximity_enable(&st->prox[snsr_id]);
return ret;
}
-static int iqs_init(struct iqs_state *st)
+static int iqs_dis(struct iqs_state *st, int snsr_id)
{
- unsigned char *wr = st->dt_init263;
+ unsigned char *wr;
int ret = 0;
- if (st->dev_id == IQS_DEVID_IQS253)
- wr = st->dt_init253;
- if (st->hal_tbl_n)
- /* only if HAL initialized */
- ret = iqs_write(st, wr);
- return ret;
-}
-
-static int iqs_dis(struct iqs_state *st)
-{
- int ret = 0;
+ if (snsr_id == IQS_DEV_PROX) {
+ if (st->dev_id == IQS_DEVID_IQS253)
+ wr = st->dt_dis_prx253;
+ else
+ wr = st->dt_dis_prx263;
+ } else if (snsr_id == IQS_DEV_TOUCH) {
+ if (st->dev_id == IQS_DEVID_IQS253)
+ wr = st->dt_dis_tch253;
+ else
+ wr = st->dt_dis_tch263;
+ } else if (snsr_id < 0) {
+ wr = st->wr_disable;
+ } else {
+ return -EINVAL;
+ }
if (st->hal_tbl_n)
/* only if HAL initialized */
- ret = iqs_write(st, st->wr_disable);
+ ret = iqs_write(st, wr);
return ret;
}
} else {
ret = nvs_vregs_sts(st->vreg, ARRAY_SIZE(iqs_vregs));
if ((ret < 0) || (ret == ARRAY_SIZE(iqs_vregs))) {
- ret = iqs_dis(st);
+ ret = iqs_dis(st, -1);
} else if (ret > 0) {
nvs_vregs_enable(&st->i2c->dev, st->vreg,
ARRAY_SIZE(iqs_vregs));
mdelay(IQS_HW_DELAY_MS);
ret = iqs_init(st);
- ret |= iqs_dis(st);
+ ret |= iqs_dis(st, -1);
}
ret |= nvs_vregs_disable(&st->i2c->dev, st->vreg,
ARRAY_SIZE(iqs_vregs));
if (!st->stream)
/* enter stream mode on first I2C transaction */
iqs_wr(st, st->wr_stream);
+ if (st->dev_id == IQS_DEVID_IQS253)
+ iqs_wr(st, st->dt_evnt253);
+ else
+ iqs_wr(st, st->dt_evnt263);
}
if ((st->op_i == st->op_read_n - 1) && !st->stream)
iqs_wr(st, st->wr_events); /* event mode at end of reads */
static int iqs_disable(struct iqs_state *st, int snsr_id)
{
bool disable = true;
+ unsigned int i;
int ret = 0;
if (snsr_id >= 0) {
- if (st->enabled & ~(1 << snsr_id)) {
+ ret = iqs_dis(st, snsr_id);
+ if (!ret)
st->enabled &= ~(1 << snsr_id);
+ if (st->enabled)
disable = false;
+ } else {
+ for (i = 0; i < IQS_DEV_N; i++) {
+ if (st->enabled & (1 << i))
+ iqs_dis(st, snsr_id);
}
}
if (disable) {
case 0x12:
val = !!val;
- if (st->gpio_sar >= 0)
+ if (st->gpio_sar >= 0) {
ret = gpio_direction_output(st->gpio_sar, val);
+ if (!ret)
+ st->gpio_sar_val = val;
+ }
dev_info(&st->i2c->dev,
"%s gpio_direction_output(gpio_sar(%d), %hhx)=%d\n",
__func__, st->gpio_sar, val, ret);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_en_prx263);
t += sprintf(buf + t, "IQS263 touch enable:\n");
t += iqs_nvs_dbg_db(st, buf, t, st->dt_en_tch263);
+ t += sprintf(buf + t, "IQS263 proximity disable:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_dis_prx263);
+ t += sprintf(buf + t, "IQS263 touch disable:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_dis_tch263);
+ t += sprintf(buf + t, "IQS263 event:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_evnt263);
t += sprintf(buf + t, "IQS253 initialization:\n");
t += iqs_nvs_dbg_db(st, buf, t, st->dt_init253);
t += sprintf(buf + t, "IQS253 proximity enable:\n");
t += iqs_nvs_dbg_db(st, buf, t, st->dt_en_prx253);
t += sprintf(buf + t, "IQS253 touch enable:\n");
t += iqs_nvs_dbg_db(st, buf, t, st->dt_en_tch253);
+ t += sprintf(buf + t, "IQS253 proximity disable:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_dis_prx253);
+ t += sprintf(buf + t, "IQS253 touch disable:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_dis_tch253);
+ t += sprintf(buf + t, "IQS253 event:\n");
+ t += iqs_nvs_dbg_db(st, buf, t, st->dt_evnt253);
return t;
}
static const struct sensor_cfg iqs_cfg_dflt = {
.snsr_id = SENSOR_TYPE_PROXIMITY,
- .no_suspend = true,
.ch_n = 1,
.ch_sz = 4,
.part = IQS_NAME,
},
.delay_us_min = IQS_POLL_DLY_MS_MIN * 1000,
.delay_us_max = IQS_POLL_DLY_MS_MAX * 1000,
+ .flags = SENSOR_FLAG_ON_CHANGE_MODE |
+ SENSOR_FLAG_WAKE_UP,
.thresh_lo = IQS_PROX_THRESHOLD,
.thresh_hi = IQS_MULTI_THRESHOLD,
};
sizeof(st->dt_en_prx263));
ret |= iqs_of_dt_db(st, dn, "263en_touch", st->dt_en_tch263,
sizeof(st->dt_en_tch263));
+ ret |= iqs_of_dt_db(st, dn, "263dis_prox", st->dt_dis_prx263,
+ sizeof(st->dt_dis_prx263));
+ ret |= iqs_of_dt_db(st, dn, "263dis_touch", st->dt_dis_tch263,
+ sizeof(st->dt_dis_tch263));
+ ret |= iqs_of_dt_db(st, dn, "263event", st->dt_evnt263,
+ sizeof(st->dt_evnt263));
ret |= iqs_of_dt_db(st, dn, "253init", st->dt_init253,
sizeof(st->dt_en_tch253));
ret |= iqs_of_dt_db(st, dn, "253en_prox", st->dt_en_prx253,
sizeof(st->dt_en_tch253));
ret |= iqs_of_dt_db(st, dn, "253en_touch", st->dt_en_tch253,
sizeof(st->dt_en_tch253));
+ ret |= iqs_of_dt_db(st, dn, "253dis_prox", st->dt_dis_prx253,
+ sizeof(st->dt_dis_tch253));
+ ret |= iqs_of_dt_db(st, dn, "253dis_touch", st->dt_dis_tch253,
+ sizeof(st->dt_dis_tch253));
+ ret |= iqs_of_dt_db(st, dn, "253event", st->dt_evnt253,
+ sizeof(st->dt_evnt253));
if (ret)
return ret;
}
st->i2c = client;
ret = iqs_of_dt(st, client->dev.of_node);
if (ret) {
- dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ if (ret == -ENODEV) {
+ dev_info(&client->dev, "%s DT disabled\n", __func__);
+ } else {
+ dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
+ ret = -ENODEV;
+ }
goto iqs_probe_exit;
}
&iqs_fn_dev, &st->cfg[i]);
st->cfg[i].snsr_id = i;
if (!ret) {
- st->prox[i].nvs_data = st->nvs_st[i];
+ st->prox[i].nvs_st = st->nvs_st[i];
st->prox[i].handler = st->nvs->handler;
n++;
}
if (client->irq) {
irqflags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
for (i = 0; i < IQS_DEV_N; i++) {
- if (st->cfg[i].no_suspend)
- irqflags |= IRQF_NO_SUSPEND;
+ if (st->cfg[i].snsr_id >= 0) {
+ if (st->cfg[i].flags & SENSOR_FLAG_WAKE_UP)
+ irqflags |= IRQF_NO_SUSPEND;
+ }
}
ret = request_threaded_irq(client->irq, NULL, iqs_irq_thread,
irqflags, IQS_NAME, st);
if (st->os) {
iqs_disable(st, -1);
} else {
- ret = iqs_enable(st, IQS_DEV_PROX, 1);
- ret |= iqs_enable(st, IQS_DEV_TOUCH, 1);
+ ret = 0;
+ if (st->nvs_st[IQS_DEV_PROX])
+ ret |= iqs_enable(st, IQS_DEV_PROX, 1);
+ if (st->nvs_st[IQS_DEV_TOUCH])
+ ret |= iqs_enable(st, IQS_DEV_TOUCH, 1);
if (ret) {
iqs_err(st);
/* if an error then switch to OS controlled */
#define NVS_FLOAT_SIGNIFICANCE_MICRO (1000000) /* IIO_VAL_INT_PLUS_MICRO */
#define NVS_FLOAT_SIGNIFICANCE_NANO (1000000000) /* IIO_VAL_INT_PLUS_NANO */
+/* from AOS sensors.h */
#define SENSOR_TYPE_ACCELEROMETER (1)
#define SENSOR_TYPE_MAGNETIC_FIELD (2)
#define SENSOR_TYPE_ORIENTATION (3)
#define SENSOR_TYPE_WAKE_GESTURE (23)
#define SENSOR_TYPE_GLANCE_GESTURE (24)
#define SENSOR_TYPE_PICK_UP_GESTURE (25)
+/* from AOS sensors.h */
+#define SENSOR_FLAG_WAKE_UP (0x1)
+#define SENSOR_FLAG_ON_CHANGE_MODE (0x2)
+#define SENSOR_FLAG_ONE_SHOT_MODE (0x4)
+#define SENSOR_FLAG_SPECIAL_REPORTING_MODE (0x6)
+/* end AOS sensors.h */
+#define SENSOR_FLAG_NO_CFG_MASK (0x6) /* unconfigurable flags */
enum nvs_float_significance {
NVS_FLOAT_MICRO = 0, /* IIO_VAL_INT_PLUS_MICRO */
struct sensor_cfg {
const char *name; /* sensor name */
int snsr_id; /* sensor ID */
- bool no_suspend; /* true if active during suspend */
int kbuf_sz; /* kernel buffer size (n bytes) */
int timestamp_sz; /* hub: timestamp size (n bytes) */
int snsr_data_n; /* hub: number of data bytes */
#ifndef _NVS_LIGHT_H_
#define _NVS_LIGHT_H_
-#include <linux/iio/iio.h>
#include <linux/of.h>
#include <linux/nvs.h>
#define RET_HW_UPDATE (1)
#define NVS_LIGHT_STRING "light"
-#define SENSOR_FLAG_ON_CHANGE_MODE 0x2 /* from AOS sensors.h */
/**
* struct nvs_light_dynamic - the structure that allows the NVS
unsigned int nld_i_hi; /* high index limit to dynamic table */
struct nvs_light_dynamic *nld_tbl; /* ptr to nvs_light_dynamic table */
struct sensor_cfg *cfg; /* pointer to sensor configuration */
- void *nvs_data; /* NVS data for NVS handler */
+ void *nvs_st; /* NVS state data for NVS handler */
int (*handler)(void *handle, void *buffer, s64 ts);
};
-static const struct iio_chan_spec iio_chan_spec_nvs_light[] = {
- {
- .type = IIO_LIGHT,
- .scan_type = IIO_ST('u', 32, 32, 0),
- .info_mask = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_BATCH_FLUSH) |
- BIT(IIO_CHAN_INFO_BATCH_PERIOD) |
- BIT(IIO_CHAN_INFO_BATCH_TIMEOUT) |
- BIT(IIO_CHAN_INFO_BATCH_FLAGS) |
- BIT(IIO_CHAN_INFO_PEAK) |
- BIT(IIO_CHAN_INFO_PEAK_SCALE) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_OFFSET) |
- BIT(IIO_CHAN_INFO_THRESHOLD_LOW) |
- BIT(IIO_CHAN_INFO_THRESHOLD_HIGH),
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_BATCH_FLUSH) |
- BIT(IIO_CHAN_INFO_BATCH_PERIOD) |
- BIT(IIO_CHAN_INFO_BATCH_TIMEOUT) |
- BIT(IIO_CHAN_INFO_BATCH_FLAGS) |
- BIT(IIO_CHAN_INFO_PEAK) |
- BIT(IIO_CHAN_INFO_PEAK_SCALE) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_OFFSET) |
- BIT(IIO_CHAN_INFO_THRESHOLD_LOW) |
- BIT(IIO_CHAN_INFO_THRESHOLD_HIGH),
- },
- IIO_CHAN_SOFT_TIMESTAMP(1)
-};
-
int nvs_light_read(struct nvs_light *nl);
int nvs_light_enable(struct nvs_light *nl);
int nvs_light_of_dt(struct nvs_light *nl, const struct device_node *np,
#ifndef _NVS_PROXIMITY_H_
#define _NVS_PROXIMITY_H_
-#include <linux/iio/iio.h>
#include <linux/of.h>
#include <linux/nvs.h>
#define RET_HW_UPDATE (1)
#define NVS_PROXIMITY_STRING "proximity"
-#define SENSOR_FLAG_ON_CHANGE_MODE 0x2 /* from AOS sensors.h */
/**
* struct nvs_proximity - the common structure between the
unsigned int delay_us; /* OS requested sample delay */
unsigned int report; /* report count */
struct sensor_cfg *cfg; /* pointer to sensor configuration */
- void *nvs_data; /* NVS data for NVS handler */
+ void *nvs_st; /* NVS state data for NVS handler */
int (*handler)(void *handle, void *buffer, s64 ts);
};
-static const struct iio_chan_spec iio_chan_spec_nvs_proximity[] = {
- {
- .type = IIO_PROXIMITY,
- .scan_type = IIO_ST('u', 32, 32, 0),
- .info_mask = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_BATCH_FLUSH) |
- BIT(IIO_CHAN_INFO_BATCH_PERIOD) |
- BIT(IIO_CHAN_INFO_BATCH_TIMEOUT) |
- BIT(IIO_CHAN_INFO_BATCH_FLAGS) |
- BIT(IIO_CHAN_INFO_PEAK) |
- BIT(IIO_CHAN_INFO_PEAK_SCALE) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_OFFSET) |
- BIT(IIO_CHAN_INFO_THRESHOLD_LOW) |
- BIT(IIO_CHAN_INFO_THRESHOLD_HIGH),
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- BIT(IIO_CHAN_INFO_BATCH_FLUSH) |
- BIT(IIO_CHAN_INFO_BATCH_PERIOD) |
- BIT(IIO_CHAN_INFO_BATCH_TIMEOUT) |
- BIT(IIO_CHAN_INFO_BATCH_FLAGS) |
- BIT(IIO_CHAN_INFO_PEAK) |
- BIT(IIO_CHAN_INFO_PEAK_SCALE) |
- BIT(IIO_CHAN_INFO_SCALE) |
- BIT(IIO_CHAN_INFO_OFFSET) |
- BIT(IIO_CHAN_INFO_THRESHOLD_LOW) |
- BIT(IIO_CHAN_INFO_THRESHOLD_HIGH),
- },
- IIO_CHAN_SOFT_TIMESTAMP(1)
-};
-
int nvs_proximity_enable(struct nvs_proximity *np);
int nvs_proximity_read(struct nvs_proximity *np);
int nvs_proximity_of_dt(struct nvs_proximity *np, const struct device_node *dn,