Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'chrome-platform-for-linus-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform

Pull chrome platform updates from Benson Leung:
"Changes in this pull request are around catching up cros_ec with the
internal chromeos-kernel versions of cros_ec, cros_ec_lpc, and
cros_ec_lightbar.

Also, switching maintainership from olof to bleung"

* tag 'chrome-platform-for-linus-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform:
platform/chrome : Add myself as Maintainer
platform/chrome: cros_ec_lightbar - hide unused PM functions
cros_ec: Don't signal wake event for non-wake host events
cros_ec: Fix deadlock when EC is not responsive at probe
cros_ec: Don't return error when checking command version
platform/chrome: cros_ec_lightbar - Avoid I2C xfer to EC during suspend
platform/chrome: cros_ec_lightbar - Add userspace lightbar control bit to EC
platform/chrome: cros_ec_lightbar - Control of suspend/resume lightbar sequence
platform/chrome: cros_ec_lightbar - Add lightbar program feature to sysfs
platform/chrome: cros_ec_lpc: Add MKBP events support over ACPI
platform/chrome: cros_ec_lpc: Add power management ops
platform/chrome: cros_ec_lpc: Add support for GOOG004 ACPI device
platform/chrome: cros_ec_lpc: Add support for mec1322 EC
platform/chrome: cros_ec_lpc: Add R/W helpers to LPC protocol variants
mfd: cros_ec: Add support for dumping panic information
cros_ec_debugfs: Pass proper struct sizes to cros_ec_cmd_xfer()
mfd: cros_ec: add debugfs, console log file
mfd: cros_ec: Add EC console read structures definitions
mfd: cros_ec: Add helper for event notifier.

