From patchwork Tue Mar 24 20:27:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456413 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E31DF913 for ; Tue, 24 Mar 2020 20:27:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AA13F2074D for ; Tue, 24 Mar 2020 20:27:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="gGxrJGQt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727967AbgCXU1x (ORCPT ); Tue, 24 Mar 2020 16:27:53 -0400 Received: from mail-pj1-f67.google.com ([209.85.216.67]:52178 "EHLO mail-pj1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727496AbgCXU1u (ORCPT ); Tue, 24 Mar 2020 16:27:50 -0400 Received: by mail-pj1-f67.google.com with SMTP id w9so42625pjh.1 for ; Tue, 24 Mar 2020 13:27:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=nloQ5x/nN9mbvQqKSehreiqma1ArFNfxg9xOisyEOvE=; b=gGxrJGQtVj6MWH52dPMi5c1df0a3FtBaV+nRQMnz4pc1tCnlSXM0MeL1Px+nLjblWO +DKZ68oPbbcIenIBpy8bpNKIaRYANJtPfAu5L4ucaAxGwtrLE4b9Nv/AgLaT3gs/AAvX cNiuQD9ZzDVn31pl8jjxH55t9L46rDsEX9FR8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=nloQ5x/nN9mbvQqKSehreiqma1ArFNfxg9xOisyEOvE=; b=tTdKcVC8jItHJ+zK0DCm6WGmnfrQ1ndgdYsOOUHq6SFtuTUOtDhIekib3bErYLoDl7 akFsPgS2O6lsy9GiMkY3BEH6xx6Jzgg6ItCr0HcmIcHEw2MryhB/F3Kd4b4rqrN5qYbB z8Y4QxtwuRvv4L9TaQJZ/jK1Hojppj/9soOvvBv2jgU911CMpuojhYqQD2dTts9a84wW MZIYMlhNLNxlcsz8FBB4dKbXWhagtQzE1Xj0uQw2ji1P7VW+x6bwXFpMhc66dPdNy3xY fFHZwpFwqG8zi9vQRFDywFlDrv41BKcIuzzKTYOCxhjRjx601kdmwQHddgPyXHUsjxvU 06ZQ== X-Gm-Message-State: ANhLgQ0VSO6WcTcxh227a6xqX0oF7QHGqJ3U40e62Pf+W+Zu8dCfv1HM QYt/CKbLcVfKT/HZpiqSKKrf0g== X-Google-Smtp-Source: ADFU+vvEh6S0NdOBlLIlMasm8/v8M88TC0Mk3lwpSm4ICD+c56fcD3Jixk2QpXco8Jszt95h8VGykQ== X-Received: by 2002:a17:902:8bc8:: with SMTP id r8mr27600089plo.48.1585081667498; Tue, 24 Mar 2020 13:27:47 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id e9sm16972951pfl.179.2020.03.24.13.27.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:47 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 01/11] platform: chrome: sensorhub: Add FIFO support Date: Tue, 24 Mar 2020 13:27:26 -0700 Message-Id: <20200324202736.243314-2-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org cros_ec_sensorhub registers a listener and query motion sense FIFO, spread to iio sensors registers. To test, we can use libiio: iiod& iio_readdev -u ip:localhost -T 10000 -s 25 -b 16 cros-ec-gyro | od -x Reviewed-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - Unify function naming in cros_ec_sensorhub: cros_ec_sensorhub_ring_... - Kernel module name is now cros-ec-sensorhub - Remove unneceassary warning messages. Changes in v5: - Use a goto in cros_ec_sensorhub_ring_handler to centralize error handling - Use devm_add_action_or_reset to not need a .remove entry point for cros_sensor_hub. - Fix logic error in cros_ec_sensorhub_register_push_data. - Update kernel_doc documentation. - Remve the need for comments in variable declaration section. Changes in v4: - Keep defining cros_ec_sensorhub in kernel-doc format - Fix logic error when checking if sensor index outside array. - Check patch with --strict option Use sizeof(*obj) instead of sizeof(struct ...obj) Alignement Use uX instead of uintX_t Use !ptr instead of ptr != NULL Changes in v3: - Do not use ret != - Simplfy errpr handling by removing a goto - Fix doxygen comments - Replace suspend/resume entry points with regular driver entry point; There was an issue in the past where the sensor stack was preventing device to suspend, but the proper fix has been implemented in cros_ec code (6ad16b78a039b "platform/chrome: don't report EC_MKBP_EVENT_SENSOR_FIFO as wakeup") - Reduce mutex scope by checking return code outside of it. Changes in v2: - Do not register a .remove routinge in plaform_driver. A devm_action_add is added later patch IIO driver register their callback. - Remove double lines, add lines before return calls. - Handle FLUSH flag from EC. - Use ktime_t for most timestamp measurements. - Add doxygen comments - Cleanup timestamp collection when processing FIFO. - Rename fifo_toggle to fifo_enable drivers/platform/chrome/Makefile | 4 +- drivers/platform/chrome/cros_ec_sensorhub.c | 107 +++-- .../platform/chrome/cros_ec_sensorhub_ring.c | 425 ++++++++++++++++++ .../linux/platform_data/cros_ec_sensorhub.h | 91 ++++ 4 files changed, 599 insertions(+), 28 deletions(-) create mode 100644 drivers/platform/chrome/cros_ec_sensorhub_ring.c diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 198c155c7c4d4..1223b028cefa0 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -20,7 +20,9 @@ obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_chardev.o obj-$(CONFIG_CROS_EC_LIGHTBAR) += cros_ec_lightbar.o obj-$(CONFIG_CROS_EC_VBC) += cros_ec_vbc.o obj-$(CONFIG_CROS_EC_DEBUGFS) += cros_ec_debugfs.o -obj-$(CONFIG_CROS_EC_SENSORHUB) += cros_ec_sensorhub.o +obj-$(CONFIG_CROS_EC_SENSORHUB) += cros-ec-sensorhub.o +cros-ec-sensorhub-objs := cros_ec_sensorhub.o +cros-ec-sensorhub-objs += cros_ec_sensorhub_ring.o obj-$(CONFIG_CROS_EC_SYSFS) += cros_ec_sysfs.o obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c index 79fefd3bb0fa6..bbb1c8f89905d 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub.c +++ b/drivers/platform/chrome/cros_ec_sensorhub.c @@ -50,10 +50,8 @@ static int cros_ec_sensorhub_register(struct device *dev, struct cros_ec_sensorhub *sensorhub) { int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 }; + struct cros_ec_command *msg = sensorhub->msg; struct cros_ec_dev *ec = sensorhub->ec; - struct ec_params_motion_sense *params; - struct ec_response_motion_sense *resp; - struct cros_ec_command *msg; int ret, i, sensor_num; char *name; @@ -70,22 +68,13 @@ static int cros_ec_sensorhub_register(struct device *dev, return -EINVAL; } - /* Prepare a message to send INFO command to each sensor. */ - msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*resp)), - GFP_KERNEL); - if (!msg) - return -ENOMEM; - msg->version = 1; - msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; - msg->outsize = sizeof(*params); - msg->insize = sizeof(*resp); - params = (struct ec_params_motion_sense *)msg->data; - resp = (struct ec_response_motion_sense *)msg->data; + msg->insize = sizeof(struct ec_response_motion_sense); + msg->outsize = sizeof(struct ec_params_motion_sense); for (i = 0; i < sensor_num; i++) { - params->cmd = MOTIONSENSE_CMD_INFO; - params->info.sensor_num = i; + sensorhub->params->cmd = MOTIONSENSE_CMD_INFO; + sensorhub->params->info.sensor_num = i; ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); if (ret < 0) { @@ -94,7 +83,7 @@ static int cros_ec_sensorhub_register(struct device *dev, continue; } - switch (resp->info.type) { + switch (sensorhub->resp->info.type) { case MOTIONSENSE_TYPE_ACCEL: name = "cros-ec-accel"; break; @@ -117,15 +106,16 @@ static int cros_ec_sensorhub_register(struct device *dev, name = "cros-ec-activity"; break; default: - dev_warn(dev, "unknown type %d\n", resp->info.type); + dev_warn(dev, "unknown type %d\n", + sensorhub->resp->info.type); continue; } ret = cros_ec_sensorhub_allocate_sensor(dev, name, i); if (ret) - goto error; + return ret; - sensor_type[resp->info.type]++; + sensor_type[sensorhub->resp->info.type]++; } if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) @@ -137,29 +127,41 @@ static int cros_ec_sensorhub_register(struct device *dev, "cros-ec-lid-angle", 0); if (ret) - goto error; + return ret; } - kfree(msg); return 0; - -error: - kfree(msg); - return ret; } static int cros_ec_sensorhub_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct cros_ec_dev *ec = dev_get_drvdata(dev->parent); struct cros_ec_sensorhub *data; + struct cros_ec_command *msg; int ret; int i; + msg = devm_kzalloc(dev, sizeof(struct cros_ec_command) + + max((u16)sizeof(struct ec_params_motion_sense), + ec->ec_dev->max_response), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; + data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL); if (!data) return -ENOMEM; - data->ec = dev_get_drvdata(dev->parent); + mutex_init(&data->cmd_lock); + + data->dev = dev; + data->ec = ec; + data->msg = msg; + data->params = (struct ec_params_motion_sense *)msg->data; + data->resp = (struct ec_response_motion_sense *)msg->data; + dev_set_drvdata(dev, data); /* Check whether this EC is a sensor hub. */ @@ -180,12 +182,63 @@ static int cros_ec_sensorhub_probe(struct platform_device *pdev) } } + /* + * If the EC does not have a FIFO, the sensors will query their data + * themselves via sysfs or a software trigger. + */ + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { + ret = cros_ec_sensorhub_ring_add(data); + if (ret) + return ret; + /* + * The msg and its data is not under the control of the ring + * handler. + */ + return devm_add_action_or_reset(dev, + cros_ec_sensorhub_ring_remove, + data); + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/* + * When the EC is suspending, we must stop sending interrupt, + * we may use the same interrupt line for waking up the device. + * Tell the EC to stop sending non-interrupt event on the iio ring. + */ +static int cros_ec_sensorhub_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev); + struct cros_ec_dev *ec = sensorhub->ec; + + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) + return cros_ec_sensorhub_ring_fifo_enable(sensorhub, false); return 0; } +static int cros_ec_sensorhub_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cros_ec_sensorhub *sensorhub = platform_get_drvdata(pdev); + struct cros_ec_dev *ec = sensorhub->ec; + + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) + return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(cros_ec_sensorhub_pm_ops, + cros_ec_sensorhub_suspend, + cros_ec_sensorhub_resume); + static struct platform_driver cros_ec_sensorhub_driver = { .driver = { .name = DRV_NAME, + .pm = &cros_ec_sensorhub_pm_ops, }, .probe = cros_ec_sensorhub_probe, }; diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c new file mode 100644 index 0000000000000..436f306899252 --- /dev/null +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Chrome OS EC Sensor hub FIFO. + * + * Copyright 2020 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline int +cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, + struct cros_ec_sensors_ring_sample *sample) +{ + cros_ec_sensorhub_push_data_cb_t cb; + int id = sample->sensor_id; + struct iio_dev *indio_dev; + + if (id > CROS_EC_SENSOR_MAX) + return -EINVAL; + + cb = sensorhub->push_data[id].push_data_cb; + if (!cb) + return 0; + + indio_dev = sensorhub->push_data[id].indio_dev; + + if (sample->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH) + return 0; + + return cb(indio_dev, sample->vector, sample->timestamp); +} + +/** + * cros_ec_sensorhub_register_push_data() - register the callback to the hub. + * + * @sensorhub : Sensor Hub object + * @sensor_num : The sensor the caller is interested in. + * @indio_dev : The iio device to use when a sample arrives. + * @cb : The callback to call when a sample arrives. + * + * The callback cb will be used by cros_ec_sensorhub_ring to distribute events + * from the EC. + * + * Return: 0 when callback is registered. + * EINVAL is the sensor number is invalid or the slot already used. + */ +int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub, + u8 sensor_num, + struct iio_dev *indio_dev, + cros_ec_sensorhub_push_data_cb_t cb) +{ + if (sensor_num >= CROS_EC_SENSOR_PDEV_MAX) + return -EINVAL; + if (sensorhub->push_data[sensor_num].indio_dev) + return -EINVAL; + + sensorhub->push_data[sensor_num].indio_dev = indio_dev; + sensorhub->push_data[sensor_num].push_data_cb = cb; + + return 0; +} +EXPORT_SYMBOL_GPL(cros_ec_sensorhub_register_push_data); + +void cros_ec_sensorhub_unregister_push_data(struct cros_ec_sensorhub *sensorhub, + u8 sensor_num) +{ + sensorhub->push_data[sensor_num].indio_dev = NULL; + sensorhub->push_data[sensor_num].push_data_cb = NULL; +} +EXPORT_SYMBOL_GPL(cros_ec_sensorhub_unregister_push_data); + +/** + * cros_ec_sensorhub_ring_fifo_enable() - Enable or disable interrupt generation + * for FIFO events. + * @sensorhub: Sensor Hub object + * @on: true when events are requested. + * + * To be called before sleeping or when noone is listening. + * Return: 0 on success, or an error when we can not communicate with the EC. + * + */ +int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub, + bool on) +{ + int ret; + + mutex_lock(&sensorhub->cmd_lock); + sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INT_ENABLE; + sensorhub->params->fifo_int_enable.enable = on; + + sensorhub->msg->outsize = sizeof(struct ec_params_motion_sense); + sensorhub->msg->insize = sizeof(struct ec_response_motion_sense); + + ret = cros_ec_cmd_xfer_status(sensorhub->ec->ec_dev, sensorhub->msg); + mutex_unlock(&sensorhub->cmd_lock); + + /* We expect to receive a payload of 4 bytes, ignore. */ + if (ret > 0) + ret = 0; + + return ret; +} + +/** + * cros_ec_sensor_ring_process_event() - process one EC FIFO event + * + * @sensorhub: Sensor Hub object. + * @fifo_info: FIFO information from the EC (includes b point, EC timebase). + * @fifo_timestamp: EC IRQ, kernel timebase (aka c). + * @current_timestamp: calculated event timestamp, kernel timebase (aka a'). + * @in: incoming FIFO event from EC (includes a point, EC timebase). + * @out: outgoing event to user space (includes a'). + * + * Process one EC event, add it in the ring if necessary. + * + * Return: true if out event has been populated. + */ +static bool +cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, + const struct cros_ec_fifo_info *fifo_info, + const ktime_t fifo_timestamp, + ktime_t *current_timestamp, + struct ec_response_motion_sensor_data *in, + struct cros_ec_sensors_ring_sample *out) +{ + const s64 now = cros_ec_get_time_ns(); + int axis, async_flags; + + /* Do not populate the filter based on asynchronous events. */ + async_flags = in->flags & + (MOTIONSENSE_SENSOR_FLAG_ODR | MOTIONSENSE_SENSOR_FLAG_FLUSH); + + if (in->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP && !async_flags) { + s64 new_timestamp; + + /* + * Disable filtering since we might add more jitter + * if b is in a random point in time. + */ + new_timestamp = fifo_timestamp - + fifo_info->info.timestamp * 1000 + + in->timestamp * 1000; + + /* + * The timestamp can be stale if we had to use the fifo + * info timestamp. + */ + if (new_timestamp - *current_timestamp > 0) + *current_timestamp = new_timestamp; + } + + if (in->flags & MOTIONSENSE_SENSOR_FLAG_FLUSH) { + out->sensor_id = in->sensor_num; + out->timestamp = *current_timestamp; + out->flag = in->flags; + /* + * No other payload information provided with + * flush ack. + */ + return true; + } + + if (in->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) + /* If we just have a timestamp, skip this entry. */ + return false; + + /* Regular sample */ + out->sensor_id = in->sensor_num; + if (*current_timestamp - now > 0) + /* If the timestamp is in the future. */ + out->timestamp = now; + else + out->timestamp = *current_timestamp; + + out->flag = in->flags; + for (axis = 0; axis < 3; axis++) + out->vector[axis] = in->data[axis]; + + return true; +} + +/** + * cros_ec_sensorhub_ring_handler() - The trigger handler function + * + * @sensorhub: Sensor Hub object. + * + * Called by the notifier, process the EC sensor FIFO queue. + */ +static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) +{ + struct cros_ec_fifo_info *fifo_info = &sensorhub->fifo_info; + struct cros_ec_dev *ec = sensorhub->ec; + ktime_t fifo_timestamp, current_timestamp; + int i, j, number_data, ret; + unsigned long sensor_mask = 0; + struct ec_response_motion_sensor_data *in; + struct cros_ec_sensors_ring_sample *out, *last_out; + + mutex_lock(&sensorhub->cmd_lock); + + /* Get FIFO information if there are lost vectors. */ + if (fifo_info->info.total_lost) { + /* Need to retrieve the number of lost vectors per sensor */ + sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INFO; + sensorhub->msg->outsize = 1; + sensorhub->msg->insize = + sizeof(struct ec_response_motion_sense_fifo_info) + + sizeof(u16) * CROS_EC_SENSOR_MAX; + + if (cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg) < 0) + goto error; + + memcpy(fifo_info, &sensorhub->resp->fifo_info, + sizeof(*fifo_info)); + + /* + * Update collection time, will not be as precise as the + * non-error case. + */ + fifo_timestamp = cros_ec_get_time_ns(); + } else { + fifo_timestamp = + sensorhub->fifo_timestamp[CROS_EC_SENSOR_NEW_TS]; + } + + if (fifo_info->info.count > sensorhub->fifo_size || + fifo_info->info.size != sensorhub->fifo_size) { + dev_warn(sensorhub->dev, + "Mismatch EC data: count %d, size %d - expected %d", + fifo_info->info.count, fifo_info->info.size, + sensorhub->fifo_size); + goto error; + } + + /* Copy elements in the main fifo */ + current_timestamp = sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS]; + out = sensorhub->ring; + for (i = 0; i < fifo_info->info.count; i += number_data) { + sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_READ; + sensorhub->params->fifo_read.max_data_vector = + fifo_info->info.count - i; + sensorhub->msg->outsize = + sizeof(struct ec_params_motion_sense); + sensorhub->msg->insize = + sizeof(sensorhub->resp->fifo_read) + + sensorhub->params->fifo_read.max_data_vector * + sizeof(struct ec_response_motion_sensor_data); + ret = cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg); + if (ret < 0) { + dev_warn(sensorhub->dev, "Fifo error: %d\n", ret); + break; + } + number_data = sensorhub->resp->fifo_read.number_data; + if (number_data == 0) { + dev_dbg(sensorhub->dev, "Unexpected empty FIFO\n"); + break; + } + if (number_data > fifo_info->info.count - i) { + dev_warn(sensorhub->dev, + "Invalid EC data: too many entry received: %d, expected %d", + number_data, fifo_info->info.count - i); + break; + } + if (out + number_data > + sensorhub->ring + fifo_info->info.count) { + dev_warn(sensorhub->dev, + "Too many samples: %d (%zd data) to %d entries for expected %d entries", + i, out - sensorhub->ring, i + number_data, + fifo_info->info.count); + break; + } + + for (in = sensorhub->resp->fifo_read.data, j = 0; + j < number_data; j++, in++) { + if (cros_ec_sensor_ring_process_event( + sensorhub, fifo_info, + fifo_timestamp, + ¤t_timestamp, + in, out)) { + sensor_mask |= BIT(in->sensor_num); + out++; + } + } + } + mutex_unlock(&sensorhub->cmd_lock); + last_out = out; + + if (out == sensorhub->ring) + /* Unexpected empty FIFO. */ + goto ring_handler_end; + + /* + * Check if current_timestamp is ahead of the last sample. + * Normally, the EC appends a timestamp after the last sample, but if + * the AP is slow to respond to the IRQ, the EC may have added new + * samples. Use the FIFO info timestamp as last timestamp then. + */ + if ((last_out - 1)->timestamp == current_timestamp) + current_timestamp = fifo_timestamp; + + /* Warn on lost samples. */ + for_each_set_bit(i, &sensor_mask, BITS_PER_LONG) { + int total_lost = fifo_info->info.total_lost; + + if (total_lost) { + int lost = fifo_info->lost[i]; + + if (lost) { + dev_warn_ratelimited(sensorhub->dev, + "Sensor %d: lost: %d out of %d\n", + i, lost, total_lost); + } + } + } + + /* Push the event into the FIFO. */ + for (out = sensorhub->ring; out < last_out; out++) + cros_sensorhub_send_sample(sensorhub, out); + +ring_handler_end: + sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = current_timestamp; + return; + +error: + mutex_unlock(&sensorhub->cmd_lock); +} + +static int cros_ec_sensorhub_event(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *_notify) +{ + struct cros_ec_sensorhub *sensorhub; + struct cros_ec_device *ec_dev; + + sensorhub = container_of(nb, struct cros_ec_sensorhub, notifier); + ec_dev = sensorhub->ec->ec_dev; + + if (ec_dev->event_data.event_type != EC_MKBP_EVENT_SENSOR_FIFO) + return NOTIFY_DONE; + + if (ec_dev->event_size != sizeof(ec_dev->event_data.data.sensor_fifo)) { + dev_warn(ec_dev->dev, "Invalid fifo info size\n"); + return NOTIFY_DONE; + } + + if (queued_during_suspend) + return NOTIFY_OK; + + sensorhub->fifo_info.info = ec_dev->event_data.data.sensor_fifo.info; + sensorhub->fifo_timestamp[CROS_EC_SENSOR_NEW_TS] = + ec_dev->last_event_time; + cros_ec_sensorhub_ring_handler(sensorhub); + + return NOTIFY_OK; +} + +/** + * cros_ec_sensorhub_ring_add() - Add the FIFO functionality if the EC + * supports it. + * + * @sensorhub : Sensor Hub object. + * + * Return: 0 on success. + */ +int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub) +{ + struct cros_ec_dev *ec = sensorhub->ec; + int ret; + + /* Retrieve FIFO information */ + sensorhub->msg->version = 2; + sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INFO; + sensorhub->msg->outsize = 1; + sensorhub->msg->insize = + sizeof(struct ec_response_motion_sense_fifo_info) + + sizeof(u16) * CROS_EC_SENSOR_MAX; + + ret = cros_ec_cmd_xfer_status(ec->ec_dev, sensorhub->msg); + if (ret < 0) + return ret; + + /* + * Allocate the full fifo. We need to copy the whole FIFO to set + * timestamps properly. + */ + sensorhub->fifo_size = sensorhub->resp->fifo_info.size; + sensorhub->ring = devm_kcalloc(sensorhub->dev, sensorhub->fifo_size, + sizeof(*sensorhub->ring), GFP_KERNEL); + if (!sensorhub->ring) + return -ENOMEM; + + sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = + cros_ec_get_time_ns(); + + /* Register the notifier that will act as a top half interrupt. */ + sensorhub->notifier.notifier_call = cros_ec_sensorhub_event; + ret = blocking_notifier_chain_register(&ec->ec_dev->event_notifier, + &sensorhub->notifier); + if (ret < 0) + return ret; + + /* Start collection samples. */ + return cros_ec_sensorhub_ring_fifo_enable(sensorhub, true); +} + +void cros_ec_sensorhub_ring_remove(void *arg) +{ + struct cros_ec_sensorhub *sensorhub = arg; + struct cros_ec_device *ec_dev = sensorhub->ec->ec_dev; + + /* Disable the ring, prevent EC interrupt to the AP for nothing. */ + cros_ec_sensorhub_ring_fifo_enable(sensorhub, false); + blocking_notifier_chain_unregister(&ec_dev->event_notifier, + &sensorhub->notifier); +} diff --git a/include/linux/platform_data/cros_ec_sensorhub.h b/include/linux/platform_data/cros_ec_sensorhub.h index bef7ffc7fce10..cb849a2da4f60 100644 --- a/include/linux/platform_data/cros_ec_sensorhub.h +++ b/include/linux/platform_data/cros_ec_sensorhub.h @@ -8,8 +8,22 @@ #ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H #define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H +#include +#include +#include #include +/* Maximal number of sensors supported by the EC. */ +#define CROS_EC_SENSOR_MAX 16 + +/* + * Maximal number of sensors supported by the hub: + * We add one for the lid angle inclinometer sensor. + */ +#define CROS_EC_SENSOR_PDEV_MAX (CROS_EC_SENSOR_MAX + 1) + +struct iio_dev; + /** * struct cros_ec_sensor_platform - ChromeOS EC sensor platform information. * @sensor_num: Id of the sensor, as reported by the EC. @@ -18,13 +32,90 @@ struct cros_ec_sensor_platform { u8 sensor_num; }; +/** + * typedef cros_ec_sensorhub_push_data_cb_t - Callback function to send datum + * to specific sensors. + * + * @indio_dev: The IIO device that will process the sample. + * @data: Vector array of the ring sample. + * @timestamp: Timestamp in host timespace when the sample was acquired by + * the EC. + */ +typedef int (*cros_ec_sensorhub_push_data_cb_t)(struct iio_dev *indio_dev, + s16 *data, + s64 timestamp); + +struct cros_ec_sensorhub_sensor_push_data { + struct iio_dev *indio_dev; + cros_ec_sensorhub_push_data_cb_t push_data_cb; +}; + +enum { + CROS_EC_SENSOR_LAST_TS, + CROS_EC_SENSOR_NEW_TS, + CROS_EC_SENSOR_ALL_TS +}; + +struct __ec_todo_packed cros_ec_fifo_info { + struct ec_response_motion_sense_fifo_info info; + u16 lost[CROS_EC_SENSOR_MAX]; +}; + +struct cros_ec_sensors_ring_sample { + u8 sensor_id; + u8 flag; + s16 vector[3]; + s64 timestamp; +} __packed; + /** * struct cros_ec_sensorhub - Sensor Hub device data. * + * @dev: Device object, mostly used for logging. * @ec: Embedded Controller where the hub is located. + * @msg: Structure to send FIFO requests. + * @params: Pointer to parameters in msg. + * @resp: Pointer to responses in msg. + * @cmd_lock : Lock for sending msg. + * @notifier: Notifier to kick the FIFO interrupt. + * @ring: Preprocessed ring to store events. + * @fifo_timestamp: array for event timestamp and spreading. + * @fifo_info: copy of FIFO information coming from the EC. + * @fifo_size: size of the ring. + * @push_data: array of callback to send datums to iio sensor object. */ struct cros_ec_sensorhub { + struct device *dev; struct cros_ec_dev *ec; + + struct cros_ec_command *msg; + struct ec_params_motion_sense *params; + struct ec_response_motion_sense *resp; + struct mutex cmd_lock; /* Lock for protecting msg structure. */ + + struct notifier_block notifier; + + struct cros_ec_sensors_ring_sample *ring; + + ktime_t fifo_timestamp[CROS_EC_SENSOR_ALL_TS]; + struct cros_ec_fifo_info fifo_info; + int fifo_size; + + struct cros_ec_sensorhub_sensor_push_data + push_data[CROS_EC_SENSOR_PDEV_MAX]; }; +int cros_ec_sensorhub_register_push_data(struct cros_ec_sensorhub *sensorhub, + u8 sensor_num, + struct iio_dev *indio_dev, + cros_ec_sensorhub_push_data_cb_t cb); + +void cros_ec_sensorhub_unregister_push_data(struct cros_ec_sensorhub *sensorhub, + u8 sensor_num); + +int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub); +void cros_ec_sensorhub_ring_remove(void *arg); +int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub, + bool on); + #endif /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */ From patchwork Tue Mar 24 20:27:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456411 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5440213A4 for ; Tue, 24 Mar 2020 20:27:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2CD9A2074D for ; Tue, 24 Mar 2020 20:27:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="fXYNnIEJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727894AbgCXU1w (ORCPT ); Tue, 24 Mar 2020 16:27:52 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:40015 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725953AbgCXU1v (ORCPT ); Tue, 24 Mar 2020 16:27:51 -0400 Received: by mail-pf1-f194.google.com with SMTP id l184so9902582pfl.7 for ; Tue, 24 Mar 2020 13:27:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4Qj04WM6WV1292DERlnygQnUZFPOVeWCGyavY3CnVo0=; b=fXYNnIEJFXbsceM0cn/xg1RpPl8jXKwcjoLAfK0PWctuEX6zp2mL7GpQ0VFTmDdC+p oc6f7ZCKl/Gyhykq8+WeC7b80Lk4Fdl2h2Fz1EGZw5XUeSeuFjID6OWBqDXYtWLDUuPR s5cJykmdeB4VT3Heg521Cvd/i4LJ8J5ftkJek= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4Qj04WM6WV1292DERlnygQnUZFPOVeWCGyavY3CnVo0=; b=TZoa39fhsw7/8e+aWHNOsf2+wWDF//RHK2zVKOcZGok44H9+zA1B0brc3GPYg3ELbo /WIQifwj/8HrEiKc27jU01HYf7VzorGPDRmQk6P9AfMiHLXxPzBQvGKxYYteQ/8WbS+h 8I1cJHe07xMQtzvReD1NCD3EfFKF5FMuTbLZ6py76Tkv9qKUndZ9uzq39N20C74LVRQz S5nk4TratKR7kW3OzXwrVIBIkX3g2484VAMW0u4WoigWZHmGy64byPk4cwpx6krLTjgN Gu8lifvDxoYRjlAzCTMrpwLhn+suVQvCcTPWqqFC5EP/ekERVtv8gCqH8ma5ypCVbNAs MXyQ== X-Gm-Message-State: ANhLgQ0nyxdyqfbb8pqyTzP7PsQDTwKcn9cMFl7rjivnXsKQUV6jnhWB wQEBHBkkKD10yN8WtgM4s0/AuQ== X-Google-Smtp-Source: ADFU+vvV6/M+B723trEGCiueLFYow5J7/7xqL4+vICG4fHYjhKVj5bqOHjB+yrQ/U37Fav1oYYRxLQ== X-Received: by 2002:aa7:96c8:: with SMTP id h8mr25009032pfq.49.1585081668670; Tue, 24 Mar 2020 13:27:48 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id i23sm16760643pfq.157.2020.03.24.13.27.48 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:48 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou , Lee Jones Subject: [PATCH v6 02/11] platform: chrome: sensorhub: Add code to spread timestmap Date: Tue, 24 Mar 2020 13:27:27 -0700 Message-Id: <20200324202736.243314-3-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org EC FIFO can send sensor events in batch. Spread them based on previous (TSa) and currnet timestamp (TSb) EC FIFO iio events +-----------+ | TSa | +-----------+ +---------------------------------------+ | event 1 | | event 1 | TSb - (TSb - TSa)/n * (n-1) | +-----------+ +---------------------------------------+ | event 2 | | event 2 | TSb - (TSb - TSa)/n * (n-2) | +-----------+ +---------------------------------------+ | ... | ------> | .... | | +-----------+ +---------------------------------------+ | event n-1 | | event 2 | TSb - (TSb - TSa)/n | +-----------+ +---------------------------------------+ | event n | | event 2 | TSb | +-----------+ +---------------------------------------+ | TSb | +-----------+ Acked-by: Jonathan Cameron Acked-by: Lee Jones Signed-off-by: Gwendal Grignou --- Changes in v6: Comment fixes Changes in v5: Added ack. Changes in v4: - Check patch with --strict option Alignement No changes in v3. Changes in v2: - Use CROS_EC_SENSOR_LAST_TS instead of LAST_TS to avoid name colisions. .../platform/chrome/cros_ec_sensorhub_ring.c | 112 ++++++++++++++++-- 1 file changed, 105 insertions(+), 7 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c index 436f306899252..efe726171bf00 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -189,6 +189,101 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, return true; } +/* + * cros_ec_sensor_ring_spread_add: Calculate proper timestamps then add to + * ringbuffer. + * + * If there is a sample with a proper timestamp + * + * timestamp | count + * ----------------- + * older_unprocess_out --> TS1 | 1 + * TS1 | 2 + * out --> TS1 | 3 + * next_out --> TS2 | + * + * We spread time for the samples [older_unprocess_out .. out] + * between TS1 and TS2: [TS1+1/4, TS1+2/4, TS1+3/4, TS2]. + * + * If we reach the end of the samples, we compare with the + * current timestamp: + * + * older_unprocess_out --> TS1 | 1 + * TS1 | 2 + * out --> TS1 | 3 + * + * We know have [TS1+1/3, TS1+2/3, current timestamp] + */ +static void cros_ec_sensor_ring_spread_add(struct cros_ec_sensorhub *sensorhub, + unsigned long sensor_mask, + s64 current_timestamp, + struct cros_ec_sensors_ring_sample + *last_out) +{ + struct cros_ec_sensors_ring_sample *out; + int i; + + for_each_set_bit(i, &sensor_mask, BITS_PER_LONG) { + s64 older_timestamp; + s64 timestamp; + struct cros_ec_sensors_ring_sample *older_unprocess_out = + sensorhub->ring; + struct cros_ec_sensors_ring_sample *next_out; + int count = 1; + + for (out = sensorhub->ring; out < last_out; out = next_out) { + s64 time_period; + + next_out = out + 1; + if (out->sensor_id != i) + continue; + + /* Timestamp to start with */ + older_timestamp = out->timestamp; + + /* Find next sample. */ + while (next_out < last_out && next_out->sensor_id != i) + next_out++; + + if (next_out >= last_out) { + timestamp = current_timestamp; + } else { + timestamp = next_out->timestamp; + if (timestamp == older_timestamp) { + count++; + continue; + } + } + + /* + * The next sample has a new timestamp, spread the + * unprocessed samples. + */ + if (next_out < last_out) + count++; + time_period = div_s64(timestamp - older_timestamp, + count); + + for (; older_unprocess_out <= out; + older_unprocess_out++) { + if (older_unprocess_out->sensor_id != i) + continue; + older_timestamp += time_period; + older_unprocess_out->timestamp = + older_timestamp; + } + count = 1; + /* The next_out sample has a valid timestamp, skip. */ + next_out++; + older_unprocess_out = next_out; + } + } + + /* Push the event into the kfifo */ + for (out = sensorhub->ring; out < last_out; out++) + cros_sensorhub_send_sample(sensorhub, out); +} + /** * cros_ec_sensorhub_ring_handler() - The trigger handler function * @@ -300,10 +395,10 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) goto ring_handler_end; /* - * Check if current_timestamp is ahead of the last sample. - * Normally, the EC appends a timestamp after the last sample, but if - * the AP is slow to respond to the IRQ, the EC may have added new - * samples. Use the FIFO info timestamp as last timestamp then. + * Check if current_timestamp is ahead of the last sample. Normally, + * the EC appends a timestamp after the last sample, but if the AP + * is slow to respond to the IRQ, the EC may have added new samples. + * Use the FIFO info timestamp as last timestamp then. */ if ((last_out - 1)->timestamp == current_timestamp) current_timestamp = fifo_timestamp; @@ -323,9 +418,12 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) } } - /* Push the event into the FIFO. */ - for (out = sensorhub->ring; out < last_out; out++) - cros_sensorhub_send_sample(sensorhub, out); + /* + * Spread samples in case of batching, then add them to the + * ringbuffer. + */ + cros_ec_sensor_ring_spread_add(sensorhub, sensor_mask, + current_timestamp, last_out); ring_handler_end: sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = current_timestamp; From patchwork Tue Mar 24 20:27:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456427 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 02EE217EF for ; Tue, 24 Mar 2020 20:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AC40020788 for ; Tue, 24 Mar 2020 20:28:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="SdewfYUv" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728057AbgCXU14 (ORCPT ); Tue, 24 Mar 2020 16:27:56 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:42412 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727902AbgCXU1x (ORCPT ); Tue, 24 Mar 2020 16:27:53 -0400 Received: by mail-pl1-f195.google.com with SMTP id e1so2870637plt.9 for ; Tue, 24 Mar 2020 13:27:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+lZ3snZ9bECpjK0Mt48We/+766+nWlHNAtQzqWc1PRo=; b=SdewfYUvV7XDT+E+Kaopr5g50lGpOnTZhi6zsUgDtyd4AQnLC11fk4MISp+APd+ZO2 z1Pjtvh3YYOxL9QZA3N5jL3+Cbl6/aktT9PNc4OCHrwXQ76V6QpbPjZWSp9g0mc5X629 tsfn/urcEvP0Qt6cY+NmJJBtGZypoqyRu/4yI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+lZ3snZ9bECpjK0Mt48We/+766+nWlHNAtQzqWc1PRo=; b=rRzNtnfckiiHdsrIJ82yu2U86TVZy+teO65ad6pOHpPgRFg/48Gdj0dH7cwIHeBSKI K8FC3Pq0qrDoDnXtXrtPTLE8VHN40xPPF/ffPazNaX/u++b+klyBVb9elpc/E5kOIUgR uOdmpJSSBca+uXtS7VKyxqa3ptdBvGhrB4kSPgpSlm/Lb9CtA3NFYWBE5MHRljEAdpcP gp4+G+g3j/CFPcC6WenzDcVAv3nrAKnyxPylAGqLToL8SL3I+BMuzZ2bZiVi2YUCeMaN BjJAwFxk0ltYuGy6da9XIJQ67khLQdlXNPVoLxNwfZnmaf9WEVqy2dvxyZm4ZvN9LkqQ OACA== X-Gm-Message-State: ANhLgQ0YjGqrRCUgnJ9FY4jXKLvGnYdbJ6Ks1Z4n+X8/BbGXAhwaSwo0 XRIO1uFkABkoLeElmjB0ZG+C9g== X-Google-Smtp-Source: ADFU+vv2rTRRFZ0OC0g8XCrptTRW2KCU0HMuUNrBd/79ubqhn+74eLLikPP156cMmcwk3bgzAAxfOQ== X-Received: by 2002:a17:90a:6501:: with SMTP id i1mr7472179pjj.32.1585081669964; Tue, 24 Mar 2020 13:27:49 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id i189sm10387656pfc.148.2020.03.24.13.27.49 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:49 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou , Lee Jones Subject: [PATCH v6 03/11] platform: chrome: sensorhub: Add median filter Date: Tue, 24 Mar 2020 13:27:28 -0700 Message-Id: <20200324202736.243314-4-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Events are timestamped in EC time space, their timestamps need to be converted in host time space. The assumption is the time delta between when the interrupt is sent by the EC and when it is receive by the host is a [small] constant. This is not always true, even with hard-wired interrupt. To mitigate worst offenders, add a median filter to weed out bigger than expected delays. Acked-by: Jonathan Cameron Acked-by: Enric Balletbo i Serra Acked-by: Lee Jones Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: - Enforce kernel-doc function naming. - Added ack. - Fix spelling - Add ratelimiting for an error message. - Remove unrelated code changes (line, kernel-doc) Changes in v4: - Keep defining cros_ec_sensorhub in kernel-doc format - Check patch with --strict option Use BIT() Add spaces around '-' Alignement Changes in v3: - Fix doxygen code. Changes in v2: - Move some #define in .c to prevent name collisions. - Add proper doxygen comments. - Use /* instead of // .../platform/chrome/cros_ec_sensorhub_ring.c | 538 +++++++++++++++++- .../linux/platform_data/cros_ec_sensorhub.h | 83 ++- 2 files changed, 591 insertions(+), 30 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c index efe726171bf00..14da503cc0559 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c +++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c @@ -17,6 +17,21 @@ #include #include +/* Precision of fixed point for the m values from the filter */ +#define M_PRECISION BIT(23) + +/* Only activate the filter once we have at least this many elements. */ +#define TS_HISTORY_THRESHOLD 8 + +/* + * If we don't have any history entries for this long, empty the filter to + * make sure there are no big discontinuities. + */ +#define TS_HISTORY_BORED_US 500000 + +/* To measure by how much the filter is overshooting, if it happens. */ +#define FUTURE_TS_ANALYTICS_COUNT_MAX 100 + static inline int cros_sensorhub_send_sample(struct cros_ec_sensorhub *sensorhub, struct cros_ec_sensors_ring_sample *sample) @@ -92,9 +107,11 @@ EXPORT_SYMBOL_GPL(cros_ec_sensorhub_unregister_push_data); int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub, bool on) { - int ret; + int ret, i; mutex_lock(&sensorhub->cmd_lock); + for (i = 0; i < CROS_EC_SENSOR_MAX; i++) + sensorhub->last_batch_len[i] = 0; sensorhub->params->cmd = MOTIONSENSE_CMD_FIFO_INT_ENABLE; sensorhub->params->fifo_int_enable.enable = on; @@ -111,8 +128,242 @@ int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub, return ret; } +static int cros_ec_sensor_ring_median_cmp(const void *pv1, const void *pv2) +{ + s64 v1 = *(s64 *)pv1; + s64 v2 = *(s64 *)pv2; + + if (v1 > v2) + return 1; + else if (v1 < v2) + return -1; + else + return 0; +} + +/* + * cros_ec_sensor_ring_median: Gets median of an array of numbers + * + * For now it's implemented using an inefficient > O(n) sort then return + * the middle element. A more optimal method would be something like + * quickselect, but given that n = 64 we can probably live with it in the + * name of clarity. + * + * Warning: the input array gets modified (sorted)! + */ +static s64 cros_ec_sensor_ring_median(s64 *array, size_t length) +{ + sort(array, length, sizeof(s64), cros_ec_sensor_ring_median_cmp, NULL); + return array[length / 2]; +} + +/* + * IRQ Timestamp Filtering + * + * Lower down in cros_ec_sensor_ring_process_event(), for each sensor event + * we have to calculate it's timestamp in the AP timebase. There are 3 time + * points: + * a - EC timebase, sensor event + * b - EC timebase, IRQ + * c - AP timebase, IRQ + * a' - what we want: sensor even in AP timebase + * + * While a and b are recorded at accurate times (due to the EC real time + * nature); c is pretty untrustworthy, even though it's recorded the + * first thing in ec_irq_handler(). There is a very good change we'll get + * added lantency due to: + * other irqs + * ddrfreq + * cpuidle + * + * Normally a' = c - b + a, but if we do that naive math any jitter in c + * will get coupled in a', which we don't want. We want a function + * a' = cros_ec_sensor_ring_ts_filter(a) which will filter out outliers in c. + * + * Think of a graph of AP time(b) on the y axis vs EC time(c) on the x axis. + * The slope of the line won't be exactly 1, there will be some clock drift + * between the 2 chips for various reasons (mechanical stress, temperature, + * voltage). We need to extrapolate values for a future x, without trusting + * recent y values too much. + * + * We use a median filter for the slope, then another median filter for the + * y-intercept to calculate this function: + * dx[n] = x[n-1] - x[n] + * dy[n] = x[n-1] - x[n] + * m[n] = dy[n] / dx[n] + * median_m = median(m[n-k:n]) + * error[i] = y[n-i] - median_m * x[n-i] + * median_error = median(error[:k]) + * predicted_y = median_m * x + median_error + * + * Implementation differences from above: + * - Redefined y to be actually c - b, this gives us a lot more precision + * to do the math. (c-b)/b variations are more obvious than c/b variations. + * - Since we don't have floating point, any operations involving slope are + * done using fixed point math (*M_PRECISION) + * - Since x and y grow with time, we keep zeroing the graph (relative to + * the last sample), this way math involving *x[n-i] will not overflow + * - EC timestamps are kept in us, it improves the slope calculation precision + */ + +/** + * cros_ec_sensor_ring_ts_filter_update() - Update filter history. + * + * @state: Filter information. + * @b: IRQ timestamp, EC timebase (us) + * @c: IRQ timestamp, AP timebase (ns) + * + * Given a new IRQ timestamp pair (EC and AP timebases), add it to the filter + * history. + */ +static void +cros_ec_sensor_ring_ts_filter_update(struct cros_ec_sensors_ts_filter_state + *state, + s64 b, s64 c) +{ + s64 x, y; + s64 dx, dy; + s64 m; /* stored as *M_PRECISION */ + s64 *m_history_copy = state->temp_buf; + s64 *error = state->temp_buf; + int i; + + /* we trust b the most, that'll be our independent variable */ + x = b; + /* y is the offset between AP and EC times, in ns */ + y = c - b * 1000; + + dx = (state->x_history[0] + state->x_offset) - x; + if (dx == 0) + return; /* we already have this irq in the history */ + dy = (state->y_history[0] + state->y_offset) - y; + m = div64_s64(dy * M_PRECISION, dx); + + /* Empty filter if we haven't seen any action in a while. */ + if (-dx > TS_HISTORY_BORED_US) + state->history_len = 0; + + /* Move everything over, also update offset to all absolute coords .*/ + for (i = state->history_len - 1; i >= 1; i--) { + state->x_history[i] = state->x_history[i - 1] + dx; + state->y_history[i] = state->y_history[i - 1] + dy; + + state->m_history[i] = state->m_history[i - 1]; + /* + * Also use the same loop to copy m_history for future + * median extraction. + */ + m_history_copy[i] = state->m_history[i - 1]; + } + + /* Store the x and y, but remember offset is actually last sample. */ + state->x_offset = x; + state->y_offset = y; + state->x_history[0] = 0; + state->y_history[0] = 0; + + state->m_history[0] = m; + m_history_copy[0] = m; + + if (state->history_len < CROS_EC_SENSORHUB_TS_HISTORY_SIZE) + state->history_len++; + + /* Precalculate things for the filter. */ + if (state->history_len > TS_HISTORY_THRESHOLD) { + state->median_m = + cros_ec_sensor_ring_median(m_history_copy, + state->history_len - 1); + + /* + * Calculate y-intercepts as if m_median is the slope and + * points in the history are on the line. median_error will + * still be in the offset coordinate system. + */ + for (i = 0; i < state->history_len; i++) + error[i] = state->y_history[i] - + div_s64(state->median_m * state->x_history[i], + M_PRECISION); + state->median_error = + cros_ec_sensor_ring_median(error, state->history_len); + } else { + state->median_m = 0; + state->median_error = 0; + } +} + +/** + * cros_ec_sensor_ring_ts_filter() - Translate EC timebase timestamp to AP + * timebase + * + * @state: filter information. + * @x: any ec timestamp (us): + * + * cros_ec_sensor_ring_ts_filter(a) => a' event timestamp, AP timebase + * cros_ec_sensor_ring_ts_filter(b) => calculated timestamp when the EC IRQ + * should have happened on the AP, with low jitter + * + * Note: The filter will only activate once state->history_len goes + * over TS_HISTORY_THRESHOLD. Otherwise it'll just do the naive c - b + a + * transform. + * + * How to derive the formula, starting from: + * f(x) = median_m * x + median_error + * That's the calculated AP - EC offset (at the x point in time) + * Undo the coordinate system transform: + * f(x) = median_m * (x - x_offset) + median_error + y_offset + * Remember to undo the "y = c - b * 1000" modification: + * f(x) = median_m * (x - x_offset) + median_error + y_offset + x * 1000 + * + * Return: timestamp in AP timebase (ns) + */ +static s64 +cros_ec_sensor_ring_ts_filter(struct cros_ec_sensors_ts_filter_state *state, + s64 x) +{ + return div_s64(state->median_m * (x - state->x_offset), M_PRECISION) + + state->median_error + state->y_offset + x * 1000; +} + +/* + * Since a and b were originally 32 bit values from the EC, + * they overflow relatively often, casting is not enough, so we need to + * add an offset. + */ +static void +cros_ec_sensor_ring_fix_overflow(s64 *ts, + const s64 overflow_period, + struct cros_ec_sensors_ec_overflow_state + *state) +{ + s64 adjust; + + *ts += state->offset; + if (abs(state->last - *ts) > (overflow_period / 2)) { + adjust = state->last > *ts ? overflow_period : -overflow_period; + state->offset += adjust; + *ts += adjust; + } + state->last = *ts; +} + +static void +cros_ec_sensor_ring_check_for_past_timestamp(struct cros_ec_sensorhub + *sensorhub, + struct cros_ec_sensors_ring_sample + *sample) +{ + const u8 sensor_id = sample->sensor_id; + + /* If this event is earlier than one we saw before... */ + if (sensorhub->newest_sensor_event[sensor_id] > sample->timestamp) + /* mark it for spreading. */ + sample->timestamp = sensorhub->last_batch_timestamp[sensor_id]; + else + sensorhub->newest_sensor_event[sensor_id] = sample->timestamp; +} + /** - * cros_ec_sensor_ring_process_event() - process one EC FIFO event + * cros_ec_sensor_ring_process_event() - Process one EC FIFO event * * @sensorhub: Sensor Hub object. * @fifo_info: FIFO information from the EC (includes b point, EC timebase). @@ -141,28 +392,54 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, (MOTIONSENSE_SENSOR_FLAG_ODR | MOTIONSENSE_SENSOR_FLAG_FLUSH); if (in->flags & MOTIONSENSE_SENSOR_FLAG_TIMESTAMP && !async_flags) { - s64 new_timestamp; + s64 a = in->timestamp; + s64 b = fifo_info->info.timestamp; + s64 c = fifo_timestamp; + + cros_ec_sensor_ring_fix_overflow(&a, 1LL << 32, + &sensorhub->overflow_a); + cros_ec_sensor_ring_fix_overflow(&b, 1LL << 32, + &sensorhub->overflow_b); + + if (sensorhub->tight_timestamps) { + cros_ec_sensor_ring_ts_filter_update( + &sensorhub->filter, b, c); + *current_timestamp = cros_ec_sensor_ring_ts_filter( + &sensorhub->filter, a); + } else { + s64 new_timestamp; - /* - * Disable filtering since we might add more jitter - * if b is in a random point in time. - */ - new_timestamp = fifo_timestamp - - fifo_info->info.timestamp * 1000 + - in->timestamp * 1000; + /* + * Disable filtering since we might add more jitter + * if b is in a random point in time. + */ + new_timestamp = fifo_timestamp - + fifo_info->info.timestamp * 1000 + + in->timestamp * 1000; + /* + * The timestamp can be stale if we had to use the fifo + * info timestamp. + */ + if (new_timestamp - *current_timestamp > 0) + *current_timestamp = new_timestamp; + } + } + if (in->flags & MOTIONSENSE_SENSOR_FLAG_ODR) { + sensorhub->last_batch_len[in->sensor_num] = + sensorhub->penultimate_batch_len[in->sensor_num] = 0; /* - * The timestamp can be stale if we had to use the fifo - * info timestamp. + * ODR change is only useful for the sensor_ring, it does not + * convey information to clients. */ - if (new_timestamp - *current_timestamp > 0) - *current_timestamp = new_timestamp; + return false; } if (in->flags & MOTIONSENSE_SENSOR_FLAG_FLUSH) { out->sensor_id = in->sensor_num; out->timestamp = *current_timestamp; out->flag = in->flags; + sensorhub->last_batch_len[out->sensor_id] = 0; /* * No other payload information provided with * flush ack. @@ -176,22 +453,220 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, /* Regular sample */ out->sensor_id = in->sensor_num; - if (*current_timestamp - now > 0) - /* If the timestamp is in the future. */ + if (*current_timestamp - now > 0) { + /* + * This fix is needed to overcome the timestamp filter putting + * events in the future. + */ + sensorhub->future_timestamp_total_ns += + *current_timestamp - now; + if (++sensorhub->future_timestamp_count == + FUTURE_TS_ANALYTICS_COUNT_MAX) { + s64 avg = div_s64(sensorhub->future_timestamp_total_ns, + sensorhub->future_timestamp_count); + dev_warn_ratelimited(sensorhub->dev, + "100 timestamps in the future, %lldns shaved on average\n", + avg); + sensorhub->future_timestamp_count = 0; + sensorhub->future_timestamp_total_ns = 0; + } out->timestamp = now; - else + } else { out->timestamp = *current_timestamp; + } out->flag = in->flags; for (axis = 0; axis < 3; axis++) out->vector[axis] = in->data[axis]; + if (sensorhub->tight_timestamps) + cros_ec_sensor_ring_check_for_past_timestamp(sensorhub, out); return true; } /* * cros_ec_sensor_ring_spread_add: Calculate proper timestamps then add to - * ringbuffer. + * ringbuffer. + * + * This is the new spreading code, assumes every sample's timestamp + * preceeds the sample. Run if tight_timestamps == true. + * + * Sometimes the EC receives only one interrupt (hence timestamp) for + * a batch of samples. Only the first sample will have the correct + * timestamp. So we must interpolate the other samples. + * We use the previous batch timestamp and our current batch timestamp + * as a way to calculate period, then spread the samples evenly. + * + * s0 int, 0ms + * s1 int, 10ms + * s2 int, 20ms + * 30ms point goes by, no interrupt, previous one is still asserted + * downloading s2 and s3 + * s3 sample, 20ms (incorrect timestamp) + * s4 int, 40ms + * + * The batches are [(s0), (s1), (s2, s3), (s4)]. Since the 3rd batch + * has 2 samples in them, we adjust the timestamp of s3. + * s2 - s1 = 10ms, so s3 must be s2 + 10ms => 20ms. If s1 would have + * been part of a bigger batch things would have gotten a little + * more complicated. + * + * Note: we also assume another sensor sample doesn't break up a batch + * in 2 or more partitions. Example, there can't ever be a sync sensor + * in between S2 and S3. This simplifies the following code. + */ +static void +cros_ec_sensor_ring_spread_add(struct cros_ec_sensorhub *sensorhub, + unsigned long sensor_mask, + struct cros_ec_sensors_ring_sample *last_out) +{ + struct cros_ec_sensors_ring_sample *batch_start, *next_batch_start; + int id; + + for_each_set_bit(id, &sensor_mask, BITS_PER_LONG) { + for (batch_start = sensorhub->ring; batch_start < last_out; + batch_start = next_batch_start) { + /* + * For each batch (where all samples have the same + * timestamp). + */ + int batch_len, sample_idx; + struct cros_ec_sensors_ring_sample *batch_end = + batch_start; + struct cros_ec_sensors_ring_sample *s; + s64 batch_timestamp = batch_start->timestamp; + s64 sample_period; + + /* + * Skip over batches that start with the sensor types + * we're not looking at right now. + */ + if (batch_start->sensor_id != id) { + next_batch_start = batch_start + 1; + continue; + } + + /* + * Do not start a batch + * from a flush, as it happens asynchronously to the + * regular flow of events. + */ + if (batch_start->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH) { + cros_sensorhub_send_sample(sensorhub, + batch_start); + next_batch_start = batch_start + 1; + continue; + } + + if (batch_start->timestamp <= + sensorhub->last_batch_timestamp[id]) { + batch_timestamp = + sensorhub->last_batch_timestamp[id]; + batch_len = sensorhub->last_batch_len[id]; + + sample_idx = batch_len; + + sensorhub->last_batch_timestamp[id] = + sensorhub->penultimate_batch_timestamp[id]; + sensorhub->last_batch_len[id] = + sensorhub->penultimate_batch_len[id]; + } else { + /* + * Push first sample in the batch to the, + * kifo, it's guaranteed to be correct, the + * rest will follow later on. + */ + sample_idx = 1; + batch_len = 1; + cros_sensorhub_send_sample(sensorhub, + batch_start); + batch_start++; + } + + /* Find all samples have the same timestamp. */ + for (s = batch_start; s < last_out; s++) { + if (s->sensor_id != id) + /* + * Skip over other sensor types that + * are interleaved, don't count them. + */ + continue; + if (s->timestamp != batch_timestamp) + /* we discovered the next batch */ + break; + if (s->flag & MOTIONSENSE_SENSOR_FLAG_FLUSH) + /* break on flush packets */ + break; + batch_end = s; + batch_len++; + } + + if (batch_len == 1) + goto done_with_this_batch; + + /* Can we calculate period? */ + if (sensorhub->last_batch_len[id] == 0) { + dev_warn(sensorhub->dev, "Sensor %d: lost %d samples when spreading\n", + id, batch_len - 1); + goto done_with_this_batch; + /* + * Note: we're dropping the rest of the samples + * in this batch since we have no idea where + * they're supposed to go without a period + * calculation. + */ + } + + sample_period = div_s64(batch_timestamp - + sensorhub->last_batch_timestamp[id], + sensorhub->last_batch_len[id]); + dev_dbg(sensorhub->dev, + "Adjusting %d samples, sensor %d last_batch @%lld (%d samples) batch_timestamp=%lld => period=%lld\n", + batch_len, id, + sensorhub->last_batch_timestamp[id], + sensorhub->last_batch_len[id], + batch_timestamp, + sample_period); + + /* + * Adjust timestamps of the samples then push them to + * kfifo. + */ + for (s = batch_start; s <= batch_end; s++) { + if (s->sensor_id != id) + /* + * Skip over other sensor types that + * are interleaved, don't change them. + */ + continue; + + s->timestamp = batch_timestamp + + sample_period * sample_idx; + sample_idx++; + + cros_sensorhub_send_sample(sensorhub, s); + } + +done_with_this_batch: + sensorhub->penultimate_batch_timestamp[id] = + sensorhub->last_batch_timestamp[id]; + sensorhub->penultimate_batch_len[id] = + sensorhub->last_batch_len[id]; + + sensorhub->last_batch_timestamp[id] = batch_timestamp; + sensorhub->last_batch_len[id] = batch_len; + + next_batch_start = batch_end + 1; + } + } +} + +/* + * cros_ec_sensor_ring_spread_add_legacy: Calculate proper timestamps then + * add to ringbuffer (legacy). + * + * Note: This assumes we're running old firmware, where every sample's timestamp + * is after the sample. Run if tight_timestamps == false. * * If there is a sample with a proper timestamp * @@ -214,11 +689,12 @@ cros_ec_sensor_ring_process_event(struct cros_ec_sensorhub *sensorhub, * * We know have [TS1+1/3, TS1+2/3, current timestamp] */ -static void cros_ec_sensor_ring_spread_add(struct cros_ec_sensorhub *sensorhub, - unsigned long sensor_mask, - s64 current_timestamp, - struct cros_ec_sensors_ring_sample - *last_out) +static void +cros_ec_sensor_ring_spread_add_legacy(struct cros_ec_sensorhub *sensorhub, + unsigned long sensor_mask, + s64 current_timestamp, + struct cros_ec_sensors_ring_sample + *last_out) { struct cros_ec_sensors_ring_sample *out; int i; @@ -400,7 +876,8 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) * is slow to respond to the IRQ, the EC may have added new samples. * Use the FIFO info timestamp as last timestamp then. */ - if ((last_out - 1)->timestamp == current_timestamp) + if (!sensorhub->tight_timestamps && + (last_out - 1)->timestamp == current_timestamp) current_timestamp = fifo_timestamp; /* Warn on lost samples. */ @@ -414,6 +891,7 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) dev_warn_ratelimited(sensorhub->dev, "Sensor %d: lost: %d out of %d\n", i, lost, total_lost); + sensorhub->last_batch_len[i] = 0; } } } @@ -422,8 +900,13 @@ static void cros_ec_sensorhub_ring_handler(struct cros_ec_sensorhub *sensorhub) * Spread samples in case of batching, then add them to the * ringbuffer. */ - cros_ec_sensor_ring_spread_add(sensorhub, sensor_mask, - current_timestamp, last_out); + if (sensorhub->tight_timestamps) + cros_ec_sensor_ring_spread_add(sensorhub, sensor_mask, + last_out); + else + cros_ec_sensor_ring_spread_add_legacy(sensorhub, sensor_mask, + current_timestamp, + last_out); ring_handler_end: sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = current_timestamp; @@ -500,6 +983,9 @@ int cros_ec_sensorhub_ring_add(struct cros_ec_sensorhub *sensorhub) sensorhub->fifo_timestamp[CROS_EC_SENSOR_LAST_TS] = cros_ec_get_time_ns(); + sensorhub->tight_timestamps = cros_ec_check_features( + ec, EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS); + /* Register the notifier that will act as a top half interrupt. */ sensorhub->notifier.notifier_call = cros_ec_sensorhub_event; ret = blocking_notifier_chain_register(&ec->ec_dev->event_notifier, diff --git a/include/linux/platform_data/cros_ec_sensorhub.h b/include/linux/platform_data/cros_ec_sensorhub.h index cb849a2da4f60..180b36adc3493 100644 --- a/include/linux/platform_data/cros_ec_sensorhub.h +++ b/include/linux/platform_data/cros_ec_sensorhub.h @@ -68,7 +68,44 @@ struct cros_ec_sensors_ring_sample { s64 timestamp; } __packed; +/* State used for cros_ec_ring_fix_overflow */ +struct cros_ec_sensors_ec_overflow_state { + s64 offset; + s64 last; +}; + +/* Length of the filter, how long to remember entries for */ +#define CROS_EC_SENSORHUB_TS_HISTORY_SIZE 64 + /** + * struct cros_ec_sensors_ts_filter_state - Timestamp filetr state. + * + * @x_offset: x is EC interrupt time. x_offset its last value. + * @y_offset: y is the difference between AP and EC time, y_offset its last + * value. + * @x_history: The past history of x, relative to x_offset. + * @y_history: The past history of y, relative to y_offset. + * @m_history: rate between y and x. + * @history_len: Amount of valid historic data in the arrays. + * @temp_buf: Temporary buffer used when updating the filter. + * @median_m: median value of m_history + * @median_error: final error to apply to AP interrupt timestamp to get the + * "true timestamp" the event occurred. + */ +struct cros_ec_sensors_ts_filter_state { + s64 x_offset, y_offset; + s64 x_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE]; + s64 y_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE]; + s64 m_history[CROS_EC_SENSORHUB_TS_HISTORY_SIZE]; + int history_len; + + s64 temp_buf[CROS_EC_SENSORHUB_TS_HISTORY_SIZE]; + + s64 median_m; + s64 median_error; +}; + +/* * struct cros_ec_sensorhub - Sensor Hub device data. * * @dev: Device object, mostly used for logging. @@ -79,10 +116,32 @@ struct cros_ec_sensors_ring_sample { * @cmd_lock : Lock for sending msg. * @notifier: Notifier to kick the FIFO interrupt. * @ring: Preprocessed ring to store events. - * @fifo_timestamp: array for event timestamp and spreading. - * @fifo_info: copy of FIFO information coming from the EC. - * @fifo_size: size of the ring. - * @push_data: array of callback to send datums to iio sensor object. + * @fifo_timestamp: Array for event timestamp and spreading. + * @fifo_info: Copy of FIFO information coming from the EC. + * @fifo_size: Size of the ring. + * @penultimate_batch_timestamp: Array of last but one batch timestamps. + * Used for timestamp spreading calculations + * when a batch shows up. + * @penultimate_batch_len: Array of last but one batch length. + * @last_batch_timestamp: Last batch timestamp array. + * @last_batch_len: Last batch length array. + * @newest_sensor_event: Last sensor timestamp. + * @overflow_a: For handling timestamp overflow for a time (sensor events) + * @overflow_b: For handling timestamp overflow for b time (ec interrupts) + * @filter: Medium fileter structure. + * @tight_timestamps: Set to truen when EC support tight timestamping: + * The timestamps reported from the EC have low jitter. + * Timestamps also come before every sample. Set either + * by feature bits coming from the EC or userspace. + * @future_timestamp_count: Statistics used to compute shaved time. + * This occurs when timestamp interpolation from EC + * time to AP time accidentally puts timestamps in + * the future. These timestamps are clamped to + * `now` and these count/total_ns maintain the + * statistics for how much time was removed in a + * given period. + * @future_timestamp_total_ns: Total amount of time shaved. + * @push_data: Array of callback to send datums to iio sensor object. */ struct cros_ec_sensorhub { struct device *dev; @@ -101,6 +160,22 @@ struct cros_ec_sensorhub { struct cros_ec_fifo_info fifo_info; int fifo_size; + s64 penultimate_batch_timestamp[CROS_EC_SENSOR_MAX]; + int penultimate_batch_len[CROS_EC_SENSOR_MAX]; + s64 last_batch_timestamp[CROS_EC_SENSOR_MAX]; + int last_batch_len[CROS_EC_SENSOR_MAX]; + s64 newest_sensor_event[CROS_EC_SENSOR_MAX]; + + struct cros_ec_sensors_ec_overflow_state overflow_a; + struct cros_ec_sensors_ec_overflow_state overflow_b; + + struct cros_ec_sensors_ts_filter_state filter; + + int tight_timestamps; + + s32 future_timestamp_count; + s64 future_timestamp_total_ns; + struct cros_ec_sensorhub_sensor_push_data push_data[CROS_EC_SENSOR_PDEV_MAX]; }; From patchwork Tue Mar 24 20:27:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456415 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C4B4C913 for ; Tue, 24 Mar 2020 20:27:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5CCC320714 for ; Tue, 24 Mar 2020 20:27:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ijO5I9xY" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727040AbgCXU1z (ORCPT ); Tue, 24 Mar 2020 16:27:55 -0400 Received: from mail-pj1-f68.google.com ([209.85.216.68]:51040 "EHLO mail-pj1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727937AbgCXU1x (ORCPT ); Tue, 24 Mar 2020 16:27:53 -0400 Received: by mail-pj1-f68.google.com with SMTP id v13so45237pjb.0 for ; Tue, 24 Mar 2020 13:27:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZpnS/j1XfTEAxa697JfCqGh5bEfIShtd5fhuG2l93l8=; b=ijO5I9xYJrPv9CaECBq+rp2MoCRZ6HJH87CVQD9pH86IYXdVtpQivHTYyHrnoLld/3 TKUEe9UuDwZ1fVvAIu4nZXlGJu2l/Z/tiJl00A6VBgPDugHEeqPvtzvGKsCBwxK4ATP+ RpHN9MYEcmMQDWAXLKJ3WrJDVJFOy932tV8GA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZpnS/j1XfTEAxa697JfCqGh5bEfIShtd5fhuG2l93l8=; b=uI/c2b9G16Ei1L2notHXZcLHiSiovXUmIWVvUmLMC7bqwAhxKlwy7TKHTpMoNNvc5Q A5RCGHvv67m0LhgOs8LbqO1oQNUmk3GpkuH/TTpgC1Hcx6wcjrzjvjXU9V1eJiBTY95t dUYMpACo0UEqjzXAu1uPdmiR7qOEcQjwgh238m84ZR7SRxueG6H2+3cE36bg+w6iOgUV ObqAZsxk0u4lKT7iC2hKcMrBSZMyFp9JdGhA5A/kPEUdAmYPk3DIhuiKn6Y5p+m5311f lzelGygBAJ4+u6v/3F77PEMazkDKFKYuXib3YrCbkxCqifmIJlT1DrqKC3ZCkp1Bdaeh E46g== X-Gm-Message-State: ANhLgQ2EMt6GgNMlw0Xv62bqCNu5KrMezn2n9acYwzM41qqGPVm4eUsL n3uKFCwoMTT1ijt/xK4n43+UGA== X-Google-Smtp-Source: ADFU+vteWSjntoj8aZ+Nx0AIgMc07uFZI7ZIcP0H9/Q7LWpXp1fHUENvhsVnOSCkEv+TAQt64R8dYg== X-Received: by 2002:a17:90a:a102:: with SMTP id s2mr7671363pjp.44.1585081671127; Tue, 24 Mar 2020 13:27:51 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id j19sm16613872pfe.102.2020.03.24.13.27.50 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:50 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 04/11] iio: cros_ec: Move function description to .c file Date: Tue, 24 Mar 2020 13:27:29 -0700 Message-Id: <20200324202736.243314-5-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org To prevent comment rot, move function description to cros_ec_sensors_core.c. Acked-by: Jonathan Cameron Acked-by: Enric Balletbo i Serra Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: Added ack. No changes in v4. Changes in v3: fix spelling. New in v2. .../cros_ec_sensors/cros_ec_sensors_core.c | 69 ++++++++++++++++ .../linux/iio/common/cros_ec_sensors_core.h | 80 ------------------- 2 files changed, 69 insertions(+), 80 deletions(-) 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 d3a3626c7cd83..f3c000448b90e 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 @@ -82,6 +82,14 @@ static void get_default_min_max_freq(enum motionsensor_type type, } } +/** + * cros_ec_sensors_core_init() - basic initialization of the core structure + * @pdev: platform device created for the sensors + * @indio_dev: iio device structure of the device + * @physical_device: true if the device refers to a physical device + * + * Return: 0 on success, -errno on failure. + */ int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device) @@ -159,6 +167,16 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_init); +/** + * cros_ec_motion_send_host_cmd() - send motion sense host command + * @state: pointer to state information for device + * @opt_length: optional length to reduce the response size, useful on the data + * path. Otherwise, the maximal allowed response size is used + * + * When called, the sub-command is assumed to be set in param->cmd. + * + * Return: 0 on success, -errno on failure. + */ int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state, u16 opt_length) { @@ -421,6 +439,14 @@ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, } EXPORT_SYMBOL_GPL(cros_ec_sensors_read_lpc); +/** + * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol + * @indio_dev: pointer to IIO device + * @scan_mask: bitmap of the sensor indices to scan + * @data: location to store data + * + * Return: 0 on success, -errno on failure. + */ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data) { @@ -445,6 +471,18 @@ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, } EXPORT_SYMBOL_GPL(cros_ec_sensors_read_cmd); +/** + * cros_ec_sensors_capture() - the trigger handler function + * @irq: the interrupt number. + * @p: a pointer to the poll function. + * + * On a trigger event occurring, if the pollfunc is attached then this + * handler is called as a threaded interrupt (and hence may sleep). It + * is responsible for grabbing data from the device and pushing it into + * the associated buffer. + * + * Return: IRQ_HANDLED + */ irqreturn_t cros_ec_sensors_capture(int irq, void *p) { struct iio_poll_func *pf = p; @@ -480,6 +518,16 @@ irqreturn_t cros_ec_sensors_capture(int irq, void *p) } EXPORT_SYMBOL_GPL(cros_ec_sensors_capture); +/** + * cros_ec_sensors_core_read() - function to request a value from the sensor + * @st: pointer to state information for device + * @chan: channel specification structure table + * @val: will contain one element making up the returned value + * @val2: will contain another element making up the returned value + * @mask: specifies which values to be requested + * + * Return: the type of value returned by the device + */ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -520,6 +568,17 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read); +/** + * cros_ec_sensors_core_read_avail() - get available values + * @indio_dev: pointer to state information for device + * @chan: channel specification structure table + * @vals: list of available values + * @type: type of data returned + * @length: number of data returned in the array + * @mask: specifies which values to be requested + * + * Return: an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST + */ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, @@ -541,6 +600,16 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail); +/** + * cros_ec_sensors_core_write() - function to write a value to the sensor + * @st: pointer to state information for device + * @chan: channel specification structure table + * @val: first part of value to write + * @val2: second part of value to write + * @mask: specifies which values to write + * + * Return: the type of value returned by the device + */ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask) diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index bb331e6356a9c..0af918978f975 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -79,95 +79,25 @@ struct cros_ec_sensors_core_state { int frequencies[3]; }; -/** - * cros_ec_sensors_read_lpc() - retrieve data from EC shared memory - * @indio_dev: pointer to IIO device - * @scan_mask: bitmap of the sensor indices to scan - * @data: location to store data - * - * This is the safe function for reading the EC data. It guarantees that the - * data sampled was not modified by the EC while being read. - * - * Return: 0 on success, -errno on failure. - */ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data); -/** - * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol - * @indio_dev: pointer to IIO device - * @scan_mask: bitmap of the sensor indices to scan - * @data: location to store data - * - * Return: 0 on success, -errno on failure. - */ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data); struct platform_device; -/** - * cros_ec_sensors_core_init() - basic initialization of the core structure - * @pdev: platform device created for the sensors - * @indio_dev: iio device structure of the device - * @physical_device: true if the device refers to a physical device - * - * Return: 0 on success, -errno on failure. - */ int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device); -/** - * cros_ec_sensors_capture() - the trigger handler function - * @irq: the interrupt number. - * @p: a pointer to the poll function. - * - * On a trigger event occurring, if the pollfunc is attached then this - * handler is called as a threaded interrupt (and hence may sleep). It - * is responsible for grabbing data from the device and pushing it into - * the associated buffer. - * - * Return: IRQ_HANDLED - */ irqreturn_t cros_ec_sensors_capture(int irq, void *p); -/** - * cros_ec_motion_send_host_cmd() - send motion sense host command - * @st: pointer to state information for device - * @opt_length: optional length to reduce the response size, useful on the data - * path. Otherwise, the maximal allowed response size is used - * - * When called, the sub-command is assumed to be set in param->cmd. - * - * Return: 0 on success, -errno on failure. - */ int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *st, u16 opt_length); -/** - * cros_ec_sensors_core_read() - function to request a value from the sensor - * @st: pointer to state information for device - * @chan: channel specification structure table - * @val: will contain one element making up the returned value - * @val2: will contain another element making up the returned value - * @mask: specifies which values to be requested - * - * Return: the type of value returned by the device - */ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int *val, int *val2, long mask); -/** - * cros_ec_sensors_core_read_avail() - get available values - * @indio_dev: pointer to state information for device - * @chan: channel specification structure table - * @vals: list of available values - * @type: type of data returned - * @length: number of data returned in the array - * @mask: specifies which values to be requested - * - * Return: an error code, IIO_AVAIL_RANGE or IIO_AVAIL_LIST - */ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, @@ -175,16 +105,6 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, int *length, long mask); -/** - * cros_ec_sensors_core_write() - function to write a value to the sensor - * @st: pointer to state information for device - * @chan: channel specification structure table - * @val: first part of value to write - * @val2: second part of value to write - * @mask: specifies which values to write - * - * Return: the type of value returned by the device - */ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask); From patchwork Tue Mar 24 20:27:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456431 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 19E1D913 for ; Tue, 24 Mar 2020 20:28:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F0C7420788 for ; Tue, 24 Mar 2020 20:28:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="EEj5rKgf" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727160AbgCXU2X (ORCPT ); Tue, 24 Mar 2020 16:28:23 -0400 Received: from mail-pg1-f196.google.com ([209.85.215.196]:36670 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727907AbgCXU1x (ORCPT ); Tue, 24 Mar 2020 16:27:53 -0400 Received: by mail-pg1-f196.google.com with SMTP id j29so22063pgl.3 for ; Tue, 24 Mar 2020 13:27:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZigHEZ9wEtW9T2r5IUfNO5JfwDcLltP6YCkvQNLzMZg=; b=EEj5rKgfO0GiydsW11KRCtfxlT6VWJWdckQbFJAHocKf9zxE4sh7bI+ssRJReWY5z+ NxlCQ7c95xJJJHBpzr4JznrxpF1Ugd+4ZaUHlfueHs3/NwQBCrXZ6lWOrabQWVYc+cB3 NxO81PWs+9IL3pXbOF6sghze+pvWw45GjQCIE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZigHEZ9wEtW9T2r5IUfNO5JfwDcLltP6YCkvQNLzMZg=; b=mVDJycaRO1FtW//3zyId3boVNbp6ZPhLm3PezlNeygvKNCCfALZC0czVNfeS1v82nz 8bunlBh3XDMCypHAqNxGZWZ4QC7ZjcBLv6xfK3R9qbdxmqZvoQmUL4zbQNtnt6MnI3Eo EYCGKXd8bhPzgDk/wVi19iPd5wE6oTKfjUKjZrbFbZP/sKgbweA7t8JAdzpQeItGIpzo iU4W2PYEogqCZyzm/pI0b4ExbxD26vX5Kw2ttBFDbGFaSeNRaCLWjkbqM7jyI3nRsyFu 1WllrGxrycPOrFno+neCSF2dryviWe/iySvMJMMelivfZZSyK1buB57f5b9CGzWU1JZz l4ig== X-Gm-Message-State: ANhLgQ1PEuq+TIc3eydaOZZmksAbTCyZvq+pGGqHVp/af9O//FDP6PWF 8V5JbET2rz8cwHdVMgglRPENpQ== X-Google-Smtp-Source: ADFU+vtrlDmTwEE9oYXJAOdQ/zBHf+vMnBKpgHdCBI82QuEAs/PG/g2Tsj9vSxggT8MDEeA66ZFpyQ== X-Received: by 2002:a63:4f0c:: with SMTP id d12mr26233420pgb.199.1585081672376; Tue, 24 Mar 2020 13:27:52 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id o33sm2993992pje.19.2020.03.24.13.27.51 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:51 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 05/11] iio: expose iio_device_set_clock Date: Tue, 24 Mar 2020 13:27:30 -0700 Message-Id: <20200324202736.243314-6-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Some IIO devices may want to override the default (realtime) to another clock source by default. It can beneficial when timestamps coming from the hardware or underlying drivers are already in that format. It can always be overridden by attribute current_timestamp_clock. Reviewed-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: - New in v5. drivers/iio/industrialio-core.c | 8 +++++++- include/linux/iio/iio.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 65ff0d0670188..26e963483bab0 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -189,7 +189,12 @@ ssize_t iio_read_const_attr(struct device *dev, } EXPORT_SYMBOL(iio_read_const_attr); -static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) +/** + * iio_device_set_clock() - Set current timestamping clock for the device + * @indio_dev: IIO device structure containing the device + * @clock_id: timestamping clock posix identifier to set. + */ +int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) { int ret; const struct iio_event_interface *ev_int = indio_dev->event_interface; @@ -207,6 +212,7 @@ static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id) return 0; } +EXPORT_SYMBOL(iio_device_set_clock); /** * iio_get_time_ns() - utility function to get a time stamp for events etc diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 862ce0019eba5..b18f34a8901f3 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -627,6 +627,8 @@ static inline clockid_t iio_device_get_clock(const struct iio_dev *indio_dev) return indio_dev->clock_id; } +int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id); + /** * dev_to_iio_dev() - Get IIO device struct from a device struct * @dev: The device embedded in the IIO device From patchwork Tue Mar 24 20:27:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456425 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 204A513A4 for ; Tue, 24 Mar 2020 20:28:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E56E72074D for ; Tue, 24 Mar 2020 20:28:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="n0ss82B2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728066AbgCXU14 (ORCPT ); Tue, 24 Mar 2020 16:27:56 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:41846 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727513AbgCXU1z (ORCPT ); Tue, 24 Mar 2020 16:27:55 -0400 Received: by mail-pf1-f196.google.com with SMTP id z65so9894721pfz.8 for ; Tue, 24 Mar 2020 13:27:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Wk1E5NST0hP0snf8CIvKzpAWiRfamSLnbLwOE0ZpuJ8=; b=n0ss82B2aZDbDi9wyAzWCCxa9fYKUh6ivd2p9DsSxRalwBVJaH0hQ2aZUUoNbiWGo0 kXp0DAIl8E0gqAQbJy+Z63MYkwq9cKsRkIbEIFWtmSO9IcCxsDs4Hstr7huV4J6EQetO aU72aYisy/+RIVJ+nVGzpgqxXfQqNTOfH+cqA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Wk1E5NST0hP0snf8CIvKzpAWiRfamSLnbLwOE0ZpuJ8=; b=j1+fyr+xQvaIl8p6r7QZMYhCPPZBpsdmmMKZWEulXKnpD4El1JTyRhZeLxqJY9dGxo JpkfKlkv1QWFo2/ZwN86HSnj7dKOME2Ok+Bgnu4738JcxOooG0vha37picU8XXop7dK7 mnw4TRaDfzAPQUpWLxsdPSYQtfZ5vqsSrWupFKSfo4+1DYu0c6WuV8oUyd5JdxlcUk99 8GBOjEBOk0zaItE3uQYB4FZvajpAkyxwFG81Y2phwbwCJDqHHmoPWYCtSCtCgHebOg5A /pubBvkgHdQ3G0GBCfmMuU5cFGEgAGmF8mdvPaxfaUqM51QwcYcymmGBlPibhII4kdMN r2/w== X-Gm-Message-State: ANhLgQ2AmUxn82OBjKMOm3zJsZDQAfhKKNFQGnkkKIr/V6ZZEReFW8JK iM4LgkkUTkhBekwqnSI2dNgrSA== X-Google-Smtp-Source: ADFU+vtCGSBfZrxRiioO/CYimNmrIYMrHFVgxk72ONRL+x9Leh9KHD5rND+CszLYomDNjzpV3fcCHQ== X-Received: by 2002:a62:834c:: with SMTP id h73mr2259096pfe.59.1585081673799; Tue, 24 Mar 2020 13:27:53 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id i4sm15412462pgo.23.2020.03.24.13.27.53 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:53 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 06/11] iio: cros_ec: Register to cros_ec_sensorhub when EC supports FIFO Date: Tue, 24 Mar 2020 13:27:31 -0700 Message-Id: <20200324202736.243314-7-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org When EC supports FIFO, each IIO device registers a callback, to put samples in the buffer when they arrives from the FIFO. When no FIFO, the user space app needs to call trigger_new, or better register a high precision timer. Reviewed-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - Revert code from v2 that allow trigger in FIFO mode. It was causing a crash when events would flow from hardware FIFO in but no triggers were setup. Creating a triggered buffers and a hardware interrupt trigger from the sensorhub and having to connect the trigger to sensor before use was not practical. Changes in v5: - Revert modes setting that were removed by mistake - Remove unnecessary check when receving events from callback - Set clock_id to boottime by default, as it is what sensorhub_ring is using. - Update commit messages reference to time domain: trigger and hub generated events are always in the same time domain. Changes in v4: - Fix a logic error when the sensor is not "physical", for instance lig angle: core_init() would return !0 even if there was no error. - Check patch with --strict option Use sizeof(*obj) instead of sizeof(struct ...obj) Alignement Change in v3: - Remove double line - Fix indentation - Add code to support iio clock_id setting. Optimized for CLOCK_BOOTTIME. Change in v2 from "Use triggered buffer only when EC does not support FIFO": - Keep trigger all the time. - Add devm_add_action to cleanup callback registration. - EC that "reports" legacy sensors do not have FIFO. - Use iiio_is_buffer_enabled instead of checking the scan_mask before sending samples to buffer. - Add empty lines for visibility. drivers/iio/accel/cros_ec_accel_legacy.c | 8 +- .../cros_ec_sensors/cros_ec_lid_angle.c | 2 +- .../common/cros_ec_sensors/cros_ec_sensors.c | 9 +- .../cros_ec_sensors/cros_ec_sensors_core.c | 101 +++++++++++++++++- drivers/iio/light/cros_ec_light_prox.c | 9 +- drivers/iio/pressure/cros_ec_baro.c | 9 +- .../linux/iio/common/cros_ec_sensors_core.h | 10 +- 7 files changed, 119 insertions(+), 29 deletions(-) diff --git a/drivers/iio/accel/cros_ec_accel_legacy.c b/drivers/iio/accel/cros_ec_accel_legacy.c index 68e847c6255e3..2532b9ad33842 100644 --- a/drivers/iio/accel/cros_ec_accel_legacy.c +++ b/drivers/iio/accel/cros_ec_accel_legacy.c @@ -170,7 +170,8 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + ret = cros_ec_sensors_core_init(pdev, indio_dev, true, + cros_ec_sensors_capture, NULL); if (ret) return ret; @@ -190,11 +191,6 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) state->sign[CROS_EC_SENSOR_Z] = -1; } - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_sensors_capture, NULL); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 1dcc2a16ab2dd..e30a59fcf0f95 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -97,7 +97,7 @@ static int cros_ec_lid_angle_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, false); + ret = cros_ec_sensors_core_init(pdev, indio_dev, false, NULL, NULL); if (ret) return ret; diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 576e45faafaff..711134d67ddee 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -230,7 +230,9 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + ret = cros_ec_sensors_core_init(pdev, indio_dev, true, + cros_ec_sensors_capture, + cros_ec_sensors_push_data); if (ret) return ret; @@ -292,11 +294,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) else state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_sensors_capture, NULL); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } 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 f3c000448b90e..01513cb933653 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 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -82,17 +83,71 @@ static void get_default_min_max_freq(enum motionsensor_type type, } } +int cros_ec_sensors_push_data(struct iio_dev *indio_dev, + s16 *data, + s64 timestamp) +{ + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + s16 *out; + s64 delta; + unsigned int i; + + /* + * Ignore samples if the buffer is not set: it is needed if the ODR is + * set but the buffer is not enabled yet. + */ + if (!iio_buffer_enabled(indio_dev)) + return 0; + + out = (s16 *)st->samples; + for_each_set_bit(i, + indio_dev->active_scan_mask, + indio_dev->masklength) { + *out = data[i]; + out++; + } + + if (iio_device_get_clock(indio_dev) != CLOCK_BOOTTIME) + delta = iio_get_time_ns(indio_dev) - cros_ec_get_time_ns(); + else + delta = 0; + + iio_push_to_buffers_with_timestamp(indio_dev, st->samples, + timestamp + delta); + + return 0; +} +EXPORT_SYMBOL_GPL(cros_ec_sensors_push_data); + +static void cros_ec_sensors_core_clean(void *arg) +{ + struct platform_device *pdev = (struct platform_device *)arg; + struct cros_ec_sensorhub *sensor_hub = + dev_get_drvdata(pdev->dev.parent); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + u8 sensor_num = st->param.info.sensor_num; + + cros_ec_sensorhub_unregister_push_data(sensor_hub, sensor_num); +} + /** * cros_ec_sensors_core_init() - basic initialization of the core structure * @pdev: platform device created for the sensors * @indio_dev: iio device structure of the device * @physical_device: true if the device refers to a physical device + * @trigger_capture: function pointer to call buffer is triggered, + * for backward compatibility. + * @push_data: function to call when cros_ec_sensorhub receives + * a sample for that sensor. * * Return: 0 on success, -errno on failure. */ int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, - bool physical_device) + bool physical_device, + cros_ec_sensors_capture_t trigger_capture, + cros_ec_sensorhub_push_data_cb_t push_data) { struct device *dev = &pdev->dev; struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); @@ -131,8 +186,6 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, indio_dev->name = pdev->name; if (physical_device) { - indio_dev->modes = INDIO_DIRECT_MODE; - state->param.cmd = MOTIONSENSE_CMD_INFO; state->param.info.sensor_num = sensor_platform->sensor_num; ret = cros_ec_motion_send_host_cmd(state, 0); @@ -161,6 +214,48 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, state->frequencies[2] = state->resp->info_3.max_frequency; } + + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { + /* + * Create a software buffer, feed by the EC FIFO. + * We can not use trigger here, as events are generated + * as soon as sample_frequency is set. + */ + struct iio_buffer *buffer; + + buffer = devm_iio_kfifo_allocate(dev); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->modes = INDIO_BUFFER_SOFTWARE; + + ret = cros_ec_sensorhub_register_push_data( + sensor_hub, sensor_platform->sensor_num, + indio_dev, push_data); + if (ret) + return ret; + + ret = devm_add_action_or_reset( + dev, cros_ec_sensors_core_clean, pdev); + if (ret) + return ret; + + /* Timestamp coming from FIFO are in ns since boot. */ + ret = iio_device_set_clock(indio_dev, CLOCK_BOOTTIME); + if (ret) + return ret; + } else { + /* + * The only way to get samples in buffer is to set a + * software tigger (systrig, hrtimer). + */ + ret = devm_iio_triggered_buffer_setup( + dev, indio_dev, NULL, trigger_capture, + NULL); + if (ret) + return ret; + } } return 0; diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 7a838e2956f40..03c951ff4a3c3 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -177,7 +177,9 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + ret = cros_ec_sensors_core_init(pdev, indio_dev, true, + cros_ec_sensors_capture, + cros_ec_sensors_push_data); if (ret) return ret; @@ -236,11 +238,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_sensors_capture, NULL); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index b521bebd551c7..6add499f11aa6 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -134,7 +134,9 @@ static int cros_ec_baro_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + ret = cros_ec_sensors_core_init(pdev, indio_dev, true, + cros_ec_sensors_capture, + cros_ec_sensors_push_data); if (ret) return ret; @@ -182,11 +184,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev) state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_sensors_capture, NULL); - if (ret) - return ret; - return devm_iio_device_register(dev, indio_dev); } diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index 0af918978f975..b8f573ca9dcc9 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -12,6 +12,7 @@ #include #include #include +#include enum { CROS_EC_SENSOR_X, @@ -32,6 +33,8 @@ enum { /* Minimum sampling period to use when device is suspending */ #define CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY 1000 /* 1 second */ +typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); + /** * struct cros_ec_sensors_core_state - state data for EC sensors IIO driver * @ec: cros EC device structure @@ -87,9 +90,14 @@ int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask, struct platform_device; int cros_ec_sensors_core_init(struct platform_device *pdev, - struct iio_dev *indio_dev, bool physical_device); + struct iio_dev *indio_dev, bool physical_device, + cros_ec_sensors_capture_t trigger_capture, + cros_ec_sensorhub_push_data_cb_t push_data); irqreturn_t cros_ec_sensors_capture(int irq, void *p); +int cros_ec_sensors_push_data(struct iio_dev *indio_dev, + s16 *data, + s64 timestamp); int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *st, u16 opt_length); From patchwork Tue Mar 24 20:27:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456429 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 33E87913 for ; Tue, 24 Mar 2020 20:28:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0CA0F20788 for ; Tue, 24 Mar 2020 20:28:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="BGzv+v9R" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727061AbgCXU2W (ORCPT ); Tue, 24 Mar 2020 16:28:22 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:42923 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727160AbgCXU14 (ORCPT ); Tue, 24 Mar 2020 16:27:56 -0400 Received: by mail-pf1-f196.google.com with SMTP id 22so6305119pfa.9 for ; Tue, 24 Mar 2020 13:27:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=L6Xkkxw+OtI3K0TdNj5ZNvGMwMn26AVCkhCOCElY92g=; b=BGzv+v9RwoXv3iDU0onqRId2oBDvCiAVFMkNKUvSOLU4KPZZyCUxJRqK4FNSDCvigJ DEzBfCvciwpVhQKA+Bxoo7ZsBvdjrlVmDDq6gqBCpA+kNMiF2BM7wn0kIemh6axV/X1t XeKIM9VJL0aiSmln12rub/u7wV2DrwCkawTgk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=L6Xkkxw+OtI3K0TdNj5ZNvGMwMn26AVCkhCOCElY92g=; b=OAxlB4j2AnNBgHdiCKvWbTBtp5K9yywbc31vNQp3oM2E3qVcTZR40ahXgVPlIHEG+A gLP8SELWBAtxwuWXrQ1YbsTTndyIviZRUKwblvQzMhrtCxIaKcHvUgoiHjX00++OLeXt j/327c4q+sO81qFOjnYamxUN+SulXzbDupPGttzUSOuqLpBtfzA50tIkt67yXQheXibQ ONQGycSRU/YUvlXtMxXc4lmowJR9eHbPZs9JuiLcKCgeordcBRU2t9jd7h+UBoxkRHnw SMLA1zi9Jh4qQmZziEzp6arECWBZdDJj1Akfh62kaFXzdFaD4O3gyAYSfUcUDeo6TLgh M6Aw== X-Gm-Message-State: ANhLgQ0K53YpWQID5nEzkv9PIRIxlBMDtol3Q2hCC7dJVvk4wsoyTneo 3IK/SwWl3S2VHMJm805kl2uE6A== X-Google-Smtp-Source: ADFU+vtOaXB3ynSuhTM+7qF9JrKZUAehCGVNvqBn/Z8wHVXOvJSCx9omLD3zvqUirBJJVFK42UaloA== X-Received: by 2002:a63:144e:: with SMTP id 14mr29951381pgu.264.1585081675065; Tue, 24 Mar 2020 13:27:55 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id r70sm5378036pfr.116.2020.03.24.13.27.54 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:54 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou , Lee Jones Subject: [PATCH v6 07/11] iio: cros_ec: Remove pm function Date: Tue, 24 Mar 2020 13:27:32 -0700 Message-Id: <20200324202736.243314-8-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Since cros_ec_sensorhub is shutting down the FIFO when the device suspends, no need to slow down the EC sampling period rate. It was necesseary to do that before command CMD_FIFO_INT_ENABLE was introduced, but now all supported chromebooks have it. Acked-by: Jonathan Cameron Acked-by: Enric Balletbo i Serra Acked-by: Lee Jones Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: Added ack. No changes in v4, v3. New in v2. .../cros_ec_sensors/cros_ec_lid_angle.c | 1 - .../common/cros_ec_sensors/cros_ec_sensors.c | 1 - .../cros_ec_sensors/cros_ec_sensors_core.c | 47 ------------------- drivers/iio/light/cros_ec_light_prox.c | 1 - .../linux/iio/common/cros_ec_sensors_core.h | 5 -- 5 files changed, 55 deletions(-) diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index e30a59fcf0f95..af801e203623e 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -127,7 +127,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_lid_angle_ids); static struct platform_driver cros_ec_lid_angle_platform_driver = { .driver = { .name = DRV_NAME, - .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_lid_angle_probe, .id_table = cros_ec_lid_angle_ids, diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 711134d67ddee..fad21a90bc7e8 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -314,7 +314,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids); static struct platform_driver cros_ec_sensors_platform_driver = { .driver = { .name = "cros-ec-sensors", - .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_sensors_probe, .id_table = cros_ec_sensors_ids, 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 01513cb933653..a1ecbd55ea767 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 @@ -738,52 +738,5 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write); -static int __maybe_unused cros_ec_sensors_prepare(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); - - if (st->curr_sampl_freq == 0) - return 0; - - /* - * If the sensors are sampled at high frequency, we will not be able to - * sleep. Set sampling to a long period if necessary. - */ - if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) { - mutex_lock(&st->cmd_lock); - st->param.cmd = MOTIONSENSE_CMD_EC_RATE; - st->param.ec_rate.data = CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY; - cros_ec_motion_send_host_cmd(st, 0); - mutex_unlock(&st->cmd_lock); - } - return 0; -} - -static void __maybe_unused cros_ec_sensors_complete(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); - - if (st->curr_sampl_freq == 0) - return; - - if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) { - mutex_lock(&st->cmd_lock); - st->param.cmd = MOTIONSENSE_CMD_EC_RATE; - st->param.ec_rate.data = st->curr_sampl_freq; - cros_ec_motion_send_host_cmd(st, 0); - mutex_unlock(&st->cmd_lock); - } -} - -const struct dev_pm_ops cros_ec_sensors_pm_ops = { -#ifdef CONFIG_PM_SLEEP - .prepare = cros_ec_sensors_prepare, - .complete = cros_ec_sensors_complete -#endif -}; -EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops); - MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 03c951ff4a3c3..e10b35de4c2fa 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -255,7 +255,6 @@ MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids); static struct platform_driver cros_ec_light_prox_platform_driver = { .driver = { .name = "cros-ec-light-prox", - .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_light_prox_probe, .id_table = cros_ec_light_prox_ids, diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index b8f573ca9dcc9..96ea4551945e2 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -30,9 +30,6 @@ enum { */ #define CROS_EC_SAMPLE_SIZE (sizeof(s64) * 2) -/* Minimum sampling period to use when device is suspending */ -#define CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY 1000 /* 1 second */ - typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); /** @@ -117,8 +114,6 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask); -extern const struct dev_pm_ops cros_ec_sensors_pm_ops; - /* List of extended channel specification for all sensors */ extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[]; From patchwork Tue Mar 24 20:27:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456423 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A638213A4 for ; Tue, 24 Mar 2020 20:28:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 75A7E2074D for ; Tue, 24 Mar 2020 20:28:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="bXq330w8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728160AbgCXU2Q (ORCPT ); Tue, 24 Mar 2020 16:28:16 -0400 Received: from mail-pj1-f67.google.com ([209.85.216.67]:39836 "EHLO mail-pj1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728107AbgCXU15 (ORCPT ); Tue, 24 Mar 2020 16:27:57 -0400 Received: by mail-pj1-f67.google.com with SMTP id ck23so35901pjb.4 for ; Tue, 24 Mar 2020 13:27:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=UjA9Cr4Fi8556lMW97WIf4gNFiOcrBCARdax3+OWh9c=; b=bXq330w8Q653SwrxKNAayyEck4TdOkmqVYlViebflD8HtRJ0XN0+Xb/IIEagZ6vI0K hEFF/YwL95q+lKGBKyqzdhSUlZ69xtvD92ohSLcQNsqLRw5OfnxuE6Z5gFV+WE3GHsHn HxKI8AwqDQnDlFnTnEihDcCb0tR2TAN6lE0NE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UjA9Cr4Fi8556lMW97WIf4gNFiOcrBCARdax3+OWh9c=; b=mbPfmDoIAzXOYjs/lISDDD9d0S0KKhPjM2HurzIc2DyW0iR8/RMad/LdIp3tpoZTei 6Z1TiXK+2JuhXthAscqOCYSk5x7xcH6UTorMARc23QlxuaimC6imkXNJx6DB2ycQNnhb EhfaHDhEWhz8dyyuwg/73lrxu7KBdk/PS4R2OPn98TuzN+exlT27ccNanGvLnVkdEQx9 fJuFs2F+62NKCZzryEf/PgqV3xAQFyJLamE8B2hied36lkYmHPPNEkq2Osyph20l9RBv e5yaIHWglx5FABdPoACVCsr/X2MyW/Mqnr0bAa/8Vpqwj3aiLitTWGCpMYGy8NNooY6y KOGQ== X-Gm-Message-State: ANhLgQ1gxvLhEo1bbOFjgvhJJ2UnnM5I0CC4N9HFc5CO+vAw9pbwJJBQ zHEZeYH+/9pIHJ/ab5pGSHZcrg== X-Google-Smtp-Source: ADFU+vtO3N/WgMmPYETNrVDOpUpP92UwvcjcdYXXrMWXl5TBqhWQNhF7H0oDAYuBr3+cqCy+uUAVsQ== X-Received: by 2002:a17:902:7488:: with SMTP id h8mr9836277pll.264.1585081676642; Tue, 24 Mar 2020 13:27:56 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id e9sm16973147pfl.179.2020.03.24.13.27.55 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:55 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 08/11] iio: cros_ec: Expose hwfifo_timeout Date: Tue, 24 Mar 2020 13:27:33 -0700 Message-Id: <20200324202736.243314-9-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Expose EC minimal interrupt period through buffer/hwfifo_timeout: - Maximal timeout is limited to 65s. - When timeout for all sensors is set to 0, EC will not send events, even if the sensor sampling rate is greater than 0. Rename frequency to sampling_frequency to match IIO ABI. Reviewed-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: Added ack. Changes in v4: - Check patch with --strict option Alignement No changes in v3. Changes in v2: - Register fifo_attributes in sensors drivers that previously advertise that feature. .../common/cros_ec_sensors/cros_ec_sensors.c | 3 +- .../cros_ec_sensors/cros_ec_sensors_core.c | 95 ++++++++++++++----- drivers/iio/light/cros_ec_light_prox.c | 5 +- drivers/iio/pressure/cros_ec_baro.c | 5 +- .../linux/iio/common/cros_ec_sensors_core.h | 4 +- 5 files changed, 82 insertions(+), 30 deletions(-) diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index fad21a90bc7e8..a66941fdb3855 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -236,6 +236,8 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) if (ret) return ret; + iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes); + indio_dev->info = &ec_sensors_info; state = iio_priv(indio_dev); for (channel = state->channels, i = CROS_EC_SENSOR_X; @@ -247,7 +249,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) BIT(IIO_CHAN_INFO_CALIBSCALE); channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_FREQUENCY) | BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ); 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 a1ecbd55ea767..b8eac7e5d5e5b 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 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,77 @@ static void get_default_min_max_freq(enum motionsensor_type type, } } +static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st, + int rate) +{ + int ret; + + if (rate > U16_MAX) + rate = U16_MAX; + + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_EC_RATE; + st->param.ec_rate.data = rate; + ret = cros_ec_motion_send_host_cmd(st, 0); + mutex_unlock(&st->cmd_lock); + return ret; +} + +static ssize_t cros_ec_sensor_set_report_latency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + int integer, fract, ret; + int latency; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); + if (ret) + return ret; + + /* EC rate is in ms. */ + latency = integer * 1000 + fract / 1000; + ret = cros_ec_sensor_set_ec_rate(st, latency); + if (ret < 0) + return ret; + + return len; +} + +static ssize_t cros_ec_sensor_get_report_latency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + int latency, ret; + + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_EC_RATE; + st->param.ec_rate.data = EC_MOTION_SENSE_NO_VALUE; + + ret = cros_ec_motion_send_host_cmd(st, 0); + latency = st->resp->ec_rate.ret; + mutex_unlock(&st->cmd_lock); + if (ret < 0) + return ret; + + return sprintf(buf, "%d.%06u\n", + latency / 1000, + (latency % 1000) * 1000); +} + +static IIO_DEVICE_ATTR(hwfifo_timeout, 0644, + cros_ec_sensor_get_report_latency, + cros_ec_sensor_set_report_latency, 0); + +const struct attribute *cros_ec_sensor_fifo_attributes[] = { + &iio_dev_attr_hwfifo_timeout.dev_attr.attr, + NULL, +}; +EXPORT_SYMBOL_GPL(cros_ec_sensor_fifo_attributes); + int cros_ec_sensors_push_data(struct iio_dev *indio_dev, s16 *data, s64 timestamp) @@ -631,18 +703,6 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - st->param.cmd = MOTIONSENSE_CMD_EC_RATE; - st->param.ec_rate.data = - EC_MOTION_SENSE_NO_VALUE; - - ret = cros_ec_motion_send_host_cmd(st, 0); - if (ret) - break; - - *val = st->resp->ec_rate.ret; - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_FREQUENCY: st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; st->param.sensor_odr.data = EC_MOTION_SENSE_NO_VALUE; @@ -712,7 +772,7 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, int ret; switch (mask) { - case IIO_CHAN_INFO_FREQUENCY: + case IIO_CHAN_INFO_SAMP_FREQ: st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; st->param.sensor_odr.data = val; @@ -721,15 +781,6 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, ret = cros_ec_motion_send_host_cmd(st, 0); break; - case IIO_CHAN_INFO_SAMP_FREQ: - st->param.cmd = MOTIONSENSE_CMD_EC_RATE; - st->param.ec_rate.data = val; - - ret = cros_ec_motion_send_host_cmd(st, 0); - if (ret) - break; - st->curr_sampl_freq = val; - break; default: ret = -EINVAL; break; diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index e10b35de4c2fa..2198b50909ed0 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -183,6 +183,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) if (ret) return ret; + iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes); + indio_dev->info = &cros_ec_light_prox_info; state = iio_priv(indio_dev); state->core.type = state->core.resp->info.type; @@ -191,8 +193,7 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev) /* Common part */ channel->info_mask_shared_by_all = - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_FREQUENCY); + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 6add499f11aa6..c079b89600824 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -140,6 +140,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev) if (ret) return ret; + iio_buffer_set_attrs(indio_dev->buffer, cros_ec_sensor_fifo_attributes); + indio_dev->info = &cros_ec_baro_info; state = iio_priv(indio_dev); state->core.type = state->core.resp->info.type; @@ -149,8 +151,7 @@ static int cros_ec_baro_probe(struct platform_device *pdev) channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_FREQUENCY); + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index 96ea4551945e2..5b0acc14c891f 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -50,7 +50,6 @@ typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); * the timestamp. The timestamp is always last and * is always 8-byte aligned. * @read_ec_sensors_data: function used for accessing sensors values - * @cuur_sampl_freq: current sampling period */ struct cros_ec_sensors_core_state { struct cros_ec_device *ec; @@ -73,8 +72,6 @@ struct cros_ec_sensors_core_state { int (*read_ec_sensors_data)(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data); - int curr_sampl_freq; - /* Table of known available frequencies : 0, Min and Max in mHz */ int frequencies[3]; }; @@ -116,5 +113,6 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, /* List of extended channel specification for all sensors */ extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[]; +extern const struct attribute *cros_ec_sensor_fifo_attributes[]; #endif /* __CROS_EC_SENSORS_CORE_H */ From patchwork Tue Mar 24 20:27:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456419 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1A85C13A4 for ; Tue, 24 Mar 2020 20:28:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E76B32074D for ; Tue, 24 Mar 2020 20:28:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="KG0PGpWZ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728219AbgCXU2H (ORCPT ); Tue, 24 Mar 2020 16:28:07 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:40030 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728190AbgCXU2A (ORCPT ); Tue, 24 Mar 2020 16:28:00 -0400 Received: by mail-pf1-f196.google.com with SMTP id l184so9902780pfl.7 for ; Tue, 24 Mar 2020 13:27:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IPhCMY19Z+ku48o+5C/DWRkmLm0JB2NK43+b9YQjM9s=; b=KG0PGpWZeQ5rYNfjsKMCxolxronMNhDUGMB1zbtR+YjuyZp7XVgAJF/dFECkiOPpJM LhkNIQpxHdRSgqfgersCyt9T8QeJxr3qft3rY2j3MRRhvJZXwMxd5IJQOvx1LpNDrnng QOZXxnhVivNh7IpLqY/Yp/y6+fWcsxsn1zJ7o= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IPhCMY19Z+ku48o+5C/DWRkmLm0JB2NK43+b9YQjM9s=; b=kNfz9OKehSA2LnljzLmVeRDa0OeQTut6Xw/MmUmt/7vrELwyi80ni+HuNKff3Xi6WV Dev9W7/2eg08ZMYaEvNHrCdGN837l3E7IGTaoq8E9ioaNGGGyV85glQ0zOc5Vy7Mti8G KZ8VUf3Tt3u7rWVjCM8aLl2/MN0Gz3lpKJLmQOLhR2lpaPgDlqHfi27obioXH7V/FLaO 8e0ybOKWEXzxoMGd4d7EIwrbqZWsbnZzZNlZuEYjHuF4T97LdVnsqz+MJKD3f2d0Fqx+ EIQe17b+1V9xPSOj+GJurcrc1xY8BTEPwb/utLRe0oU0elaACoCM2wgmQFFxE8vgXm8n 3sow== X-Gm-Message-State: ANhLgQ3etxnmX9baIgq26087KgbcoWrDYiLkE1tmduIw5AGQNZ+Yy86b XSvEzI9czFYZ/QoWGsWaTpRABQ== X-Google-Smtp-Source: ADFU+vtVKFQOKPuBiRfBvjYuAv2bvTMUMIvH22MMVmM7wu5YXcyQAoB85cMGdSE8LLDhScAyWpPEqg== X-Received: by 2002:a63:5050:: with SMTP id q16mr26178759pgl.118.1585081677877; Tue, 24 Mar 2020 13:27:57 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id i3sm10672667pgj.13.2020.03.24.13.27.57 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:57 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 09/11] iio: cros_ec: Report hwfifo_watermark_max Date: Tue, 24 Mar 2020 13:27:34 -0700 Message-Id: <20200324202736.243314-10-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Report the maximum amount of sample the EC can hold. This is not tunable, but can be useful for application to find out the maximum amount of time it can sleep when hwfifo_timeout is set to a large number. Reviewed-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: Added ack. Changes in v4: - Check patch with --strict option Alignement No changes in v3. Changes in v2: - Remove double lines, add line before return for visibility. .../cros_ec_sensors/cros_ec_sensors_core.c | 33 +++++++++++++++++-- .../linux/iio/common/cros_ec_sensors_core.h | 3 ++ 2 files changed, 34 insertions(+), 2 deletions(-) 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 b8eac7e5d5e5b..67e8eff038cf5 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 @@ -22,6 +22,12 @@ #include #include +/* + * Hard coded to the first device to support sensor fifo. The EC has a 2048 + * byte fifo and will trigger an interrupt when fifo is 2/3 full. + */ +#define CROS_EC_FIFO_SIZE (2048 * 2 / 3) + static char *cros_ec_loc[] = { [MOTIONSENSE_LOC_BASE] = "base", [MOTIONSENSE_LOC_LID] = "lid", @@ -55,8 +61,15 @@ static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev, static void get_default_min_max_freq(enum motionsensor_type type, u32 *min_freq, - u32 *max_freq) + u32 *max_freq, + u32 *max_fifo_events) { + /* + * We don't know fifo size, set to size previously used by older + * hardware. + */ + *max_fifo_events = CROS_EC_FIFO_SIZE; + switch (type) { case MOTIONSENSE_TYPE_ACCEL: case MOTIONSENSE_TYPE_GYRO: @@ -149,8 +162,21 @@ static IIO_DEVICE_ATTR(hwfifo_timeout, 0644, cros_ec_sensor_get_report_latency, cros_ec_sensor_set_report_latency, 0); +static ssize_t hwfifo_watermark_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", st->fifo_max_event_count); +} + +static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); + const struct attribute *cros_ec_sensor_fifo_attributes[] = { &iio_dev_attr_hwfifo_timeout.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr, NULL, }; EXPORT_SYMBOL_GPL(cros_ec_sensor_fifo_attributes); @@ -279,12 +305,15 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, if (state->msg->version < 3) { get_default_min_max_freq(state->resp->info.type, &state->frequencies[1], - &state->frequencies[2]); + &state->frequencies[2], + &state->fifo_max_event_count); } else { state->frequencies[1] = state->resp->info_3.min_frequency; state->frequencies[2] = state->resp->info_3.max_frequency; + state->fifo_max_event_count = + state->resp->info_3.fifo_max_event_count; } if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index 5b0acc14c891f..bc26ae2e32729 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -50,6 +50,7 @@ typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); * the timestamp. The timestamp is always last and * is always 8-byte aligned. * @read_ec_sensors_data: function used for accessing sensors values + * @fifo_max_event_count: Size of the EC sensor FIFO */ struct cros_ec_sensors_core_state { struct cros_ec_device *ec; @@ -72,6 +73,8 @@ struct cros_ec_sensors_core_state { int (*read_ec_sensors_data)(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data); + u32 fifo_max_event_count; + /* Table of known available frequencies : 0, Min and Max in mHz */ int frequencies[3]; }; From patchwork Tue Mar 24 20:27:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456421 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 420BC913 for ; Tue, 24 Mar 2020 20:28:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 24A12208DB for ; Tue, 24 Mar 2020 20:28:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="B0ZNmDr1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728190AbgCXU2I (ORCPT ); Tue, 24 Mar 2020 16:28:08 -0400 Received: from mail-pl1-f194.google.com ([209.85.214.194]:33263 "EHLO mail-pl1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728199AbgCXU2A (ORCPT ); Tue, 24 Mar 2020 16:28:00 -0400 Received: by mail-pl1-f194.google.com with SMTP id g18so7906762plq.0 for ; Tue, 24 Mar 2020 13:27:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=brVc5HweTkVKa9eDNLWjc+3fwT3hTHkdcZ9vXwZpRVo=; b=B0ZNmDr1ZYxns4f5hTjh5wgb/axTWGz2kctWnxVKUWkEKFfHnd41cshI3+gGm95IyO 3dB4AWqyEYTDnBQPwsxvJhD45IxFgRLsYxyzIkTibuamuVnqYuNxtUp4LoUr/93IG8ID non7kSXwG6SVBNQRGybtKBmfSbTI7G5Pp3+Mw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=brVc5HweTkVKa9eDNLWjc+3fwT3hTHkdcZ9vXwZpRVo=; b=tP6G9A2m4Z/cLLhhkCZJx7Vpx94hSZ8Y1aGlrqEUmVnCDcG0o+IavEVXPgvH1t2Cul hTn6L+ss+5SKcrEUpvLebUTXKlAju3IKE/d4B1Gxq1ElAioL/lfJMAgU5jw577lj19hG y0rVAtNPNh3MNkQSAaB6iLXb8vkuYJBXZ0T/GlkNaYrsJM11Ul3n5fgsHi8GmpyyyQi0 lWsrXhChUAlUZr+PruyjopZER8f56xxllI1xHS+wbYTsg697FBCzIlLVUsmJ/uMxcbM0 wnS5ej8RcHVtMDx6pamHsgf6KjjzY1mC2QKSoca/K3zOUYxJhUSECa5yStlPpkOuwCeU L0Ow== X-Gm-Message-State: ANhLgQ1wcvVRfT9dapOuuR/RIC3szqrGbgpb7RwPgSimoRk2HFeJKH4J aXDwTdTICUyq5RCbmFmxrsINAQ== X-Google-Smtp-Source: ADFU+vsrk88nfzUoRis7U4y/8YMsjvF5//C1FObSKJ1B0E50lQJb/QiIb1UGqQAd56zDTHOnChxghQ== X-Received: by 2002:a17:90a:1f0b:: with SMTP id u11mr7474612pja.18.1585081679302; Tue, 24 Mar 2020 13:27:59 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id x75sm17171446pfc.161.2020.03.24.13.27.58 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:27:58 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 10/11] iio: cros_ec: Use Hertz as unit for sampling frequency Date: Tue, 24 Mar 2020 13:27:35 -0700 Message-Id: <20200324202736.243314-11-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org To be compliant with other sensors, set and get sensor sampling frequency in Hz, not mHz. Fixes: ae7b02ad2f32 ("iio: common: cros_ec_sensors: Expose cros_ec_sensors frequency range via iio sysfs") Acked-by: Jonathan Cameron Signed-off-by: Gwendal Grignou --- Changes in v6: - No changes. Changes in v5: Added ack. Changes in v4: - Check patch with --strict option Alignement No changes in v3. No changes in v2. .../cros_ec_sensors/cros_ec_sensors_core.c | 32 +++++++++++-------- .../linux/iio/common/cros_ec_sensors_core.h | 6 ++-- 2 files changed, 22 insertions(+), 16 deletions(-) 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 67e8eff038cf5..c831915ca7e56 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 @@ -253,6 +253,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, struct cros_ec_dev *ec = sensor_hub->ec; struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); u32 ver_mask; + int frequencies[ARRAY_SIZE(state->frequencies) / 2] = { 0 }; int ret, i; platform_set_drvdata(pdev, indio_dev); @@ -301,20 +302,22 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, state->calib[i].scale = MOTION_SENSE_DEFAULT_SCALE; /* 0 is a correct value used to stop the device */ - state->frequencies[0] = 0; if (state->msg->version < 3) { get_default_min_max_freq(state->resp->info.type, - &state->frequencies[1], - &state->frequencies[2], + &frequencies[1], + &frequencies[2], &state->fifo_max_event_count); } else { - state->frequencies[1] = - state->resp->info_3.min_frequency; - state->frequencies[2] = - state->resp->info_3.max_frequency; + frequencies[1] = state->resp->info_3.min_frequency; + frequencies[2] = state->resp->info_3.max_frequency; state->fifo_max_event_count = state->resp->info_3.fifo_max_event_count; } + for (i = 0; i < ARRAY_SIZE(frequencies); i++) { + state->frequencies[2 * i] = frequencies[i] / 1000; + state->frequencies[2 * i + 1] = + (frequencies[i] % 1000) * 1000; + } if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { /* @@ -728,7 +731,7 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - int ret; + int ret, frequency; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: @@ -740,8 +743,10 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, if (ret) break; - *val = st->resp->sensor_odr.ret; - ret = IIO_VAL_INT; + frequency = st->resp->sensor_odr.ret; + *val = frequency / 1000; + *val2 = (frequency % 1000) * 1000; + ret = IIO_VAL_INT_PLUS_MICRO; break; default: ret = -EINVAL; @@ -776,7 +781,7 @@ int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: *length = ARRAY_SIZE(state->frequencies); *vals = (const int *)&state->frequencies; - *type = IIO_VAL_INT; + *type = IIO_VAL_INT_PLUS_MICRO; return IIO_AVAIL_LIST; } @@ -798,12 +803,13 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret; + int ret, frequency; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: + frequency = val * 1000 + val2 / 1000; st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR; - st->param.sensor_odr.data = val; + st->param.sensor_odr.data = frequency; /* Always roundup, so caller gets at least what it asks for. */ st->param.sensor_odr.roundup = 1; diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index bc26ae2e32729..7bc961defa87e 100644 --- a/include/linux/iio/common/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -51,6 +51,8 @@ typedef irqreturn_t (*cros_ec_sensors_capture_t)(int irq, void *p); * is always 8-byte aligned. * @read_ec_sensors_data: function used for accessing sensors values * @fifo_max_event_count: Size of the EC sensor FIFO + * @frequencies: Table of known available frequencies: + * 0, Min and Max in mHz */ struct cros_ec_sensors_core_state { struct cros_ec_device *ec; @@ -74,9 +76,7 @@ struct cros_ec_sensors_core_state { unsigned long scan_mask, s16 *data); u32 fifo_max_event_count; - - /* Table of known available frequencies : 0, Min and Max in mHz */ - int frequencies[3]; + int frequencies[6]; }; int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask, From patchwork Tue Mar 24 20:27:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gwendal Grignou X-Patchwork-Id: 11456417 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7B9D213A4 for ; Tue, 24 Mar 2020 20:28:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5DC112074D for ; Tue, 24 Mar 2020 20:28:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="eEVyWcqX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728250AbgCXU2E (ORCPT ); Tue, 24 Mar 2020 16:28:04 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:45169 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725953AbgCXU2D (ORCPT ); Tue, 24 Mar 2020 16:28:03 -0400 Received: by mail-pg1-f193.google.com with SMTP id o26so487pgc.12 for ; Tue, 24 Mar 2020 13:28:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=aG3ZG/JseQ9SHgEGTa48Huh2O7B5gsYW9O6b0GiUzZo=; b=eEVyWcqXnp/Fdd1gQU3vtTzHqjyGFSC1Gxxb4UYfyVOoa84+V7sy/oZDeYU7mJ3sOP S5ULEOjK3Bl5+CfiQGxI0p6lUuKqqQ2tmriaS0oqV7384B+05d3ZeTctCsvGUqWoAQ3E p0F1fBYGAsHKJmdkX/WDt9UvI9Xf37h8ZxQek= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=aG3ZG/JseQ9SHgEGTa48Huh2O7B5gsYW9O6b0GiUzZo=; b=Uh0F37xCOvGQLIsU33tPrzQ3NTUDOFDXkFE3SjNvT+a4CvijWjs73lpH4gDENIzCkR FEkojgaw9TBJPMN0+QnIqBOinZmoTmi3KkFdyD2DkrbVDERruLEyWQJf3pqGapnQNnNM eWQzITbiBTG0ZI8Lhc1qf4SDZOwKz2Xzx0qkoG5/EI/KNs0Rh9FUJ3v5c+UWkr9dPR25 2Xx18y7zJsZAKoGDJOT8DmBumk6QYTDcTdKR89ZFNB/I3yeqxmcz/I4+/SVnTE1N+ZWS ZCU96g+pbgtSChOYzR363UwXeRcnaPEQj3qgdgmLl8jI53XQFAFPzjFPY38UuVU9Cw/R Xjcw== X-Gm-Message-State: ANhLgQ1or6BPwlrB1LTFZ3VQwIE9ej2DxHQ9Sy4mlBG6p7/8KceI10b7 9ZgYWPUrts35eGQow/lyfJKuoQ== X-Google-Smtp-Source: ADFU+vsZBe8JrbNa0VLrHSDVrWMSTj1DEaHQdKmwz64a+ux0d1WYmgQc5n2eh8ePMaAouYw7QryK9w== X-Received: by 2002:a65:5846:: with SMTP id s6mr29062581pgr.179.1585081680649; Tue, 24 Mar 2020 13:28:00 -0700 (PDT) Received: from localhost ([2620:15c:202:1:4cc0:7eee:97c9:3c1a]) by smtp.gmail.com with ESMTPSA id 193sm9900116pfa.182.2020.03.24.13.27.59 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 24 Mar 2020 13:28:00 -0700 (PDT) From: Gwendal Grignou To: bleung@chromium.org, enric.balletbo@collabora.com, Jonathan.Cameron@huawei.com Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Gwendal Grignou Subject: [PATCH v6 11/11] iio: cros_ec: flush as hwfifo attribute Date: Tue, 24 Mar 2020 13:27:36 -0700 Message-Id: <20200324202736.243314-12-gwendal@chromium.org> X-Mailer: git-send-email 2.25.1.696.g5e7596f4ac-goog In-Reply-To: <20200324202736.243314-1-gwendal@chromium.org> References: <20200324202736.243314-1-gwendal@chromium.org> MIME-Version: 1.0 Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Add buffer/hwfifo_flush. It is not part of the ABI, but it follows ST and HID lead: Tells the sensor hub to send to the host all pending sensor events. Signed-off-by: Gwendal Grignou --- New in v6. .../cros_ec_sensors/cros_ec_sensors_core.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) 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 c831915ca7e56..aaf124a82e0e4 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 @@ -113,6 +113,33 @@ static int cros_ec_sensor_set_ec_rate(struct cros_ec_sensors_core_state *st, return ret; } +static ssize_t cros_ec_sensors_flush(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + int ret = 0; + bool flush; + + ret = strtobool(buf, &flush); + if (ret < 0) + return ret; + if (!flush) + return -EINVAL; + + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_FIFO_FLUSH; + ret = cros_ec_motion_send_host_cmd(st, 0); + if (ret != 0) + dev_warn(&indio_dev->dev, "Unable to flush sensor\n"); + mutex_unlock(&st->cmd_lock); + return ret ? ret : len; +} + +static IIO_DEVICE_ATTR(hwfifo_flush, 0644, NULL, + cros_ec_sensors_flush, 0); + static ssize_t cros_ec_sensor_set_report_latency(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -175,6 +202,7 @@ static ssize_t hwfifo_watermark_max_show(struct device *dev, static IIO_DEVICE_ATTR_RO(hwfifo_watermark_max, 0); const struct attribute *cros_ec_sensor_fifo_attributes[] = { + &iio_dev_attr_hwfifo_flush.dev_attr.attr, &iio_dev_attr_hwfifo_timeout.dev_attr.attr, &iio_dev_attr_hwfifo_watermark_max.dev_attr.attr, NULL,