18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright © 2010 Intel Corporation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Authors:
248c2ecf20Sopenharmony_ci *	Li Peng <peng.li@intel.com>
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/export.h>
288c2ecf20Sopenharmony_ci#include <linux/mutex.h>
298c2ecf20Sopenharmony_ci#include <linux/pci.h>
308c2ecf20Sopenharmony_ci#include <linux/i2c.h>
318c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
328c2ecf20Sopenharmony_ci#include <linux/delay.h>
338c2ecf20Sopenharmony_ci#include "psb_drv.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define HDMI_READ(reg)		readl(hdmi_dev->regs + (reg))
368c2ecf20Sopenharmony_ci#define HDMI_WRITE(reg, val)	writel(val, hdmi_dev->regs + (reg))
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define HDMI_HCR	0x1000
398c2ecf20Sopenharmony_ci#define HCR_DETECT_HDP		(1 << 6)
408c2ecf20Sopenharmony_ci#define HCR_ENABLE_HDCP		(1 << 5)
418c2ecf20Sopenharmony_ci#define HCR_ENABLE_AUDIO	(1 << 2)
428c2ecf20Sopenharmony_ci#define HCR_ENABLE_PIXEL	(1 << 1)
438c2ecf20Sopenharmony_ci#define HCR_ENABLE_TMDS		(1 << 0)
448c2ecf20Sopenharmony_ci#define HDMI_HICR	0x1004
458c2ecf20Sopenharmony_ci#define HDMI_INTR_I2C_ERROR	(1 << 4)
468c2ecf20Sopenharmony_ci#define HDMI_INTR_I2C_FULL	(1 << 3)
478c2ecf20Sopenharmony_ci#define HDMI_INTR_I2C_DONE	(1 << 2)
488c2ecf20Sopenharmony_ci#define HDMI_INTR_HPD		(1 << 0)
498c2ecf20Sopenharmony_ci#define HDMI_HSR	0x1008
508c2ecf20Sopenharmony_ci#define HDMI_HISR	0x100C
518c2ecf20Sopenharmony_ci#define HDMI_HI2CRDB0	0x1200
528c2ecf20Sopenharmony_ci#define HDMI_HI2CHCR	0x1240
538c2ecf20Sopenharmony_ci#define HI2C_HDCP_WRITE		(0 << 2)
548c2ecf20Sopenharmony_ci#define HI2C_HDCP_RI_READ	(1 << 2)
558c2ecf20Sopenharmony_ci#define HI2C_HDCP_READ		(2 << 2)
568c2ecf20Sopenharmony_ci#define HI2C_EDID_READ		(3 << 2)
578c2ecf20Sopenharmony_ci#define HI2C_READ_CONTINUE	(1 << 1)
588c2ecf20Sopenharmony_ci#define HI2C_ENABLE_TRANSACTION	(1 << 0)
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define HDMI_ICRH	0x1100
618c2ecf20Sopenharmony_ci#define HDMI_HI2CTDR0	0x1244
628c2ecf20Sopenharmony_ci#define HDMI_HI2CTDR1	0x1248
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define I2C_STAT_INIT		0
658c2ecf20Sopenharmony_ci#define I2C_READ_DONE		1
668c2ecf20Sopenharmony_ci#define I2C_TRANSACTION_DONE	2
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct hdmi_i2c_dev {
698c2ecf20Sopenharmony_ci	struct i2c_adapter *adap;
708c2ecf20Sopenharmony_ci	struct mutex i2c_lock;
718c2ecf20Sopenharmony_ci	struct completion complete;
728c2ecf20Sopenharmony_ci	int status;
738c2ecf20Sopenharmony_ci	struct i2c_msg *msg;
748c2ecf20Sopenharmony_ci	int buf_offset;
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic void hdmi_i2c_irq_enable(struct oaktrail_hdmi_dev *hdmi_dev)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	u32 temp;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	temp = HDMI_READ(HDMI_HICR);
828c2ecf20Sopenharmony_ci	temp |= (HDMI_INTR_I2C_ERROR | HDMI_INTR_I2C_FULL | HDMI_INTR_I2C_DONE);
838c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HICR, temp);
848c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HICR);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void hdmi_i2c_irq_disable(struct oaktrail_hdmi_dev *hdmi_dev)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HICR, 0x0);
908c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HICR);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int xfer_read(struct i2c_adapter *adap, struct i2c_msg *pmsg)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
968c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
978c2ecf20Sopenharmony_ci	u32 temp;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	i2c_dev->status = I2C_STAT_INIT;
1008c2ecf20Sopenharmony_ci	i2c_dev->msg = pmsg;
1018c2ecf20Sopenharmony_ci	i2c_dev->buf_offset = 0;
1028c2ecf20Sopenharmony_ci	reinit_completion(&i2c_dev->complete);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* Enable I2C transaction */
1058c2ecf20Sopenharmony_ci	temp = ((pmsg->len) << 20) | HI2C_EDID_READ | HI2C_ENABLE_TRANSACTION;
1068c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HI2CHCR, temp);
1078c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HI2CHCR);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	while (i2c_dev->status != I2C_TRANSACTION_DONE)
1108c2ecf20Sopenharmony_ci		wait_for_completion_interruptible_timeout(&i2c_dev->complete,
1118c2ecf20Sopenharmony_ci								10 * HZ);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int xfer_write(struct i2c_adapter *adap, struct i2c_msg *pmsg)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * XXX: i2c write seems isn't useful for EDID probe, don't do anything
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int oaktrail_hdmi_i2c_access(struct i2c_adapter *adap,
1258c2ecf20Sopenharmony_ci				struct i2c_msg *pmsg,
1268c2ecf20Sopenharmony_ci				int num)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct oaktrail_hdmi_dev *hdmi_dev = i2c_get_adapdata(adap);
1298c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
1308c2ecf20Sopenharmony_ci	int i;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	mutex_lock(&i2c_dev->i2c_lock);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* Enable i2c unit */
1358c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_ICRH, 0x00008760);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/* Enable irq */
1388c2ecf20Sopenharmony_ci	hdmi_i2c_irq_enable(hdmi_dev);
1398c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
1408c2ecf20Sopenharmony_ci		if (pmsg->len && pmsg->buf) {
1418c2ecf20Sopenharmony_ci			if (pmsg->flags & I2C_M_RD)
1428c2ecf20Sopenharmony_ci				xfer_read(adap, pmsg);
1438c2ecf20Sopenharmony_ci			else
1448c2ecf20Sopenharmony_ci				xfer_write(adap, pmsg);
1458c2ecf20Sopenharmony_ci		}
1468c2ecf20Sopenharmony_ci		pmsg++;         /* next message */
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* Disable irq */
1508c2ecf20Sopenharmony_ci	hdmi_i2c_irq_disable(hdmi_dev);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	mutex_unlock(&i2c_dev->i2c_lock);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return i;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic u32 oaktrail_hdmi_i2c_func(struct i2c_adapter *adapter)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic const struct i2c_algorithm oaktrail_hdmi_i2c_algorithm = {
1638c2ecf20Sopenharmony_ci	.master_xfer	= oaktrail_hdmi_i2c_access,
1648c2ecf20Sopenharmony_ci	.functionality  = oaktrail_hdmi_i2c_func,
1658c2ecf20Sopenharmony_ci};
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic struct i2c_adapter oaktrail_hdmi_i2c_adapter = {
1688c2ecf20Sopenharmony_ci	.name		= "oaktrail_hdmi_i2c",
1698c2ecf20Sopenharmony_ci	.nr		= 3,
1708c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
1718c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_DDC,
1728c2ecf20Sopenharmony_ci	.algo		= &oaktrail_hdmi_i2c_algorithm,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void hdmi_i2c_read(struct oaktrail_hdmi_dev *hdmi_dev)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
1788c2ecf20Sopenharmony_ci	struct i2c_msg *msg = i2c_dev->msg;
1798c2ecf20Sopenharmony_ci	u8 *buf = msg->buf;
1808c2ecf20Sopenharmony_ci	u32 temp;
1818c2ecf20Sopenharmony_ci	int i, offset;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	offset = i2c_dev->buf_offset;
1848c2ecf20Sopenharmony_ci	for (i = 0; i < 0x10; i++) {
1858c2ecf20Sopenharmony_ci		temp = HDMI_READ(HDMI_HI2CRDB0 + (i * 4));
1868c2ecf20Sopenharmony_ci		memcpy(buf + (offset + i * 4), &temp, 4);
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	i2c_dev->buf_offset += (0x10 * 4);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/* clearing read buffer full intr */
1918c2ecf20Sopenharmony_ci	temp = HDMI_READ(HDMI_HISR);
1928c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_FULL);
1938c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HISR);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* continue read transaction */
1968c2ecf20Sopenharmony_ci	temp = HDMI_READ(HDMI_HI2CHCR);
1978c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HI2CHCR, temp | HI2C_READ_CONTINUE);
1988c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HI2CHCR);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	i2c_dev->status = I2C_READ_DONE;
2018c2ecf20Sopenharmony_ci	return;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void hdmi_i2c_transaction_done(struct oaktrail_hdmi_dev *hdmi_dev)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
2078c2ecf20Sopenharmony_ci	u32 temp;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	/* clear transaction done intr */
2108c2ecf20Sopenharmony_ci	temp = HDMI_READ(HDMI_HISR);
2118c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HISR, temp | HDMI_INTR_I2C_DONE);
2128c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HISR);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	temp = HDMI_READ(HDMI_HI2CHCR);
2168c2ecf20Sopenharmony_ci	HDMI_WRITE(HDMI_HI2CHCR, temp & ~HI2C_ENABLE_TRANSACTION);
2178c2ecf20Sopenharmony_ci	HDMI_READ(HDMI_HI2CHCR);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	i2c_dev->status = I2C_TRANSACTION_DONE;
2208c2ecf20Sopenharmony_ci	return;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic irqreturn_t oaktrail_hdmi_i2c_handler(int this_irq, void *dev)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct oaktrail_hdmi_dev *hdmi_dev = dev;
2268c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev = hdmi_dev->i2c_dev;
2278c2ecf20Sopenharmony_ci	u32 stat;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	stat = HDMI_READ(HDMI_HISR);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (stat & HDMI_INTR_HPD) {
2328c2ecf20Sopenharmony_ci		HDMI_WRITE(HDMI_HISR, stat | HDMI_INTR_HPD);
2338c2ecf20Sopenharmony_ci		HDMI_READ(HDMI_HISR);
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (stat & HDMI_INTR_I2C_FULL)
2378c2ecf20Sopenharmony_ci		hdmi_i2c_read(hdmi_dev);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (stat & HDMI_INTR_I2C_DONE)
2408c2ecf20Sopenharmony_ci		hdmi_i2c_transaction_done(hdmi_dev);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	complete(&i2c_dev->complete);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/*
2488c2ecf20Sopenharmony_ci * choose alternate function 2 of GPIO pin 52, 53,
2498c2ecf20Sopenharmony_ci * which is used by HDMI I2C logic
2508c2ecf20Sopenharmony_ci */
2518c2ecf20Sopenharmony_cistatic void oaktrail_hdmi_i2c_gpio_fix(void)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	void __iomem *base;
2548c2ecf20Sopenharmony_ci	unsigned int gpio_base = 0xff12c000;
2558c2ecf20Sopenharmony_ci	int gpio_len = 0x1000;
2568c2ecf20Sopenharmony_ci	u32 temp;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	base = ioremap((resource_size_t)gpio_base, gpio_len);
2598c2ecf20Sopenharmony_ci	if (base == NULL) {
2608c2ecf20Sopenharmony_ci		DRM_ERROR("gpio ioremap fail\n");
2618c2ecf20Sopenharmony_ci		return;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	temp = readl(base + 0x44);
2658c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("old gpio val %x\n", temp);
2668c2ecf20Sopenharmony_ci	writel((temp | 0x00000a00), (base +  0x44));
2678c2ecf20Sopenharmony_ci	temp = readl(base + 0x44);
2688c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("new gpio val %x\n", temp);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	iounmap(base);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciint oaktrail_hdmi_i2c_init(struct pci_dev *dev)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct oaktrail_hdmi_dev *hdmi_dev;
2768c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev;
2778c2ecf20Sopenharmony_ci	int ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	hdmi_dev = pci_get_drvdata(dev);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	i2c_dev = kzalloc(sizeof(struct hdmi_i2c_dev), GFP_KERNEL);
2828c2ecf20Sopenharmony_ci	if (!i2c_dev)
2838c2ecf20Sopenharmony_ci		return -ENOMEM;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	i2c_dev->adap = &oaktrail_hdmi_i2c_adapter;
2868c2ecf20Sopenharmony_ci	i2c_dev->status = I2C_STAT_INIT;
2878c2ecf20Sopenharmony_ci	init_completion(&i2c_dev->complete);
2888c2ecf20Sopenharmony_ci	mutex_init(&i2c_dev->i2c_lock);
2898c2ecf20Sopenharmony_ci	i2c_set_adapdata(&oaktrail_hdmi_i2c_adapter, hdmi_dev);
2908c2ecf20Sopenharmony_ci	hdmi_dev->i2c_dev = i2c_dev;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Enable HDMI I2C function on gpio */
2938c2ecf20Sopenharmony_ci	oaktrail_hdmi_i2c_gpio_fix();
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* request irq */
2968c2ecf20Sopenharmony_ci	ret = request_irq(dev->irq, oaktrail_hdmi_i2c_handler, IRQF_SHARED,
2978c2ecf20Sopenharmony_ci			  oaktrail_hdmi_i2c_adapter.name, hdmi_dev);
2988c2ecf20Sopenharmony_ci	if (ret) {
2998c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to request IRQ for I2C controller\n");
3008c2ecf20Sopenharmony_ci		goto free_dev;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Adapter registration */
3048c2ecf20Sopenharmony_ci	ret = i2c_add_numbered_adapter(&oaktrail_hdmi_i2c_adapter);
3058c2ecf20Sopenharmony_ci	if (ret) {
3068c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to add I2C adapter\n");
3078c2ecf20Sopenharmony_ci		goto free_irq;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	return 0;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cifree_irq:
3138c2ecf20Sopenharmony_ci	free_irq(dev->irq, hdmi_dev);
3148c2ecf20Sopenharmony_cifree_dev:
3158c2ecf20Sopenharmony_ci	kfree(i2c_dev);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	return ret;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_civoid oaktrail_hdmi_i2c_exit(struct pci_dev *dev)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct oaktrail_hdmi_dev *hdmi_dev;
3238c2ecf20Sopenharmony_ci	struct hdmi_i2c_dev *i2c_dev;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	hdmi_dev = pci_get_drvdata(dev);
3268c2ecf20Sopenharmony_ci	i2c_del_adapter(&oaktrail_hdmi_i2c_adapter);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	i2c_dev = hdmi_dev->i2c_dev;
3298c2ecf20Sopenharmony_ci	kfree(i2c_dev);
3308c2ecf20Sopenharmony_ci	free_irq(dev->irq, hdmi_dev);
3318c2ecf20Sopenharmony_ci}
332