Commit 5bb3bf24 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tag-chrome-platform-for-v5.20' of...

Merge tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux

Pull chrome platform updates from Tzung-Bi Shih:
 "cros_ec_proto:
   - Leverage Kunit and add Kunit test cases
   - Clean-ups
   - Fix typo

  cros_ec_commands:
   - Fix typo
   - Fix compile errors

  cros_kbd_led_backlight:
   - Support OF match
   - Support EC PWM backend

  cros_ec:
   - Always expose the last resume result to fix sleep hang detection on
     ARM-based chromebooks

  wilco_ec:
   - Fix typo

  cros_ec_typec:
   - Clean-ups
   - Use Type-C framework utilities to manage altmode structs"

* tag 'tag-chrome-platform-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux: (59 commits)
  platform/chrome: cros_kunit_util: add default value for `msg->result`
  platform/chrome: merge Kunit utils and test cases
  platform/chrome: cros_kbd_led_backlight: fix build warning
  platform/chrome: cros_ec_proto: add Kunit test for cros_ec_cmd()
  platform/chrome: cros_ec_proto: add Kunit tests for get_sensor_count
  platform/chrome: cros_ec_proto: add Kunit tests for check_features
  platform/chrome: cros_ec_proto: add Kunit tests for get_host_event
  platform/chrome: cros_ec_proto: add Kunit tests for get_next_event
  platform/chrome: cros_ec_proto: add Kunit test for cros_ec_map_error()
  platform/chrome: cros_ec_proto: add Kunit tests for cmd_xfer_status
  platform/chrome: cros_ec_proto: return -EPROTO if empty payload
  platform/chrome: cros_ec_proto: add Kunit test for empty payload
  platform/chrome: cros_ec_proto: return -EAGAIN when retries timed out
  platform/chrome: cros_ec_proto: change Kunit expectation when timed out
  platform/chrome: cros_ec_proto: separate cros_ec_wait_until_complete()
  platform/chrome: cros_ec_proto: separate cros_ec_xfer_command()
  platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_send_command()
  platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_cmd_xfer()
  platform/chrome: cros_ec_proto: add "cros_ec_" prefix to send_command()
  platform/chrome: cros_ec_typec: Register port altmodes
  ...
