Merge tag 'ib-mfd-extcon-hid-i2c-iio-input-media-chrome-power-pwm-rtc-sound-v5.4' into chrome-platform/for-next
Immutable branch between MFD, Extcon, HID, I2C, IIO, Input, Chrome, Power, PWM, RTC and Sound to allow picking patches that depends on the series that moves some code from the MFD subsystem to platform/chrome. Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
这个提交包含在:
@@ -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
|
||||
|
281
drivers/platform/chrome/cros_ec.c
普通文件
281
drivers/platform/chrome/cros_ec.c
普通文件
@@ -0,0 +1,281 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* ChromeOS EC multi-function device
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc
|
||||
*
|
||||
* The ChromeOS EC multi function device is used to mux all the requests
|
||||
* to the EC device for its multiple features: keyboard controller,
|
||||
* battery charging and regulator control, firmware update.
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.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>
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
#define CROS_EC_DEV_PD_INDEX 1
|
||||
|
||||
static struct cros_ec_platform ec_p = {
|
||||
.ec_name = CROS_EC_DEV_NAME,
|
||||
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX),
|
||||
};
|
||||
|
||||
static struct cros_ec_platform pd_p = {
|
||||
.ec_name = CROS_EC_DEV_PD_NAME,
|
||||
.cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
|
||||
};
|
||||
|
||||
static irqreturn_t ec_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = data;
|
||||
bool wake_event = true;
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_get_next_event(ec_dev, &wake_event);
|
||||
|
||||
/*
|
||||
* Signal only if wake host events or any interrupt if
|
||||
* cros_ec_get_next_event() returned an error (default value for
|
||||
* wake_event is true)
|
||||
*/
|
||||
if (wake_event && device_may_wakeup(ec_dev->dev))
|
||||
pm_wakeup_event(ec_dev->dev, 0);
|
||||
|
||||
if (ret > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
0, ec_dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
||||
{
|
||||
int ret;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
union {
|
||||
struct ec_params_host_sleep_event req0;
|
||||
struct ec_params_host_sleep_event_v1 req1;
|
||||
struct ec_response_host_sleep_event_v1 resp1;
|
||||
} u;
|
||||
} __packed buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
if (ec_dev->host_sleep_v1) {
|
||||
buf.u.req1.sleep_event = sleep_event;
|
||||
buf.u.req1.suspend_params.sleep_timeout_ms =
|
||||
EC_HOST_SLEEP_TIMEOUT_DEFAULT;
|
||||
|
||||
buf.msg.outsize = sizeof(buf.u.req1);
|
||||
if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) ||
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
|
||||
buf.msg.insize = sizeof(buf.u.resp1);
|
||||
|
||||
buf.msg.version = 1;
|
||||
|
||||
} else {
|
||||
buf.u.req0.sleep_event = sleep_event;
|
||||
buf.msg.outsize = sizeof(buf.u.req0);
|
||||
}
|
||||
|
||||
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
|
||||
|
||||
/* For now, report failure to transition to S0ix with a warning. */
|
||||
if (ret >= 0 && ec_dev->host_sleep_v1 &&
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
|
||||
ec_dev->last_resume_result =
|
||||
buf.u.resp1.resume_response.sleep_transitions;
|
||||
|
||||
WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TIMEOUT,
|
||||
"EC detected sleep transition timeout. Total slp_s0 transitions: %d",
|
||||
buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
int err = 0;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
|
||||
|
||||
ec_dev->max_request = sizeof(struct ec_params_hello);
|
||||
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
|
||||
ec_dev->max_passthru = 0;
|
||||
|
||||
ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
|
||||
if (!ec_dev->din)
|
||||
return -ENOMEM;
|
||||
|
||||
ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
|
||||
if (!ec_dev->dout)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ec_dev->lock);
|
||||
|
||||
err = cros_ec_query_all(ec_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Cannot identify the EC: error %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (ec_dev->irq) {
|
||||
err = devm_request_threaded_irq(dev, ec_dev->irq, NULL,
|
||||
ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"chromeos-ec", ec_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d",
|
||||
ec_dev->irq, 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 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).
|
||||
*/
|
||||
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) {
|
||||
platform_device_unregister(ec_dev->pd);
|
||||
platform_device_unregister(ec_dev->ec);
|
||||
dev_err(dev, "Failed to register sub-devices\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear sleep event - this will fail harmlessly on platforms that
|
||||
* don't implement the sleep event host command.
|
||||
*/
|
||||
err = cros_ec_sleep_event(ec_dev, 0);
|
||||
if (err < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
|
||||
err);
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
int ret;
|
||||
u8 sleep_event;
|
||||
|
||||
sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
|
||||
HOST_SLEEP_EVENT_S3_SUSPEND :
|
||||
HOST_SLEEP_EVENT_S0IX_SUSPEND;
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec",
|
||||
ret);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
|
||||
|
||||
disable_irq(ec_dev->irq);
|
||||
ec_dev->was_wake_device = ec_dev->wake_enabled;
|
||||
ec_dev->suspended = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_suspend);
|
||||
|
||||
static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
while (ec_dev->mkbp_event_supported &&
|
||||
cros_ec_get_next_event(ec_dev, NULL) > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
1, ec_dev);
|
||||
}
|
||||
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
int ret;
|
||||
u8 sleep_event;
|
||||
|
||||
ec_dev->suspended = false;
|
||||
enable_irq(ec_dev->irq);
|
||||
|
||||
sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
|
||||
HOST_SLEEP_EVENT_S3_RESUME :
|
||||
HOST_SLEEP_EVENT_S0IX_RESUME;
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
|
||||
ret);
|
||||
|
||||
if (ec_dev->wake_enabled) {
|
||||
disable_irq_wake(ec_dev->irq);
|
||||
ec_dev->wake_enabled = 0;
|
||||
}
|
||||
/*
|
||||
* Let the mfd devices know about events that occur during
|
||||
* suspend. This way the clients know what to do with them.
|
||||
*/
|
||||
cros_ec_report_events_during_suspend(ec_dev);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_resume);
|
||||
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("ChromeOS EC core driver");
|
@@ -0,0 +1,252 @@
|
||||
// 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/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/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-chardev"
|
||||
|
||||
struct chardev_data {
|
||||
struct cros_ec_dev *ec_dev;
|
||||
struct miscdevice misc;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
filp->private_data = ec_dev;
|
||||
nonseekable_open(inode, filp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 cros_ec_dev *ec = filp->private_data;
|
||||
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 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 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 cros_ec_chardev_ioctl_xcmd(ec, (void __user *)arg);
|
||||
case CROS_EC_DEV_IOCRDMEM:
|
||||
return cros_ec_chardev_ioctl_readmem(ec, (void __user *)arg);
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
static const struct file_operations chardev_fops = {
|
||||
.open = cros_ec_chardev_open,
|
||||
.read = cros_ec_chardev_read,
|
||||
.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>
|
||||
@@ -233,6 +233,8 @@ 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);
|
||||
|
||||
cancel_work_sync(&ec_rpmsg->host_event_work);
|
||||
}
|
||||
|
||||
|
@@ -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>
|
||||
|
||||
|
在新工单中引用
屏蔽一个用户