mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
chrome platform changes for v5.4
* CrOS EC / MFD Migration - Move cros_ec core driver from mfd into chrome platform. * Wilco EC: - Add batt_ppid_info command to Wilco telemetry driver. * CrOS EC: - cros_ec_rpmsg : Add support to inform EC of suspend/resume status - cros_ec_rpmsg : Fix race condition on probe failed - cros_ec_chardev : Add a poll handler to receive MKBP events * Misc: - bugfixes in cros_usbpd_logger and cros_ec_ishtp -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQCtZK6p/AktxXfkOlzbaomhzOwwgUCXYKpygAKCRBzbaomhzOw wlkXAP9QCKia7LiNujIl9kh7WXSloxdO0BzL93pgSpNHfUDeSAD+Mlcp+54bDqkB WaF2SR14Z2vzAFafroQTl6m41xJTog4= =slD7 -----END PGP SIGNATURE----- Merge tag 'tag-chrome-platform-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux Pull chrome platform updates from Benson Leung: "CrOS EC / MFD Migration: - Move cros_ec core driver from mfd into chrome platform. Wilco EC: - Add batt_ppid_info command to Wilco telemetry driver. CrOS EC: - cros_ec_rpmsg : Add support to inform EC of suspend/resume status - cros_ec_rpmsg : Fix race condition on probe failed - cros_ec_chardev : Add a poll handler to receive MKBP events Misc: - bugfixes in cros_usbpd_logger and cros_ec_ishtp" * tag 'tag-chrome-platform-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: platform/chrome: cros_usbpd_logger: null check create_singlethread_workqueue platform/chrome: cros_ec_chardev: Add a poll handler to receive MKBP events platform/chrome: cros_ec_rpmsg: Fix race with host command when probe failed platform/chrome: chromeos_tbmc: Report wake events mfd: cros_ec: Use mfd_add_hotplug_devices() helper mfd: cros_ec: Add convenience struct to define autodetectable CrOS EC subdevices mfd: cros_ec: Add convenience struct to define dedicated CrOS EC MCUs mfd: cros_ec: Use kzalloc and cros_ec_cmd_xfer_status helper mfd / platform: cros_ec: Reorganize platform and mfd includes mfd / platform: cros_ec: Rename config to a better name mfd: cros_ec: Switch to use the new cros-ec-chardev driver mfd / platform: cros_ec: Miscellaneous character device to talk with the EC mfd / platform: cros_ec: Move cros-ec core driver out from MFD mfd / platform: cros_ec: Handle chained ECs as platform devices platform/chrome: cros_ec_rpmsg: Add host command AP sleep state support platform/chrome: chromeos_laptop: drop checks of NULL-safe functions platform/chrome: wilco_ec: Add batt_ppid_info command to telemetry driver
This commit is contained in:
commit
32b90daf5c
@ -181,7 +181,7 @@ config EXTCON_USB_GPIO
|
||||
|
||||
config EXTCON_USBC_CROS_EC
|
||||
tristate "ChromeOS Embedded Controller EXTCON support"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
help
|
||||
Say Y here to enable USB Type C cable detection extcon support when
|
||||
using Chrome OS EC based USB Type-C ports.
|
||||
|
@ -6,10 +6,11 @@
|
||||
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
|
@ -376,7 +376,7 @@ config HOLTEK_FF
|
||||
|
||||
config HID_GOOGLE_HAMMER
|
||||
tristate "Google Hammer Keyboard"
|
||||
depends on USB_HID && LEDS_CLASS && MFD_CROS_EC
|
||||
depends on USB_HID && LEDS_CLASS && CROS_EC
|
||||
---help---
|
||||
Say Y here if you have a Google Hammer device.
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
@ -1345,7 +1345,7 @@ config I2C_SIBYTE
|
||||
|
||||
config I2C_CROS_EC_TUNNEL
|
||||
tristate "ChromeOS EC tunnel I2C bus"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
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
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -19,9 +19,10 @@
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-accel-legacy"
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
config IIO_CROS_EC_SENSORS_CORE
|
||||
tristate "ChromeOS EC Sensors Core"
|
||||
depends on SYSFS && MFD_CROS_EC
|
||||
depends on SYSFS && CROS_EC
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
|
@ -20,9 +20,8 @@
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -17,8 +17,9 @@
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -14,9 +14,10 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static char *cros_ec_loc[] = {
|
||||
|
@ -15,8 +15,9 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -15,9 +15,10 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
|
@ -736,7 +736,7 @@ config KEYBOARD_XTKBD
|
||||
config KEYBOARD_CROS_EC
|
||||
tristate "ChromeOS EC keyboard"
|
||||
select INPUT_MATRIXKMAP
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
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
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -547,10 +547,9 @@ if CEC_PLATFORM_DRIVERS
|
||||
|
||||
config VIDEO_CROS_EC_CEC
|
||||
tristate "ChromeOS EC CEC driver"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
select CEC_CORE
|
||||
select CEC_NOTIFIER
|
||||
select CHROME_PLATFORMS
|
||||
select CROS_EC_PROTO
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
|
@ -14,10 +14,11 @@
|
||||
#include <linux/cec.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/cec-notifier.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-cec"
|
||||
|
||||
|
@ -211,26 +211,18 @@ config MFD_AXP20X_RSB
|
||||
components like regulators or the PEK (Power Enable Key) under the
|
||||
corresponding menus.
|
||||
|
||||
config MFD_CROS_EC
|
||||
tristate "ChromeOS Embedded Controller"
|
||||
config MFD_CROS_EC_DEV
|
||||
tristate "ChromeOS Embedded Controller multifunction device"
|
||||
select MFD_CORE
|
||||
select CHROME_PLATFORMS
|
||||
select CROS_EC_PROTO
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
depends on CROS_EC
|
||||
default CROS_EC
|
||||
help
|
||||
If you say Y here you get support for the ChromeOS Embedded
|
||||
Controller (EC) providing keyboard, battery and power services.
|
||||
You also need to enable the driver for the bus you are using. The
|
||||
protocol for talking to the EC is defined by the bus driver.
|
||||
Select this to get support for ChromeOS Embedded Controller
|
||||
sub-devices. This driver will instantiate additional drivers such
|
||||
as RTC, USBPD, etc. but you have to select the individual drivers.
|
||||
|
||||
config MFD_CROS_EC_CHARDEV
|
||||
tristate "Chrome OS Embedded Controller userspace device interface"
|
||||
depends on MFD_CROS_EC
|
||||
---help---
|
||||
This driver adds support to talk with the ChromeOS EC from userspace.
|
||||
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called cros_ec_dev.
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called cros-ec-dev.
|
||||
|
||||
config MFD_MADERA
|
||||
tristate "Cirrus Logic Madera codecs"
|
||||
|
@ -13,9 +13,7 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
|
||||
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
||||
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
|
||||
cros_ec_core-objs := cros_ec.o
|
||||
obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
|
||||
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
|
||||
|
||||
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
|
||||
|
@ -5,73 +5,112 @@
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/platform_data/cros_ec_chardev.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "cros_ec_dev.h"
|
||||
|
||||
#define DRV_NAME "cros-ec-dev"
|
||||
|
||||
/* Device variables */
|
||||
#define CROS_MAX_DEV 128
|
||||
static int ec_major;
|
||||
|
||||
static struct class cros_class = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "chromeos",
|
||||
};
|
||||
|
||||
/* Basic communication */
|
||||
static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
|
||||
{
|
||||
struct ec_response_get_version *resp;
|
||||
static const char * const current_image_name[] = {
|
||||
"unknown", "read-only", "read-write", "invalid",
|
||||
};
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
/**
|
||||
* cros_feature_to_name - CrOS feature id to name/short description.
|
||||
* @id: The feature identifier.
|
||||
* @name: Device name associated with the feature id.
|
||||
* @desc: Short name that will be displayed.
|
||||
*/
|
||||
struct cros_feature_to_name {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
/**
|
||||
* cros_feature_to_cells - CrOS feature id to mfd cells association.
|
||||
* @id: The feature identifier.
|
||||
* @mfd_cells: Pointer to the array of mfd cells that needs to be added.
|
||||
* @num_cells: Number of mfd cells into the array.
|
||||
*/
|
||||
struct cros_feature_to_cells {
|
||||
unsigned int id;
|
||||
const struct mfd_cell *mfd_cells;
|
||||
unsigned int num_cells;
|
||||
};
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_VERSION + ec->cmd_offset;
|
||||
msg->insize = sizeof(*resp);
|
||||
msg->outsize = 0;
|
||||
static const struct cros_feature_to_name cros_mcu_devices[] = {
|
||||
{
|
||||
.id = EC_FEATURE_FINGERPRINT,
|
||||
.name = CROS_EC_DEV_FP_NAME,
|
||||
.desc = "Fingerprint",
|
||||
},
|
||||
{
|
||||
.id = EC_FEATURE_ISH,
|
||||
.name = CROS_EC_DEV_ISH_NAME,
|
||||
.desc = "Integrated Sensor Hub",
|
||||
},
|
||||
{
|
||||
.id = EC_FEATURE_SCP,
|
||||
.name = CROS_EC_DEV_SCP_NAME,
|
||||
.desc = "System Control Processor",
|
||||
},
|
||||
{
|
||||
.id = EC_FEATURE_TOUCHPAD,
|
||||
.name = CROS_EC_DEV_TP_NAME,
|
||||
.desc = "Touchpad",
|
||||
},
|
||||
};
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
static const struct mfd_cell cros_ec_cec_cells[] = {
|
||||
{ .name = "cros-ec-cec", },
|
||||
};
|
||||
|
||||
if (msg->result != EC_RES_SUCCESS) {
|
||||
snprintf(str, maxlen,
|
||||
"%s\nUnknown EC version: EC returned %d\n",
|
||||
CROS_EC_DEV_VERSION, msg->result);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
static const struct mfd_cell cros_ec_rtc_cells[] = {
|
||||
{ .name = "cros-ec-rtc", },
|
||||
};
|
||||
|
||||
resp = (struct ec_response_get_version *)msg->data;
|
||||
if (resp->current_image >= ARRAY_SIZE(current_image_name))
|
||||
resp->current_image = 3; /* invalid */
|
||||
static const struct mfd_cell cros_usbpd_charger_cells[] = {
|
||||
{ .name = "cros-usbpd-charger", },
|
||||
{ .name = "cros-usbpd-logger", },
|
||||
};
|
||||
|
||||
snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION,
|
||||
resp->version_string_ro, resp->version_string_rw,
|
||||
current_image_name[resp->current_image]);
|
||||
static const struct cros_feature_to_cells cros_subdevices[] = {
|
||||
{
|
||||
.id = EC_FEATURE_CEC,
|
||||
.mfd_cells = cros_ec_cec_cells,
|
||||
.num_cells = ARRAY_SIZE(cros_ec_cec_cells),
|
||||
},
|
||||
{
|
||||
.id = EC_FEATURE_RTC,
|
||||
.mfd_cells = cros_ec_rtc_cells,
|
||||
.num_cells = ARRAY_SIZE(cros_ec_rtc_cells),
|
||||
},
|
||||
{
|
||||
.id = EC_FEATURE_USB_PD,
|
||||
.mfd_cells = cros_usbpd_charger_cells,
|
||||
.num_cells = ARRAY_SIZE(cros_usbpd_charger_cells),
|
||||
},
|
||||
};
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
static const struct mfd_cell cros_ec_platform_cells[] = {
|
||||
{ .name = "cros-ec-chardev", },
|
||||
{ .name = "cros-ec-debugfs", },
|
||||
{ .name = "cros-ec-lightbar", },
|
||||
{ .name = "cros-ec-sysfs", },
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
@ -80,18 +119,15 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
|
||||
|
||||
if (ec->features[0] == -1U && ec->features[1] == -1U) {
|
||||
/* features bitmap not read yet */
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
|
||||
msg = kzalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
|
||||
msg->insize = sizeof(ec->features);
|
||||
msg->outsize = 0;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0 || msg->result != EC_RES_SUCCESS) {
|
||||
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));
|
||||
@ -108,142 +144,6 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
|
||||
return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
|
||||
}
|
||||
|
||||
/* Device file ops */
|
||||
static int ec_device_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cros_ec_dev *ec = container_of(inode->i_cdev,
|
||||
struct cros_ec_dev, cdev);
|
||||
filp->private_data = ec;
|
||||
nonseekable_open(inode, filp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ec_device_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ec_device_read(struct file *filp, char __user *buffer,
|
||||
size_t length, loff_t *offset)
|
||||
{
|
||||
struct cros_ec_dev *ec = filp->private_data;
|
||||
char msg[sizeof(struct ec_response_get_version) +
|
||||
sizeof(CROS_EC_DEV_VERSION)];
|
||||
size_t count;
|
||||
int ret;
|
||||
|
||||
if (*offset != 0)
|
||||
return 0;
|
||||
|
||||
ret = ec_get_version(ec, msg, sizeof(msg));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
count = min(length, strlen(msg));
|
||||
|
||||
if (copy_to_user(buffer, msg, count))
|
||||
return -EFAULT;
|
||||
|
||||
*offset = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Ioctls */
|
||||
static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
|
||||
{
|
||||
long ret;
|
||||
struct cros_ec_command u_cmd;
|
||||
struct cros_ec_command *s_cmd;
|
||||
|
||||
if (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((u_cmd.outsize > EC_MAX_MSG_BYTES) ||
|
||||
(u_cmd.insize > EC_MAX_MSG_BYTES))
|
||||
return -EINVAL;
|
||||
|
||||
s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize),
|
||||
GFP_KERNEL);
|
||||
if (!s_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) {
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (u_cmd.outsize != s_cmd->outsize ||
|
||||
u_cmd.insize != s_cmd->insize) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s_cmd->command += ec->cmd_offset;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
|
||||
/* Only copy data to userland if data was received. */
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
|
||||
ret = -EFAULT;
|
||||
exit:
|
||||
kfree(s_cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ec->ec_dev;
|
||||
struct cros_ec_readmem s_mem = { };
|
||||
long num;
|
||||
|
||||
/* Not every platform supports direct reads */
|
||||
if (!ec_dev->cmd_readmem)
|
||||
return -ENOTTY;
|
||||
|
||||
if (copy_from_user(&s_mem, arg, sizeof(s_mem)))
|
||||
return -EFAULT;
|
||||
|
||||
num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes,
|
||||
s_mem.buffer);
|
||||
if (num <= 0)
|
||||
return num;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem)))
|
||||
return -EFAULT;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static long ec_device_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct cros_ec_dev *ec = filp->private_data;
|
||||
|
||||
if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case CROS_EC_DEV_IOCXCMD:
|
||||
return ec_device_ioctl_xcmd(ec, (void __user *)arg);
|
||||
case CROS_EC_DEV_IOCRDMEM:
|
||||
return ec_device_ioctl_readmem(ec, (void __user *)arg);
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
/* Module initialization */
|
||||
static const struct file_operations fops = {
|
||||
.open = ec_device_open,
|
||||
.release = ec_device_release,
|
||||
.read = ec_device_read,
|
||||
.unlocked_ioctl = ec_device_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ec_device_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void cros_ec_class_release(struct device *dev)
|
||||
{
|
||||
kfree(to_cros_ec_dev(dev));
|
||||
@ -276,8 +176,8 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec)
|
||||
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 || msg->result != EC_RES_SUCCESS) {
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n",
|
||||
ret, msg->result);
|
||||
goto error;
|
||||
@ -304,8 +204,8 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec)
|
||||
for (i = 0; i < sensor_num; i++) {
|
||||
params->cmd = MOTIONSENSE_CMD_INFO;
|
||||
params->info.sensor_num = i;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
|
||||
if (ret < 0 || msg->result != EC_RES_SUCCESS) {
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n",
|
||||
i, ret, msg->result);
|
||||
continue;
|
||||
@ -429,37 +329,12 @@ static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec)
|
||||
* Register 2 accelerometers, we will fail in the IIO driver if there
|
||||
* are no sensors.
|
||||
*/
|
||||
ret = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_ec_accel_legacy_cells,
|
||||
ARRAY_SIZE(cros_ec_accel_legacy_cells),
|
||||
NULL, 0, NULL);
|
||||
ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells,
|
||||
ARRAY_SIZE(cros_ec_accel_legacy_cells));
|
||||
if (ret)
|
||||
dev_err(ec_dev->dev, "failed to add EC sensors\n");
|
||||
}
|
||||
|
||||
static const struct mfd_cell cros_ec_cec_cells[] = {
|
||||
{ .name = "cros-ec-cec" }
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_ec_rtc_cells[] = {
|
||||
{ .name = "cros-ec-rtc" }
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_usbpd_charger_cells[] = {
|
||||
{ .name = "cros-usbpd-charger" },
|
||||
{ .name = "cros-usbpd-logger" },
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_ec_platform_cells[] = {
|
||||
{ .name = "cros-ec-debugfs" },
|
||||
{ .name = "cros-ec-lightbar" },
|
||||
{ .name = "cros-ec-sysfs" },
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_ec_vbc_cells[] = {
|
||||
{ .name = "cros-ec-vbc" }
|
||||
};
|
||||
|
||||
static int ec_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
@ -467,6 +342,7 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_platform *ec_platform = dev_get_platdata(dev);
|
||||
struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL);
|
||||
int i;
|
||||
|
||||
if (!ec)
|
||||
return retval;
|
||||
@ -478,57 +354,27 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
ec->features[0] = -1U; /* Not cached yet */
|
||||
ec->features[1] = -1U; /* Not cached yet */
|
||||
device_initialize(&ec->class_dev);
|
||||
cdev_init(&ec->cdev, &fops);
|
||||
|
||||
/* Check whether this is actually a Fingerprint MCU rather than an EC */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) {
|
||||
dev_info(dev, "CrOS Fingerprint MCU detected.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(cros_mcu_devices); i++) {
|
||||
/*
|
||||
* Help userspace differentiating ECs from FP MCU,
|
||||
* regardless of the probing order.
|
||||
* Check whether this is actually a dedicated MCU rather
|
||||
* than an standard EC.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_FP_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether this is actually an Integrated Sensor Hub (ISH)
|
||||
* rather than an EC.
|
||||
*/
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_ISH)) {
|
||||
dev_info(dev, "CrOS ISH MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from ISH MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_ISH_NAME;
|
||||
}
|
||||
|
||||
/* Check whether this is actually a Touchpad MCU rather than an EC */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_TOUCHPAD)) {
|
||||
dev_info(dev, "CrOS Touchpad MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from TP MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_TP_NAME;
|
||||
}
|
||||
|
||||
/* Check whether this is actually a SCP rather than an EC. */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_SCP)) {
|
||||
dev_info(dev, "CrOS SCP MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from SCP,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_SCP_NAME;
|
||||
if (cros_ec_check_features(ec, cros_mcu_devices[i].id)) {
|
||||
dev_info(dev, "CrOS %s MCU detected\n",
|
||||
cros_mcu_devices[i].desc);
|
||||
/*
|
||||
* Help userspace differentiating ECs from other MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = cros_mcu_devices[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the class device
|
||||
* Link to the character device for creating the /dev entry
|
||||
* in devtmpfs.
|
||||
*/
|
||||
ec->class_dev.devt = MKDEV(ec_major, pdev->id);
|
||||
ec->class_dev.class = &cros_class;
|
||||
ec->class_dev.parent = dev;
|
||||
ec->class_dev.release = cros_ec_class_release;
|
||||
@ -539,6 +385,10 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
retval = device_add(&ec->class_dev);
|
||||
if (retval)
|
||||
goto failed;
|
||||
|
||||
/* check whether this EC is a sensor hub. */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
|
||||
cros_ec_sensors_register(ec);
|
||||
@ -546,53 +396,29 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
/* Workaroud for older EC firmware */
|
||||
cros_ec_accel_legacy_register(ec);
|
||||
|
||||
/* Check whether this EC instance has CEC host command support */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_CEC)) {
|
||||
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_ec_cec_cells,
|
||||
ARRAY_SIZE(cros_ec_cec_cells),
|
||||
NULL, 0, NULL);
|
||||
if (retval)
|
||||
dev_err(ec->dev,
|
||||
"failed to add cros-ec-cec device: %d\n",
|
||||
retval);
|
||||
/*
|
||||
* The following subdevices can be detected by sending the
|
||||
* EC_FEATURE_GET_CMD Embedded Controller device.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(cros_subdevices); i++) {
|
||||
if (cros_ec_check_features(ec, cros_subdevices[i].id)) {
|
||||
retval = mfd_add_hotplug_devices(ec->dev,
|
||||
cros_subdevices[i].mfd_cells,
|
||||
cros_subdevices[i].num_cells);
|
||||
if (retval)
|
||||
dev_err(ec->dev,
|
||||
"failed to add %s subdevice: %d\n",
|
||||
cros_subdevices[i].mfd_cells->name,
|
||||
retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether this EC instance has RTC host command support */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_RTC)) {
|
||||
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_ec_rtc_cells,
|
||||
ARRAY_SIZE(cros_ec_rtc_cells),
|
||||
NULL, 0, NULL);
|
||||
if (retval)
|
||||
dev_err(ec->dev,
|
||||
"failed to add cros-ec-rtc device: %d\n",
|
||||
retval);
|
||||
}
|
||||
|
||||
/* Check whether this EC instance has the PD charge manager */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) {
|
||||
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_usbpd_charger_cells,
|
||||
ARRAY_SIZE(cros_usbpd_charger_cells),
|
||||
NULL, 0, NULL);
|
||||
if (retval)
|
||||
dev_err(ec->dev,
|
||||
"failed to add cros-usbpd-charger device: %d\n",
|
||||
retval);
|
||||
}
|
||||
|
||||
/* We can now add the sysfs class, we know which parameter to show */
|
||||
retval = cdev_device_add(&ec->cdev, &ec->class_dev);
|
||||
if (retval) {
|
||||
dev_err(dev, "cdev_device_add failed => %d\n", retval);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_ec_platform_cells,
|
||||
ARRAY_SIZE(cros_ec_platform_cells),
|
||||
NULL, 0, NULL);
|
||||
/*
|
||||
* The following subdevices cannot be detected by sending the
|
||||
* EC_FEATURE_GET_CMD to the Embedded Controller device.
|
||||
*/
|
||||
retval = mfd_add_hotplug_devices(ec->dev, cros_ec_platform_cells,
|
||||
ARRAY_SIZE(cros_ec_platform_cells));
|
||||
if (retval)
|
||||
dev_warn(ec->dev,
|
||||
"failed to add cros-ec platform devices: %d\n",
|
||||
@ -601,10 +427,8 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
/* Check whether this EC instance has a VBC NVRAM */
|
||||
node = ec->ec_dev->dev->of_node;
|
||||
if (of_property_read_bool(node, "google,has-vbc-nvram")) {
|
||||
retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO,
|
||||
cros_ec_vbc_cells,
|
||||
ARRAY_SIZE(cros_ec_vbc_cells),
|
||||
NULL, 0, NULL);
|
||||
retval = mfd_add_hotplug_devices(ec->dev, cros_ec_vbc_cells,
|
||||
ARRAY_SIZE(cros_ec_vbc_cells));
|
||||
if (retval)
|
||||
dev_warn(ec->dev, "failed to add VBC devices: %d\n",
|
||||
retval);
|
||||
@ -622,7 +446,6 @@ static int ec_device_remove(struct platform_device *pdev)
|
||||
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
mfd_remove_devices(ec->dev);
|
||||
cdev_del(&ec->cdev);
|
||||
device_unregister(&ec->class_dev);
|
||||
return 0;
|
||||
}
|
||||
@ -645,7 +468,6 @@ static struct platform_driver cros_ec_dev_driver = {
|
||||
static int __init cros_ec_dev_init(void)
|
||||
{
|
||||
int ret;
|
||||
dev_t dev = 0;
|
||||
|
||||
ret = class_register(&cros_class);
|
||||
if (ret) {
|
||||
@ -653,14 +475,6 @@ static int __init cros_ec_dev_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get a range of minor numbers (starting with 0) to work with */
|
||||
ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME);
|
||||
if (ret < 0) {
|
||||
pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n");
|
||||
goto failed_chrdevreg;
|
||||
}
|
||||
ec_major = MAJOR(dev);
|
||||
|
||||
/* Register the driver */
|
||||
ret = platform_driver_register(&cros_ec_dev_driver);
|
||||
if (ret < 0) {
|
||||
@ -670,8 +484,6 @@ static int __init cros_ec_dev_init(void)
|
||||
return 0;
|
||||
|
||||
failed_devreg:
|
||||
unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV);
|
||||
failed_chrdevreg:
|
||||
class_unregister(&cros_class);
|
||||
return ret;
|
||||
}
|
||||
@ -679,7 +491,6 @@ failed_chrdevreg:
|
||||
static void __exit cros_ec_dev_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cros_ec_dev_driver);
|
||||
unregister_chrdev(ec_major, CROS_EC_DEV_NAME);
|
||||
class_unregister(&cros_class);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,16 @@
|
||||
# Platform support for Chrome OS hardware (Chromebooks and Chromeboxes)
|
||||
#
|
||||
|
||||
config MFD_CROS_EC
|
||||
tristate "Platform support for Chrome hardware (transitional)"
|
||||
select CHROME_PLATFORMS
|
||||
select CROS_EC
|
||||
select CONFIG_MFD_CROS_EC_DEV
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
help
|
||||
This is a transitional Kconfig option and will be removed after
|
||||
everyone enables the parts individually.
|
||||
|
||||
menuconfig CHROME_PLATFORMS
|
||||
bool "Platform support for Chrome hardware"
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
@ -50,9 +60,22 @@ config CHROMEOS_TBMC
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called chromeos_tbmc.
|
||||
|
||||
config CROS_EC
|
||||
tristate "ChromeOS Embedded Controller"
|
||||
select CROS_EC_PROTO
|
||||
depends on X86 || ARM || ARM64 || COMPILE_TEST
|
||||
help
|
||||
If you say Y here you get support for the ChromeOS Embedded
|
||||
Controller (EC) providing keyboard, battery and power services.
|
||||
You also need to enable the driver for the bus you are using. The
|
||||
protocol for talking to the EC is defined by the bus driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_ec.
|
||||
|
||||
config CROS_EC_I2C
|
||||
tristate "ChromeOS Embedded Controller (I2C)"
|
||||
depends on MFD_CROS_EC && I2C
|
||||
depends on CROS_EC && I2C
|
||||
|
||||
help
|
||||
If you say Y here, you get support for talking to the ChromeOS
|
||||
@ -62,7 +85,7 @@ config CROS_EC_I2C
|
||||
|
||||
config CROS_EC_RPMSG
|
||||
tristate "ChromeOS Embedded Controller (rpmsg)"
|
||||
depends on MFD_CROS_EC && RPMSG && OF
|
||||
depends on CROS_EC && RPMSG && OF
|
||||
help
|
||||
If you say Y here, you get support for talking to the ChromeOS EC
|
||||
through rpmsg. This uses a simple byte-level protocol with a
|
||||
@ -74,7 +97,7 @@ config CROS_EC_RPMSG
|
||||
|
||||
config CROS_EC_ISHTP
|
||||
tristate "ChromeOS Embedded Controller (ISHTP)"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
depends on INTEL_ISH_HID
|
||||
help
|
||||
If you say Y here, you get support for talking to the ChromeOS EC
|
||||
@ -87,7 +110,7 @@ config CROS_EC_ISHTP
|
||||
|
||||
config CROS_EC_SPI
|
||||
tristate "ChromeOS Embedded Controller (SPI)"
|
||||
depends on MFD_CROS_EC && SPI
|
||||
depends on CROS_EC && SPI
|
||||
|
||||
---help---
|
||||
If you say Y here, you get support for talking to the ChromeOS EC
|
||||
@ -97,7 +120,7 @@ config CROS_EC_SPI
|
||||
|
||||
config CROS_EC_LPC
|
||||
tristate "ChromeOS Embedded Controller (LPC)"
|
||||
depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
|
||||
depends on CROS_EC && ACPI && (X86 || COMPILE_TEST)
|
||||
help
|
||||
If you say Y here, you get support for talking to the ChromeOS EC
|
||||
over an LPC bus, including the LPC Microchip EC (MEC) variant.
|
||||
@ -123,10 +146,21 @@ config CROS_KBD_LED_BACKLIGHT
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_kbd_led_backlight.
|
||||
|
||||
config CROS_EC_CHARDEV
|
||||
tristate "ChromeOS EC miscdevice"
|
||||
depends on MFD_CROS_EC_DEV
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
This driver adds file operations support to talk with the
|
||||
ChromeOS EC from userspace via a character device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cros_ec_chardev.
|
||||
|
||||
config CROS_EC_LIGHTBAR
|
||||
tristate "Chromebook Pixel's lightbar support"
|
||||
depends on MFD_CROS_EC_CHARDEV
|
||||
default MFD_CROS_EC_CHARDEV
|
||||
depends on MFD_CROS_EC_DEV
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
This option exposes the Chromebook Pixel's lightbar to
|
||||
userspace.
|
||||
@ -136,8 +170,8 @@ config CROS_EC_LIGHTBAR
|
||||
|
||||
config CROS_EC_VBC
|
||||
tristate "ChromeOS EC vboot context support"
|
||||
depends on MFD_CROS_EC_CHARDEV && OF
|
||||
default MFD_CROS_EC_CHARDEV
|
||||
depends on MFD_CROS_EC_DEV && OF
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
This option exposes the ChromeOS EC vboot context nvram to
|
||||
userspace.
|
||||
@ -147,8 +181,8 @@ config CROS_EC_VBC
|
||||
|
||||
config CROS_EC_DEBUGFS
|
||||
tristate "Export ChromeOS EC internals in DebugFS"
|
||||
depends on MFD_CROS_EC_CHARDEV && DEBUG_FS
|
||||
default MFD_CROS_EC_CHARDEV
|
||||
depends on MFD_CROS_EC_DEV && DEBUG_FS
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
This option exposes the ChromeOS EC device internals to
|
||||
userspace.
|
||||
@ -158,8 +192,8 @@ config CROS_EC_DEBUGFS
|
||||
|
||||
config CROS_EC_SYSFS
|
||||
tristate "ChromeOS EC control and information through sysfs"
|
||||
depends on MFD_CROS_EC_CHARDEV && SYSFS
|
||||
default MFD_CROS_EC_CHARDEV
|
||||
depends on MFD_CROS_EC_DEV && SYSFS
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
This option exposes some sysfs attributes to control and get
|
||||
information from ChromeOS EC.
|
||||
|
@ -6,6 +6,7 @@ CFLAGS_cros_ec_trace.o:= -I$(src)
|
||||
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
|
||||
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
|
||||
obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o
|
||||
obj-$(CONFIG_CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
|
||||
obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o
|
||||
obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o
|
||||
@ -14,6 +15,7 @@ cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o
|
||||
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
|
||||
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o
|
||||
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
|
||||
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
|
||||
|
@ -838,18 +838,14 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
|
||||
i2c_dev = &cros_laptop->i2c_peripherals[i];
|
||||
info = &i2c_dev->board_info;
|
||||
|
||||
if (i2c_dev->client)
|
||||
i2c_unregister_device(i2c_dev->client);
|
||||
|
||||
if (info->properties)
|
||||
property_entries_free(info->properties);
|
||||
i2c_unregister_device(i2c_dev->client);
|
||||
property_entries_free(info->properties);
|
||||
}
|
||||
|
||||
for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
|
||||
acpi_dev = &cros_laptop->acpi_peripherals[i];
|
||||
|
||||
if (acpi_dev->properties)
|
||||
property_entries_free(acpi_dev->properties);
|
||||
property_entries_free(acpi_dev->properties);
|
||||
}
|
||||
|
||||
kfree(cros_laptop->i2c_peripherals);
|
||||
|
@ -47,6 +47,7 @@ static __maybe_unused int chromeos_tbmc_resume(struct device *dev)
|
||||
|
||||
static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event)
|
||||
{
|
||||
acpi_pm_wakeup_event(&adev->dev);
|
||||
switch (event) {
|
||||
case 0x80:
|
||||
chromeos_tbmc_query_switch(adev, adev->driver_data);
|
||||
@ -90,6 +91,7 @@ static int chromeos_tbmc_add(struct acpi_device *adev)
|
||||
dev_err(dev, "cannot register input device\n");
|
||||
return ret;
|
||||
}
|
||||
device_init_wakeup(dev, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/core.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/suspend.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@ -31,18 +31,6 @@ static struct cros_ec_platform pd_p = {
|
||||
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
|
||||
};
|
||||
|
||||
static const struct mfd_cell ec_cell = {
|
||||
.name = "cros-ec-dev",
|
||||
.platform_data = &ec_p,
|
||||
.pdata_size = sizeof(ec_p),
|
||||
};
|
||||
|
||||
static const struct mfd_cell ec_pd_cell = {
|
||||
.name = "cros-ec-dev",
|
||||
.platform_data = &pd_p,
|
||||
.pdata_size = sizeof(pd_p),
|
||||
};
|
||||
|
||||
static irqreturn_t ec_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = data;
|
||||
@ -154,38 +142,42 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
}
|
||||
}
|
||||
|
||||
err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell,
|
||||
1, NULL, ec_dev->irq, NULL);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"Failed to register Embedded Controller subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
/* Register a platform device for the main EC instance */
|
||||
ec_dev->ec = platform_device_register_data(ec_dev->dev, "cros-ec-dev",
|
||||
PLATFORM_DEVID_AUTO, &ec_p,
|
||||
sizeof(struct cros_ec_platform));
|
||||
if (IS_ERR(ec_dev->ec)) {
|
||||
dev_err(ec_dev->dev,
|
||||
"Failed to create CrOS EC platform device\n");
|
||||
return PTR_ERR(ec_dev->ec);
|
||||
}
|
||||
|
||||
if (ec_dev->max_passthru) {
|
||||
/*
|
||||
* Register a PD device as well on top of this device.
|
||||
* Register a platform device for the PD behind the main EC.
|
||||
* We make the following assumptions:
|
||||
* - behind an EC, we have a pd
|
||||
* - only one device added.
|
||||
* - the EC is responsive at init time (it is not true for a
|
||||
* sensor hub.
|
||||
* sensor hub).
|
||||
*/
|
||||
err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO,
|
||||
&ec_pd_cell, 1, NULL, ec_dev->irq, NULL);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"Failed to register Power Delivery subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
ec_dev->pd = platform_device_register_data(ec_dev->dev,
|
||||
"cros-ec-dev",
|
||||
PLATFORM_DEVID_AUTO, &pd_p,
|
||||
sizeof(struct cros_ec_platform));
|
||||
if (IS_ERR(ec_dev->pd)) {
|
||||
dev_err(ec_dev->dev,
|
||||
"Failed to create CrOS PD platform device\n");
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
return PTR_ERR(ec_dev->pd);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
err = devm_of_platform_populate(dev);
|
||||
if (err) {
|
||||
mfd_remove_devices(dev);
|
||||
platform_device_unregister(ec_dev->pd);
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
dev_err(dev, "Failed to register sub-devices\n");
|
||||
return err;
|
||||
}
|
||||
@ -206,6 +198,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_register);
|
||||
|
||||
int cros_ec_unregister(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
if (ec_dev->pd)
|
||||
platform_device_unregister(ec_dev->pd);
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_unregister);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int cros_ec_suspend(struct cros_ec_device *ec_dev)
|
||||
{
|
419
drivers/platform/chrome/cros_ec_chardev.c
Normal file
419
drivers/platform/chrome/cros_ec_chardev.c
Normal file
@ -0,0 +1,419 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Miscellaneous character driver for ChromeOS Embedded Controller
|
||||
*
|
||||
* Copyright 2014 Google, Inc.
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* This file is a rework and part of the code is ported from
|
||||
* drivers/mfd/cros_ec_dev.c that was originally written by
|
||||
* Bill Richardson.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_data/cros_ec_chardev.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-chardev"
|
||||
|
||||
/* Arbitrary bounded size for the event queue */
|
||||
#define CROS_MAX_EVENT_LEN PAGE_SIZE
|
||||
|
||||
struct chardev_data {
|
||||
struct cros_ec_dev *ec_dev;
|
||||
struct miscdevice misc;
|
||||
};
|
||||
|
||||
struct chardev_priv {
|
||||
struct cros_ec_dev *ec_dev;
|
||||
struct notifier_block notifier;
|
||||
wait_queue_head_t wait_event;
|
||||
unsigned long event_mask;
|
||||
struct list_head events;
|
||||
size_t event_len;
|
||||
};
|
||||
|
||||
struct ec_event {
|
||||
struct list_head node;
|
||||
size_t size;
|
||||
u8 event_type;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
|
||||
{
|
||||
static const char * const current_image_name[] = {
|
||||
"unknown", "read-only", "read-write", "invalid",
|
||||
};
|
||||
struct ec_response_get_version *resp;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = EC_CMD_GET_VERSION + ec->cmd_offset;
|
||||
msg->insize = sizeof(*resp);
|
||||
|
||||
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
snprintf(str, maxlen,
|
||||
"Unknown EC version, returned error: %d\n",
|
||||
msg->result);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
resp = (struct ec_response_get_version *)msg->data;
|
||||
if (resp->current_image >= ARRAY_SIZE(current_image_name))
|
||||
resp->current_image = 3; /* invalid */
|
||||
|
||||
snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION,
|
||||
resp->version_string_ro, resp->version_string_rw,
|
||||
current_image_name[resp->current_image]);
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_chardev_mkbp_event(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend,
|
||||
void *_notify)
|
||||
{
|
||||
struct chardev_priv *priv = container_of(nb, struct chardev_priv,
|
||||
notifier);
|
||||
struct cros_ec_device *ec_dev = priv->ec_dev->ec_dev;
|
||||
struct ec_event *event;
|
||||
unsigned long event_bit = 1 << ec_dev->event_data.event_type;
|
||||
int total_size = sizeof(*event) + ec_dev->event_size;
|
||||
|
||||
if (!(event_bit & priv->event_mask) ||
|
||||
(priv->event_len + total_size) > CROS_MAX_EVENT_LEN)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
event = kzalloc(total_size, GFP_KERNEL);
|
||||
if (!event)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
event->size = ec_dev->event_size;
|
||||
event->event_type = ec_dev->event_data.event_type;
|
||||
memcpy(event->data, &ec_dev->event_data.data, ec_dev->event_size);
|
||||
|
||||
spin_lock(&priv->wait_event.lock);
|
||||
list_add_tail(&event->node, &priv->events);
|
||||
priv->event_len += total_size;
|
||||
wake_up_locked(&priv->wait_event);
|
||||
spin_unlock(&priv->wait_event.lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct ec_event *cros_ec_chardev_fetch_event(struct chardev_priv *priv,
|
||||
bool fetch, bool block)
|
||||
{
|
||||
struct ec_event *event;
|
||||
int err;
|
||||
|
||||
spin_lock(&priv->wait_event.lock);
|
||||
if (!block && list_empty(&priv->events)) {
|
||||
event = ERR_PTR(-EWOULDBLOCK);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!fetch) {
|
||||
event = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = wait_event_interruptible_locked(priv->wait_event,
|
||||
!list_empty(&priv->events));
|
||||
if (err) {
|
||||
event = ERR_PTR(err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
event = list_first_entry(&priv->events, struct ec_event, node);
|
||||
list_del(&event->node);
|
||||
priv->event_len -= sizeof(*event) + event->size;
|
||||
|
||||
out:
|
||||
spin_unlock(&priv->wait_event.lock);
|
||||
return event;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device file ops
|
||||
*/
|
||||
static int cros_ec_chardev_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct miscdevice *mdev = filp->private_data;
|
||||
struct cros_ec_dev *ec_dev = dev_get_drvdata(mdev->parent);
|
||||
struct chardev_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ec_dev = ec_dev;
|
||||
filp->private_data = priv;
|
||||
INIT_LIST_HEAD(&priv->events);
|
||||
init_waitqueue_head(&priv->wait_event);
|
||||
nonseekable_open(inode, filp);
|
||||
|
||||
priv->notifier.notifier_call = cros_ec_chardev_mkbp_event;
|
||||
ret = blocking_notifier_chain_register(&ec_dev->ec_dev->event_notifier,
|
||||
&priv->notifier);
|
||||
if (ret) {
|
||||
dev_err(ec_dev->dev, "failed to register event notifier\n");
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct chardev_priv *priv = filp->private_data;
|
||||
|
||||
poll_wait(filp, &priv->wait_event, wait);
|
||||
|
||||
if (list_empty(&priv->events))
|
||||
return 0;
|
||||
|
||||
return EPOLLIN | EPOLLRDNORM;
|
||||
}
|
||||
|
||||
static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer,
|
||||
size_t length, loff_t *offset)
|
||||
{
|
||||
char msg[sizeof(struct ec_response_get_version) +
|
||||
sizeof(CROS_EC_DEV_VERSION)];
|
||||
struct chardev_priv *priv = filp->private_data;
|
||||
struct cros_ec_dev *ec_dev = priv->ec_dev;
|
||||
size_t count;
|
||||
int ret;
|
||||
|
||||
if (priv->event_mask) { /* queued MKBP event */
|
||||
struct ec_event *event;
|
||||
|
||||
event = cros_ec_chardev_fetch_event(priv, length != 0,
|
||||
!(filp->f_flags & O_NONBLOCK));
|
||||
if (IS_ERR(event))
|
||||
return PTR_ERR(event);
|
||||
/*
|
||||
* length == 0 is special - no IO is done but we check
|
||||
* for error conditions.
|
||||
*/
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
/* The event is 1 byte of type plus the payload */
|
||||
count = min(length, event->size + 1);
|
||||
ret = copy_to_user(buffer, &event->event_type, count);
|
||||
kfree(event);
|
||||
if (ret) /* the copy failed */
|
||||
return -EFAULT;
|
||||
*offset = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy behavior if no event mask is defined
|
||||
*/
|
||||
if (*offset != 0)
|
||||
return 0;
|
||||
|
||||
ret = ec_get_version(ec_dev, msg, sizeof(msg));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
count = min(length, strlen(msg));
|
||||
|
||||
if (copy_to_user(buffer, msg, count))
|
||||
return -EFAULT;
|
||||
|
||||
*offset = count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int cros_ec_chardev_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct chardev_priv *priv = filp->private_data;
|
||||
struct cros_ec_dev *ec_dev = priv->ec_dev;
|
||||
struct ec_event *event, *e;
|
||||
|
||||
blocking_notifier_chain_unregister(&ec_dev->ec_dev->event_notifier,
|
||||
&priv->notifier);
|
||||
|
||||
list_for_each_entry_safe(event, e, &priv->events, node) {
|
||||
list_del(&event->node);
|
||||
kfree(event);
|
||||
}
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ioctls
|
||||
*/
|
||||
static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
|
||||
{
|
||||
struct cros_ec_command *s_cmd;
|
||||
struct cros_ec_command u_cmd;
|
||||
long ret;
|
||||
|
||||
if (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
if (u_cmd.outsize > EC_MAX_MSG_BYTES ||
|
||||
u_cmd.insize > EC_MAX_MSG_BYTES)
|
||||
return -EINVAL;
|
||||
|
||||
s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize),
|
||||
GFP_KERNEL);
|
||||
if (!s_cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) {
|
||||
ret = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (u_cmd.outsize != s_cmd->outsize ||
|
||||
u_cmd.insize != s_cmd->insize) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s_cmd->command += ec->cmd_offset;
|
||||
ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
|
||||
/* Only copy data to userland if data was received. */
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
|
||||
ret = -EFAULT;
|
||||
exit:
|
||||
kfree(s_cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long cros_ec_chardev_ioctl_readmem(struct cros_ec_dev *ec,
|
||||
void __user *arg)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ec->ec_dev;
|
||||
struct cros_ec_readmem s_mem = { };
|
||||
long num;
|
||||
|
||||
/* Not every platform supports direct reads */
|
||||
if (!ec_dev->cmd_readmem)
|
||||
return -ENOTTY;
|
||||
|
||||
if (copy_from_user(&s_mem, arg, sizeof(s_mem)))
|
||||
return -EFAULT;
|
||||
|
||||
num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes,
|
||||
s_mem.buffer);
|
||||
if (num <= 0)
|
||||
return num;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem)))
|
||||
return -EFAULT;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct chardev_priv *priv = filp->private_data;
|
||||
struct cros_ec_dev *ec = priv->ec_dev;
|
||||
|
||||
if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
|
||||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case CROS_EC_DEV_IOCXCMD:
|
||||
return cros_ec_chardev_ioctl_xcmd(ec, (void __user *)arg);
|
||||
case CROS_EC_DEV_IOCRDMEM:
|
||||
return cros_ec_chardev_ioctl_readmem(ec, (void __user *)arg);
|
||||
case CROS_EC_DEV_IOCEVENTMASK:
|
||||
priv->event_mask = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static const struct file_operations chardev_fops = {
|
||||
.open = cros_ec_chardev_open,
|
||||
.poll = cros_ec_chardev_poll,
|
||||
.read = cros_ec_chardev_read,
|
||||
.release = cros_ec_chardev_release,
|
||||
.unlocked_ioctl = cros_ec_chardev_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = cros_ec_chardev_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int cros_ec_chardev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
|
||||
struct cros_ec_platform *ec_platform = dev_get_platdata(ec_dev->dev);
|
||||
struct chardev_data *data;
|
||||
|
||||
/* Create a char device: we want to create it anew */
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->ec_dev = ec_dev;
|
||||
data->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
data->misc.fops = &chardev_fops;
|
||||
data->misc.name = ec_platform->ec_name;
|
||||
data->misc.parent = pdev->dev.parent;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, data);
|
||||
|
||||
return misc_register(&data->misc);
|
||||
}
|
||||
|
||||
static int cros_ec_chardev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct chardev_data *data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
misc_deregister(&data->misc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver cros_ec_chardev_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = cros_ec_chardev_probe,
|
||||
.remove = cros_ec_chardev_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(cros_ec_chardev_driver);
|
||||
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
|
||||
MODULE_DESCRIPTION("ChromeOS EC Miscellaneous Character Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -8,9 +8,10 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -307,6 +307,13 @@ static int cros_ec_i2c_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = i2c_get_clientdata(client);
|
||||
|
||||
return cros_ec_unregister(ec_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cros_ec_i2c_suspend(struct device *dev)
|
||||
{
|
||||
@ -357,6 +364,7 @@ static struct i2c_driver cros_ec_driver = {
|
||||
.pm = &cros_ec_i2c_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_i2c_probe,
|
||||
.remove = cros_ec_i2c_remove,
|
||||
.id_table = cros_ec_i2c_id,
|
||||
};
|
||||
|
||||
|
@ -8,11 +8,10 @@
|
||||
// (ISH-TP).
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/intel-ish-client-if.h>
|
||||
|
||||
/*
|
||||
|
@ -9,8 +9,9 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -16,9 +16,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/suspend.h>
|
||||
@ -421,6 +421,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
|
||||
|
||||
static int cros_ec_lpc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = platform_get_drvdata(pdev);
|
||||
struct acpi_device *adev;
|
||||
|
||||
adev = ACPI_COMPANION(&pdev->dev);
|
||||
@ -428,7 +429,7 @@ static int cros_ec_lpc_remove(struct platform_device *pdev)
|
||||
acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
|
||||
cros_ec_lpc_acpi_notify);
|
||||
|
||||
return 0;
|
||||
return cros_ec_unregister(ec_dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = {
|
||||
|
@ -3,10 +3,11 @@
|
||||
//
|
||||
// Copyright (C) 2015 Google, Inc
|
||||
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -6,9 +6,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rpmsg.h>
|
||||
#include <linux/slab.h>
|
||||
@ -41,6 +41,7 @@ struct cros_ec_rpmsg {
|
||||
struct rpmsg_device *rpdev;
|
||||
struct completion xfer_ack;
|
||||
struct work_struct host_event_work;
|
||||
struct rpmsg_endpoint *ept;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -72,7 +73,6 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *ec_msg)
|
||||
{
|
||||
struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
|
||||
struct rpmsg_device *rpdev = ec_rpmsg->rpdev;
|
||||
struct ec_host_response *response;
|
||||
unsigned long timeout;
|
||||
int len;
|
||||
@ -85,7 +85,7 @@ static int cros_ec_pkt_xfer_rpmsg(struct cros_ec_device *ec_dev,
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
reinit_completion(&ec_rpmsg->xfer_ack);
|
||||
ret = rpmsg_send(rpdev->ept, ec_dev->dout, len);
|
||||
ret = rpmsg_send(ec_rpmsg->ept, ec_dev->dout, len);
|
||||
if (ret) {
|
||||
dev_err(ec_dev->dev, "rpmsg send failed\n");
|
||||
return ret;
|
||||
@ -196,11 +196,24 @@ static int cros_ec_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rpmsg_endpoint *
|
||||
cros_ec_rpmsg_create_ept(struct rpmsg_device *rpdev)
|
||||
{
|
||||
struct rpmsg_channel_info chinfo = {};
|
||||
|
||||
strscpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
|
||||
chinfo.src = rpdev->src;
|
||||
chinfo.dst = RPMSG_ADDR_ANY;
|
||||
|
||||
return rpmsg_create_ept(rpdev, cros_ec_rpmsg_callback, NULL, chinfo);
|
||||
}
|
||||
|
||||
static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
|
||||
{
|
||||
struct device *dev = &rpdev->dev;
|
||||
struct cros_ec_rpmsg *ec_rpmsg;
|
||||
struct cros_ec_device *ec_dev;
|
||||
int ret;
|
||||
|
||||
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
|
||||
if (!ec_dev)
|
||||
@ -225,7 +238,18 @@ static int cros_ec_rpmsg_probe(struct rpmsg_device *rpdev)
|
||||
INIT_WORK(&ec_rpmsg->host_event_work,
|
||||
cros_ec_rpmsg_host_event_function);
|
||||
|
||||
return cros_ec_register(ec_dev);
|
||||
ec_rpmsg->ept = cros_ec_rpmsg_create_ept(rpdev);
|
||||
if (!ec_rpmsg->ept)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_register(ec_dev);
|
||||
if (ret < 0) {
|
||||
rpmsg_destroy_ept(ec_rpmsg->ept);
|
||||
cancel_work_sync(&ec_rpmsg->host_event_work);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
|
||||
@ -233,9 +257,30 @@ static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
|
||||
struct cros_ec_device *ec_dev = dev_get_drvdata(&rpdev->dev);
|
||||
struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
|
||||
|
||||
cros_ec_unregister(ec_dev);
|
||||
rpmsg_destroy_ept(ec_rpmsg->ept);
|
||||
cancel_work_sync(&ec_rpmsg->host_event_work);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cros_ec_rpmsg_suspend(struct device *dev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
|
||||
|
||||
return cros_ec_suspend(ec_dev);
|
||||
}
|
||||
|
||||
static int cros_ec_rpmsg_resume(struct device *dev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
|
||||
|
||||
return cros_ec_resume(ec_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cros_ec_rpmsg_pm_ops, cros_ec_rpmsg_suspend,
|
||||
cros_ec_rpmsg_resume);
|
||||
|
||||
static const struct of_device_id cros_ec_rpmsg_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-rpmsg", },
|
||||
{ }
|
||||
@ -246,10 +291,10 @@ static struct rpmsg_driver cros_ec_driver_rpmsg = {
|
||||
.drv = {
|
||||
.name = "cros-ec-rpmsg",
|
||||
.of_match_table = cros_ec_rpmsg_of_match,
|
||||
.pm = &cros_ec_rpmsg_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_rpmsg_probe,
|
||||
.remove = cros_ec_rpmsg_remove,
|
||||
.callback = cros_ec_rpmsg_callback,
|
||||
};
|
||||
|
||||
module_rpmsg_driver(cros_ec_driver_rpmsg);
|
||||
|
@ -6,9 +6,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@ -785,6 +785,13 @@ static int cros_ec_spi_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = spi_get_drvdata(spi);
|
||||
|
||||
return cros_ec_unregister(ec_dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cros_ec_spi_suspend(struct device *dev)
|
||||
{
|
||||
@ -823,6 +830,7 @@ static struct spi_driver cros_ec_driver_spi = {
|
||||
.pm = &cros_ec_spi_pm_ops,
|
||||
},
|
||||
.probe = cros_ec_spi_probe,
|
||||
.remove = cros_ec_spi_remove,
|
||||
.id_table = cros_ec_spi_id,
|
||||
};
|
||||
|
||||
|
@ -9,8 +9,9 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define TRACE_SYMBOL(a) {a, #a}
|
||||
|
||||
// Generate the list using the following script:
|
||||
// sed -n 's/^#define \(EC_CMD_[[:alnum:]_]*\)\s.*/\tTRACE_SYMBOL(\1), \\/p' include/linux/mfd/cros_ec_commands.h
|
||||
// sed -n 's/^#define \(EC_CMD_[[:alnum:]_]*\)\s.*/\tTRACE_SYMBOL(\1), \\/p' include/linux/platform_data/cros_ec_commands.h
|
||||
#define EC_CMDS \
|
||||
TRACE_SYMBOL(EC_CMD_PROTO_VERSION), \
|
||||
TRACE_SYMBOL(EC_CMD_HELLO), \
|
||||
|
@ -11,8 +11,10 @@
|
||||
#if !defined(_CROS_EC_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
|
||||
#define _CROS_EC_TRACE_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/types.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/tracepoint.h>
|
||||
|
||||
|
@ -7,8 +7,9 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-vbc"
|
||||
|
@ -6,10 +6,11 @@
|
||||
*/
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
@ -209,6 +210,9 @@ static int cros_usbpd_logger_probe(struct platform_device *pd)
|
||||
/* Retrieve PD event logs periodically */
|
||||
INIT_DELAYED_WORK(&logger->log_work, cros_usbpd_log_check);
|
||||
logger->log_workqueue = create_singlethread_workqueue("cros_usbpd_log");
|
||||
if (!logger->log_workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
queue_delayed_work(logger->log_workqueue, &logger->log_work,
|
||||
CROS_USBPD_LOG_UPDATE_DELAY);
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
* the OS sends a command to the EC via a write() to a char device,
|
||||
* and can read the response with a read(). The write() request is
|
||||
* verified by the driver to ensure that it is performing only one
|
||||
* of the whitelisted commands, and that no extraneous data is
|
||||
* of the allowlisted commands, and that no extraneous data is
|
||||
* being transmitted to the EC. The response is passed directly
|
||||
* back to the reader with no modification.
|
||||
*
|
||||
@ -59,21 +59,10 @@ static DEFINE_IDA(telem_ida);
|
||||
#define WILCO_EC_TELEM_GET_TEMP_INFO 0x95
|
||||
#define WILCO_EC_TELEM_GET_TEMP_READ 0x2C
|
||||
#define WILCO_EC_TELEM_GET_BATT_EXT_INFO 0x07
|
||||
#define WILCO_EC_TELEM_GET_BATT_PPID_INFO 0x8A
|
||||
|
||||
#define TELEM_ARGS_SIZE_MAX 30
|
||||
|
||||
/**
|
||||
* struct wilco_ec_telem_request - Telemetry command and arguments sent to EC.
|
||||
* @command: One of WILCO_EC_TELEM_GET_* command codes.
|
||||
* @reserved: Must be 0.
|
||||
* @args: The first N bytes are one of telem_args_get_* structs, the rest is 0.
|
||||
*/
|
||||
struct wilco_ec_telem_request {
|
||||
u8 command;
|
||||
u8 reserved;
|
||||
u8 args[TELEM_ARGS_SIZE_MAX];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* The following telem_args_get_* structs are embedded within the |args| field
|
||||
* of wilco_ec_telem_request.
|
||||
@ -122,6 +111,32 @@ struct telem_args_get_batt_ext_info {
|
||||
u8 var_args[5];
|
||||
} __packed;
|
||||
|
||||
struct telem_args_get_batt_ppid_info {
|
||||
u8 always1; /* Should always be 1 */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct wilco_ec_telem_request - Telemetry command and arguments sent to EC.
|
||||
* @command: One of WILCO_EC_TELEM_GET_* command codes.
|
||||
* @reserved: Must be 0.
|
||||
* @args: The first N bytes are one of telem_args_get_* structs, the rest is 0.
|
||||
*/
|
||||
struct wilco_ec_telem_request {
|
||||
u8 command;
|
||||
u8 reserved;
|
||||
union {
|
||||
u8 buf[TELEM_ARGS_SIZE_MAX];
|
||||
struct telem_args_get_log get_log;
|
||||
struct telem_args_get_version get_version;
|
||||
struct telem_args_get_fan_info get_fan_info;
|
||||
struct telem_args_get_diag_info get_diag_info;
|
||||
struct telem_args_get_temp_info get_temp_info;
|
||||
struct telem_args_get_temp_read get_temp_read;
|
||||
struct telem_args_get_batt_ext_info get_batt_ext_info;
|
||||
struct telem_args_get_batt_ppid_info get_batt_ppid_info;
|
||||
} args;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* check_telem_request() - Ensure that a request from userspace is valid.
|
||||
* @rq: Request buffer copied from userspace.
|
||||
@ -133,7 +148,7 @@ struct telem_args_get_batt_ext_info {
|
||||
* We do not want to allow userspace to send arbitrary telemetry commands to
|
||||
* the EC. Therefore we check to ensure that
|
||||
* 1. The request follows the format of struct wilco_ec_telem_request.
|
||||
* 2. The supplied command code is one of the whitelisted commands.
|
||||
* 2. The supplied command code is one of the allowlisted commands.
|
||||
* 3. The request only contains the necessary data for the header and arguments.
|
||||
*/
|
||||
static int check_telem_request(struct wilco_ec_telem_request *rq,
|
||||
@ -146,25 +161,31 @@ static int check_telem_request(struct wilco_ec_telem_request *rq,
|
||||
|
||||
switch (rq->command) {
|
||||
case WILCO_EC_TELEM_GET_LOG:
|
||||
max_size += sizeof(struct telem_args_get_log);
|
||||
max_size += sizeof(rq->args.get_log);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_VERSION:
|
||||
max_size += sizeof(struct telem_args_get_version);
|
||||
max_size += sizeof(rq->args.get_version);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_FAN_INFO:
|
||||
max_size += sizeof(struct telem_args_get_fan_info);
|
||||
max_size += sizeof(rq->args.get_fan_info);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_DIAG_INFO:
|
||||
max_size += sizeof(struct telem_args_get_diag_info);
|
||||
max_size += sizeof(rq->args.get_diag_info);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_TEMP_INFO:
|
||||
max_size += sizeof(struct telem_args_get_temp_info);
|
||||
max_size += sizeof(rq->args.get_temp_info);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_TEMP_READ:
|
||||
max_size += sizeof(struct telem_args_get_temp_read);
|
||||
max_size += sizeof(rq->args.get_temp_read);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_BATT_EXT_INFO:
|
||||
max_size += sizeof(struct telem_args_get_batt_ext_info);
|
||||
max_size += sizeof(rq->args.get_batt_ext_info);
|
||||
break;
|
||||
case WILCO_EC_TELEM_GET_BATT_PPID_INFO:
|
||||
if (rq->args.get_batt_ppid_info.always1 != 1)
|
||||
return -EINVAL;
|
||||
|
||||
max_size += sizeof(rq->args.get_batt_ppid_info);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -250,6 +271,7 @@ static ssize_t telem_write(struct file *filp, const char __user *buf,
|
||||
|
||||
if (count > sizeof(sess_data->request))
|
||||
return -EMSGSIZE;
|
||||
memset(&sess_data->request, 0, sizeof(sess_data->request));
|
||||
if (copy_from_user(&sess_data->request, buf, count))
|
||||
return -EFAULT;
|
||||
ret = check_telem_request(&sess_data->request, count);
|
||||
|
@ -670,7 +670,7 @@ config CHARGER_RT9455
|
||||
|
||||
config CHARGER_CROS_USBPD
|
||||
tristate "ChromeOS EC based USBPD charger"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
default n
|
||||
help
|
||||
Say Y here to enable ChromeOS EC based USBPD charger
|
||||
|
@ -5,9 +5,10 @@
|
||||
* Copyright (c) 2014 - 2018 Google, Inc
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -145,7 +145,7 @@ config PWM_CRC
|
||||
|
||||
config PWM_CROS_EC
|
||||
tristate "ChromeOS EC PWM driver"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
help
|
||||
PWM driver for exposing a PWM attached to the ChromeOS Embedded
|
||||
Controller.
|
||||
|
@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -1274,7 +1274,7 @@ config RTC_DRV_ZYNQMP
|
||||
|
||||
config RTC_DRV_CROS_EC
|
||||
tristate "Chrome OS EC RTC driver"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
Chrome OS Embedded Controller's RTC.
|
||||
|
@ -6,8 +6,9 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -310,7 +310,6 @@ header-test- += linux/mfd/adp5520.h
|
||||
header-test- += linux/mfd/arizona/pdata.h
|
||||
header-test- += linux/mfd/as3711.h
|
||||
header-test- += linux/mfd/as3722.h
|
||||
header-test- += linux/mfd/cros_ec_commands.h
|
||||
header-test- += linux/mfd/da903x.h
|
||||
header-test- += linux/mfd/da9055/pdata.h
|
||||
header-test- += linux/mfd/da9063/pdata.h
|
||||
@ -455,6 +454,7 @@ header-test- += linux/platform_data/ata-pxa.h
|
||||
header-test- += linux/platform_data/atmel.h
|
||||
header-test- += linux/platform_data/bh1770glc.h
|
||||
header-test- += linux/platform_data/brcmfmac.h
|
||||
header-test- += linux/platform_data/cros_ec_commands.h
|
||||
header-test- += linux/platform_data/clk-u300.h
|
||||
header-test- += linux/platform_data/cyttsp4.h
|
||||
header-test- += linux/platform_data/dma-coh901318.h
|
||||
|
@ -10,7 +10,8 @@
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
|
||||
enum {
|
||||
CROS_EC_SENSOR_X,
|
||||
|
@ -8,183 +8,11 @@
|
||||
#ifndef __LINUX_MFD_CROS_EC_H
|
||||
#define __LINUX_MFD_CROS_EC_H
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define CROS_EC_DEV_NAME "cros_ec"
|
||||
#define CROS_EC_DEV_FP_NAME "cros_fp"
|
||||
#define CROS_EC_DEV_PD_NAME "cros_pd"
|
||||
#define CROS_EC_DEV_TP_NAME "cros_tp"
|
||||
#define CROS_EC_DEV_ISH_NAME "cros_ish"
|
||||
#define CROS_EC_DEV_SCP_NAME "cros_scp"
|
||||
|
||||
/*
|
||||
* The EC is unresponsive for a time after a reboot command. Add a
|
||||
* simple delay to make sure that the bus stays locked.
|
||||
*/
|
||||
#define EC_REBOOT_DELAY_MS 50
|
||||
|
||||
/*
|
||||
* Max bus-specific overhead incurred by request/responses.
|
||||
* I2C requires 1 additional byte for requests.
|
||||
* I2C requires 2 additional bytes for responses.
|
||||
* SPI requires up to 32 additional bytes for responses.
|
||||
*/
|
||||
#define EC_PROTO_VERSION_UNKNOWN 0
|
||||
#define EC_MAX_REQUEST_OVERHEAD 1
|
||||
#define EC_MAX_RESPONSE_OVERHEAD 32
|
||||
|
||||
/*
|
||||
* Command interface between EC and AP, for LPC, I2C and SPI interfaces.
|
||||
*/
|
||||
enum {
|
||||
EC_MSG_TX_HEADER_BYTES = 3,
|
||||
EC_MSG_TX_TRAILER_BYTES = 1,
|
||||
EC_MSG_TX_PROTO_BYTES = EC_MSG_TX_HEADER_BYTES +
|
||||
EC_MSG_TX_TRAILER_BYTES,
|
||||
EC_MSG_RX_PROTO_BYTES = 3,
|
||||
|
||||
/* Max length of messages for proto 2*/
|
||||
EC_PROTO2_MSG_BYTES = EC_PROTO2_MAX_PARAM_SIZE +
|
||||
EC_MSG_TX_PROTO_BYTES,
|
||||
|
||||
EC_MAX_MSG_BYTES = 64 * 1024,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_command - Information about a ChromeOS EC command.
|
||||
* @version: Command version number (often 0).
|
||||
* @command: Command to send (EC_CMD_...).
|
||||
* @outsize: Outgoing length in bytes.
|
||||
* @insize: Max number of bytes to accept from the EC.
|
||||
* @result: EC's response to the command (separate from communication failure).
|
||||
* @data: Where to put the incoming data from EC and outgoing data to EC.
|
||||
*/
|
||||
struct cros_ec_command {
|
||||
uint32_t version;
|
||||
uint32_t command;
|
||||
uint32_t outsize;
|
||||
uint32_t insize;
|
||||
uint32_t result;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_device - Information about a ChromeOS EC device.
|
||||
* @phys_name: Name of physical comms layer (e.g. 'i2c-4').
|
||||
* @dev: Device pointer for physical comms device
|
||||
* @was_wake_device: True if this device was set to wake the system from
|
||||
* sleep at the last suspend.
|
||||
* @cros_class: The class structure for this device.
|
||||
* @cmd_readmem: Direct read of the EC memory-mapped region, if supported.
|
||||
* @offset: Is within EC_LPC_ADDR_MEMMAP region.
|
||||
* @bytes: Number of bytes to read. zero means "read a string" (including
|
||||
* the trailing '\0'). At most only EC_MEMMAP_SIZE bytes can be
|
||||
* read. Caller must ensure that the buffer is large enough for the
|
||||
* result when reading a string.
|
||||
* @max_request: Max size of message requested.
|
||||
* @max_response: Max size of message response.
|
||||
* @max_passthru: Max sice of passthru message.
|
||||
* @proto_version: The protocol version used for this device.
|
||||
* @priv: Private data.
|
||||
* @irq: Interrupt to use.
|
||||
* @id: Device id.
|
||||
* @din: Input buffer (for data from EC). This buffer will always be
|
||||
* dword-aligned and include enough space for up to 7 word-alignment
|
||||
* bytes also, so we can ensure that the body of the message is always
|
||||
* dword-aligned (64-bit). We use this alignment to keep ARM and x86
|
||||
* happy. Probably word alignment would be OK, there might be a small
|
||||
* performance advantage to using dword.
|
||||
* @dout: Output buffer (for data to EC). This buffer will always be
|
||||
* dword-aligned and include enough space for up to 7 word-alignment
|
||||
* bytes also, so we can ensure that the body of the message is always
|
||||
* dword-aligned (64-bit). We use this alignment to keep ARM and x86
|
||||
* happy. Probably word alignment would be OK, there might be a small
|
||||
* performance advantage to using dword.
|
||||
* @din_size: Size of din buffer to allocate (zero to use static din).
|
||||
* @dout_size: Size of dout buffer to allocate (zero to use static dout).
|
||||
* @wake_enabled: True if this device can wake the system from sleep.
|
||||
* @suspended: True if this device had been suspended.
|
||||
* @cmd_xfer: Send command to EC and get response.
|
||||
* Returns the number of bytes received if the communication
|
||||
* succeeded, but that doesn't mean the EC was happy with the
|
||||
* command. The caller should check msg.result for the EC's result
|
||||
* code.
|
||||
* @pkt_xfer: Send packet to EC and get response.
|
||||
* @lock: One transaction at a time.
|
||||
* @mkbp_event_supported: True if this EC supports the MKBP event protocol.
|
||||
* @host_sleep_v1: True if this EC supports the sleep v1 command.
|
||||
* @event_notifier: Interrupt event notifier for transport devices.
|
||||
* @event_data: Raw payload transferred with the MKBP event.
|
||||
* @event_size: Size in bytes of the event data.
|
||||
* @host_event_wake_mask: Mask of host events that cause wake from suspend.
|
||||
*/
|
||||
struct cros_ec_device {
|
||||
/* These are used by other drivers that want to talk to the EC */
|
||||
const char *phys_name;
|
||||
struct device *dev;
|
||||
bool was_wake_device;
|
||||
struct class *cros_class;
|
||||
int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset,
|
||||
unsigned int bytes, void *dest);
|
||||
|
||||
/* These are used to implement the platform-specific interface */
|
||||
u16 max_request;
|
||||
u16 max_response;
|
||||
u16 max_passthru;
|
||||
u16 proto_version;
|
||||
void *priv;
|
||||
int irq;
|
||||
u8 *din;
|
||||
u8 *dout;
|
||||
int din_size;
|
||||
int dout_size;
|
||||
bool wake_enabled;
|
||||
bool suspended;
|
||||
int (*cmd_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
int (*pkt_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
struct mutex lock;
|
||||
bool mkbp_event_supported;
|
||||
bool host_sleep_v1;
|
||||
struct blocking_notifier_head event_notifier;
|
||||
|
||||
struct ec_response_get_next_event_v1 event_data;
|
||||
int event_size;
|
||||
u32 host_event_wake_mask;
|
||||
u32 last_resume_result;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
|
||||
* @sensor_num: Id of the sensor, as reported by the EC.
|
||||
*/
|
||||
struct cros_ec_sensor_platform {
|
||||
u8 sensor_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_platform - ChromeOS EC platform information.
|
||||
* @ec_name: Name of EC device (e.g. 'cros-ec', 'cros-pd', ...)
|
||||
* used in /dev/ and sysfs.
|
||||
* @cmd_offset: Offset to apply for each command. Set when
|
||||
* registering a device behind another one.
|
||||
*/
|
||||
struct cros_ec_platform {
|
||||
const char *ec_name;
|
||||
u16 cmd_offset;
|
||||
};
|
||||
|
||||
struct cros_ec_debugfs;
|
||||
|
||||
/**
|
||||
* struct cros_ec_dev - ChromeOS EC device entry point.
|
||||
* @class_dev: Device structure used in sysfs.
|
||||
* @cdev: Character device structure in /dev.
|
||||
* @ec_dev: cros_ec_device structure to talk to the physical device.
|
||||
* @dev: Pointer to the platform device.
|
||||
* @debug_info: cros_ec_debugfs structure for debugging information.
|
||||
@ -194,7 +22,6 @@ struct cros_ec_debugfs;
|
||||
*/
|
||||
struct cros_ec_dev {
|
||||
struct device class_dev;
|
||||
struct cdev cdev;
|
||||
struct cros_ec_device *ec_dev;
|
||||
struct device *dev;
|
||||
struct cros_ec_debugfs *debug_info;
|
||||
@ -205,123 +32,4 @@ struct cros_ec_dev {
|
||||
|
||||
#define to_cros_ec_dev(dev) container_of(dev, struct cros_ec_dev, class_dev)
|
||||
|
||||
/**
|
||||
* cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
|
||||
* @ec_dev: Device to suspend.
|
||||
*
|
||||
* This can be called by drivers to handle a suspend event.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_suspend(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
|
||||
* @ec_dev: Device to resume.
|
||||
*
|
||||
* This can be called by drivers to handle a resume event.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
|
||||
* @ec_dev: Device to register.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This is intended to be used by all ChromeOS EC drivers, but at present
|
||||
* only SPI uses it. Once LPC uses the same protocol it can start using it.
|
||||
* I2C could use it now, with a refactor of the existing code.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_check_result() - Check ec_msg->result.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to check.
|
||||
*
|
||||
* This is used by ChromeOS EC drivers to check the ec_msg->result for
|
||||
* errors and to warn about them.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_check_result(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* Call this to send a command to the ChromeOS EC. This should be used
|
||||
* instead of calling the EC's cmd_xfer() callback directly.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This function is identical to cros_ec_cmd_xfer, except it returns success
|
||||
* status only if both the command was transmitted successfully and the EC
|
||||
* replied with success status. It's not necessary to check msg->result when
|
||||
* using this function.
|
||||
*
|
||||
* Return: The number of bytes transferred on success or negative error code.
|
||||
*/
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_register() - Register a new ChromeOS EC, using the provided info.
|
||||
* @ec_dev: Device to register.
|
||||
*
|
||||
* Before calling this, allocate a pointer to a new device and then fill
|
||||
* in all the fields up to the --private-- marker.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_query_all() - Query the protocol version supported by the
|
||||
* ChromeOS EC.
|
||||
* @ec_dev: Device to register.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_query_all(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
|
||||
* @ec_dev: Device to fetch event from.
|
||||
* @wake_event: Pointer to a bool set to true upon return if the event might be
|
||||
* treated as a wake event. Ignored if null.
|
||||
*
|
||||
* Return: negative error code on errors; 0 for no data; or else number of
|
||||
* bytes received (i.e., an event was retrieved successfully). Event types are
|
||||
* written out to @ec_dev->event_data.event_type on success.
|
||||
*/
|
||||
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
|
||||
|
||||
/**
|
||||
* cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
|
||||
* @ec_dev: Device to fetch event from.
|
||||
*
|
||||
* When MKBP is supported, when the EC raises an interrupt, we collect the
|
||||
* events raised and call the functions in the ec notifier. This function
|
||||
* is a helper to know which events are raised.
|
||||
*
|
||||
* Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
|
||||
*/
|
||||
u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
|
||||
|
||||
#endif /* __LINUX_MFD_CROS_EC_H */
|
||||
|
@ -1,16 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* cros_ec_dev - expose the Chrome OS Embedded Controller to userspace
|
||||
* ChromeOS EC device interface.
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _CROS_EC_DEV_H_
|
||||
#define _CROS_EC_DEV_H_
|
||||
#ifndef _UAPI_LINUX_CROS_EC_DEV_H_
|
||||
#define _UAPI_LINUX_CROS_EC_DEV_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
|
||||
#define CROS_EC_DEV_VERSION "1.0.0"
|
||||
|
||||
@ -31,5 +33,6 @@ struct cros_ec_readmem {
|
||||
#define CROS_EC_DEV_IOC 0xEC
|
||||
#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command)
|
||||
#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem)
|
||||
#define CROS_EC_DEV_IOCEVENTMASK _IO(CROS_EC_DEV_IOC, 2)
|
||||
|
||||
#endif /* _CROS_EC_DEV_H_ */
|
319
include/linux/platform_data/cros_ec_proto.h
Normal file
319
include/linux/platform_data/cros_ec_proto.h
Normal file
@ -0,0 +1,319 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* ChromeOS Embedded Controller protocol interface.
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_CROS_EC_PROTO_H
|
||||
#define __LINUX_CROS_EC_PROTO_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
|
||||
#define CROS_EC_DEV_NAME "cros_ec"
|
||||
#define CROS_EC_DEV_FP_NAME "cros_fp"
|
||||
#define CROS_EC_DEV_ISH_NAME "cros_ish"
|
||||
#define CROS_EC_DEV_PD_NAME "cros_pd"
|
||||
#define CROS_EC_DEV_SCP_NAME "cros_scp"
|
||||
#define CROS_EC_DEV_TP_NAME "cros_tp"
|
||||
|
||||
/*
|
||||
* The EC is unresponsive for a time after a reboot command. Add a
|
||||
* simple delay to make sure that the bus stays locked.
|
||||
*/
|
||||
#define EC_REBOOT_DELAY_MS 50
|
||||
|
||||
/*
|
||||
* Max bus-specific overhead incurred by request/responses.
|
||||
* I2C requires 1 additional byte for requests.
|
||||
* I2C requires 2 additional bytes for responses.
|
||||
* SPI requires up to 32 additional bytes for responses.
|
||||
*/
|
||||
#define EC_PROTO_VERSION_UNKNOWN 0
|
||||
#define EC_MAX_REQUEST_OVERHEAD 1
|
||||
#define EC_MAX_RESPONSE_OVERHEAD 32
|
||||
|
||||
/*
|
||||
* Command interface between EC and AP, for LPC, I2C and SPI interfaces.
|
||||
*/
|
||||
enum {
|
||||
EC_MSG_TX_HEADER_BYTES = 3,
|
||||
EC_MSG_TX_TRAILER_BYTES = 1,
|
||||
EC_MSG_TX_PROTO_BYTES = EC_MSG_TX_HEADER_BYTES +
|
||||
EC_MSG_TX_TRAILER_BYTES,
|
||||
EC_MSG_RX_PROTO_BYTES = 3,
|
||||
|
||||
/* Max length of messages for proto 2*/
|
||||
EC_PROTO2_MSG_BYTES = EC_PROTO2_MAX_PARAM_SIZE +
|
||||
EC_MSG_TX_PROTO_BYTES,
|
||||
|
||||
EC_MAX_MSG_BYTES = 64 * 1024,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_command - Information about a ChromeOS EC command.
|
||||
* @version: Command version number (often 0).
|
||||
* @command: Command to send (EC_CMD_...).
|
||||
* @outsize: Outgoing length in bytes.
|
||||
* @insize: Max number of bytes to accept from the EC.
|
||||
* @result: EC's response to the command (separate from communication failure).
|
||||
* @data: Where to put the incoming data from EC and outgoing data to EC.
|
||||
*/
|
||||
struct cros_ec_command {
|
||||
uint32_t version;
|
||||
uint32_t command;
|
||||
uint32_t outsize;
|
||||
uint32_t insize;
|
||||
uint32_t result;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_device - Information about a ChromeOS EC device.
|
||||
* @phys_name: Name of physical comms layer (e.g. 'i2c-4').
|
||||
* @dev: Device pointer for physical comms device
|
||||
* @was_wake_device: True if this device was set to wake the system from
|
||||
* sleep at the last suspend.
|
||||
* @cros_class: The class structure for this device.
|
||||
* @cmd_readmem: Direct read of the EC memory-mapped region, if supported.
|
||||
* @offset: Is within EC_LPC_ADDR_MEMMAP region.
|
||||
* @bytes: Number of bytes to read. zero means "read a string" (including
|
||||
* the trailing '\0'). At most only EC_MEMMAP_SIZE bytes can be
|
||||
* read. Caller must ensure that the buffer is large enough for the
|
||||
* result when reading a string.
|
||||
* @max_request: Max size of message requested.
|
||||
* @max_response: Max size of message response.
|
||||
* @max_passthru: Max sice of passthru message.
|
||||
* @proto_version: The protocol version used for this device.
|
||||
* @priv: Private data.
|
||||
* @irq: Interrupt to use.
|
||||
* @id: Device id.
|
||||
* @din: Input buffer (for data from EC). This buffer will always be
|
||||
* dword-aligned and include enough space for up to 7 word-alignment
|
||||
* bytes also, so we can ensure that the body of the message is always
|
||||
* dword-aligned (64-bit). We use this alignment to keep ARM and x86
|
||||
* happy. Probably word alignment would be OK, there might be a small
|
||||
* performance advantage to using dword.
|
||||
* @dout: Output buffer (for data to EC). This buffer will always be
|
||||
* dword-aligned and include enough space for up to 7 word-alignment
|
||||
* bytes also, so we can ensure that the body of the message is always
|
||||
* dword-aligned (64-bit). We use this alignment to keep ARM and x86
|
||||
* happy. Probably word alignment would be OK, there might be a small
|
||||
* performance advantage to using dword.
|
||||
* @din_size: Size of din buffer to allocate (zero to use static din).
|
||||
* @dout_size: Size of dout buffer to allocate (zero to use static dout).
|
||||
* @wake_enabled: True if this device can wake the system from sleep.
|
||||
* @suspended: True if this device had been suspended.
|
||||
* @cmd_xfer: Send command to EC and get response.
|
||||
* Returns the number of bytes received if the communication
|
||||
* succeeded, but that doesn't mean the EC was happy with the
|
||||
* command. The caller should check msg.result for the EC's result
|
||||
* code.
|
||||
* @pkt_xfer: Send packet to EC and get response.
|
||||
* @lock: One transaction at a time.
|
||||
* @mkbp_event_supported: True if this EC supports the MKBP event protocol.
|
||||
* @host_sleep_v1: True if this EC supports the sleep v1 command.
|
||||
* @event_notifier: Interrupt event notifier for transport devices.
|
||||
* @event_data: Raw payload transferred with the MKBP event.
|
||||
* @event_size: Size in bytes of the event data.
|
||||
* @host_event_wake_mask: Mask of host events that cause wake from suspend.
|
||||
* @ec: The platform_device used by the mfd driver to interface with the
|
||||
* main EC.
|
||||
* @pd: The platform_device used by the mfd driver to interface with the
|
||||
* PD behind an EC.
|
||||
*/
|
||||
struct cros_ec_device {
|
||||
/* These are used by other drivers that want to talk to the EC */
|
||||
const char *phys_name;
|
||||
struct device *dev;
|
||||
bool was_wake_device;
|
||||
struct class *cros_class;
|
||||
int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset,
|
||||
unsigned int bytes, void *dest);
|
||||
|
||||
/* These are used to implement the platform-specific interface */
|
||||
u16 max_request;
|
||||
u16 max_response;
|
||||
u16 max_passthru;
|
||||
u16 proto_version;
|
||||
void *priv;
|
||||
int irq;
|
||||
u8 *din;
|
||||
u8 *dout;
|
||||
int din_size;
|
||||
int dout_size;
|
||||
bool wake_enabled;
|
||||
bool suspended;
|
||||
int (*cmd_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
int (*pkt_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
struct mutex lock;
|
||||
bool mkbp_event_supported;
|
||||
bool host_sleep_v1;
|
||||
struct blocking_notifier_head event_notifier;
|
||||
|
||||
struct ec_response_get_next_event_v1 event_data;
|
||||
int event_size;
|
||||
u32 host_event_wake_mask;
|
||||
u32 last_resume_result;
|
||||
|
||||
/* The platform devices used by the mfd driver */
|
||||
struct platform_device *ec;
|
||||
struct platform_device *pd;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_sensor_platform - ChromeOS EC sensor platform information.
|
||||
* @sensor_num: Id of the sensor, as reported by the EC.
|
||||
*/
|
||||
struct cros_ec_sensor_platform {
|
||||
u8 sensor_num;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cros_ec_platform - ChromeOS EC platform information.
|
||||
* @ec_name: Name of EC device (e.g. 'cros-ec', 'cros-pd', ...)
|
||||
* used in /dev/ and sysfs.
|
||||
* @cmd_offset: Offset to apply for each command. Set when
|
||||
* registering a device behind another one.
|
||||
*/
|
||||
struct cros_ec_platform {
|
||||
const char *ec_name;
|
||||
u16 cmd_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device.
|
||||
* @ec_dev: Device to suspend.
|
||||
*
|
||||
* This can be called by drivers to handle a suspend event.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_suspend(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_resume() - Handle a resume operation for the ChromeOS EC device.
|
||||
* @ec_dev: Device to resume.
|
||||
*
|
||||
* This can be called by drivers to handle a resume event.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_prepare_tx() - Prepare an outgoing message in the output buffer.
|
||||
* @ec_dev: Device to register.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This is intended to be used by all ChromeOS EC drivers, but at present
|
||||
* only SPI uses it. Once LPC uses the same protocol it can start using it.
|
||||
* I2C could use it now, with a refactor of the existing code.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_check_result() - Check ec_msg->result.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to check.
|
||||
*
|
||||
* This is used by ChromeOS EC drivers to check the ec_msg->result for
|
||||
* errors and to warn about them.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_check_result(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* Call this to send a command to the ChromeOS EC. This should be used
|
||||
* instead of calling the EC's cmd_xfer() callback directly.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_cmd_xfer_status() - Send a command to the ChromeOS EC.
|
||||
* @ec_dev: EC device.
|
||||
* @msg: Message to write.
|
||||
*
|
||||
* This function is identical to cros_ec_cmd_xfer, except it returns success
|
||||
* status only if both the command was transmitted successfully and the EC
|
||||
* replied with success status. It's not necessary to check msg->result when
|
||||
* using this function.
|
||||
*
|
||||
* Return: The number of bytes transferred on success or negative error code.
|
||||
*/
|
||||
int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *msg);
|
||||
|
||||
/**
|
||||
* cros_ec_register() - Register a new ChromeOS EC, using the provided info.
|
||||
* @ec_dev: Device to register.
|
||||
*
|
||||
* Before calling this, allocate a pointer to a new device and then fill
|
||||
* in all the fields up to the --private-- marker.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_unregister() - Remove a ChromeOS EC.
|
||||
* @ec_dev: Device to unregister.
|
||||
*
|
||||
* Call this to deregister a ChromeOS EC, then clean up any private data.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_unregister(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_query_all() - Query the protocol version supported by the
|
||||
* ChromeOS EC.
|
||||
* @ec_dev: Device to register.
|
||||
*
|
||||
* Return: 0 on success or negative error code.
|
||||
*/
|
||||
int cros_ec_query_all(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_get_next_event() - Fetch next event from the ChromeOS EC.
|
||||
* @ec_dev: Device to fetch event from.
|
||||
* @wake_event: Pointer to a bool set to true upon return if the event might be
|
||||
* treated as a wake event. Ignored if null.
|
||||
*
|
||||
* Return: negative error code on errors; 0 for no data; or else number of
|
||||
* bytes received (i.e., an event was retrieved successfully). Event types are
|
||||
* written out to @ec_dev->event_data.event_type on success.
|
||||
*/
|
||||
int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
|
||||
|
||||
/**
|
||||
* cros_ec_get_host_event() - Return a mask of event set by the ChromeOS EC.
|
||||
* @ec_dev: Device to fetch event from.
|
||||
*
|
||||
* When MKBP is supported, when the EC raises an interrupt, we collect the
|
||||
* events raised and call the functions in the ec notifier. This function
|
||||
* is a helper to know which events are raised.
|
||||
*
|
||||
* Return: 0 on error or non-zero bitmask of one or more EC_HOST_EVENT_*.
|
||||
*/
|
||||
u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
|
||||
|
||||
#endif /* __LINUX_CROS_EC_PROTO_H */
|
@ -51,7 +51,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_BT_SCO
|
||||
select SND_SOC_BD28623
|
||||
select SND_SOC_CQ0093VC
|
||||
select SND_SOC_CROS_EC_CODEC if MFD_CROS_EC
|
||||
select SND_SOC_CROS_EC_CODEC if CROS_EC
|
||||
select SND_SOC_CS35L32 if I2C
|
||||
select SND_SOC_CS35L33 if I2C
|
||||
select SND_SOC_CS35L34 if I2C
|
||||
@ -477,7 +477,7 @@ config SND_SOC_CQ0093VC
|
||||
|
||||
config SND_SOC_CROS_EC_CODEC
|
||||
tristate "codec driver for ChromeOS EC"
|
||||
depends on MFD_CROS_EC
|
||||
depends on CROS_EC
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
ChromeOS Embedded Controller's Audio Codec.
|
||||
|
@ -9,9 +9,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
@ -99,7 +99,7 @@ config SND_SOC_MSM8996
|
||||
|
||||
config SND_SOC_SDM845
|
||||
tristate "SoC Machine driver for SDM845 boards"
|
||||
depends on QCOM_APR && MFD_CROS_EC && I2C
|
||||
depends on QCOM_APR && CROS_EC && I2C
|
||||
select SND_SOC_QDSP6
|
||||
select SND_SOC_QCOM_COMMON
|
||||
select SND_SOC_RT5663
|
||||
|
Loading…
Reference in New Issue
Block a user