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