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
25struct 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
40static 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
100err:
101	outb(0xff, HSTS);
102	return status;
103}
104
105static 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;
148err:
149	return status;
150}
151
152static 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
183static 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
232err:
233	return status;
234}
235
236static 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
254static 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
330rxerr:
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
339static 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
347static 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
405err:
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
415static 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
439err:
440	dev_err(dev, "IR Receive message failed (%d)", status);
441	return -EIO;
442}
443#else
444static void secocec_ir_rx(struct secocec_data *priv)
445{
446}
447
448static int secocec_ir_probe(void *priv)
449{
450	return 0;
451}
452#endif
453
454static 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
499err:
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
509struct cec_dmi_match {
510	const char *sys_vendor;
511	const char *product_name;
512	const char *devname;
513	const char *conn;
514};
515
516static const struct cec_dmi_match secocec_dmi_match_table[] = {
517	/* UDOO X86 */
518	{ "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
519};
520
521static 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
548static 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
572static 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
673err_notifier:
674	cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
675err_delete_adapter:
676	cec_delete_adapter(secocec->cec_adap);
677err:
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
684static 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
707static 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
735err:
736	dev_err(dev, "Suspend failed (err: %d)", status);
737	return status;
738}
739
740static 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
769err:
770	dev_err(dev, "Resume failed (err: %d)", status);
771	return status;
772}
773
774static 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
781static const struct acpi_device_id secocec_acpi_match[] = {
782	{"CEC00001", 0},
783	{},
784};
785
786MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
787#endif
788
789static 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
799module_platform_driver(secocec_driver);
800
801MODULE_DESCRIPTION("SECO CEC X86 Driver");
802MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
803MODULE_LICENSE("Dual BSD/GPL");
804