File Index
Files and directories
Sign in
FILE

core.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/chrome/wilco_ec/core.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Core driver for Wilco Embedded Controller
  4 *
  5 * Copyright 2018 Google LLC
  6 *
  7 * This is the entry point for the drivers that control the Wilco EC.
  8 */
  9
 10#include <linux/acpi.h>
 11#include <linux/device.h>
 12#include <linux/ioport.h>
 13#include <linux/mod_devicetable.h>
 14#include <linux/module.h>
 15#include <linux/platform_data/wilco-ec.h>
 16#include <linux/platform_device.h>
 17
 18#include "../cros_ec_lpc_mec.h"
 19
 20#define DRV_NAME "wilco-ec"
 21
 22static struct resource *wilco_get_resource(struct platform_device *pdev,
 23					   int index)
 24{
 25	struct device *dev = &pdev->dev;
 26	struct resource *res;
 27
 28	res = platform_get_resource(pdev, IORESOURCE_IO, index);
 29	if (!res) {
 30		dev_dbg(dev, "Couldn't find IO resource %d\n", index);
 31		return res;
 32	}
 33
 34	return devm_request_region(dev, res->start, resource_size(res),
 35				   dev_name(dev));
 36}
 37
 38static int wilco_ec_probe(struct platform_device *pdev)
 39{
 40	struct device *dev = &pdev->dev;
 41	struct wilco_ec_device *ec;
 42	int ret;
 43
 44	ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
 45	if (!ec)
 46		return -ENOMEM;
 47
 48	platform_set_drvdata(pdev, ec);
 49	ec->dev = dev;
 50	mutex_init(&ec->mailbox_lock);
 51
 52	ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE;
 53	ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
 54	if (!ec->data_buffer)
 55		return -ENOMEM;
 56
 57	/* Prepare access to IO regions provided by ACPI */
 58	ec->io_data = wilco_get_resource(pdev, 0);	/* Host Data */
 59	ec->io_command = wilco_get_resource(pdev, 1);	/* Host Command */
 60	ec->io_packet = wilco_get_resource(pdev, 2);	/* MEC EMI */
 61	if (!ec->io_data || !ec->io_command || !ec->io_packet)
 62		return -ENODEV;
 63
 64	/* Initialize cros_ec register interface for communication */
 65	cros_ec_lpc_mec_init(ec->io_packet->start,
 66			     ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
 67
 68	/*
 69	 * Register a child device that will be found by the debugfs driver.
 70	 * Ignore failure.
 71	 */
 72	ec->debugfs_pdev = platform_device_register_data(dev,
 73							 "wilco-ec-debugfs",
 74							 PLATFORM_DEVID_AUTO,
 75							 NULL, 0);
 76
 77	/* Register a child device that will be found by the RTC driver. */
 78	ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec",
 79						     PLATFORM_DEVID_AUTO,
 80						     NULL, 0);
 81	if (IS_ERR(ec->rtc_pdev)) {
 82		dev_err(dev, "Failed to create RTC platform device\n");
 83		ret = PTR_ERR(ec->rtc_pdev);
 84		goto unregister_debugfs;
 85	}
 86
 87	/* Set up the keyboard backlight LEDs. */
 88	ret = wilco_keyboard_leds_init(ec);
 89	if (ret < 0) {
 90		dev_err(dev,
 91			"Failed to initialize keyboard LEDs: %d\n",
 92			ret);
 93		goto unregister_rtc;
 94	}
 95
 96	ret = wilco_ec_add_sysfs(ec);
 97	if (ret < 0) {
 98		dev_err(dev, "Failed to create sysfs entries: %d\n", ret);
 99		goto unregister_rtc;
100	}
101
102	/* Register child device to be found by charger config driver. */
103	ec->charger_pdev = platform_device_register_data(dev, "wilco-charger",
104							 PLATFORM_DEVID_AUTO,
105							 NULL, 0);
106	if (IS_ERR(ec->charger_pdev)) {
107		dev_err(dev, "Failed to create charger platform device\n");
108		ret = PTR_ERR(ec->charger_pdev);
109		goto remove_sysfs;
110	}
111
112	/* Register child device that will be found by the telemetry driver. */
113	ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
114						       PLATFORM_DEVID_AUTO,
115						       ec, sizeof(*ec));
116	if (IS_ERR(ec->telem_pdev)) {
117		dev_err(dev, "Failed to create telemetry platform device\n");
118		ret = PTR_ERR(ec->telem_pdev);
119		goto unregister_charge_config;
120	}
121
122	return 0;
123
124unregister_charge_config:
125	platform_device_unregister(ec->charger_pdev);
126remove_sysfs:
127	wilco_ec_remove_sysfs(ec);
128unregister_rtc:
129	platform_device_unregister(ec->rtc_pdev);
130unregister_debugfs:
131	if (ec->debugfs_pdev)
132		platform_device_unregister(ec->debugfs_pdev);
133	return ret;
134}
135
136static void wilco_ec_remove(struct platform_device *pdev)
137{
138	struct wilco_ec_device *ec = platform_get_drvdata(pdev);
139
140	platform_device_unregister(ec->telem_pdev);
141	platform_device_unregister(ec->charger_pdev);
142	wilco_ec_remove_sysfs(ec);
143	platform_device_unregister(ec->rtc_pdev);
144	if (ec->debugfs_pdev)
145		platform_device_unregister(ec->debugfs_pdev);
146}
147
148static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
149	{ "GOOG000C", 0 },
150	{ }
151};
152MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
153
154static const struct platform_device_id wilco_ec_id[] = {
155	{ DRV_NAME, 0 },
156	{}
157};
158MODULE_DEVICE_TABLE(platform, wilco_ec_id);
159
160static struct platform_driver wilco_ec_driver = {
161	.driver = {
162		.name = DRV_NAME,
163		.acpi_match_table = wilco_ec_acpi_device_ids,
164	},
165	.probe = wilco_ec_probe,
166	.remove = wilco_ec_remove,
167	.id_table = wilco_ec_id,
168};
169
170module_platform_driver(wilco_ec_driver);
171
172MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
173MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>");
174MODULE_LICENSE("GPL v2");
175MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");
~/ Read-only file preview.