Files
linux/drivers/iio/accel/bmc150-accel.h
Linus Walleij 3aa385a9c7 iio: accel: bmc150: Fix irq assumption regression
The code in bmc150-accel-core.c unconditionally calls
bmc150_accel_set_interrupt() in the iio_buffer_setup_ops,
such as on the runtime PM resume path giving a kernel
splat like this if the device has no interrupts:

Unable to handle kernel NULL pointer dereference at virtual
  address 00000001 when read

PC is at bmc150_accel_set_interrupt+0x98/0x194
LR is at __pm_runtime_resume+0x5c/0x64
(...)
Call trace:
bmc150_accel_set_interrupt from bmc150_accel_buffer_postenable+0x40/0x108
bmc150_accel_buffer_postenable from __iio_update_buffers+0xbe0/0xcbc
__iio_update_buffers from enable_store+0x84/0xc8
enable_store from kernfs_fop_write_iter+0x154/0x1b4

This bug seems to have been in the driver since the beginning,
but it only manifests recently, I do not know why.

Store the IRQ number in the state struct, as this is a common
pattern in other drivers, then use this to determine if we have
IRQ support or not.

Cc: stable@vger.kernel.org
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2025-11-11 20:22:23 +00:00

98 lines
2.7 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BMC150_ACCEL_H_
#define _BMC150_ACCEL_H_
#include <linux/atomic.h>
#include <linux/iio/iio.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/workqueue.h>
struct regmap;
struct i2c_client;
struct bmc150_accel_chip_info;
struct bmc150_accel_interrupt_info;
/*
* We can often guess better than "UNKNOWN" based on the device IDs
* but unfortunately this information is not always accurate. There are some
* devices where ACPI firmware specifies an ID like "BMA250E" when the device
* actually has a BMA222E. The driver attempts to detect those by reading the
* chip ID from the registers but this information is not always enough either.
*
* Therefore, this enum should be only used when the chip ID detection is not
* enough and we can be reasonably sure that the device IDs are reliable
* in practice (e.g. for device tree platforms).
*/
enum bmc150_type {
BOSCH_UNKNOWN,
BOSCH_BMC156,
};
struct bmc150_accel_interrupt {
const struct bmc150_accel_interrupt_info *info;
atomic_t users;
};
struct bmc150_accel_trigger {
struct bmc150_accel_data *data;
struct iio_trigger *indio_trig;
int (*setup)(struct bmc150_accel_trigger *t, bool state);
int intr;
bool enabled;
};
enum bmc150_accel_interrupt_id {
BMC150_ACCEL_INT_DATA_READY,
BMC150_ACCEL_INT_ANY_MOTION,
BMC150_ACCEL_INT_WATERMARK,
BMC150_ACCEL_INTERRUPTS,
};
enum bmc150_accel_trigger_id {
BMC150_ACCEL_TRIGGER_DATA_READY,
BMC150_ACCEL_TRIGGER_ANY_MOTION,
BMC150_ACCEL_TRIGGERS,
};
struct bmc150_accel_data {
struct regmap *regmap;
int irq;
struct regulator_bulk_data regulators[2];
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
struct mutex mutex;
u8 fifo_mode, watermark;
s16 buffer[8];
/*
* Ensure there is sufficient space and correct alignment for
* the timestamp if enabled
*/
struct {
__le16 channels[3];
aligned_s64 ts;
} scan;
u8 bw_bits;
u32 slope_dur;
u32 slope_thres;
u32 range;
int ev_enable_state;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
const struct bmc150_accel_chip_info *chip_info;
enum bmc150_type type;
struct i2c_client *second_device;
void (*resume_callback)(struct device *dev);
struct delayed_work resume_work;
struct iio_mount_matrix orientation;
};
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
enum bmc150_type type, const char *name,
bool block_supported);
void bmc150_accel_core_remove(struct device *dev);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
#endif /* _BMC150_ACCEL_H_ */