summaryrefslogtreecommitdiff
path: root/drivers/iio/accel/fxls8962af-core.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-19 12:44:28 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-10-19 12:44:28 +0300
commit6bce28cb49320f403ab075ecdc2feb6cee24c416 (patch)
treebf4e29c34eac9e865d891086ef739e184188cd8c /drivers/iio/accel/fxls8962af-core.c
parentf5245a5fdf757f50a6c905fc16cceb1a6146ccf5 (diff)
parent0336d605daeea142c3ec9b143d0131a137f45108 (diff)
downloadlinux-6bce28cb49320f403ab075ecdc2feb6cee24c416.tar.xz
Merge tag 'iio-for-5.16a-split-take4' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: First set of IIO new device and feature support for the 5.16 cycle Counter subsystem changes now sent separately. This has been a busy cycle, so lots here and a few more stragglers to come next week. Big new feature in this cycle is probably output buffer support. This has been in the works for a very long time so it's great to see Mihail pick up the challenge and build upon his predecessors work to finally bring this feature to mainline. New device support ------------------ * adi,adxl313 - New driver and dt bindings for this low power accelerometer. * adi,adxl355 - New driver and dt bindings for this accelerometer. - Later series adds buffer support. * asahi-kasei,ak8975 - Minor additions to driver to support ak09916 * aspeed,aspeed-adc - Substantial rework plus feature additions to add support for the ast2600 including a new dt bindings doc. * atmel,at91_sama5d2 - Rework and support introduced for the sama7g5 parts. * maxim,max31865 - New driver and bindings for this RTD temperature sensor chip. * nxp,imx8qxp - New driver and bindings for the ADC found on the i.MX 8QuadXPlus Soc. * senseair,sunrise - New driver and bindings for this family of carbon dioxide gas sensors. * sensiron,scd4x - New driver and bindings for this carbon dioxide gas sensor. New features ------------ * Output buffer support. Works in a similar fashion to input buffers, but in this case userspace pushes data into the kfifo which is then drained to the device when a trigger occurs. Support added to the ad5766 DAC driver. * Core, devm_iio_map_array_register() to avoid need for devm_add_action_or_reset() based cleanup in fully managed allocation drivers. * Core iio_push_to_buffers_with_ts_unaligned() function to safely handle a few drivers where it really hard to ensure the correct data alignment in an iio_push_to_buffers_with_timestamp() call. Note this uses a bounce buffer so should be avoided whenever possible. Used in the ti,adc108s102, invense,mpu3050 and adi,adis16400. This closes the last known set of drivers with alignment issues at this interface. * maxim,max1027 - Substantial rework to this driver main target of which was supporting use of other triggers than it's own EOC interrupt. - Transfer optimization. * nxp,fxls8962af - Threshold even support including using it as a wakeup source. Cleanups, minor fixes etc ------------------------- Chances of a common type to multiple drivers: * devm_ conversion and drop of .remove() callbacks in: - adi,ad5064 - adi,ad7291 - adi,ad7303 - adi,ad7746 - adi,ad9832 - adi,adis16080 - dialog,da9150-gpadc - intel,mrfld_adc - marvell,berlin2 - maxim,max1363 - maxim,max44000 - nuvoton,nau7802 - st_sensors (includes a lot of rework!) - ti,ads8344 - ti,lp8788 * devm_platform_ioremap_resource() used to reduce boilerplate - cirrus,ep93xx - rockchip,saradc - stm,stm32-dac * Use dev_err_probe() in more places to both not print on deferred probe and ensure a reason for the deferral is available for debug purposes. - adi,ad8801 - capella,cm36651 - linear,ltc1660 - maxim,ds4424 - maxim,max5821 - microchip,mcp4922 - nxp,lpc18xx - onnn,noa1305 - st,lsm9ds0 - st,st_sensors - st,stm32-dac - ti,afe4403 - ti,afe4404 - ti,dac7311 * Drop error returns in SPI and I2C remove() functions as they are ignored and long term plan is to change these all over to returning void. In some cases these patches just make it 'obvious' they always return 0 where it was the case before but not easy to tell. - adi,ad5380 - adi,ad5446 - adi,ad5686 - adi,ad5592r - bosch,bma400 - bosch,bmc150 - fsl,mma7455 - honeywell,hmc5843 - kionix,kxsd9 - maxim,max5487 - meas,ms5611 - ti,afe4403 Driver specific changes * adi,ad5770r - Bring driver inline with documented bindings. * adi,ad7746 - Trivial style fix * adi,ad7949 - Express some magic values as the underlying parts via new #defines. - Make it work with SPI controllers that don't support 14 or 16 bit messages - Support selection of voltage reference from dt including expanding the dt-bindings to cover this new functionality. * adi,ad799x - Implement selection of external reference voltage on AD7991, AD7995 and AD7999. - Add missing dt-bindings doc for devices supported by this driver. * adi,adislib - Move interrupt startup to better location in startup flow. - Handle devices that cannot mask/unmask the drdy pin and must instead mask at the interrupt controller. Applies to the adis16460 and adis16475 from which we then drop equivalent code. * adi,ltc2983 - Add support for optional reset pin. - Fail to probe if no channels specified in dt binding. * asahi-kasei,ak8975 - dt-binding additions of missing vid-supply regulator. * aspeed,aspeed-adc - Typo fix. * fsl,mma7660 - Mark acpi_device_id table __maybe_unused to avoid build warning. * fsl,imx25-gcq - Avoid initializing regulators that aren't used. * invensense,mpu3050 - Drop a dead protection against a clash with the old input driver. * invensense,mpu6050 - Rework code to not use strcpy() and hence avoid possibility of wrong sized buffers. Note this wasn't a bug, but the new code is a lot more readable. - Mark acpi_device_id table __maybe_unused to avoid build warning. * kionix,kxcjk1013 - dt-binding addition to note it supports interrupts. * marvell,berlin2-adc - Enable COMPILE_TEST building. * maxim,max1027 - Avoid returning success in an error path. * nxp,imx8qxp - Fix warning when runtime pm not enabled via __maybe_unused. * ricoh,rn5t618 - Use the new devm_iio_map_array_register() instead of open coding the same. * samsung,exynos_adc - Improve kconfig help text. * st,lsm6dsx - Move max_fifo_size into the fifo_ops structure where the other configuration parameters are found. * st,st_sensors: - Reorder to ensure we turn the power off after removing userspace interfaces. * senseair,sunrise - Add missing I2C dependency. * ti,twl6030 - Small code tidy up. * tag 'iio-for-5.16a-split-take4' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (148 commits) iio: imx8qxp-adc: mark PM functions as __maybe_unused iio: pressure: ms5611: Make ms5611_remove() return void iio: potentiometer: max5487: Don't return an error in .remove() iio: magn: hmc5843: Make hmc5843_common_remove() return void iio: health: afe4403: Don't return an error in .remove() iio: dac: ad5686: Make ad5686_remove() return void iio: dac: ad5592r: Make ad5592r_remove() return void iio: dac: ad5446: Make ad5446_remove() return void iio: dac: ad5380: Make ad5380_remove() return void iio: accel: mma7455: Make mma7455_core_remove() return void iio: accel: kxsd9: Make kxsd9_common_remove() return void iio: accel: bmi088: Make bmi088_accel_core_remove() return void iio: accel: bmc150: Make bmc150_accel_core_remove() return void iio: accel: bma400: Make bma400_remove() return void drivers:iio:dac:ad5766.c: Add trigger buffer iio: triggered-buffer: extend support to configure output buffers iio: kfifo-buffer: Add output buffer support iio: Add output buffer support iio: documentation: Document scd4x calibration use drivers: iio: chemical: Add support for Sensirion SCD4x CO2 sensor ...
Diffstat (limited to 'drivers/iio/accel/fxls8962af-core.c')
-rw-r--r--drivers/iio/accel/fxls8962af-core.c347
1 files changed, 342 insertions, 5 deletions
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index f41db9e0249a..32989d91b982 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
@@ -30,6 +31,7 @@
#define FXLS8962AF_INT_STATUS 0x00
#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0)
+#define FXLS8962AF_INT_STATUS_SRC_SDCD_OT BIT(4)
#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5)
#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7)
#define FXLS8962AF_TEMP_OUT 0x01
@@ -73,6 +75,7 @@
#define FXLS8962AF_ASLP_COUNT_LSB 0x1e
#define FXLS8962AF_INT_EN 0x20
+#define FXLS8962AF_INT_EN_SDCD_OT_EN BIT(5)
#define FXLS8962AF_INT_EN_BUF_EN BIT(6)
#define FXLS8962AF_INT_PIN_SEL 0x21
#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0)
@@ -96,9 +99,21 @@
#define FXLS8962AF_ORIENT_THS_REG 0x2c
#define FXLS8962AF_SDCD_INT_SRC1 0x2d
+#define FXLS8962AF_SDCD_INT_SRC1_X_OT BIT(5)
+#define FXLS8962AF_SDCD_INT_SRC1_X_POL BIT(4)
+#define FXLS8962AF_SDCD_INT_SRC1_Y_OT BIT(3)
+#define FXLS8962AF_SDCD_INT_SRC1_Y_POL BIT(2)
+#define FXLS8962AF_SDCD_INT_SRC1_Z_OT BIT(1)
+#define FXLS8962AF_SDCD_INT_SRC1_Z_POL BIT(0)
#define FXLS8962AF_SDCD_INT_SRC2 0x2e
#define FXLS8962AF_SDCD_CONFIG1 0x2f
+#define FXLS8962AF_SDCD_CONFIG1_Z_OT_EN BIT(3)
+#define FXLS8962AF_SDCD_CONFIG1_Y_OT_EN BIT(4)
+#define FXLS8962AF_SDCD_CONFIG1_X_OT_EN BIT(5)
+#define FXLS8962AF_SDCD_CONFIG1_OT_ELE BIT(7)
#define FXLS8962AF_SDCD_CONFIG2 0x30
+#define FXLS8962AF_SDCD_CONFIG2_SDCD_EN BIT(7)
+#define FXLS8962AF_SC2_REF_UPDM_AC GENMASK(6, 5)
#define FXLS8962AF_SDCD_OT_DBCNT 0x31
#define FXLS8962AF_SDCD_WT_DBCNT 0x32
#define FXLS8962AF_SDCD_LTHS_LSB 0x33
@@ -151,7 +166,11 @@ struct fxls8962af_data {
} scan;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
struct iio_mount_matrix orientation;
+ int irq;
u8 watermark;
+ u8 enable_event;
+ u16 lower_thres;
+ u16 upper_thres;
};
const struct regmap_config fxls8962af_regmap_conf = {
@@ -238,7 +257,7 @@ static int fxls8962af_get_out(struct fxls8962af_data *data,
}
ret = regmap_bulk_read(data->regmap, chan->address,
- &raw_val, (chan->scan_type.storagebits / 8));
+ &raw_val, sizeof(data->lower_thres));
if (!is_active)
fxls8962af_power_off(data);
@@ -451,6 +470,15 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev,
}
}
+static int fxls8962af_event_setup(struct fxls8962af_data *data, int state)
+{
+ /* Enable wakeup interrupt */
+ int mask = FXLS8962AF_INT_EN_SDCD_OT_EN;
+ int value = state ? mask : 0;
+
+ return regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, mask, value);
+}
+
static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -463,6 +491,217 @@ static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
return 0;
}
+static int __fxls8962af_set_thresholds(struct fxls8962af_data *data,
+ const struct iio_chan_spec *chan,
+ enum iio_event_direction dir,
+ int val)
+{
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ data->lower_thres = val;
+ return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
+ &data->lower_thres, sizeof(data->lower_thres));
+ case IIO_EV_DIR_RISING:
+ data->upper_thres = val;
+ return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
+ &data->upper_thres, sizeof(data->upper_thres));
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
+ &data->lower_thres, sizeof(data->lower_thres));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(data->lower_thres, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_RISING:
+ ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
+ &data->upper_thres, sizeof(data->upper_thres));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(data->upper_thres, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret, val_masked;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ if (val < -2048 || val > 2047)
+ return -EINVAL;
+
+ if (data->enable_event)
+ return -EBUSY;
+
+ val_masked = val & GENMASK(11, 0);
+ if (fxls8962af_is_active(data)) {
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+
+ ret = __fxls8962af_set_thresholds(data, chan, dir, val_masked);
+ if (ret)
+ return ret;
+
+ return fxls8962af_active(data);
+ } else {
+ return __fxls8962af_set_thresholds(data, chan, dir, val_masked);
+ }
+}
+
+static int
+fxls8962af_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ return !!(FXLS8962AF_SDCD_CONFIG1_X_OT_EN & data->enable_event);
+ case IIO_MOD_Y:
+ return !!(FXLS8962AF_SDCD_CONFIG1_Y_OT_EN & data->enable_event);
+ case IIO_MOD_Z:
+ return !!(FXLS8962AF_SDCD_CONFIG1_Z_OT_EN & data->enable_event);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+fxls8962af_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ u8 enable_event, enable_bits;
+ int ret, value;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_X_OT_EN;
+ break;
+ case IIO_MOD_Y:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_Y_OT_EN;
+ break;
+ case IIO_MOD_Z:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_Z_OT_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (state)
+ enable_event = data->enable_event | enable_bits;
+ else
+ enable_event = data->enable_event & ~enable_bits;
+
+ if (data->enable_event == enable_event)
+ return 0;
+
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+
+ /* Enable events */
+ value = enable_event | FXLS8962AF_SDCD_CONFIG1_OT_ELE;
+ ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG1, value);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable update of SDCD_REF_X/Y/Z values with the current decimated and
+ * trimmed X/Y/Z acceleration input data. This allows for acceleration
+ * slope detection with Data(n) to Data(n–1) always used as the input
+ * to the window comparator.
+ */
+ value = enable_event ?
+ FXLS8962AF_SDCD_CONFIG2_SDCD_EN | FXLS8962AF_SC2_REF_UPDM_AC :
+ 0x00;
+ ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG2, value);
+ if (ret)
+ return ret;
+
+ ret = fxls8962af_event_setup(data, state);
+ if (ret)
+ return ret;
+
+ data->enable_event = enable_event;
+
+ if (data->enable_event) {
+ fxls8962af_active(data);
+ ret = fxls8962af_power_on(data);
+ } else {
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Not in buffered mode so disable power */
+ ret = fxls8962af_power_off(data);
+
+ iio_device_release_direct_mode(indio_dev);
+ }
+
+ return ret;
+}
+
+static const struct iio_event_spec fxls8962af_event[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
#define FXLS8962AF_CHANNEL(axis, reg, idx) { \
.type = IIO_ACCEL, \
.address = reg, \
@@ -481,6 +720,8 @@ static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
.shift = 4, \
.endianness = IIO_BE, \
}, \
+ .event_spec = fxls8962af_event, \
+ .num_event_specs = ARRAY_SIZE(fxls8962af_event), \
}
#define FXLS8962AF_TEMP_CHANNEL { \
@@ -522,6 +763,10 @@ static const struct iio_info fxls8962af_info = {
.read_raw = &fxls8962af_read_raw,
.write_raw = &fxls8962af_write_raw,
.write_raw_get_fmt = fxls8962af_write_raw_get_fmt,
+ .read_event_value = fxls8962af_read_event,
+ .write_event_value = fxls8962af_write_event,
+ .read_event_config = fxls8962af_read_event_config,
+ .write_event_config = fxls8962af_write_event_config,
.read_avail = fxls8962af_read_avail,
.hwfifo_set_watermark = fxls8962af_set_watermark,
};
@@ -605,7 +850,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
ret = __fxls8962af_fifo_set_mode(data, false);
- fxls8962af_active(data);
+ if (data->enable_event)
+ fxls8962af_active(data);
return ret;
}
@@ -614,7 +860,10 @@ static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
- return fxls8962af_power_off(data);
+ if (!data->enable_event)
+ fxls8962af_power_off(data);
+
+ return 0;
}
static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = {
@@ -725,6 +974,45 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
return count;
}
+static int fxls8962af_event_interrupt(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ s64 ts = iio_get_time_ns(indio_dev);
+ unsigned int reg;
+ u64 ev_code;
+ int ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_SDCD_INT_SRC1, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_X_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_X_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_Y_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Y_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_Z_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Z_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ return 0;
+}
+
static irqreturn_t fxls8962af_interrupt(int irq, void *p)
{
struct iio_dev *indio_dev = p;
@@ -744,6 +1032,14 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p)
return IRQ_HANDLED;
}
+ if (reg & FXLS8962AF_INT_STATUS_SRC_SDCD_OT) {
+ ret = fxls8962af_event_interrupt(indio_dev);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+ }
+
return IRQ_NONE;
}
@@ -861,6 +1157,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
+ data->irq = irq;
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
@@ -930,6 +1227,9 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
if (ret)
return ret;
+ if (device_property_read_bool(dev, "wakeup-source"))
+ device_init_wakeup(dev, true);
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(fxls8962af_core_probe);
@@ -955,9 +1255,46 @@ static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
return fxls8962af_active(data);
}
+static int __maybe_unused fxls8962af_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (device_may_wakeup(dev) && data->enable_event) {
+ enable_irq_wake(data->irq);
+
+ /*
+ * Disable buffer, as the buffer is so small the device will wake
+ * almost immediately.
+ */
+ if (iio_buffer_enabled(indio_dev))
+ fxls8962af_buffer_predisable(indio_dev);
+ } else {
+ fxls8962af_runtime_suspend(dev);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused fxls8962af_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (device_may_wakeup(dev) && data->enable_event) {
+ disable_irq_wake(data->irq);
+
+ if (iio_buffer_enabled(indio_dev))
+ fxls8962af_buffer_postenable(indio_dev);
+ } else {
+ fxls8962af_runtime_resume(dev);
+ }
+
+ return 0;
+}
+
const struct dev_pm_ops fxls8962af_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
fxls8962af_runtime_resume, NULL)
};