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