iio / platform: cros_ec: Add cros-ec-sensorhub driver

Similar to HID sensor stack, the new driver sits between cros-ec-dev
and the IIO device drivers:

The EC based IIO device topology would be:

iio:device1 ->
   ...0/0000:00:1f.0/PNP0C09:00/GOOG0004:00/cros-ec-dev.6.auto/
                                            cros-ec-sensorhub.7.auto/
                                            cros-ec-accel.15.auto/
                                            iio:device1

It will be expanded to control EC sensor FIFO.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
[Fix "unknown type name 'uint32_t'" type errors]
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
This commit is contained in:
Gwendal Grignou 2019-11-19 13:45:45 +01:00 committed by Enric Balletbo i Serra
parent a16b2e2819
commit 5306747118
5 changed files with 235 additions and 1 deletions

View File

@ -4,7 +4,7 @@
#
config IIO_CROS_EC_SENSORS_CORE
tristate "ChromeOS EC Sensors Core"
depends on SYSFS && CROS_EC
depends on SYSFS && CROS_EC_SENSORHUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help

View File

@ -190,6 +190,18 @@ config CROS_EC_DEBUGFS
To compile this driver as a module, choose M here: the
module will be called cros_ec_debugfs.
config CROS_EC_SENSORHUB
tristate "ChromeOS EC MEMS Sensor Hub"
depends on CROS_EC
help
Allow loading IIO sensors. This driver is loaded by MFD and will in
turn query the EC and register the sensors.
It also spreads the sensor data coming from the EC to the IIO sensor
object.
To compile this driver as a module, choose M here: the
module will be called cros_ec_sensorhub.
config CROS_EC_SYSFS
tristate "ChromeOS EC control and information through sysfs"
depends on MFD_CROS_EC_DEV && SYSFS

View File

@ -19,6 +19,7 @@ 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_SYSFS) += cros_ec_sysfs.o
obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o

View File

@ -0,0 +1,199 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Sensor HUB driver that discovers sensors behind a ChromeOS Embedded
* Controller.
*
* Copyright 2019 Google LLC
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mfd/cros_ec.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_data/cros_ec_sensorhub.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#define DRV_NAME "cros-ec-sensorhub"
static void cros_ec_sensorhub_free_sensor(void *arg)
{
struct platform_device *pdev = arg;
platform_device_unregister(pdev);
}
static int cros_ec_sensorhub_allocate_sensor(struct device *parent,
char *sensor_name,
int sensor_num)
{
struct cros_ec_sensor_platform sensor_platforms = {
.sensor_num = sensor_num,
};
struct platform_device *pdev;
pdev = platform_device_register_data(parent, sensor_name,
PLATFORM_DEVID_AUTO,
&sensor_platforms,
sizeof(sensor_platforms));
if (IS_ERR(pdev))
return PTR_ERR(pdev);
return devm_add_action_or_reset(parent,
cros_ec_sensorhub_free_sensor,
pdev);
}
static int cros_ec_sensorhub_register(struct device *dev,
struct cros_ec_sensorhub *sensorhub)
{
int sensor_type[MOTIONSENSE_TYPE_MAX] = { 0 };
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;
sensor_num = cros_ec_get_sensor_count(ec);
if (sensor_num < 0) {
dev_err(dev,
"Unable to retrieve sensor information (err:%d)\n",
sensor_num);
return sensor_num;
}
if (sensor_num == 0) {
dev_err(dev, "Zero sensors reported.\n");
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;
for (i = 0; i < sensor_num; i++) {
params->cmd = MOTIONSENSE_CMD_INFO;
params->info.sensor_num = i;
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
dev_warn(dev, "no info for EC sensor %d : %d/%d\n",
i, ret, msg->result);
continue;
}
switch (resp->info.type) {
case MOTIONSENSE_TYPE_ACCEL:
name = "cros-ec-accel";
break;
case MOTIONSENSE_TYPE_BARO:
name = "cros-ec-baro";
break;
case MOTIONSENSE_TYPE_GYRO:
name = "cros-ec-gyro";
break;
case MOTIONSENSE_TYPE_MAG:
name = "cros-ec-mag";
break;
case MOTIONSENSE_TYPE_PROX:
name = "cros-ec-prox";
break;
case MOTIONSENSE_TYPE_LIGHT:
name = "cros-ec-light";
break;
case MOTIONSENSE_TYPE_ACTIVITY:
name = "cros-ec-activity";
break;
default:
dev_warn(dev, "unknown type %d\n", resp->info.type);
continue;
}
ret = cros_ec_sensorhub_allocate_sensor(dev, name, i);
if (ret)
goto error;
sensor_type[resp->info.type]++;
}
if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2)
ec->has_kb_wake_angle = true;
if (cros_ec_check_features(ec,
EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS)) {
ret = cros_ec_sensorhub_allocate_sensor(dev,
"cros-ec-lid-angle",
0);
if (ret)
goto error;
}
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_sensorhub *data;
int ret;
int i;
data = devm_kzalloc(dev, sizeof(struct cros_ec_sensorhub), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->ec = dev_get_drvdata(dev->parent);
dev_set_drvdata(dev, data);
/* Check whether this EC is a sensor hub. */
if (cros_ec_check_features(data->ec, EC_FEATURE_MOTION_SENSE)) {
ret = cros_ec_sensorhub_register(dev, data);
if (ret)
return ret;
} else {
/*
* If the device has sensors but does not claim to
* be a sensor hub, we are in legacy mode.
*/
for (i = 0; i < 2; i++) {
ret = cros_ec_sensorhub_allocate_sensor(dev,
"cros-ec-accel-legacy", i);
if (ret)
return ret;
}
}
return 0;
}
static struct platform_driver cros_ec_sensorhub_driver = {
.driver = {
.name = DRV_NAME,
},
.probe = cros_ec_sensorhub_probe,
};
module_platform_driver(cros_ec_sensorhub_driver);
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
MODULE_DESCRIPTION("ChromeOS EC MEMS Sensor Hub Driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Chrome OS EC MEMS Sensor Hub driver.
*
* Copyright 2019 Google LLC
*/
#ifndef __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
#define __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H
#include <linux/platform_data/cros_ec_commands.h>
/**
* struct cros_ec_sensorhub - Sensor Hub device data.
*
* @ec: Embedded Controller where the hub is located.
*/
struct cros_ec_sensorhub {
struct cros_ec_dev *ec;
};
#endif /* __LINUX_PLATFORM_DATA_CROS_EC_SENSORHUB_H */