0001
0002
0003
0004
0005
0006
0007
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
0057 ec->io_data = wilco_get_resource(pdev, 0);
0058 ec->io_command = wilco_get_resource(pdev, 1);
0059 ec->io_packet = wilco_get_resource(pdev, 2);
0060 if (!ec->io_data || !ec->io_command || !ec->io_packet)
0061 return -ENODEV;
0062
0063
0064 cros_ec_lpc_mec_init(ec->io_packet->start,
0065 ec->io_packet->start + EC_MAILBOX_DATA_SIZE);
0066
0067
0068
0069
0070
0071 ec->debugfs_pdev = platform_device_register_data(dev,
0072 "wilco-ec-debugfs",
0073 PLATFORM_DEVID_AUTO,
0074 NULL, 0);
0075
0076
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
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
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
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
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);