Skip to content

Commit

Permalink
iio / platform: cros_ec: Add cros-ec-sensorhub driver
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gwendal Grignou authored and Enric Balletbo i Serra committed Nov 21, 2019
1 parent a16b2e2 commit 5306747
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 1 deletion.
2 changes: 1 addition & 1 deletion drivers/iio/common/cros_ec_sensors/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions drivers/platform/chrome/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/platform/chrome/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
199 changes: 199 additions & 0 deletions drivers/platform/chrome/cros_ec_sensorhub.c
Original file line number Diff line number Diff line change
@@ -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");
22 changes: 22 additions & 0 deletions include/linux/platform_data/cros_ec_sensorhub.h
Original file line number Diff line number Diff line change
@@ -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 */

0 comments on commit 5306747

Please sign in to comment.