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
24struct 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
39static 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
87err:
88	outb(0xff, HSTS);
89	return status;
90}
91
92static 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;
135err:
136	return status;
137}
138
139static 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
170static 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
219err:
220	return status;
221}
222
223static 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
241static 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
317rxerr:
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
326static 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
334static 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
392err:
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
402static 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
426err:
427	dev_err(dev, "IR Receive message failed (%d)\n", status);
428	return -EIO;
429}
430#else
431static void secocec_ir_rx(struct secocec_data *priv)
432{
433}
434
435static int secocec_ir_probe(void *priv)
436{
437	return 0;
438}
439#endif
440
441static 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
486err:
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
496struct cec_dmi_match {
497	const char *sys_vendor;
498	const char *product_name;
499	const char *devname;
500	const char *conn;
501};
502
503static const struct cec_dmi_match secocec_dmi_match_table[] = {
504	/* UDOO X86 */
505	{ "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
506};
507
508static 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
535static 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
559static 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
660err_notifier:
661	cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
662err_delete_adapter:
663	cec_delete_adapter(secocec->cec_adap);
664err:
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
671static 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
692static 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
720err:
721	dev_err(dev, "Suspend failed: %d\n", status);
722	return status;
723}
724
725static 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
754err:
755	dev_err(dev, "Resume failed: %d\n", status);
756	return status;
757}
758
759static 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
766static const struct acpi_device_id secocec_acpi_match[] = {
767	{"CEC00001", 0},
768	{},
769};
770
771MODULE_DEVICE_TABLE(acpi, secocec_acpi_match);
772#endif
773
774static 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
784module_platform_driver(secocec_driver);
785
786MODULE_DESCRIPTION("SECO CEC X86 Driver");
787MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>");
788MODULE_LICENSE("Dual BSD/GPL");
789