aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS3
-rw-r--r--drivers/mfd/cros_ec.c13
-rw-r--r--drivers/platform/chrome/Kconfig14
-rw-r--r--drivers/platform/chrome/Makefile7
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c401
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.h27
-rw-r--r--drivers/platform/chrome/cros_ec_dev.c40
-rw-r--r--drivers/platform/chrome/cros_ec_dev.h6
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c197
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c168
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_mec.c140
-rw-r--r--drivers/platform/chrome/cros_ec_lpc_reg.c133
-rw-r--r--drivers/platform/chrome/cros_ec_proto.c116
-rw-r--r--include/linux/mfd/cros_ec.h19
-rw-r--r--include/linux/mfd/cros_ec_commands.h42
-rw-r--r--include/linux/mfd/cros_ec_lpc_mec.h90
-rw-r--r--include/linux/mfd/cros_ec_lpc_reg.h61
17 files changed, 1393 insertions, 84 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index d8eab9322ba2..f6ec1be48609 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3319,9 +3319,10 @@ F: Documentation/devicetree/bindings/input/touchscreen/chipone_icn8318.txt
3319F: drivers/input/touchscreen/chipone_icn8318.c 3319F: drivers/input/touchscreen/chipone_icn8318.c
3320 3320
3321CHROME HARDWARE PLATFORM SUPPORT 3321CHROME HARDWARE PLATFORM SUPPORT
3322M: Benson Leung <bleung@chromium.org>
3322M: Olof Johansson <olof@lixom.net> 3323M: Olof Johansson <olof@lixom.net>
3323S: Maintained 3324S: Maintained
3324T: git git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform.git 3325T: git git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git
3325F: drivers/platform/chrome/ 3326F: drivers/platform/chrome/
3326 3327
3327CISCO VIC ETHERNET NIC DRIVER 3328CISCO VIC ETHERNET NIC DRIVER
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index dc6ce9091694..b0ca5a4c841e 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -54,12 +54,19 @@ static const struct mfd_cell ec_pd_cell = {
54static irqreturn_t ec_irq_thread(int irq, void *data) 54static irqreturn_t ec_irq_thread(int irq, void *data)
55{ 55{
56 struct cros_ec_device *ec_dev = data; 56 struct cros_ec_device *ec_dev = data;
57 bool wake_event = true;
57 int ret; 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 pm_wakeup_event(ec_dev->dev, 0); 68 pm_wakeup_event(ec_dev->dev, 0);
61 69
62 ret = cros_ec_get_next_event(ec_dev);
63 if (ret > 0) 70 if (ret > 0)
64 blocking_notifier_call_chain(&ec_dev->event_notifier, 71 blocking_notifier_call_chain(&ec_dev->event_notifier,
65 0, ec_dev); 72 0, ec_dev);
@@ -224,7 +231,7 @@ EXPORT_SYMBOL(cros_ec_suspend);
224 231
225static void cros_ec_drain_events(struct cros_ec_device *ec_dev) 232static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
226{ 233{
227 while (cros_ec_get_next_event(ec_dev) > 0) 234 while (cros_ec_get_next_event(ec_dev, NULL) > 0)
228 blocking_notifier_call_chain(&ec_dev->event_notifier, 235 blocking_notifier_call_chain(&ec_dev->event_notifier,
229 1, ec_dev); 236 1, ec_dev);
230} 237}
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 76bdae1a93bb..0ad6e290bbda 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -49,7 +49,7 @@ config CROS_EC_CHARDEV
49 49
50config CROS_EC_LPC 50config CROS_EC_LPC
51 tristate "ChromeOS Embedded Controller (LPC)" 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 help 53 help
54 If you say Y here, you get support for talking to the ChromeOS EC 54 If you say Y here, you get support for talking to the ChromeOS EC
55 over an LPC bus. This uses a simple byte-level protocol with a 55 over an LPC bus. This uses a simple byte-level protocol with a
@@ -59,6 +59,18 @@ config CROS_EC_LPC
59 To compile this driver as a module, choose M here: the 59 To compile this driver as a module, choose M here: the
60 module will be called cros_ec_lpc. 60 module will be called cros_ec_lpc.
61 61
62config 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.
73
62config CROS_EC_PROTO 74config CROS_EC_PROTO
63 bool 75 bool
64 help 76 help
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 4f3462783a3c..66c345ca35fc 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -2,8 +2,11 @@
2obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 2obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
3obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o 3obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
4cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \ 4cros_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
6obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o 7obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
7obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o 8cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o
9cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
10obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
8obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o 11obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o
9obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o 12obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
new file mode 100644
index 000000000000..4cc66f405760
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -0,0 +1,401 @@
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 */
52struct 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 */
69static 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
139resched:
140 schedule_delayed_work(&debug_info->log_poll_work,
141 msecs_to_jiffies(LOG_POLL_SEC * 1000));
142}
143
144static 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
151static 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
189error:
190 mutex_unlock(&debug_info->log_mutex);
191 return ret;
192}
193
194static 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
212static int cros_ec_console_log_release(struct inode *inode, struct file *file)
213{
214 return 0;
215}
216
217const 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
226static 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
256static 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
307static 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
315static 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
356free:
357 devm_kfree(debug_info->ec->dev, msg);
358 return ret;
359}
360
361int 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
389remove_debugfs:
390 debugfs_remove_recursive(debug_info->dir);
391 return ret;
392}
393
394void 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}
diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
new file mode 100644
index 000000000000..1ff3a50aa1b8
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_debugfs.h
@@ -0,0 +1,27 @@
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 */
24int cros_ec_debugfs_init(struct cros_ec_dev *ec);
25void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
26
27#endif /* _DRV_CROS_EC_DEBUGFS_H_ */
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index 6aa120cd0574..cf6c4f0846b8 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -21,9 +21,11 @@
21#include <linux/mfd/core.h> 21#include <linux/mfd/core.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/pm.h>
24#include <linux/slab.h> 25#include <linux/slab.h>
25#include <linux/uaccess.h> 26#include <linux/uaccess.h>
26 27
28#include "cros_ec_debugfs.h"
27#include "cros_ec_dev.h" 29#include "cros_ec_dev.h"
28 30
29/* Device variables */ 31/* Device variables */
@@ -427,10 +429,16 @@ static int ec_device_probe(struct platform_device *pdev)
427 goto failed; 429 goto failed;
428 } 430 }
429 431
432 if (cros_ec_debugfs_init(ec))
433 dev_warn(dev, "failed to create debugfs directory\n");
434
430 /* check whether this EC is a sensor hub. */ 435 /* check whether this EC is a sensor hub. */
431 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) 436 if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
432 cros_ec_sensors_register(ec); 437 cros_ec_sensors_register(ec);
433 438
439 /* Take control of the lightbar from the EC. */
440 lb_manual_suspend_ctrl(ec, 1);
441
434 return 0; 442 return 0;
435 443
436failed: 444failed:
@@ -441,6 +449,12 @@ failed:
441static int ec_device_remove(struct platform_device *pdev) 449static int ec_device_remove(struct platform_device *pdev)
442{ 450{
443 struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); 451 struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
452
453 /* Let the EC take over the lightbar again. */
454 lb_manual_suspend_ctrl(ec, 0);
455
456 cros_ec_debugfs_remove(ec);
457
444 cdev_del(&ec->cdev); 458 cdev_del(&ec->cdev);
445 device_unregister(&ec->class_dev); 459 device_unregister(&ec->class_dev);
446 return 0; 460 return 0;
@@ -452,9 +466,35 @@ static const struct platform_device_id cros_ec_id[] = {
452}; 466};
453MODULE_DEVICE_TABLE(platform, cros_ec_id); 467MODULE_DEVICE_TABLE(platform, cros_ec_id);
454 468
469static __maybe_unused int ec_device_suspend(struct device *dev)
470{
471 struct cros_ec_dev *ec = dev_get_drvdata(dev);
472
473 lb_suspend(ec);
474
475 return 0;
476}
477
478static __maybe_unused int ec_device_resume(struct device *dev)
479{
480 struct cros_ec_dev *ec = dev_get_drvdata(dev);
481
482 lb_resume(ec);
483
484 return 0;
485}
486
487static const struct dev_pm_ops cros_ec_dev_pm_ops = {
488#ifdef CONFIG_PM_SLEEP
489 .suspend = ec_device_suspend,
490 .resume = ec_device_resume,
491#endif
492};
493
455static struct platform_driver cros_ec_dev_driver = { 494static struct platform_driver cros_ec_dev_driver = {
456 .driver = { 495 .driver = {
457 .name = "cros-ec-ctl", 496 .name = "cros-ec-ctl",
497 .pm = &cros_ec_dev_pm_ops,
458 }, 498 },
459 .probe = ec_device_probe, 499 .probe = ec_device_probe,
460 .remove = ec_device_remove, 500 .remove = ec_device_remove,
diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h
index bfd2c84c3571..45e9453608c5 100644
--- a/drivers/platform/chrome/cros_ec_dev.h
+++ b/drivers/platform/chrome/cros_ec_dev.h
@@ -43,4 +43,10 @@ struct cros_ec_readmem {
43#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) 43#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command)
44#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) 44#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem)
45 45
46/* Lightbar utilities */
47extern bool ec_has_lightbar(struct cros_ec_dev *ec);
48extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable);
49extern int lb_suspend(struct cros_ec_dev *ec);
50extern int lb_resume(struct cros_ec_dev *ec);
51
46#endif /* _CROS_EC_DEV_H_ */ 52#endif /* _CROS_EC_DEV_H_ */
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 8df3d447cacf..fd2b047a2748 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -38,6 +38,13 @@
38/* Rate-limit the lightbar interface to prevent DoS. */ 38/* Rate-limit the lightbar interface to prevent DoS. */
39static unsigned long lb_interval_jiffies = 50 * HZ / 1000; 39static 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 */
45static bool userspace_control;
46static struct cros_ec_dev *ec_with_lightbar;
47
41static ssize_t interval_msec_show(struct device *dev, 48static ssize_t interval_msec_show(struct device *dev,
42 struct device_attribute *attr, char *buf) 49 struct device_attribute *attr, char *buf)
43{ 50{
@@ -295,7 +302,8 @@ exit:
295 302
296static char const *seqname[] = { 303static char const *seqname[] = {
297 "ERROR", "S5", "S3", "S0", "S5S3", "S3S0", 304 "ERROR", "S5", "S3", "S0", "S5S3", "S3S0",
298 "S0S3", "S3S5", "STOP", "RUN", "PULSE", "TEST", "KONAMI", 305 "S0S3", "S3S5", "STOP", "RUN", "KONAMI",
306 "TAP", "PROGRAM",
299}; 307};
300 308
301static ssize_t sequence_show(struct device *dev, 309static ssize_t sequence_show(struct device *dev,
@@ -340,6 +348,89 @@ exit:
340 return ret; 348 return ret;
341} 349}
342 350
351static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
352{
353 struct ec_params_lightbar *param;
354 struct cros_ec_command *msg;
355 int ret;
356
357 msg = alloc_lightbar_cmd_msg(ec);
358 if (!msg)
359 return -ENOMEM;
360
361 param = (struct ec_params_lightbar *)msg->data;
362 param->cmd = cmd;
363
364 ret = lb_throttle();
365 if (ret)
366 goto error;
367
368 ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
369 if (ret < 0)
370 goto error;
371 if (msg->result != EC_RES_SUCCESS) {
372 ret = -EINVAL;
373 goto error;
374 }
375 ret = 0;
376error:
377 kfree(msg);
378
379 return ret;
380}
381
382int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
383{
384 struct ec_params_lightbar *param;
385 struct cros_ec_command *msg;
386 int ret;
387
388 if (ec != ec_with_lightbar)
389 return 0;
390
391 msg = alloc_lightbar_cmd_msg(ec);
392 if (!msg)
393 return -ENOMEM;
394
395 param = (struct ec_params_lightbar *)msg->data;
396
397 param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL;
398 param->manual_suspend_ctrl.enable = enable;
399
400 ret = lb_throttle();
401 if (ret)
402 goto error;
403
404 ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
405 if (ret < 0)
406 goto error;
407 if (msg->result != EC_RES_SUCCESS) {
408 ret = -EINVAL;
409 goto error;
410 }
411 ret = 0;
412error:
413 kfree(msg);
414
415 return ret;
416}
417
418int lb_suspend(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_SUSPEND);
424}
425
426int lb_resume(struct cros_ec_dev *ec)
427{
428 if (userspace_control || ec != ec_with_lightbar)
429 return 0;
430
431 return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
432}
433
343static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, 434static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
344 const char *buf, size_t count) 435 const char *buf, size_t count)
345{ 436{
@@ -390,6 +481,93 @@ exit:
390 return ret; 481 return ret;
391} 482}
392 483
484static ssize_t program_store(struct device *dev, struct device_attribute *attr,
485 const char *buf, size_t count)
486{
487 int extra_bytes, max_size, ret;
488 struct ec_params_lightbar *param;
489 struct cros_ec_command *msg;
490 struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
491 class_dev);
492
493 /*
494 * We might need to reject the program for size reasons. The EC
495 * enforces a maximum program size, but we also don't want to try
496 * and send a program that is too big for the protocol. In order
497 * to ensure the latter, we also need to ensure we have extra bytes
498 * to represent the rest of the packet.
499 */
500 extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
501 max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
502 if (count > max_size) {
503 dev_err(dev, "Program is %u bytes, too long to send (max: %u)",
504 (unsigned int)count, max_size);
505
506 return -EINVAL;
507 }
508
509 msg = alloc_lightbar_cmd_msg(ec);
510 if (!msg)
511 return -ENOMEM;
512
513 ret = lb_throttle();
514 if (ret)
515 goto exit;
516
517 dev_info(dev, "Copying %zu byte program to EC", count);
518
519 param = (struct ec_params_lightbar *)msg->data;
520 param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
521
522 param->set_program.size = count;
523 memcpy(param->set_program.data, buf, count);
524
525 /*
526 * We need to set the message size manually or else it will use
527 * EC_LB_PROG_LEN. This might be too long, and the program
528 * is unlikely to use all of the space.
529 */
530 msg->outsize = count + extra_bytes;
531
532 ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
533 if (ret < 0)
534 goto exit;
535 if (msg->result != EC_RES_SUCCESS) {
536 ret = -EINVAL;
537 goto exit;
538 }
539
540 ret = count;
541exit:
542 kfree(msg);
543
544 return ret;
545}
546
547static ssize_t userspace_control_show(struct device *dev,
548 struct device_attribute *attr,
549 char *buf)
550{
551 return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control);
552}
553
554static ssize_t userspace_control_store(struct device *dev,
555 struct device_attribute *attr,
556 const char *buf,
557 size_t count)
558{
559 bool enable;
560 int ret;
561
562 ret = strtobool(buf, &enable);
563 if (ret < 0)
564 return ret;
565
566 userspace_control = enable;
567
568 return count;
569}
570
393/* Module initialization */ 571/* Module initialization */
394 572
395static DEVICE_ATTR_RW(interval_msec); 573static DEVICE_ATTR_RW(interval_msec);
@@ -397,15 +575,25 @@ static DEVICE_ATTR_RO(version);
397static DEVICE_ATTR_WO(brightness); 575static DEVICE_ATTR_WO(brightness);
398static DEVICE_ATTR_WO(led_rgb); 576static DEVICE_ATTR_WO(led_rgb);
399static DEVICE_ATTR_RW(sequence); 577static DEVICE_ATTR_RW(sequence);
578static DEVICE_ATTR_WO(program);
579static DEVICE_ATTR_RW(userspace_control);
580
400static struct attribute *__lb_cmds_attrs[] = { 581static struct attribute *__lb_cmds_attrs[] = {
401 &dev_attr_interval_msec.attr, 582 &dev_attr_interval_msec.attr,
402 &dev_attr_version.attr, 583 &dev_attr_version.attr,
403 &dev_attr_brightness.attr, 584 &dev_attr_brightness.attr,
404 &dev_attr_led_rgb.attr, 585 &dev_attr_led_rgb.attr,
405 &dev_attr_sequence.attr, 586 &dev_attr_sequence.attr,
587 &dev_attr_program.attr,
588 &dev_attr_userspace_control.attr,
406 NULL, 589 NULL,
407}; 590};
408 591
592bool ec_has_lightbar(struct cros_ec_dev *ec)
593{
594 return !!get_lightbar_version(ec, NULL, NULL);
595}
596
409static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, 597static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
410 struct attribute *a, int n) 598 struct attribute *a, int n)
411{ 599{
@@ -422,10 +610,11 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
422 return 0; 610 return 0;
423 611
424 /* Only instantiate this stuff if the EC has a lightbar */ 612 /* Only instantiate this stuff if the EC has a lightbar */
425 if (get_lightbar_version(ec, NULL, NULL)) 613 if (ec_has_lightbar(ec)) {
614 ec_with_lightbar = ec;
426 return a->mode; 615 return a->mode;
427 else 616 }
428 return 0; 617 return 0;
429} 618}
430 619
431struct attribute_group cros_ec_lightbar_attr_group = { 620struct attribute_group cros_ec_lightbar_attr_group = {
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index f9a245465fd0..2b6436d1b6a4 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -21,24 +21,29 @@
21 * expensive. 21 * expensive.
22 */ 22 */
23 23
24#include <linux/acpi.h>
24#include <linux/dmi.h> 25#include <linux/dmi.h>
25#include <linux/delay.h> 26#include <linux/delay.h>
26#include <linux/io.h> 27#include <linux/io.h>
27#include <linux/mfd/cros_ec.h> 28#include <linux/mfd/cros_ec.h>
28#include <linux/mfd/cros_ec_commands.h> 29#include <linux/mfd/cros_ec_commands.h>
30#include <linux/mfd/cros_ec_lpc_reg.h>
29#include <linux/module.h> 31#include <linux/module.h>
30#include <linux/platform_device.h> 32#include <linux/platform_device.h>
31#include <linux/printk.h> 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
35static int ec_response_timed_out(void) 38static int ec_response_timed_out(void)
36{ 39{
37 unsigned long one_second = jiffies + HZ; 40 unsigned long one_second = jiffies + HZ;
41 u8 data;
38 42
39 usleep_range(200, 300); 43 usleep_range(200, 300);
40 do { 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 return 0; 47 return 0;
43 usleep_range(100, 200); 48 usleep_range(100, 200);
44 } while (time_before(jiffies, one_second)); 49 } while (time_before(jiffies, one_second));
@@ -51,21 +56,20 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
51{ 56{
52 struct ec_host_request *request; 57 struct ec_host_request *request;
53 struct ec_host_response response; 58 struct ec_host_response response;
54 u8 sum = 0; 59 u8 sum;
55 int i;
56 int ret = 0; 60 int ret = 0;
57 u8 *dout; 61 u8 *dout;
58 62
59 ret = cros_ec_prepare_tx(ec, msg); 63 ret = cros_ec_prepare_tx(ec, msg);
60 64
61 /* Write buffer */ 65 /* Write buffer */
62 for (i = 0; i < ret; i++) 66 cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout);
63 outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i);
64 67
65 request = (struct ec_host_request *)ec->dout; 68 request = (struct ec_host_request *)ec->dout;
66 69
67 /* Here we go */ 70 /* Here we go */
68 outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); 71 sum = EC_COMMAND_PROTOCOL_3;
72 cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
69 73
70 if (ec_response_timed_out()) { 74 if (ec_response_timed_out()) {
71 dev_warn(ec->dev, "EC responsed timed out\n"); 75 dev_warn(ec->dev, "EC responsed timed out\n");
@@ -74,17 +78,15 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
74 } 78 }
75 79
76 /* Check result */ 80 /* Check result */
77 msg->result = inb(EC_LPC_ADDR_HOST_DATA); 81 msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
78 ret = cros_ec_check_result(ec, msg); 82 ret = cros_ec_check_result(ec, msg);
79 if (ret) 83 if (ret)
80 goto done; 84 goto done;
81 85
82 /* Read back response */ 86 /* Read back response */
83 dout = (u8 *)&response; 87 dout = (u8 *)&response;
84 for (i = 0; i < sizeof(response); i++) { 88 sum = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET, sizeof(response),
85 dout[i] = inb(EC_LPC_ADDR_HOST_PACKET + i); 89 dout);
86 sum += dout[i];
87 }
88 90
89 msg->result = response.result; 91 msg->result = response.result;
90 92
@@ -97,11 +99,9 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec,
97 } 99 }
98 100
99 /* Read response and process checksum */ 101 /* Read response and process checksum */
100 for (i = 0; i < response.data_len; i++) { 102 sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PACKET +
101 msg->data[i] = 103 sizeof(response), response.data_len,
102 inb(EC_LPC_ADDR_HOST_PACKET + sizeof(response) + i); 104 msg->data);
103 sum += msg->data[i];
104 }
105 105
106 if (sum) { 106 if (sum) {
107 dev_err(ec->dev, 107 dev_err(ec->dev,
@@ -121,8 +121,7 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
121 struct cros_ec_command *msg) 121 struct cros_ec_command *msg)
122{ 122{
123 struct ec_lpc_host_args args; 123 struct ec_lpc_host_args args;
124 int csum; 124 u8 sum;
125 int i;
126 int ret = 0; 125 int ret = 0;
127 126
128 if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE || 127 if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE ||
@@ -139,24 +138,20 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
139 args.data_size = msg->outsize; 138 args.data_size = msg->outsize;
140 139
141 /* Initialize checksum */ 140 /* Initialize checksum */
142 csum = msg->command + args.flags + 141 sum = msg->command + args.flags + args.command_version + args.data_size;
143 args.command_version + args.data_size;
144 142
145 /* Copy data and update checksum */ 143 /* Copy data and update checksum */
146 for (i = 0; i < msg->outsize; i++) { 144 sum += cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_PARAM, msg->outsize,
147 outb(msg->data[i], EC_LPC_ADDR_HOST_PARAM + i); 145 msg->data);
148 csum += msg->data[i];
149 }
150 146
151 /* Finalize checksum and write args */ 147 /* Finalize checksum and write args */
152 args.checksum = csum & 0xFF; 148 args.checksum = sum;
153 outb(args.flags, EC_LPC_ADDR_HOST_ARGS); 149 cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
154 outb(args.command_version, EC_LPC_ADDR_HOST_ARGS + 1); 150 (u8 *)&args);
155 outb(args.data_size, EC_LPC_ADDR_HOST_ARGS + 2);
156 outb(args.checksum, EC_LPC_ADDR_HOST_ARGS + 3);
157 151
158 /* Here we go */ 152 /* Here we go */
159 outb(msg->command, EC_LPC_ADDR_HOST_CMD); 153 sum = msg->command;
154 cros_ec_lpc_write_bytes(EC_LPC_ADDR_HOST_CMD, 1, &sum);
160 155
161 if (ec_response_timed_out()) { 156 if (ec_response_timed_out()) {
162 dev_warn(ec->dev, "EC responsed timed out\n"); 157 dev_warn(ec->dev, "EC responsed timed out\n");
@@ -165,16 +160,14 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
165 } 160 }
166 161
167 /* Check result */ 162 /* Check result */
168 msg->result = inb(EC_LPC_ADDR_HOST_DATA); 163 msg->result = cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_DATA, 1, &sum);
169 ret = cros_ec_check_result(ec, msg); 164 ret = cros_ec_check_result(ec, msg);
170 if (ret) 165 if (ret)
171 goto done; 166 goto done;
172 167
173 /* Read back args */ 168 /* Read back args */
174 args.flags = inb(EC_LPC_ADDR_HOST_ARGS); 169 cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_ARGS, sizeof(args),
175 args.command_version = inb(EC_LPC_ADDR_HOST_ARGS + 1); 170 (u8 *)&args);
176 args.data_size = inb(EC_LPC_ADDR_HOST_ARGS + 2);
177 args.checksum = inb(EC_LPC_ADDR_HOST_ARGS + 3);
178 171
179 if (args.data_size > msg->insize) { 172 if (args.data_size > msg->insize) {
180 dev_err(ec->dev, 173 dev_err(ec->dev,
@@ -185,20 +178,17 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
185 } 178 }
186 179
187 /* Start calculating response checksum */ 180 /* Start calculating response checksum */
188 csum = msg->command + args.flags + 181 sum = msg->command + args.flags + args.command_version + args.data_size;
189 args.command_version + args.data_size;
190 182
191 /* Read response and update checksum */ 183 /* Read response and update checksum */
192 for (i = 0; i < args.data_size; i++) { 184 sum += cros_ec_lpc_read_bytes(EC_LPC_ADDR_HOST_PARAM, args.data_size,
193 msg->data[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); 185 msg->data);
194 csum += msg->data[i];
195 }
196 186
197 /* Verify checksum */ 187 /* Verify checksum */
198 if (args.checksum != (csum & 0xFF)) { 188 if (args.checksum != sum) {
199 dev_err(ec->dev, 189 dev_err(ec->dev,
200 "bad packet checksum, expected %02x, got %02x\n", 190 "bad packet checksum, expected %02x, got %02x\n",
201 args.checksum, csum & 0xFF); 191 args.checksum, sum);
202 ret = -EBADMSG; 192 ret = -EBADMSG;
203 goto done; 193 goto done;
204 } 194 }
@@ -222,14 +212,13 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
222 212
223 /* fixed length */ 213 /* fixed length */
224 if (bytes) { 214 if (bytes) {
225 for (; cnt < bytes; i++, s++, cnt++) 215 cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + offset, bytes, s);
226 *s = inb(EC_LPC_ADDR_MEMMAP + i); 216 return bytes;
227 return cnt;
228 } 217 }
229 218
230 /* string */ 219 /* string */
231 for (; i < EC_MEMMAP_SIZE; i++, s++) { 220 for (; i < EC_MEMMAP_SIZE; i++, s++) {
232 *s = inb(EC_LPC_ADDR_MEMMAP + i); 221 cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + i, 1, s);
233 cnt++; 222 cnt++;
234 if (!*s) 223 if (!*s)
235 break; 224 break;
@@ -238,10 +227,23 @@ static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
238 return cnt; 227 return cnt;
239} 228}
240 229
230static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
231{
232 struct cros_ec_device *ec_dev = data;
233
234 if (ec_dev->mkbp_event_supported &&
235 cros_ec_get_next_event(ec_dev, NULL) > 0)
236 blocking_notifier_call_chain(&ec_dev->event_notifier, 0,
237 ec_dev);
238}
239
241static int cros_ec_lpc_probe(struct platform_device *pdev) 240static int cros_ec_lpc_probe(struct platform_device *pdev)
242{ 241{
243 struct device *dev = &pdev->dev; 242 struct device *dev = &pdev->dev;
243 struct acpi_device *adev;
244 acpi_status status;
244 struct cros_ec_device *ec_dev; 245 struct cros_ec_device *ec_dev;
246 u8 buf[2];
245 int ret; 247 int ret;
246 248
247 if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE, 249 if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
@@ -250,8 +252,8 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
250 return -EBUSY; 252 return -EBUSY;
251 } 253 }
252 254
253 if ((inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E') || 255 cros_ec_lpc_read_bytes(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf);
254 (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C')) { 256 if (buf[0] != 'E' || buf[1] != 'C') {
255 dev_err(dev, "EC ID not detected\n"); 257 dev_err(dev, "EC ID not detected\n");
256 return -ENODEV; 258 return -ENODEV;
257 } 259 }
@@ -287,12 +289,33 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
287 return ret; 289 return ret;
288 } 290 }
289 291
292 /*
293 * Connect a notify handler to process MKBP messages if we have a
294 * companion ACPI device.
295 */
296 adev = ACPI_COMPANION(dev);
297 if (adev) {
298 status = acpi_install_notify_handler(adev->handle,
299 ACPI_ALL_NOTIFY,
300 cros_ec_lpc_acpi_notify,
301 ec_dev);
302 if (ACPI_FAILURE(status))
303 dev_warn(dev, "Failed to register notifier %08x\n",
304 status);
305 }
306
290 return 0; 307 return 0;
291} 308}
292 309
293static int cros_ec_lpc_remove(struct platform_device *pdev) 310static int cros_ec_lpc_remove(struct platform_device *pdev)
294{ 311{
295 struct cros_ec_device *ec_dev; 312 struct cros_ec_device *ec_dev;
313 struct acpi_device *adev;
314
315 adev = ACPI_COMPANION(&pdev->dev);
316 if (adev)
317 acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
318 cros_ec_lpc_acpi_notify);
296 319
297 ec_dev = platform_get_drvdata(pdev); 320 ec_dev = platform_get_drvdata(pdev);
298 cros_ec_remove(ec_dev); 321 cros_ec_remove(ec_dev);
@@ -300,6 +323,12 @@ static int cros_ec_lpc_remove(struct platform_device *pdev)
300 return 0; 323 return 0;
301} 324}
302 325
326static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = {
327 { ACPI_DRV_NAME, 0 },
328 { }
329};
330MODULE_DEVICE_TABLE(acpi, cros_ec_lpc_acpi_device_ids);
331
303static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = { 332static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = {
304 { 333 {
305 /* 334 /*
@@ -337,18 +366,36 @@ static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = {
337}; 366};
338MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table); 367MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table);
339 368
369#ifdef CONFIG_PM_SLEEP
370static int cros_ec_lpc_suspend(struct device *dev)
371{
372 struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
373
374 return cros_ec_suspend(ec_dev);
375}
376
377static int cros_ec_lpc_resume(struct device *dev)
378{
379 struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
380
381 return cros_ec_resume(ec_dev);
382}
383#endif
384
385const struct dev_pm_ops cros_ec_lpc_pm_ops = {
386 SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend, cros_ec_lpc_resume)
387};
388
340static struct platform_driver cros_ec_lpc_driver = { 389static struct platform_driver cros_ec_lpc_driver = {
341 .driver = { 390 .driver = {
342 .name = DRV_NAME, 391 .name = DRV_NAME,
392 .acpi_match_table = cros_ec_lpc_acpi_device_ids,
393 .pm = &cros_ec_lpc_pm_ops,
343 }, 394 },
344 .probe = cros_ec_lpc_probe, 395 .probe = cros_ec_lpc_probe,
345 .remove = cros_ec_lpc_remove, 396 .remove = cros_ec_lpc_remove,
346}; 397};
347 398
348static struct platform_device cros_ec_lpc_device = {
349 .name = DRV_NAME
350};
351
352static int __init cros_ec_lpc_init(void) 399static int __init cros_ec_lpc_init(void)
353{ 400{
354 int ret; 401 int ret;
@@ -358,18 +405,13 @@ static int __init cros_ec_lpc_init(void)
358 return -ENODEV; 405 return -ENODEV;
359 } 406 }
360 407
408 cros_ec_lpc_reg_init();
409
361 /* Register the driver */ 410 /* Register the driver */
362 ret = platform_driver_register(&cros_ec_lpc_driver); 411 ret = platform_driver_register(&cros_ec_lpc_driver);
363 if (ret) { 412 if (ret) {
364 pr_err(DRV_NAME ": can't register driver: %d\n", ret); 413 pr_err(DRV_NAME ": can't register driver: %d\n", ret);
365 return ret; 414 cros_ec_lpc_reg_destroy();
366 }
367
368 /* Register the device, and it'll get hooked up automatically */
369 ret = platform_device_register(&cros_ec_lpc_device);
370 if (ret) {
371 pr_err(DRV_NAME ": can't register device: %d\n", ret);
372 platform_driver_unregister(&cros_ec_lpc_driver);
373 return ret; 415 return ret;
374 } 416 }
375 417
@@ -378,8 +420,8 @@ static int __init cros_ec_lpc_init(void)
378 420
379static void __exit cros_ec_lpc_exit(void) 421static void __exit cros_ec_lpc_exit(void)
380{ 422{
381 platform_device_unregister(&cros_ec_lpc_device);
382 platform_driver_unregister(&cros_ec_lpc_driver); 423 platform_driver_unregister(&cros_ec_lpc_driver);
424 cros_ec_lpc_reg_destroy();
383} 425}
384 426
385module_init(cros_ec_lpc_init); 427module_init(cros_ec_lpc_init);
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c
new file mode 100644
index 000000000000..2eda2c2fc210
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_lpc_mec.c
@@ -0,0 +1,140 @@
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 */
35static 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 */
45static 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 */
64u8 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
123done:
124 mutex_unlock(&io_mutex);
125
126 return sum;
127}
128EXPORT_SYMBOL(cros_ec_lpc_io_bytes_mec);
129
130void cros_ec_lpc_mec_init(void)
131{
132 mutex_init(&io_mutex);
133}
134EXPORT_SYMBOL(cros_ec_lpc_mec_init);
135
136void cros_ec_lpc_mec_destroy(void)
137{
138 mutex_destroy(&io_mutex);
139}
140EXPORT_SYMBOL(cros_ec_lpc_mec_destroy);
diff --git a/drivers/platform/chrome/cros_ec_lpc_reg.c b/drivers/platform/chrome/cros_ec_lpc_reg.c
new file mode 100644
index 000000000000..dcc7a3e30604
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_lpc_reg.c
@@ -0,0 +1,133 @@
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
29static 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
43static 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
59u8 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
81u8 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
103void cros_ec_lpc_reg_init(void)
104{
105 cros_ec_lpc_mec_init();
106}
107
108void cros_ec_lpc_reg_destroy(void)
109{
110 cros_ec_lpc_mec_destroy();
111}
112
113#else /* CONFIG_CROS_EC_LPC_MEC */
114
115u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, u8 *dest)
116{
117 return lpc_read_bytes(offset, length, dest);
118}
119
120u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, u8 *msg)
121{
122 return lpc_write_bytes(offset, length, msg);
123}
124
125void cros_ec_lpc_reg_init(void)
126{
127}
128
129void cros_ec_lpc_reg_destroy(void)
130{
131}
132
133#endif /* CONFIG_CROS_EC_LPC_MEC */
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c
index ed5dee744c74..8dfa7fcb1248 100644
--- a/drivers/platform/chrome/cros_ec_proto.c
+++ b/drivers/platform/chrome/cros_ec_proto.c
@@ -150,6 +150,40 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev,
150} 150}
151EXPORT_SYMBOL(cros_ec_check_result); 151EXPORT_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 */
166static 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
153static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, 187static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev,
154 int devidx, 188 int devidx,
155 struct cros_ec_command *msg) 189 struct cros_ec_command *msg)
@@ -235,6 +269,22 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
235 return ret; 269 return ret;
236} 270}
237 271
272/*
273 * cros_ec_get_host_command_version_mask
274 *
275 * Get the version mask of a given command.
276 *
277 * @ec_dev: EC device to call
278 * @msg: message structure to use
279 * @cmd: command to get the version of.
280 * @mask: result when function returns 0.
281 *
282 * @return 0 on success, error code otherwise
283 *
284 * LOCKING:
285 * the caller has ec_dev->lock mutex or the caller knows there is
286 * no other command in progress.
287 */
238static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, 288static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
239 u16 cmd, u32 *mask) 289 u16 cmd, u32 *mask)
240{ 290{
@@ -256,7 +306,7 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
256 pver = (struct ec_params_get_cmd_versions *)msg->data; 306 pver = (struct ec_params_get_cmd_versions *)msg->data;
257 pver->cmd = cmd; 307 pver->cmd = cmd;
258 308
259 ret = cros_ec_cmd_xfer(ec_dev, msg); 309 ret = send_command(ec_dev, msg);
260 if (ret > 0) { 310 if (ret > 0) {
261 rver = (struct ec_response_get_cmd_versions *)msg->data; 311 rver = (struct ec_response_get_cmd_versions *)msg->data;
262 *mask = rver->version_mask; 312 *mask = rver->version_mask;
@@ -371,6 +421,17 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
371 else 421 else
372 ec_dev->mkbp_event_supported = 1; 422 ec_dev->mkbp_event_supported = 1;
373 423
424 /*
425 * Get host event wake mask, assume all events are wake events
426 * if unavailable.
427 */
428 ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg,
429 &ec_dev->host_event_wake_mask);
430 if (ret < 0)
431 ec_dev->host_event_wake_mask = U32_MAX;
432
433 ret = 0;
434
374exit: 435exit:
375 kfree(proto_msg); 436 kfree(proto_msg);
376 return ret; 437 return ret;
@@ -486,11 +547,54 @@ static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
486 return ec_dev->event_size; 547 return ec_dev->event_size;
487} 548}
488 549
489int cros_ec_get_next_event(struct cros_ec_device *ec_dev) 550int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event)
490{ 551{
491 if (ec_dev->mkbp_event_supported) 552 u32 host_event;
492 return get_next_event(ec_dev); 553 int ret;
493 else 554
494 return get_keyboard_state_event(ec_dev); 555 if (!ec_dev->mkbp_event_supported) {
556 ret = get_keyboard_state_event(ec_dev);
557 if (ret < 0)
558 return ret;
559
560 if (wake_event)
561 *wake_event = true;
562
563 return ret;
564 }
565
566 ret = get_next_event(ec_dev);
567 if (ret < 0)
568 return ret;
569
570 if (wake_event) {
571 host_event = cros_ec_get_host_event(ec_dev);
572
573 /* Consider non-host_event as wake event */
574 *wake_event = !host_event ||
575 !!(host_event & ec_dev->host_event_wake_mask);
576 }
577
578 return ret;
495} 579}
496EXPORT_SYMBOL(cros_ec_get_next_event); 580EXPORT_SYMBOL(cros_ec_get_next_event);
581
582u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev)
583{
584 u32 host_event;
585
586 BUG_ON(!ec_dev->mkbp_event_supported);
587
588 if (ec_dev->event_data.event_type != EC_MKBP_EVENT_HOST_EVENT)
589 return 0;
590
591 if (ec_dev->event_size != sizeof(host_event)) {
592 dev_warn(ec_dev->dev, "Invalid host event size\n");
593 return 0;
594 }
595
596 host_event = get_unaligned_le32(&ec_dev->event_data.data.host_event);
597
598 return host_event;
599}
600EXPORT_SYMBOL(cros_ec_get_host_event);
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index 28baee63eaf6..4e887ba22635 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -149,6 +149,7 @@ struct cros_ec_device {
149 149
150 struct ec_response_get_next_event event_data; 150 struct ec_response_get_next_event event_data;
151 int event_size; 151 int event_size;
152 u32 host_event_wake_mask;
152}; 153};
153 154
154/** 155/**
@@ -172,6 +173,8 @@ struct cros_ec_platform {
172 u16 cmd_offset; 173 u16 cmd_offset;
173}; 174};
174 175
176struct cros_ec_debugfs;
177
175/* 178/*
176 * struct cros_ec_dev - ChromeOS EC device entry point 179 * struct cros_ec_dev - ChromeOS EC device entry point
177 * 180 *
@@ -179,6 +182,7 @@ struct cros_ec_platform {
179 * @cdev: Character device structure in /dev 182 * @cdev: Character device structure in /dev
180 * @ec_dev: cros_ec_device structure to talk to the physical device 183 * @ec_dev: cros_ec_device structure to talk to the physical device
181 * @dev: pointer to the platform device 184 * @dev: pointer to the platform device
185 * @debug_info: cros_ec_debugfs structure for debugging information
182 * @cmd_offset: offset to apply for each command. 186 * @cmd_offset: offset to apply for each command.
183 */ 187 */
184struct cros_ec_dev { 188struct cros_ec_dev {
@@ -186,6 +190,7 @@ struct cros_ec_dev {
186 struct cdev cdev; 190 struct cdev cdev;
187 struct cros_ec_device *ec_dev; 191 struct cros_ec_device *ec_dev;
188 struct device *dev; 192 struct device *dev;
193 struct cros_ec_debugfs *debug_info;
189 u16 cmd_offset; 194 u16 cmd_offset;
190 u32 features[2]; 195 u32 features[2];
191}; 196};
@@ -295,10 +300,22 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev);
295 * cros_ec_get_next_event - Fetch next event from the ChromeOS EC 300 * cros_ec_get_next_event - Fetch next event from the ChromeOS EC
296 * 301 *
297 * @ec_dev: Device to fetch event from 302 * @ec_dev: Device to fetch event from
303 * @wake_event: Pointer to a bool set to true upon return if the event might be
304 * treated as a wake event. Ignored if null.
298 * 305 *
299 * Returns: 0 on success, Linux error number on failure 306 * Returns: 0 on success, Linux error number on failure
300 */ 307 */
301int cros_ec_get_next_event(struct cros_ec_device *ec_dev); 308int cros_ec_get_next_event(struct cros_ec_device *ec_dev, bool *wake_event);
309
310/**
311 * cros_ec_get_host_event - Return a mask of event set by the EC.
312 *
313 * When MKBP is supported, when the EC raises an interrupt,
314 * We collect the events raised and call the functions in the ec notifier.
315 *
316 * This function is a helper to know which events are raised.
317 */
318u32 cros_ec_get_host_event(struct cros_ec_device *ec_dev);
302 319
303/* sysfs stuff */ 320/* sysfs stuff */
304extern struct attribute_group cros_ec_attr_group; 321extern struct attribute_group cros_ec_attr_group;
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h
index c93e7e0300ef..190c8f4afa02 100644
--- a/include/linux/mfd/cros_ec_commands.h
+++ b/include/linux/mfd/cros_ec_commands.h
@@ -625,6 +625,10 @@ struct ec_params_get_cmd_versions {
625 uint8_t cmd; /* Command to check */ 625 uint8_t cmd; /* Command to check */
626} __packed; 626} __packed;
627 627
628struct ec_params_get_cmd_versions_v1 {
629 uint16_t cmd; /* Command to check */
630} __packed;
631
628struct ec_response_get_cmd_versions { 632struct ec_response_get_cmd_versions {
629 /* 633 /*
630 * Mask of supported versions; use EC_VER_MASK() to compare with a 634 * Mask of supported versions; use EC_VER_MASK() to compare with a
@@ -1158,13 +1162,20 @@ struct lightbar_params_v1 {
1158 struct rgb_s color[8]; /* 0-3 are Google colors */ 1162 struct rgb_s color[8]; /* 0-3 are Google colors */
1159} __packed; 1163} __packed;
1160 1164
1165/* Lightbar program */
1166#define EC_LB_PROG_LEN 192
1167struct lightbar_program {
1168 uint8_t size;
1169 uint8_t data[EC_LB_PROG_LEN];
1170};
1171
1161struct ec_params_lightbar { 1172struct ec_params_lightbar {
1162 uint8_t cmd; /* Command (see enum lightbar_command) */ 1173 uint8_t cmd; /* Command (see enum lightbar_command) */
1163 union { 1174 union {
1164 struct { 1175 struct {
1165 /* no args */ 1176 /* no args */
1166 } dump, off, on, init, get_seq, get_params_v0, get_params_v1, 1177 } dump, off, on, init, get_seq, get_params_v0, get_params_v1,
1167 version, get_brightness, get_demo; 1178 version, get_brightness, get_demo, suspend, resume;
1168 1179
1169 struct { 1180 struct {
1170 uint8_t num; 1181 uint8_t num;
@@ -1182,8 +1193,13 @@ struct ec_params_lightbar {
1182 uint8_t led; 1193 uint8_t led;
1183 } get_rgb; 1194 } get_rgb;
1184 1195
1196 struct {
1197 uint8_t enable;
1198 } manual_suspend_ctrl;
1199
1185 struct lightbar_params_v0 set_params_v0; 1200 struct lightbar_params_v0 set_params_v0;
1186 struct lightbar_params_v1 set_params_v1; 1201 struct lightbar_params_v1 set_params_v1;
1202 struct lightbar_program set_program;
1187 }; 1203 };
1188} __packed; 1204} __packed;
1189 1205
@@ -1216,7 +1232,8 @@ struct ec_response_lightbar {
1216 struct { 1232 struct {
1217 /* no return params */ 1233 /* no return params */
1218 } off, on, init, set_brightness, seq, reg, set_rgb, 1234 } off, on, init, set_brightness, seq, reg, set_rgb,
1219 demo, set_params_v0, set_params_v1; 1235 demo, set_params_v0, set_params_v1,
1236 set_program, manual_suspend_ctrl, suspend, resume;
1220 }; 1237 };
1221} __packed; 1238} __packed;
1222 1239
@@ -1240,6 +1257,10 @@ enum lightbar_command {
1240 LIGHTBAR_CMD_GET_DEMO = 15, 1257 LIGHTBAR_CMD_GET_DEMO = 15,
1241 LIGHTBAR_CMD_GET_PARAMS_V1 = 16, 1258 LIGHTBAR_CMD_GET_PARAMS_V1 = 16,
1242 LIGHTBAR_CMD_SET_PARAMS_V1 = 17, 1259 LIGHTBAR_CMD_SET_PARAMS_V1 = 17,
1260 LIGHTBAR_CMD_SET_PROGRAM = 18,
1261 LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL = 19,
1262 LIGHTBAR_CMD_SUSPEND = 20,
1263 LIGHTBAR_CMD_RESUME = 21,
1243 LIGHTBAR_NUM_CMDS 1264 LIGHTBAR_NUM_CMDS
1244}; 1265};
1245 1266
@@ -2285,13 +2306,28 @@ struct ec_params_charge_control {
2285#define EC_CMD_CONSOLE_SNAPSHOT 0x97 2306#define EC_CMD_CONSOLE_SNAPSHOT 0x97
2286 2307
2287/* 2308/*
2288 * Read next chunk of data from saved snapshot. 2309 * Read data from the saved snapshot. If the subcmd parameter is
2310 * CONSOLE_READ_NEXT, this will return data starting from the beginning of
2311 * the latest snapshot. If it is CONSOLE_READ_RECENT, it will start from the
2312 * end of the previous snapshot.
2313 *
2314 * The params are only looked at in version >= 1 of this command. Prior
2315 * versions will just default to CONSOLE_READ_NEXT behavior.
2289 * 2316 *
2290 * Response is null-terminated string. Empty string, if there is no more 2317 * Response is null-terminated string. Empty string, if there is no more
2291 * remaining output. 2318 * remaining output.
2292 */ 2319 */
2293#define EC_CMD_CONSOLE_READ 0x98 2320#define EC_CMD_CONSOLE_READ 0x98
2294 2321
2322enum ec_console_read_subcmd {
2323 CONSOLE_READ_NEXT = 0,
2324 CONSOLE_READ_RECENT
2325};
2326
2327struct ec_params_console_read_v1 {
2328 uint8_t subcmd; /* enum ec_console_read_subcmd */
2329} __packed;
2330
2295/*****************************************************************************/ 2331/*****************************************************************************/
2296 2332
2297/* 2333/*
diff --git a/include/linux/mfd/cros_ec_lpc_mec.h b/include/linux/mfd/cros_ec_lpc_mec.h
new file mode 100644
index 000000000000..176496ddc66c
--- /dev/null
+++ b/include/linux/mfd/cros_ec_lpc_mec.h
@@ -0,0 +1,90 @@
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
29enum 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
43enum 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 */
68void cros_ec_lpc_mec_init(void);
69
70/*
71 * cros_ec_lpc_mec_destroy
72 *
73 * Cleanup MEC I/O.
74 */
75void 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 */
87u8 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 */
diff --git a/include/linux/mfd/cros_ec_lpc_reg.h b/include/linux/mfd/cros_ec_lpc_reg.h
new file mode 100644
index 000000000000..5560bef63c2b
--- /dev/null
+++ b/include/linux/mfd/cros_ec_lpc_reg.h
@@ -0,0 +1,61 @@
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 */
35u8 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 */
45u8 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 */
52void cros_ec_lpc_reg_init(void);
53
54/**
55 * cros_ec_lpc_reg_destroy
56 *
57 * Cleanup reg I/O.
58 */
59void cros_ec_lpc_reg_destroy(void);
60
61#endif /* __LINUX_MFD_CROS_EC_REG_H */