parents da8d07af afef1e1a
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/chrome/google,cros-kbd-led-backlight.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ChromeOS keyboard backlight LED driver.
maintainers:
- Tzung-Bi Shih <tzungbi@kernel.org>
properties:
compatible:
const: google,cros-kbd-led-backlight
required:
- compatible
additionalProperties: false
examples:
- |
spi0 {
#address-cells = <1>;
#size-cells = <0>;
cros_ec: ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
kbd-led-backlight {
compatible = "google,cros-kbd-led-backlight";
};
};
};
......@@ -90,6 +90,9 @@ properties:
pwm:
$ref: "/schemas/pwm/google,cros-ec-pwm.yaml#"
kbd-led-backlight:
$ref: "/schemas/chrome/google,cros-kbd-led-backlight.yaml#"
keyboard-controller:
$ref: "/schemas/input/google,cros-ec-keyb.yaml#"
......
......@@ -250,8 +250,8 @@ static int ec_device_probe(struct platform_device *pdev)
* The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but
* it can be detected by querying the number of peripheral chargers.
*/
retval = cros_ec_command(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
&pchg_count, sizeof(pchg_count));
retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0,
&pchg_count, sizeof(pchg_count));
if (retval >= 0 && pchg_count.port_count) {
retval = mfd_add_hotplug_devices(ec->dev,
cros_ec_pchg_cells,
......
......@@ -139,7 +139,7 @@ config CROS_EC_PROTO
config CROS_KBD_LED_BACKLIGHT
tristate "Backlight LED support for Chrome OS keyboards"
depends on LEDS_CLASS && ACPI
depends on LEDS_CLASS && (ACPI || CROS_EC)
help
This option enables support for the keyboard backlight LEDs on
select Chrome OS systems.
......@@ -267,4 +267,13 @@ config CHROMEOS_PRIVACY_SCREEN
source "drivers/platform/chrome/wilco_ec/Kconfig"
# Kunit test cases
config CROS_KUNIT
tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS
depends on KUNIT && CROS_EC
default KUNIT_ALL_TESTS
select CROS_EC_PROTO
help
ChromeOS Kunit tests.
endif # CHROMEOS_PLATFORMS
......@@ -30,3 +30,8 @@ obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o
obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o
obj-$(CONFIG_WILCO_EC) += wilco_ec/
# Kunit test cases
obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o
cros_kunit-objs := cros_kunit_util.o
cros_kunit-objs += cros_ec_proto_test.o
......@@ -19,9 +19,6 @@
#include "cros_ec.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),
......@@ -135,16 +132,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
/* For now, report failure to transition to S0ix with a warning. */
/* Report failure to transition to system wide suspend with a warning. */
if (ret >= 0 && ec_dev->host_sleep_v1 &&
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) {
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME ||
sleep_event == HOST_SLEEP_EVENT_S3_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",
"EC detected sleep transition timeout. Total sleep transitions: %d",
buf.u.resp1.resume_response.sleep_transitions &
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -30,8 +30,8 @@ TRACE_EVENT(cros_ec_request_start,
),
TP_fast_assign(
__entry->version = cmd->version;
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
),
......@@ -55,8 +55,8 @@ TRACE_EVENT(cros_ec_request_done,
),
TP_fast_assign(
__entry->version = cmd->version;
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1);
__entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX);
__entry->outsize = cmd->outsize;
__entry->insize = cmd->insize;
__entry->result = cmd->result;
......
......@@ -25,6 +25,8 @@
#define DRV_NAME "cros-ec-typec"
#define DP_PORT_VDO (BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D) | DP_CAP_DFP_D)
/* Supported alt modes. */
enum {
CROS_EC_ALTMODE_DP = 0,
......@@ -60,8 +62,7 @@ struct cros_typec_port {
uint8_t mux_flags;
uint8_t role;
/* Port alt modes. */
struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX];
struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
/* Flag indicating that PD partner discovery data parsing is completed. */
bool sop_disc_done;
......@@ -254,6 +255,14 @@ static void cros_typec_remove_cable(struct cros_typec_data *typec,
port->sop_prime_disc_done = false;
}
static void cros_typec_unregister_port_altmodes(struct cros_typec_port *port)
{
int i;
for (i = 0; i < CROS_EC_ALTMODE_MAX; i++)
typec_unregister_altmode(port->port_altmode[i]);
}
static void cros_unregister_ports(struct cros_typec_data *typec)
{
int i;
......@@ -268,34 +277,49 @@ static void cros_unregister_ports(struct cros_typec_data *typec)
usb_role_switch_put(typec->ports[i]->role_sw);
typec_switch_put(typec->ports[i]->ori_sw);
typec_mux_put(typec->ports[i]->mux);
cros_typec_unregister_port_altmodes(typec->ports[i]);
typec_unregister_port(typec->ports[i]->port);
}
}
/*
* Fake the alt mode structs until we actually start registering Type C port
* and partner alt modes.
* Register port alt modes with known values till we start retrieving
* port capabilities from the EC.
*/
static void cros_typec_register_port_altmodes(struct cros_typec_data *typec,
static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
int port_num)
{
struct cros_typec_port *port = typec->ports[port_num];
struct typec_altmode_desc desc;
struct typec_altmode *amode;
/* All PD capable CrOS devices are assumed to support DP altmode. */
port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID;
port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE;
desc.svid = USB_TYPEC_DP_SID,
desc.mode = USB_TYPEC_DP_MODE,
desc.vdo = DP_PORT_VDO,
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
/*
* Register TBT compatibility alt mode. The EC will not enter the mode
* if it doesn't support it, so it's safe to register it unconditionally
* here for now.
*/
port->p_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID;
port->p_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE;
memset(&desc, 0, sizeof(desc));
desc.svid = USB_TYPEC_TBT_SID,
desc.mode = TYPEC_ANY_MODE,
amode = typec_port_register_altmode(port->port, &desc);
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
port->state.data = NULL;
return 0;
}
static int cros_typec_init_ports(struct cros_typec_data *typec)
......@@ -352,8 +376,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
cros_port->port = typec_register_port(dev, cap);
if (IS_ERR(cros_port->port)) {
dev_err(dev, "Failed to register port %d\n", port_num);
ret = PTR_ERR(cros_port->port);
dev_err_probe(dev, ret, "Failed to register port %d\n", port_num);
goto unregister_ports;
}
......@@ -362,7 +386,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
dev_dbg(dev, "No switch control for port %d\n",
port_num);
cros_typec_register_port_altmodes(typec, port_num);
ret = cros_typec_register_port_altmodes(typec, port_num);
if (ret) {
dev_err(dev, "Failed to register port altmodes\n");
goto unregister_ports;
}
cros_port->disc_data = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL);
if (!cros_port->disc_data) {
......@@ -431,7 +459,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec,
data.enter_vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
if (!port->state.alt) {
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_TBT];
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_TBT];
ret = cros_typec_usb_safe_state(port);
if (ret)
return ret;
......@@ -473,7 +501,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec,
/* Configuration VDO. */
dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode);
if (!port->state.alt) {
port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP];
port->state.alt = port->port_altmode[CROS_EC_ALTMODE_DP];
ret = cros_typec_usb_safe_state(port);
if (ret)
return ret;
......@@ -525,8 +553,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
enum typec_orientation orientation;
int ret;
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
&req, sizeof(req), &resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO,
&req, sizeof(req), &resp, sizeof(resp));
if (ret < 0) {
dev_warn(typec->dev, "Failed to get mux info for port: %d, err = %d\n",
port_num, ret);
......@@ -585,8 +613,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num,
/* Sending Acknowledgment to EC */
mux_ack.port = port_num;
if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
sizeof(mux_ack), NULL, 0) < 0)
if (cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack,
sizeof(mux_ack), NULL, 0) < 0)
dev_warn(typec->dev,
"Failed to send Mux ACK to EC for port: %d\n",
port_num);
......@@ -754,8 +782,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p
int ret = 0;
memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
disc, EC_PROTO2_MAX_RESPONSE_SIZE);
if (ret < 0) {
dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num);
goto sop_prime_disc_exit;
......@@ -837,8 +865,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu
typec_partner_set_pd_revision(port->partner, pd_revision);
memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req),
sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE);
if (ret < 0) {
dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num);
goto disc_exit;
......@@ -870,8 +898,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n
.clear_events_mask = events_mask,
};
return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
sizeof(req), NULL, 0);
return cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
sizeof(req), NULL, 0);
}
static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num)
......@@ -882,8 +910,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
};
int ret;
ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req),
&resp, sizeof(resp));
if (ret < 0) {
dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num);
return;
......@@ -960,9 +988,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
req.mux = USB_PD_CTRL_MUX_NO_CHANGE;
req.swap = USB_PD_CTRL_SWAP_NONE;
ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver,
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, typec->pd_ctrl_ver,
EC_CMD_USB_PD_CONTROL, &req, sizeof(req),
&resp, sizeof(resp));
if (ret < 0)
return ret;
......@@ -997,9 +1025,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec)
/* We're interested in the PD control command version. */
req_v1.cmd = EC_CMD_USB_PD_CONTROL;
ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
&req_v1, sizeof(req_v1), &resp,
sizeof(resp));
ret = cros_ec_cmd(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS,
&req_v1, sizeof(req_v1), &resp, sizeof(resp));
if (ret < 0)
return ret;
......@@ -1090,8 +1117,8 @@ static int cros_typec_probe(struct platform_device *pdev)
typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD);
typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK);
ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
&resp, sizeof(resp));
ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0,
&resp, sizeof(resp));
if (ret < 0)
return ret;
......
......@@ -4,24 +4,60 @@
// Copyright (C) 2012 Google, Inc.
#include <linux/acpi.h>
#include <linux/leds.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.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/property.h>
#include <linux/slab.h>
struct keyboard_led {
struct led_classdev cdev;
struct cros_ec_device *ec;
};
/**
* struct keyboard_led_drvdata - keyboard LED driver data.
* @init: Init function.
* @brightness_get: Get LED brightness level.
* @brightness_set: Set LED brightness level. Must not sleep.
* @brightness_set_blocking: Set LED brightness level. It can block the
* caller for the time required for accessing a
* LED device register
* @max_brightness: Maximum brightness.
*
* See struct led_classdev in include/linux/leds.h for more details.
*/
struct keyboard_led_drvdata {
int (*init)(struct platform_device *pdev);
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
int (*brightness_set_blocking)(struct led_classdev *led_cdev,
enum led_brightness brightness);
enum led_brightness max_brightness;
};
#define KEYBOARD_BACKLIGHT_MAX 100
#ifdef CONFIG_ACPI
/* Keyboard LED ACPI Device must be defined in firmware */
#define ACPI_KEYBOARD_BACKLIGHT_DEVICE "\\_SB.KBLT"
#define ACPI_KEYBOARD_BACKLIGHT_READ ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBQC"
#define ACPI_KEYBOARD_BACKLIGHT_WRITE ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBCM"
#define ACPI_KEYBOARD_BACKLIGHT_MAX 100
static void keyboard_led_set_brightness(struct led_classdev *cdev,
enum led_brightness brightness)
static void keyboard_led_set_brightness_acpi(struct led_classdev *cdev,
enum led_brightness brightness)
{
union acpi_object param;
struct acpi_object_list input;
......@@ -40,7 +76,7 @@ static void keyboard_led_set_brightness(struct led_classdev *cdev,
}
static enum led_brightness
keyboard_led_get_brightness(struct led_classdev *cdev)
keyboard_led_get_brightness_acpi(struct led_classdev *cdev)
{
unsigned long long brightness;
acpi_status status;
......@@ -56,12 +92,10 @@ keyboard_led_get_brightness(struct led_classdev *cdev)
return brightness;
}
static int keyboard_led_probe(struct platform_device *pdev)
static int keyboard_led_init_acpi(struct platform_device *pdev)
{
struct led_classdev *cdev;
acpi_handle handle;
acpi_status status;
int error;
/* Look for the keyboard LED ACPI Device */
status = acpi_get_handle(ACPI_ROOT_OBJECT,
......@@ -73,33 +107,151 @@ static int keyboard_led_probe(struct platform_device *pdev)
return -ENXIO;
}
cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return 0;
}
static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = {
.init = keyboard_led_init_acpi,
.brightness_set = keyboard_led_set_brightness_acpi,
.brightness_get = keyboard_led_get_brightness_acpi,
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
#endif /* CONFIG_ACPI */
#if IS_ENABLED(CONFIG_CROS_EC)
static int
keyboard_led_set_brightness_ec_pwm(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct {
struct cros_ec_command msg;
struct ec_params_pwm_set_keyboard_backlight params;
} __packed buf;
struct ec_params_pwm_set_keyboard_backlight *params = &buf.params;
struct cros_ec_command *msg = &buf.msg;
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
memset(&buf, 0, sizeof(buf));
msg->command = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT;
msg->outsize = sizeof(*params);
params->percent = brightness;
return cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
}
static enum led_brightness
keyboard_led_get_brightness_ec_pwm(struct led_classdev *cdev)
{
struct {
struct cros_ec_command msg;
struct ec_response_pwm_get_keyboard_backlight resp;
} __packed buf;
struct ec_response_pwm_get_keyboard_backlight *resp = &buf.resp;
struct cros_ec_command *msg = &buf.msg;
struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev);
int ret;
memset(&buf, 0, sizeof(buf));
msg->command = EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT;
msg->insize = sizeof(*resp);
ret = cros_ec_cmd_xfer_status(keyboard_led->ec, msg);
if (ret < 0)
return ret;
return resp->percent;
}
static int keyboard_led_init_ec_pwm(struct platform_device *pdev)
{
struct keyboard_led *keyboard_led = platform_get_drvdata(pdev);
keyboard_led->ec = dev_get_drvdata(pdev->dev.parent);
if (!keyboard_led->ec) {
dev_err(&pdev->dev, "no parent EC device\n");
return -EINVAL;
}
return 0;
}
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {
.init = keyboard_led_init_ec_pwm,
.brightness_set_blocking = keyboard_led_set_brightness_ec_pwm,
.brightness_get = keyboard_led_get_brightness_ec_pwm,
.max_brightness = KEYBOARD_BACKLIGHT_MAX,
};
#else /* IS_ENABLED(CONFIG_CROS_EC) */
static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {};
#endif /* IS_ENABLED(CONFIG_CROS_EC) */
static int keyboard_led_probe(struct platform_device *pdev)
{
const struct keyboard_led_drvdata *drvdata;
struct keyboard_led *keyboard_led;
int error;
drvdata = device_get_match_data(&pdev->dev);
if (!drvdata)
return -EINVAL;
keyboard_led = devm_kzalloc(&pdev->dev, sizeof(*keyboard_led), GFP_KERNEL);
if (!keyboard_led)
return -ENOMEM;
platform_set_drvdata(pdev, keyboard_led);
if (drvdata->init) {
error = drvdata->init(pdev);
if (error)
return error;
}
cdev->name = "chromeos::kbd_backlight";
cdev->max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX;
cdev->flags |= LED_CORE_SUSPENDRESUME;
cdev->brightness_set = keyboard_led_set_brightness;
cdev->brightness_get = keyboard_led_get_brightness;
keyboard_led->cdev.name = "chromeos::kbd_backlight";
keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME;
keyboard_led->cdev.max_brightness = drvdata->max_brightness;
keyboard_led->cdev.brightness_set = drvdata->brightness_set;
keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking;
keyboard_led->cdev.brightness_get = drvdata->brightness_get;
error = devm_led_classdev_register(&pdev->dev, cdev);
error = devm_led_classdev_register(&pdev->dev, &keyboard_led->cdev);
if (error)
return error;
return 0;
}
static const struct acpi_device_id keyboard_led_id[] = {
{ "GOOG0002", 0 },
#ifdef CONFIG_ACPI
static const struct acpi_device_id keyboard_led_acpi_match[] = {
{ "GOOG0002", (kernel_ulong_t)&keyboard_led_drvdata_acpi },
{ }
};
MODULE_DEVICE_TABLE(acpi, keyboard_led_id);
MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match);
#endif
#ifdef CONFIG_OF
static const struct of_device_id keyboard_led_of_match[] = {
{
.compatible = "google,cros-kbd-led-backlight",
.data = &keyboard_led_drvdata_ec_pwm,
},
{}
};
MODULE_DEVICE_TABLE(of, keyboard_led_of_match);
#endif
static struct platform_driver keyboard_led_driver = {
.driver = {
.name = "chromeos-keyboard-leds",
.acpi_match_table = ACPI_PTR(keyboard_led_id),
.acpi_match_table = ACPI_PTR(keyboard_led_acpi_match),
.of_match_table = of_match_ptr(keyboard_led_of_match),
},
.probe = keyboard_led_probe,
};
......
// SPDX-License-Identifier: GPL-2.0
/*
* CrOS Kunit tests utilities.
*/
#include <kunit/test.h>
#include <linux/list.h>
#include <linux/minmax.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include "cros_ec.h"
#include "cros_kunit_util.h"
int cros_kunit_ec_xfer_mock_default_result;
int cros_kunit_ec_xfer_mock_default_ret;
int cros_kunit_ec_cmd_xfer_mock_called;
int cros_kunit_ec_pkt_xfer_mock_called;
static struct list_head cros_kunit_ec_xfer_mock_in;
static struct list_head cros_kunit_ec_xfer_mock_out;
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
struct ec_xfer_mock *mock;
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_in, struct ec_xfer_mock, list);
if (!mock) {
msg->result = cros_kunit_ec_xfer_mock_default_result;
return cros_kunit_ec_xfer_mock_default_ret;
}
list_del(&mock->list);
memcpy(&mock->msg, msg, sizeof(*msg));
if (msg->outsize) {
mock->i_data = kunit_kzalloc(mock->test, msg->outsize, GFP_KERNEL);
if (mock->i_data)
memcpy(mock->i_data, msg->data, msg->outsize);
}
msg->result = mock->result;
if (msg->insize)
memcpy(msg->data, mock->o_data, min(msg->insize, mock->o_data_len));
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_out);
return mock->ret;
}
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
++cros_kunit_ec_cmd_xfer_mock_called;
return cros_kunit_ec_xfer_mock(ec_dev, msg);
}
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg)
{
++cros_kunit_ec_pkt_xfer_mock_called;
return cros_kunit_ec_xfer_mock(ec_dev, msg);
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size)
{
return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size);
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
int ret, int result, size_t size)
{
struct ec_xfer_mock *mock;
mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
if (!mock)
return NULL;
list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_in);
mock->test = test;
mock->ret = ret;
mock->result = result;
mock->o_data = kunit_kzalloc(test, size, GFP_KERNEL);
if (!mock->o_data)
return NULL;
mock->o_data_len = size;
return mock;
}
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void)
{
struct ec_xfer_mock *mock;
mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_out, struct ec_xfer_mock, list);
if (mock)
list_del(&mock->list);
return mock;
}
int cros_kunit_readmem_mock_offset;
u8 *cros_kunit_readmem_mock_data;
int cros_kunit_readmem_mock_ret;
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
unsigned int bytes, void *dest)
{
cros_kunit_readmem_mock_offset = offset;
memcpy(dest, cros_kunit_readmem_mock_data, bytes);
return cros_kunit_readmem_mock_ret;
}
void cros_kunit_mock_reset(void)
{
cros_kunit_ec_xfer_mock_default_result = 0;
cros_kunit_ec_xfer_mock_default_ret = 0;
cros_kunit_ec_cmd_xfer_mock_called = 0;
cros_kunit_ec_pkt_xfer_mock_called = 0;
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in);
INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out);
cros_kunit_readmem_mock_offset = 0;
cros_kunit_readmem_mock_data = NULL;
cros_kunit_readmem_mock_ret = 0;
}
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* CrOS Kunit tests utilities.
*/
#ifndef _CROS_KUNIT_UTIL_H_
#define _CROS_KUNIT_UTIL_H_
#include <linux/platform_data/cros_ec_proto.h>
struct ec_xfer_mock {
struct list_head list;
struct kunit *test;
/* input */
struct cros_ec_command msg;
void *i_data;
/* output */
int ret;
int result;
void *o_data;
u32 o_data_len;
};
extern int cros_kunit_ec_xfer_mock_default_result;
extern int cros_kunit_ec_xfer_mock_default_ret;
extern int cros_kunit_ec_cmd_xfer_mock_called;
extern int cros_kunit_ec_pkt_xfer_mock_called;
int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test,
int ret, int result, size_t size);
struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void);
extern int cros_kunit_readmem_mock_offset;
extern u8 *cros_kunit_readmem_mock_data;
extern int cros_kunit_readmem_mock_ret;
int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset,
unsigned int bytes, void *dest);
void cros_kunit_mock_reset(void);
#endif
......@@ -71,8 +71,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev,
}
/* Check for PD host events on EC. */
ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
NULL, 0, &host_event_status, sizeof(host_event_status));
ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS,
NULL, 0, &host_event_status, sizeof(host_event_status));
if (ret < 0) {
dev_warn(dev, "Can't get host event status (err: %d)\n", ret);
goto send_notify;
......
......@@ -343,7 +343,7 @@ static __poll_t event_poll(struct file *filp, poll_table *wait)
*
* Removes the first event from the queue, places it in the passed buffer.
*
* If there are no events in the the queue, then one of two things happens,
* If there are no events in the queue, then one of two things happens,
* depending on if the file was opened in nonblocking mode: If in nonblocking
* mode, then return -EAGAIN to say there's no data. If in blocking mode, then
* block until an event is available.
......
......@@ -22,36 +22,6 @@ struct cros_ec_regulator_data {
u16 num_voltages;
};
static int cros_ec_cmd(struct cros_ec_device *ec, u32 version, u32 command,
void *outdata, u32 outsize, void *indata, u32 insize)
{
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
if (!msg)
return -ENOMEM;
msg->version = version;
msg->command = command;
msg->outsize = outsize;
msg->insize = insize;
if (outdata && outsize > 0)
memcpy(msg->data, outdata, outsize);
ret = cros_ec_cmd_xfer_status(ec, msg);
if (ret < 0)
goto cleanup;
if (insize)
memcpy(indata, msg->data, insize);
cleanup:
kfree(msg);
return ret;
}
static int cros_ec_regulator_enable(struct regulator_dev *dev)
{
struct cros_ec_regulator_data *data = rdev_get_drvdata(dev);
......@@ -61,7 +31,7 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev)
};
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
sizeof(cmd), NULL, 0);
sizeof(cmd), NULL, 0);
}
static int cros_ec_regulator_disable(struct regulator_dev *dev)
......@@ -73,7 +43,7 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev)
};
return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd,
sizeof(cmd), NULL, 0);
sizeof(cmd), NULL, 0);
}
static int cros_ec_regulator_is_enabled(struct regulator_dev *dev)
......@@ -161,7 +131,7 @@ static int cros_ec_regulator_init_info(struct device *dev,
int ret;
ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd,
sizeof(cmd), &resp, sizeof(resp));
sizeof(cmd), &resp, sizeof(resp));
if (ret < 0)
return ret;
......
......@@ -13,8 +13,8 @@
#ifndef __CROS_EC_COMMANDS_H
#define __CROS_EC_COMMANDS_H
#include <linux/bits.h>
#include <linux/types.h>
#define BUILD_ASSERT(_cond)
......@@ -787,7 +787,7 @@ struct ec_host_response {
*
* Packets always start with a request or response header. They are followed
* by data_len bytes of data. If the data_crc_present flag is set, the data
* bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1
* bytes are followed by a CRC-8 of that data, using x^8 + x^2 + x + 1
* polynomial.
*
* Host algorithm when sending a request q:
......
......@@ -21,6 +21,9 @@
#define CROS_EC_DEV_SCP_NAME "cros_scp"
#define CROS_EC_DEV_TP_NAME "cros_tp"
#define CROS_EC_DEV_EC_INDEX 0
#define CROS_EC_DEV_PD_INDEX 1
/*
* The EC is unresponsive for a time after a reboot command. Add a
* simple delay to make sure that the bus stays locked.
......@@ -231,8 +234,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature);
int cros_ec_get_sensor_count(struct cros_ec_dev *ec);
int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
int outsize, void *indata, int insize);
int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata,
size_t outsize, void *indata, size_t insize);
/**
* cros_ec_get_time_ns() - Return time in ns.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment