blob: 66119826e614e970cc598a1f2b4149ac54292a3d [file] [log] [blame]
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