+1393 -84
+2 -1
MAINTAINERS
··· 3319 3319 F: drivers/input/touchscreen/chipone_icn8318.c 3320 3320 3321 3321 CHROME HARDWARE PLATFORM SUPPORT 3322 + M: Benson Leung <bleung@chromium.org> 3322 3323 M: Olof Johansson <olof@lixom.net> 3323 3324 S: Maintained 3324 - T: git git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform.git 3325 + T: git git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git 3325 3326 F: drivers/platform/chrome/ 3326 3327 3327 3328 CISCO VIC ETHERNET NIC DRIVER
+10 -3
drivers/mfd/cros_ec.c
··· 54 54 static irqreturn_t ec_irq_thread(int irq, void *data) 55 55 { 56 56 struct cros_ec_device *ec_dev = data; 57 + bool wake_event = true; 57 58 int ret; 58 59 59 - if (device_may_wakeup(ec_dev->dev)) 60 + ret = cros_ec_get_next_event(ec_dev, &wake_event); 61 + 62 + /* 63 + * Signal only if wake host events or any interrupt if 64 + * cros_ec_get_next_event() returned an error (default value for 65 + * wake_event is true) 66 + */ 67 + if (wake_event && device_may_wakeup(ec_dev->dev)) 60 68 pm_wakeup_event(ec_dev->dev, 0); 61 69 62 - ret = cros_ec_get_next_event(ec_dev); 63 70 if (ret > 0) 64 71 blocking_notifier_call_chain(&ec_dev->event_notifier, 65 72 0, ec_dev); ··· 231 224 232 225 static void cros_ec_drain_events(struct cros_ec_device *ec_dev) 233 226 { 234 - while (cros_ec_get_next_event(ec_dev) > 0) 227 + while (cros_ec_get_next_event(ec_dev, NULL) > 0) 235 228 blocking_notifier_call_chain(&ec_dev->event_notifier, 236 229 1, ec_dev); 237 230 }
+13 -1
drivers/platform/chrome/Kconfig
··· 49 49 50 50 config CROS_EC_LPC 51 51 tristate "ChromeOS Embedded Controller (LPC)" 52 - depends on MFD_CROS_EC && (X86 || COMPILE_TEST) 52 + depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST) 53 53 help 54 54 If you say Y here, you get support for talking to the ChromeOS EC 55 55 over an LPC bus. This uses a simple byte-level protocol with a ··· 58 58 59 59 To compile this driver as a module, choose M here: the 60 60 module will be called cros_ec_lpc. 61 + 62 + config CROS_EC_LPC_MEC 63 + bool "ChromeOS Embedded Controller LPC Microchip EC (MEC) variant" 64 + depends on CROS_EC_LPC 65 + default n 66 + help 67 + If you say Y here, a variant LPC protocol for the Microchip EC 68 + will be used. Note that this variant is not backward compatible 69 + with non-Microchip ECs. 70 + 71 + If you have a ChromeOS Embedded Controller Microchip EC variant 72 + choose Y here. 61 73 62 74 config CROS_EC_PROTO 63 75 bool
+5 -2
drivers/platform/chrome/Makefile
··· 2 2 obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 3 3 obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o 4 4 cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \ 5 - cros_ec_lightbar.o cros_ec_vbc.o 5 + cros_ec_lightbar.o cros_ec_vbc.o \ 6 + cros_ec_debugfs.o 6 7 obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o 7 - obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o 8 + cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o 9 + cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o 10 + obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o 8 11 obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o 9 12 obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
+401
drivers/platform/chrome/cros_ec_debugfs.c
··· 1 + /* 2 + * cros_ec_debugfs - debug logs for Chrome OS EC 3 + * 4 + * Copyright 2015 Google, Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/circ_buf.h> 21 + #include <linux/debugfs.h> 22 + #include <linux/delay.h> 23 + #include <linux/fs.h> 24 + #include <linux/mfd/cros_ec.h> 25 + #include <linux/mfd/cros_ec_commands.h> 26 + #include <linux/mutex.h> 27 + #include <linux/poll.h> 28 + #include <linux/sched.h> 29 + #include <linux/slab.h> 30 + #include <linux/wait.h> 31 + 32 + #include "cros_ec_dev.h" 33 + #include "cros_ec_debugfs.h" 34 + 35 + #define LOG_SHIFT 14 36 + #define LOG_SIZE (1 << LOG_SHIFT) 37 + #define LOG_POLL_SEC 10 38 + 39 + #define CIRC_ADD(idx, size, value) (((idx) + (value)) & ((size) - 1)) 40 + 41 + /* struct cros_ec_debugfs - ChromeOS EC debugging information 42 + * 43 + * @ec: EC device this debugfs information belongs to 44 + * @dir: dentry for debugfs files 45 + * @log_buffer: circular buffer for console log information 46 + * @read_msg: preallocated EC command and buffer to read console log 47 + * @log_mutex: mutex to protect circular buffer 48 + * @log_wq: waitqueue for log readers 49 + * @log_poll_work: recurring task to poll EC for new console log data 50 + * @panicinfo_blob: panicinfo debugfs blob 51 + */ 52 + struct cros_ec_debugfs { 53 + struct cros_ec_dev *ec; 54 + struct dentry *dir; 55 + /* EC log */ 56 + struct circ_buf log_buffer; 57 + struct cros_ec_command *read_msg; 58 + struct mutex log_mutex; 59 + wait_queue_head_t log_wq; 60 + struct delayed_work log_poll_work; 61 + /* EC panicinfo */ 62 + struct debugfs_blob_wrapper panicinfo_blob; 63 + }; 64 + 65 + /* 66 + * We need to make sure that the EC log buffer on the UART is large enough, 67 + * so that it is unlikely enough to overlow within LOG_POLL_SEC. 68 + */ 69 + static void cros_ec_console_log_work(struct work_struct *__work) 70 + { 71 + struct cros_ec_debugfs *debug_info = 72 + container_of(to_delayed_work(__work), 73 + struct cros_ec_debugfs, 74 + log_poll_work); 75 + struct cros_ec_dev *ec = debug_info->ec; 76 + struct circ_buf *cb = &debug_info->log_buffer; 77 + struct cros_ec_command snapshot_msg = { 78 + .command = EC_CMD_CONSOLE_SNAPSHOT + ec->cmd_offset, 79 + }; 80 + 81 + struct ec_params_console_read_v1 *read_params = 82 + (struct ec_params_console_read_v1 *)debug_info->read_msg->data; 83 + uint8_t *ec_buffer = (uint8_t *)debug_info->read_msg->data; 84 + int idx; 85 + int buf_space; 86 + int ret; 87 + 88 + ret = cros_ec_cmd_xfer(ec->ec_dev, &snapshot_msg); 89 + if (ret < 0) { 90 + dev_err(ec->dev, "EC communication failed\n"); 91 + goto resched; 92 + } 93 + if (snapshot_msg.result != EC_RES_SUCCESS) { 94 + dev_err(ec->dev, "EC failed to snapshot the console log\n"); 95 + goto resched; 96 + } 97 + 98 + /* Loop until we have read everything, or there's an error. */ 99 + mutex_lock(&debug_info->log_mutex); 100 + buf_space = CIRC_SPACE(cb->head, cb->tail, LOG_SIZE); 101 + 102 + while (1) { 103 + if (!buf_space) { 104 + dev_info_once(ec->dev, 105 + "Some logs may have been dropped...\n"); 106 + break; 107 + } 108 + 109 + memset(read_params, '\0', sizeof(*read_params)); 110 + read_params->subcmd = CONSOLE_READ_RECENT; 111 + ret = cros_ec_cmd_xfer(ec->ec_dev, debug_info->read_msg); 112 + if (ret < 0) { 113 + dev_err(ec->dev, "EC communication failed\n"); 114 + break; 115 + } 116 + if (debug_info->read_msg->result != EC_RES_SUCCESS) { 117 + dev_err(ec->dev, 118 + "EC failed to read the console log\n"); 119 + break; 120 + } 121 + 122 + /* If the buffer is empty, we're done here. */ 123 + if (ret == 0 || ec_buffer[0] == '\0') 124 + break; 125 + 126 + idx = 0; 127 + while (idx < ret && ec_buffer[idx] != '\0' && buf_space > 0) { 128 + cb->buf[cb->head] = ec_buffer[idx]; 129 + cb->head = CIRC_ADD(cb->head, LOG_SIZE, 1); 130 + idx++; 131 + buf_space--; 132 + } 133 + 134 + wake_up(&debug_info->log_wq); 135 + } 136 + 137 + mutex_unlock(&debug_info->log_mutex); 138 + 139 + resched: 140 + schedule_delayed_work(&debug_info->log_poll_work, 141 + msecs_to_jiffies(LOG_POLL_SEC * 1000)); 142 + } 143 + 144 + static int cros_ec_console_log_open(struct inode *inode, struct file *file) 145 + { 146 + file->private_data = inode->i_private; 147 + 148 + return nonseekable_open(inode, file); 149 + } 150 + 151 + static ssize_t cros_ec_console_log_read(struct file *file, char __user *buf, 152 + size_t count, loff_t *ppos) 153 + { 154 + struct cros_ec_debugfs *debug_info = file->private_data; 155 + struct circ_buf *cb = &debug_info->log_buffer; 156 + ssize_t ret; 157 + 158 + mutex_lock(&debug_info->log_mutex); 159 + 160 + while (!CIRC_CNT(cb->head, cb->tail, LOG_SIZE)) { 161 + if (file->f_flags & O_NONBLOCK) { 162 + ret = -EAGAIN; 163 + goto error; 164 + } 165 + 166 + mutex_unlock(&debug_info->log_mutex); 167 + 168 + ret = wait_event_interruptible(debug_info->log_wq, 169 + CIRC_CNT(cb->head, cb->tail, LOG_SIZE)); 170 + if (ret < 0) 171 + return ret; 172 + 173 + mutex_lock(&debug_info->log_mutex); 174 + } 175 + 176 + /* Only copy until the end of the circular buffer, and let userspace 177 + * retry to get the rest of the data. 178 + */ 179 + ret = min_t(size_t, CIRC_CNT_TO_END(cb->head, cb->tail, LOG_SIZE), 180 + count); 181 + 182 + if (copy_to_user(buf, cb->buf + cb->tail, ret)) { 183 + ret = -EFAULT; 184 + goto error; 185 + } 186 + 187 + cb->tail = CIRC_ADD(cb->tail, LOG_SIZE, ret); 188 + 189 + error: 190 + mutex_unlock(&debug_info->log_mutex); 191 + return ret; 192 + } 193 + 194 + static unsigned int cros_ec_console_log_poll(struct file *file, 195 + poll_table *wait) 196 + { 197 + struct cros_ec_debugfs *debug_info = file->private_data; 198 + unsigned int mask = 0; 199 + 200 + poll_wait(file, &debug_info->log_wq, wait); 201 + 202 + mutex_lock(&debug_info->log_mutex); 203 + if (CIRC_CNT(debug_info->log_buffer.head, 204 + debug_info->log_buffer.tail, 205 + LOG_SIZE)) 206 + mask |= POLLIN | POLLRDNORM; 207 + mutex_unlock(&debug_info->log_mutex); 208 + 209 + return mask; 210 + } 211 + 212 + static int cros_ec_console_log_release(struct inode *inode, struct file *file) 213 + { 214 + return 0; 215 + } 216 + 217 + const struct file_operations cros_ec_console_log_fops = { 218 + .owner = THIS_MODULE, 219 + .open = cros_ec_console_log_open, 220 + .read = cros_ec_console_log_read, 221 + .llseek = no_llseek, 222 + .poll = cros_ec_console_log_poll, 223 + .release = cros_ec_console_log_release, 224 + }; 225 + 226 + static int ec_read_version_supported(struct cros_ec_dev *ec) 227 + { 228 + struct ec_params_get_cmd_versions_v1 *params; 229 + struct ec_response_get_cmd_versions *response; 230 + int ret; 231 + 232 + struct cros_ec_command *msg; 233 + 234 + msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)), 235 + GFP_KERNEL); 236 + if (!msg) 237 + return 0; 238 + 239 + msg->command = EC_CMD_GET_CMD_VERSIONS + ec->cmd_offset; 240 + msg->outsize = sizeof(*params); 241 + msg->insize = sizeof(*response); 242 + 243 + params = (struct ec_params_get_cmd_versions_v1 *)msg->data; 244 + params->cmd = EC_CMD_CONSOLE_READ; 245 + response = (struct ec_response_get_cmd_versions *)msg->data; 246 + 247 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg) >= 0 && 248 + msg->result == EC_RES_SUCCESS && 249 + (response->version_mask & EC_VER_MASK(1)); 250 + 251 + kfree(msg); 252 + 253 + return ret; 254 + } 255 + 256 + static int cros_ec_create_console_log(struct cros_ec_debugfs *debug_info) 257 + { 258 + struct cros_ec_dev *ec = debug_info->ec; 259 + char *buf; 260 + int read_params_size; 261 + int read_response_size; 262 + 263 + if (!ec_read_version_supported(ec)) { 264 + dev_warn(ec->dev, 265 + "device does not support reading the console log\n"); 266 + return 0; 267 + } 268 + 269 + buf = devm_kzalloc(ec->dev, LOG_SIZE, GFP_KERNEL); 270 + if (!buf) 271 + return -ENOMEM; 272 + 273 + read_params_size = sizeof(struct ec_params_console_read_v1); 274 + read_response_size = ec->ec_dev->max_response; 275 + debug_info->read_msg = devm_kzalloc(ec->dev, 276 + sizeof(*debug_info->read_msg) + 277 + max(read_params_size, read_response_size), GFP_KERNEL); 278 + if (!debug_info->read_msg) 279 + return -ENOMEM; 280 + 281 + debug_info->read_msg->version = 1; 282 + debug_info->read_msg->command = EC_CMD_CONSOLE_READ + ec->cmd_offset; 283 + debug_info->read_msg->outsize = read_params_size; 284 + debug_info->read_msg->insize = read_response_size; 285 + 286 + debug_info->log_buffer.buf = buf; 287 + debug_info->log_buffer.head = 0; 288 + debug_info->log_buffer.tail = 0; 289 + 290 + mutex_init(&debug_info->log_mutex); 291 + init_waitqueue_head(&debug_info->log_wq); 292 + 293 + if (!debugfs_create_file("console_log", 294 + S_IFREG | S_IRUGO, 295 + debug_info->dir, 296 + debug_info, 297 + &cros_ec_console_log_fops)) 298 + return -ENOMEM; 299 + 300 + INIT_DELAYED_WORK(&debug_info->log_poll_work, 301 + cros_ec_console_log_work); 302 + schedule_delayed_work(&debug_info->log_poll_work, 0); 303 + 304 + return 0; 305 + } 306 + 307 + static void cros_ec_cleanup_console_log(struct cros_ec_debugfs *debug_info) 308 + { 309 + if (debug_info->log_buffer.buf) { 310 + cancel_delayed_work_sync(&debug_info->log_poll_work); 311 + mutex_destroy(&debug_info->log_mutex); 312 + } 313 + } 314 + 315 + static int cros_ec_create_panicinfo(struct cros_ec_debugfs *debug_info) 316 + { 317 + struct cros_ec_device *ec_dev = debug_info->ec->ec_dev; 318 + int ret; 319 + struct cros_ec_command *msg; 320 + int insize; 321 + 322 + insize = ec_dev->max_response; 323 + 324 + msg = devm_kzalloc(debug_info->ec->dev, 325 + sizeof(*msg) + insize, GFP_KERNEL); 326 + if (!msg) 327 + return -ENOMEM; 328 + 329 + msg->command = EC_CMD_GET_PANIC_INFO; 330 + msg->insize = insize; 331 + 332 + ret = cros_ec_cmd_xfer(ec_dev, msg); 333 + if (ret < 0) { 334 + dev_warn(debug_info->ec->dev, "Cannot read panicinfo.\n"); 335 + ret = 0; 336 + goto free; 337 + } 338 + 339 + /* No panic data */ 340 + if (ret == 0) 341 + goto free; 342 + 343 + debug_info->panicinfo_blob.data = msg->data; 344 + debug_info->panicinfo_blob.size = ret; 345 + 346 + if (!debugfs_create_blob("panicinfo", 347 + S_IFREG | S_IRUGO, 348 + debug_info->dir, 349 + &debug_info->panicinfo_blob)) { 350 + ret = -ENOMEM; 351 + goto free; 352 + } 353 + 354 + return 0; 355 + 356 + free: 357 + devm_kfree(debug_info->ec->dev, msg); 358 + return ret; 359 + } 360 + 361 + int cros_ec_debugfs_init(struct cros_ec_dev *ec) 362 + { 363 + struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev); 364 + const char *name = ec_platform->ec_name; 365 + struct cros_ec_debugfs *debug_info; 366 + int ret; 367 + 368 + debug_info = devm_kzalloc(ec->dev, sizeof(*debug_info), GFP_KERNEL); 369 + if (!debug_info) 370 + return -ENOMEM; 371 + 372 + debug_info->ec = ec; 373 + debug_info->dir = debugfs_create_dir(name, NULL); 374 + if (!debug_info->dir) 375 + return -ENOMEM; 376 + 377 + ret = cros_ec_create_panicinfo(debug_info); 378 + if (ret) 379 + goto remove_debugfs; 380 + 381 + ret = cros_ec_create_console_log(debug_info); 382 + if (ret) 383 + goto remove_debugfs; 384 + 385 + ec->debug_info = debug_info; 386 + 387 + return 0; 388 + 389 + remove_debugfs: 390 + debugfs_remove_recursive(debug_info->dir); 391 + return ret; 392 + } 393 + 394 + void cros_ec_debugfs_remove(struct cros_ec_dev *ec) 395 + { 396 + if (!ec->debug_info) 397 + return; 398 + 399 + debugfs_remove_recursive(ec->debug_info->dir); 400 + cros_ec_cleanup_console_log(ec->debug_info); 401 + }
+27
drivers/platform/chrome/cros_ec_debugfs.h
··· 1 + /* 2 + * Copyright 2015 Google, Inc. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef _DRV_CROS_EC_DEBUGFS_H_ 19 + #define _DRV_CROS_EC_DEBUGFS_H_ 20 + 21 + #include "cros_ec_dev.h" 22 + 23 + /* debugfs stuff */ 24 + int cros_ec_debugfs_init(struct cros_ec_dev *ec); 25 + void cros_ec_debugfs_remove(struct cros_ec_dev *ec); 26 + 27 + #endif /* _DRV_CROS_EC_DEBUGFS_H_ */
+40
drivers/platform/chrome/cros_ec_dev.c
··· 21 21 #include <linux/mfd/core.h> 22 22 #include <linux/module.h> 23 23 #include <linux/platform_device.h> 24 + #include <linux/pm.h> 24 25 #include <linux/slab.h> 25 26 #include <linux/uaccess.h> 26 27 28 + #include "cros_ec_debugfs.h" 27 29 #include "cros_ec_dev.h" 28 30 29 31 /* Device variables */ ··· 429 427 goto failed; 430 428 } 431 429 430 + if (cros_ec_debugfs_init(ec)) 431 + dev_warn(dev, "failed to create debugfs directory\n"); 432 + 432 433 /* check whether this EC is a sensor hub. */ 433 434 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) 434 435 cros_ec_sensors_register(ec); 436 + 437 + /* Take control of the lightbar from the EC. */ 438 + lb_manual_suspend_ctrl(ec, 1); 435 439 436 440 return 0; 437 441 ··· 449 441 static int ec_device_remove(struct platform_device *pdev) 450 442 { 451 443 struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); 444 + 445 + /* Let the EC take over the lightbar again. */ 446 + lb_manual_suspend_ctrl(ec, 0); 447 + 448 + cros_ec_debugfs_remove(ec); 449 + 452 450 cdev_del(&ec->cdev); 453 451 device_unregister(&ec->class_dev); 454 452 return 0; ··· 466 452 }; 467 453 MODULE_DEVICE_TABLE(platform, cros_ec_id); 468 454 455 + static __maybe_unused int ec_device_suspend(struct device *dev) 456 + { 457 + struct cros_ec_dev *ec = dev_get_drvdata(dev); 458 + 459 + lb_suspend(ec); 460 + 461 + return 0; 462 + } 463 + 464 + static __maybe_unused int ec_device_resume(struct device *dev) 465 + { 466 + struct cros_ec_dev *ec = dev_get_drvdata(dev); 467 + 468 + lb_resume(ec); 469 + 470 + return 0; 471 + } 472 + 473 + static const struct dev_pm_ops cros_ec_dev_pm_ops = { 474 + #ifdef CONFIG_PM_SLEEP 475 + .suspend = ec_device_suspend, 476 + .resume = ec_device_resume, 477 + #endif 478 + }; 479 + 469 480 static struct platform_driver cros_ec_dev_driver = { 470 481 .driver = { 471 482 .name = "cros-ec-ctl", 483 + .pm = &cros_ec_dev_pm_ops, 472 484 }, 473 485 .probe = ec_device_probe, 474 486 .remove = ec_device_remove,
+6
drivers/platform/chrome/cros_ec_dev.h
··· 43 43 #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) 44 44 #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) 45 45 46 + /* Lightbar utilities */ 47 + extern bool ec_has_lightbar(struct cros_ec_dev *ec); 48 + extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable); 49 + extern int lb_suspend(struct cros_ec_dev *ec); 50 + extern int lb_resume(struct cros_ec_dev *ec); 51 + 46 52 #endif /* _CROS_EC_DEV_H_ */
+193 -4
drivers/platform/chrome/cros_ec_lightbar.c
··· 38 38 /* Rate-limit the lightbar interface to prevent DoS. */ 39 39 static unsigned long lb_interval_jiffies = 50 * HZ / 1000; 40 40 41 + /* 42 + * Whether or not we have given userspace control of the lightbar. 43 + * If this is true, we won't do anything during suspend/resume. 44 + */ 45 + static bool userspace_control; 46 + static struct cros_ec_dev *ec_with_lightbar; 47 + 41 48 static ssize_t interval_msec_show(struct device *dev, 42 49 struct device_attribute *attr, char *buf) 43 50 { ··· 302 295 303 296 static char const *seqname[] = { 304 297 "ERROR", "S5", "S3", "S0", "S5S3", "S3S0", 305 - "S0S3", "S3S5", "STOP", "RUN", "PULSE", "TEST", "KONAMI", 298 + "S0S3", "S3S5", "STOP", "RUN", "KONAMI", 299 + "TAP", "PROGRAM", 306 300 }; 307 301 308 302 static ssize_t sequence_show(struct device *dev, ··· 346 338 exit: 347 339 kfree(msg); 348 340 return ret; 341 + } 342 + 343 + static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd) 344 + { 345 + struct ec_params_lightbar *param; 346 + struct cros_ec_command *msg; 347 + int ret; 348 + 349 + msg = alloc_lightbar_cmd_msg(ec); 350 + if (!msg) 351 + return -ENOMEM; 352 + 353 + param = (struct ec_params_lightbar *)msg->data; 354 + param->cmd = cmd; 355 + 356 + ret = lb_throttle(); 357 + if (ret) 358 + goto error; 359 + 360 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 361 + if (ret < 0) 362 + goto error; 363 + if (msg->result != EC_RES_SUCCESS) { 364 + ret = -EINVAL; 365 + goto error; 366 + } 367 + ret = 0; 368 + error: 369 + kfree(msg); 370 + 371 + return ret; 372 + } 373 + 374 + int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable) 375 + { 376 + struct ec_params_lightbar *param; 377 + struct cros_ec_command *msg; 378 + int ret; 379 + 380 + if (ec != ec_with_lightbar) 381 + return 0; 382 + 383 + msg = alloc_lightbar_cmd_msg(ec); 384 + if (!msg) 385 + return -ENOMEM; 386 + 387 + param = (struct ec_params_lightbar *)msg->data; 388 + 389 + param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL; 390 + param->manual_suspend_ctrl.enable = enable; 391 + 392 + ret = lb_throttle(); 393 + if (ret) 394 + goto error; 395 + 396 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 397 + if (ret < 0) 398 + goto error; 399 + if (msg->result != EC_RES_SUCCESS) { 400 + ret = -EINVAL; 401 + goto error; 402 + } 403 + ret = 0; 404 + error: 405 + kfree(msg); 406 + 407 + return ret; 408 + } 409 + 410 + int lb_suspend(struct cros_ec_dev *ec) 411 + { 412 + if (userspace_control || ec != ec_with_lightbar) 413 + return 0; 414 + 415 + return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND); 416 + } 417 + 418 + int lb_resume(struct cros_ec_dev *ec) 419 + { 420 + if (userspace_control || ec != ec_with_lightbar) 421 + return 0; 422 + 423 + return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME); 349 424 } 350 425 351 426 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, ··· 481 390 return ret; 482 391 } 483 392 393 + static ssize_t program_store(struct device *dev, struct device_attribute *attr, 394 + const char *buf, size_t count) 395 + { 396 + int extra_bytes, max_size, ret; 397 + struct ec_params_lightbar *param; 398 + struct cros_ec_command *msg; 399 + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, 400 + class_dev); 401 + 402 + /* 403 + * We might need to reject the program for size reasons. The EC 404 + * enforces a maximum program size, but we also don't want to try 405 + * and send a program that is too big for the protocol. In order 406 + * to ensure the latter, we also need to ensure we have extra bytes 407 + * to represent the rest of the packet. 408 + */ 409 + extra_bytes = sizeof(*param) - sizeof(param->set_program.data); 410 + max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes); 411 + if (count > max_size) { 412 + dev_err(dev, "Program is %u bytes, too long to send (max: %u)", 413 + (unsigned int)count, max_size); 414 + 415 + return -EINVAL; 416 + } 417 + 418 + msg = alloc_lightbar_cmd_msg(ec); 419 + if (!msg) 420 + return -ENOMEM; 421 + 422 + ret = lb_throttle(); 423 + if (ret) 424 + goto exit; 425 + 426 + dev_info(dev, "Copying %zu byte program to EC", count); 427 + 428 + param = (struct ec_params_lightbar *)msg->data; 429 + param->cmd = LIGHTBAR_CMD_SET_PROGRAM; 430 + 431 + param->set_program.size = count; 432 + memcpy(param->set_program.data, buf, count); 433 + 434 + /* 435 + * We need to set the message size manually or else it will use 436 + * EC_LB_PROG_LEN. This might be too long, and the program 437 + * is unlikely to use all of the space. 438 + */ 439 + msg->outsize = count + extra_bytes; 440 + 441 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 442 + if (ret < 0) 443 + goto exit; 444 + if (msg->result != EC_RES_SUCCESS) { 445 + ret = -EINVAL; 446 + goto exit; 447 + } 448 + 449 + ret = count; 450 + exit: 451 + kfree(msg); 452 + 453 + return ret; 454 + } 455 + 456 + static ssize_t userspace_control_show(struct device *dev, 457 + struct device_attribute *attr, 458 + char *buf) 459 + { 460 + return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control); 461 + } 462 + 463 + static ssize_t userspace_control_store(struct device *dev, 464 + struct device_attribute *attr, 465 + const char *buf, 466 + size_t count) 467 + { 468 + bool enable; 469 + int ret; 470 + 471 + ret = strtobool(buf, &enable); 472 + if (ret < 0) 473 + return ret; 474 + 475 + userspace_control = enable; 476 + 477 + return count; 478 + } 479 + 484 480 /* Module initialization */ 485 481 486 482 static DEVICE_ATTR_RW(interval_msec); ··· 575 397 static DEVICE_ATTR_WO(brightness); 576 398 static DEVICE_ATTR_WO(led_rgb); 577 399 static DEVICE_ATTR_RW(sequence); 400 + static DEVICE_ATTR_WO(program); 401 + static DEVICE_ATTR_RW(userspace_control); 402 + 578 403 static struct attribute *__lb_cmds_attrs[] = { 579 404 &dev_attr_interval_msec.attr, 580 405 &dev_attr_version.attr, 581 406 &dev_attr_brightness.attr, 582 407 &dev_attr_led_rgb.attr, 583 408 &dev_attr_sequence.attr, 409 + &dev_attr_program.attr, 410 + &dev_attr_userspace_control.attr, 584 411 NULL, 585 412 }; 413 + 414 + bool ec_has_lightbar(struct cros_ec_dev *ec) 415 + { 416 + return !!get_lightbar_version(ec, NULL, NULL); 417 + } 586 418 587 419 static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, 588 420 struct attribute *a, int n) ··· 610 422 return 0; 611 423 612 424 /* Only instantiate this stuff if the EC has a lightbar */ 613 - if (get_lightbar_version(ec, NULL, NULL)) 425 + if (ec_has_lightbar(ec)) { 426 + ec_with_lightbar = ec; 614 427 return a->mode; 615 - else 616 - return 0; 428 + } 429 + return 0; 617 430 } 618 431 619 432 struct attribute_group cros_ec_lightbar_attr_group = {
+105 -63
drivers/platform/chrome/cros_ec_lpc.c
··· 21 21 * expensive. 22 22 */ 23 23 24 + #include <linux/acpi.h> 24 25 #include <linux/dmi.h> 25 26 #include <linux/delay.h> 26 27 #include <linux/io.h> 27 28 #include <linux/mfd/cros_ec.h> 28 29 #include <linux/mfd/cros_ec_commands.h> 30 + #include <linux/mfd/cros_ec_lpc_reg.h> 29 31 #include <linux/module.h> 30 32 #include <linux/platform_device.h> 31 33 #include <linux/printk.h> 32 34 33 - #define DRV_NAME "cros_ec_lpc" 35 + #define DRV_NAME "cros_ec_lpcs" 36 + #define ACPI_DRV_NAME "GOOG0004" 34 37 35 38 static int ec_response_timed_out(void) 36 39 { 37 40 unsigned long one_second = jiffies + HZ; 41 + u8 data; 38 42 39 43 usleep_range(200, 300); 40 44 do { 41 - if (!(inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK)) 45 + if (!(cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_CMD, 1, &data) & 46 + EC_LPC_STATUS_BUSY_MASK)) 42 47 return 0; 43 48 usleep_range(100, 200); 44 49 } while (time_before(jiffies, one_second)); ··· 56 51 { 57 52 struct ec_host_request *request; 58 53 struct ec_host_response response; 59 - u8 sum = 0; 60 - int i; 54 + u8 sum; 61 55 int ret = 0; 62 56 u8 *dout; 63 57 64 58 ret = cros_ec_prepare_tx(ec, msg); 65 59 66 60 /* Write buffer */ 67 - for (i = 0; i < ret; i++) 68 - outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i); 61 + cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout); 69 62 70 63 request = (struct ec_host_request *)ec->dout; 71 64 72 65 /* Here we go */ 73 - outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); 66 + sum = EC_COMMAND_PROTOCOL_3; 67 + cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum); 74 68 75 69 if (ec_response_timed_out()) { 76 70 dev_warn(ec->dev, "EC responsed timed out\n"); ··· 78 74 } 79 75 80 76 /* Check result */ 81 - msg->result = inb(EC_LPC_ADDR_HOST_DATA); 77 + msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum); 82 78 ret = cros_ec_check_result(ec, msg); 83 79 if (ret) 84 80 goto done; 85 81 86 82 /* Read back response */ 87 83 dout = (u8 *)&response; 88 - for (i = 0; i < sizeof(response); i++) { 89 - dout[i] = inb(EC_LPC_ADDR_HOST_PACKET + i); 90 - sum += dout[i]; 91 - } 84 + sum = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET, sizeof(response), 85 + dout); 92 86 93 87 msg->result = response.result; 94 88 ··· 99 97 } 100 98 101 99 /* Read response and process checksum */ 102 - for (i = 0; i < response.data_len; i++) { 103 - msg->data[i] = 104 - inb(EC_LPC_ADDR_HOST_PACKET + sizeof(response) + i); 105 - sum += msg->data[i]; 106 - } 100 + sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET + 101 + sizeof(response), response.data_len, 102 + msg->data); 107 103 108 104 if (sum) { 109 105 dev_err(ec->dev, ··· 121 121 struct cros_ec_command *msg) 122 122 { 123 123 struct ec_lpc_host_args args; 124 - int csum; 125 - int i; 124 + u8 sum; 126 125 int ret = 0; 127 126 128 127 if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE || ··· 138 139 args.data_size = msg->outsize; 139 140 140 141 /* Initialize checksum */ 141 - csum = msg->command + args.flags + 142 - args.command_version + args.data_size; 142 + sum = msg->command + args.flags + args.command_version + args.data_size; 143 143 144 144 /* Copy data and update checksum */ 145 - for (i = 0; i < msg->outsize; i++) { 146 - outb(msg->data[i], EC_LPC_ADDR_HOST_PARAM + i); 147 - csum += msg->data[i]; 148 - } 145 + sum += cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PARAM, msg->outsize, 146 + msg->data); 149 147 150 148 /* Finalize checksum and write args */ 151 - args.checksum = csum & 0xFF; 152 - outb(args.flags, EC_LPC_ADDR_HOST_ARGS); 153 - outb(args.command_version, EC_LPC_ADDR_HOST_ARGS + 1); 154 - outb(args.data_size, EC_LPC_ADDR_HOST_ARGS + 2); 155 - outb(args.checksum, EC_LPC_ADDR_HOST_ARGS + 3); 149 + args.checksum = sum; 150 + cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args), 151 + (u8 *)&args); 156 152 157 153 /* Here we go */ 158 - outb(msg->command, EC_LPC_ADDR_HOST_CMD); 154 + sum = msg->command; 155 + cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum); 159 156 160 157 if (ec_response_timed_out()) { 161 158 dev_warn(ec->dev, "EC responsed timed out\n"); ··· 160 165 } 161 166 162 167 /* Check result */ 163 - msg->result = inb(EC_LPC_ADDR_HOST_DATA); 168 + msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum); 164 169 ret = cros_ec_check_result(ec, msg); 165 170 if (ret) 166 171 goto done; 167 172 168 173 /* Read back args */ 169 - args.flags = inb(EC_LPC_ADDR_HOST_ARGS); 170 - args.command_version = inb(EC_LPC_ADDR_HOST_ARGS + 1); 171 - args.data_size = inb(EC_LPC_ADDR_HOST_ARGS + 2); 172 - args.checksum = inb(EC_LPC_ADDR_HOST_ARGS + 3); 174 + cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args), 175 + (u8 *)&args); 173 176 174 177 if (args.data_size > msg->insize) { 175 178 dev_err(ec->dev, ··· 178 185 } 179 186 180 187 /* Start calculating response checksum */ 181 - csum = msg->command + args.flags + 182 - args.command_version + args.data_size; 188 + sum = msg->command + args.flags + args.command_version + args.data_size; 183 189 184 190 /* Read response and update checksum */ 185 - for (i = 0; i < args.data_size; i++) { 186 - msg->data[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); 187 - csum += msg->data[i]; 188 - } 191 + sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PARAM, args.data_size, 192 + msg->data); 189 193 190 194 /* Verify checksum */ 191 - if (args.checksum != (csum & 0xFF)) { 195 + if (args.checksum != sum) { 192 196 dev_err(ec->dev, 193 197 "bad packet checksum, expected %02x, got %02x\n", 194 - args.checksum, csum & 0xFF); 198 + args.checksum, sum); 195 199 ret = -EBADMSG; 196 200 goto done; 197 201 } ··· 212 222 213 223 /* fixed length */ 214 224 if (bytes) { 215 - for (; cnt < bytes; i++, s++, cnt++) 216 - *s = inb(EC_LPC_ADDR_MEMMAP + i); 217 - return cnt; 225 + cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + offset, bytes, s); 226 + return bytes; 218 227 } 219 228 220 229 /* string */ 221 230 for (; i < EC_MEMMAP_SIZE; i++, s++) { 222 - *s = inb(EC_LPC_ADDR_MEMMAP + i); 231 + cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + i, 1, s); 223 232 cnt++; 224 233 if (!*s) 225 234 break; ··· 227 238 return cnt; 228 239 } 229 240 241 + static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data) 242 + { 243 + struct cros_ec_device *ec_dev = data; 244 + 245 + if (ec_dev->mkbp_event_supported && 246 + cros_ec_get_next_event(ec_dev, NULL) > 0) 247 + blocking_notifier_call_chain(&ec_dev->event_notifier, 0, 248 + ec_dev); 249 + } 250 + 230 251 static int cros_ec_lpc_probe(struct platform_device *pdev) 231 252 { 232 253 struct device *dev = &pdev->dev; 254 + struct acpi_device *adev; 255 + acpi_status status; 233 256 struct cros_ec_device *ec_dev; 257 + u8 buf[2]; 234 258 int ret; 235 259 236 260 if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE, ··· 252 250 return -EBUSY; 253 251 } 254 252 255 - if ((inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E') || 256 - (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C')) { 253 + cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf); 254 + if (buf[0] != 'E' || buf[1] != 'C') { 257 255 dev_err(dev, "EC ID not detected\n"); 258 256 return -ENODEV; 259 257 } ··· 289 287 return ret; 290 288 } 291 289 290 + /* 291 + * Connect a notify handler to process MKBP messages if we have a 292 + * companion ACPI device. 293 + */ 294 + adev = ACPI_COMPANION(dev); 295 + if (adev) { 296 + status = acpi_install_notify_handler(adev->handle, 297 + ACPI_ALL_NOTIFY, 298 + cros_ec_lpc_acpi_notify, 299 + ec_dev); 300 + if (ACPI_FAILURE(status)) 301 + dev_warn(dev, "Failed to register notifier %08x\n", 302 + status); 303 + } 304 + 292 305 return 0; 293 306 } 294 307 295 308 static int cros_ec_lpc_remove(struct platform_device *pdev) 296 309 { 297 310 struct cros_ec_device *ec_dev; 311 + struct acpi_device *adev; 312 + 313 + adev = ACPI_COMPANION(&pdev->dev); 314 + if (adev) 315 + acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, 316 + cros_ec_lpc_acpi_notify); 298 317 299 318 ec_dev = platform_get_drvdata(pdev); 300 319 cros_ec_remove(ec_dev); 301 320 302 321 return 0; 303 322 } 323 + 324 + static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { 325 + { ACPI_DRV_NAME, 0 }, 326 + { } 327 + }; 328 + MODULE_DEVICE_TABLE(acpi, cros_ec_lpc_acpi_device_ids); 304 329 305 330 static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = { 306 331 { ··· 366 337 }; 367 338 MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table); 368 339 340 + #ifdef CONFIG_PM_SLEEP 341 + static int cros_ec_lpc_suspend(struct device *dev) 342 + { 343 + struct cros_ec_device *ec_dev = dev_get_drvdata(dev); 344 + 345 + return cros_ec_suspend(ec_dev); 346 + } 347 + 348 + static int cros_ec_lpc_resume(struct device *dev) 349 + { 350 + struct cros_ec_device *ec_dev = dev_get_drvdata(dev); 351 + 352 + return cros_ec_resume(ec_dev); 353 + } 354 + #endif 355 + 356 + const struct dev_pm_ops cros_ec_lpc_pm_ops = { 357 + SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend, cros_ec_lpc_resume) 358 + }; 359 + 369 360 static struct platform_driver cros_ec_lpc_driver = { 370 361 .driver = { 371 362 .name = DRV_NAME, 363 + .acpi_match_table = cros_ec_lpc_acpi_device_ids, 364 + .pm = &cros_ec_lpc_pm_ops, 372 365 }, 373 366 .probe = cros_ec_lpc_probe, 374 367 .remove = cros_ec_lpc_remove, 375 - }; 376 - 377 - static struct platform_device cros_ec_lpc_device = { 378 - .name = DRV_NAME 379 368 }; 380 369 381 370 static int __init cros_ec_lpc_init(void) ··· 405 358 return -ENODEV; 406 359 } 407 360 361 + cros_ec_lpc_reg_init(); 362 + 408 363 /* Register the driver */ 409 364 ret = platform_driver_register(&cros_ec_lpc_driver); 410 365 if (ret) { 411 366 pr_err(DRV_NAME ": can't register driver: %d\n", ret); 412 - return ret; 413 - } 414 - 415 - /* Register the device, and it'll get hooked up automatically */ 416 - ret = platform_device_register(&cros_ec_lpc_device); 417 - if (ret) { 418 - pr_err(DRV_NAME ": can't register device: %d\n", ret); 419 - platform_driver_unregister(&cros_ec_lpc_driver); 367 + cros_ec_lpc_reg_destroy(); 420 368 return ret; 421 369 } 422 370 ··· 420 378 421 379 static void __exit cros_ec_lpc_exit(void) 422 380 { 423 - platform_device_unregister(&cros_ec_lpc_device); 424 381 platform_driver_unregister(&cros_ec_lpc_driver); 382 + cros_ec_lpc_reg_destroy(); 425 383 } 426 384 427 385 module_init(cros_ec_lpc_init);
+140
drivers/platform/chrome/cros_ec_lpc_mec.c
··· 1 + /* 2 + * cros_ec_lpc_mec - LPC variant I/O for Microchip EC 3 + * 4 + * Copyright (C) 2016 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 + * This driver uses the Chrome OS EC byte-level message-based protocol for 16 + * communicating the keyboard state (which keys are pressed) from a keyboard EC 17 + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, 18 + * but everything else (including deghosting) is done here. The main 19 + * motivation for this is to keep the EC firmware as simple as possible, since 20 + * it cannot be easily upgraded and EC flash/IRAM space is relatively 21 + * expensive. 22 + */ 23 + 24 + #include <linux/delay.h> 25 + #include <linux/io.h> 26 + #include <linux/mfd/cros_ec_commands.h> 27 + #include <linux/mfd/cros_ec_lpc_mec.h> 28 + #include <linux/mutex.h> 29 + #include <linux/types.h> 30 + 31 + /* 32 + * This mutex must be held while accessing the EMI unit. We can't rely on the 33 + * EC mutex because memmap data may be accessed without it being held. 34 + */ 35 + static struct mutex io_mutex; 36 + 37 + /* 38 + * cros_ec_lpc_mec_emi_write_address 39 + * 40 + * Initialize EMI read / write at a given address. 41 + * 42 + * @addr: Starting read / write address 43 + * @access_type: Type of access, typically 32-bit auto-increment 44 + */ 45 + static void cros_ec_lpc_mec_emi_write_address(u16 addr, 46 + enum cros_ec_lpc_mec_emi_access_mode access_type) 47 + { 48 + /* Address relative to start of EMI range */ 49 + addr -= MEC_EMI_RANGE_START; 50 + outb((addr & 0xfc) | access_type, MEC_EMI_EC_ADDRESS_B0); 51 + outb((addr >> 8) & 0x7f, MEC_EMI_EC_ADDRESS_B1); 52 + } 53 + 54 + /* 55 + * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port 56 + * 57 + * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request 58 + * @offset: Base read / write address 59 + * @length: Number of bytes to read / write 60 + * @buf: Destination / source buffer 61 + * 62 + * @return 8-bit checksum of all bytes read / written 63 + */ 64 + u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, 65 + unsigned int offset, unsigned int length, 66 + u8 *buf) 67 + { 68 + int i = 0; 69 + int io_addr; 70 + u8 sum = 0; 71 + enum cros_ec_lpc_mec_emi_access_mode access, new_access; 72 + 73 + /* 74 + * Long access cannot be used on misaligned data since reading B0 loads 75 + * the data register and writing B3 flushes. 76 + */ 77 + if (offset & 0x3 || length < 4) 78 + access = ACCESS_TYPE_BYTE; 79 + else 80 + access = ACCESS_TYPE_LONG_AUTO_INCREMENT; 81 + 82 + mutex_lock(&io_mutex); 83 + 84 + /* Initialize I/O at desired address */ 85 + cros_ec_lpc_mec_emi_write_address(offset, access); 86 + 87 + /* Skip bytes in case of misaligned offset */ 88 + io_addr = MEC_EMI_EC_DATA_B0 + (offset & 0x3); 89 + while (i < length) { 90 + while (io_addr <= MEC_EMI_EC_DATA_B3) { 91 + if (io_type == MEC_IO_READ) 92 + buf[i] = inb(io_addr++); 93 + else 94 + outb(buf[i], io_addr++); 95 + 96 + sum += buf[i++]; 97 + offset++; 98 + 99 + /* Extra bounds check in case of misaligned length */ 100 + if (i == length) 101 + goto done; 102 + } 103 + 104 + /* 105 + * Use long auto-increment access except for misaligned write, 106 + * since writing B3 triggers the flush. 107 + */ 108 + if (length - i < 4 && io_type == MEC_IO_WRITE) 109 + new_access = ACCESS_TYPE_BYTE; 110 + else 111 + new_access = ACCESS_TYPE_LONG_AUTO_INCREMENT; 112 + 113 + if (new_access != access || 114 + access != ACCESS_TYPE_LONG_AUTO_INCREMENT) { 115 + access = new_access; 116 + cros_ec_lpc_mec_emi_write_address(offset, access); 117 + } 118 + 119 + /* Access [B0, B3] on each loop pass */ 120 + io_addr = MEC_EMI_EC_DATA_B0; 121 + } 122 + 123 + done: 124 + mutex_unlock(&io_mutex); 125 + 126 + return sum; 127 + } 128 + EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec); 129 + 130 + void cros_ec_lpc_mec_init(void) 131 + { 132 + mutex_init(&io_mutex); 133 + } 134 + EXPORT_SYMBOL(cros_ec_lpc_mec_init); 135 + 136 + void cros_ec_lpc_mec_destroy(void) 137 + { 138 + mutex_destroy(&io_mutex); 139 + } 140 + EXPORT_SYMBOL(cros_ec_lpc_mec_destroy);
+133
drivers/platform/chrome/cros_ec_lpc_reg.c
··· 1 + /* 2 + * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller 3 + * 4 + * Copyright (C) 2016 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 + * This driver uses the Chrome OS EC byte-level message-based protocol for 16 + * communicating the keyboard state (which keys are pressed) from a keyboard EC 17 + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, 18 + * but everything else (including deghosting) is done here. The main 19 + * motivation for this is to keep the EC firmware as simple as possible, since 20 + * it cannot be easily upgraded and EC flash/IRAM space is relatively 21 + * expensive. 22 + */ 23 + 24 + #include <linux/io.h> 25 + #include <linux/mfd/cros_ec.h> 26 + #include <linux/mfd/cros_ec_commands.h> 27 + #include <linux/mfd/cros_ec_lpc_mec.h> 28 + 29 + static u8 lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest) 30 + { 31 + int i; 32 + int sum = 0; 33 + 34 + for (i = 0; i < length; ++i) { 35 + dest[i] = inb(offset + i); 36 + sum += dest[i]; 37 + } 38 + 39 + /* Return checksum of all bytes read */ 40 + return sum; 41 + } 42 + 43 + static u8 lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) 44 + { 45 + int i; 46 + int sum = 0; 47 + 48 + for (i = 0; i < length; ++i) { 49 + outb(msg[i], offset + i); 50 + sum += msg[i]; 51 + } 52 + 53 + /* Return checksum of all bytes written */ 54 + return sum; 55 + } 56 + 57 + #ifdef CONFIG_CROS_EC_LPC_MEC 58 + 59 + u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest) 60 + { 61 + if (length == 0) 62 + return 0; 63 + 64 + /* Access desired range through EMI interface */ 65 + if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) { 66 + /* Ensure we don't straddle EMI region */ 67 + if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END)) 68 + return 0; 69 + 70 + return cros_ec_lpc_io_bytes_mec(MEC_IO_READ, offset, length, 71 + dest); 72 + } 73 + 74 + if (WARN_ON(offset + length > MEC_EMI_RANGE_START && 75 + offset < MEC_EMI_RANGE_START)) 76 + return 0; 77 + 78 + return lpc_read_bytes(offset, length, dest); 79 + } 80 + 81 + u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) 82 + { 83 + if (length == 0) 84 + return 0; 85 + 86 + /* Access desired range through EMI interface */ 87 + if (offset >= MEC_EMI_RANGE_START && offset <= MEC_EMI_RANGE_END) { 88 + /* Ensure we don't straddle EMI region */ 89 + if (WARN_ON(offset + length - 1 > MEC_EMI_RANGE_END)) 90 + return 0; 91 + 92 + return cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, offset, length, 93 + msg); 94 + } 95 + 96 + if (WARN_ON(offset + length > MEC_EMI_RANGE_START && 97 + offset < MEC_EMI_RANGE_START)) 98 + return 0; 99 + 100 + return lpc_write_bytes(offset, length, msg); 101 + } 102 + 103 + void cros_ec_lpc_reg_init(void) 104 + { 105 + cros_ec_lpc_mec_init(); 106 + } 107 + 108 + void cros_ec_lpc_reg_destroy(void) 109 + { 110 + cros_ec_lpc_mec_destroy(); 111 + } 112 + 113 + #else /* CONFIG_CROS_EC_LPC_MEC */ 114 + 115 + u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest) 116 + { 117 + return lpc_read_bytes(offset, length, dest); 118 + } 119 + 120 + u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg) 121 + { 122 + return lpc_write_bytes(offset, length, msg); 123 + } 124 + 125 + void cros_ec_lpc_reg_init(void) 126 + { 127 + } 128 + 129 + void cros_ec_lpc_reg_destroy(void) 130 + { 131 + } 132 + 133 + #endif /* CONFIG_CROS_EC_LPC_MEC */
+110 -6
drivers/platform/chrome/cros_ec_proto.c
··· 150 150 } 151 151 EXPORT_SYMBOL(cros_ec_check_result); 152 152 153 + /* 154 + * cros_ec_get_host_event_wake_mask 155 + * 156 + * Get the mask of host events that cause wake from suspend. 157 + * 158 + * @ec_dev: EC device to call 159 + * @msg: message structure to use 160 + * @mask: result when function returns >=0. 161 + * 162 + * LOCKING: 163 + * the caller has ec_dev->lock mutex, or the caller knows there is 164 + * no other command in progress. 165 + */ 166 + static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, 167 + struct cros_ec_command *msg, 168 + uint32_t *mask) 169 + { 170 + struct ec_response_host_event_mask *r; 171 + int ret; 172 + 173 + msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK; 174 + msg->version = 0; 175 + msg->outsize = 0; 176 + msg->insize = sizeof(*r); 177 + 178 + ret = send_command(ec_dev, msg); 179 + if (ret > 0) { 180 + r = (struct ec_response_host_event_mask *)msg->data; 181 + *mask = r->mask; 182 + } 183 + 184 + return ret; 185 + } 186 + 153 187 static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, 154 188 int devidx, 155 189 struct cros_ec_command *msg) ··· 269 235 return ret; 270 236 } 271 237 238 + /* 239 + * cros_ec_get_host_command_version_mask 240 + * 241 + * Get the version mask of a given command. 242 + * 243 + * @ec_dev: EC device to call 244 + * @msg: message structure to use 245 + * @cmd: command to get the version of. 246 + * @mask: result when function returns 0. 247 + * 248 + * @return 0 on success, error code otherwise 249 + * 250 + * LOCKING: 251 + * the caller has ec_dev->lock mutex or the caller knows there is 252 + * no other command in progress. 253 + */ 272 254 static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, 273 255 u16 cmd, u32 *mask) 274 256 { ··· 306 256 pver = (struct ec_params_get_cmd_versions *)msg->data; 307 257 pver->cmd = cmd; 308 258 309 - ret = cros_ec_cmd_xfer(ec_dev, msg); 259 + ret = send_command(ec_dev, msg); 310 260 if (ret > 0) { 311 261 rver = (struct ec_response_get_cmd_versions *)msg->data; 312 262 *mask = rver->version_mask; ··· 420 370 ec_dev->mkbp_event_supported = 0; 421 371 else 422 372 ec_dev->mkbp_event_supported = 1; 373 + 374 + /* 375 + * Get host event wake mask, assume all events are wake events 376 + * if unavailable. 377 + */ 378 + ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg, 379 + &ec_dev->host_event_wake_mask); 380 + if (ret < 0) 381 + ec_dev->host_event_wake_mask = U32_MAX; 382 + 383 + ret = 0; 423 384 424 385 exit: 425 386 kfree(proto_msg); ··· 547 486 return ec_dev->event_size; 548 487 } 549 488 550 - int cros_ec_get_next_event(struct cros_ec_device *ec_dev) 489 + int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event) 551 490 { 552 - if (ec_dev->mkbp_event_supported) 553 - return get_next_event(ec_dev); 554 - else 555 - return get_keyboard_state_event(ec_dev); 491 + u32 host_event; 492 + int ret; 493 + 494 + if (!ec_dev->mkbp_event_supported) { 495 + ret = get_keyboard_state_event(ec_dev); 496 + if (ret < 0) 497 + return ret; 498 + 499 + if (wake_event) 500 + *wake_event = true; 501 + 502 + return ret; 503 + } 504 + 505 + ret = get_next_event(ec_dev); 506 + if (ret < 0) 507 + return ret; 508 + 509 + if (wake_event) { 510 + host_event = cros_ec_get_host_event(ec_dev); 511 + 512 + /* Consider non-host_event as wake event */ 513 + *wake_event = !host_event || 514 + !!(host_event & ec_dev->host_event_wake_mask); 515 + } 516 + 517 + return ret; 556 518 } 557 519 EXPORT_SYMBOL(cros_ec_get_next_event); 520 + 521 + u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev) 522 + { 523 + u32 host_event; 524 + 525 + BUG_ON(!ec_dev->mkbp_event_supported); 526 + 527 + if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT) 528 + return 0; 529 + 530 + if (ec_dev->event_size != sizeof(host_event)) { 531 + dev_warn(ec_dev->dev, "Invalid host event size\n"); 532 + return 0; 533 + } 534 + 535 + host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event); 536 + 537 + return host_event; 538 + } 539 + EXPORT_SYMBOL(cros_ec_get_host_event);
+18 -1
include/linux/mfd/cros_ec.h
··· 149 149 150 150 struct ec_response_get_next_event event_data; 151 151 int event_size; 152 + u32 host_event_wake_mask; 152 153 }; 153 154 154 155 /** ··· 173 172 u16 cmd_offset; 174 173 }; 175 174 175 + struct cros_ec_debugfs; 176 + 176 177 /* 177 178 * struct cros_ec_dev - ChromeOS EC device entry point 178 179 * ··· 182 179 * @cdev: Character device structure in /dev 183 180 * @ec_dev: cros_ec_device structure to talk to the physical device 184 181 * @dev: pointer to the platform device 182 + * @debug_info: cros_ec_debugfs structure for debugging information 185 183 * @cmd_offset: offset to apply for each command. 186 184 */ 187 185 struct cros_ec_dev { ··· 190 186 struct cdev cdev; 191 187 struct cros_ec_device *ec_dev; 192 188 struct device *dev; 189 + struct cros_ec_debugfs *debug_info; 193 190 u16 cmd_offset; 194 191 u32 features[2]; 195 192 }; ··· 300 295 * cros_ec_get_next_event - Fetch next event from the ChromeOS EC 301 296 * 302 297 * @ec_dev: Device to fetch event from 298 + * @wake_event: Pointer to a bool set to true upon return if the event might be 299 + * treated as a wake event. Ignored if null. 303 300 * 304 301 * Returns: 0 on success, Linux error number on failure 305 302 */ 306 - int cros_ec_get_next_event(struct cros_ec_device *ec_dev); 303 + int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event); 304 + 305 + /** 306 + * cros_ec_get_host_event - Return a mask of event set by the EC. 307 + * 308 + * When MKBP is supported, when the EC raises an interrupt, 309 + * We collect the events raised and call the functions in the ec notifier. 310 + * 311 + * This function is a helper to know which events are raised. 312 + */ 313 + u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev); 307 314 308 315 /* sysfs stuff */ 309 316 extern struct attribute_group cros_ec_attr_group;
+39 -3
include/linux/mfd/cros_ec_commands.h
··· 625 625 uint8_t cmd; /* Command to check */ 626 626 } __packed; 627 627 628 + struct ec_params_get_cmd_versions_v1 { 629 + uint16_t cmd; /* Command to check */ 630 + } __packed; 631 + 628 632 struct ec_response_get_cmd_versions { 629 633 /* 630 634 * Mask of supported versions; use EC_VER_MASK() to compare with a ··· 1162 1158 struct rgb_s color[8]; /* 0-3 are Google colors */ 1163 1159 } __packed; 1164 1160 1161 + /* Lightbar program */ 1162 + #define EC_LB_PROG_LEN 192 1163 + struct lightbar_program { 1164 + uint8_t size; 1165 + uint8_t data[EC_LB_PROG_LEN]; 1166 + }; 1167 + 1165 1168 struct ec_params_lightbar { 1166 1169 uint8_t cmd; /* Command (see enum lightbar_command) */ 1167 1170 union { 1168 1171 struct { 1169 1172 /* no args */ 1170 1173 } dump, off, on, init, get_seq, get_params_v0, get_params_v1, 1171 - version, get_brightness, get_demo; 1174 + version, get_brightness, get_demo, suspend, resume; 1172 1175 1173 1176 struct { 1174 1177 uint8_t num; ··· 1193 1182 uint8_t led; 1194 1183 } get_rgb; 1195 1184 1185 + struct { 1186 + uint8_t enable; 1187 + } manual_suspend_ctrl; 1188 + 1196 1189 struct lightbar_params_v0 set_params_v0; 1197 1190 struct lightbar_params_v1 set_params_v1; 1191 + struct lightbar_program set_program; 1198 1192 }; 1199 1193 } __packed; 1200 1194 ··· 1232 1216 struct { 1233 1217 /* no return params */ 1234 1218 } off, on, init, set_brightness, seq, reg, set_rgb, 1235 - demo, set_params_v0, set_params_v1; 1219 + demo, set_params_v0, set_params_v1, 1220 + set_program, manual_suspend_ctrl, suspend, resume; 1236 1221 }; 1237 1222 } __packed; 1238 1223 ··· 1257 1240 LIGHTBAR_CMD_GET_DEMO = 15, 1258 1241 LIGHTBAR_CMD_GET_PARAMS_V1 = 16, 1259 1242 LIGHTBAR_CMD_SET_PARAMS_V1 = 17, 1243 + LIGHTBAR_CMD_SET_PROGRAM = 18, 1244 + LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL = 19, 1245 + LIGHTBAR_CMD_SUSPEND = 20, 1246 + LIGHTBAR_CMD_RESUME = 21, 1260 1247 LIGHTBAR_NUM_CMDS 1261 1248 }; 1262 1249 ··· 2306 2285 #define EC_CMD_CONSOLE_SNAPSHOT 0x97 2307 2286 2308 2287 /* 2309 - * Read next chunk of data from saved snapshot. 2288 + * Read data from the saved snapshot. If the subcmd parameter is 2289 + * CONSOLE_READ_NEXT, this will return data starting from the beginning of 2290 + * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the 2291 + * end of the previous snapshot. 2292 + * 2293 + * The params are only looked at in version >= 1 of this command. Prior 2294 + * versions will just default to CONSOLE_READ_NEXT behavior. 2310 2295 * 2311 2296 * Response is null-terminated string. Empty string, if there is no more 2312 2297 * remaining output. 2313 2298 */ 2314 2299 #define EC_CMD_CONSOLE_READ 0x98 2300 + 2301 + enum ec_console_read_subcmd { 2302 + CONSOLE_READ_NEXT = 0, 2303 + CONSOLE_READ_RECENT 2304 + }; 2305 + 2306 + struct ec_params_console_read_v1 { 2307 + uint8_t subcmd; /* enum ec_console_read_subcmd */ 2308 + } __packed; 2315 2309 2316 2310 /*****************************************************************************/ 2317 2311
+90
include/linux/mfd/cros_ec_lpc_mec.h
··· 1 + /* 2 + * cros_ec_lpc_mec - LPC variant I/O for Microchip EC 3 + * 4 + * Copyright (C) 2016 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 + * This driver uses the Chrome OS EC byte-level message-based protocol for 16 + * communicating the keyboard state (which keys are pressed) from a keyboard EC 17 + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, 18 + * but everything else (including deghosting) is done here. The main 19 + * motivation for this is to keep the EC firmware as simple as possible, since 20 + * it cannot be easily upgraded and EC flash/IRAM space is relatively 21 + * expensive. 22 + */ 23 + 24 + #ifndef __LINUX_MFD_CROS_EC_MEC_H 25 + #define __LINUX_MFD_CROS_EC_MEC_H 26 + 27 + #include <linux/mfd/cros_ec_commands.h> 28 + 29 + enum cros_ec_lpc_mec_emi_access_mode { 30 + /* 8-bit access */ 31 + ACCESS_TYPE_BYTE = 0x0, 32 + /* 16-bit access */ 33 + ACCESS_TYPE_WORD = 0x1, 34 + /* 32-bit access */ 35 + ACCESS_TYPE_LONG = 0x2, 36 + /* 37 + * 32-bit access, read or write of MEC_EMI_EC_DATA_B3 causes the 38 + * EC data register to be incremented. 39 + */ 40 + ACCESS_TYPE_LONG_AUTO_INCREMENT = 0x3, 41 + }; 42 + 43 + enum cros_ec_lpc_mec_io_type { 44 + MEC_IO_READ, 45 + MEC_IO_WRITE, 46 + }; 47 + 48 + /* Access IO ranges 0x800 thru 0x9ff using EMI interface instead of LPC */ 49 + #define MEC_EMI_RANGE_START EC_HOST_CMD_REGION0 50 + #define MEC_EMI_RANGE_END (EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE) 51 + 52 + /* EMI registers are relative to base */ 53 + #define MEC_EMI_BASE 0x800 54 + #define MEC_EMI_HOST_TO_EC (MEC_EMI_BASE + 0) 55 + #define MEC_EMI_EC_TO_HOST (MEC_EMI_BASE + 1) 56 + #define MEC_EMI_EC_ADDRESS_B0 (MEC_EMI_BASE + 2) 57 + #define MEC_EMI_EC_ADDRESS_B1 (MEC_EMI_BASE + 3) 58 + #define MEC_EMI_EC_DATA_B0 (MEC_EMI_BASE + 4) 59 + #define MEC_EMI_EC_DATA_B1 (MEC_EMI_BASE + 5) 60 + #define MEC_EMI_EC_DATA_B2 (MEC_EMI_BASE + 6) 61 + #define MEC_EMI_EC_DATA_B3 (MEC_EMI_BASE + 7) 62 + 63 + /* 64 + * cros_ec_lpc_mec_init 65 + * 66 + * Initialize MEC I/O. 67 + */ 68 + void cros_ec_lpc_mec_init(void); 69 + 70 + /* 71 + * cros_ec_lpc_mec_destroy 72 + * 73 + * Cleanup MEC I/O. 74 + */ 75 + void cros_ec_lpc_mec_destroy(void); 76 + 77 + /** 78 + * cros_ec_lpc_io_bytes_mec - Read / write bytes to MEC EMI port 79 + * 80 + * @io_type: MEC_IO_READ or MEC_IO_WRITE, depending on request 81 + * @offset: Base read / write address 82 + * @length: Number of bytes to read / write 83 + * @buf: Destination / source buffer 84 + * 85 + * @return 8-bit checksum of all bytes read / written 86 + */ 87 + u8 cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, 88 + unsigned int offset, unsigned int length, u8 *buf); 89 + 90 + #endif /* __LINUX_MFD_CROS_EC_MEC_H */
+61
include/linux/mfd/cros_ec_lpc_reg.h
··· 1 + /* 2 + * cros_ec_lpc_reg - LPC access to the Chrome OS Embedded Controller 3 + * 4 + * Copyright (C) 2016 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 + * This driver uses the Chrome OS EC byte-level message-based protocol for 16 + * communicating the keyboard state (which keys are pressed) from a keyboard EC 17 + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, 18 + * but everything else (including deghosting) is done here. The main 19 + * motivation for this is to keep the EC firmware as simple as possible, since 20 + * it cannot be easily upgraded and EC flash/IRAM space is relatively 21 + * expensive. 22 + */ 23 + 24 + #ifndef __LINUX_MFD_CROS_EC_REG_H 25 + #define __LINUX_MFD_CROS_EC_REG_H 26 + 27 + /** 28 + * cros_ec_lpc_read_bytes - Read bytes from a given LPC-mapped address. 29 + * Returns 8-bit checksum of all bytes read. 30 + * 31 + * @offset: Base read address 32 + * @length: Number of bytes to read 33 + * @dest: Destination buffer 34 + */ 35 + u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest); 36 + 37 + /** 38 + * cros_ec_lpc_write_bytes - Write bytes to a given LPC-mapped address. 39 + * Returns 8-bit checksum of all bytes written. 40 + * 41 + * @offset: Base write address 42 + * @length: Number of bytes to write 43 + * @msg: Write data buffer 44 + */ 45 + u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg); 46 + 47 + /** 48 + * cros_ec_lpc_reg_init 49 + * 50 + * Initialize register I/O. 51 + */ 52 + void cros_ec_lpc_reg_init(void); 53 + 54 + /** 55 + * cros_ec_lpc_reg_destroy 56 + * 57 + * Cleanup reg I/O. 58 + */ 59 + void cros_ec_lpc_reg_destroy(void); 60 + 61 + #endif /* __LINUX_MFD_CROS_EC_REG_H */