drivers/watchdog/cros_ec_wdt.c

Source file repositories/reference/linux-study-clean/drivers/watchdog/cros_ec_wdt.c

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/cros_ec_wdt.c
Extension
.c
Size
5212 bytes
Lines
201
Domain
Driver Families
Bucket
drivers/watchdog
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2024 Google LLC.
 * Author: Lukasz Majczak <lma@chromium.com>
 */

#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>

#define CROS_EC_WATCHDOG_DEFAULT_TIME	30 /* seconds */
#define DRV_NAME	"cros-ec-wdt"

union cros_ec_wdt_data {
	struct ec_params_hang_detect req;
	struct ec_response_hang_detect resp;
} __packed;

static int cros_ec_wdt_send_cmd(struct cros_ec_device *cros_ec,
				union cros_ec_wdt_data *arg)
{
	int ret;
	DEFINE_RAW_FLEX(struct cros_ec_command, msg, data,
			sizeof(union cros_ec_wdt_data));

	msg->version = 0;
	msg->command = EC_CMD_HANG_DETECT;
	msg->insize  = (arg->req.command == EC_HANG_DETECT_CMD_GET_STATUS) ?
		   sizeof(struct ec_response_hang_detect) :
		   0;
	msg->outsize = sizeof(struct ec_params_hang_detect);
	*(struct ec_params_hang_detect *)msg->data = arg->req;

	ret = cros_ec_cmd_xfer_status(cros_ec, msg);
	if (ret < 0)
		return ret;

	arg->resp = *(struct ec_response_hang_detect *)msg->data;

	return 0;
}

static int cros_ec_wdt_ping(struct watchdog_device *wdd)
{
	struct cros_ec_device *cros_ec = watchdog_get_drvdata(wdd);
	union cros_ec_wdt_data arg;
	int ret;

	arg.req.command = EC_HANG_DETECT_CMD_RELOAD;
	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);
	if (ret < 0)
		dev_dbg(wdd->parent, "Failed to ping watchdog (%d)\n", ret);

	return ret;
}

static int cros_ec_wdt_start(struct watchdog_device *wdd)
{
	struct cros_ec_device *cros_ec = watchdog_get_drvdata(wdd);
	union cros_ec_wdt_data arg;
	int ret;

	/* Prepare watchdog on EC side */
	arg.req.command = EC_HANG_DETECT_CMD_SET_TIMEOUT;
	arg.req.reboot_timeout_sec = wdd->timeout;
	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);
	if (ret < 0)
		dev_dbg(wdd->parent, "Failed to start watchdog (%d)\n", ret);

	return ret;
}

static int cros_ec_wdt_stop(struct watchdog_device *wdd)
{
	struct cros_ec_device *cros_ec = watchdog_get_drvdata(wdd);
	union cros_ec_wdt_data arg;
	int ret;

	arg.req.command = EC_HANG_DETECT_CMD_CANCEL;
	ret = cros_ec_wdt_send_cmd(cros_ec, &arg);
	if (ret < 0)
		dev_dbg(wdd->parent, "Failed to stop watchdog (%d)\n", ret);

	return ret;
}

Annotation

Implementation Notes