1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ChromeOS EC multi-function device 4 * 5 * Copyright (C) 2012 Google, Inc 6 * 7 * The ChromeOS EC multi function device is used to mux all the requests 8 * to the EC device for its multiple features: keyboard controller, 9 * battery charging and regulator control, firmware update. 10 */ 11 12 #include <linux/of_platform.h> 13 #include <linux/interrupt.h> 14 #include <linux/slab.h> 15 #include <linux/module.h> 16 #include <linux/platform_data/cros_ec_commands.h> 17 #include <linux/platform_data/cros_ec_proto.h> 18 #include <linux/suspend.h> 19 #include <asm/unaligned.h> 20 21 #define CROS_EC_DEV_EC_INDEX 0 22 #define CROS_EC_DEV_PD_INDEX 1 23 24 static struct cros_ec_platform ec_p = { 25 .ec_name = CROS_EC_DEV_NAME, 26 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), 27 }; 28 29 static struct cros_ec_platform pd_p = { 30 .ec_name = CROS_EC_DEV_PD_NAME, 31 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), 32 }; 33 34 static irqreturn_t ec_irq_handler(int irq, void *data) 35 { 36 struct cros_ec_device *ec_dev = data; 37 38 ec_dev->last_event_time = cros_ec_get_time_ns(); 39 40 return IRQ_WAKE_THREAD; 41 } 42 43 /** 44 * cros_ec_handle_event() - process and forward pending events on EC 45 * @ec_dev: Device with events to process. 46 * 47 * Call this function in a loop when the kernel is notified that the EC has 48 * pending events. 49 * 50 * Return: true if more events are still pending and this function should be 51 * called again. 52 */ 53 bool cros_ec_handle_event(struct cros_ec_device *ec_dev) 54 { 55 bool wake_event; 56 bool ec_has_more_events; 57 int ret; 58 59 ret = cros_ec_get_next_event(ec_dev, &wake_event, &ec_has_more_events); 60 61 /* 62 * Signal only if wake host events or any interrupt if 63 * cros_ec_get_next_event() returned an error (default value for 64 * wake_event is true) 65 */ 66 if (wake_event && device_may_wakeup(ec_dev->dev)) 67 pm_wakeup_event(ec_dev->dev, 0); 68 69 if (ret > 0) 70 blocking_notifier_call_chain(&ec_dev->event_notifier, 71 0, ec_dev); 72 73 return ec_has_more_events; 74 } 75 EXPORT_SYMBOL(cros_ec_handle_event); 76 77 static irqreturn_t ec_irq_thread(int irq, void *data) 78 { 79 struct cros_ec_device *ec_dev = data; 80 bool ec_has_more_events; 81 82 do { 83 ec_has_more_events = cros_ec_handle_event(ec_dev); 84 } while (ec_has_more_events); 85 86 return IRQ_HANDLED; 87 } 88 89 static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) 90 { 91 int ret; 92 struct { 93 struct cros_ec_command msg; 94 union { 95 struct ec_params_host_sleep_event req0; 96 struct ec_params_host_sleep_event_v1 req1; 97 struct ec_response_host_sleep_event_v1 resp1; 98 } u; 99 } __packed buf; 100 101 memset(&buf, 0, sizeof(buf)); 102 103 if (ec_dev->host_sleep_v1) { 104 buf.u.req1.sleep_event = sleep_event; 105 buf.u.req1.suspend_params.sleep_timeout_ms = 106 EC_HOST_SLEEP_TIMEOUT_DEFAULT; 107 108 buf.msg.outsize = sizeof(buf.u.req1); 109 if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) || 110 (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) 111 buf.msg.insize = sizeof(buf.u.resp1); 112 113 buf.msg.version = 1; 114 115 } else { 116 buf.u.req0.sleep_event = sleep_event; 117 buf.msg.outsize = sizeof(buf.u.req0); 118 } 119 120 buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; 121 122 ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); 123 124 /* For now, report failure to transition to S0ix with a warning. */ 125 if (ret >= 0 && ec_dev->host_sleep_v1 && 126 (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) { 127 ec_dev->last_resume_result = 128 buf.u.resp1.resume_response.sleep_transitions; 129 130 WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions & 131 EC_HOST_RESUME_SLEEP_TIMEOUT, 132 "EC detected sleep transition timeout. Total slp_s0 transitions: %d", 133 buf.u.resp1.resume_response.sleep_transitions & 134 EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK); 135 } 136 137 return ret; 138 } 139 140 /** 141 * cros_ec_register() - Register a new ChromeOS EC, using the provided info. 142 * @ec_dev: Device to register. 143 * 144 * Before calling this, allocate a pointer to a new device and then fill 145 * in all the fields up to the --private-- marker. 146 * 147 * Return: 0 on success or negative error code. 148 */ 149 int cros_ec_register(struct cros_ec_device *ec_dev) 150 { 151 struct device *dev = ec_dev->dev; 152 int err = 0; 153 154 BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); 155 156 ec_dev->max_request = sizeof(struct ec_params_hello); 157 ec_dev->max_response = sizeof(struct ec_response_get_protocol_info); 158 ec_dev->max_passthru = 0; 159 160 ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); 161 if (!ec_dev->din) 162 return -ENOMEM; 163 164 ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); 165 if (!ec_dev->dout) 166 return -ENOMEM; 167 168 mutex_init(&ec_dev->lock); 169 170 err = cros_ec_query_all(ec_dev); 171 if (err) { 172 dev_err(dev, "Cannot identify the EC: error %d\n", err); 173 return err; 174 } 175 176 if (ec_dev->irq > 0) { 177 err = devm_request_threaded_irq(dev, ec_dev->irq, 178 ec_irq_handler, 179 ec_irq_thread, 180 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 181 "chromeos-ec", ec_dev); 182 if (err) { 183 dev_err(dev, "Failed to request IRQ %d: %d", 184 ec_dev->irq, err); 185 return err; 186 } 187 } 188 189 /* Register a platform device for the main EC instance */ 190 ec_dev->ec = platform_device_register_data(ec_dev->dev, "cros-ec-dev", 191 PLATFORM_DEVID_AUTO, &ec_p, 192 sizeof(struct cros_ec_platform)); 193 if (IS_ERR(ec_dev->ec)) { 194 dev_err(ec_dev->dev, 195 "Failed to create CrOS EC platform device\n"); 196 return PTR_ERR(ec_dev->ec); 197 } 198 199 if (ec_dev->max_passthru) { 200 /* 201 * Register a platform device for the PD behind the main EC. 202 * We make the following assumptions: 203 * - behind an EC, we have a pd 204 * - only one device added. 205 * - the EC is responsive at init time (it is not true for a 206 * sensor hub). 207 */ 208 ec_dev->pd = platform_device_register_data(ec_dev->dev, 209 "cros-ec-dev", 210 PLATFORM_DEVID_AUTO, &pd_p, 211 sizeof(struct cros_ec_platform)); 212 if (IS_ERR(ec_dev->pd)) { 213 dev_err(ec_dev->dev, 214 "Failed to create CrOS PD platform device\n"); 215 platform_device_unregister(ec_dev->ec); 216 return PTR_ERR(ec_dev->pd); 217 } 218 } 219 220 if (IS_ENABLED(CONFIG_OF) && dev->of_node) { 221 err = devm_of_platform_populate(dev); 222 if (err) { 223 platform_device_unregister(ec_dev->pd); 224 platform_device_unregister(ec_dev->ec); 225 dev_err(dev, "Failed to register sub-devices\n"); 226 return err; 227 } 228 } 229 230 /* 231 * Clear sleep event - this will fail harmlessly on platforms that 232 * don't implement the sleep event host command. 233 */ 234 err = cros_ec_sleep_event(ec_dev, 0); 235 if (err < 0) 236 dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec", 237 err); 238 239 dev_info(dev, "Chrome EC device registered\n"); 240 241 return 0; 242 } 243 EXPORT_SYMBOL(cros_ec_register); 244 245 /** 246 * cros_ec_unregister() - Remove a ChromeOS EC. 247 * @ec_dev: Device to unregister. 248 * 249 * Call this to deregister a ChromeOS EC, then clean up any private data. 250 * 251 * Return: 0 on success or negative error code. 252 */ 253 int cros_ec_unregister(struct cros_ec_device *ec_dev) 254 { 255 if (ec_dev->pd) 256 platform_device_unregister(ec_dev->pd); 257 platform_device_unregister(ec_dev->ec); 258 259 return 0; 260 } 261 EXPORT_SYMBOL(cros_ec_unregister); 262 263 #ifdef CONFIG_PM_SLEEP 264 /** 265 * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device. 266 * @ec_dev: Device to suspend. 267 * 268 * This can be called by drivers to handle a suspend event. 269 * 270 * Return: 0 on success or negative error code. 271 */ 272 int cros_ec_suspend(struct cros_ec_device *ec_dev) 273 { 274 struct device *dev = ec_dev->dev; 275 int ret; 276 u8 sleep_event; 277 278 sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? 279 HOST_SLEEP_EVENT_S3_SUSPEND : 280 HOST_SLEEP_EVENT_S0IX_SUSPEND; 281 282 ret = cros_ec_sleep_event(ec_dev, sleep_event); 283 if (ret < 0) 284 dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec", 285 ret); 286 287 if (device_may_wakeup(dev)) 288 ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); 289 290 disable_irq(ec_dev->irq); 291 ec_dev->was_wake_device = ec_dev->wake_enabled; 292 ec_dev->suspended = true; 293 294 return 0; 295 } 296 EXPORT_SYMBOL(cros_ec_suspend); 297 298 static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev) 299 { 300 while (ec_dev->mkbp_event_supported && 301 cros_ec_get_next_event(ec_dev, NULL, NULL) > 0) 302 blocking_notifier_call_chain(&ec_dev->event_notifier, 303 1, ec_dev); 304 } 305 306 /** 307 * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device. 308 * @ec_dev: Device to resume. 309 * 310 * This can be called by drivers to handle a resume event. 311 * 312 * Return: 0 on success or negative error code. 313 */ 314 int cros_ec_resume(struct cros_ec_device *ec_dev) 315 { 316 int ret; 317 u8 sleep_event; 318 319 ec_dev->suspended = false; 320 enable_irq(ec_dev->irq); 321 322 sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? 323 HOST_SLEEP_EVENT_S3_RESUME : 324 HOST_SLEEP_EVENT_S0IX_RESUME; 325 326 ret = cros_ec_sleep_event(ec_dev, sleep_event); 327 if (ret < 0) 328 dev_dbg(ec_dev->dev, "Error %d sending resume event to ec", 329 ret); 330 331 if (ec_dev->wake_enabled) { 332 disable_irq_wake(ec_dev->irq); 333 ec_dev->wake_enabled = 0; 334 } 335 /* 336 * Let the mfd devices know about events that occur during 337 * suspend. This way the clients know what to do with them. 338 */ 339 cros_ec_report_events_during_suspend(ec_dev); 340 341 342 return 0; 343 } 344 EXPORT_SYMBOL(cros_ec_resume); 345 346 #endif 347 348 MODULE_LICENSE("GPL"); 349 MODULE_DESCRIPTION("ChromeOS EC core driver"); 350