1/* 2 * ChromeOS EC multi-function device 3 * 4 * Copyright (C) 2012 Google, Inc 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * The ChromeOS EC multi function device is used to mux all the requests 16 * to the EC device for its multiple features: keyboard controller, 17 * battery charging and regulator control, firmware update. 18 */ 19 20#include <linux/of_platform.h> 21#include <linux/interrupt.h> 22#include <linux/slab.h> 23#include <linux/module.h> 24#include <linux/mfd/core.h> 25#include <linux/mfd/cros_ec.h> 26 27#define CROS_EC_DEV_EC_INDEX 0 28#define CROS_EC_DEV_PD_INDEX 1 29 30static struct cros_ec_platform ec_p = { 31 .ec_name = CROS_EC_DEV_NAME, 32 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), 33}; 34 35static struct cros_ec_platform pd_p = { 36 .ec_name = CROS_EC_DEV_PD_NAME, 37 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), 38}; 39 40static const struct mfd_cell ec_cell = { 41 .name = "cros-ec-ctl", 42 .platform_data = &ec_p, 43 .pdata_size = sizeof(ec_p), 44}; 45 46static const struct mfd_cell ec_pd_cell = { 47 .name = "cros-ec-ctl", 48 .platform_data = &pd_p, 49 .pdata_size = sizeof(pd_p), 50}; 51 52int cros_ec_register(struct cros_ec_device *ec_dev) 53{ 54 struct device *dev = ec_dev->dev; 55 int err = 0; 56 57 ec_dev->max_request = sizeof(struct ec_params_hello); 58 ec_dev->max_response = sizeof(struct ec_response_get_protocol_info); 59 ec_dev->max_passthru = 0; 60 61 ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); 62 if (!ec_dev->din) 63 return -ENOMEM; 64 65 ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); 66 if (!ec_dev->dout) 67 return -ENOMEM; 68 69 mutex_init(&ec_dev->lock); 70 71 cros_ec_query_all(ec_dev); 72 73 err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1, 74 NULL, ec_dev->irq, NULL); 75 if (err) { 76 dev_err(dev, 77 "Failed to register Embedded Controller subdevice %d\n", 78 err); 79 return err; 80 } 81 82 if (ec_dev->max_passthru) { 83 /* 84 * Register a PD device as well on top of this device. 85 * We make the following assumptions: 86 * - behind an EC, we have a pd 87 * - only one device added. 88 * - the EC is responsive at init time (it is not true for a 89 * sensor hub. 90 */ 91 err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, 92 &ec_pd_cell, 1, NULL, ec_dev->irq, NULL); 93 if (err) { 94 dev_err(dev, 95 "Failed to register Power Delivery subdevice %d\n", 96 err); 97 return err; 98 } 99 } 100 101 if (IS_ENABLED(CONFIG_OF) && dev->of_node) { 102 err = of_platform_populate(dev->of_node, NULL, NULL, dev); 103 if (err) { 104 mfd_remove_devices(dev); 105 dev_err(dev, "Failed to register sub-devices\n"); 106 return err; 107 } 108 } 109 110 dev_info(dev, "Chrome EC device registered\n"); 111 112 return 0; 113} 114EXPORT_SYMBOL(cros_ec_register); 115 116int cros_ec_remove(struct cros_ec_device *ec_dev) 117{ 118 mfd_remove_devices(ec_dev->dev); 119 120 return 0; 121} 122EXPORT_SYMBOL(cros_ec_remove); 123 124#ifdef CONFIG_PM_SLEEP 125int cros_ec_suspend(struct cros_ec_device *ec_dev) 126{ 127 struct device *dev = ec_dev->dev; 128 129 if (device_may_wakeup(dev)) 130 ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); 131 132 disable_irq(ec_dev->irq); 133 ec_dev->was_wake_device = ec_dev->wake_enabled; 134 135 return 0; 136} 137EXPORT_SYMBOL(cros_ec_suspend); 138 139int cros_ec_resume(struct cros_ec_device *ec_dev) 140{ 141 enable_irq(ec_dev->irq); 142 143 if (ec_dev->wake_enabled) { 144 disable_irq_wake(ec_dev->irq); 145 ec_dev->wake_enabled = 0; 146 } 147 148 return 0; 149} 150EXPORT_SYMBOL(cros_ec_resume); 151 152#endif 153 154MODULE_LICENSE("GPL"); 155MODULE_DESCRIPTION("ChromeOS EC core driver"); 156