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 
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 
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 
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 
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 
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 
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_CEC_SECO_RC
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_US(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 
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
444 static void secocec_ir_rx(struct secocec_data *priv)
445 {
446 }
447 
448 static int secocec_ir_probe(void *priv)
449 {
450 	return 0;
451 }
452 #endif
453 
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 
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 
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 
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, secocec->cec_adap);
675 err_delete_adapter:
676 	cec_delete_adapter(secocec->cec_adap);
677 err:
678 	release_region(BRA_SMB_BASE_ADDR, 7);
679 	dev_err(dev, "%s device probe failed\n", dev_name(dev));
680 
681 	return ret;
682 }
683 
684 static int secocec_remove(struct platform_device *pdev)
685 {
686 	struct secocec_data *secocec = platform_get_drvdata(pdev);
687 	u16 val;
688 
689 	if (secocec->ir) {
690 		smb_rd16(SECOCEC_ENABLE_REG_1, &val);
691 
692 		smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR);
693 
694 		dev_dbg(&pdev->dev, "IR disabled");
695 	}
696 	cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
697 	cec_unregister_adapter(secocec->cec_adap);
698 
699 	release_region(BRA_SMB_BASE_ADDR, 7);
700 
701 	dev_dbg(&pdev->dev, "CEC device removed");
702 
703 	return 0;
704 }
705 
706 #ifdef CONFIG_PM_SLEEP
707 static int secocec_suspend(struct device *dev)
708 {
709 	int status;
710 	u16 val;
711 
712 	dev_dbg(dev, "Device going to suspend, disabling");
713 
714 	/* Clear the status register */
715 	status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
716 	if (status)
717 		goto err;
718 
719 	status = smb_wr16(SECOCEC_STATUS_REG_1, val);
720 	if (status)
721 		goto err;
722 
723 	/* Disable the interrupts */
724 	status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
725 	if (status)
726 		goto err;
727 
728 	status = smb_wr16(SECOCEC_ENABLE_REG_1, val &
729 			  ~SECOCEC_ENABLE_REG_1_CEC & ~SECOCEC_ENABLE_REG_1_IR);
730 	if (status)
731 		goto err;
732 
733 	return 0;
734 
735 err:
736 	dev_err(dev, "Suspend failed (err: %d)", status);
737 	return status;
738 }
739 
740 static int secocec_resume(struct device *dev)
741 {
742 	int status;
743 	u16 val;
744 
745 	dev_dbg(dev, "Resuming device from suspend");
746 
747 	/* Clear the status register */
748 	status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
749 	if (status)
750 		goto err;
751 
752 	status = smb_wr16(SECOCEC_STATUS_REG_1, val);
753 	if (status)
754 		goto err;
755 
756 	/* Enable the interrupts */
757 	status = smb_rd16(SECOCEC_ENABLE_REG_1, &val);
758 	if (status)
759 		goto err;
760 
761 	status = smb_wr16(SECOCEC_ENABLE_REG_1, val | SECOCEC_ENABLE_REG_1_CEC);
762 	if (status)
763 		goto err;
764 
765 	dev_dbg(dev, "Device resumed from suspend");
766 
767 	return 0;
768 
769 err:
770 	dev_err(dev, "Resume failed (err: %d)", status);
771 	return status;
772 }
773 
774 static SIMPLE_DEV_PM_OPS(secocec_pm_ops, secocec_suspend, secocec_resume);
775 #define SECOCEC_PM_OPS (&secocec_pm_ops)
776 #else
777 #define SECOCEC_PM_OPS NULL
778 #endif
779 
780 #ifdef CONFIG_ACPI
781 static const struct acpi_device_id secocec_acpi_match[] = {
782 	{"CEC00001", 0},
783 	{},
784 };
785 
786 MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
787 #endif
788 
789 static struct platform_driver secocec_driver = {
790 	.driver = {
791 		   .name = SECOCEC_DEV_NAME,
792 		   .acpi_match_table = ACPI_PTR(secocec_acpi_match),
793 		   .pm = SECOCEC_PM_OPS,
794 	},
795 	.probe = secocec_probe,
796 	.remove = secocec_remove,
797 };
798 
799 module_platform_driver(secocec_driver);
800 
801 MODULE_DESCRIPTION("SECO CEC X86 Driver");
802 MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
803 MODULE_LICENSE("Dual BSD/GPL");
804