17b3d4f44SNick Crews // SPDX-License-Identifier: GPL-2.0 27b3d4f44SNick Crews /* 37b3d4f44SNick Crews * Core driver for Wilco Embedded Controller 47b3d4f44SNick Crews * 57b3d4f44SNick Crews * Copyright 2018 Google LLC 67b3d4f44SNick Crews * 77b3d4f44SNick Crews * This is the entry point for the drivers that control the Wilco EC. 87b3d4f44SNick Crews */ 97b3d4f44SNick Crews 107b3d4f44SNick Crews #include <linux/acpi.h> 117b3d4f44SNick Crews #include <linux/device.h> 127b3d4f44SNick Crews #include <linux/ioport.h> 137b3d4f44SNick Crews #include <linux/module.h> 147b3d4f44SNick Crews #include <linux/platform_data/wilco-ec.h> 157b3d4f44SNick Crews #include <linux/platform_device.h> 167b3d4f44SNick Crews 177b3d4f44SNick Crews #include "../cros_ec_lpc_mec.h" 187b3d4f44SNick Crews 197b3d4f44SNick Crews #define DRV_NAME "wilco-ec" 207b3d4f44SNick Crews 217b3d4f44SNick Crews static struct resource *wilco_get_resource(struct platform_device *pdev, 227b3d4f44SNick Crews int index) 237b3d4f44SNick Crews { 247b3d4f44SNick Crews struct device *dev = &pdev->dev; 257b3d4f44SNick Crews struct resource *res; 267b3d4f44SNick Crews 277b3d4f44SNick Crews res = platform_get_resource(pdev, IORESOURCE_IO, index); 287b3d4f44SNick Crews if (!res) { 297b3d4f44SNick Crews dev_dbg(dev, "Couldn't find IO resource %d\n", index); 307b3d4f44SNick Crews return res; 317b3d4f44SNick Crews } 327b3d4f44SNick Crews 337b3d4f44SNick Crews return devm_request_region(dev, res->start, resource_size(res), 347b3d4f44SNick Crews dev_name(dev)); 357b3d4f44SNick Crews } 367b3d4f44SNick Crews 377b3d4f44SNick Crews static int wilco_ec_probe(struct platform_device *pdev) 387b3d4f44SNick Crews { 397b3d4f44SNick Crews struct device *dev = &pdev->dev; 407b3d4f44SNick Crews struct wilco_ec_device *ec; 410d2f2a3dSNick Crews int ret; 427b3d4f44SNick Crews 437b3d4f44SNick Crews ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL); 447b3d4f44SNick Crews if (!ec) 457b3d4f44SNick Crews return -ENOMEM; 467b3d4f44SNick Crews 477b3d4f44SNick Crews platform_set_drvdata(pdev, ec); 487b3d4f44SNick Crews ec->dev = dev; 497b3d4f44SNick Crews mutex_init(&ec->mailbox_lock); 507b3d4f44SNick Crews 512ad1f7a9SNick Crews ec->data_size = sizeof(struct wilco_ec_response) + EC_MAILBOX_DATA_SIZE; 527b3d4f44SNick Crews ec->data_buffer = devm_kzalloc(dev, ec->data_size, GFP_KERNEL); 537b3d4f44SNick Crews if (!ec->data_buffer) 547b3d4f44SNick Crews return -ENOMEM; 557b3d4f44SNick Crews 567b3d4f44SNick Crews /* Prepare access to IO regions provided by ACPI */ 577b3d4f44SNick Crews ec->io_data = wilco_get_resource(pdev, 0); /* Host Data */ 587b3d4f44SNick Crews ec->io_command = wilco_get_resource(pdev, 1); /* Host Command */ 597b3d4f44SNick Crews ec->io_packet = wilco_get_resource(pdev, 2); /* MEC EMI */ 607b3d4f44SNick Crews if (!ec->io_data || !ec->io_command || !ec->io_packet) 617b3d4f44SNick Crews return -ENODEV; 627b3d4f44SNick Crews 637b3d4f44SNick Crews /* Initialize cros_ec register interface for communication */ 647b3d4f44SNick Crews cros_ec_lpc_mec_init(ec->io_packet->start, 657b3d4f44SNick Crews ec->io_packet->start + EC_MAILBOX_DATA_SIZE); 667b3d4f44SNick Crews 67b787bb12SNick Crews /* 68b787bb12SNick Crews * Register a child device that will be found by the debugfs driver. 69b787bb12SNick Crews * Ignore failure. 70b787bb12SNick Crews */ 71b787bb12SNick Crews ec->debugfs_pdev = platform_device_register_data(dev, 72b787bb12SNick Crews "wilco-ec-debugfs", 73b787bb12SNick Crews PLATFORM_DEVID_AUTO, 74b787bb12SNick Crews NULL, 0); 75b787bb12SNick Crews 760d2f2a3dSNick Crews /* Register a child device that will be found by the RTC driver. */ 770d2f2a3dSNick Crews ec->rtc_pdev = platform_device_register_data(dev, "rtc-wilco-ec", 780d2f2a3dSNick Crews PLATFORM_DEVID_AUTO, 790d2f2a3dSNick Crews NULL, 0); 800d2f2a3dSNick Crews if (IS_ERR(ec->rtc_pdev)) { 810d2f2a3dSNick Crews dev_err(dev, "Failed to create RTC platform device\n"); 820d2f2a3dSNick Crews ret = PTR_ERR(ec->rtc_pdev); 830d2f2a3dSNick Crews goto unregister_debugfs; 840d2f2a3dSNick Crews } 850d2f2a3dSNick Crews 86119a3cb6SDaniel Campello /* Set up the keyboard backlight LEDs. */ 87119a3cb6SDaniel Campello ret = wilco_keyboard_leds_init(ec); 88119a3cb6SDaniel Campello if (ret < 0) { 89119a3cb6SDaniel Campello dev_err(dev, 90119a3cb6SDaniel Campello "Failed to initialize keyboard LEDs: %d\n", 91119a3cb6SDaniel Campello ret); 92119a3cb6SDaniel Campello goto unregister_rtc; 93119a3cb6SDaniel Campello } 94119a3cb6SDaniel Campello 954c1ca625SNick Crews ret = wilco_ec_add_sysfs(ec); 964c1ca625SNick Crews if (ret < 0) { 974c1ca625SNick Crews dev_err(dev, "Failed to create sysfs entries: %d", ret); 984c1ca625SNick Crews goto unregister_rtc; 994c1ca625SNick Crews } 1004c1ca625SNick Crews 1013c4d77b6SNick Crews /* Register child device to be found by charger config driver. */ 1023c4d77b6SNick Crews ec->charger_pdev = platform_device_register_data(dev, "wilco-charger", 1033c4d77b6SNick Crews PLATFORM_DEVID_AUTO, 1043c4d77b6SNick Crews NULL, 0); 1053c4d77b6SNick Crews if (IS_ERR(ec->charger_pdev)) { 1063c4d77b6SNick Crews dev_err(dev, "Failed to create charger platform device\n"); 1073c4d77b6SNick Crews ret = PTR_ERR(ec->charger_pdev); 1083c4d77b6SNick Crews goto remove_sysfs; 1093c4d77b6SNick Crews } 1103c4d77b6SNick Crews 1111210d1e6SNick Crews /* Register child device that will be found by the telemetry driver. */ 1121210d1e6SNick Crews ec->telem_pdev = platform_device_register_data(dev, "wilco_telem", 1131210d1e6SNick Crews PLATFORM_DEVID_AUTO, 1141210d1e6SNick Crews ec, sizeof(*ec)); 1151210d1e6SNick Crews if (IS_ERR(ec->telem_pdev)) { 1161210d1e6SNick Crews dev_err(dev, "Failed to create telemetry platform device\n"); 1171210d1e6SNick Crews ret = PTR_ERR(ec->telem_pdev); 1183c4d77b6SNick Crews goto unregister_charge_config; 1191210d1e6SNick Crews } 1201210d1e6SNick Crews 1217b3d4f44SNick Crews return 0; 1220d2f2a3dSNick Crews 1233c4d77b6SNick Crews unregister_charge_config: 1243c4d77b6SNick Crews platform_device_unregister(ec->charger_pdev); 1251210d1e6SNick Crews remove_sysfs: 1261210d1e6SNick Crews wilco_ec_remove_sysfs(ec); 1274c1ca625SNick Crews unregister_rtc: 1284c1ca625SNick Crews platform_device_unregister(ec->rtc_pdev); 1290d2f2a3dSNick Crews unregister_debugfs: 1300d2f2a3dSNick Crews if (ec->debugfs_pdev) 1310d2f2a3dSNick Crews platform_device_unregister(ec->debugfs_pdev); 1320d2f2a3dSNick Crews cros_ec_lpc_mec_destroy(); 1330d2f2a3dSNick Crews return ret; 1347b3d4f44SNick Crews } 1357b3d4f44SNick Crews 1367b3d4f44SNick Crews static int wilco_ec_remove(struct platform_device *pdev) 1377b3d4f44SNick Crews { 138b787bb12SNick Crews struct wilco_ec_device *ec = platform_get_drvdata(pdev); 139b787bb12SNick Crews 140ffd7263eSDaniel Campello platform_device_unregister(ec->telem_pdev); 1413c4d77b6SNick Crews platform_device_unregister(ec->charger_pdev); 1424c1ca625SNick Crews wilco_ec_remove_sysfs(ec); 1430d2f2a3dSNick Crews platform_device_unregister(ec->rtc_pdev); 144b787bb12SNick Crews if (ec->debugfs_pdev) 145b787bb12SNick Crews platform_device_unregister(ec->debugfs_pdev); 146b787bb12SNick Crews 1477b3d4f44SNick Crews /* Teardown cros_ec interface */ 1487b3d4f44SNick Crews cros_ec_lpc_mec_destroy(); 1497b3d4f44SNick Crews 1507b3d4f44SNick Crews return 0; 1517b3d4f44SNick Crews } 1527b3d4f44SNick Crews 1537b3d4f44SNick Crews static const struct acpi_device_id wilco_ec_acpi_device_ids[] = { 1547b3d4f44SNick Crews { "GOOG000C", 0 }, 1557b3d4f44SNick Crews { } 1567b3d4f44SNick Crews }; 1577b3d4f44SNick Crews MODULE_DEVICE_TABLE(acpi, wilco_ec_acpi_device_ids); 1587b3d4f44SNick Crews 1597b3d4f44SNick Crews static struct platform_driver wilco_ec_driver = { 1607b3d4f44SNick Crews .driver = { 1617b3d4f44SNick Crews .name = DRV_NAME, 1627b3d4f44SNick Crews .acpi_match_table = wilco_ec_acpi_device_ids, 1637b3d4f44SNick Crews }, 1647b3d4f44SNick Crews .probe = wilco_ec_probe, 1657b3d4f44SNick Crews .remove = wilco_ec_remove, 1667b3d4f44SNick Crews }; 1677b3d4f44SNick Crews 1687b3d4f44SNick Crews module_platform_driver(wilco_ec_driver); 1697b3d4f44SNick Crews 1707b3d4f44SNick Crews MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>"); 1717b3d4f44SNick Crews MODULE_AUTHOR("Duncan Laurie <dlaurie@chromium.org>"); 1727b3d4f44SNick Crews MODULE_LICENSE("GPL v2"); 1737b3d4f44SNick Crews MODULE_DESCRIPTION("ChromeOS Wilco Embedded Controller driver"); 1747b3d4f44SNick Crews MODULE_ALIAS("platform:" DRV_NAME); 175