Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Core driver for Wilco Embedded Controller
0004  *
0005  * Copyright 2018 Google LLC
0006  *
0007  * This is the entry point for the drivers that control the Wilco EC.
0008  */
0009 
0010 #include <linux/acpi.h>
0011 #include <linux/device.h>
0012 #include <linux/ioport.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_data/wilco-ec.h>
0015 #include <linux/platform_device.h>
0016 
0017 #include "../cros_ec_lpc_mec.h"
0018 
0019 #define DRV_NAME "wilco-ec"
0020 
0021 static struct resource *wilco_get_resource(struct platform_device *pdev,
0022                        int index)
0023 {
0024     struct device *dev = &pdev->dev;
0025     struct resource *res;
0026 
0027     res = platform_get_resource(pdev, IORESOURCE_IO, index);
0028     if (!res) {
0029         dev_dbg(dev, "Couldn't find IO resource %d\n", index);
0030         return res;
0031     }
0032 
0033     return devm_request_region(dev, res->start, resource_size(res),
0034                    dev_name(dev));
0035 }
0036 
0037 static int wilco_ec_probe(struct platform_device *pdev)
0038 {
0039     struct device *dev = &pdev->dev;
0040     struct wilco_ec_device *ec;
0041     int ret;
0042 
0043     ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
0044     if (!ec)
0045         return -ENOMEM;
0046 
0047     platform_set_drvdata(pdev, ec);
0048     ec->dev = dev;
0049     mutex_init(&ec->mailbox_lock);
0050 
0051     ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE;
0052     ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL);
0053     if (!ec->data_buffer)
0054         return -ENOMEM;
0055 
0056     /* Prepare access to IO regions provided by ACPI */
0057     ec->io_data = wilco_get_resource(pdev, 0);  /* Host Data */
0058     ec->io_command = wilco_get_resource(pdev, 1);   /* Host Command */
0059     ec->io_packet = wilco_get_resource(pdev, 2);    /* MEC EMI */
0060     if (!ec->io_data || !ec->io_command || !ec->io_packet)
0061         return -ENODEV;
0062 
0063     /* Initialize cros_ec register interface for communication */
0064     cros_ec_lpc_mec_init(ec->io_packet->start,
0065                  ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
0066 
0067     /*
0068      * Register a child device that will be found by the debugfs driver.
0069      * Ignore failure.
0070      */
0071     ec->debugfs_pdev = platform_device_register_data(dev,
0072                              "wilco-ec-debugfs",
0073                              PLATFORM_DEVID_AUTO,
0074                              NULL, 0);
0075 
0076     /* Register a child device that will be found by the RTC driver. */
0077     ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec",
0078                              PLATFORM_DEVID_AUTO,
0079                              NULL, 0);
0080     if (IS_ERR(ec->rtc_pdev)) {
0081         dev_err(dev, "Failed to create RTC platform device\n");
0082         ret = PTR_ERR(ec->rtc_pdev);
0083         goto unregister_debugfs;
0084     }
0085 
0086     /* Set up the keyboard backlight LEDs. */
0087     ret = wilco_keyboard_leds_init(ec);
0088     if (ret < 0) {
0089         dev_err(dev,
0090             "Failed to initialize keyboard LEDs: %d\n",
0091             ret);
0092         goto unregister_rtc;
0093     }
0094 
0095     ret = wilco_ec_add_sysfs(ec);
0096     if (ret < 0) {
0097         dev_err(dev, "Failed to create sysfs entries: %d\n", ret);
0098         goto unregister_rtc;
0099     }
0100 
0101     /* Register child device to be found by charger config driver. */
0102     ec->charger_pdev = platform_device_register_data(dev, "wilco-charger",
0103                              PLATFORM_DEVID_AUTO,
0104                              NULL, 0);
0105     if (IS_ERR(ec->charger_pdev)) {
0106         dev_err(dev, "Failed to create charger platform device\n");
0107         ret = PTR_ERR(ec->charger_pdev);
0108         goto remove_sysfs;
0109     }
0110 
0111     /* Register child device that will be found by the telemetry driver. */
0112     ec->telem_pdev = platform_device_register_data(dev, "wilco_telem",
0113                                PLATFORM_DEVID_AUTO,
0114                                ec, sizeof(*ec));
0115     if (IS_ERR(ec->telem_pdev)) {
0116         dev_err(dev, "Failed to create telemetry platform device\n");
0117         ret = PTR_ERR(ec->telem_pdev);
0118         goto unregister_charge_config;
0119     }
0120 
0121     return 0;
0122 
0123 unregister_charge_config:
0124     platform_device_unregister(ec->charger_pdev);
0125 remove_sysfs:
0126     wilco_ec_remove_sysfs(ec);
0127 unregister_rtc:
0128     platform_device_unregister(ec->rtc_pdev);
0129 unregister_debugfs:
0130     if (ec->debugfs_pdev)
0131         platform_device_unregister(ec->debugfs_pdev);
0132     cros_ec_lpc_mec_destroy();
0133     return ret;
0134 }
0135 
0136 static int wilco_ec_remove(struct platform_device *pdev)
0137 {
0138     struct wilco_ec_device *ec = platform_get_drvdata(pdev);
0139 
0140     platform_device_unregister(ec->telem_pdev);
0141     platform_device_unregister(ec->charger_pdev);
0142     wilco_ec_remove_sysfs(ec);
0143     platform_device_unregister(ec->rtc_pdev);
0144     if (ec->debugfs_pdev)
0145         platform_device_unregister(ec->debugfs_pdev);
0146 
0147     /* Teardown cros_ec interface */
0148     cros_ec_lpc_mec_destroy();
0149 
0150     return 0;
0151 }
0152 
0153 static const struct acpi_device_id wilco_ec_acpi_device_ids[] = {
0154     { "GOOG000C", 0 },
0155     { }
0156 };
0157 MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids);
0158 
0159 static struct platform_driver wilco_ec_driver = {
0160     .driver = {
0161         .name = DRV_NAME,
0162         .acpi_match_table = wilco_ec_acpi_device_ids,
0163     },
0164     .probe = wilco_ec_probe,
0165     .remove = wilco_ec_remove,
0166 };
0167 
0168 module_platform_driver(wilco_ec_driver);
0169 
0170 MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
0171 MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>");
0172 MODULE_LICENSE("GPL v2");
0173 MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver");
0174 MODULE_ALIAS("platform:" DRV_NAME);