1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * CEC driver for SECO X86 Boards
4 *
5 * Author: Ettore Chimenti <ek5.chimenti@gmail.com>
6 * Copyright (C) 2018, SECO SpA.
7 * Copyright (C) 2018, Aidilab Srl.
8 */
9
10 #include <linux/module.h>
11 #include <linux/acpi.h>
12 #include <linux/delay.h>
13 #include <linux/dmi.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/interrupt.h>
16 #include <linux/pci.h>
17 #include <linux/platform_device.h>
18
19 /* CEC Framework */
20 #include <media/cec-notifier.h>
21
22 #include "seco-cec.h"
23
24 struct secocec_data {
25 struct device *dev;
26 struct platform_device *pdev;
27 struct cec_adapter *cec_adap;
28 struct cec_notifier *notifier;
29 struct rc_dev *ir;
30 char ir_input_phys[32];
31 int irq;
32 };
33
34 #define smb_wr16(cmd, data) smb_word_op(SECOCEC_MICRO_ADDRESS, \
35 cmd, data, SMBUS_WRITE, NULL)
36 #define smb_rd16(cmd, res) smb_word_op(SECOCEC_MICRO_ADDRESS, \
37 cmd, 0, SMBUS_READ, res)
38
smb_word_op(u16 slave_addr,u8 cmd,u16 data,u8 operation,u16 * result)39 static int smb_word_op(u16 slave_addr, u8 cmd, u16 data,
40 u8 operation, u16 *result)
41 {
42 unsigned int count;
43 int status = 0;
44
45 /* Active wait until ready */
46 for (count = 0; count <= SMBTIMEOUT; ++count) {
47 if (!(inb(HSTS) & BRA_INUSE_STS))
48 break;
49 udelay(SMB_POLL_UDELAY);
50 }
51
52 if (count > SMBTIMEOUT)
53 /* Reset the lock instead of failing */
54 outb(0xff, HSTS);
55
56 outb(0x00, HCNT);
57 outb((u8)(slave_addr & 0xfe) | operation, XMIT_SLVA);
58 outb(cmd, HCMD);
59 inb(HCNT);
60
61 if (operation == SMBUS_WRITE) {
62 outb((u8)data, HDAT0);
63 outb((u8)(data >> 8), HDAT1);
64 }
65
66 outb(BRA_START + BRA_SMB_CMD_WORD_DATA, HCNT);
67
68 for (count = 0; count <= SMBTIMEOUT; count++) {
69 if (!(inb(HSTS) & BRA_HOST_BUSY))
70 break;
71 udelay(SMB_POLL_UDELAY);
72 }
73
74 if (count > SMBTIMEOUT) {
75 status = -EBUSY;
76 goto err;
77 }
78
79 if (inb(HSTS) & BRA_HSTS_ERR_MASK) {
80 status = -EIO;
81 goto err;
82 }
83
84 if (operation == SMBUS_READ)
85 *result = ((inb(HDAT0) & 0xff) + ((inb(HDAT1) & 0xff) << 8));
86
87 err:
88 outb(0xff, HSTS);
89 return status;
90 }
91
secocec_adap_enable(struct cec_adapter * adap,bool enable)92 static int secocec_adap_enable(struct cec_adapter *adap, bool enable)
93 {
94 struct secocec_data *cec = cec_get_drvdata(adap);
95 struct device *dev = cec->dev;
96 u16 val = 0;
97 int status;
98
99 if (enable) {
100 /* Clear the status register */
101 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
102 if (status)
103 goto err;
104
105 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
106 if (status)
107 goto err;
108
109 /* Enable the interrupts */
110 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
111 if (status)
112 goto err;
113
114 status = smb_wr16(SECOCEC_ENABLE_REG_1,
115 val | SECOCEC_ENABLE_REG_1_CEC);
116 if (status)
117 goto err;
118
119 dev_dbg(dev, "Device enabled\n");
120 } else {
121 /* Clear the status register */
122 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
123 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
124
125 /* Disable the interrupts */
126 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
127 status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
128 ~SECOCEC_ENABLE_REG_1_CEC &
129 ~SECOCEC_ENABLE_REG_1_IR);
130
131 dev_dbg(dev, "Device disabled\n");
132 }
133
134 return 0;
135 err:
136 return status;
137 }
138
secocec_adap_log_addr(struct cec_adapter * adap,u8 logical_addr)139 static int secocec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
140 {
141 u16 enable_val = 0;
142 int status;
143
144 /* Disable device */
145 status = smb_rd16(SECOCEC_ENABLE_REG_1, &enable_val);
146 if (status)
147 return status;
148
149 status = smb_wr16(SECOCEC_ENABLE_REG_1,
150 enable_val & ~SECOCEC_ENABLE_REG_1_CEC);
151 if (status)
152 return status;
153
154 /* Write logical address
155 * NOTE: CEC_LOG_ADDR_INVALID is mapped to the 'Unregistered' LA
156 */
157 status = smb_wr16(SECOCEC_DEVICE_LA, logical_addr & 0xf);
158 if (status)
159 return status;
160
161 /* Re-enable device */
162 status = smb_wr16(SECOCEC_ENABLE_REG_1,
163 enable_val | SECOCEC_ENABLE_REG_1_CEC);
164 if (status)
165 return status;
166
167 return 0;
168 }
169
secocec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)170 static int secocec_adap_transmit(struct cec_adapter *adap, u8 attempts,
171 u32 signal_free_time, struct cec_msg *msg)
172 {
173 u16 payload_len, payload_id_len, destination, val = 0;
174 u8 *payload_msg;
175 int status;
176 u8 i;
177
178 /* Device msg len already accounts for header */
179 payload_id_len = msg->len - 1;
180
181 /* Send data length */
182 status = smb_wr16(SECOCEC_WRITE_DATA_LENGTH, payload_id_len);
183 if (status)
184 goto err;
185
186 /* Send Operation ID if present */
187 if (payload_id_len > 0) {
188 status = smb_wr16(SECOCEC_WRITE_OPERATION_ID, msg->msg[1]);
189 if (status)
190 goto err;
191 }
192 /* Send data if present */
193 if (payload_id_len > 1) {
194 /* Only data; */
195 payload_len = msg->len - 2;
196 payload_msg = &msg->msg[2];
197
198 /* Copy message into registers */
199 for (i = 0; i < payload_len; i += 2) {
200 /* hi byte */
201 val = payload_msg[i + 1] << 8;
202
203 /* lo byte */
204 val |= payload_msg[i];
205
206 status = smb_wr16(SECOCEC_WRITE_DATA_00 + i / 2, val);
207 if (status)
208 goto err;
209 }
210 }
211 /* Send msg source/destination and fire msg */
212 destination = msg->msg[0];
213 status = smb_wr16(SECOCEC_WRITE_BYTE0, destination);
214 if (status)
215 goto err;
216
217 return 0;
218
219 err:
220 return status;
221 }
222
secocec_tx_done(struct cec_adapter * adap,u16 status_val)223 static void secocec_tx_done(struct cec_adapter *adap, u16 status_val)
224 {
225 if (status_val & SECOCEC_STATUS_TX_ERROR_MASK) {
226 if (status_val & SECOCEC_STATUS_TX_NACK_ERROR)
227 cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK);
228 else
229 cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR);
230 } else {
231 cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK);
232 }
233
234 /* Reset status reg */
235 status_val = SECOCEC_STATUS_TX_ERROR_MASK |
236 SECOCEC_STATUS_MSG_SENT_MASK |
237 SECOCEC_STATUS_TX_NACK_ERROR;
238 smb_wr16(SECOCEC_STATUS, status_val);
239 }
240
secocec_rx_done(struct cec_adapter * adap,u16 status_val)241 static void secocec_rx_done(struct cec_adapter *adap, u16 status_val)
242 {
243 struct secocec_data *cec = cec_get_drvdata(adap);
244 struct device *dev = cec->dev;
245 struct cec_msg msg = { };
246 bool flag_overflow = false;
247 u8 payload_len, i = 0;
248 u8 *payload_msg;
249 u16 val = 0;
250 int status;
251
252 if (status_val & SECOCEC_STATUS_RX_OVERFLOW_MASK) {
253 /* NOTE: Untested, it also might not be necessary */
254 dev_warn(dev, "Received more than 16 bytes. Discarding\n");
255 flag_overflow = true;
256 }
257
258 if (status_val & SECOCEC_STATUS_RX_ERROR_MASK) {
259 dev_warn(dev, "Message received with errors. Discarding\n");
260 status = -EIO;
261 goto rxerr;
262 }
263
264 /* Read message length */
265 status = smb_rd16(SECOCEC_READ_DATA_LENGTH, &val);
266 if (status)
267 return;
268
269 /* Device msg len already accounts for the header */
270 msg.len = min(val + 1, CEC_MAX_MSG_SIZE);
271
272 /* Read logical address */
273 status = smb_rd16(SECOCEC_READ_BYTE0, &val);
274 if (status)
275 return;
276
277 /* device stores source LA and destination */
278 msg.msg[0] = val;
279
280 /* Read operation ID */
281 status = smb_rd16(SECOCEC_READ_OPERATION_ID, &val);
282 if (status)
283 return;
284
285 msg.msg[1] = val;
286
287 /* Read data if present */
288 if (msg.len > 1) {
289 payload_len = msg.len - 2;
290 payload_msg = &msg.msg[2];
291
292 /* device stores 2 bytes in every 16-bit val */
293 for (i = 0; i < payload_len; i += 2) {
294 status = smb_rd16(SECOCEC_READ_DATA_00 + i / 2, &val);
295 if (status)
296 return;
297
298 /* low byte, skipping header */
299 payload_msg[i] = val & 0x00ff;
300
301 /* hi byte */
302 payload_msg[i + 1] = (val & 0xff00) >> 8;
303 }
304 }
305
306 cec_received_msg(cec->cec_adap, &msg);
307
308 /* Reset status reg */
309 status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK;
310 if (flag_overflow)
311 status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
312
313 status = smb_wr16(SECOCEC_STATUS, status_val);
314
315 return;
316
317 rxerr:
318 /* Reset error reg */
319 status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK |
320 SECOCEC_STATUS_RX_ERROR_MASK;
321 if (flag_overflow)
322 status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK;
323 smb_wr16(SECOCEC_STATUS, status_val);
324 }
325
326 static const struct cec_adap_ops secocec_cec_adap_ops = {
327 /* Low-level callbacks */
328 .adap_enable = secocec_adap_enable,
329 .adap_log_addr = secocec_adap_log_addr,
330 .adap_transmit = secocec_adap_transmit,
331 };
332
333 #ifdef CONFIG_CEC_SECO_RC
secocec_ir_probe(void * priv)334 static int secocec_ir_probe(void *priv)
335 {
336 struct secocec_data *cec = priv;
337 struct device *dev = cec->dev;
338 int status;
339 u16 val;
340
341 /* Prepare the RC input device */
342 cec->ir = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE);
343 if (!cec->ir)
344 return -ENOMEM;
345
346 snprintf(cec->ir_input_phys, sizeof(cec->ir_input_phys),
347 "%s/input0", dev_name(dev));
348
349 cec->ir->device_name = dev_name(dev);
350 cec->ir->input_phys = cec->ir_input_phys;
351 cec->ir->input_id.bustype = BUS_HOST;
352 cec->ir->input_id.vendor = 0;
353 cec->ir->input_id.product = 0;
354 cec->ir->input_id.version = 1;
355 cec->ir->driver_name = SECOCEC_DEV_NAME;
356 cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
357 cec->ir->priv = cec;
358 cec->ir->map_name = RC_MAP_HAUPPAUGE;
359 cec->ir->timeout = MS_TO_US(100);
360
361 /* Clear the status register */
362 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
363 if (status != 0)
364 goto err;
365
366 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
367 if (status != 0)
368 goto err;
369
370 /* Enable the interrupts */
371 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
372 if (status != 0)
373 goto err;
374
375 status = smb_wr16(SECOCEC_ENABLE_REG_1,
376 val | SECOCEC_ENABLE_REG_1_IR);
377 if (status != 0)
378 goto err;
379
380 dev_dbg(dev, "IR enabled\n");
381
382 status = devm_rc_register_device(dev, cec->ir);
383
384 if (status) {
385 dev_err(dev, "Failed to prepare input device\n");
386 cec->ir = NULL;
387 goto err;
388 }
389
390 return 0;
391
392 err:
393 smb_rd16(SECOCEC_ENABLE_REG_1, &val);
394
395 smb_wr16(SECOCEC_ENABLE_REG_1,
396 val & ~SECOCEC_ENABLE_REG_1_IR);
397
398 dev_dbg(dev, "IR disabled\n");
399 return status;
400 }
401
secocec_ir_rx(struct secocec_data * priv)402 static int secocec_ir_rx(struct secocec_data *priv)
403 {
404 struct secocec_data *cec = priv;
405 struct device *dev = cec->dev;
406 u16 val, status, key, addr, toggle;
407
408 if (!cec->ir)
409 return -ENODEV;
410
411 status = smb_rd16(SECOCEC_IR_READ_DATA, &val);
412 if (status != 0)
413 goto err;
414
415 key = val & SECOCEC_IR_COMMAND_MASK;
416 addr = (val & SECOCEC_IR_ADDRESS_MASK) >> SECOCEC_IR_ADDRESS_SHL;
417 toggle = (val & SECOCEC_IR_TOGGLE_MASK) >> SECOCEC_IR_TOGGLE_SHL;
418
419 rc_keydown(cec->ir, RC_PROTO_RC5, RC_SCANCODE_RC5(addr, key), toggle);
420
421 dev_dbg(dev, "IR key pressed: 0x%02x addr 0x%02x toggle 0x%02x\n", key,
422 addr, toggle);
423
424 return 0;
425
426 err:
427 dev_err(dev, "IR Receive message failed (%d)\n", status);
428 return -EIO;
429 }
430 #else
secocec_ir_rx(struct secocec_data * priv)431 static void secocec_ir_rx(struct secocec_data *priv)
432 {
433 }
434
secocec_ir_probe(void * priv)435 static int secocec_ir_probe(void *priv)
436 {
437 return 0;
438 }
439 #endif
440
secocec_irq_handler(int irq,void * priv)441 static irqreturn_t secocec_irq_handler(int irq, void *priv)
442 {
443 struct secocec_data *cec = priv;
444 struct device *dev = cec->dev;
445 u16 status_val, cec_val, val = 0;
446 int status;
447
448 /* Read status register */
449 status = smb_rd16(SECOCEC_STATUS_REG_1, &status_val);
450 if (status)
451 goto err;
452
453 if (status_val & SECOCEC_STATUS_REG_1_CEC) {
454 /* Read CEC status register */
455 status = smb_rd16(SECOCEC_STATUS, &cec_val);
456 if (status)
457 goto err;
458
459 if (cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK)
460 secocec_rx_done(cec->cec_adap, cec_val);
461
462 if (cec_val & SECOCEC_STATUS_MSG_SENT_MASK)
463 secocec_tx_done(cec->cec_adap, cec_val);
464
465 if ((~cec_val & SECOCEC_STATUS_MSG_SENT_MASK) &&
466 (~cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK))
467 dev_warn_once(dev,
468 "Message not received or sent, but interrupt fired");
469
470 val = SECOCEC_STATUS_REG_1_CEC;
471 }
472
473 if (status_val & SECOCEC_STATUS_REG_1_IR) {
474 val |= SECOCEC_STATUS_REG_1_IR;
475
476 secocec_ir_rx(cec);
477 }
478
479 /* Reset status register */
480 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
481 if (status)
482 goto err;
483
484 return IRQ_HANDLED;
485
486 err:
487 dev_err_once(dev, "IRQ: R/W SMBus operation failed %d\n", status);
488
489 /* Reset status register */
490 val = SECOCEC_STATUS_REG_1_CEC | SECOCEC_STATUS_REG_1_IR;
491 smb_wr16(SECOCEC_STATUS_REG_1, val);
492
493 return IRQ_HANDLED;
494 }
495
496 struct cec_dmi_match {
497 const char *sys_vendor;
498 const char *product_name;
499 const char *devname;
500 const char *conn;
501 };
502
503 static const struct cec_dmi_match secocec_dmi_match_table[] = {
504 /* UDOO X86 */
505 { "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
506 };
507
secocec_cec_find_hdmi_dev(struct device * dev,const char ** conn)508 static struct device *secocec_cec_find_hdmi_dev(struct device *dev,
509 const char **conn)
510 {
511 int i;
512
513 for (i = 0 ; i < ARRAY_SIZE(secocec_dmi_match_table) ; ++i) {
514 const struct cec_dmi_match *m = &secocec_dmi_match_table[i];
515
516 if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) &&
517 dmi_match(DMI_PRODUCT_NAME, m->product_name)) {
518 struct device *d;
519
520 /* Find the device, bail out if not yet registered */
521 d = bus_find_device_by_name(&pci_bus_type, NULL,
522 m->devname);
523 if (!d)
524 return ERR_PTR(-EPROBE_DEFER);
525
526 put_device(d);
527 *conn = m->conn;
528 return d;
529 }
530 }
531
532 return ERR_PTR(-EINVAL);
533 }
534
secocec_acpi_probe(struct secocec_data * sdev)535 static int secocec_acpi_probe(struct secocec_data *sdev)
536 {
537 struct device *dev = sdev->dev;
538 struct gpio_desc *gpio;
539 int irq = 0;
540
541 gpio = devm_gpiod_get(dev, NULL, GPIOD_IN);
542 if (IS_ERR(gpio)) {
543 dev_err(dev, "Cannot request interrupt gpio\n");
544 return PTR_ERR(gpio);
545 }
546
547 irq = gpiod_to_irq(gpio);
548 if (irq < 0) {
549 dev_err(dev, "Cannot find valid irq\n");
550 return -ENODEV;
551 }
552 dev_dbg(dev, "irq-gpio is bound to IRQ %d\n", irq);
553
554 sdev->irq = irq;
555
556 return 0;
557 }
558
secocec_probe(struct platform_device * pdev)559 static int secocec_probe(struct platform_device *pdev)
560 {
561 struct secocec_data *secocec;
562 struct device *dev = &pdev->dev;
563 struct device *hdmi_dev;
564 const char *conn = NULL;
565 int ret;
566 u16 val;
567
568 hdmi_dev = secocec_cec_find_hdmi_dev(&pdev->dev, &conn);
569 if (IS_ERR(hdmi_dev))
570 return PTR_ERR(hdmi_dev);
571
572 secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL);
573 if (!secocec)
574 return -ENOMEM;
575
576 dev_set_drvdata(dev, secocec);
577
578 /* Request SMBus regions */
579 if (!request_muxed_region(BRA_SMB_BASE_ADDR, 7, "CEC00001")) {
580 dev_err(dev, "Request memory region failed\n");
581 return -ENXIO;
582 }
583
584 secocec->pdev = pdev;
585 secocec->dev = dev;
586
587 if (!has_acpi_companion(dev)) {
588 dev_dbg(dev, "Cannot find any ACPI companion\n");
589 ret = -ENODEV;
590 goto err;
591 }
592
593 ret = secocec_acpi_probe(secocec);
594 if (ret) {
595 dev_err(dev, "Cannot assign gpio to IRQ\n");
596 ret = -ENODEV;
597 goto err;
598 }
599
600 /* Firmware version check */
601 ret = smb_rd16(SECOCEC_VERSION, &val);
602 if (ret) {
603 dev_err(dev, "Cannot check fw version\n");
604 goto err;
605 }
606 if (val < SECOCEC_LATEST_FW) {
607 dev_err(dev, "CEC Firmware not supported (v.%04x). Use ver > v.%04x\n",
608 val, SECOCEC_LATEST_FW);
609 ret = -EINVAL;
610 goto err;
611 }
612
613 ret = devm_request_threaded_irq(dev,
614 secocec->irq,
615 NULL,
616 secocec_irq_handler,
617 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
618 dev_name(&pdev->dev), secocec);
619
620 if (ret) {
621 dev_err(dev, "Cannot request IRQ %d\n", secocec->irq);
622 ret = -EIO;
623 goto err;
624 }
625
626 /* Allocate CEC adapter */
627 secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops,
628 secocec,
629 dev_name(dev),
630 CEC_CAP_DEFAULTS |
631 CEC_CAP_CONNECTOR_INFO,
632 SECOCEC_MAX_ADDRS);
633
634 if (IS_ERR(secocec->cec_adap)) {
635 ret = PTR_ERR(secocec->cec_adap);
636 goto err;
637 }
638
639 secocec->notifier = cec_notifier_cec_adap_register(hdmi_dev, conn,
640 secocec->cec_adap);
641 if (!secocec->notifier) {
642 ret = -ENOMEM;
643 goto err_delete_adapter;
644 }
645
646 ret = cec_register_adapter(secocec->cec_adap, dev);
647 if (ret)
648 goto err_notifier;
649
650 ret = secocec_ir_probe(secocec);
651 if (ret)
652 goto err_notifier;
653
654 platform_set_drvdata(pdev, secocec);
655
656 dev_dbg(dev, "Device registered\n");
657
658 return ret;
659
660 err_notifier:
661 cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
662 err_delete_adapter:
663 cec_delete_adapter(secocec->cec_adap);
664 err:
665 release_region(BRA_SMB_BASE_ADDR, 7);
666 dev_err(dev, "%s device probe failed\n", dev_name(dev));
667
668 return ret;
669 }
670
secocec_remove(struct platform_device * pdev)671 static void secocec_remove(struct platform_device *pdev)
672 {
673 struct secocec_data *secocec = platform_get_drvdata(pdev);
674 u16 val;
675
676 if (secocec->ir) {
677 smb_rd16(SECOCEC_ENABLE_REG_1, &val);
678
679 smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR);
680
681 dev_dbg(&pdev->dev, "IR disabled\n");
682 }
683 cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
684 cec_unregister_adapter(secocec->cec_adap);
685
686 release_region(BRA_SMB_BASE_ADDR, 7);
687
688 dev_dbg(&pdev->dev, "CEC device removed\n");
689 }
690
691 #ifdef CONFIG_PM_SLEEP
secocec_suspend(struct device * dev)692 static int secocec_suspend(struct device *dev)
693 {
694 int status;
695 u16 val;
696
697 dev_dbg(dev, "Device going to suspend, disabling\n");
698
699 /* Clear the status register */
700 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
701 if (status)
702 goto err;
703
704 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
705 if (status)
706 goto err;
707
708 /* Disable the interrupts */
709 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
710 if (status)
711 goto err;
712
713 status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
714 ~SECOCEC_ENABLE_REG_1_CEC & ~SECOCEC_ENABLE_REG_1_IR);
715 if (status)
716 goto err;
717
718 return 0;
719
720 err:
721 dev_err(dev, "Suspend failed: %d\n", status);
722 return status;
723 }
724
secocec_resume(struct device * dev)725 static int secocec_resume(struct device *dev)
726 {
727 int status;
728 u16 val;
729
730 dev_dbg(dev, "Resuming device from suspend\n");
731
732 /* Clear the status register */
733 status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
734 if (status)
735 goto err;
736
737 status = smb_wr16(SECOCEC_STATUS_REG_1, val);
738 if (status)
739 goto err;
740
741 /* Enable the interrupts */
742 status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
743 if (status)
744 goto err;
745
746 status = smb_wr16(SECOCEC_ENABLE_REG_1, val | SECOCEC_ENABLE_REG_1_CEC);
747 if (status)
748 goto err;
749
750 dev_dbg(dev, "Device resumed from suspend\n");
751
752 return 0;
753
754 err:
755 dev_err(dev, "Resume failed: %d\n", status);
756 return status;
757 }
758
759 static SIMPLE_DEV_PM_OPS(secocec_pm_ops, secocec_suspend, secocec_resume);
760 #define SECOCEC_PM_OPS (&secocec_pm_ops)
761 #else
762 #define SECOCEC_PM_OPS NULL
763 #endif
764
765 #ifdef CONFIG_ACPI
766 static const struct acpi_device_id secocec_acpi_match[] = {
767 {"CEC00001", 0},
768 {},
769 };
770
771 MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
772 #endif
773
774 static struct platform_driver secocec_driver = {
775 .driver = {
776 .name = SECOCEC_DEV_NAME,
777 .acpi_match_table = ACPI_PTR(secocec_acpi_match),
778 .pm = SECOCEC_PM_OPS,
779 },
780 .probe = secocec_probe,
781 .remove_new = secocec_remove,
782 };
783
784 module_platform_driver(secocec_driver);
785
786 MODULE_DESCRIPTION("SECO CEC X86 Driver");
787 MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
788 MODULE_LICENSE("Dual BSD/GPL");
789