iio: acpi_als: Add trigger support
As some firmware does not notify on illuminance changes, add a trigger to be able to query light via software (sysfs-trigger or hrtrigger). Add a hardware trigger set as the default trigger to maintain backward compatibility. Check iio_info reports the sensor as buffer capable: iio:device0: acpi-als (buffer capable) To test, check we can get data on demand on an Intel based chromebook: IIO_DEV="iio:device0" echo 1 > iio_sysfs_trigger/add_trigger cat trigger2/name > ${IIO_DEV}/trigger/current_trigger for i in ${IIO_DEV}/scan_elements/*_en ${IIO_DEV}/buffer/enable ; do echo 1 > $i done od -x /dev/${IIO_DEV} & echo 1 > trigger2/trigger_now Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Link: https://lore.kernel.org/r/20210317074012.2336454-4-gwendal@chromium.org Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
ddaf14dab7
commit
24b84444eb
@ -16,11 +16,14 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define ACPI_ALS_CLASS "als"
|
||||
#define ACPI_ALS_DEVICE_NAME "acpi-als"
|
||||
@ -59,6 +62,7 @@ static const struct iio_chan_spec acpi_als_channels[] = {
|
||||
struct acpi_als {
|
||||
struct acpi_device *device;
|
||||
struct mutex lock;
|
||||
struct iio_trigger *trig;
|
||||
|
||||
s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE / sizeof(s32)] __aligned(8);
|
||||
};
|
||||
@ -102,33 +106,19 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
struct iio_dev *indio_dev = acpi_driver_data(device);
|
||||
struct acpi_als *als = iio_priv(indio_dev);
|
||||
s32 *buffer = als->evt_buffer;
|
||||
s64 time_ns = iio_get_time_ns(indio_dev);
|
||||
s32 val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&als->lock);
|
||||
|
||||
memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE);
|
||||
|
||||
switch (event) {
|
||||
case ACPI_ALS_NOTIFY_ILLUMINANCE:
|
||||
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
*buffer++ = val;
|
||||
break;
|
||||
default:
|
||||
/* Unhandled event */
|
||||
dev_dbg(&device->dev, "Unhandled ACPI ALS event (%08x)!\n",
|
||||
event);
|
||||
goto out;
|
||||
if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev)) {
|
||||
switch (event) {
|
||||
case ACPI_ALS_NOTIFY_ILLUMINANCE:
|
||||
iio_trigger_poll_chained(als->trig);
|
||||
break;
|
||||
default:
|
||||
/* Unhandled event */
|
||||
dev_dbg(&device->dev,
|
||||
"Unhandled ACPI ALS event (%08x)!\n",
|
||||
event);
|
||||
}
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, als->evt_buffer, time_ns);
|
||||
|
||||
out:
|
||||
mutex_unlock(&als->lock);
|
||||
}
|
||||
|
||||
static int acpi_als_read_raw(struct iio_dev *indio_dev,
|
||||
@ -159,6 +149,41 @@ static const struct iio_info acpi_als_info = {
|
||||
.read_raw = acpi_als_read_raw,
|
||||
};
|
||||
|
||||
static irqreturn_t acpi_als_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct acpi_als *als = iio_priv(indio_dev);
|
||||
s32 *buffer = als->evt_buffer;
|
||||
s32 val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&als->lock);
|
||||
|
||||
ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
*buffer = val;
|
||||
|
||||
/*
|
||||
* When coming from own trigger via polls, set polling function
|
||||
* timestamp here. Given ACPI notifier is already in a thread and call
|
||||
* function directly, there is no need to set the timestamp in the
|
||||
* notify function.
|
||||
*
|
||||
* If the timestamp was actually 0, the timestamp is set one more time.
|
||||
*/
|
||||
if (!pf->timestamp)
|
||||
pf->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
|
||||
out:
|
||||
mutex_unlock(&als->lock);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int acpi_als_add(struct acpi_device *device)
|
||||
{
|
||||
struct device *dev = &device->dev;
|
||||
@ -181,8 +206,23 @@ static int acpi_als_add(struct acpi_device *device)
|
||||
indio_dev->channels = acpi_als_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels);
|
||||
|
||||
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
|
||||
INDIO_BUFFER_SOFTWARE, NULL);
|
||||
als->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id);
|
||||
if (!als->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_iio_trigger_register(dev, als->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* Set hardware trigger by default to let events flow when
|
||||
* BIOS support notification.
|
||||
*/
|
||||
indio_dev->trig = iio_trigger_get(als->trig);
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
acpi_als_trigger_handler,
|
||||
NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user