14be5e864SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-or-later
24be5e864SMauro Carvalho Chehab /* drivers/media/platform/s5p-cec/s5p_cec.c
34be5e864SMauro Carvalho Chehab  *
44be5e864SMauro Carvalho Chehab  * Samsung S5P CEC driver
54be5e864SMauro Carvalho Chehab  *
64be5e864SMauro Carvalho Chehab  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
74be5e864SMauro Carvalho Chehab  *
84be5e864SMauro Carvalho Chehab  * This driver is based on the "cec interface driver for exynos soc" by
94be5e864SMauro Carvalho Chehab  * SangPil Moon.
104be5e864SMauro Carvalho Chehab  */
114be5e864SMauro Carvalho Chehab 
124be5e864SMauro Carvalho Chehab #include <linux/clk.h>
134be5e864SMauro Carvalho Chehab #include <linux/interrupt.h>
144be5e864SMauro Carvalho Chehab #include <linux/kernel.h>
154be5e864SMauro Carvalho Chehab #include <linux/mfd/syscon.h>
164be5e864SMauro Carvalho Chehab #include <linux/module.h>
174be5e864SMauro Carvalho Chehab #include <linux/of.h>
184be5e864SMauro Carvalho Chehab #include <linux/of_platform.h>
194be5e864SMauro Carvalho Chehab #include <linux/platform_device.h>
204be5e864SMauro Carvalho Chehab #include <linux/pm_runtime.h>
214be5e864SMauro Carvalho Chehab #include <linux/timer.h>
224be5e864SMauro Carvalho Chehab #include <linux/workqueue.h>
234be5e864SMauro Carvalho Chehab #include <media/cec.h>
244be5e864SMauro Carvalho Chehab #include <media/cec-notifier.h>
254be5e864SMauro Carvalho Chehab 
264be5e864SMauro Carvalho Chehab #include "exynos_hdmi_cec.h"
274be5e864SMauro Carvalho Chehab #include "regs-cec.h"
284be5e864SMauro Carvalho Chehab #include "s5p_cec.h"
294be5e864SMauro Carvalho Chehab 
304be5e864SMauro Carvalho Chehab #define CEC_NAME	"s5p-cec"
314be5e864SMauro Carvalho Chehab 
324be5e864SMauro Carvalho Chehab static int debug;
334be5e864SMauro Carvalho Chehab module_param(debug, int, 0644);
344be5e864SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "debug level (0-2)");
354be5e864SMauro Carvalho Chehab 
s5p_cec_adap_enable(struct cec_adapter * adap,bool enable)364be5e864SMauro Carvalho Chehab static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
374be5e864SMauro Carvalho Chehab {
38fdc34e82SMauro Carvalho Chehab 	int ret;
394be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = cec_get_drvdata(adap);
404be5e864SMauro Carvalho Chehab 
414be5e864SMauro Carvalho Chehab 	if (enable) {
42fdc34e82SMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(cec->dev);
43fdc34e82SMauro Carvalho Chehab 		if (ret < 0)
44fdc34e82SMauro Carvalho Chehab 			return ret;
454be5e864SMauro Carvalho Chehab 
464be5e864SMauro Carvalho Chehab 		s5p_cec_reset(cec);
474be5e864SMauro Carvalho Chehab 
484be5e864SMauro Carvalho Chehab 		s5p_cec_set_divider(cec);
494be5e864SMauro Carvalho Chehab 		s5p_cec_threshold(cec);
504be5e864SMauro Carvalho Chehab 
514be5e864SMauro Carvalho Chehab 		s5p_cec_unmask_tx_interrupts(cec);
524be5e864SMauro Carvalho Chehab 		s5p_cec_unmask_rx_interrupts(cec);
534be5e864SMauro Carvalho Chehab 		s5p_cec_enable_rx(cec);
544be5e864SMauro Carvalho Chehab 	} else {
554be5e864SMauro Carvalho Chehab 		s5p_cec_mask_tx_interrupts(cec);
564be5e864SMauro Carvalho Chehab 		s5p_cec_mask_rx_interrupts(cec);
57747bad54SMauro Carvalho Chehab 		pm_runtime_put(cec->dev);
584be5e864SMauro Carvalho Chehab 	}
594be5e864SMauro Carvalho Chehab 
604be5e864SMauro Carvalho Chehab 	return 0;
614be5e864SMauro Carvalho Chehab }
624be5e864SMauro Carvalho Chehab 
s5p_cec_adap_log_addr(struct cec_adapter * adap,u8 addr)634be5e864SMauro Carvalho Chehab static int s5p_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
644be5e864SMauro Carvalho Chehab {
654be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = cec_get_drvdata(adap);
664be5e864SMauro Carvalho Chehab 
674be5e864SMauro Carvalho Chehab 	s5p_cec_set_addr(cec, addr);
684be5e864SMauro Carvalho Chehab 	return 0;
694be5e864SMauro Carvalho Chehab }
704be5e864SMauro Carvalho Chehab 
s5p_cec_adap_transmit(struct cec_adapter * adap,u8 attempts,u32 signal_free_time,struct cec_msg * msg)714be5e864SMauro Carvalho Chehab static int s5p_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
724be5e864SMauro Carvalho Chehab 				 u32 signal_free_time, struct cec_msg *msg)
734be5e864SMauro Carvalho Chehab {
744be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = cec_get_drvdata(adap);
754be5e864SMauro Carvalho Chehab 
764be5e864SMauro Carvalho Chehab 	/*
774be5e864SMauro Carvalho Chehab 	 * Unclear if 0 retries are allowed by the hardware, so have 1 as
784be5e864SMauro Carvalho Chehab 	 * the minimum.
794be5e864SMauro Carvalho Chehab 	 */
804be5e864SMauro Carvalho Chehab 	s5p_cec_copy_packet(cec, msg->msg, msg->len, max(1, attempts - 1));
814be5e864SMauro Carvalho Chehab 	return 0;
824be5e864SMauro Carvalho Chehab }
834be5e864SMauro Carvalho Chehab 
s5p_cec_irq_handler(int irq,void * priv)844be5e864SMauro Carvalho Chehab static irqreturn_t s5p_cec_irq_handler(int irq, void *priv)
854be5e864SMauro Carvalho Chehab {
864be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = priv;
874be5e864SMauro Carvalho Chehab 	u32 status = 0;
884be5e864SMauro Carvalho Chehab 
894be5e864SMauro Carvalho Chehab 	status = s5p_cec_get_status(cec);
904be5e864SMauro Carvalho Chehab 
914be5e864SMauro Carvalho Chehab 	dev_dbg(cec->dev, "irq received\n");
924be5e864SMauro Carvalho Chehab 
934be5e864SMauro Carvalho Chehab 	if (status & CEC_STATUS_TX_DONE) {
944be5e864SMauro Carvalho Chehab 		if (status & CEC_STATUS_TX_NACK) {
954be5e864SMauro Carvalho Chehab 			dev_dbg(cec->dev, "CEC_STATUS_TX_NACK set\n");
964be5e864SMauro Carvalho Chehab 			cec->tx = STATE_NACK;
974be5e864SMauro Carvalho Chehab 		} else if (status & CEC_STATUS_TX_ERROR) {
984be5e864SMauro Carvalho Chehab 			dev_dbg(cec->dev, "CEC_STATUS_TX_ERROR set\n");
994be5e864SMauro Carvalho Chehab 			cec->tx = STATE_ERROR;
1004be5e864SMauro Carvalho Chehab 		} else {
1014be5e864SMauro Carvalho Chehab 			dev_dbg(cec->dev, "CEC_STATUS_TX_DONE\n");
1024be5e864SMauro Carvalho Chehab 			cec->tx = STATE_DONE;
1034be5e864SMauro Carvalho Chehab 		}
1044be5e864SMauro Carvalho Chehab 		s5p_clr_pending_tx(cec);
1054be5e864SMauro Carvalho Chehab 	}
1064be5e864SMauro Carvalho Chehab 
1074be5e864SMauro Carvalho Chehab 	if (status & CEC_STATUS_RX_DONE) {
1084be5e864SMauro Carvalho Chehab 		if (status & CEC_STATUS_RX_ERROR) {
1094be5e864SMauro Carvalho Chehab 			dev_dbg(cec->dev, "CEC_STATUS_RX_ERROR set\n");
1104be5e864SMauro Carvalho Chehab 			s5p_cec_rx_reset(cec);
1114be5e864SMauro Carvalho Chehab 			s5p_cec_enable_rx(cec);
1124be5e864SMauro Carvalho Chehab 		} else {
1134be5e864SMauro Carvalho Chehab 			dev_dbg(cec->dev, "CEC_STATUS_RX_DONE set\n");
1144be5e864SMauro Carvalho Chehab 			if (cec->rx != STATE_IDLE)
1154be5e864SMauro Carvalho Chehab 				dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n");
1164be5e864SMauro Carvalho Chehab 			cec->rx = STATE_BUSY;
1174be5e864SMauro Carvalho Chehab 			cec->msg.len = status >> 24;
11893f65ce0SHans Verkuil 			if (cec->msg.len > CEC_MAX_MSG_SIZE)
11993f65ce0SHans Verkuil 				cec->msg.len = CEC_MAX_MSG_SIZE;
1204be5e864SMauro Carvalho Chehab 			cec->msg.rx_status = CEC_RX_STATUS_OK;
1214be5e864SMauro Carvalho Chehab 			s5p_cec_get_rx_buf(cec, cec->msg.len,
1224be5e864SMauro Carvalho Chehab 					cec->msg.msg);
1234be5e864SMauro Carvalho Chehab 			cec->rx = STATE_DONE;
1244be5e864SMauro Carvalho Chehab 			s5p_cec_enable_rx(cec);
1254be5e864SMauro Carvalho Chehab 		}
1264be5e864SMauro Carvalho Chehab 		/* Clear interrupt pending bit */
1274be5e864SMauro Carvalho Chehab 		s5p_clr_pending_rx(cec);
1284be5e864SMauro Carvalho Chehab 	}
1294be5e864SMauro Carvalho Chehab 	return IRQ_WAKE_THREAD;
1304be5e864SMauro Carvalho Chehab }
1314be5e864SMauro Carvalho Chehab 
s5p_cec_irq_handler_thread(int irq,void * priv)1324be5e864SMauro Carvalho Chehab static irqreturn_t s5p_cec_irq_handler_thread(int irq, void *priv)
1334be5e864SMauro Carvalho Chehab {
1344be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = priv;
1354be5e864SMauro Carvalho Chehab 
1364be5e864SMauro Carvalho Chehab 	dev_dbg(cec->dev, "irq processing thread\n");
1374be5e864SMauro Carvalho Chehab 	switch (cec->tx) {
1384be5e864SMauro Carvalho Chehab 	case STATE_DONE:
1394be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
1404be5e864SMauro Carvalho Chehab 		cec->tx = STATE_IDLE;
1414be5e864SMauro Carvalho Chehab 		break;
1424be5e864SMauro Carvalho Chehab 	case STATE_NACK:
1434be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap,
1444be5e864SMauro Carvalho Chehab 			CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_NACK,
1454be5e864SMauro Carvalho Chehab 			0, 1, 0, 0);
1464be5e864SMauro Carvalho Chehab 		cec->tx = STATE_IDLE;
1474be5e864SMauro Carvalho Chehab 		break;
1484be5e864SMauro Carvalho Chehab 	case STATE_ERROR:
1494be5e864SMauro Carvalho Chehab 		cec_transmit_done(cec->adap,
1504be5e864SMauro Carvalho Chehab 			CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_ERROR,
1514be5e864SMauro Carvalho Chehab 			0, 0, 0, 1);
1524be5e864SMauro Carvalho Chehab 		cec->tx = STATE_IDLE;
1534be5e864SMauro Carvalho Chehab 		break;
1544be5e864SMauro Carvalho Chehab 	case STATE_BUSY:
1554be5e864SMauro Carvalho Chehab 		dev_err(cec->dev, "state set to busy, this should not occur here\n");
1564be5e864SMauro Carvalho Chehab 		break;
1574be5e864SMauro Carvalho Chehab 	default:
1584be5e864SMauro Carvalho Chehab 		break;
1594be5e864SMauro Carvalho Chehab 	}
1604be5e864SMauro Carvalho Chehab 
1614be5e864SMauro Carvalho Chehab 	switch (cec->rx) {
1624be5e864SMauro Carvalho Chehab 	case STATE_DONE:
1634be5e864SMauro Carvalho Chehab 		cec_received_msg(cec->adap, &cec->msg);
1644be5e864SMauro Carvalho Chehab 		cec->rx = STATE_IDLE;
1654be5e864SMauro Carvalho Chehab 		break;
1664be5e864SMauro Carvalho Chehab 	default:
1674be5e864SMauro Carvalho Chehab 		break;
1684be5e864SMauro Carvalho Chehab 	}
1694be5e864SMauro Carvalho Chehab 
1704be5e864SMauro Carvalho Chehab 	return IRQ_HANDLED;
1714be5e864SMauro Carvalho Chehab }
1724be5e864SMauro Carvalho Chehab 
1734be5e864SMauro Carvalho Chehab static const struct cec_adap_ops s5p_cec_adap_ops = {
1744be5e864SMauro Carvalho Chehab 	.adap_enable = s5p_cec_adap_enable,
1754be5e864SMauro Carvalho Chehab 	.adap_log_addr = s5p_cec_adap_log_addr,
1764be5e864SMauro Carvalho Chehab 	.adap_transmit = s5p_cec_adap_transmit,
1774be5e864SMauro Carvalho Chehab };
1784be5e864SMauro Carvalho Chehab 
s5p_cec_probe(struct platform_device * pdev)1794be5e864SMauro Carvalho Chehab static int s5p_cec_probe(struct platform_device *pdev)
1804be5e864SMauro Carvalho Chehab {
1814be5e864SMauro Carvalho Chehab 	struct device *dev = &pdev->dev;
1824be5e864SMauro Carvalho Chehab 	struct device *hdmi_dev;
1834be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec;
1844be5e864SMauro Carvalho Chehab 	bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd");
1854be5e864SMauro Carvalho Chehab 	int ret;
1864be5e864SMauro Carvalho Chehab 
1874be5e864SMauro Carvalho Chehab 	hdmi_dev = cec_notifier_parse_hdmi_phandle(dev);
1884be5e864SMauro Carvalho Chehab 
1894be5e864SMauro Carvalho Chehab 	if (IS_ERR(hdmi_dev))
1904be5e864SMauro Carvalho Chehab 		return PTR_ERR(hdmi_dev);
1914be5e864SMauro Carvalho Chehab 
1924be5e864SMauro Carvalho Chehab 	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
1934be5e864SMauro Carvalho Chehab 	if (!cec)
1944be5e864SMauro Carvalho Chehab 		return -ENOMEM;
1954be5e864SMauro Carvalho Chehab 
1964be5e864SMauro Carvalho Chehab 	cec->dev = dev;
1974be5e864SMauro Carvalho Chehab 
1984be5e864SMauro Carvalho Chehab 	cec->irq = platform_get_irq(pdev, 0);
1994be5e864SMauro Carvalho Chehab 	if (cec->irq < 0)
2004be5e864SMauro Carvalho Chehab 		return cec->irq;
2014be5e864SMauro Carvalho Chehab 
2024be5e864SMauro Carvalho Chehab 	ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler,
2034be5e864SMauro Carvalho Chehab 		s5p_cec_irq_handler_thread, 0, pdev->name, cec);
2044be5e864SMauro Carvalho Chehab 	if (ret)
2054be5e864SMauro Carvalho Chehab 		return ret;
2064be5e864SMauro Carvalho Chehab 
2074be5e864SMauro Carvalho Chehab 	cec->clk = devm_clk_get(dev, "hdmicec");
2084be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->clk))
2094be5e864SMauro Carvalho Chehab 		return PTR_ERR(cec->clk);
2104be5e864SMauro Carvalho Chehab 
2114be5e864SMauro Carvalho Chehab 	cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
2124be5e864SMauro Carvalho Chehab 						 "samsung,syscon-phandle");
2134be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->pmu))
2144be5e864SMauro Carvalho Chehab 		return -EPROBE_DEFER;
2154be5e864SMauro Carvalho Chehab 
216399e0f9aSCai Huoqing 	cec->reg = devm_platform_ioremap_resource(pdev, 0);
2174be5e864SMauro Carvalho Chehab 	if (IS_ERR(cec->reg))
2184be5e864SMauro Carvalho Chehab 		return PTR_ERR(cec->reg);
2194be5e864SMauro Carvalho Chehab 
2204be5e864SMauro Carvalho Chehab 	cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME,
2214be5e864SMauro Carvalho Chehab 		CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0) |
2224be5e864SMauro Carvalho Chehab 		CEC_CAP_CONNECTOR_INFO, 1);
2234be5e864SMauro Carvalho Chehab 	ret = PTR_ERR_OR_ZERO(cec->adap);
2244be5e864SMauro Carvalho Chehab 	if (ret)
2254be5e864SMauro Carvalho Chehab 		return ret;
2264be5e864SMauro Carvalho Chehab 
2274be5e864SMauro Carvalho Chehab 	cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
2284be5e864SMauro Carvalho Chehab 						       cec->adap);
2294be5e864SMauro Carvalho Chehab 	if (!cec->notifier) {
2304be5e864SMauro Carvalho Chehab 		ret = -ENOMEM;
2314be5e864SMauro Carvalho Chehab 		goto err_delete_adapter;
2324be5e864SMauro Carvalho Chehab 	}
2334be5e864SMauro Carvalho Chehab 
2344be5e864SMauro Carvalho Chehab 	ret = cec_register_adapter(cec->adap, &pdev->dev);
2354be5e864SMauro Carvalho Chehab 	if (ret)
2364be5e864SMauro Carvalho Chehab 		goto err_notifier;
2374be5e864SMauro Carvalho Chehab 
2384be5e864SMauro Carvalho Chehab 	platform_set_drvdata(pdev, cec);
2394be5e864SMauro Carvalho Chehab 	pm_runtime_enable(dev);
2404be5e864SMauro Carvalho Chehab 
2414be5e864SMauro Carvalho Chehab 	dev_dbg(dev, "successfully probed\n");
2424be5e864SMauro Carvalho Chehab 	return 0;
2434be5e864SMauro Carvalho Chehab 
2444be5e864SMauro Carvalho Chehab err_notifier:
2454be5e864SMauro Carvalho Chehab 	cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
2464be5e864SMauro Carvalho Chehab 
2474be5e864SMauro Carvalho Chehab err_delete_adapter:
2484be5e864SMauro Carvalho Chehab 	cec_delete_adapter(cec->adap);
2494be5e864SMauro Carvalho Chehab 	return ret;
2504be5e864SMauro Carvalho Chehab }
2514be5e864SMauro Carvalho Chehab 
s5p_cec_remove(struct platform_device * pdev)252*3f8b9bbcSUwe Kleine-König static void s5p_cec_remove(struct platform_device *pdev)
2534be5e864SMauro Carvalho Chehab {
2544be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
2554be5e864SMauro Carvalho Chehab 
2564be5e864SMauro Carvalho Chehab 	cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
2574be5e864SMauro Carvalho Chehab 	cec_unregister_adapter(cec->adap);
2584be5e864SMauro Carvalho Chehab 	pm_runtime_disable(&pdev->dev);
2594be5e864SMauro Carvalho Chehab }
2604be5e864SMauro Carvalho Chehab 
s5p_cec_runtime_suspend(struct device * dev)2614be5e864SMauro Carvalho Chehab static int __maybe_unused s5p_cec_runtime_suspend(struct device *dev)
2624be5e864SMauro Carvalho Chehab {
2634be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = dev_get_drvdata(dev);
2644be5e864SMauro Carvalho Chehab 
2654be5e864SMauro Carvalho Chehab 	clk_disable_unprepare(cec->clk);
2664be5e864SMauro Carvalho Chehab 	return 0;
2674be5e864SMauro Carvalho Chehab }
2684be5e864SMauro Carvalho Chehab 
s5p_cec_runtime_resume(struct device * dev)2694be5e864SMauro Carvalho Chehab static int __maybe_unused s5p_cec_runtime_resume(struct device *dev)
2704be5e864SMauro Carvalho Chehab {
2714be5e864SMauro Carvalho Chehab 	struct s5p_cec_dev *cec = dev_get_drvdata(dev);
2724be5e864SMauro Carvalho Chehab 	int ret;
2734be5e864SMauro Carvalho Chehab 
2744be5e864SMauro Carvalho Chehab 	ret = clk_prepare_enable(cec->clk);
2754be5e864SMauro Carvalho Chehab 	if (ret < 0)
2764be5e864SMauro Carvalho Chehab 		return ret;
2774be5e864SMauro Carvalho Chehab 	return 0;
2784be5e864SMauro Carvalho Chehab }
2794be5e864SMauro Carvalho Chehab 
2804be5e864SMauro Carvalho Chehab static const struct dev_pm_ops s5p_cec_pm_ops = {
2814be5e864SMauro Carvalho Chehab 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
2824be5e864SMauro Carvalho Chehab 				pm_runtime_force_resume)
2834be5e864SMauro Carvalho Chehab 	SET_RUNTIME_PM_OPS(s5p_cec_runtime_suspend, s5p_cec_runtime_resume,
2844be5e864SMauro Carvalho Chehab 			   NULL)
2854be5e864SMauro Carvalho Chehab };
2864be5e864SMauro Carvalho Chehab 
2874be5e864SMauro Carvalho Chehab static const struct of_device_id s5p_cec_match[] = {
2884be5e864SMauro Carvalho Chehab 	{
2894be5e864SMauro Carvalho Chehab 		.compatible	= "samsung,s5p-cec",
2904be5e864SMauro Carvalho Chehab 	},
2914be5e864SMauro Carvalho Chehab 	{},
2924be5e864SMauro Carvalho Chehab };
2934be5e864SMauro Carvalho Chehab MODULE_DEVICE_TABLE(of, s5p_cec_match);
2944be5e864SMauro Carvalho Chehab 
2954be5e864SMauro Carvalho Chehab static struct platform_driver s5p_cec_pdrv = {
2964be5e864SMauro Carvalho Chehab 	.probe	= s5p_cec_probe,
297*3f8b9bbcSUwe Kleine-König 	.remove_new = s5p_cec_remove,
2984be5e864SMauro Carvalho Chehab 	.driver	= {
2994be5e864SMauro Carvalho Chehab 		.name		= CEC_NAME,
3004be5e864SMauro Carvalho Chehab 		.of_match_table	= s5p_cec_match,
3014be5e864SMauro Carvalho Chehab 		.pm		= &s5p_cec_pm_ops,
3024be5e864SMauro Carvalho Chehab 	},
3034be5e864SMauro Carvalho Chehab };
3044be5e864SMauro Carvalho Chehab 
3054be5e864SMauro Carvalho Chehab module_platform_driver(s5p_cec_pdrv);
3064be5e864SMauro Carvalho Chehab 
3074be5e864SMauro Carvalho Chehab MODULE_AUTHOR("Kamil Debski <kamil@wypas.org>");
3084be5e864SMauro Carvalho Chehab MODULE_LICENSE("GPL");
3094be5e864SMauro Carvalho Chehab MODULE_DESCRIPTION("Samsung S5P CEC driver");
310