1 // SPDX-License-Identifier: GPL-2.0
3 * Core driver for Wilco Embedded Controller
5 * Copyright 2018 Google LLC
7 * This is the entry point for the drivers that control the Wilco EC.
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>
18 #include "../cros_ec_lpc_mec.h"
20 #define DRV_NAME "wilco-ec"
22 static struct resource *wilco_get_resource(struct platform_device *pdev,
25 struct device *dev = &pdev->dev;
28 res = platform_get_resource(pdev, IORESOURCE_IO, index);
30 dev_dbg(dev, "Couldn't find IO resource %d\n", index);
34 return devm_request_region(dev, res->start, resource_size(res),
38 static int wilco_ec_probe(struct platform_device *pdev)
40 struct device *dev = &pdev->dev;
41 struct wilco_ec_device *ec;
44 ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
48 platform_set_drvdata(pdev, ec);
50 mutex_init(&ec->mailbox_lock);
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);
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)
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);
69 * Register a child device that will be found by the debugfs driver.
72 ec->debugfs_pdev = platform_device_register_data(dev,
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",
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;
87 /* Set up the keyboard backlight LEDs. */
88 ret = wilco_keyboard_leds_init(ec);
91 "Failed to initialize keyboard LEDs: %d\n",
96 ret = wilco_ec_add_sysfs(ec);
98 dev_err(dev, "Failed to create sysfs entries: %d\n", ret);
102 /* Register child device to be found by charger config driver. */
103 ec->charger_pdev = platform_device_register_data(dev, "wilco-charger",
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);
112 /* Register child device that will be found by the telemetry driver. */
113 ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
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;
124 unregister_charge_config:
125 platform_device_unregister(ec->charger_pdev);
127 wilco_ec_remove_sysfs(ec);
129 platform_device_unregister(ec->rtc_pdev);
131 if (ec->debugfs_pdev)
132 platform_device_unregister(ec->debugfs_pdev);
136 static void wilco_ec_remove(struct platform_device *pdev)
138 struct wilco_ec_device *ec = platform_get_drvdata(pdev);
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);
148 static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
152 MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
154 static const struct platform_device_id wilco_ec_id[] = {
158 MODULE_DEVICE_TABLE(platform, wilco_ec_id);
160 static struct platform_driver wilco_ec_driver = {
163 .acpi_match_table = wilco_ec_acpi_device_ids,
165 .probe = wilco_ec_probe,
166 .remove_new = wilco_ec_remove,
167 .id_table = wilco_ec_id,
170 module_platform_driver(wilco_ec_driver);
174 MODULE_LICENSE("GPL v2");
175 MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");