mfd / platform: cros_ec: Add sensor_count and make check_features public
authorGwendal Grignou <gwendal@chromium.org>
Tue, 19 Nov 2019 12:45:45 +0000 (13:45 +0100)
committerEnric Balletbo i Serra <enric.balletbo@collabora.com>
Thu, 21 Nov 2019 10:23:13 +0000 (11:23 +0100)
Add a new function to return the number of MEMS sensors available in a
ChromeOS Embedded Controller. It uses MOTIONSENSE_CMD_DUMP if available
or a specific memory map ACPI registers to find out.

Also, make check_features public as it can be useful for other drivers
to know what the Embedded Controller supports.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
drivers/mfd/cros_ec_dev.c
drivers/platform/chrome/cros_ec_proto.c
include/linux/platform_data/cros_ec_proto.h

index 6e6dfd6..a35104e 100644 (file)
@@ -112,38 +112,6 @@ static const struct mfd_cell cros_ec_vbc_cells[] = {
        { .name = "cros-ec-vbc", }
 };
 
-static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
-{
-       struct cros_ec_command *msg;
-       int ret;
-
-       if (ec->features[0] == -1U && ec->features[1] == -1U) {
-               /* features bitmap not read yet */
-               msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
-               if (!msg)
-                       return -ENOMEM;
-
-               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
-               msg->insize = sizeof(ec->features);
-
-               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
-               if (ret < 0) {
-                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
-                                ret, msg->result);
-                       memset(ec->features, 0, sizeof(ec->features));
-               } else {
-                       memcpy(ec->features, msg->data, sizeof(ec->features));
-               }
-
-               dev_dbg(ec->dev, "EC features %08x %08x\n",
-                       ec->features[0], ec->features[1]);
-
-               kfree(msg);
-       }
-
-       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
-}
-
 static void cros_ec_class_release(struct device *dev)
 {
        kfree(to_cros_ec_dev(dev));
index 7db5877..12bdd1f 100644 (file)
@@ -717,3 +717,120 @@ u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
        return host_event;
 }
 EXPORT_SYMBOL(cros_ec_get_host_event);
+
+/**
+ * cros_ec_check_features() - Test for the presence of EC features
+ *
+ * @ec: EC device, does not have to be connected directly to the AP,
+ *      can be daisy chained through another device.
+ * @feature: One of ec_feature_code bit.
+ *
+ * Call this function to test whether the ChromeOS EC supports a feature.
+ *
+ * Return: 1 if supported, 0 if not
+ */
+int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
+{
+       struct cros_ec_command *msg;
+       int ret;
+
+       if (ec->features[0] == -1U && ec->features[1] == -1U) {
+               /* features bitmap not read yet */
+               msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
+               if (!msg)
+                       return -ENOMEM;
+
+               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
+               msg->insize = sizeof(ec->features);
+
+               ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
+               if (ret < 0) {
+                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
+                                ret, msg->result);
+                       memset(ec->features, 0, sizeof(ec->features));
+               } else {
+                       memcpy(ec->features, msg->data, sizeof(ec->features));
+               }
+
+               dev_dbg(ec->dev, "EC features %08x %08x\n",
+                       ec->features[0], ec->features[1]);
+
+               kfree(msg);
+       }
+
+       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
+}
+EXPORT_SYMBOL_GPL(cros_ec_check_features);
+
+/**
+ * cros_ec_get_sensor_count() - Return the number of MEMS sensors supported.
+ *
+ * @ec: EC device, does not have to be connected directly to the AP,
+ *      can be daisy chained through another device.
+ * Return: < 0 in case of error.
+ */
+int cros_ec_get_sensor_count(struct cros_ec_dev *ec)
+{
+       /*
+        * Issue a command to get the number of sensor reported.
+        * If not supported, check for legacy mode.
+        */
+       int ret, sensor_count;
+       struct ec_params_motion_sense *params;
+       struct ec_response_motion_sense *resp;
+       struct cros_ec_command *msg;
+       struct cros_ec_device *ec_dev = ec->ec_dev;
+       u8 status;
+
+       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;
+       params->cmd = MOTIONSENSE_CMD_DUMP;
+
+       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
+       if (ret < 0) {
+               sensor_count = ret;
+       } else if (msg->result != EC_RES_SUCCESS) {
+               sensor_count = -EPROTO;
+       } else {
+               resp = (struct ec_response_motion_sense *)msg->data;
+               sensor_count = resp->dump.sensor_count;
+       }
+       kfree(msg);
+
+       /*
+        * Check legacy mode: Let's find out if sensors are accessible
+        * via LPC interface.
+        */
+       if (sensor_count == -EPROTO &&
+           ec->cmd_offset == 0 &&
+           ec_dev->cmd_readmem) {
+               ret = ec_dev->cmd_readmem(ec_dev, EC_MEMMAP_ACC_STATUS,
+                               1, &status);
+               if (ret >= 0 &&
+                   (status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT)) {
+                       /*
+                        * We have 2 sensors, one in the lid, one in the base.
+                        */
+                       sensor_count = 2;
+               } else {
+                       /*
+                        * EC uses LPC interface and no sensors are presented.
+                        */
+                       sensor_count = 0;
+               }
+       } else if (sensor_count == -EPROTO) {
+               /* EC responded, but does not understand DUMP command. */
+               sensor_count = 0;
+       }
+       return sensor_count;
+}
+EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count);
index 0d4e4aa..f3de066 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/notifier.h>
 
+#include <linux/mfd/cros_ec.h>
 #include <linux/platform_data/cros_ec_commands.h>
 
 #define CROS_EC_DEV_NAME       "cros_ec"
@@ -213,4 +214,8 @@ int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
 
 u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
 
+int cros_ec_check_features(struct cros_ec_dev *ec, int feature);
+
+int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
+
 #endif /* __LINUX_CROS_EC_PROTO_H */