Re: [PATCH v3 3/7] mfd: cros_ec: Move protocol helpers out of the MFD driver

Lee Jones
2015-05-27T08:38:09Z

On Fri, 22 May 2015, Javier Martinez Canillas wrote:

> The MFD driver should only have the logic to instantiate its child devices
> and setup any shared resources that will be used by the subdevices drivers.
>
> The cros_ec MFD is more complex than expected since it also has helpers to
> communicate with the EC. So the driver will only get more bigger as other
> protocols are supported in the future. So move the communication protocol
> helpers to its own driver as drivers/platform/chrome/cros_ec_proto.c.
>
> Suggested-by: Lee Jones <lee.jones@linaro.org>
> Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
> ---
>
> Changes since v2: None, new patch.
> ---
> drivers/i2c/busses/Kconfig | 2 +-
> drivers/input/keyboard/Kconfig | 2 +-
> drivers/mfd/Kconfig | 5 +-
> drivers/mfd/cros_ec.c | 96 --------------------------

:)

Acked-by: Lee Jones <lee.jones@linaro.org>

> drivers/platform/chrome/Kconfig | 9 ++-
> drivers/platform/chrome/Makefile | 1 +
> drivers/platform/chrome/cros_ec_proto.c | 115 ++++++++++++++++++++++++++++++++
> 7 files changed, 128 insertions(+), 102 deletions(-)
> create mode 100644 drivers/platform/chrome/cros_ec_proto.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 2255af23b9c7..5f1c1c4f5d87 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -1103,7 +1103,7 @@ config I2C_SIBYTE
>
> config I2C_CROS_EC_TUNNEL
> tristate "ChromeOS EC tunnel I2C bus"
> - depends on MFD_CROS_EC
> + depends on CROS_EC_PROTO
> help
> If you say yes here you get an I2C bus that will tunnel i2c commands
> through to the other side of the ChromeOS EC to the i2c bus
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index 106fbac7f8c5..e8eb60c6d83e 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -677,7 +677,7 @@ config KEYBOARD_W90P910
> config KEYBOARD_CROS_EC
> tristate "ChromeOS EC keyboard"
> select INPUT_MATRIXKMAP
> - depends on MFD_CROS_EC
> + depends on CROS_EC_PROTO
> help
> Say Y here to enable the matrix keyboard used by ChromeOS devices
> and implemented on the ChromeOS EC. You must enable one bus option
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index d5ad04dad081..927ba61e5bf9 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -94,6 +94,7 @@ config MFD_AXP20X
> config MFD_CROS_EC
> tristate "ChromeOS Embedded Controller"
> select MFD_CORE
> + select CROS_EC_PROTO
> help
> If you say Y here you get support for the ChromeOS Embedded
> Controller (EC) providing keyboard, battery and power services.
> @@ -102,7 +103,7 @@ config MFD_CROS_EC
>
> config MFD_CROS_EC_I2C
> tristate "ChromeOS Embedded Controller (I2C)"
> - depends on MFD_CROS_EC && I2C
> + depends on MFD_CROS_EC && CROS_EC_PROTO && I2C
>
> help
> If you say Y here, you get support for talking to the ChromeOS
> @@ -112,7 +113,7 @@ config MFD_CROS_EC_I2C
>
> config MFD_CROS_EC_SPI
> tristate "ChromeOS Embedded Controller (SPI)"
> - depends on MFD_CROS_EC && SPI && OF
> + depends on MFD_CROS_EC && CROS_EC_PROTO && SPI && OF
>
> ---help---
> If you say Y here, you get support for talking to the ChromeOS EC
> diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
> index 4a0f6dfcd376..d857f6a2b57b 100644
> --- a/drivers/mfd/cros_ec.c
> +++ b/drivers/mfd/cros_ec.c
> @@ -23,102 +23,6 @@
> #include <linux/module.h>
> #include <linux/mfd/core.h>
> #include <linux/mfd/cros_ec.h>
> -#include <linux/mfd/cros_ec_commands.h>
> -#include <linux/delay.h>
> -
> -#define EC_COMMAND_RETRIES 50
> -
> -int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
> - struct cros_ec_command *msg)
> -{
> - uint8_t *out;
> - int csum, i;
> -
> - BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
> - out = ec_dev->dout;
> - out[0] = EC_CMD_VERSION0 + msg->version;
> - out[1] = msg->command;
> - out[2] = msg->outsize;
> - csum = out[0] + out[1] + out[2];
> - for (i = 0; i < msg->outsize; i++)
> - csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
> - out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff);
> -
> - return EC_MSG_TX_PROTO_BYTES + msg->outsize;
> -}
> -EXPORT_SYMBOL(cros_ec_prepare_tx);
> -
> -int cros_ec_check_result(struct cros_ec_device *ec_dev,
> - struct cros_ec_command *msg)
> -{
> - switch (msg->result) {
> - case EC_RES_SUCCESS:
> - return 0;
> - case EC_RES_IN_PROGRESS:
> - dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",
> - msg->command);
> - return -EAGAIN;
> - default:
> - dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",
> - msg->command, msg->result);
> - return 0;
> - }
> -}
> -EXPORT_SYMBOL(cros_ec_check_result);
> -
> -int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
> - struct cros_ec_command *msg)
> -{
> - int ret;
> -
> - mutex_lock(&ec_dev->lock);
> - ret = ec_dev->cmd_xfer(ec_dev, msg);
> - if (msg->result == EC_RES_IN_PROGRESS) {
> - int i;
> - struct cros_ec_command *status_msg;
> - struct ec_response_get_comms_status *status;
> -
> - status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
> - GFP_KERNEL);
> - if (!status_msg) {
> - ret = -ENOMEM;
> - goto exit;
> - }
> -
> - status_msg->version = 0;
> - status_msg->command = EC_CMD_GET_COMMS_STATUS;
> - status_msg->insize = sizeof(*status);
> - status_msg->outsize = 0;
> -
> - /*
> - * Query the EC's status until it's no longer busy or
> - * we encounter an error.
> - */
> - for (i = 0; i < EC_COMMAND_RETRIES; i++) {
> - usleep_range(10000, 11000);
> -
> - ret = ec_dev->cmd_xfer(ec_dev, status_msg);
> - if (ret < 0)
> - break;
> -
> - msg->result = status_msg->result;
> - if (status_msg->result != EC_RES_SUCCESS)
> - break;
> -
> - status = (struct ec_response_get_comms_status *)
> - status_msg->data;
> - if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
> - break;
> - }
> -
> - kfree(status_msg);
> - }
> -exit:
> - mutex_unlock(&ec_dev->lock);
> -
> - return ret;
> -}
> -EXPORT_SYMBOL(cros_ec_cmd_xfer);
>
> static const struct mfd_cell cros_devs[] = {
> {
> diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
> index 2a6531a5fde8..cb1329919527 100644
> --- a/drivers/platform/chrome/Kconfig
> +++ b/drivers/platform/chrome/Kconfig
> @@ -40,7 +40,7 @@ config CHROMEOS_PSTORE
>
> config CROS_EC_CHARDEV
> tristate "Chrome OS Embedded Controller userspace device interface"
> - depends on MFD_CROS_EC
> + depends on CROS_EC_PROTO
> ---help---
> This driver adds support to talk with the ChromeOS EC from userspace.
>
> @@ -49,7 +49,7 @@ config CROS_EC_CHARDEV
>
> config CROS_EC_LPC
> tristate "ChromeOS Embedded Controller (LPC)"
> - depends on MFD_CROS_EC && (X86 || COMPILE_TEST)
> + depends on MFD_CROS_EC && CROS_EC_PROTO && (X86 || COMPILE_TEST)
> help
> If you say Y here, you get support for talking to the ChromeOS EC
> over an LPC bus. This uses a simple byte-level protocol with a
> @@ -59,4 +59,9 @@ config CROS_EC_LPC
> To compile this driver as a module, choose M here: the
> module will be called cros_ec_lpc.
>
> +config CROS_EC_PROTO
> + bool
> + help
> + ChromeOS EC communication protocol helpers.
> +
> endif # CHROMEOS_PLATFORMS
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index bd8d8601e875..4a11b010f5d8 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -4,3 +4,4 @@ obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
> cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o
> obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
> obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
> +obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o
> diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
> new file mode 100644
> index 000000000000..58e98a24fd08
> --- /dev/null
> +++ b/drivers/platform/chrome/cros_ec_proto.c
> @@ -0,0 +1,115 @@
> +/*
> + * ChromeOS EC communication protocol helper functions
> + *
> + * Copyright (C) 2015 Google, Inc
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/mfd/cros_ec.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +
> +#define EC_COMMAND_RETRIES 50
> +
> +int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
> + struct cros_ec_command *msg)
> +{
> + uint8_t *out;
> + int csum, i;
> +
> + BUG_ON(msg->outsize > EC_PROTO2_MAX_PARAM_SIZE);
> + out = ec_dev->dout;
> + out[0] = EC_CMD_VERSION0 + msg->version;
> + out[1] = msg->command;
> + out[2] = msg->outsize;
> + csum = out[0] + out[1] + out[2];
> + for (i = 0; i < msg->outsize; i++)
> + csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i];
> + out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = (uint8_t)(csum & 0xff);
> +
> + return EC_MSG_TX_PROTO_BYTES + msg->outsize;
> +}
> +EXPORT_SYMBOL(cros_ec_prepare_tx);
> +
> +int cros_ec_check_result(struct cros_ec_device *ec_dev,
> + struct cros_ec_command *msg)
> +{
> + switch (msg->result) {
> + case EC_RES_SUCCESS:
> + return 0;
> + case EC_RES_IN_PROGRESS:
> + dev_dbg(ec_dev->dev, "command 0x%02x in progress\n",
> + msg->command);
> + return -EAGAIN;
> + default:
> + dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n",
> + msg->command, msg->result);
> + return 0;
> + }
> +}
> +EXPORT_SYMBOL(cros_ec_check_result);
> +
> +int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
> + struct cros_ec_command *msg)
> +{
> + int ret;
> +
> + mutex_lock(&ec_dev->lock);
> + ret = ec_dev->cmd_xfer(ec_dev, msg);
> + if (msg->result == EC_RES_IN_PROGRESS) {
> + int i;
> + struct cros_ec_command *status_msg;
> + struct ec_response_get_comms_status *status;
> +
> + status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status),
> + GFP_KERNEL);
> + if (!status_msg) {
> + ret = -ENOMEM;
> + goto exit;
> + }
> +
> + status_msg->version = 0;
> + status_msg->command = EC_CMD_GET_COMMS_STATUS;
> + status_msg->insize = sizeof(*status);
> + status_msg->outsize = 0;
> +
> + /*
> + * Query the EC's status until it's no longer busy or
> + * we encounter an error.
> + */
> + for (i = 0; i < EC_COMMAND_RETRIES; i++) {
> + usleep_range(10000, 11000);
> +
> + ret = ec_dev->cmd_xfer(ec_dev, status_msg);
> + if (ret < 0)
> + break;
> +
> + msg->result = status_msg->result;
> + if (status_msg->result != EC_RES_SUCCESS)
> + break;
> +
> + status = (struct ec_response_get_comms_status *)
> + status_msg->data;
> + if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
> + break;
> + }
> +
> + kfree(status_msg);
> + }
> +exit:
> + mutex_unlock(&ec_dev->lock);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(cros_ec_cmd_xfer);

--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog