platform/chrome: Add cros_ec_lpc driver for x86 devices
[deliverable/linux.git] / drivers / platform / chrome / cros_ec_lpc.c
CommitLineData
ec2f33ab
BR
1/*
2 * cros_ec_lpc - LPC access to the Chrome OS Embedded Controller
3 *
4 * Copyright (C) 2012-2015 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/dmi.h>
25#include <linux/delay.h>
26#include <linux/mfd/cros_ec.h>
27#include <linux/mfd/cros_ec_commands.h>
28#include <linux/module.h>
29#include <linux/platform_device.h>
30#include <linux/printk.h>
31
32#define DRV_NAME "cros_ec_lpc"
33
34static int ec_response_timed_out(void)
35{
36 unsigned long one_second = jiffies + HZ;
37
38 usleep_range(200, 300);
39 do {
40 if (!(inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK))
41 return 0;
42 usleep_range(100, 200);
43 } while (time_before(jiffies, one_second));
44
45 return 1;
46}
47
48static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
49 struct cros_ec_command *msg)
50{
51 struct ec_lpc_host_args args;
52 int csum;
53 int i;
54 int ret = 0;
55
56 if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE ||
57 msg->insize > EC_PROTO2_MAX_PARAM_SIZE) {
58 dev_err(ec->dev,
59 "invalid buffer sizes (out %d, in %d)\n",
60 msg->outsize, msg->insize);
61 return -EINVAL;
62 }
63
64 /* Now actually send the command to the EC and get the result */
65 args.flags = EC_HOST_ARGS_FLAG_FROM_HOST;
66 args.command_version = msg->version;
67 args.data_size = msg->outsize;
68
69 /* Initialize checksum */
70 csum = msg->command + args.flags +
71 args.command_version + args.data_size;
72
73 /* Copy data and update checksum */
74 for (i = 0; i < msg->outsize; i++) {
75 outb(msg->outdata[i], EC_LPC_ADDR_HOST_PARAM + i);
76 csum += msg->outdata[i];
77 }
78
79 /* Finalize checksum and write args */
80 args.checksum = csum & 0xFF;
81 outb(args.flags, EC_LPC_ADDR_HOST_ARGS);
82 outb(args.command_version, EC_LPC_ADDR_HOST_ARGS + 1);
83 outb(args.data_size, EC_LPC_ADDR_HOST_ARGS + 2);
84 outb(args.checksum, EC_LPC_ADDR_HOST_ARGS + 3);
85
86 /* Here we go */
87 outb(msg->command, EC_LPC_ADDR_HOST_CMD);
88
89 if (ec_response_timed_out()) {
90 dev_warn(ec->dev, "EC responsed timed out\n");
91 ret = -EIO;
92 goto done;
93 }
94
95 /* Check result */
96 msg->result = inb(EC_LPC_ADDR_HOST_DATA);
97
98 switch (msg->result) {
99 case EC_RES_SUCCESS:
100 break;
101 case EC_RES_IN_PROGRESS:
102 ret = -EAGAIN;
103 dev_dbg(ec->dev, "command 0x%02x in progress\n",
104 msg->command);
105 goto done;
106 default:
107 dev_dbg(ec->dev, "command 0x%02x returned %d\n",
108 msg->command, msg->result);
109 }
110
111 /* Read back args */
112 args.flags = inb(EC_LPC_ADDR_HOST_ARGS);
113 args.command_version = inb(EC_LPC_ADDR_HOST_ARGS + 1);
114 args.data_size = inb(EC_LPC_ADDR_HOST_ARGS + 2);
115 args.checksum = inb(EC_LPC_ADDR_HOST_ARGS + 3);
116
117 if (args.data_size > msg->insize) {
118 dev_err(ec->dev,
119 "packet too long (%d bytes, expected %d)",
120 args.data_size, msg->insize);
121 ret = -ENOSPC;
122 goto done;
123 }
124
125 /* Start calculating response checksum */
126 csum = msg->command + args.flags +
127 args.command_version + args.data_size;
128
129 /* Read response and update checksum */
130 for (i = 0; i < args.data_size; i++) {
131 msg->indata[i] = inb(EC_LPC_ADDR_HOST_PARAM + i);
132 csum += msg->indata[i];
133 }
134
135 /* Verify checksum */
136 if (args.checksum != (csum & 0xFF)) {
137 dev_err(ec->dev,
138 "bad packet checksum, expected %02x, got %02x\n",
139 args.checksum, csum & 0xFF);
140 ret = -EBADMSG;
141 goto done;
142 }
143
144 /* Return actual amount of data received */
145 ret = args.data_size;
146done:
147 return ret;
148}
149
150/* Returns num bytes read, or negative on error. Doesn't need locking. */
151static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset,
152 unsigned int bytes, void *dest)
153{
154 int i = offset;
155 char *s = dest;
156 int cnt = 0;
157
158 if (offset >= EC_MEMMAP_SIZE - bytes)
159 return -EINVAL;
160
161 /* fixed length */
162 if (bytes) {
163 for (; cnt < bytes; i++, s++, cnt++)
164 *s = inb(EC_LPC_ADDR_MEMMAP + i);
165 return cnt;
166 }
167
168 /* string */
169 for (; i < EC_MEMMAP_SIZE; i++, s++) {
170 *s = inb(EC_LPC_ADDR_MEMMAP + i);
171 cnt++;
172 if (!*s)
173 break;
174 }
175
176 return cnt;
177}
178
179static int cros_ec_lpc_probe(struct platform_device *pdev)
180{
181 struct device *dev = &pdev->dev;
182 struct cros_ec_device *ec_dev;
183 int ret;
184
185 if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE,
186 dev_name(dev))) {
187 dev_err(dev, "couldn't reserve memmap region\n");
188 return -EBUSY;
189 }
190
191 if ((inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E') ||
192 (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C')) {
193 dev_err(dev, "EC ID not detected\n");
194 return -ENODEV;
195 }
196
197 if (!devm_request_region(dev, EC_HOST_CMD_REGION0,
198 EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
199 dev_err(dev, "couldn't reserve region0\n");
200 return -EBUSY;
201 }
202 if (!devm_request_region(dev, EC_HOST_CMD_REGION1,
203 EC_HOST_CMD_REGION_SIZE, dev_name(dev))) {
204 dev_err(dev, "couldn't reserve region1\n");
205 return -EBUSY;
206 }
207
208 ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
209 if (!ec_dev)
210 return -ENOMEM;
211
212 platform_set_drvdata(pdev, ec_dev);
213 ec_dev->dev = dev;
214 ec_dev->ec_name = pdev->name;
215 ec_dev->phys_name = dev_name(dev);
216 ec_dev->parent = dev;
217 ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc;
218 ec_dev->cmd_readmem = cros_ec_lpc_readmem;
219
220 ret = cros_ec_register(ec_dev);
221 if (ret) {
222 dev_err(dev, "couldn't register ec_dev (%d)\n", ret);
223 return ret;
224 }
225
226 return 0;
227}
228
229static int cros_ec_lpc_remove(struct platform_device *pdev)
230{
231 struct cros_ec_device *ec_dev;
232
233 ec_dev = platform_get_drvdata(pdev);
234 cros_ec_remove(ec_dev);
235
236 return 0;
237}
238
239static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = {
240 {
241 /*
242 * Today all Chromebooks/boxes ship with Google_* as version and
243 * coreboot as bios vendor. No other systems with this
244 * combination are known to date.
245 */
246 .matches = {
247 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
248 DMI_MATCH(DMI_BIOS_VERSION, "Google_"),
249 },
250 },
251 {
252 /* x86-link, the Chromebook Pixel. */
253 .matches = {
254 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
255 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
256 },
257 },
258 {
259 /* x86-peppy, the Acer C720 Chromebook. */
260 .matches = {
261 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
262 DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
263 },
264 },
265 { /* sentinel */ }
266};
267MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table);
268
269static struct platform_driver cros_ec_lpc_driver = {
270 .driver = {
271 .name = DRV_NAME,
272 .owner = THIS_MODULE,
273 },
274 .probe = cros_ec_lpc_probe,
275 .remove = cros_ec_lpc_remove,
276};
277
278static struct platform_device cros_ec_lpc_device = {
279 .name = DRV_NAME
280};
281
282static int __init cros_ec_lpc_init(void)
283{
284 int ret;
285
286 if (!dmi_check_system(cros_ec_lpc_dmi_table)) {
287 pr_err(DRV_NAME ": unsupported system.\n");
288 return -ENODEV;
289 }
290
291 /* Register the driver */
292 ret = platform_driver_register(&cros_ec_lpc_driver);
293 if (ret) {
294 pr_err(DRV_NAME ": can't register driver: %d\n", ret);
295 return ret;
296 }
297
298 /* Register the device, and it'll get hooked up automatically */
299 ret = platform_device_register(&cros_ec_lpc_device);
300 if (ret) {
301 pr_err(DRV_NAME ": can't register device: %d\n", ret);
302 platform_driver_unregister(&cros_ec_lpc_driver);
303 return ret;
304 }
305
306 return 0;
307}
308
309static void __exit cros_ec_lpc_exit(void)
310{
311 platform_device_unregister(&cros_ec_lpc_device);
312 platform_driver_unregister(&cros_ec_lpc_driver);
313}
314
315module_init(cros_ec_lpc_init);
316module_exit(cros_ec_lpc_exit);
317
318MODULE_LICENSE("GPL");
319MODULE_DESCRIPTION("ChromeOS EC LPC driver");
This page took 0.041713 seconds and 5 git commands to generate.