176 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Core driver for Wilco Embedded Controller4 *5 * Copyright 2018 Google LLC6 *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_new = 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");176