1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Driver for the OLPC XO-1.75 Embedded Controller. |
4 | * |
5 | * The EC protocol is documented at: |
6 | * http://wiki.laptop.org/go/XO_1.75_HOST_to_EC_Protocol |
7 | * |
8 | * Copyright (C) 2010 One Laptop per Child Foundation. |
9 | * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> |
10 | */ |
11 | |
12 | #include <linux/completion.h> |
13 | #include <linux/ctype.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/input.h> |
17 | #include <linux/kfifo.h> |
18 | #include <linux/module.h> |
19 | #include <linux/olpc-ec.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/power_supply.h> |
22 | #include <linux/reboot.h> |
23 | #include <linux/slab.h> |
24 | #include <linux/spinlock.h> |
25 | #include <linux/spi/spi.h> |
26 | |
27 | struct ec_cmd_t { |
28 | u8 cmd; |
29 | u8 bytes_returned; |
30 | }; |
31 | |
32 | enum ec_chan_t { |
33 | CHAN_NONE = 0, |
34 | CHAN_SWITCH, |
35 | CHAN_CMD_RESP, |
36 | CHAN_KEYBOARD, |
37 | CHAN_TOUCHPAD, |
38 | CHAN_EVENT, |
39 | CHAN_DEBUG, |
40 | CHAN_CMD_ERROR, |
41 | }; |
42 | |
43 | /* |
44 | * EC events |
45 | */ |
46 | #define EVENT_AC_CHANGE 1 /* AC plugged/unplugged */ |
47 | #define EVENT_BATTERY_STATUS 2 /* Battery low/full/error/gone */ |
48 | #define EVENT_BATTERY_CRITICAL 3 /* Battery critical voltage */ |
49 | #define EVENT_BATTERY_SOC_CHANGE 4 /* 1% SOC Change */ |
50 | #define EVENT_BATTERY_ERROR 5 /* Abnormal error, query for cause */ |
51 | #define EVENT_POWER_PRESSED 6 /* Power button was pressed */ |
52 | #define EVENT_POWER_PRESS_WAKE 7 /* Woken up with a power button */ |
53 | #define EVENT_TIMED_HOST_WAKE 8 /* Host wake timer */ |
54 | #define EVENT_OLS_HIGH_LIMIT 9 /* OLS crossed dark threshold */ |
55 | #define EVENT_OLS_LOW_LIMIT 10 /* OLS crossed light threshold */ |
56 | |
57 | /* |
58 | * EC commands |
59 | * (from http://dev.laptop.org/git/users/rsmith/ec-1.75/tree/ec_cmd.h) |
60 | */ |
61 | #define CMD_GET_API_VERSION 0x08 /* out: u8 */ |
62 | #define CMD_READ_VOLTAGE 0x10 /* out: u16, *9.76/32, mV */ |
63 | #define CMD_READ_CURRENT 0x11 /* out: s16, *15.625/120, mA */ |
64 | #define CMD_READ_ACR 0x12 /* out: s16, *6250/15, uAh */ |
65 | #define CMD_READ_BATT_TEMPERATURE 0x13 /* out: u16, *100/256, deg C */ |
66 | #define CMD_READ_AMBIENT_TEMPERATURE 0x14 /* unimplemented, no hardware */ |
67 | #define CMD_READ_BATTERY_STATUS 0x15 /* out: u8, bitmask */ |
68 | #define CMD_READ_SOC 0x16 /* out: u8, percentage */ |
69 | #define CMD_READ_GAUGE_ID 0x17 /* out: u8 * 8 */ |
70 | #define CMD_READ_GAUGE_DATA 0x18 /* in: u8 addr, out: u8 data */ |
71 | #define CMD_READ_BOARD_ID 0x19 /* out: u16 (platform id) */ |
72 | #define CMD_READ_BATT_ERR_CODE 0x1f /* out: u8, error bitmask */ |
73 | #define CMD_SET_DCON_POWER 0x26 /* in: u8 */ |
74 | #define CMD_RESET_EC 0x28 /* none */ |
75 | #define CMD_READ_BATTERY_TYPE 0x2c /* out: u8 */ |
76 | #define CMD_SET_AUTOWAK 0x33 /* out: u8 */ |
77 | #define CMD_SET_EC_WAKEUP_TIMER 0x36 /* in: u32, out: ? */ |
78 | #define CMD_READ_EXT_SCI_MASK 0x37 /* ? */ |
79 | #define CMD_WRITE_EXT_SCI_MASK 0x38 /* ? */ |
80 | #define CMD_CLEAR_EC_WAKEUP_TIMER 0x39 /* none */ |
81 | #define CMD_ENABLE_RUNIN_DISCHARGE 0x3B /* none */ |
82 | #define CMD_DISABLE_RUNIN_DISCHARGE 0x3C /* none */ |
83 | #define CMD_READ_MPPT_ACTIVE 0x3d /* out: u8 */ |
84 | #define CMD_READ_MPPT_LIMIT 0x3e /* out: u8 */ |
85 | #define CMD_SET_MPPT_LIMIT 0x3f /* in: u8 */ |
86 | #define CMD_DISABLE_MPPT 0x40 /* none */ |
87 | #define CMD_ENABLE_MPPT 0x41 /* none */ |
88 | #define CMD_READ_VIN 0x42 /* out: u16 */ |
89 | #define CMD_EXT_SCI_QUERY 0x43 /* ? */ |
90 | #define RSP_KEYBOARD_DATA 0x48 /* ? */ |
91 | #define RSP_TOUCHPAD_DATA 0x49 /* ? */ |
92 | #define CMD_GET_FW_VERSION 0x4a /* out: u8 * 16 */ |
93 | #define CMD_POWER_CYCLE 0x4b /* none */ |
94 | #define CMD_POWER_OFF 0x4c /* none */ |
95 | #define CMD_RESET_EC_SOFT 0x4d /* none */ |
96 | #define CMD_READ_GAUGE_U16 0x4e /* ? */ |
97 | #define CMD_ENABLE_MOUSE 0x4f /* ? */ |
98 | #define CMD_ECHO 0x52 /* in: u8 * 5, out: u8 * 5 */ |
99 | #define CMD_GET_FW_DATE 0x53 /* out: u8 * 16 */ |
100 | #define CMD_GET_FW_USER 0x54 /* out: u8 * 16 */ |
101 | #define CMD_TURN_OFF_POWER 0x55 /* none (same as 0x4c) */ |
102 | #define CMD_READ_OLS 0x56 /* out: u16 */ |
103 | #define CMD_OLS_SMT_LEDON 0x57 /* none */ |
104 | #define CMD_OLS_SMT_LEDOFF 0x58 /* none */ |
105 | #define CMD_START_OLS_ASSY 0x59 /* none */ |
106 | #define CMD_STOP_OLS_ASSY 0x5a /* none */ |
107 | #define CMD_OLS_SMTTEST_STOP 0x5b /* none */ |
108 | #define CMD_READ_VIN_SCALED 0x5c /* out: u16 */ |
109 | #define CMD_READ_BAT_MIN_W 0x5d /* out: u16 */ |
110 | #define CMD_READ_BAR_MAX_W 0x5e /* out: u16 */ |
111 | #define CMD_RESET_BAT_MINMAX_W 0x5f /* none */ |
112 | #define CMD_READ_LOCATION 0x60 /* in: u16 addr, out: u8 data */ |
113 | #define CMD_WRITE_LOCATION 0x61 /* in: u16 addr, u8 data */ |
114 | #define CMD_KEYBOARD_CMD 0x62 /* in: u8, out: ? */ |
115 | #define CMD_TOUCHPAD_CMD 0x63 /* in: u8, out: ? */ |
116 | #define CMD_GET_FW_HASH 0x64 /* out: u8 * 16 */ |
117 | #define CMD_SUSPEND_HINT 0x65 /* in: u8 */ |
118 | #define CMD_ENABLE_WAKE_TIMER 0x66 /* in: u8 */ |
119 | #define CMD_SET_WAKE_TIMER 0x67 /* in: 32 */ |
120 | #define CMD_ENABLE_WAKE_AUTORESET 0x68 /* in: u8 */ |
121 | #define CMD_OLS_SET_LIMITS 0x69 /* in: u16, u16 */ |
122 | #define CMD_OLS_GET_LIMITS 0x6a /* out: u16, u16 */ |
123 | #define CMD_OLS_SET_CEILING 0x6b /* in: u16 */ |
124 | #define CMD_OLS_GET_CEILING 0x6c /* out: u16 */ |
125 | |
126 | /* |
127 | * Accepted EC commands, and how many bytes they return. There are plenty |
128 | * of EC commands that are no longer implemented, or are implemented only on |
129 | * certain older boards. |
130 | */ |
131 | static const struct ec_cmd_t olpc_xo175_ec_cmds[] = { |
132 | { CMD_GET_API_VERSION, 1 }, |
133 | { CMD_READ_VOLTAGE, 2 }, |
134 | { CMD_READ_CURRENT, 2 }, |
135 | { CMD_READ_ACR, 2 }, |
136 | { CMD_READ_BATT_TEMPERATURE, 2 }, |
137 | { CMD_READ_BATTERY_STATUS, 1 }, |
138 | { CMD_READ_SOC, 1 }, |
139 | { CMD_READ_GAUGE_ID, 8 }, |
140 | { CMD_READ_GAUGE_DATA, 1 }, |
141 | { CMD_READ_BOARD_ID, 2 }, |
142 | { CMD_READ_BATT_ERR_CODE, 1 }, |
143 | { CMD_SET_DCON_POWER, 0 }, |
144 | { CMD_RESET_EC, 0 }, |
145 | { CMD_READ_BATTERY_TYPE, 1 }, |
146 | { CMD_ENABLE_RUNIN_DISCHARGE, 0 }, |
147 | { CMD_DISABLE_RUNIN_DISCHARGE, 0 }, |
148 | { CMD_READ_MPPT_ACTIVE, 1 }, |
149 | { CMD_READ_MPPT_LIMIT, 1 }, |
150 | { CMD_SET_MPPT_LIMIT, 0 }, |
151 | { CMD_DISABLE_MPPT, 0 }, |
152 | { CMD_ENABLE_MPPT, 0 }, |
153 | { CMD_READ_VIN, 2 }, |
154 | { CMD_GET_FW_VERSION, 16 }, |
155 | { CMD_POWER_CYCLE, 0 }, |
156 | { CMD_POWER_OFF, 0 }, |
157 | { CMD_RESET_EC_SOFT, 0 }, |
158 | { CMD_ECHO, 5 }, |
159 | { CMD_GET_FW_DATE, 16 }, |
160 | { CMD_GET_FW_USER, 16 }, |
161 | { CMD_TURN_OFF_POWER, 0 }, |
162 | { CMD_READ_OLS, 2 }, |
163 | { CMD_OLS_SMT_LEDON, 0 }, |
164 | { CMD_OLS_SMT_LEDOFF, 0 }, |
165 | { CMD_START_OLS_ASSY, 0 }, |
166 | { CMD_STOP_OLS_ASSY, 0 }, |
167 | { CMD_OLS_SMTTEST_STOP, 0 }, |
168 | { CMD_READ_VIN_SCALED, 2 }, |
169 | { CMD_READ_BAT_MIN_W, 2 }, |
170 | { CMD_READ_BAR_MAX_W, 2 }, |
171 | { CMD_RESET_BAT_MINMAX_W, 0 }, |
172 | { CMD_READ_LOCATION, 1 }, |
173 | { CMD_WRITE_LOCATION, 0 }, |
174 | { CMD_GET_FW_HASH, 16 }, |
175 | { CMD_SUSPEND_HINT, 0 }, |
176 | { CMD_ENABLE_WAKE_TIMER, 0 }, |
177 | { CMD_SET_WAKE_TIMER, 0 }, |
178 | { CMD_ENABLE_WAKE_AUTORESET, 0 }, |
179 | { CMD_OLS_SET_LIMITS, 0 }, |
180 | { CMD_OLS_GET_LIMITS, 4 }, |
181 | { CMD_OLS_SET_CEILING, 0 }, |
182 | { CMD_OLS_GET_CEILING, 2 }, |
183 | { CMD_READ_EXT_SCI_MASK, 2 }, |
184 | { CMD_WRITE_EXT_SCI_MASK, 0 }, |
185 | |
186 | { } |
187 | }; |
188 | |
189 | #define EC_MAX_CMD_DATA_LEN 5 |
190 | #define EC_MAX_RESP_LEN 16 |
191 | |
192 | #define LOG_BUF_SIZE 128 |
193 | |
194 | #define PM_WAKEUP_TIME 1000 |
195 | |
196 | #define EC_ALL_EVENTS GENMASK(15, 0) |
197 | |
198 | enum ec_state_t { |
199 | CMD_STATE_IDLE = 0, |
200 | CMD_STATE_WAITING_FOR_SWITCH, |
201 | CMD_STATE_CMD_IN_TX_FIFO, |
202 | CMD_STATE_CMD_SENT, |
203 | CMD_STATE_RESP_RECEIVED, |
204 | CMD_STATE_ERROR_RECEIVED, |
205 | }; |
206 | |
207 | struct olpc_xo175_ec_cmd { |
208 | u8 command; |
209 | u8 nr_args; |
210 | u8 data_len; |
211 | u8 args[EC_MAX_CMD_DATA_LEN]; |
212 | }; |
213 | |
214 | struct olpc_xo175_ec_resp { |
215 | u8 channel; |
216 | u8 byte; |
217 | }; |
218 | |
219 | struct olpc_xo175_ec { |
220 | bool suspended; |
221 | |
222 | /* SPI related stuff. */ |
223 | struct spi_device *spi; |
224 | struct spi_transfer xfer; |
225 | struct spi_message msg; |
226 | union { |
227 | struct olpc_xo175_ec_cmd cmd; |
228 | struct olpc_xo175_ec_resp resp; |
229 | } tx_buf, rx_buf; |
230 | |
231 | /* GPIO for the CMD signals. */ |
232 | struct gpio_desc *gpio_cmd; |
233 | |
234 | /* Command handling related state. */ |
235 | spinlock_t cmd_state_lock; |
236 | int cmd_state; |
237 | bool cmd_running; |
238 | struct completion cmd_done; |
239 | struct olpc_xo175_ec_cmd cmd; |
240 | u8 resp_data[EC_MAX_RESP_LEN]; |
241 | int expected_resp_len; |
242 | int resp_len; |
243 | |
244 | /* Power button. */ |
245 | struct input_dev *pwrbtn; |
246 | |
247 | /* Debug handling. */ |
248 | char logbuf[LOG_BUF_SIZE]; |
249 | int logbuf_len; |
250 | }; |
251 | |
252 | static struct platform_device *olpc_ec; |
253 | |
254 | static int olpc_xo175_ec_resp_len(u8 cmd) |
255 | { |
256 | const struct ec_cmd_t *p; |
257 | |
258 | for (p = olpc_xo175_ec_cmds; p->cmd; p++) { |
259 | if (p->cmd == cmd) |
260 | return p->bytes_returned; |
261 | } |
262 | |
263 | return -EINVAL; |
264 | } |
265 | |
266 | static void olpc_xo175_ec_flush_logbuf(struct olpc_xo175_ec *priv) |
267 | { |
268 | dev_dbg(&priv->spi->dev, "got debug string [%*pE]\n" , |
269 | priv->logbuf_len, priv->logbuf); |
270 | priv->logbuf_len = 0; |
271 | } |
272 | |
273 | static void olpc_xo175_ec_complete(void *arg); |
274 | |
275 | static void olpc_xo175_ec_send_command(struct olpc_xo175_ec *priv, void *cmd, |
276 | size_t cmdlen) |
277 | { |
278 | int ret; |
279 | |
280 | memcpy(&priv->tx_buf, cmd, cmdlen); |
281 | priv->xfer.len = cmdlen; |
282 | |
283 | spi_message_init_with_transfers(m: &priv->msg, xfers: &priv->xfer, num_xfers: 1); |
284 | |
285 | priv->msg.complete = olpc_xo175_ec_complete; |
286 | priv->msg.context = priv; |
287 | |
288 | ret = spi_async(spi: priv->spi, message: &priv->msg); |
289 | if (ret) |
290 | dev_err(&priv->spi->dev, "spi_async() failed %d\n" , ret); |
291 | } |
292 | |
293 | static void olpc_xo175_ec_read_packet(struct olpc_xo175_ec *priv) |
294 | { |
295 | u8 nonce[] = {0xA5, 0x5A}; |
296 | |
297 | olpc_xo175_ec_send_command(priv, cmd: nonce, cmdlen: sizeof(nonce)); |
298 | } |
299 | |
300 | static void olpc_xo175_ec_complete(void *arg) |
301 | { |
302 | struct olpc_xo175_ec *priv = arg; |
303 | struct device *dev = &priv->spi->dev; |
304 | struct power_supply *psy; |
305 | unsigned long flags; |
306 | u8 channel; |
307 | u8 byte; |
308 | int ret; |
309 | |
310 | ret = priv->msg.status; |
311 | if (ret) { |
312 | dev_err(dev, "SPI transfer failed: %d\n" , ret); |
313 | |
314 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
315 | if (priv->cmd_running) { |
316 | priv->resp_len = 0; |
317 | priv->cmd_state = CMD_STATE_ERROR_RECEIVED; |
318 | complete(&priv->cmd_done); |
319 | } |
320 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
321 | |
322 | if (ret != -EINTR) |
323 | olpc_xo175_ec_read_packet(priv); |
324 | |
325 | return; |
326 | } |
327 | |
328 | channel = priv->rx_buf.resp.channel; |
329 | byte = priv->rx_buf.resp.byte; |
330 | |
331 | switch (channel) { |
332 | case CHAN_NONE: |
333 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
334 | |
335 | if (!priv->cmd_running) { |
336 | /* We can safely ignore these */ |
337 | dev_err(dev, "spurious FIFO read packet\n" ); |
338 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
339 | return; |
340 | } |
341 | |
342 | priv->cmd_state = CMD_STATE_CMD_SENT; |
343 | if (!priv->expected_resp_len) |
344 | complete(&priv->cmd_done); |
345 | olpc_xo175_ec_read_packet(priv); |
346 | |
347 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
348 | return; |
349 | |
350 | case CHAN_SWITCH: |
351 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
352 | |
353 | if (!priv->cmd_running) { |
354 | /* Just go with the flow */ |
355 | dev_err(dev, "spurious SWITCH packet\n" ); |
356 | memset(&priv->cmd, 0, sizeof(priv->cmd)); |
357 | priv->cmd.command = CMD_ECHO; |
358 | } |
359 | |
360 | priv->cmd_state = CMD_STATE_CMD_IN_TX_FIFO; |
361 | |
362 | /* Throw command into TxFIFO */ |
363 | gpiod_set_value_cansleep(desc: priv->gpio_cmd, value: 0); |
364 | olpc_xo175_ec_send_command(priv, cmd: &priv->cmd, cmdlen: sizeof(priv->cmd)); |
365 | |
366 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
367 | return; |
368 | |
369 | case CHAN_CMD_RESP: |
370 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
371 | |
372 | if (!priv->cmd_running) { |
373 | dev_err(dev, "spurious response packet\n" ); |
374 | } else if (priv->resp_len >= priv->expected_resp_len) { |
375 | dev_err(dev, "too many response packets\n" ); |
376 | } else { |
377 | priv->resp_data[priv->resp_len++] = byte; |
378 | if (priv->resp_len == priv->expected_resp_len) { |
379 | priv->cmd_state = CMD_STATE_RESP_RECEIVED; |
380 | complete(&priv->cmd_done); |
381 | } |
382 | } |
383 | |
384 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
385 | break; |
386 | |
387 | case CHAN_CMD_ERROR: |
388 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
389 | |
390 | if (!priv->cmd_running) { |
391 | dev_err(dev, "spurious cmd error packet\n" ); |
392 | } else { |
393 | priv->resp_data[0] = byte; |
394 | priv->resp_len = 1; |
395 | priv->cmd_state = CMD_STATE_ERROR_RECEIVED; |
396 | complete(&priv->cmd_done); |
397 | } |
398 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
399 | break; |
400 | |
401 | case CHAN_KEYBOARD: |
402 | dev_warn(dev, "keyboard is not supported\n" ); |
403 | break; |
404 | |
405 | case CHAN_TOUCHPAD: |
406 | dev_warn(dev, "touchpad is not supported\n" ); |
407 | break; |
408 | |
409 | case CHAN_EVENT: |
410 | dev_dbg(dev, "got event %.2x\n" , byte); |
411 | switch (byte) { |
412 | case EVENT_AC_CHANGE: |
413 | psy = power_supply_get_by_name(name: "olpc_ac" ); |
414 | if (psy) { |
415 | power_supply_changed(psy); |
416 | power_supply_put(psy); |
417 | } |
418 | break; |
419 | case EVENT_BATTERY_STATUS: |
420 | case EVENT_BATTERY_CRITICAL: |
421 | case EVENT_BATTERY_SOC_CHANGE: |
422 | case EVENT_BATTERY_ERROR: |
423 | psy = power_supply_get_by_name(name: "olpc_battery" ); |
424 | if (psy) { |
425 | power_supply_changed(psy); |
426 | power_supply_put(psy); |
427 | } |
428 | break; |
429 | case EVENT_POWER_PRESSED: |
430 | input_report_key(dev: priv->pwrbtn, KEY_POWER, value: 1); |
431 | input_sync(dev: priv->pwrbtn); |
432 | input_report_key(dev: priv->pwrbtn, KEY_POWER, value: 0); |
433 | input_sync(dev: priv->pwrbtn); |
434 | fallthrough; |
435 | case EVENT_POWER_PRESS_WAKE: |
436 | case EVENT_TIMED_HOST_WAKE: |
437 | pm_wakeup_event(dev: priv->pwrbtn->dev.parent, |
438 | PM_WAKEUP_TIME); |
439 | break; |
440 | default: |
441 | dev_dbg(dev, "ignored unknown event %.2x\n" , byte); |
442 | break; |
443 | } |
444 | break; |
445 | |
446 | case CHAN_DEBUG: |
447 | if (byte == '\n') { |
448 | olpc_xo175_ec_flush_logbuf(priv); |
449 | } else if (isprint(byte)) { |
450 | priv->logbuf[priv->logbuf_len++] = byte; |
451 | if (priv->logbuf_len == LOG_BUF_SIZE) |
452 | olpc_xo175_ec_flush_logbuf(priv); |
453 | } |
454 | break; |
455 | |
456 | default: |
457 | dev_warn(dev, "unknown channel: %d, %.2x\n" , channel, byte); |
458 | break; |
459 | } |
460 | |
461 | /* Most non-command packets get the TxFIFO refilled and an ACK. */ |
462 | olpc_xo175_ec_read_packet(priv); |
463 | } |
464 | |
465 | /* |
466 | * This function is protected with a mutex. We can safely assume that |
467 | * there will be only one instance of this function running at a time. |
468 | * One of the ways in which we enforce this is by waiting until we get |
469 | * all response bytes back from the EC, rather than just the number that |
470 | * the caller requests (otherwise, we might start a new command while an |
471 | * old command's response bytes are still incoming). |
472 | */ |
473 | static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp, |
474 | size_t resp_len, void *ec_cb_arg) |
475 | { |
476 | struct olpc_xo175_ec *priv = ec_cb_arg; |
477 | struct device *dev = &priv->spi->dev; |
478 | unsigned long flags; |
479 | size_t nr_bytes; |
480 | int ret = 0; |
481 | |
482 | dev_dbg(dev, "CMD %x, %zd bytes expected\n" , cmd, resp_len); |
483 | |
484 | if (inlen > 5) { |
485 | dev_err(dev, "command len %zd too big!\n" , resp_len); |
486 | return -EOVERFLOW; |
487 | } |
488 | |
489 | /* Suspending in the middle of an EC command hoses things badly! */ |
490 | if (WARN_ON(priv->suspended)) |
491 | return -EBUSY; |
492 | |
493 | /* Ensure a valid command and return bytes */ |
494 | ret = olpc_xo175_ec_resp_len(cmd); |
495 | if (ret < 0) { |
496 | dev_err_ratelimited(dev, "unknown command 0x%x\n" , cmd); |
497 | |
498 | /* |
499 | * Assume the best in our callers, and allow unknown commands |
500 | * through. I'm not the charitable type, but it was beaten |
501 | * into me. Just maintain a minimum standard of sanity. |
502 | */ |
503 | if (resp_len > sizeof(priv->resp_data)) { |
504 | dev_err(dev, "response too big: %zd!\n" , resp_len); |
505 | return -EOVERFLOW; |
506 | } |
507 | nr_bytes = resp_len; |
508 | } else { |
509 | nr_bytes = (size_t)ret; |
510 | ret = 0; |
511 | } |
512 | resp_len = min(resp_len, nr_bytes); |
513 | |
514 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
515 | |
516 | /* Initialize the state machine */ |
517 | init_completion(x: &priv->cmd_done); |
518 | priv->cmd_running = true; |
519 | priv->cmd_state = CMD_STATE_WAITING_FOR_SWITCH; |
520 | memset(&priv->cmd, 0, sizeof(priv->cmd)); |
521 | priv->cmd.command = cmd; |
522 | priv->cmd.nr_args = inlen; |
523 | priv->cmd.data_len = 0; |
524 | memcpy(priv->cmd.args, inbuf, inlen); |
525 | priv->expected_resp_len = nr_bytes; |
526 | priv->resp_len = 0; |
527 | |
528 | /* Tickle the cmd gpio to get things started */ |
529 | gpiod_set_value_cansleep(desc: priv->gpio_cmd, value: 1); |
530 | |
531 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
532 | |
533 | /* The irq handler should do the rest */ |
534 | if (!wait_for_completion_timeout(x: &priv->cmd_done, |
535 | timeout: msecs_to_jiffies(m: 4000))) { |
536 | dev_err(dev, "EC cmd error: timeout in STATE %d\n" , |
537 | priv->cmd_state); |
538 | gpiod_set_value_cansleep(desc: priv->gpio_cmd, value: 0); |
539 | spi_slave_abort(spi: priv->spi); |
540 | olpc_xo175_ec_read_packet(priv); |
541 | return -ETIMEDOUT; |
542 | } |
543 | |
544 | spin_lock_irqsave(&priv->cmd_state_lock, flags); |
545 | |
546 | /* Deal with the results. */ |
547 | if (priv->cmd_state == CMD_STATE_ERROR_RECEIVED) { |
548 | /* EC-provided error is in the single response byte */ |
549 | dev_err(dev, "command 0x%x returned error 0x%x\n" , |
550 | cmd, priv->resp_data[0]); |
551 | ret = -EREMOTEIO; |
552 | } else if (priv->resp_len != nr_bytes) { |
553 | dev_err(dev, "command 0x%x returned %d bytes, expected %zd bytes\n" , |
554 | cmd, priv->resp_len, nr_bytes); |
555 | ret = -EREMOTEIO; |
556 | } else { |
557 | /* |
558 | * We may have 8 bytes in priv->resp, but we only care about |
559 | * what we've been asked for. If the caller asked for only 2 |
560 | * bytes, give them that. We've guaranteed that |
561 | * resp_len <= priv->resp_len and priv->resp_len == nr_bytes. |
562 | */ |
563 | memcpy(resp, priv->resp_data, resp_len); |
564 | } |
565 | |
566 | /* This should already be low, but just in case. */ |
567 | gpiod_set_value_cansleep(desc: priv->gpio_cmd, value: 0); |
568 | priv->cmd_running = false; |
569 | |
570 | spin_unlock_irqrestore(lock: &priv->cmd_state_lock, flags); |
571 | |
572 | return ret; |
573 | } |
574 | |
575 | static int olpc_xo175_ec_set_event_mask(unsigned int mask) |
576 | { |
577 | u8 args[2]; |
578 | |
579 | args[0] = mask >> 0; |
580 | args[1] = mask >> 8; |
581 | return olpc_ec_cmd(CMD_WRITE_EXT_SCI_MASK, inbuf: args, inlen: 2, NULL, outlen: 0); |
582 | } |
583 | |
584 | static void olpc_xo175_ec_power_off(void) |
585 | { |
586 | while (1) { |
587 | olpc_ec_cmd(CMD_POWER_OFF, NULL, inlen: 0, NULL, outlen: 0); |
588 | mdelay(1000); |
589 | } |
590 | } |
591 | |
592 | static int __maybe_unused olpc_xo175_ec_suspend(struct device *dev) |
593 | { |
594 | struct olpc_xo175_ec *priv = dev_get_drvdata(dev); |
595 | static struct { |
596 | u8 suspend; |
597 | u32 suspend_count; |
598 | } __packed hintargs; |
599 | static unsigned int suspend_count; |
600 | |
601 | /* |
602 | * SOC_SLEEP is not wired to the EC on B3 and earlier boards. |
603 | * This command lets the EC know instead. The suspend count doesn't seem |
604 | * to be used anywhere but in the EC debug output. |
605 | */ |
606 | hintargs.suspend = 1; |
607 | hintargs.suspend_count = suspend_count++; |
608 | olpc_ec_cmd(CMD_SUSPEND_HINT, inbuf: (void *)&hintargs, inlen: sizeof(hintargs), |
609 | NULL, outlen: 0); |
610 | |
611 | /* |
612 | * After we've sent the suspend hint, don't allow further EC commands |
613 | * to be run until we've resumed. Userspace tasks should be frozen, |
614 | * but kernel threads and interrupts could still schedule EC commands. |
615 | */ |
616 | priv->suspended = true; |
617 | |
618 | return 0; |
619 | } |
620 | |
621 | static int __maybe_unused olpc_xo175_ec_resume_noirq(struct device *dev) |
622 | { |
623 | struct olpc_xo175_ec *priv = dev_get_drvdata(dev); |
624 | |
625 | priv->suspended = false; |
626 | |
627 | return 0; |
628 | } |
629 | |
630 | static int __maybe_unused olpc_xo175_ec_resume(struct device *dev) |
631 | { |
632 | u8 x = 0; |
633 | |
634 | /* |
635 | * The resume hint is only needed if no other commands are |
636 | * being sent during resume. all it does is tell the EC |
637 | * the SoC is definitely awake. |
638 | */ |
639 | olpc_ec_cmd(CMD_SUSPEND_HINT, inbuf: &x, inlen: 1, NULL, outlen: 0); |
640 | |
641 | /* Enable all EC events while we're awake */ |
642 | olpc_xo175_ec_set_event_mask(EC_ALL_EVENTS); |
643 | |
644 | return 0; |
645 | } |
646 | |
647 | static struct olpc_ec_driver olpc_xo175_ec_driver = { |
648 | .ec_cmd = olpc_xo175_ec_cmd, |
649 | }; |
650 | |
651 | static void olpc_xo175_ec_remove(struct spi_device *spi) |
652 | { |
653 | if (pm_power_off == olpc_xo175_ec_power_off) |
654 | pm_power_off = NULL; |
655 | |
656 | spi_slave_abort(spi); |
657 | |
658 | platform_device_unregister(olpc_ec); |
659 | olpc_ec = NULL; |
660 | } |
661 | |
662 | static int olpc_xo175_ec_probe(struct spi_device *spi) |
663 | { |
664 | struct olpc_xo175_ec *priv; |
665 | int ret; |
666 | |
667 | if (olpc_ec) { |
668 | dev_err(&spi->dev, "OLPC EC already registered.\n" ); |
669 | return -EBUSY; |
670 | } |
671 | |
672 | priv = devm_kzalloc(dev: &spi->dev, size: sizeof(*priv), GFP_KERNEL); |
673 | if (!priv) |
674 | return -ENOMEM; |
675 | |
676 | priv->gpio_cmd = devm_gpiod_get(dev: &spi->dev, con_id: "cmd" , flags: GPIOD_OUT_LOW); |
677 | if (IS_ERR(ptr: priv->gpio_cmd)) { |
678 | dev_err(&spi->dev, "failed to get cmd gpio: %ld\n" , |
679 | PTR_ERR(priv->gpio_cmd)); |
680 | return PTR_ERR(ptr: priv->gpio_cmd); |
681 | } |
682 | |
683 | priv->spi = spi; |
684 | |
685 | spin_lock_init(&priv->cmd_state_lock); |
686 | priv->cmd_state = CMD_STATE_IDLE; |
687 | init_completion(x: &priv->cmd_done); |
688 | |
689 | priv->logbuf_len = 0; |
690 | |
691 | /* Set up power button input device */ |
692 | priv->pwrbtn = devm_input_allocate_device(&spi->dev); |
693 | if (!priv->pwrbtn) |
694 | return -ENOMEM; |
695 | priv->pwrbtn->name = "Power Button" ; |
696 | priv->pwrbtn->dev.parent = &spi->dev; |
697 | input_set_capability(dev: priv->pwrbtn, EV_KEY, KEY_POWER); |
698 | ret = input_register_device(priv->pwrbtn); |
699 | if (ret) { |
700 | dev_err(&spi->dev, "error registering input device: %d\n" , ret); |
701 | return ret; |
702 | } |
703 | |
704 | spi_set_drvdata(spi, data: priv); |
705 | |
706 | priv->xfer.rx_buf = &priv->rx_buf; |
707 | priv->xfer.tx_buf = &priv->tx_buf; |
708 | |
709 | olpc_xo175_ec_read_packet(priv); |
710 | |
711 | olpc_ec_driver_register(drv: &olpc_xo175_ec_driver, arg: priv); |
712 | olpc_ec = platform_device_register_resndata(parent: &spi->dev, name: "olpc-ec" , id: -1, |
713 | NULL, num: 0, NULL, size: 0); |
714 | |
715 | /* Enable all EC events while we're awake */ |
716 | olpc_xo175_ec_set_event_mask(EC_ALL_EVENTS); |
717 | |
718 | if (pm_power_off == NULL) |
719 | pm_power_off = olpc_xo175_ec_power_off; |
720 | |
721 | dev_info(&spi->dev, "OLPC XO-1.75 Embedded Controller driver\n" ); |
722 | |
723 | return 0; |
724 | } |
725 | |
726 | static const struct dev_pm_ops olpc_xo175_ec_pm_ops = { |
727 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, olpc_xo175_ec_resume_noirq) |
728 | SET_RUNTIME_PM_OPS(olpc_xo175_ec_suspend, olpc_xo175_ec_resume, NULL) |
729 | }; |
730 | |
731 | static const struct of_device_id olpc_xo175_ec_of_match[] = { |
732 | { .compatible = "olpc,xo1.75-ec" }, |
733 | { } |
734 | }; |
735 | MODULE_DEVICE_TABLE(of, olpc_xo175_ec_of_match); |
736 | |
737 | static const struct spi_device_id olpc_xo175_ec_id_table[] = { |
738 | { "xo1.75-ec" , 0 }, |
739 | {} |
740 | }; |
741 | MODULE_DEVICE_TABLE(spi, olpc_xo175_ec_id_table); |
742 | |
743 | static struct spi_driver olpc_xo175_ec_spi_driver = { |
744 | .driver = { |
745 | .name = "olpc-xo175-ec" , |
746 | .of_match_table = olpc_xo175_ec_of_match, |
747 | .pm = &olpc_xo175_ec_pm_ops, |
748 | }, |
749 | .id_table = olpc_xo175_ec_id_table, |
750 | .probe = olpc_xo175_ec_probe, |
751 | .remove = olpc_xo175_ec_remove, |
752 | }; |
753 | module_spi_driver(olpc_xo175_ec_spi_driver); |
754 | |
755 | MODULE_DESCRIPTION("OLPC XO-1.75 Embedded Controller driver" ); |
756 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>" ); /* Functionality */ |
757 | MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>" ); /* Bugs */ |
758 | MODULE_LICENSE("GPL" ); |
759 | |