| From 92622a90284f09268e74865970139e9686f82bff Mon Sep 17 00:00:00 2001 |
| From: Enric Balletbo i Serra <enric.balletbo@collabora.com> |
| Date: Mon, 19 Jun 2017 17:33:31 +0200 |
| Subject: [PATCH] CHROMIUM: iio: cros_ec: add support for single sensor hub |
| FIFO |
| |
| For satisfying HAL requirement, add a IIO driver that expose the cros ec |
| sensor hub FIFO. Named cros-ec-ring, it allows an application to get |
| all the events in a single FIFO, prefixed by sensor id and flags. |
| The old behavior where we can read all sensors in a single sample |
| via cros-ec-sensors is preserved. |
| |
| BUG=chromium:510242,chromium:946178 |
| |
| Signed-off-by: Gwendal Grignou <gwendal@chromium.org> |
| (Squashed related commits bc14076e8807 .. 6addb52fb680) |
| Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com> |
| |
| [rebase419(groeck): cros_ec_sensors_core.h is now common include file |
| Move sensor_fifo from ec_response_get_next_data to |
| ec_response_get_next_data_v1 |
| Squash: |
| FIXUP: CHROMIUM: iio: cros_ec: add support for single sensor hub FIFO |
| ] |
| Signed-off-by: Guenter Roeck <groeck@chromium.org> |
| |
| [rebase54(gwendal): drop change in cros_ec_commands.h, already in] |
| [rebase510(gwendal): squash all changes related to ring, as the code has moved to |
| cros_ec_sensorhub_ring.c] |
| |
| Signed-off-by: Gwendal Grignou <gwendal@chromium.org> |
| Change-Id: I156f1842165a542baadd761e7951b19cd926b183 |
| --- |
| drivers/iio/common/cros_ec_sensors/Kconfig | 9 ++ |
| drivers/iio/common/cros_ec_sensors/Makefile | 1 + |
| .../cros_ec_sensors/cros_ec_sensors_core.c | 12 ++ |
| .../cros_ec_sensors/cros_ec_sensors_ring.c | 152 ++++++++++++++++++ |
| drivers/platform/chrome/cros_ec_sensorhub.c | 7 + |
| .../platform/chrome/cros_ec_sensorhub_ring.c | 27 +++- |
| 6 files changed, 206 insertions(+), 2 deletions(-) |
| create mode 100644 drivers/iio/common/cros_ec_sensors/cros_ec_sensors_ring.c |
| |
| diff --git a/drivers/iio/common/cros_ec_sensors/Kconfig b/drivers/iio/common/cros_ec_sensors/Kconfig |
| index fefad9572790..d4e6a5e81665 100644 |
| --- a/drivers/iio/common/cros_ec_sensors/Kconfig |
| +++ b/drivers/iio/common/cros_ec_sensors/Kconfig |
| @@ -30,3 +30,12 @@ config IIO_CROS_EC_SENSORS_LID_ANGLE |
| convertible devices. |
| This module is loaded when the EC can calculate the angle between the base |
| and the lid. |
| + |
| +config IIO_CROS_EC_SENSORS_RING |
| + tristate "ChromeOS EC Sensors Ring" |
| + depends on IIO_CROS_EC_SENSORS || IIO_CROS_EC_LIGHT_PROX |
| + help |
| + Add support for handling sensor events FIFO produced by |
| + the sensor hub. |
| + A single device with a buffer will collect all samples produced |
| + by the sensors managed by the CroEC sensor hub. |
| diff --git a/drivers/iio/common/cros_ec_sensors/Makefile b/drivers/iio/common/cros_ec_sensors/Makefile |
| index e0a33ab66d21..59ba12dcc3c9 100644 |
| --- a/drivers/iio/common/cros_ec_sensors/Makefile |
| +++ b/drivers/iio/common/cros_ec_sensors/Makefile |
| @@ -6,3 +6,4 @@ |
| obj-$(CONFIG_IIO_CROS_EC_SENSORS_CORE) += cros_ec_sensors_core.o |
| obj-$(CONFIG_IIO_CROS_EC_SENSORS) += cros_ec_sensors.o |
| obj-$(CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE) += cros_ec_lid_angle.o |
| +obj-$(CONFIG_IIO_CROS_EC_SENSORS_RING) += cros_ec_sensors_ring.o |
| diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c |
| index 28bde13003b7..2d4c8c19ea8d 100644 |
| --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c |
| +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c |
| @@ -333,9 +333,21 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, |
| * We can not use trigger here, as events are generated |
| * as soon as sample_frequency is set. |
| */ |
| + |
| +#if IS_ENABLED(CONFIG_IIO_CROS_EC_SENSORS_RING) |
| + /* |
| + * To preserve backward compatibility, when sensor ring |
| + * is set, all events are going to the ring buffer. |
| + * To pull event to the individual buffers, |
| + * we need triggers. |
| + */ |
| + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, |
| + NULL, trigger_capture, NULL); |
| +#else |
| ret = devm_iio_kfifo_buffer_setup_ext(dev, indio_dev, |
| INDIO_BUFFER_SOFTWARE, NULL, |
| cros_ec_sensor_fifo_attributes); |
| +#endif |
| if (ret) |
| return ret; |
| |
| diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_ring.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_ring.c |
| new file mode 100644 |
| index 000000000000..9bb457ba669b |
| --- /dev/null |
| +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_ring.c |
| @@ -0,0 +1,152 @@ |
| +/* |
| + * cros_ec_sensors_ring - Driver for Chrome OS EC Sensor hub FIFO. |
| + * |
| + * Copyright (C) 2015 Google, Inc |
| + * |
| + * This software is licensed under the terms of the GNU General Public |
| + * License version 2, as published by the Free Software Foundation, and |
| + * may be copied, distributed, and modified under those terms. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * This driver uses the cros-ec interface to communicate with the Chrome OS |
| + * EC about accelerometer data. Accelerometer access is presented through |
| + * iio sysfs. |
| + */ |
| + |
| +#include <linux/delay.h> |
| +#include <linux/device.h> |
| +#include <linux/iio/buffer.h> |
| +#include <linux/iio/iio.h> |
| +#include <linux/iio/kfifo_buf.h> |
| +#include <linux/iio/sysfs.h> |
| +#include <linux/kernel.h> |
| +#include <linux/module.h> |
| +#include <linux/platform_data/cros_ec_sensorhub.h> |
| +#include <linux/platform_device.h> |
| + |
| +#define DRV_NAME "cros-ec-ring" |
| + |
| +/* |
| + * The ring is a FIFO that return sensor information from |
| + * the single EC FIFO. |
| + * There are always 5 channels returned: |
| + * | ID | FLAG | X | Y | Z | Timestamp | |
| + * ID is the EC sensor id |
| + * FLAG are extra information provided by the EC. |
| + */ |
| + |
| +enum { |
| + CHANNEL_SENSOR_ID, |
| + CHANNEL_SENSOR_FLAG, |
| + CHANNEL_X, |
| + CHANNEL_Y, |
| + CHANNEL_Z, |
| + CHANNEL_TIMESTAMP, |
| + MAX_CHANNEL, |
| +}; |
| + |
| +#define CROS_EC_RING_ID(_id, _name) \ |
| +{ \ |
| + .type = IIO_ACCEL, \ |
| + .scan_index = _id, \ |
| + .scan_type = { \ |
| + .sign = 'u', \ |
| + .realbits = 8, \ |
| + .storagebits = 8, \ |
| + }, \ |
| + .extend_name = _name, \ |
| +} |
| + |
| +#define CROS_EC_RING_AXIS(_axis) \ |
| +{ \ |
| + .type = IIO_ACCEL, \ |
| + .modified = 1, \ |
| + .channel2 = IIO_MOD_##_axis, \ |
| + .scan_index = CHANNEL_##_axis, \ |
| + .scan_type = { \ |
| + .sign = 's', \ |
| + .realbits = 16, \ |
| + .storagebits = 16, \ |
| + }, \ |
| + .extend_name = "ring", \ |
| +} |
| + |
| +static const struct iio_chan_spec cros_ec_ring_channels[] = { |
| + CROS_EC_RING_ID(CHANNEL_SENSOR_ID, "id"), |
| + CROS_EC_RING_ID(CHANNEL_SENSOR_FLAG, "flag"), |
| + CROS_EC_RING_AXIS(X), |
| + CROS_EC_RING_AXIS(Y), |
| + CROS_EC_RING_AXIS(Z), |
| + IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_TIMESTAMP) |
| +}; |
| + |
| +static const struct iio_info ec_sensors_info = { |
| +}; |
| + |
| +static int cros_sensor_ring_push_sample( |
| + struct iio_dev *indio_dev, |
| + s16 *data, s64 timestamp) |
| +{ |
| + return iio_push_to_buffers(indio_dev, (u8 *)data); |
| +} |
| + |
| +static int cros_ec_ring_probe(struct platform_device *pdev) |
| +{ |
| + struct device *dev = &pdev->dev; |
| + struct cros_ec_sensorhub *sensor_hub = dev_get_drvdata(dev->parent); |
| + struct iio_dev *indio_dev; |
| + struct iio_buffer *buffer; |
| + int ret; |
| + |
| + indio_dev = devm_iio_device_alloc(dev, 0); |
| + if (!indio_dev) |
| + return -ENOMEM; |
| + |
| + platform_set_drvdata(pdev, indio_dev); |
| + indio_dev->dev.parent = dev; |
| + indio_dev->name = pdev->name; |
| + indio_dev->channels = cros_ec_ring_channels; |
| + indio_dev->num_channels = ARRAY_SIZE(cros_ec_ring_channels); |
| + indio_dev->info = &ec_sensors_info; |
| + indio_dev->modes = INDIO_BUFFER_SOFTWARE; |
| + |
| + buffer = devm_iio_kfifo_allocate(dev); |
| + if (!buffer) |
| + return -ENOMEM; |
| + |
| + iio_device_attach_buffer(indio_dev, buffer); |
| + ret = cros_ec_sensorhub_register_push_data( |
| + sensor_hub, sensor_hub->sensor_num, indio_dev, |
| + cros_sensor_ring_push_sample); |
| + if (ret) |
| + return ret; |
| + |
| + return devm_iio_device_register(dev, indio_dev); |
| +} |
| + |
| +static int cros_ec_ring_remove(struct platform_device *pdev) |
| +{ |
| + struct cros_ec_sensorhub *sensor_hub = |
| + dev_get_drvdata(pdev->dev.parent); |
| + |
| + cros_ec_sensorhub_unregister_push_data(sensor_hub, sensor_hub->sensor_num); |
| + |
| + return 0; |
| +} |
| + |
| +static struct platform_driver cros_ec_ring_platform_driver = { |
| + .driver = { |
| + .name = DRV_NAME, |
| + }, |
| + .probe = cros_ec_ring_probe, |
| + .remove = cros_ec_ring_remove, |
| +}; |
| +module_platform_driver(cros_ec_ring_platform_driver); |
| + |
| +MODULE_DESCRIPTION("ChromeOS EC sensor hub ring driver"); |
| +MODULE_ALIAS("platform:" DRV_NAME); |
| +MODULE_LICENSE("GPL v2"); |
| diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c |
| index 9c4af76a9956..9dedf33c9514 100644 |
| --- a/drivers/platform/chrome/cros_ec_sensorhub.c |
| +++ b/drivers/platform/chrome/cros_ec_sensorhub.c |
| @@ -109,6 +109,13 @@ static int cros_ec_sensorhub_register(struct device *dev, |
| if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) |
| ec->has_kb_wake_angle = true; |
| |
| + if (IS_ENABLED(CONFIG_IIO_CROS_EC_SENSORS_RING) && |
| + cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { |
| + ret = cros_ec_sensorhub_allocate_sensor(dev, "cros-ec-ring", 0); |
| + if (ret) |
| + return ret; |
| + } |
| + |
| if (cros_ec_check_features(ec, |
| EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) { |
| ret = cros_ec_sensorhub_allocate_sensor(dev, |
| diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c |
| index 8921f24e83ba..b8877bafc5b8 100644 |
| --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c |
| +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c |
| @@ -32,6 +32,11 @@ |
| /* To measure by how much the filter is overshooting, if it happens. */ |
| #define FUTURE_TS_ANALYTICS_COUNT_MAX 100 |
| |
| +#if IS_ENABLED(CONFIG_IIO_CROS_EC_SENSORS_RING) |
| +/* |
| + * To be compliant with existing code, device buffer is only for |
| + * triggered samples. |
| + */ |
| static inline int |
| cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, |
| struct cros_ec_sensors_ring_sample *sample) |
| @@ -43,6 +48,23 @@ cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, |
| if (id >= sensorhub->sensor_num) |
| return -EINVAL; |
| |
| + cb = sensorhub->push_data[sensorhub->sensor_num].push_data_cb; |
| + |
| + indio_dev = sensorhub->push_data[sensorhub->sensor_num].indio_dev; |
| + if (!indio_dev) |
| + return 0; |
| + |
| + return cb(indio_dev, (s16 *)sample, 0); |
| +} |
| +#else |
| +static inline int |
| +cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, |
| + struct cros_ec_sensors_ring_sample *sample) |
| +{ |
| + int id = sample->sensor_id; |
| + cros_ec_sensorhub_push_data_cb_t cb; |
| + struct iio_dev *indio_dev; |
| + |
| cb = sensorhub->push_data[id].push_data_cb; |
| if (!cb) |
| return 0; |
| @@ -54,6 +76,7 @@ cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, |
| |
| return cb(indio_dev, sample->vector, sample->timestamp); |
| } |
| +#endif |
| |
| /** |
| * cros_ec_sensorhub_register_push_data() - register the callback to the hub. |
| @@ -74,7 +97,7 @@ int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub, |
| struct iio_dev *indio_dev, |
| cros_ec_sensorhub_push_data_cb_t cb) |
| { |
| - if (sensor_num >= sensorhub->sensor_num) |
| + if (sensor_num >= sensorhub->sensor_num + 1) |
| return -EINVAL; |
| if (sensorhub->push_data[sensor_num].indio_dev) |
| return -EINVAL; |
| @@ -951,7 +974,7 @@ int cros_ec_sensorhub_ring_allocate(struct cros_ec_sensorhub *sensorhub) |
| * Add one for the sensor ring. |
| */ |
| sensorhub->push_data = devm_kcalloc(sensorhub->dev, |
| - sensorhub->sensor_num, |
| + sensorhub->sensor_num + 1, |
| sizeof(*sensorhub->push_data), |
| GFP_KERNEL); |
| if (!sensorhub->push_data) |
| -- |
| 2.31.1.607.g51e8a6a459-goog |
| |